xref: /aosp_15_r20/external/skia/src/core/SkConvertPixels.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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