blob: 1c263487bd70ad651f15f6f789a858df94c2f21d [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,
26 int width, int bpp);
epoger@google.com4ce738b2012-11-16 18:44:18 +000027
28/**
29 * Identity transformation: just copy bytes from src to dst.
30 */
msarettf17b71f2016-09-12 14:30:03 -070031static void transform_scanline_memcpy(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
32 int width, int bpp) {
33 memcpy(dst, src, width * bpp);
epoger@google.com4ce738b2012-11-16 18:44:18 +000034}
35
36/**
37 * Transform from kRGB_565_Config to 3-bytes-per-pixel RGB.
38 * Alpha channel data is not present in kRGB_565_Config format, so there is no
39 * alpha channel data to preserve.
40 */
msarettf17b71f2016-09-12 14:30:03 -070041static void transform_scanline_565(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
42 int width, int) {
43 const uint16_t* srcP = (const uint16_t*)src;
epoger@google.com4ce738b2012-11-16 18:44:18 +000044 for (int i = 0; i < width; i++) {
45 unsigned c = *srcP++;
46 *dst++ = SkPacked16ToR32(c);
47 *dst++ = SkPacked16ToG32(c);
48 *dst++ = SkPacked16ToB32(c);
49 }
50}
51
52/**
msarettf17b71f2016-09-12 14:30:03 -070053 * Transform from kRGBA_8888_SkColorType to 3-bytes-per-pixel RGB.
54 * Alpha channel data is abandoned.
epoger@google.com4ce738b2012-11-16 18:44:18 +000055 */
msarettf17b71f2016-09-12 14:30:03 -070056static void transform_scanline_RGBX(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
57 int width, int) {
58 const uint32_t* srcP = (const SkPMColor*)src;
epoger@google.com4ce738b2012-11-16 18:44:18 +000059 for (int i = 0; i < width; i++) {
msarettf17b71f2016-09-12 14:30:03 -070060 uint32_t c = *srcP++;
61 *dst++ = (c >> 0) & 0xFF;
62 *dst++ = (c >> 8) & 0xFF;
63 *dst++ = (c >> 16) & 0xFF;
64 }
65}
66
67/**
68 * Transform from kBGRA_8888_SkColorType to 3-bytes-per-pixel RGB.
69 * Alpha channel data is abandoned.
70 */
71static void transform_scanline_BGRX(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
72 int width, int) {
73 const uint32_t* srcP = (const SkPMColor*)src;
74 for (int i = 0; i < width; i++) {
75 uint32_t c = *srcP++;
76 *dst++ = (c >> 16) & 0xFF;
77 *dst++ = (c >> 8) & 0xFF;
78 *dst++ = (c >> 0) & 0xFF;
epoger@google.com4ce738b2012-11-16 18:44:18 +000079 }
80}
81
82/**
83 * Transform from kARGB_4444_Config to 3-bytes-per-pixel RGB.
84 * Alpha channel data, if any, is abandoned.
85 */
msarettf17b71f2016-09-12 14:30:03 -070086static void transform_scanline_444(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
87 int width, int) {
88 const SkPMColor16* srcP = (const SkPMColor16*)src;
epoger@google.com4ce738b2012-11-16 18:44:18 +000089 for (int i = 0; i < width; i++) {
90 SkPMColor16 c = *srcP++;
91 *dst++ = SkPacked4444ToR32(c);
92 *dst++ = SkPacked4444ToG32(c);
93 *dst++ = SkPacked4444ToB32(c);
94 }
95}
96
msarettf17b71f2016-09-12 14:30:03 -070097template <bool kIsRGBA>
98static inline void transform_scanline_unpremultiply(char* SK_RESTRICT dst,
Matt Sarett1da27ef2017-01-19 17:14:07 -050099 const char* SK_RESTRICT src, int width) {
msarettf17b71f2016-09-12 14:30:03 -0700100 const uint32_t* srcP = (const SkPMColor*)src;
101 const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleTable();
epoger@google.com4ce738b2012-11-16 18:44:18 +0000102
103 for (int i = 0; i < width; i++) {
msarettf17b71f2016-09-12 14:30:03 -0700104 uint32_t c = *srcP++;
105 unsigned r, g, b, a;
106 if (kIsRGBA) {
107 r = (c >> 0) & 0xFF;
108 g = (c >> 8) & 0xFF;
109 b = (c >> 16) & 0xFF;
110 a = (c >> 24) & 0xFF;
111 } else {
112 r = (c >> 16) & 0xFF;
113 g = (c >> 8) & 0xFF;
114 b = (c >> 0) & 0xFF;
115 a = (c >> 24) & 0xFF;
116 }
epoger@google.com4ce738b2012-11-16 18:44:18 +0000117
118 if (0 != a && 255 != a) {
119 SkUnPreMultiply::Scale scale = table[a];
120 r = SkUnPreMultiply::ApplyScale(scale, r);
121 g = SkUnPreMultiply::ApplyScale(scale, g);
122 b = SkUnPreMultiply::ApplyScale(scale, b);
123 }
124 *dst++ = r;
125 *dst++ = g;
126 *dst++ = b;
127 *dst++ = a;
128 }
129}
130
131/**
Matt Sarett84014f02017-01-10 11:28:54 -0500132 * Transform from legacy kPremul, kRGBA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
133 */
134static void transform_scanline_rgbA(char* SK_RESTRICT dst, const char* SK_RESTRICT src, int width,
Matt Sarett1da27ef2017-01-19 17:14:07 -0500135 int) {
136 transform_scanline_unpremultiply<true>(dst, src, width);
Matt Sarett84014f02017-01-10 11:28:54 -0500137}
138
139/**
140 * Transform from legacy kPremul, kBGRA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
141 */
142static void transform_scanline_bgrA(char* SK_RESTRICT dst, const char* SK_RESTRICT src, int width,
Matt Sarett1da27ef2017-01-19 17:14:07 -0500143 int) {
144 transform_scanline_unpremultiply<false>(dst, src, width);
Matt Sarett84014f02017-01-10 11:28:54 -0500145}
146
147template <bool kIsRGBA>
Matt Sarett1da27ef2017-01-19 17:14:07 -0500148static inline void transform_scanline_unpremultiply_sRGB(void* dst, const void* src, int width) {
Matt Sarett84014f02017-01-10 11:28:54 -0500149 SkRasterPipeline p;
150 p.append(SkRasterPipeline::load_8888, &src);
151 if (!kIsRGBA) {
152 p.append(SkRasterPipeline::swap_rb);
153 }
154
155 p.append_from_srgb(kPremul_SkAlphaType);
156 p.append(SkRasterPipeline::unpremul);
157 p.append(SkRasterPipeline::to_srgb);
158 p.append(SkRasterPipeline::store_8888, &dst);
159 p.run(0, 0, width);
160}
161
162/**
msarettf17b71f2016-09-12 14:30:03 -0700163 * Transform from kPremul, kRGBA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
164 */
Matt Sarett84014f02017-01-10 11:28:54 -0500165static void transform_scanline_srgbA(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
Matt Sarett1da27ef2017-01-19 17:14:07 -0500166 int width, int) {
167 transform_scanline_unpremultiply_sRGB<true>(dst, src, width);
msarettf17b71f2016-09-12 14:30:03 -0700168}
169
170/**
171 * Transform from kPremul, kBGRA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
172 */
Matt Sarett84014f02017-01-10 11:28:54 -0500173static void transform_scanline_sbgrA(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
Matt Sarett1da27ef2017-01-19 17:14:07 -0500174 int width, int) {
175 transform_scanline_unpremultiply_sRGB<false>(dst, src, width);
msarettf17b71f2016-09-12 14:30:03 -0700176}
177
178/**
179 * Transform from kUnpremul, kBGRA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
180 */
181static void transform_scanline_BGRA(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
182 int width, int) {
183 const uint32_t* srcP = (const SkPMColor*)src;
184 for (int i = 0; i < width; i++) {
185 uint32_t c = *srcP++;
186 *dst++ = (c >> 16) & 0xFF;
187 *dst++ = (c >> 8) & 0xFF;
188 *dst++ = (c >> 0) & 0xFF;
189 *dst++ = (c >> 24) & 0xFF;
190 }
191}
192
193/**
epoger@google.com4ce738b2012-11-16 18:44:18 +0000194 * Transform from kARGB_8888_Config to 4-bytes-per-pixel RGBA,
195 * with scaling of RGB based on alpha channel.
196 */
msarettf17b71f2016-09-12 14:30:03 -0700197static void transform_scanline_4444(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
198 int width, int) {
199 const SkPMColor16* srcP = (const SkPMColor16*)src;
200 const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleTable();
epoger@google.com4ce738b2012-11-16 18:44:18 +0000201
202 for (int i = 0; i < width; i++) {
203 SkPMColor16 c = *srcP++;
204 unsigned a = SkPacked4444ToA32(c);
205 unsigned r = SkPacked4444ToR32(c);
206 unsigned g = SkPacked4444ToG32(c);
207 unsigned b = SkPacked4444ToB32(c);
208
209 if (0 != a && 255 != a) {
210 SkUnPreMultiply::Scale scale = table[a];
211 r = SkUnPreMultiply::ApplyScale(scale, r);
212 g = SkUnPreMultiply::ApplyScale(scale, g);
213 b = SkUnPreMultiply::ApplyScale(scale, b);
214 }
215 *dst++ = r;
216 *dst++ = g;
217 *dst++ = b;
218 *dst++ = a;
219 }
220}
Matt Sarett1da27ef2017-01-19 17:14:07 -0500221
222/**
223 * Transform from kRGBA_F16 to 4-bytes-per-pixel RGBA.
224 */
225static void transform_scanline_F16(char* SK_RESTRICT dst, const char* SK_RESTRICT src, int width,
226 int) {
227 SkRasterPipeline p;
228 p.append(SkRasterPipeline::load_f16, (const void**) &src);
229 p.append(SkRasterPipeline::to_srgb);
230 p.append(SkRasterPipeline::store_u16_be, (void**) &dst);
231 p.run(0, 0, width);
232}
233
234/**
235 * Transform from kPremul, kRGBA_F16 to 4-bytes-per-pixel RGBA.
236 */
237static void transform_scanline_F16_premul(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
238 int width, int) {
239 SkRasterPipeline p;
240 p.append(SkRasterPipeline::load_f16, (const void**) &src);
241 p.append(SkRasterPipeline::unpremul);
242 p.append(SkRasterPipeline::to_srgb);
243 p.append(SkRasterPipeline::store_u16_be, (void**) &dst);
244 p.run(0, 0, width);
245}