1 | /* |
2 | * Copyright 2014 Google Inc. |
3 | * |
4 | * Use of this source code is governed by a BSD-style license that can be |
5 | * found in the LICENSE file. |
6 | */ |
7 | |
8 | #include "include/private/SkColorData.h" |
9 | #include "include/private/SkHalf.h" |
10 | #include "include/private/SkImageInfoPriv.h" |
11 | #include "src/core/SkColorSpacePriv.h" |
12 | #include "src/core/SkColorSpaceXformSteps.h" |
13 | #include "src/core/SkConvertPixels.h" |
14 | #include "src/core/SkOpts.h" |
15 | #include "src/core/SkRasterPipeline.h" |
16 | |
17 | static bool rect_memcpy(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB, |
18 | const SkImageInfo& srcInfo, const void* srcPixels, size_t srcRB, |
19 | const SkColorSpaceXformSteps& steps) { |
20 | // We can copy the pixels when no color type, alpha type, or color space changes. |
21 | if (dstInfo.colorType() != srcInfo.colorType()) { |
22 | return false; |
23 | } |
24 | if (dstInfo.colorType() != kAlpha_8_SkColorType |
25 | && steps.flags.mask() != 0b00000) { |
26 | return false; |
27 | } |
28 | |
29 | SkRectMemcpy(dstPixels, dstRB, |
30 | srcPixels, srcRB, dstInfo.minRowBytes(), dstInfo.height()); |
31 | return true; |
32 | } |
33 | |
34 | static bool swizzle_or_premul(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB, |
35 | const SkImageInfo& srcInfo, const void* srcPixels, size_t srcRB, |
36 | const SkColorSpaceXformSteps& steps) { |
37 | auto is_8888 = [](SkColorType ct) { |
38 | return ct == kRGBA_8888_SkColorType || ct == kBGRA_8888_SkColorType; |
39 | }; |
40 | if (!is_8888(dstInfo.colorType()) || |
41 | !is_8888(srcInfo.colorType()) || |
42 | steps.flags.linearize || |
43 | steps.flags.gamut_transform || |
44 | steps.flags.unpremul || |
45 | steps.flags.encode) { |
46 | return false; |
47 | } |
48 | |
49 | const bool swapRB = dstInfo.colorType() != srcInfo.colorType(); |
50 | |
51 | void (*fn)(uint32_t*, const uint32_t*, int) = nullptr; |
52 | |
53 | if (steps.flags.premul) { |
54 | fn = swapRB ? SkOpts::RGBA_to_bgrA |
55 | : SkOpts::RGBA_to_rgbA; |
56 | } else { |
57 | // If we're not swizzling, we ought to have used rect_memcpy(). |
58 | SkASSERT(swapRB); |
59 | fn = SkOpts::RGBA_to_BGRA; |
60 | } |
61 | |
62 | for (int y = 0; y < dstInfo.height(); y++) { |
63 | fn((uint32_t*)dstPixels, (const uint32_t*)srcPixels, dstInfo.width()); |
64 | dstPixels = SkTAddOffset<void>(dstPixels, dstRB); |
65 | srcPixels = SkTAddOffset<const void>(srcPixels, srcRB); |
66 | } |
67 | return true; |
68 | } |
69 | |
70 | static bool convert_to_alpha8(const SkImageInfo& dstInfo, void* vdst, size_t dstRB, |
71 | const SkImageInfo& srcInfo, const void* src, size_t srcRB, |
72 | const SkColorSpaceXformSteps&) { |
73 | if (dstInfo.colorType() != kAlpha_8_SkColorType) { |
74 | return false; |
75 | } |
76 | auto dst = (uint8_t*)vdst; |
77 | |
78 | switch (srcInfo.colorType()) { |
79 | case kUnknown_SkColorType: |
80 | case kAlpha_8_SkColorType: { |
81 | // Unknown should never happen. |
82 | // Alpha8 should have been handled by rect_memcpy(). |
83 | SkASSERT(false); |
84 | return false; |
85 | } |
86 | |
87 | case kA16_unorm_SkColorType: { |
88 | auto src16 = (const uint16_t*) src; |
89 | for (int y = 0; y < srcInfo.height(); y++) { |
90 | for (int x = 0; x < srcInfo.width(); x++) { |
91 | dst[x] = src16[x] >> 8; |
92 | } |
93 | dst = SkTAddOffset<uint8_t>(dst, dstRB); |
94 | src16 = SkTAddOffset<const uint16_t>(src16, srcRB); |
95 | } |
96 | return true; |
97 | } |
98 | |
99 | case kGray_8_SkColorType: |
100 | case kRGB_565_SkColorType: |
101 | case kR8G8_unorm_SkColorType: |
102 | case kR16G16_unorm_SkColorType: |
103 | case kR16G16_float_SkColorType: |
104 | case kRGB_888x_SkColorType: |
105 | case kRGB_101010x_SkColorType: |
106 | case kBGR_101010x_SkColorType: { |
107 | for (int y = 0; y < srcInfo.height(); ++y) { |
108 | memset(dst, 0xFF, srcInfo.width()); |
109 | dst = SkTAddOffset<uint8_t>(dst, dstRB); |
110 | } |
111 | return true; |
112 | } |
113 | |
114 | case kARGB_4444_SkColorType: { |
115 | auto src16 = (const uint16_t*) src; |
116 | for (int y = 0; y < srcInfo.height(); y++) { |
117 | for (int x = 0; x < srcInfo.width(); x++) { |
118 | dst[x] = SkPacked4444ToA32(src16[x]); |
119 | } |
120 | dst = SkTAddOffset<uint8_t>(dst, dstRB); |
121 | src16 = SkTAddOffset<const uint16_t>(src16, srcRB); |
122 | } |
123 | return true; |
124 | } |
125 | |
126 | case kBGRA_8888_SkColorType: |
127 | case kRGBA_8888_SkColorType: { |
128 | auto src32 = (const uint32_t*) src; |
129 | for (int y = 0; y < srcInfo.height(); y++) { |
130 | for (int x = 0; x < srcInfo.width(); x++) { |
131 | dst[x] = src32[x] >> 24; |
132 | } |
133 | dst = SkTAddOffset<uint8_t>(dst, dstRB); |
134 | src32 = SkTAddOffset<const uint32_t>(src32, srcRB); |
135 | } |
136 | return true; |
137 | } |
138 | |
139 | case kRGBA_1010102_SkColorType: |
140 | case kBGRA_1010102_SkColorType: { |
141 | auto src32 = (const uint32_t*) src; |
142 | for (int y = 0; y < srcInfo.height(); y++) { |
143 | for (int x = 0; x < srcInfo.width(); x++) { |
144 | dst[x] = (src32[x] >> 30) * 0x55; |
145 | } |
146 | dst = SkTAddOffset<uint8_t>(dst, dstRB); |
147 | src32 = SkTAddOffset<const uint32_t>(src32, srcRB); |
148 | } |
149 | return true; |
150 | } |
151 | |
152 | case kRGBA_F16Norm_SkColorType: |
153 | case kRGBA_F16_SkColorType: { |
154 | auto src64 = (const uint64_t*) src; |
155 | for (int y = 0; y < srcInfo.height(); y++) { |
156 | for (int x = 0; x < srcInfo.width(); x++) { |
157 | dst[x] = (uint8_t) (255.0f * SkHalfToFloat(src64[x] >> 48)); |
158 | } |
159 | dst = SkTAddOffset<uint8_t>(dst, dstRB); |
160 | src64 = SkTAddOffset<const uint64_t>(src64, srcRB); |
161 | } |
162 | return true; |
163 | } |
164 | |
165 | case kRGBA_F32_SkColorType: { |
166 | auto rgba = (const float*)src; |
167 | for (int y = 0; y < srcInfo.height(); y++) { |
168 | for (int x = 0; x < srcInfo.width(); x++) { |
169 | dst[x] = (uint8_t)(255.0f * rgba[4*x+3]); |
170 | } |
171 | dst = SkTAddOffset<uint8_t>(dst, dstRB); |
172 | rgba = SkTAddOffset<const float>(rgba, srcRB); |
173 | } |
174 | return true; |
175 | } |
176 | |
177 | case kA16_float_SkColorType: { |
178 | auto srcF16 = (const uint16_t*) src; |
179 | for (int y = 0; y < srcInfo.height(); y++) { |
180 | for (int x = 0; x < srcInfo.width(); x++) { |
181 | dst[x] = (uint8_t) (255.0f * SkHalfToFloat(srcF16[x])); |
182 | } |
183 | dst = SkTAddOffset<uint8_t>(dst, dstRB); |
184 | srcF16 = SkTAddOffset<const uint16_t>(srcF16, srcRB); |
185 | } |
186 | return true; |
187 | } |
188 | |
189 | case kR16G16B16A16_unorm_SkColorType: { |
190 | auto src64 = (const uint64_t*) src; |
191 | for (int y = 0; y < srcInfo.height(); y++) { |
192 | for (int x = 0; x < srcInfo.width(); x++) { |
193 | dst[x] = (src64[x] >> 48) >> 8; |
194 | } |
195 | dst = SkTAddOffset<uint8_t>(dst, dstRB); |
196 | src64 = SkTAddOffset<const uint64_t>(src64, srcRB); |
197 | } |
198 | return true; |
199 | } |
200 | } |
201 | return false; |
202 | } |
203 | |
204 | // Default: Use the pipeline. |
205 | static void convert_with_pipeline(const SkImageInfo& dstInfo, void* dstRow, size_t dstRB, |
206 | const SkImageInfo& srcInfo, const void* srcRow, size_t srcRB, |
207 | const SkColorSpaceXformSteps& steps) { |
208 | |
209 | SkRasterPipeline_MemoryCtx src = { (void*)srcRow, (int)(srcRB / srcInfo.bytesPerPixel()) }, |
210 | dst = { (void*)dstRow, (int)(dstRB / dstInfo.bytesPerPixel()) }; |
211 | |
212 | SkRasterPipeline_<256> pipeline; |
213 | pipeline.append_load(srcInfo.colorType(), &src); |
214 | steps.apply(&pipeline, srcInfo.colorType()); |
215 | |
216 | pipeline.append_gamut_clamp_if_normalized(dstInfo); |
217 | |
218 | pipeline.append_store(dstInfo.colorType(), &dst); |
219 | pipeline.run(0,0, srcInfo.width(), srcInfo.height()); |
220 | } |
221 | |
222 | void SkConvertPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB, |
223 | const SkImageInfo& srcInfo, const void* srcPixels, size_t srcRB) { |
224 | SkASSERT(dstInfo.dimensions() == srcInfo.dimensions()); |
225 | SkASSERT(SkImageInfoValidConversion(dstInfo, srcInfo)); |
226 | |
227 | SkColorSpaceXformSteps steps{srcInfo.colorSpace(), srcInfo.alphaType(), |
228 | dstInfo.colorSpace(), dstInfo.alphaType()}; |
229 | |
230 | for (auto fn : {rect_memcpy, swizzle_or_premul, convert_to_alpha8}) { |
231 | if (fn(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, srcRB, steps)) { |
232 | return; |
233 | } |
234 | } |
235 | convert_with_pipeline(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, srcRB, steps); |
236 | } |
237 | |