• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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