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 #include "src/core/SkConvertPixels.h"
8
9 #include "include/core/SkColorType.h"
10 #include "include/core/SkImageInfo.h"
11 #include "include/core/SkSize.h"
12 #include "include/private/SkColorData.h"
13 #include "include/private/base/SkAssert.h"
14 #include "include/private/base/SkTPin.h"
15 #include "include/private/base/SkTemplates.h"
16 #include "src/base/SkHalf.h"
17 #include "src/base/SkRectMemcpy.h"
18 #include "src/core/SkColorSpaceXformSteps.h"
19 #include "src/core/SkImageInfoPriv.h"
20 #include "src/core/SkRasterPipeline.h"
21 #include "src/core/SkRasterPipelineOpContexts.h"
22 #include "src/core/SkSwizzlePriv.h"
23
24 #include <cstdint>
25 #include <cstring>
26 #include <initializer_list>
27
rect_memcpy(const SkImageInfo & dstInfo,void * dstPixels,size_t dstRB,const SkImageInfo & srcInfo,const void * srcPixels,size_t srcRB,const SkColorSpaceXformSteps & steps)28 static bool rect_memcpy(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
29 const SkImageInfo& srcInfo, const void* srcPixels, size_t srcRB,
30 const SkColorSpaceXformSteps& steps) {
31 // We can copy the pixels when no color type, alpha type, or color space changes.
32 if (dstInfo.colorType() != srcInfo.colorType()) {
33 return false;
34 }
35 if (dstInfo.colorType() != kAlpha_8_SkColorType
36 && steps.flags.mask() != 0b00000) {
37 return false;
38 }
39
40 SkRectMemcpy(dstPixels, dstRB,
41 srcPixels, srcRB, dstInfo.minRowBytes(), dstInfo.height());
42 return true;
43 }
44
swizzle_or_premul(const SkImageInfo & dstInfo,void * dstPixels,size_t dstRB,const SkImageInfo & srcInfo,const void * srcPixels,size_t srcRB,const SkColorSpaceXformSteps & steps)45 static bool swizzle_or_premul(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
46 const SkImageInfo& srcInfo, const void* srcPixels, size_t srcRB,
47 const SkColorSpaceXformSteps& steps) {
48 auto is_8888 = [](SkColorType ct) {
49 return ct == kRGBA_8888_SkColorType || ct == kBGRA_8888_SkColorType;
50 };
51 if (!is_8888(dstInfo.colorType()) ||
52 !is_8888(srcInfo.colorType()) ||
53 steps.flags.linearize ||
54 steps.flags.gamut_transform ||
55 #if !defined(SK_ARM_HAS_NEON)
56 steps.flags.unpremul ||
57 #endif
58 steps.flags.encode) {
59 return false;
60 }
61
62 const bool swapRB = dstInfo.colorType() != srcInfo.colorType();
63
64 void (*fn)(uint32_t*, const uint32_t*, int) = nullptr;
65
66 if (steps.flags.premul) {
67 fn = swapRB ? SkOpts::RGBA_to_bgrA
68 : SkOpts::RGBA_to_rgbA;
69 } else if (steps.flags.unpremul) {
70 fn = swapRB ? SkOpts::rgbA_to_BGRA
71 : SkOpts::rgbA_to_RGBA;
72 } else {
73 // If we're not swizzling, we ought to have used rect_memcpy().
74 SkASSERT(swapRB);
75 fn = SkOpts::RGBA_to_BGRA;
76 }
77
78 for (int y = 0; y < dstInfo.height(); y++) {
79 fn((uint32_t*)dstPixels, (const uint32_t*)srcPixels, dstInfo.width());
80 dstPixels = SkTAddOffset<void>(dstPixels, dstRB);
81 srcPixels = SkTAddOffset<const void>(srcPixels, srcRB);
82 }
83 return true;
84 }
85
convert_to_alpha8(const SkImageInfo & dstInfo,void * vdst,size_t dstRB,const SkImageInfo & srcInfo,const void * src,size_t srcRB,const SkColorSpaceXformSteps &)86 static bool convert_to_alpha8(const SkImageInfo& dstInfo, void* vdst, size_t dstRB,
87 const SkImageInfo& srcInfo, const void* src, size_t srcRB,
88 const SkColorSpaceXformSteps&) {
89 if (dstInfo.colorType() != kAlpha_8_SkColorType) {
90 return false;
91 }
92 auto dst = (uint8_t*)vdst;
93
94 switch (srcInfo.colorType()) {
95 case kUnknown_SkColorType:
96 case kAlpha_8_SkColorType: {
97 // Unknown should never happen.
98 // Alpha8 should have been handled by rect_memcpy().
99 SkASSERT(false);
100 return false;
101 }
102
103 case kA16_unorm_SkColorType: {
104 auto src16 = (const uint16_t*) src;
105 for (int y = 0; y < srcInfo.height(); y++) {
106 for (int x = 0; x < srcInfo.width(); x++) {
107 dst[x] = src16[x] >> 8;
108 }
109 dst = SkTAddOffset<uint8_t>(dst, dstRB);
110 src16 = SkTAddOffset<const uint16_t>(src16, srcRB);
111 }
112 return true;
113 }
114
115 case kGray_8_SkColorType:
116 case kRGB_565_SkColorType:
117 case kR8G8_unorm_SkColorType:
118 case kR16G16_unorm_SkColorType:
119 case kR16G16_float_SkColorType:
120 case kRGB_888x_SkColorType:
121 case kRGB_101010x_SkColorType:
122 case kBGR_101010x_SkColorType:
123 case kBGR_101010x_XR_SkColorType:
124 case kRGB_F16F16F16x_SkColorType:
125 case kR8_unorm_SkColorType: {
126 for (int y = 0; y < srcInfo.height(); ++y) {
127 memset(dst, 0xFF, srcInfo.width());
128 dst = SkTAddOffset<uint8_t>(dst, dstRB);
129 }
130 return true;
131 }
132
133 case kARGB_4444_SkColorType: {
134 auto src16 = (const uint16_t*) src;
135 for (int y = 0; y < srcInfo.height(); y++) {
136 for (int x = 0; x < srcInfo.width(); x++) {
137 dst[x] = SkPacked4444ToA32(src16[x]);
138 }
139 dst = SkTAddOffset<uint8_t>(dst, dstRB);
140 src16 = SkTAddOffset<const uint16_t>(src16, srcRB);
141 }
142 return true;
143 }
144
145 case kBGRA_8888_SkColorType:
146 case kRGBA_8888_SkColorType:
147 case kSRGBA_8888_SkColorType: {
148 auto src32 = (const uint32_t*) src;
149 for (int y = 0; y < srcInfo.height(); y++) {
150 for (int x = 0; x < srcInfo.width(); x++) {
151 dst[x] = src32[x] >> 24;
152 }
153 dst = SkTAddOffset<uint8_t>(dst, dstRB);
154 src32 = SkTAddOffset<const uint32_t>(src32, srcRB);
155 }
156 return true;
157 }
158
159 case kRGBA_1010102_SkColorType:
160 case kBGRA_1010102_SkColorType: {
161 auto src32 = (const uint32_t*) src;
162 for (int y = 0; y < srcInfo.height(); y++) {
163 for (int x = 0; x < srcInfo.width(); x++) {
164 dst[x] = (src32[x] >> 30) * 0x55;
165 }
166 dst = SkTAddOffset<uint8_t>(dst, dstRB);
167 src32 = SkTAddOffset<const uint32_t>(src32, srcRB);
168 }
169 return true;
170 }
171
172 case kRGBA_F16Norm_SkColorType:
173 case kRGBA_F16_SkColorType: {
174 auto src64 = (const uint64_t*) src;
175 for (int y = 0; y < srcInfo.height(); y++) {
176 for (int x = 0; x < srcInfo.width(); x++) {
177 dst[x] = (uint8_t) (255.0f * SkHalfToFloat(src64[x] >> 48));
178 }
179 dst = SkTAddOffset<uint8_t>(dst, dstRB);
180 src64 = SkTAddOffset<const uint64_t>(src64, srcRB);
181 }
182 return true;
183 }
184
185 case kRGBA_F32_SkColorType: {
186 auto rgba = (const float*)src;
187 for (int y = 0; y < srcInfo.height(); y++) {
188 for (int x = 0; x < srcInfo.width(); x++) {
189 dst[x] = (uint8_t)(255.0f * rgba[4*x+3]);
190 }
191 dst = SkTAddOffset<uint8_t>(dst, dstRB);
192 rgba = SkTAddOffset<const float>(rgba, srcRB);
193 }
194 return true;
195 }
196
197 case kA16_float_SkColorType: {
198 auto srcF16 = (const uint16_t*) src;
199 for (int y = 0; y < srcInfo.height(); y++) {
200 for (int x = 0; x < srcInfo.width(); x++) {
201 dst[x] = (uint8_t) (255.0f * SkHalfToFloat(srcF16[x]));
202 }
203 dst = SkTAddOffset<uint8_t>(dst, dstRB);
204 srcF16 = SkTAddOffset<const uint16_t>(srcF16, srcRB);
205 }
206 return true;
207 }
208
209 case kBGRA_10101010_XR_SkColorType: {
210 auto src64 = (const uint64_t*) src;
211 for (int y = 0; y < srcInfo.height(); y++) {
212 for (int x = 0; x < srcInfo.width(); x++) {
213 static constexpr int64_t kZero = 384;
214 static constexpr int64_t kRange = 510;
215 static constexpr int64_t kMaxU8 = 0xff;
216 static constexpr int64_t kMinU8 = 0x00;
217 static constexpr int64_t kDivisor = kRange / kMaxU8;
218 int64_t raw_alpha = src64[x] >> 54;
219 // f(384) = 0
220 // f(894) = 255
221 int64_t alpha =
222 SkTPin((raw_alpha - kZero) / kDivisor, kMinU8, kMaxU8);
223 dst[x] = static_cast<uint8_t>(alpha);
224 }
225 dst = SkTAddOffset<uint8_t>(dst, dstRB);
226 src64 = SkTAddOffset<const uint64_t>(src64, srcRB);
227 }
228 return true;
229 }
230 case kRGBA_10x6_SkColorType:
231 case kR16G16B16A16_unorm_SkColorType: {
232 auto src64 = (const uint64_t*) src;
233 for (int y = 0; y < srcInfo.height(); y++) {
234 for (int x = 0; x < srcInfo.width(); x++) {
235 dst[x] = (src64[x] >> 48) >> 8;
236 }
237 dst = SkTAddOffset<uint8_t>(dst, dstRB);
238 src64 = SkTAddOffset<const uint64_t>(src64, srcRB);
239 }
240 return true;
241 }
242 }
243 return false;
244 }
245
246 // Default: Use the pipeline.
convert_with_pipeline(const SkImageInfo & dstInfo,void * dstRow,int dstStride,const SkImageInfo & srcInfo,const void * srcRow,int srcStride,const SkColorSpaceXformSteps & steps)247 static void convert_with_pipeline(const SkImageInfo& dstInfo, void* dstRow, int dstStride,
248 const SkImageInfo& srcInfo, const void* srcRow, int srcStride,
249 const SkColorSpaceXformSteps& steps) {
250 SkRasterPipeline_MemoryCtx src = { const_cast<void*>(srcRow), srcStride },
251 dst = { dstRow, dstStride };
252
253 SkRasterPipeline_<256> pipeline;
254 pipeline.appendLoad(srcInfo.colorType(), &src);
255 steps.apply(&pipeline);
256 pipeline.appendStore(dstInfo.colorType(), &dst);
257 pipeline.run(0,0, srcInfo.width(), srcInfo.height());
258 }
259
SkConvertPixels(const SkImageInfo & dstInfo,void * dstPixels,size_t dstRB,const SkImageInfo & srcInfo,const void * srcPixels,size_t srcRB)260 bool SkConvertPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
261 const SkImageInfo& srcInfo, const void* srcPixels, size_t srcRB) {
262 SkASSERT(dstInfo.dimensions() == srcInfo.dimensions());
263 SkASSERT(SkImageInfoValidConversion(dstInfo, srcInfo));
264
265 int srcStride = (int)(srcRB / srcInfo.bytesPerPixel());
266 int dstStride = (int)(dstRB / dstInfo.bytesPerPixel());
267 if ((size_t)srcStride * srcInfo.bytesPerPixel() != srcRB ||
268 (size_t)dstStride * dstInfo.bytesPerPixel() != dstRB) {
269 return false;
270 }
271
272 SkColorSpaceXformSteps steps{srcInfo.colorSpace(), srcInfo.alphaType(),
273 dstInfo.colorSpace(), dstInfo.alphaType()};
274
275 for (auto fn : {rect_memcpy, swizzle_or_premul, convert_to_alpha8}) {
276 if (fn(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, srcRB, steps)) {
277 return true;
278 }
279 }
280 convert_with_pipeline(dstInfo, dstPixels, dstStride, srcInfo, srcPixels, srcStride, steps);
281 return true;
282 }
283