xref: /aosp_15_r20/external/skia/src/gpu/ganesh/GrTestUtils.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2015 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/gpu/ganesh/GrTestUtils.h"
8 
9 #if defined(GPU_TEST_UTILS)
10 
11 #include "include/core/SkAlphaType.h"
12 #include "include/core/SkColorSpace.h"
13 #include "include/core/SkMatrix.h"
14 #include "include/core/SkPaint.h"
15 #include "include/core/SkPath.h"
16 #include "include/core/SkPathBuilder.h"
17 #include "include/core/SkRRect.h"
18 #include "include/core/SkRect.h"
19 #include "include/private/base/SkMacros.h"
20 #include "include/private/gpu/ganesh/GrTypesPriv.h"
21 #include "src/base/SkRandom.h"
22 #include "src/core/SkRectPriv.h"
23 #include "src/gpu/ganesh/GrColorInfo.h"
24 #include "src/gpu/ganesh/GrColorSpaceXform.h"
25 #include "src/gpu/ganesh/GrFPArgs.h"
26 #include "src/gpu/ganesh/GrProcessorUnitTest.h"
27 #include "src/gpu/ganesh/GrStyle.h"
28 #include "src/utils/SkDashPathPriv.h"
29 
30 #include <array>
31 #include <cstring>
32 #include <utility>
33 
test_matrix(SkRandom * random,bool includeNonPerspective,bool includePerspective)34 static const SkMatrix& test_matrix(SkRandom* random,
35                                    bool includeNonPerspective,
36                                    bool includePerspective) {
37     static SkMatrix gMatrices[5];
38     static const int kPerspectiveCount = 1;
39     static bool gOnce;
40     if (!gOnce) {
41         gOnce = true;
42         gMatrices[0].reset();
43         gMatrices[1].setTranslate(SkIntToScalar(-100), SkIntToScalar(100));
44         gMatrices[2].setRotate(SkIntToScalar(17));
45         gMatrices[3].setRotate(SkIntToScalar(185));
46         gMatrices[3].postTranslate(SkIntToScalar(66), SkIntToScalar(-33));
47         gMatrices[3].postScale(SkIntToScalar(2), SK_ScalarHalf);
48 
49         // Perspective matrices
50         gMatrices[4].setRotate(SkIntToScalar(215));
51         gMatrices[4].set(SkMatrix::kMPersp0, 0.00013f);
52         gMatrices[4].set(SkMatrix::kMPersp1, -0.000039f);
53     }
54 
55     uint32_t count = static_cast<uint32_t>(std::size(gMatrices));
56     if (includeNonPerspective && includePerspective) {
57         return gMatrices[random->nextULessThan(count)];
58     } else if (!includeNonPerspective) {
59         return gMatrices[count - 1 - random->nextULessThan(kPerspectiveCount)];
60     } else {
61         SkASSERT(includeNonPerspective && !includePerspective);
62         return gMatrices[random->nextULessThan(count - kPerspectiveCount)];
63     }
64 }
65 
66 namespace GrTest {
TestMatrix(SkRandom * random)67 const SkMatrix& TestMatrix(SkRandom* random) { return test_matrix(random, true, true); }
68 
TestMatrixPreservesRightAngles(SkRandom * random)69 const SkMatrix& TestMatrixPreservesRightAngles(SkRandom* random) {
70     static SkMatrix gMatrices[5];
71     static bool gOnce;
72     if (!gOnce) {
73         gOnce = true;
74         // identity
75         gMatrices[0].reset();
76         // translation
77         gMatrices[1].setTranslate(SkIntToScalar(-100), SkIntToScalar(100));
78         // scale
79         gMatrices[2].setScale(SkIntToScalar(17), SkIntToScalar(17));
80         // scale + translation
81         gMatrices[3].setScale(SkIntToScalar(-17), SkIntToScalar(-17));
82         gMatrices[3].postTranslate(SkIntToScalar(66), SkIntToScalar(-33));
83         // orthogonal basis vectors
84         gMatrices[4].reset();
85         gMatrices[4].setScale(SkIntToScalar(-1), SkIntToScalar(-1));
86         gMatrices[4].setRotate(47);
87 
88         for (size_t i = 0; i < std::size(gMatrices); i++) {
89             SkASSERT(gMatrices[i].preservesRightAngles());
90         }
91     }
92     return gMatrices[random->nextULessThan(static_cast<uint32_t>(std::size(gMatrices)))];
93 }
94 
TestMatrixRectStaysRect(SkRandom * random)95 const SkMatrix& TestMatrixRectStaysRect(SkRandom* random) {
96     static SkMatrix gMatrices[6];
97     static bool gOnce;
98     if (!gOnce) {
99         gOnce = true;
100         // identity
101         gMatrices[0].reset();
102         // translation
103         gMatrices[1].setTranslate(SkIntToScalar(-100), SkIntToScalar(100));
104         // scale
105         gMatrices[2].setScale(SkIntToScalar(17), SkIntToScalar(17));
106         // scale + translation
107         gMatrices[3].setScale(SkIntToScalar(-17), SkIntToScalar(-17));
108         gMatrices[3].postTranslate(SkIntToScalar(66), SkIntToScalar(-33));
109         // reflection
110         gMatrices[4].setScale(SkIntToScalar(-1), SkIntToScalar(-1));
111         // 90 degress rotation
112         gMatrices[5].setRotate(90);
113 
114         for (size_t i = 0; i < std::size(gMatrices); i++) {
115             SkASSERT(gMatrices[i].rectStaysRect());
116         }
117     }
118     return gMatrices[random->nextULessThan(static_cast<uint32_t>(std::size(gMatrices)))];
119 }
120 
TestMatrixInvertible(SkRandom * random)121 const SkMatrix& TestMatrixInvertible(SkRandom* random) { return test_matrix(random, true, false); }
TestMatrixPerspective(SkRandom * random)122 const SkMatrix& TestMatrixPerspective(SkRandom* random) { return test_matrix(random, false, true); }
123 
TestWrapModes(SkRandom * random,GrSamplerState::WrapMode wrapModes[2])124 void TestWrapModes(SkRandom* random, GrSamplerState::WrapMode wrapModes[2]) {
125     static const GrSamplerState::WrapMode kWrapModes[] = {
126             GrSamplerState::WrapMode::kClamp,
127             GrSamplerState::WrapMode::kRepeat,
128             GrSamplerState::WrapMode::kMirrorRepeat,
129     };
130     wrapModes[0] = kWrapModes[random->nextULessThan(std::size(kWrapModes))];
131     wrapModes[1] = kWrapModes[random->nextULessThan(std::size(kWrapModes))];
132 }
TestRect(SkRandom * random)133 const SkRect& TestRect(SkRandom* random) {
134     static SkRect gRects[7];
135     static bool gOnce;
136     if (!gOnce) {
137         gOnce = true;
138         gRects[0] = SkRect::MakeWH(1.f, 1.f);
139         gRects[1] = SkRect::MakeWH(1.0f, 256.0f);
140         gRects[2] = SkRect::MakeWH(256.0f, 1.0f);
141         gRects[3] = SkRectPriv::MakeLargest();
142         gRects[4] = SkRect::MakeLTRB(-65535.0f, -65535.0f, 65535.0f, 65535.0f);
143         gRects[5] = SkRect::MakeLTRB(-10.0f, -10.0f, 10.0f, 10.0f);
144     }
145     return gRects[random->nextULessThan(static_cast<uint32_t>(std::size(gRects)))];
146 }
147 
148 // Just some simple rects for code which expects its input very sanitized
TestSquare(SkRandom * random)149 const SkRect& TestSquare(SkRandom* random) {
150     static SkRect gRects[2];
151     static bool gOnce;
152     if (!gOnce) {
153         gOnce = true;
154         gRects[0] = SkRect::MakeWH(128.f, 128.f);
155         gRects[1] = SkRect::MakeWH(256.0f, 256.0f);
156     }
157     return gRects[random->nextULessThan(static_cast<uint32_t>(std::size(gRects)))];
158 }
159 
TestRRectSimple(SkRandom * random)160 const SkRRect& TestRRectSimple(SkRandom* random) {
161     static SkRRect gRRect[2];
162     static bool gOnce;
163     if (!gOnce) {
164         gOnce = true;
165         SkRect rectangle = SkRect::MakeWH(10.f, 20.f);
166         // true round rect with circular corners
167         gRRect[0].setRectXY(rectangle, 1.f, 1.f);
168         // true round rect with elliptical corners
169         gRRect[1].setRectXY(rectangle, 2.0f, 1.0f);
170 
171         for (size_t i = 0; i < std::size(gRRect); i++) {
172             SkASSERT(gRRect[i].isSimple());
173         }
174     }
175     return gRRect[random->nextULessThan(static_cast<uint32_t>(std::size(gRRect)))];
176 }
177 
TestPath(SkRandom * random)178 const SkPath& TestPath(SkRandom* random) {
179     static SkPath gPath[7];
180     static bool gOnce;
181     if (!gOnce) {
182         gOnce = true;
183         // line
184         gPath[0] = SkPathBuilder().moveTo(0.f, 0.f)
185                                   .lineTo(10.f, 10.f)
186                                   .detach();
187         // quad
188         gPath[1] = SkPathBuilder().moveTo(0.f, 0.f)
189                                   .quadTo(10.f, 10.f, 20.f, 20.f)
190                                   .detach();
191         // conic
192         gPath[2] = SkPathBuilder().moveTo(0.f, 0.f)
193                                   .conicTo(10.f, 10.f, 20.f, 20.f, 1.f)
194                                   .detach();
195         // cubic
196         gPath[3] = SkPathBuilder().moveTo(0.f, 0.f)
197                                   .cubicTo(10.f, 10.f, 20.f, 20.f, 30.f, 30.f)
198                                   .detach();
199         // all three
200         gPath[4] = SkPathBuilder().moveTo(0.f, 0.f)
201                                   .lineTo(10.f, 10.f)
202                                   .quadTo(10.f, 10.f, 20.f, 20.f)
203                                   .conicTo(10.f, 10.f, 20.f, 20.f, 1.f)
204                                   .cubicTo(10.f, 10.f, 20.f, 20.f, 30.f, 30.f)
205                                   .detach();
206         // convex
207         gPath[5] = SkPathBuilder().moveTo(0.0f, 0.0f)
208                                   .lineTo(10.0f, 0.0f)
209                                   .lineTo(10.0f, 10.0f)
210                                   .lineTo(0.0f, 10.0f)
211                                   .close()
212                                   .detach();
213         // concave
214         gPath[6] = SkPathBuilder().moveTo(0.0f, 0.0f)
215                                   .lineTo(5.0f, 5.0f)
216                                   .lineTo(10.0f, 0.0f)
217                                   .lineTo(10.0f, 10.0f)
218                                   .lineTo(0.0f, 10.0f)
219                                   .close()
220                                   .detach();
221     }
222 
223     return gPath[random->nextULessThan(static_cast<uint32_t>(std::size(gPath)))];
224 }
225 
TestPathConvex(SkRandom * random)226 const SkPath& TestPathConvex(SkRandom* random) {
227     static SkPath gPath[3];
228     static bool gOnce;
229     if (!gOnce) {
230         gOnce = true;
231         // narrow rect
232         gPath[0] = SkPath::Polygon({{-1.5f, -50.0f},
233                                     {-1.5f, -50.0f},
234                                     { 1.5f, -50.0f},
235                                     { 1.5f,  50.0f},
236                                     {-1.5f,  50.0f}}, false);
237         // degenerate
238         gPath[1] = SkPath::Polygon({{-0.025f, -0.025f},
239                                     {-0.025f, -0.025f},
240                                     { 0.025f, -0.025f},
241                                     { 0.025f,  0.025f},
242                                     {-0.025f,  0.025f}}, false);
243         // clipped triangle
244         gPath[2] = SkPath::Polygon({{-10.0f, -50.0f},
245                                     {-10.0f, -50.0f},
246                                     { 10.0f, -50.0f},
247                                     { 50.0f,  31.0f},
248                                     { 40.0f,  50.0f},
249                                     {-40.0f,  50.0f},
250                                     {-50.0f,  31.0f}}, false);
251 
252         for (size_t i = 0; i < std::size(gPath); i++) {
253             SkASSERT(gPath[i].isConvex());
254         }
255     }
256 
257     return gPath[random->nextULessThan(static_cast<uint32_t>(std::size(gPath)))];
258 }
259 
randomize_stroke_rec(SkStrokeRec * rec,SkRandom * random)260 static void randomize_stroke_rec(SkStrokeRec* rec, SkRandom* random) {
261     bool strokeAndFill = random->nextBool();
262     SkScalar strokeWidth = random->nextBool() ? 0.f : 1.f;
263     rec->setStrokeStyle(strokeWidth, strokeAndFill);
264 
265     SkPaint::Cap cap = SkPaint::Cap(random->nextULessThan(SkPaint::kCapCount));
266     SkPaint::Join join = SkPaint::Join(random->nextULessThan(SkPaint::kJoinCount));
267     SkScalar miterLimit = random->nextRangeScalar(1.f, 5.f);
268     rec->setStrokeParams(cap, join, miterLimit);
269 }
270 
TestStrokeRec(SkRandom * random)271 SkStrokeRec TestStrokeRec(SkRandom* random) {
272     SkStrokeRec::InitStyle style =
273             SkStrokeRec::InitStyle(random->nextULessThan(SkStrokeRec::kFill_InitStyle + 1));
274     SkStrokeRec rec(style);
275     randomize_stroke_rec(&rec, random);
276     return rec;
277 }
278 
TestStyle(SkRandom * random,GrStyle * style)279 void TestStyle(SkRandom* random, GrStyle* style) {
280     SkStrokeRec::InitStyle initStyle =
281             SkStrokeRec::InitStyle(random->nextULessThan(SkStrokeRec::kFill_InitStyle + 1));
282     SkStrokeRec stroke(initStyle);
283     randomize_stroke_rec(&stroke, random);
284     sk_sp<SkPathEffect> pe;
285     if (random->nextBool()) {
286         int cnt = random->nextRangeU(1, 50) * 2;
287         std::unique_ptr<SkScalar[]> intervals(new SkScalar[cnt]);
288         SkScalar sum = 0;
289         for (int i = 0; i < cnt; i++) {
290             intervals[i] = random->nextRangeScalar(SkDoubleToScalar(0.01),
291                                                    SkDoubleToScalar(10.0));
292             sum += intervals[i];
293         }
294         SkScalar phase = random->nextRangeScalar(0, sum);
295         pe = TestDashPathEffect::Make(intervals.get(), cnt, phase);
296     }
297     *style = GrStyle(stroke, std::move(pe));
298 }
299 
TestDashPathEffect(const SkScalar * intervals,int count,SkScalar phase)300 TestDashPathEffect::TestDashPathEffect(const SkScalar* intervals, int count, SkScalar phase) {
301     fCount = count;
302     fIntervals.reset(count);
303     memcpy(fIntervals.get(), intervals, count * sizeof(SkScalar));
304     SkDashPath::CalcDashParameters(phase, intervals, count, &fInitialDashLength,
305                                    &fInitialDashIndex, &fIntervalLength, &fPhase);
306 }
307 
onFilterPath(SkPath * dst,const SkPath & src,SkStrokeRec * rec,const SkRect * cullRect,const SkMatrix &) const308 bool TestDashPathEffect::onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec,
309                                       const SkRect* cullRect, const SkMatrix&) const {
310     return SkDashPath::InternalFilter(dst, src, rec, cullRect, fIntervals.get(), fCount,
311                                       fInitialDashLength, fInitialDashIndex, fIntervalLength,
312                                       fPhase);
313 }
314 
asADash(DashInfo * info) const315 SkPathEffectBase::DashType TestDashPathEffect::asADash(DashInfo* info) const {
316     if (info) {
317         if (info->fCount >= fCount && info->fIntervals) {
318             memcpy(info->fIntervals, fIntervals.get(), fCount * sizeof(SkScalar));
319         }
320         info->fCount = fCount;
321         info->fPhase = fPhase;
322     }
323     return DashType::kDash;
324 }
325 
TestColorSpace(SkRandom * random)326 sk_sp<SkColorSpace> TestColorSpace(SkRandom* random) {
327     static sk_sp<SkColorSpace> gColorSpaces[3];
328     static bool gOnce;
329     if (!gOnce) {
330         gOnce = true;
331         // No color space (legacy mode)
332         gColorSpaces[0] = nullptr;
333         // sRGB or color-spin sRGB
334         gColorSpaces[1] = SkColorSpace::MakeSRGB();
335         gColorSpaces[2] = SkColorSpace::MakeSRGB()->makeColorSpin();
336     }
337     return gColorSpaces[random->nextULessThan(static_cast<uint32_t>(std::size(gColorSpaces)))];
338 }
339 
TestColorXform(SkRandom * random)340 sk_sp<GrColorSpaceXform> TestColorXform(SkRandom* random) {
341     // TODO: Add many more kinds of xforms here
342     static sk_sp<GrColorSpaceXform> gXforms[3];
343     static bool gOnce;
344     if (!gOnce) {
345         gOnce = true;
346         sk_sp<SkColorSpace> srgb = SkColorSpace::MakeSRGB();
347         sk_sp<SkColorSpace> spin = SkColorSpace::MakeSRGB()->makeColorSpin();
348         // No gamut change
349         gXforms[0] = nullptr;
350         gXforms[1] = GrColorSpaceXform::Make(srgb.get(), kPremul_SkAlphaType,
351                                              spin.get(), kPremul_SkAlphaType);
352         gXforms[2] = GrColorSpaceXform::Make(spin.get(), kPremul_SkAlphaType,
353                                              srgb.get(), kPremul_SkAlphaType);
354     }
355     return gXforms[random->nextULessThan(static_cast<uint32_t>(std::size(gXforms)))];
356 }
357 
TestAsFPArgs(GrProcessorTestData * d)358 TestAsFPArgs::TestAsFPArgs(GrProcessorTestData* d)
359         : fColorInfoStorage(std::make_unique<GrColorInfo>(
360                   GrColorType::kRGBA_8888, kPremul_SkAlphaType, TestColorSpace(d->fRandom)))
361         , fArgs(d->context(), fColorInfoStorage.get(), fSurfaceProps, GrFPArgs::Scope::kDefault) {}
362 
~TestAsFPArgs()363 TestAsFPArgs::~TestAsFPArgs() {}
364 
RandomColor(SkRandom * random)365 GrColor RandomColor(SkRandom* random) {
366     // There are only a few cases of random colors which interest us
367     enum ColorMode {
368         kAllOnes_ColorMode,
369         kAllZeros_ColorMode,
370         kAlphaOne_ColorMode,
371         kRandom_ColorMode,
372         kLast_ColorMode = kRandom_ColorMode
373     };
374 
375     ColorMode colorMode = ColorMode(random->nextULessThan(kLast_ColorMode + 1));
376     GrColor color SK_INIT_TO_AVOID_WARNING;
377     switch (colorMode) {
378         case kAllOnes_ColorMode:
379             color = GrColorPackRGBA(0xFF, 0xFF, 0xFF, 0xFF);
380             break;
381         case kAllZeros_ColorMode:
382             color = GrColorPackRGBA(0, 0, 0, 0);
383             break;
384         case kAlphaOne_ColorMode:
385             color = GrColorPackRGBA(random->nextULessThan(256),
386                                     random->nextULessThan(256),
387                                     random->nextULessThan(256),
388                                     0xFF);
389             break;
390         case kRandom_ColorMode: {
391                 uint8_t alpha = random->nextULessThan(256);
392                 color = GrColorPackRGBA(random->nextRangeU(0, alpha),
393                                         random->nextRangeU(0, alpha),
394                                         random->nextRangeU(0, alpha),
395                                         alpha);
396             break;
397         }
398     }
399     return color;
400 }
401 
RandomCoverage(SkRandom * random)402 uint8_t RandomCoverage(SkRandom* random) {
403     enum CoverageMode {
404         kZero_CoverageMode,
405         kAllOnes_CoverageMode,
406         kRandom_CoverageMode,
407         kLast_CoverageMode = kRandom_CoverageMode
408     };
409 
410     CoverageMode colorMode = CoverageMode(random->nextULessThan(kLast_CoverageMode + 1));
411     uint8_t coverage SK_INIT_TO_AVOID_WARNING;
412     switch (colorMode) {
413         case kZero_CoverageMode:
414             coverage = 0;
415             break;
416         case kAllOnes_CoverageMode:
417             coverage = 0xff;
418             break;
419         case kRandom_CoverageMode:
420             coverage = random->nextULessThan(256);
421             break;
422     }
423     return coverage;
424 }
425 
426 }  // namespace GrTest
427 
428 #endif
429