2 * Copyright 2014 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #include "SkColorSpaceXform_Base.h"
9 #include "SkColorSpaceXformPriv.h"
10 #include "SkColorTable.h"
11 #include "SkConvertPixels.h"
13 #include "SkImageInfoPriv.h"
15 #include "SkPM4fPriv.h"
16 #include "SkRasterPipeline.h"
17 #include "SkUnPreMultiply.h"
18 #include "SkUnPreMultiplyPriv.h"
19 #include "../jumper/SkJumper.h"
21 // Fast Path 1: The memcpy() case.
22 static inline bool can_memcpy(const SkImageInfo& dstInfo, const SkImageInfo& srcInfo) {
23 if (dstInfo.colorType() != srcInfo.colorType()) {
27 if (kAlpha_8_SkColorType == dstInfo.colorType()) {
31 if (dstInfo.alphaType() != srcInfo.alphaType() &&
32 kOpaque_SkAlphaType != dstInfo.alphaType() &&
33 kOpaque_SkAlphaType != srcInfo.alphaType())
35 // We need to premultiply or unpremultiply.
39 return !dstInfo.colorSpace() ||
40 SkColorSpace::Equals(dstInfo.colorSpace(), srcInfo.colorSpace());
43 // Fast Path 2: Simple swizzles and premuls.
50 template <bool kSwapRB>
51 static void wrap_unpremultiply(uint32_t* dst, const void* src, int count) {
52 SkUnpremultiplyRow<kSwapRB>(dst, (const uint32_t*) src, count);
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())
63 alphaVerb = kPremul_AlphaVerb;
64 } else if (kUnpremul_SkAlphaType == dstInfo.alphaType() &&
65 kPremul_SkAlphaType == srcInfo.alphaType()) {
66 alphaVerb = kUnpremul_AlphaVerb;
70 case kNothing_AlphaVerb:
71 // If we do not need to swap or multiply, we should hit the memcpy case.
73 proc = SkOpts::RGBA_to_BGRA;
75 case kPremul_AlphaVerb:
76 proc = swapRB ? SkOpts::RGBA_to_bgrA : SkOpts::RGBA_to_rgbA;
78 case kUnpremul_AlphaVerb:
79 proc = swapRB ? wrap_unpremultiply<true> : wrap_unpremultiply<false>;
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);
90 // Fast Path 3: Color space xform.
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)) {
101 switch (dstInfo.colorType()) {
102 case kRGBA_8888_SkColorType:
103 case kBGRA_8888_SkColorType:
104 case kRGBA_F16_SkColorType:
110 switch (srcInfo.colorType()) {
111 case kRGBA_8888_SkColorType:
112 case kBGRA_8888_SkColorType:
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;
131 case kPremul_SkAlphaType:
132 SkASSERT(kPremul_SkAlphaType == dstInfo.alphaType());
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;
138 case kUnpremul_SkAlphaType:
139 SkASSERT(kPremul_SkAlphaType == dstInfo.alphaType() ||
140 kUnpremul_SkAlphaType == dstInfo.alphaType());
142 xformAlpha = dstInfo.alphaType();
146 xformAlpha = kUnpremul_SkAlphaType;
150 std::unique_ptr<SkColorSpaceXform> xform =
151 SkColorSpaceXform_Base::New(srcInfo.colorSpace(), dstInfo.colorSpace(), behavior);
154 for (int y = 0; y < dstInfo.height(); y++) {
155 SkAssertResult(xform->apply(dstFormat, dstPixels, srcFormat, srcPixels, dstInfo.width(),
157 dstPixels = SkTAddOffset<void>(dstPixels, dstRB);
158 srcPixels = SkTAddOffset<const void>(srcPixels, srcRB);
162 // Fast Path 4: Index 8 sources.
163 template <typename T>
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) {
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,
175 for (int y = 0; y < dstInfo.height(); y++) {
176 for (int x = 0; x < dstInfo.width(); x++) {
177 dstPixels[x] = dstCTable[srcPixels[x]];
179 dstPixels = SkTAddOffset<T>(dstPixels, dstRB);
180 srcPixels = SkTAddOffset<const uint8_t>(srcPixels, srcRB);
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,
192 case kRGB_565_SkColorType:
193 case kARGB_4444_SkColorType:
194 do_index8(dstInfo, (uint16_t*) dstPixels, dstRB, srcInfo, srcPixels, srcRB, ctable,
197 case kRGBA_8888_SkColorType:
198 case kBGRA_8888_SkColorType:
199 do_index8(dstInfo, (uint32_t*) dstPixels, dstRB, srcInfo, srcPixels, srcRB, ctable,
202 case kRGBA_F16_SkColorType:
203 do_index8(dstInfo, (uint64_t*) dstPixels, dstRB, srcInfo, srcPixels, srcRB, ctable,
211 // Fast Path 5: Alpha 8 dsts.
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);
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;
230 dst = SkTAddOffset<uint8_t>(dst, dstRB);
231 src32 = SkTAddOffset<const uint32_t>(src32, srcRB);
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]);
241 dst = SkTAddOffset<uint8_t>(dst, dstRB);
242 src16 = SkTAddOffset<const uint16_t>(src16, srcRB);
246 case kIndex_8_SkColorType: {
248 const uint32_t* table = ctable->readColors();
249 auto src8 = (const uint8_t*)src;
250 for (int y = 0; y < srcInfo.height(); y++) {
251 for (int x = 0; x < srcInfo.width(); x++) {
252 dst[x] = table[src8[x]] >> 24;
254 dst = SkTAddOffset<uint8_t>(dst, dstRB);
255 src8 = SkTAddOffset<const uint8_t>(src8, srcRB);
259 case kRGBA_F16_SkColorType: {
260 auto src64 = (const uint64_t*) src;
261 for (int y = 0; y < srcInfo.height(); y++) {
262 for (int x = 0; x < srcInfo.width(); x++) {
263 dst[x] = (uint8_t) (255.0f * SkHalfToFloat(src64[x] >> 48));
265 dst = SkTAddOffset<uint8_t>(dst, dstRB);
266 src64 = SkTAddOffset<const uint64_t>(src64, srcRB);
276 // Default: Use the pipeline.
277 static void convert_with_pipeline(const SkImageInfo& dstInfo, void* dstRow, size_t dstRB,
278 const SkImageInfo& srcInfo, const void* srcRow, size_t srcRB,
279 bool isColorAware, SkTransferFunctionBehavior behavior) {
280 SkRasterPipeline_<256> pipeline;
281 switch (srcInfo.colorType()) {
282 case kRGBA_8888_SkColorType:
283 pipeline.append(SkRasterPipeline::load_8888, &srcRow);
285 case kBGRA_8888_SkColorType:
286 pipeline.append(SkRasterPipeline::load_8888, &srcRow);
287 pipeline.append(SkRasterPipeline::swap_rb);
289 case kRGB_565_SkColorType:
290 pipeline.append(SkRasterPipeline::load_565, &srcRow);
292 case kRGBA_F16_SkColorType:
293 pipeline.append(SkRasterPipeline::load_f16, &srcRow);
295 case kGray_8_SkColorType:
296 pipeline.append(SkRasterPipeline::load_g8, &srcRow);
298 case kARGB_4444_SkColorType:
299 pipeline.append(SkRasterPipeline::load_4444, &srcRow);
306 SkAlphaType premulState = srcInfo.alphaType();
307 if (kPremul_SkAlphaType == premulState && SkTransferFunctionBehavior::kIgnore == behavior) {
308 pipeline.append(SkRasterPipeline::unpremul);
309 premulState = kUnpremul_SkAlphaType;
312 if (isColorAware && srcInfo.gammaCloseToSRGB()) {
313 pipeline.append_from_srgb(srcInfo.alphaType());
314 } else if (isColorAware && !srcInfo.colorSpace()->gammaIsLinear()) {
315 SkColorSpaceTransferFn fn;
316 SkAssertResult(srcInfo.colorSpace()->isNumericalTransferFn(&fn));
317 pipeline.append(SkRasterPipeline::parametric_r, &fn);
318 pipeline.append(SkRasterPipeline::parametric_g, &fn);
319 pipeline.append(SkRasterPipeline::parametric_b, &fn);
324 append_gamut_transform(&pipeline, matrix, srcInfo.colorSpace(), dstInfo.colorSpace(),
328 SkAlphaType dat = dstInfo.alphaType();
329 if (SkTransferFunctionBehavior::kRespect == behavior) {
330 if (kPremul_SkAlphaType == premulState && kUnpremul_SkAlphaType == dat) {
331 pipeline.append(SkRasterPipeline::unpremul);
332 premulState = kUnpremul_SkAlphaType;
333 } else if (kUnpremul_SkAlphaType == premulState && kPremul_SkAlphaType == dat) {
334 pipeline.append(SkRasterPipeline::premul);
335 premulState = kPremul_SkAlphaType;
339 if (isColorAware && dstInfo.gammaCloseToSRGB()) {
340 pipeline.append(SkRasterPipeline::to_srgb);
341 } else if (isColorAware && !dstInfo.colorSpace()->gammaIsLinear()) {
342 SkColorSpaceTransferFn fn;
343 SkAssertResult(dstInfo.colorSpace()->isNumericalTransferFn(&fn));
345 pipeline.append(SkRasterPipeline::parametric_r, &fn);
346 pipeline.append(SkRasterPipeline::parametric_g, &fn);
347 pipeline.append(SkRasterPipeline::parametric_b, &fn);
350 if (kUnpremul_SkAlphaType == premulState && kPremul_SkAlphaType == dat &&
351 SkTransferFunctionBehavior::kIgnore == behavior)
353 pipeline.append(SkRasterPipeline::premul);
354 premulState = kPremul_SkAlphaType;
357 // The final premul state must equal the dst alpha type. Note that if we are "converting"
358 // opaque to another alpha type, there's no need to worry about multiplication.
359 SkASSERT(premulState == dat || kOpaque_SkAlphaType == srcInfo.alphaType());
361 // We'll dither if we're decreasing precision below 32-bit.
363 SkJumper_DitherCtx dither = {&y, 0.0f};
364 if (srcInfo.bytesPerPixel() > dstInfo.bytesPerPixel()) {
365 switch (dstInfo.colorType()) {
366 case kRGB_565_SkColorType: dither.rate = 1/63.0f; break;
367 case kARGB_4444_SkColorType: dither.rate = 1/15.0f; break;
368 default: dither.rate = 0.0f; break;
371 if (dither.rate > 0) {
372 pipeline.append(SkRasterPipeline::dither, &dither);
375 switch (dstInfo.colorType()) {
376 case kRGBA_8888_SkColorType:
377 pipeline.append(SkRasterPipeline::store_8888, &dstRow);
379 case kBGRA_8888_SkColorType:
380 pipeline.append(SkRasterPipeline::swap_rb);
381 pipeline.append(SkRasterPipeline::store_8888, &dstRow);
383 case kRGB_565_SkColorType:
384 pipeline.append(SkRasterPipeline::store_565, &dstRow);
386 case kRGBA_F16_SkColorType:
387 pipeline.append(SkRasterPipeline::store_f16, &dstRow);
389 case kARGB_4444_SkColorType:
390 pipeline.append(SkRasterPipeline::store_4444, &dstRow);
397 // This y is declared above when handling dither (which needs to know y).
398 for (y = 0; y < srcInfo.height(); ++y) {
399 pipeline.run(0,srcInfo.width());
400 // The pipeline has pointers to srcRow and dstRow, so we just need to update them in the
401 // loop to move between rows of src/dst.
402 dstRow = SkTAddOffset<void>(dstRow, dstRB);
403 srcRow = SkTAddOffset<const void>(srcRow, srcRB);
407 void SkConvertPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
408 const SkImageInfo& srcInfo, const void* srcPixels, size_t srcRB,
409 SkColorTable* ctable, SkTransferFunctionBehavior behavior) {
410 SkASSERT(dstInfo.dimensions() == srcInfo.dimensions());
411 SkASSERT(SkImageInfoValidConversion(dstInfo, srcInfo));
413 // Fast Path 1: The memcpy() case.
414 if (can_memcpy(dstInfo, srcInfo)) {
415 SkRectMemcpy(dstPixels, dstRB, srcPixels, srcRB, dstInfo.minRowBytes(), dstInfo.height());
419 const bool isColorAware = dstInfo.colorSpace();
420 SkASSERT(srcInfo.colorSpace() || !isColorAware);
422 // Fast Path 2: Simple swizzles and premuls.
423 if (4 == srcInfo.bytesPerPixel() && 4 == dstInfo.bytesPerPixel() && !isColorAware) {
424 swizzle_and_multiply(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, srcRB);
428 // Fast Path 3: Color space xform.
429 if (isColorAware && optimized_color_xform(dstInfo, srcInfo, behavior)) {
430 apply_color_xform(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, srcRB, behavior);
434 // Fast Path 4: Index 8 sources.
435 if (kIndex_8_SkColorType == srcInfo.colorType()) {
437 convert_from_index8(dstInfo, dstPixels, dstRB, srcInfo, (const uint8_t*) srcPixels, srcRB,
442 // Fast Path 5: Alpha 8 dsts.
443 if (kAlpha_8_SkColorType == dstInfo.colorType()) {
444 convert_to_alpha8((uint8_t*) dstPixels, dstRB, srcInfo, srcPixels, srcRB, ctable);
448 // Default: Use the pipeline.
449 convert_with_pipeline(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, srcRB, isColorAware,