• 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 "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