Flutter Engine
The Flutter Engine
PremulAlphaRoundTripTest.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2011 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
24#include "tests/Test.h"
25
26#include <array>
27#include <cstddef>
28#include <cstdint>
29
30struct GrContextOptions;
31
32static uint32_t pack_unpremul_rgba(SkColor c) {
33 uint32_t packed;
34 uint8_t* byte = reinterpret_cast<uint8_t*>(&packed);
35 byte[0] = SkColorGetR(c);
36 byte[1] = SkColorGetG(c);
37 byte[2] = SkColorGetB(c);
38 byte[3] = SkColorGetA(c);
39 return packed;
40}
41
42static uint32_t pack_unpremul_bgra(SkColor c) {
43 uint32_t packed;
44 uint8_t* byte = reinterpret_cast<uint8_t*>(&packed);
45 byte[0] = SkColorGetB(c);
46 byte[1] = SkColorGetG(c);
47 byte[2] = SkColorGetR(c);
48 byte[3] = SkColorGetA(c);
49 return packed;
50}
51
52typedef uint32_t (*PackUnpremulProc)(SkColor);
53
54const struct {
57} gUnpremul[] = {
60};
61
63 // Don't strictly need a bitmap, but its a handy way to allocate the pixels
64 SkBitmap bmp;
65 bmp.allocN32Pixels(256, 256);
66
67 for (int a = 0; a < 256; ++a) {
68 uint32_t* pixels = bmp.getAddr32(0, a);
69 for (int r = 0; r < 256; ++r) {
70 pixels[r] = proc(SkColorSetARGB(a, r, 0, 0));
71 }
72 }
73
75 surf->writePixels({info, bmp.getPixels(), bmp.rowBytes()}, 0, 0);
76}
77
79 for (size_t upmaIdx = 0; upmaIdx < std::size(gUnpremul); ++upmaIdx) {
80 fill_surface(surf, gUnpremul[upmaIdx].fColorType, gUnpremul[upmaIdx].fPackProc);
81
82 const SkImageInfo info = SkImageInfo::Make(256, 256, gUnpremul[upmaIdx].fColorType,
84 SkBitmap readBmp1;
85 readBmp1.allocPixels(info);
86 SkBitmap readBmp2;
87 readBmp2.allocPixels(info);
88
89 readBmp1.eraseColor(0);
90 readBmp2.eraseColor(0);
91
92 surf->readPixels(readBmp1, 0, 0);
93 surf->writePixels(readBmp1, 0, 0);
94 surf->readPixels(readBmp2, 0, 0);
95
96 bool success = true;
97 for (int y = 0; y < 256 && success; ++y) {
98 const uint32_t* pixels1 = readBmp1.getAddr32(0, y);
99 const uint32_t* pixels2 = readBmp2.getAddr32(0, y);
100 for (int x = 0; x < 256 && success; ++x) {
101 // We see sporadic failures here. May help to see where it goes wrong.
102 if (pixels1[x] != pixels2[x]) {
103 SkDebugf("%x != %x, x = %d, y = %d\n", pixels1[x], pixels2[x], x, y);
104 }
105 REPORTER_ASSERT(reporter, success = pixels1[x] == pixels2[x]);
106 }
107 }
108 }
109}
110
111DEF_TEST(PremulAlphaRoundTrip, reporter) {
113
115
117}
119 reporter,
120 ctxInfo,
123
124 sk_sp<SkSurface> surf(
125 SkSurfaces::RenderTarget(ctxInfo.directContext(), skgpu::Budgeted::kNo, info));
127}
128
129DEF_TEST(PremulAlphaRoundTripGrConvertPixels, reporter) {
130 // Code that does the same thing as above, but using GrConvertPixels. This simulates what
131 // happens if you run the above on a machine with a GPU that doesn't have a valid PM/UPM
132 // conversion pair of FPs.
133 const SkImageInfo upmInfo =
135 const SkImageInfo pmInfo =
137
139 uint32_t* srcPixels = (uint32_t*)src.addr();
140 for (int y = 0; y < 256; ++y) {
141 for (int x = 0; x < 256; ++x) {
142 srcPixels[y * 256 + x] = pack_unpremul_rgba(SkColorSetARGB(y, x, x, x));
143 }
144 }
145
146 GrPixmap surf = GrPixmap::Allocate(pmInfo);
147 GrConvertPixels(surf, src);
148
149 GrPixmap read1 = GrPixmap::Allocate(upmInfo);
150 GrConvertPixels(read1, surf);
151
152 GrPixmap surf2 = GrPixmap::Allocate(pmInfo);
153 GrConvertPixels(surf2, read1);
154
155 GrPixmap read2 = GrPixmap::Allocate(upmInfo);
156 GrConvertPixels(read2, surf2);
157
158 auto get_pixel = [](const GrPixmap& pm, int x, int y) {
159 const uint32_t* addr = (const uint32_t*)pm.addr();
160 return addr[y * 256 + x];
161 };
162 auto dump_pixel_history = [&](int x, int y) {
163 SkDebugf("Pixel history for (%d, %d):\n", x, y);
164 SkDebugf("Src : %08x\n", get_pixel(src, x, y));
165 SkDebugf(" -> : %08x\n", get_pixel(surf, x, y));
166 SkDebugf(" <- : %08x\n", get_pixel(read1, x, y));
167 SkDebugf(" -> : %08x\n", get_pixel(surf2, x, y));
168 SkDebugf(" <- : %08x\n", get_pixel(read2, x, y));
169 };
170
171 bool success = true;
172 for (int y = 0; y < 256 && success; ++y) {
173 const uint32_t* pixels1 = (const uint32_t*) read1.addr();
174 const uint32_t* pixels2 = (const uint32_t*) read2.addr();
175 for (int x = 0; x < 256 && success; ++x) {
176 uint32_t c1 = pixels1[y * 256 + x],
177 c2 = pixels2[y * 256 + x];
178 // If this ever fails, it's helpful to see where it goes wrong.
179 if (c1 != c2) {
180 dump_pixel_history(x, y);
181 }
182 REPORTER_ASSERT(reporter, success = c1 == c2);
183 }
184 }
185}
186
187DEF_TEST(PremulAlphaRoundTripSkConvertPixels, reporter) {
188 // ... and now using SkConvertPixels, just for completeness
189 const SkImageInfo upmInfo =
191 const SkImageInfo pmInfo =
193
194 SkBitmap src; src.allocPixels(upmInfo);
195 uint32_t* srcPixels = src.getAddr32(0, 0);
196 for (int y = 0; y < 256; ++y) {
197 for (int x = 0; x < 256; ++x) {
198 srcPixels[y * 256 + x] = pack_unpremul_rgba(SkColorSetARGB(y, x, x, x));
199 }
200 }
201
202 auto convert = [](const SkBitmap& dst, const SkBitmap& src){
203 SkAssertResult(SkConvertPixels(dst.info(), dst.getAddr(0, 0), dst.rowBytes(),
204 src.info(), src.getAddr(0, 0), src.rowBytes()));
205 };
206
207 SkBitmap surf; surf.allocPixels(pmInfo);
208 convert(surf, src);
209
210 SkBitmap read1; read1.allocPixels(upmInfo);
211 convert(read1, surf);
212
213 SkBitmap surf2; surf2.allocPixels(pmInfo);
214 convert(surf2, read1);
215
216 SkBitmap read2; read2.allocPixels(upmInfo);
217 convert(read2, surf2);
218
219 auto dump_pixel_history = [&](int x, int y) {
220 SkDebugf("Pixel history for (%d, %d):\n", x, y);
221 SkDebugf("Src : %08x\n", *src.getAddr32(x, y));
222 SkDebugf(" -> : %08x\n", *surf.getAddr32(x, y));
223 SkDebugf(" <- : %08x\n", *read1.getAddr32(x, y));
224 SkDebugf(" -> : %08x\n", *surf2.getAddr32(x, y));
225 SkDebugf(" <- : %08x\n", *read2.getAddr32(x, y));
226 };
227
228 bool success = true;
229 for (int y = 0; y < 256 && success; ++y) {
230 const uint32_t* pixels1 = read1.getAddr32(0, 0);
231 const uint32_t* pixels2 = read2.getAddr32(0, 0);
232 for (int x = 0; x < 256 && success; ++x) {
233 uint32_t c1 = pixels1[y * 256 + x],
234 c2 = pixels2[y * 256 + x];
235 // If this ever fails, it's helpful to see where it goes wrong.
236 if (c1 != c2) {
237 dump_pixel_history(x, y);
238 }
239 REPORTER_ASSERT(reporter, success = c1 == c2);
240 }
241 }
242}
243
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
reporter
Definition: FontMgrTest.cpp:39
SkAssertResult(font.textToGlyphs("Hello", 5, SkTextEncoding::kUTF8, glyphs, std::size(glyphs))==count)
bool GrConvertPixels(const GrPixmap &dst, const GrCPixmap &src, bool flipY)
static void test_premul_alpha_roundtrip(skiatest::Reporter *reporter, SkSurface *surf)
uint32_t(* PackUnpremulProc)(SkColor)
static void fill_surface(SkSurface *surf, SkColorType colorType, PackUnpremulProc proc)
SkColorType fColorType
const struct @436 gUnpremul[]
static uint32_t pack_unpremul_bgra(SkColor c)
static uint32_t pack_unpremul_rgba(SkColor c)
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(PremulAlphaRoundTrip_Gpu, reporter, ctxInfo, CtsEnforcement::kApiLevel_T)
PackUnpremulProc fPackProc
DEF_TEST(PremulAlphaRoundTrip, reporter)
kUnpremul_SkAlphaType
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition: SkAlphaType.h:29
SkColorType
Definition: SkColorType.h:19
@ kBGRA_8888_SkColorType
pixel with 8 bits for blue, green, red, alpha; in 32-bit word
Definition: SkColorType.h:26
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
Definition: SkColorType.h:24
#define SkColorGetR(color)
Definition: SkColor.h:65
#define SkColorGetG(color)
Definition: SkColor.h:69
uint32_t SkColor
Definition: SkColor.h:37
static constexpr SkColor SkColorSetARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b)
Definition: SkColor.h:49
#define SkColorGetA(color)
Definition: SkColor.h:61
#define SkColorGetB(color)
Definition: SkColor.h:73
bool SkConvertPixels(const SkImageInfo &dstInfo, void *dstPixels, size_t dstRB, const SkImageInfo &srcInfo, const void *srcPixels, size_t srcRB)
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
static SkColorType colorType(AImageDecoder *decoder, const AImageDecoderHeaderInfo *headerInfo)
#define REPORTER_ASSERT(r, cond,...)
Definition: Test.h:286
T * addr() const
Definition: GrPixmap.h:20
static GrPixmap Allocate(const GrImageInfo &info)
Definition: GrPixmap.h:101
void allocPixels(const SkImageInfo &info, size_t rowBytes)
Definition: SkBitmap.cpp:258
SkISize dimensions() const
Definition: SkBitmap.h:388
size_t rowBytes() const
Definition: SkBitmap.h:238
void * getPixels() const
Definition: SkBitmap.h:283
void allocN32Pixels(int width, int height, bool isOpaque=false)
Definition: SkBitmap.cpp:232
uint32_t * getAddr32(int x, int y) const
Definition: SkBitmap.h:1260
void eraseColor(SkColor4f) const
Definition: SkBitmap.cpp:442
void writePixels(const SkPixmap &src, int dstX, int dstY)
Definition: SkSurface.cpp:202
bool readPixels(const SkPixmap &dst, int srcX, int srcY)
Definition: SkSurface.cpp:125
T * get() const
Definition: SkRefCnt.h:303
static Editor::Movement convert(skui::Key key)
struct MyStruct a[10]
double y
double x
SK_API sk_sp< SkSurface > Raster(const SkImageInfo &imageInfo, size_t rowBytes, const SkSurfaceProps *surfaceProps)
SK_API sk_sp< SkSurface > RenderTarget(GrRecordingContext *context, skgpu::Budgeted budgeted, const SkImageInfo &imageInfo, int sampleCount, GrSurfaceOrigin surfaceOrigin, const SkSurfaceProps *surfaceProps, bool shouldCreateWithMips=false, bool isProtected=false)
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
dst
Definition: cp.py:12
static SkImageInfo MakeN32Premul(int width, int height)
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)