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.
23static 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.
45enum AlphaVerb {
46    kNothing_AlphaVerb,
47    kPremul_AlphaVerb,
48    kUnpremul_AlphaVerb,
49};
50
51template <bool kSwapRB>
52static void wrap_unpremultiply(uint32_t* dst, const void* src, int count) {
53    SkUnpremultiplyRow<kSwapRB>(dst, (const uint32_t*) src, count);
54}
55
56void 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.
92static 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
122static 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.
164static 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.
216static 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
348void 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