xref: /aosp_15_r20/external/skia/tests/TestUtils.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2017 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 "tests/TestUtils.h"
9 
10 #include "include/core/SkAlphaType.h"
11 #include "include/core/SkColorSpace.h"
12 #include "include/core/SkColorType.h"
13 #include "include/core/SkImageInfo.h"
14 #include "include/core/SkPixmap.h"
15 #include "include/core/SkSize.h"
16 #include "include/gpu/ganesh/GrBackendSurface.h"
17 #include "include/gpu/ganesh/GrDirectContext.h"
18 #include "include/gpu/ganesh/GrRecordingContext.h"
19 #include "include/private/base/SkTemplates.h"
20 #include "include/private/base/SkTo.h"
21 #include "include/private/gpu/ganesh/GrTypesPriv.h"
22 #include "src/core/SkAutoPixmapStorage.h"
23 #include "src/gpu/ganesh/GrCaps.h"
24 #include "src/gpu/ganesh/GrDataUtils.h"
25 #include "src/gpu/ganesh/GrDirectContextPriv.h"
26 #include "src/gpu/ganesh/GrImageInfo.h"
27 #include "src/gpu/ganesh/GrRecordingContextPriv.h"
28 #include "src/gpu/ganesh/GrSurfaceProxy.h"
29 #include "src/gpu/ganesh/GrSurfaceProxyView.h"
30 #include "src/gpu/ganesh/SkGr.h"
31 #include "src/gpu/ganesh/SurfaceContext.h"
32 #include "src/utils/SkCharToGlyphCache.h"
33 #include "tests/Test.h"
34 
35 #include <cmath>
36 #include <cstdlib>
37 #include <utility>
38 
TestReadPixels(skiatest::Reporter * reporter,GrDirectContext * dContext,skgpu::ganesh::SurfaceContext * srcContext,uint32_t expectedPixelValues[],const char * testName)39 void TestReadPixels(skiatest::Reporter* reporter,
40                     GrDirectContext* dContext,
41                     skgpu::ganesh::SurfaceContext* srcContext,
42                     uint32_t expectedPixelValues[],
43                     const char* testName) {
44     int pixelCnt = srcContext->width() * srcContext->height();
45     SkImageInfo ii = SkImageInfo::Make(srcContext->dimensions(),
46                                        kRGBA_8888_SkColorType,
47                                        kPremul_SkAlphaType);
48     SkAutoPixmapStorage pm;
49     pm.alloc(ii);
50     pm.erase(SK_ColorTRANSPARENT);
51 
52     bool read = srcContext->readPixels(dContext, pm, {0, 0});
53     if (!read) {
54         ERRORF(reporter, "%s: Error reading from texture.", testName);
55     }
56 
57     for (int i = 0; i < pixelCnt; ++i) {
58         if (pm.addr32()[i] != expectedPixelValues[i]) {
59             ERRORF(reporter, "%s: Error, pixel value %d should be 0x%08x, got 0x%08x.",
60                    testName, i, expectedPixelValues[i], pm.addr32()[i]);
61             break;
62         }
63     }
64 }
65 
TestWritePixels(skiatest::Reporter * reporter,GrDirectContext * dContext,skgpu::ganesh::SurfaceContext * dstContext,bool expectedToWork,const char * testName)66 void TestWritePixels(skiatest::Reporter* reporter,
67                      GrDirectContext* dContext,
68                      skgpu::ganesh::SurfaceContext* dstContext,
69                      bool expectedToWork,
70                      const char* testName) {
71     SkImageInfo ii = SkImageInfo::Make(dstContext->dimensions(),
72                                        kRGBA_8888_SkColorType,
73                                        kPremul_SkAlphaType);
74     SkAutoPixmapStorage pm;
75     pm.alloc(ii);
76     for (int y = 0; y < dstContext->height(); ++y) {
77         for (int x = 0; x < dstContext->width(); ++x) {
78             *pm.writable_addr32(x, y) = SkColorToPremulGrColor(SkColorSetARGB(2*y, x, y, x + y));
79         }
80     }
81 
82     bool write = dstContext->writePixels(dContext, pm, {0, 0});
83     if (!write) {
84         if (expectedToWork) {
85             ERRORF(reporter, "%s: Error writing to texture.", testName);
86         }
87         return;
88     }
89 
90     if (write && !expectedToWork) {
91         ERRORF(reporter, "%s: writePixels succeeded when it wasn't supposed to.", testName);
92         return;
93     }
94 
95     TestReadPixels(reporter, dContext, dstContext, pm.writable_addr32(0, 0), testName);
96 }
97 
TestCopyFromSurface(skiatest::Reporter * reporter,GrDirectContext * dContext,sk_sp<GrSurfaceProxy> proxy,GrSurfaceOrigin origin,GrColorType colorType,uint32_t expectedPixelValues[],const char * testName)98 void TestCopyFromSurface(skiatest::Reporter* reporter,
99                          GrDirectContext* dContext,
100                          sk_sp<GrSurfaceProxy> proxy,
101                          GrSurfaceOrigin origin,
102                          GrColorType colorType,
103                          uint32_t expectedPixelValues[],
104                          const char* testName) {
105     auto copy = GrSurfaceProxy::Copy(dContext,
106                                      std::move(proxy),
107                                      origin,
108                                      skgpu::Mipmapped::kNo,
109                                      SkBackingFit::kExact,
110                                      skgpu::Budgeted::kYes,
111                                      /*label=*/"CopyFromSurface_Test");
112     SkASSERT(copy && copy->asTextureProxy());
113     auto swizzle = dContext->priv().caps()->getReadSwizzle(copy->backendFormat(), colorType);
114     GrSurfaceProxyView view(std::move(copy), origin, swizzle);
115     auto dstContext = dContext->priv().makeSC(std::move(view),
116                                               {colorType, kPremul_SkAlphaType, nullptr});
117     SkASSERT(dstContext);
118 
119     TestReadPixels(reporter, dContext, dstContext.get(), expectedPixelValues, testName);
120 }
121 
compare_colors(int x,int y,const float rgbaA[],const float rgbaB[],const float tolRGBA[4],std::function<ComparePixmapsErrorReporter> & error)122 static bool compare_colors(int x, int y,
123                            const float rgbaA[],
124                            const float rgbaB[],
125                            const float tolRGBA[4],
126                            std::function<ComparePixmapsErrorReporter>& error) {
127     float diffs[4];
128     bool bad = false;
129     for (int i = 0; i < 4; ++i) {
130         diffs[i] = rgbaB[i] - rgbaA[i];
131         if (std::abs(diffs[i]) > std::abs(tolRGBA[i])) {
132             bad = true;
133         }
134     }
135     if (bad) {
136         error(x, y, diffs);
137         return false;
138     }
139     return true;
140 }
141 
ComparePixels(const GrCPixmap & a,const GrCPixmap & b,const float tolRGBA[4],std::function<ComparePixmapsErrorReporter> & error)142 bool ComparePixels(const GrCPixmap& a,
143                    const GrCPixmap& b,
144                    const float tolRGBA[4],
145                    std::function<ComparePixmapsErrorReporter>& error) {
146     if (a.dimensions() != b.dimensions()) {
147         static constexpr float kEmptyDiffs[4] = {};
148         error(-1, -1, kEmptyDiffs);
149         return false;
150     }
151 
152     SkAlphaType floatAlphaType = a.alphaType();
153     // If one is premul and the other is unpremul we do the comparison in premul space.
154     if ((a.alphaType() == kPremul_SkAlphaType   || b.alphaType() == kPremul_SkAlphaType) &&
155         (a.alphaType() == kUnpremul_SkAlphaType || b.alphaType() == kUnpremul_SkAlphaType)) {
156         floatAlphaType = kPremul_SkAlphaType;
157     }
158     sk_sp<SkColorSpace> floatCS;
159     if (SkColorSpace::Equals(a.colorSpace(), b.colorSpace())) {
160         floatCS = a.refColorSpace();
161     } else {
162         floatCS = SkColorSpace::MakeSRGBLinear();
163     }
164     GrImageInfo floatInfo(GrColorType::kRGBA_F32,
165                           floatAlphaType,
166                           std::move(floatCS),
167                           a.dimensions());
168 
169     GrPixmap floatA = GrPixmap::Allocate(floatInfo);
170     GrPixmap floatB = GrPixmap::Allocate(floatInfo);
171     SkAssertResult(GrConvertPixels(floatA, a));
172     SkAssertResult(GrConvertPixels(floatB, b));
173 
174     SkASSERT(floatA.rowBytes() == floatB.rowBytes());
175     auto at = [rb = floatA.rowBytes()](const void* base, int x, int y) {
176         return SkTAddOffset<const float>(base, y*rb + x*sizeof(float)*4);
177     };
178 
179     for (int y = 0; y < floatA.height(); ++y) {
180         for (int x = 0; x < floatA.width(); ++x) {
181             const float* rgbaA = at(floatA.addr(), x, y);
182             const float* rgbaB = at(floatB.addr(), x, y);
183             if (!compare_colors(x, y, rgbaA, rgbaB, tolRGBA, error)) {
184                 return false;
185             }
186         }
187     }
188     return true;
189 }
190 
CheckSolidPixels(const SkColor4f & col,const SkPixmap & pixmap,const float tolRGBA[4],std::function<ComparePixmapsErrorReporter> & error)191 bool CheckSolidPixels(const SkColor4f& col,
192                       const SkPixmap& pixmap,
193                       const float tolRGBA[4],
194                       std::function<ComparePixmapsErrorReporter>& error) {
195     size_t floatBpp = GrColorTypeBytesPerPixel(GrColorType::kRGBA_F32);
196 
197     // First convert 'col' to be compatible with 'pixmap'
198     GrPixmap colorPixmap;
199     {
200         sk_sp<SkColorSpace> srcCS = SkColorSpace::MakeSRGBLinear();
201         GrImageInfo srcInfo(GrColorType::kRGBA_F32,
202                             kUnpremul_SkAlphaType,
203                             std::move(srcCS),
204                             {1, 1});
205         GrCPixmap srcPixmap(srcInfo, col.vec(), floatBpp);
206         GrImageInfo dstInfo =
207                 srcInfo.makeAlphaType(pixmap.alphaType()).makeColorSpace(pixmap.refColorSpace());
208         colorPixmap = GrPixmap::Allocate(dstInfo);
209         SkAssertResult(GrConvertPixels(colorPixmap, srcPixmap));
210     }
211 
212     size_t floatRowBytes = floatBpp * pixmap.width();
213     std::unique_ptr<char[]> floatB(new char[floatRowBytes * pixmap.height()]);
214     // Then convert 'pixmap' to RGBA_F32
215     GrPixmap f32Pixmap = GrPixmap::Allocate(pixmap.info().makeColorType(kRGBA_F32_SkColorType));
216     SkAssertResult(GrConvertPixels(f32Pixmap, pixmap));
217 
218     for (int y = 0; y < f32Pixmap.height(); ++y) {
219         for (int x = 0; x < f32Pixmap.width(); ++x) {
220             auto rgbaA = SkTAddOffset<const float>(f32Pixmap.addr(),
221                                                    f32Pixmap.rowBytes()*y + floatBpp*x);
222             auto rgbaB = static_cast<const float*>(colorPixmap.addr());
223             if (!compare_colors(x, y, rgbaA, rgbaB, tolRGBA, error)) {
224                 return false;
225             }
226         }
227     }
228     return true;
229 }
230 
CheckSingleThreadedProxyRefs(skiatest::Reporter * reporter,GrSurfaceProxy * proxy,int32_t expectedProxyRefs,int32_t expectedBackingRefs)231 void CheckSingleThreadedProxyRefs(skiatest::Reporter* reporter,
232                                   GrSurfaceProxy* proxy,
233                                   int32_t expectedProxyRefs,
234                                   int32_t expectedBackingRefs) {
235     int32_t actualBackingRefs = proxy->testingOnly_getBackingRefCnt();
236 
237     REPORTER_ASSERT(reporter, proxy->refCntGreaterThan(expectedProxyRefs - 1) &&
238                               !proxy->refCntGreaterThan(expectedProxyRefs));
239     REPORTER_ASSERT(reporter, actualBackingRefs == expectedBackingRefs);
240 }
241 
CreateSurfaceContext(GrRecordingContext * rContext,const GrImageInfo & info,SkBackingFit fit,GrSurfaceOrigin origin,GrRenderable renderable,int sampleCount,skgpu::Mipmapped mipmapped,GrProtected isProtected,skgpu::Budgeted budgeted)242 std::unique_ptr<skgpu::ganesh::SurfaceContext> CreateSurfaceContext(GrRecordingContext* rContext,
243                                                                     const GrImageInfo& info,
244                                                                     SkBackingFit fit,
245                                                                     GrSurfaceOrigin origin,
246                                                                     GrRenderable renderable,
247                                                                     int sampleCount,
248                                                                     skgpu::Mipmapped mipmapped,
249                                                                     GrProtected isProtected,
250                                                                     skgpu::Budgeted budgeted) {
251     GrBackendFormat format = rContext->priv().caps()->getDefaultBackendFormat(info.colorType(),
252                                                                               renderable);
253     return rContext->priv().makeSC(info,
254                                    format,
255                                    /*label=*/{},
256                                    fit,
257                                    origin,
258                                    renderable,
259                                    sampleCount,
260                                    mipmapped,
261                                    isProtected,
262                                    budgeted);
263 }
264 
hash_to_glyph(uint32_t value)265 static SkGlyphID hash_to_glyph(uint32_t value) {
266     return SkToU16(((value >> 16) ^ value) & 0xFFFF);
267 }
268 
269 namespace {
270 class UnicharGen {
271     SkUnichar fU;
272     const int fStep;
273 public:
UnicharGen(int step)274     UnicharGen(int step) : fU(0), fStep(step) {}
275 
next()276     SkUnichar next() {
277         fU += fStep;
278         return fU;
279     }
280 };
281 }  // namespace
282 
DEF_TEST(chartoglyph_cache,reporter)283 DEF_TEST(chartoglyph_cache, reporter) {
284     SkCharToGlyphCache cache;
285     const int step = 3;
286 
287     UnicharGen gen(step);
288     for (int i = 0; i < 500; ++i) {
289         SkUnichar c = gen.next();
290         SkGlyphID glyph = hash_to_glyph(c);
291 
292         int index = cache.findGlyphIndex(c);
293         if (index >= 0) {
294             index = cache.findGlyphIndex(c);
295         }
296         REPORTER_ASSERT(reporter, index < 0);
297         cache.insertCharAndGlyph(~index, c, glyph);
298 
299         UnicharGen gen2(step);
300         for (int j = 0; j <= i; ++j) {
301             c = gen2.next();
302             glyph = hash_to_glyph(c);
303             index = cache.findGlyphIndex(c);
304             if ((unsigned)index != glyph) {
305                 index = cache.findGlyphIndex(c);
306             }
307             REPORTER_ASSERT(reporter, (unsigned)index == glyph);
308         }
309     }
310 }
311