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