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