blob: 6bf347419f1178d276e68af610a8d8346fc7da9e [file] [log] [blame]
epoger@google.com4ce738b2012-11-16 18:44:18 +00001/*
2 * Copyright 2012 The Android Open Source Project
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/**
9 * Functions to transform scanlines between packed-pixel formats.
10 */
11
12#include "SkBitmap.h"
13#include "SkColor.h"
14#include "SkColorPriv.h"
15#include "SkPreConfig.h"
Matt Sarett84014f02017-01-10 11:28:54 -050016#include "SkRasterPipeline.h"
epoger@google.com4ce738b2012-11-16 18:44:18 +000017#include "SkUnPreMultiply.h"
18
19/**
20 * Function template for transforming scanlines.
21 * Transform 'width' pixels from 'src' buffer into 'dst' buffer,
22 * repacking color channel data as appropriate for the given transformation.
msarettf17b71f2016-09-12 14:30:03 -070023 * 'bpp' is bytes per pixel in the 'src' buffer.
epoger@google.com4ce738b2012-11-16 18:44:18 +000024 */
msarettf17b71f2016-09-12 14:30:03 -070025typedef void (*transform_scanline_proc)(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
Matt Sarett62bb2802017-01-23 12:28:02 -050026 int width, int bpp, const SkPMColor* colors);
epoger@google.com4ce738b2012-11-16 18:44:18 +000027
28/**
29 * Identity transformation: just copy bytes from src to dst.
30 */
Matt Sarett62bb2802017-01-23 12:28:02 -050031static inline void transform_scanline_memcpy(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
32 int width, int bpp, const SkPMColor*) {
msarettf17b71f2016-09-12 14:30:03 -070033 memcpy(dst, src, width * bpp);
epoger@google.com4ce738b2012-11-16 18:44:18 +000034}
35
Matt Sarett62bb2802017-01-23 12:28:02 -050036static inline void transform_scanline_index8_opaque(char* SK_RESTRICT dst,
37 const char* SK_RESTRICT src, int width, int,
38 const SkPMColor* colors) {
39 for (int i = 0; i < width; i++) {
40 const uint32_t c = colors[(uint8_t)*src++];
41 dst[0] = SkGetPackedR32(c);
42 dst[1] = SkGetPackedG32(c);
43 dst[2] = SkGetPackedB32(c);
44 dst += 3;
45 }
46}
47
48static inline void transform_scanline_index8_unpremul(char* SK_RESTRICT dst,
49 const char* SK_RESTRICT src, int width, int,
50 const SkPMColor* colors) {
51 uint32_t* SK_RESTRICT dst32 = (uint32_t*) dst;
52 for (int i = 0; i < width; i++) {
53 // This function swizzles R and B on platforms where SkPMColor is BGRA. This is
54 // exactly what we want.
55 dst32[i] = SkSwizzle_RGBA_to_PMColor(colors[(uint8_t)*src++]);
56 }
57}
58
59static inline void transform_scanline_gray(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
60 int width, int, const SkPMColor* colors) {
61 for (int i = 0; i < width; i++) {
62 const uint8_t g = (uint8_t) *src++;
63 dst[0] = g;
64 dst[1] = g;
65 dst[2] = g;
66 dst += 3;
67 }
68}
69
epoger@google.com4ce738b2012-11-16 18:44:18 +000070/**
71 * Transform from kRGB_565_Config to 3-bytes-per-pixel RGB.
72 * Alpha channel data is not present in kRGB_565_Config format, so there is no
73 * alpha channel data to preserve.
74 */
Matt Sarett62bb2802017-01-23 12:28:02 -050075static inline void transform_scanline_565(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
76 int width, int, const SkPMColor*) {
msarettf17b71f2016-09-12 14:30:03 -070077 const uint16_t* srcP = (const uint16_t*)src;
epoger@google.com4ce738b2012-11-16 18:44:18 +000078 for (int i = 0; i < width; i++) {
79 unsigned c = *srcP++;
80 *dst++ = SkPacked16ToR32(c);
81 *dst++ = SkPacked16ToG32(c);
82 *dst++ = SkPacked16ToB32(c);
83 }
84}
85
86/**
msarettf17b71f2016-09-12 14:30:03 -070087 * Transform from kRGBA_8888_SkColorType to 3-bytes-per-pixel RGB.
88 * Alpha channel data is abandoned.
epoger@google.com4ce738b2012-11-16 18:44:18 +000089 */
Matt Sarett62bb2802017-01-23 12:28:02 -050090static inline void transform_scanline_RGBX(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
91 int width, int, const SkPMColor*) {
msarettf17b71f2016-09-12 14:30:03 -070092 const uint32_t* srcP = (const SkPMColor*)src;
epoger@google.com4ce738b2012-11-16 18:44:18 +000093 for (int i = 0; i < width; i++) {
msarettf17b71f2016-09-12 14:30:03 -070094 uint32_t c = *srcP++;
95 *dst++ = (c >> 0) & 0xFF;
96 *dst++ = (c >> 8) & 0xFF;
97 *dst++ = (c >> 16) & 0xFF;
98 }
99}
100
101/**
102 * Transform from kBGRA_8888_SkColorType to 3-bytes-per-pixel RGB.
103 * Alpha channel data is abandoned.
104 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500105static inline void transform_scanline_BGRX(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
106 int width, int, const SkPMColor*) {
msarettf17b71f2016-09-12 14:30:03 -0700107 const uint32_t* srcP = (const SkPMColor*)src;
108 for (int i = 0; i < width; i++) {
109 uint32_t c = *srcP++;
110 *dst++ = (c >> 16) & 0xFF;
111 *dst++ = (c >> 8) & 0xFF;
112 *dst++ = (c >> 0) & 0xFF;
epoger@google.com4ce738b2012-11-16 18:44:18 +0000113 }
114}
115
116/**
117 * Transform from kARGB_4444_Config to 3-bytes-per-pixel RGB.
118 * Alpha channel data, if any, is abandoned.
119 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500120static inline void transform_scanline_444(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
121 int width, int, const SkPMColor*) {
msarettf17b71f2016-09-12 14:30:03 -0700122 const SkPMColor16* srcP = (const SkPMColor16*)src;
epoger@google.com4ce738b2012-11-16 18:44:18 +0000123 for (int i = 0; i < width; i++) {
124 SkPMColor16 c = *srcP++;
125 *dst++ = SkPacked4444ToR32(c);
126 *dst++ = SkPacked4444ToG32(c);
127 *dst++ = SkPacked4444ToB32(c);
128 }
129}
130
msarettf17b71f2016-09-12 14:30:03 -0700131template <bool kIsRGBA>
132static inline void transform_scanline_unpremultiply(char* SK_RESTRICT dst,
Matt Sarett1da27ef2017-01-19 17:14:07 -0500133 const char* SK_RESTRICT src, int width) {
msarettf17b71f2016-09-12 14:30:03 -0700134 const uint32_t* srcP = (const SkPMColor*)src;
135 const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleTable();
epoger@google.com4ce738b2012-11-16 18:44:18 +0000136
137 for (int i = 0; i < width; i++) {
msarettf17b71f2016-09-12 14:30:03 -0700138 uint32_t c = *srcP++;
139 unsigned r, g, b, a;
140 if (kIsRGBA) {
141 r = (c >> 0) & 0xFF;
142 g = (c >> 8) & 0xFF;
143 b = (c >> 16) & 0xFF;
144 a = (c >> 24) & 0xFF;
145 } else {
146 r = (c >> 16) & 0xFF;
147 g = (c >> 8) & 0xFF;
148 b = (c >> 0) & 0xFF;
149 a = (c >> 24) & 0xFF;
150 }
epoger@google.com4ce738b2012-11-16 18:44:18 +0000151
152 if (0 != a && 255 != a) {
153 SkUnPreMultiply::Scale scale = table[a];
154 r = SkUnPreMultiply::ApplyScale(scale, r);
155 g = SkUnPreMultiply::ApplyScale(scale, g);
156 b = SkUnPreMultiply::ApplyScale(scale, b);
157 }
158 *dst++ = r;
159 *dst++ = g;
160 *dst++ = b;
161 *dst++ = a;
162 }
163}
164
165/**
Matt Sarett84014f02017-01-10 11:28:54 -0500166 * Transform from legacy kPremul, kRGBA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
167 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500168static inline void transform_scanline_rgbA(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
169 int width, int, const SkPMColor*) {
Matt Sarett1da27ef2017-01-19 17:14:07 -0500170 transform_scanline_unpremultiply<true>(dst, src, width);
Matt Sarett84014f02017-01-10 11:28:54 -0500171}
172
173/**
174 * Transform from legacy kPremul, kBGRA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
175 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500176static inline void transform_scanline_bgrA(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
177 int width, int, const SkPMColor*) {
Matt Sarett1da27ef2017-01-19 17:14:07 -0500178 transform_scanline_unpremultiply<false>(dst, src, width);
Matt Sarett84014f02017-01-10 11:28:54 -0500179}
180
181template <bool kIsRGBA>
Matt Sarett1da27ef2017-01-19 17:14:07 -0500182static inline void transform_scanline_unpremultiply_sRGB(void* dst, const void* src, int width) {
Matt Sarett84014f02017-01-10 11:28:54 -0500183 SkRasterPipeline p;
184 p.append(SkRasterPipeline::load_8888, &src);
185 if (!kIsRGBA) {
186 p.append(SkRasterPipeline::swap_rb);
187 }
188
189 p.append_from_srgb(kPremul_SkAlphaType);
190 p.append(SkRasterPipeline::unpremul);
191 p.append(SkRasterPipeline::to_srgb);
192 p.append(SkRasterPipeline::store_8888, &dst);
Mike Klein319ba3d2017-01-20 15:11:54 -0500193 p.run(0, width);
Matt Sarett84014f02017-01-10 11:28:54 -0500194}
195
196/**
msarettf17b71f2016-09-12 14:30:03 -0700197 * Transform from kPremul, kRGBA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
198 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500199static inline void transform_scanline_srgbA(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
200 int width, int, const SkPMColor*) {
Matt Sarett1da27ef2017-01-19 17:14:07 -0500201 transform_scanline_unpremultiply_sRGB<true>(dst, src, width);
msarettf17b71f2016-09-12 14:30:03 -0700202}
203
204/**
205 * Transform from kPremul, kBGRA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
206 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500207static inline void transform_scanline_sbgrA(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
208 int width, int, const SkPMColor*) {
Matt Sarett1da27ef2017-01-19 17:14:07 -0500209 transform_scanline_unpremultiply_sRGB<false>(dst, src, width);
msarettf17b71f2016-09-12 14:30:03 -0700210}
211
212/**
213 * Transform from kUnpremul, kBGRA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
214 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500215static inline void transform_scanline_BGRA(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
216 int width, int, const SkPMColor*) {
msarettf17b71f2016-09-12 14:30:03 -0700217 const uint32_t* srcP = (const SkPMColor*)src;
218 for (int i = 0; i < width; i++) {
219 uint32_t c = *srcP++;
220 *dst++ = (c >> 16) & 0xFF;
221 *dst++ = (c >> 8) & 0xFF;
222 *dst++ = (c >> 0) & 0xFF;
223 *dst++ = (c >> 24) & 0xFF;
224 }
225}
226
227/**
epoger@google.com4ce738b2012-11-16 18:44:18 +0000228 * Transform from kARGB_8888_Config to 4-bytes-per-pixel RGBA,
229 * with scaling of RGB based on alpha channel.
230 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500231static inline void transform_scanline_4444(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
232 int width, int, const SkPMColor*) {
msarettf17b71f2016-09-12 14:30:03 -0700233 const SkPMColor16* srcP = (const SkPMColor16*)src;
234 const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleTable();
epoger@google.com4ce738b2012-11-16 18:44:18 +0000235
236 for (int i = 0; i < width; i++) {
237 SkPMColor16 c = *srcP++;
238 unsigned a = SkPacked4444ToA32(c);
239 unsigned r = SkPacked4444ToR32(c);
240 unsigned g = SkPacked4444ToG32(c);
241 unsigned b = SkPacked4444ToB32(c);
242
243 if (0 != a && 255 != a) {
244 SkUnPreMultiply::Scale scale = table[a];
245 r = SkUnPreMultiply::ApplyScale(scale, r);
246 g = SkUnPreMultiply::ApplyScale(scale, g);
247 b = SkUnPreMultiply::ApplyScale(scale, b);
248 }
249 *dst++ = r;
250 *dst++ = g;
251 *dst++ = b;
252 *dst++ = a;
253 }
254}
Matt Sarett1da27ef2017-01-19 17:14:07 -0500255
256/**
Matt Sarett55213562017-01-23 19:37:37 -0500257 * Transform from kRGBA_F16 to 8-bytes-per-pixel RGBA.
Matt Sarett1da27ef2017-01-19 17:14:07 -0500258 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500259static inline void transform_scanline_F16(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
260 int width, int, const SkPMColor*) {
Matt Sarett1da27ef2017-01-19 17:14:07 -0500261 SkRasterPipeline p;
262 p.append(SkRasterPipeline::load_f16, (const void**) &src);
263 p.append(SkRasterPipeline::to_srgb);
264 p.append(SkRasterPipeline::store_u16_be, (void**) &dst);
Mike Klein319ba3d2017-01-20 15:11:54 -0500265 p.run(0, width);
Matt Sarett1da27ef2017-01-19 17:14:07 -0500266}
267
268/**
Matt Sarett55213562017-01-23 19:37:37 -0500269 * Transform from kPremul, kRGBA_F16 to 8-bytes-per-pixel RGBA.
Matt Sarett1da27ef2017-01-19 17:14:07 -0500270 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500271static inline void transform_scanline_F16_premul(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
272 int width, int, const SkPMColor*) {
Matt Sarett1da27ef2017-01-19 17:14:07 -0500273 SkRasterPipeline p;
274 p.append(SkRasterPipeline::load_f16, (const void**) &src);
275 p.append(SkRasterPipeline::unpremul);
276 p.append(SkRasterPipeline::to_srgb);
277 p.append(SkRasterPipeline::store_u16_be, (void**) &dst);
Mike Klein319ba3d2017-01-20 15:11:54 -0500278 p.run(0, width);
Matt Sarett1da27ef2017-01-19 17:14:07 -0500279}
Matt Sarett55213562017-01-23 19:37:37 -0500280
281/**
282 * Transform from kRGBA_F16 to 4-bytes-per-pixel RGBA.
283 */
284static inline void transform_scanline_F16_to_8888(char* SK_RESTRICT dst,
285 const char* SK_RESTRICT src, int width, int,
286 const SkPMColor*) {
287 SkRasterPipeline p;
288 p.append(SkRasterPipeline::load_f16, (const void**) &src);
289 p.append(SkRasterPipeline::to_srgb);
290 p.append(SkRasterPipeline::store_8888, (void**) &dst);
291 p.run(0, width);
292}
293
294/**
295 * Transform from kPremul, kRGBA_F16 to 4-bytes-per-pixel RGBA.
296 */
297static inline void transform_scanline_F16_premul_to_8888(char* SK_RESTRICT dst,
298 const char* SK_RESTRICT src, int width,
299 int, const SkPMColor*) {
300 SkRasterPipeline p;
301 p.append(SkRasterPipeline::load_f16, (const void**) &src);
302 p.append(SkRasterPipeline::unpremul);
303 p.append(SkRasterPipeline::to_srgb);
304 p.append(SkRasterPipeline::store_8888, (void**) &dst);
305 p.run(0, width);
306}