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