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 "SkColorSpaceXform_Base.h"
9 #include "SkColorSpaceXformPriv.h"
10 #include "SkColorSpacePriv.h"
11 #include "SkColorTable.h"
12 #include "SkConvertPixels.h"
13 #include "SkHalf.h"
14 #include "SkImageInfoPriv.h"
15 #include "SkOpts.h"
16 #include "SkPM4fPriv.h"
17 #include "SkRasterPipeline.h"
18 #include "SkUnPreMultiply.h"
19 #include "SkUnPreMultiplyPriv.h"
20 #include "../jumper/SkJumper.h"
21
22 // Fast Path 1: The memcpy() case.
can_memcpy(const SkImageInfo & dstInfo,const SkImageInfo & srcInfo)23 static inline bool can_memcpy(const SkImageInfo& dstInfo, const SkImageInfo& srcInfo) {
24 if (dstInfo.colorType() != srcInfo.colorType()) {
25 return false;
26 }
27
28 if (kAlpha_8_SkColorType == dstInfo.colorType()) {
29 return true;
30 }
31
32 if (dstInfo.alphaType() != srcInfo.alphaType() &&
33 kOpaque_SkAlphaType != dstInfo.alphaType() &&
34 kOpaque_SkAlphaType != srcInfo.alphaType())
35 {
36 // We need to premultiply or unpremultiply.
37 return false;
38 }
39
40 return !dstInfo.colorSpace() ||
41 SkColorSpace::Equals(dstInfo.colorSpace(), srcInfo.colorSpace());
42 }
43
44 // Fast Path 2: Simple swizzles and premuls.
45 enum AlphaVerb {
46 kNothing_AlphaVerb,
47 kPremul_AlphaVerb,
48 kUnpremul_AlphaVerb,
49 };
50
51 template <bool kSwapRB>
wrap_unpremultiply(uint32_t * dst,const void * src,int count)52 static void wrap_unpremultiply(uint32_t* dst, const void* src, int count) {
53 SkUnpremultiplyRow<kSwapRB>(dst, (const uint32_t*) src, count);
54 }
55
swizzle_and_multiply(const SkImageInfo & dstInfo,void * dstPixels,size_t dstRB,const SkImageInfo & srcInfo,const void * srcPixels,size_t srcRB)56 void swizzle_and_multiply(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
57 const SkImageInfo& srcInfo, const void* srcPixels, size_t srcRB) {
58 void (*proc)(uint32_t* dst, const void* src, int count);
59 const bool swapRB = dstInfo.colorType() != srcInfo.colorType();
60 AlphaVerb alphaVerb = kNothing_AlphaVerb;
61 if (kPremul_SkAlphaType == dstInfo.alphaType() &&
62 kUnpremul_SkAlphaType == srcInfo.alphaType())
63 {
64 alphaVerb = kPremul_AlphaVerb;
65 } else if (kUnpremul_SkAlphaType == dstInfo.alphaType() &&
66 kPremul_SkAlphaType == srcInfo.alphaType()) {
67 alphaVerb = kUnpremul_AlphaVerb;
68 }
69
70 switch (alphaVerb) {
71 case kNothing_AlphaVerb:
72 // If we do not need to swap or multiply, we should hit the memcpy case.
73 SkASSERT(swapRB);
74 proc = SkOpts::RGBA_to_BGRA;
75 break;
76 case kPremul_AlphaVerb:
77 proc = swapRB ? SkOpts::RGBA_to_bgrA : SkOpts::RGBA_to_rgbA;
78 break;
79 case kUnpremul_AlphaVerb:
80 proc = swapRB ? wrap_unpremultiply<true> : wrap_unpremultiply<false>;
81 break;
82 }
83
84 for (int y = 0; y < dstInfo.height(); y++) {
85 proc((uint32_t*) dstPixels, srcPixels, dstInfo.width());
86 dstPixels = SkTAddOffset<void>(dstPixels, dstRB);
87 srcPixels = SkTAddOffset<const void>(srcPixels, srcRB);
88 }
89 }
90
91 // Fast Path 3: Color space xform.
optimized_color_xform(const SkImageInfo & dstInfo,const SkImageInfo & srcInfo,SkTransferFunctionBehavior behavior)92 static inline bool optimized_color_xform(const SkImageInfo& dstInfo, const SkImageInfo& srcInfo,
93 SkTransferFunctionBehavior behavior) {
94 // Unpremultiplication is unsupported by SkColorSpaceXform. Note that if |src| is non-linearly
95 // premultiplied, we're always going to have to unpremultiply before doing anything.
96 if (kPremul_SkAlphaType == srcInfo.alphaType() &&
97 (kUnpremul_SkAlphaType == dstInfo.alphaType() ||
98 SkTransferFunctionBehavior::kIgnore == behavior)) {
99 return false;
100 }
101
102 switch (dstInfo.colorType()) {
103 case kRGBA_8888_SkColorType:
104 case kBGRA_8888_SkColorType:
105 case kRGBA_F16_SkColorType:
106 break;
107 default:
108 return false;
109 }
110
111 switch (srcInfo.colorType()) {
112 case kRGBA_8888_SkColorType:
113 case kBGRA_8888_SkColorType:
114 break;
115 default:
116 return false;
117 }
118
119 return true;
120 }
121
apply_color_xform(const SkImageInfo & dstInfo,void * dstPixels,size_t dstRB,const SkImageInfo & srcInfo,const void * srcPixels,size_t srcRB,SkTransferFunctionBehavior behavior)122 static inline void apply_color_xform(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
123 const SkImageInfo& srcInfo, const void* srcPixels,
124 size_t srcRB, SkTransferFunctionBehavior behavior) {
125 SkColorSpaceXform::ColorFormat dstFormat = select_xform_format(dstInfo.colorType());
126 SkColorSpaceXform::ColorFormat srcFormat = select_xform_format(srcInfo.colorType());
127 SkAlphaType xformAlpha;
128 switch (srcInfo.alphaType()) {
129 case kOpaque_SkAlphaType:
130 xformAlpha = kOpaque_SkAlphaType;
131 break;
132 case kPremul_SkAlphaType:
133 SkASSERT(kPremul_SkAlphaType == dstInfo.alphaType());
134
135 // This signal means: copy the src alpha to the dst, do not premultiply (in this
136 // case because the pixels are already premultiplied).
137 xformAlpha = kUnpremul_SkAlphaType;
138 break;
139 case kUnpremul_SkAlphaType:
140 SkASSERT(kPremul_SkAlphaType == dstInfo.alphaType() ||
141 kUnpremul_SkAlphaType == dstInfo.alphaType());
142
143 xformAlpha = dstInfo.alphaType();
144 break;
145 default:
146 SkASSERT(false);
147 xformAlpha = kUnpremul_SkAlphaType;
148 break;
149 }
150
151 std::unique_ptr<SkColorSpaceXform> xform =
152 SkColorSpaceXform_Base::New(srcInfo.colorSpace(), dstInfo.colorSpace(), behavior);
153 SkASSERT(xform);
154
155 for (int y = 0; y < dstInfo.height(); y++) {
156 SkAssertResult(xform->apply(dstFormat, dstPixels, srcFormat, srcPixels, dstInfo.width(),
157 xformAlpha));
158 dstPixels = SkTAddOffset<void>(dstPixels, dstRB);
159 srcPixels = SkTAddOffset<const void>(srcPixels, srcRB);
160 }
161 }
162
163 // Fast Path 4: Alpha 8 dsts.
convert_to_alpha8(uint8_t * dst,size_t dstRB,const SkImageInfo & srcInfo,const void * src,size_t srcRB,SkColorTable * ctable)164 static void convert_to_alpha8(uint8_t* dst, size_t dstRB, const SkImageInfo& srcInfo,
165 const void* src, size_t srcRB, SkColorTable* ctable) {
166 if (srcInfo.isOpaque()) {
167 for (int y = 0; y < srcInfo.height(); ++y) {
168 memset(dst, 0xFF, srcInfo.width());
169 dst = SkTAddOffset<uint8_t>(dst, dstRB);
170 }
171 return;
172 }
173
174 switch (srcInfo.colorType()) {
175 case kBGRA_8888_SkColorType:
176 case kRGBA_8888_SkColorType: {
177 auto src32 = (const uint32_t*) src;
178 for (int y = 0; y < srcInfo.height(); y++) {
179 for (int x = 0; x < srcInfo.width(); x++) {
180 dst[x] = src32[x] >> 24;
181 }
182 dst = SkTAddOffset<uint8_t>(dst, dstRB);
183 src32 = SkTAddOffset<const uint32_t>(src32, srcRB);
184 }
185 break;
186 }
187 case kARGB_4444_SkColorType: {
188 auto src16 = (const uint16_t*) src;
189 for (int y = 0; y < srcInfo.height(); y++) {
190 for (int x = 0; x < srcInfo.width(); x++) {
191 dst[x] = SkPacked4444ToA32(src16[x]);
192 }
193 dst = SkTAddOffset<uint8_t>(dst, dstRB);
194 src16 = SkTAddOffset<const uint16_t>(src16, srcRB);
195 }
196 break;
197 }
198 case kRGBA_F16_SkColorType: {
199 auto src64 = (const uint64_t*) src;
200 for (int y = 0; y < srcInfo.height(); y++) {
201 for (int x = 0; x < srcInfo.width(); x++) {
202 dst[x] = (uint8_t) (255.0f * SkHalfToFloat(src64[x] >> 48));
203 }
204 dst = SkTAddOffset<uint8_t>(dst, dstRB);
205 src64 = SkTAddOffset<const uint64_t>(src64, srcRB);
206 }
207 break;
208 }
209 default:
210 SkASSERT(false);
211 break;
212 }
213 }
214
215 // Default: Use the pipeline.
convert_with_pipeline(const SkImageInfo & dstInfo,void * dstRow,size_t dstRB,const SkImageInfo & srcInfo,const void * srcRow,size_t srcRB,bool isColorAware,SkTransferFunctionBehavior behavior)216 static void convert_with_pipeline(const SkImageInfo& dstInfo, void* dstRow, size_t dstRB,
217 const SkImageInfo& srcInfo, const void* srcRow, size_t srcRB,
218 bool isColorAware, SkTransferFunctionBehavior behavior) {
219
220 SkJumper_MemoryCtx src = { (void*)srcRow, (int)(srcRB / srcInfo.bytesPerPixel()) },
221 dst = { (void*)dstRow, (int)(dstRB / dstInfo.bytesPerPixel()) };
222
223 SkRasterPipeline_<256> pipeline;
224 switch (srcInfo.colorType()) {
225 case kRGBA_8888_SkColorType:
226 pipeline.append(SkRasterPipeline::load_8888, &src);
227 break;
228 case kBGRA_8888_SkColorType:
229 pipeline.append(SkRasterPipeline::load_bgra, &src);
230 break;
231 case kRGB_565_SkColorType:
232 pipeline.append(SkRasterPipeline::load_565, &src);
233 break;
234 case kRGBA_F16_SkColorType:
235 pipeline.append(SkRasterPipeline::load_f16, &src);
236 break;
237 case kGray_8_SkColorType:
238 pipeline.append(SkRasterPipeline::load_g8, &src);
239 break;
240 case kARGB_4444_SkColorType:
241 pipeline.append(SkRasterPipeline::load_4444, &src);
242 break;
243 default:
244 SkASSERT(false);
245 break;
246 }
247
248 SkAlphaType premulState = srcInfo.alphaType();
249 if (kPremul_SkAlphaType == premulState && SkTransferFunctionBehavior::kIgnore == behavior) {
250 pipeline.append(SkRasterPipeline::unpremul);
251 premulState = kUnpremul_SkAlphaType;
252 }
253
254 SkColorSpaceTransferFn srcFn;
255 if (isColorAware && srcInfo.gammaCloseToSRGB()) {
256 pipeline.append(SkRasterPipeline::from_srgb);
257 } else if (isColorAware && !srcInfo.colorSpace()->gammaIsLinear()) {
258 SkAssertResult(srcInfo.colorSpace()->isNumericalTransferFn(&srcFn));
259 if (is_just_gamma(srcFn)) {
260 pipeline.append(SkRasterPipeline::gamma, &srcFn.fG);
261 } else {
262 pipeline.append(SkRasterPipeline::parametric_r, &srcFn);
263 pipeline.append(SkRasterPipeline::parametric_g, &srcFn);
264 pipeline.append(SkRasterPipeline::parametric_b, &srcFn);
265 }
266 }
267
268 float matrix[12];
269 if (isColorAware) {
270 append_gamut_transform(&pipeline, matrix, srcInfo.colorSpace(), dstInfo.colorSpace(),
271 premulState);
272 }
273
274 SkAlphaType dat = dstInfo.alphaType();
275 if (SkTransferFunctionBehavior::kRespect == behavior) {
276 if (kPremul_SkAlphaType == premulState && kUnpremul_SkAlphaType == dat) {
277 pipeline.append(SkRasterPipeline::unpremul);
278 premulState = kUnpremul_SkAlphaType;
279 } else if (kUnpremul_SkAlphaType == premulState && kPremul_SkAlphaType == dat) {
280 pipeline.append(SkRasterPipeline::premul);
281 premulState = kPremul_SkAlphaType;
282 }
283 }
284
285 SkColorSpaceTransferFn dstFn;
286 if (isColorAware && dstInfo.gammaCloseToSRGB()) {
287 pipeline.append(SkRasterPipeline::to_srgb);
288 } else if (isColorAware && !dstInfo.colorSpace()->gammaIsLinear()) {
289 SkAssertResult(dstInfo.colorSpace()->isNumericalTransferFn(&dstFn));
290 dstFn = dstFn.invert();
291 if (is_just_gamma(dstFn)) {
292 pipeline.append(SkRasterPipeline::gamma, &dstFn.fG);
293 } else {
294 pipeline.append(SkRasterPipeline::parametric_r, &dstFn);
295 pipeline.append(SkRasterPipeline::parametric_g, &dstFn);
296 pipeline.append(SkRasterPipeline::parametric_b, &dstFn);
297 }
298 }
299
300 if (kUnpremul_SkAlphaType == premulState && kPremul_SkAlphaType == dat &&
301 SkTransferFunctionBehavior::kIgnore == behavior)
302 {
303 pipeline.append(SkRasterPipeline::premul);
304 premulState = kPremul_SkAlphaType;
305 }
306
307 // The final premul state must equal the dst alpha type. Note that if we are "converting"
308 // opaque to another alpha type, there's no need to worry about multiplication.
309 SkASSERT(premulState == dat || kOpaque_SkAlphaType == srcInfo.alphaType());
310
311 // We'll dither if we're decreasing precision below 32-bit.
312 float dither_rate = 0.0f;
313 if (srcInfo.bytesPerPixel() > dstInfo.bytesPerPixel()) {
314 switch (dstInfo.colorType()) {
315 case kRGB_565_SkColorType: dither_rate = 1/63.0f; break;
316 case kARGB_4444_SkColorType: dither_rate = 1/15.0f; break;
317 default: dither_rate = 0.0f; break;
318 }
319 }
320 if (dither_rate > 0) {
321 pipeline.append(SkRasterPipeline::dither, &dither_rate);
322 }
323
324 switch (dstInfo.colorType()) {
325 case kRGBA_8888_SkColorType:
326 pipeline.append(SkRasterPipeline::store_8888, &dst);
327 break;
328 case kBGRA_8888_SkColorType:
329 pipeline.append(SkRasterPipeline::store_bgra, &dst);
330 break;
331 case kRGB_565_SkColorType:
332 pipeline.append(SkRasterPipeline::store_565, &dst);
333 break;
334 case kRGBA_F16_SkColorType:
335 pipeline.append(SkRasterPipeline::store_f16, &dst);
336 break;
337 case kARGB_4444_SkColorType:
338 pipeline.append(SkRasterPipeline::store_4444, &dst);
339 break;
340 default:
341 SkASSERT(false);
342 break;
343 }
344
345 pipeline.run(0,0, srcInfo.width(), srcInfo.height());
346 }
347
SkConvertPixels(const SkImageInfo & dstInfo,void * dstPixels,size_t dstRB,const SkImageInfo & srcInfo,const void * srcPixels,size_t srcRB,SkColorTable * ctable,SkTransferFunctionBehavior behavior)348 void SkConvertPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
349 const SkImageInfo& srcInfo, const void* srcPixels, size_t srcRB,
350 SkColorTable* ctable, SkTransferFunctionBehavior behavior) {
351 SkASSERT(dstInfo.dimensions() == srcInfo.dimensions());
352 SkASSERT(SkImageInfoValidConversion(dstInfo, srcInfo));
353
354 // Fast Path 1: The memcpy() case.
355 if (can_memcpy(dstInfo, srcInfo)) {
356 SkRectMemcpy(dstPixels, dstRB, srcPixels, srcRB, dstInfo.minRowBytes(), dstInfo.height());
357 return;
358 }
359
360 const bool isColorAware = dstInfo.colorSpace();
361 SkASSERT(srcInfo.colorSpace() || !isColorAware);
362
363 // Fast Path 2: Simple swizzles and premuls.
364 if (4 == srcInfo.bytesPerPixel() && 4 == dstInfo.bytesPerPixel() && !isColorAware) {
365 swizzle_and_multiply(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, srcRB);
366 return;
367 }
368
369 // Fast Path 3: Color space xform.
370 if (isColorAware && optimized_color_xform(dstInfo, srcInfo, behavior)) {
371 apply_color_xform(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, srcRB, behavior);
372 return;
373 }
374
375 // Fast Path 4: Alpha 8 dsts.
376 if (kAlpha_8_SkColorType == dstInfo.colorType()) {
377 convert_to_alpha8((uint8_t*) dstPixels, dstRB, srcInfo, srcPixels, srcRB, ctable);
378 return;
379 }
380
381 // Default: Use the pipeline.
382 convert_with_pipeline(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, srcRB, isColorAware,
383 behavior);
384 }
385