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