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