xref: /aosp_15_r20/external/skia/tests/GpuDrawPathTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2013 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker #include "tests/Test.h"
8*c8dee2aaSAndroid Build Coastguard Worker 
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColor.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImageInfo.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkMatrix.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPaint.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPath.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPathEffect.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPathTypes.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRRect.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSurface.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "include/effects/SkDashPathEffect.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/GpuTypes.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrDirectContext.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrTypes.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/SkSurfaceGanesh.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "tests/CtsEnforcement.h"
29*c8dee2aaSAndroid Build Coastguard Worker 
30*c8dee2aaSAndroid Build Coastguard Worker #include <initializer_list>
31*c8dee2aaSAndroid Build Coastguard Worker 
32*c8dee2aaSAndroid Build Coastguard Worker struct GrContextOptions;
33*c8dee2aaSAndroid Build Coastguard Worker 
test_drawPathEmpty(skiatest::Reporter *,SkCanvas * canvas)34*c8dee2aaSAndroid Build Coastguard Worker static void test_drawPathEmpty(skiatest::Reporter*, SkCanvas* canvas) {
35*c8dee2aaSAndroid Build Coastguard Worker     // Filling an empty path should not crash.
36*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paint;
37*c8dee2aaSAndroid Build Coastguard Worker     SkRect emptyRect = SkRect::MakeEmpty();
38*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawRect(emptyRect, paint);
39*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawPath(SkPath(), paint);
40*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawOval(emptyRect, paint);
41*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawRect(emptyRect, paint);
42*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawRRect(SkRRect::MakeRect(emptyRect), paint);
43*c8dee2aaSAndroid Build Coastguard Worker 
44*c8dee2aaSAndroid Build Coastguard Worker     // Stroking an empty path should not crash.
45*c8dee2aaSAndroid Build Coastguard Worker     paint.setAntiAlias(true);
46*c8dee2aaSAndroid Build Coastguard Worker     paint.setStyle(SkPaint::kStroke_Style);
47*c8dee2aaSAndroid Build Coastguard Worker     paint.setColor(SK_ColorGRAY);
48*c8dee2aaSAndroid Build Coastguard Worker     paint.setStrokeWidth(SkIntToScalar(20));
49*c8dee2aaSAndroid Build Coastguard Worker     paint.setStrokeJoin(SkPaint::kRound_Join);
50*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawRect(emptyRect, paint);
51*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawPath(SkPath(), paint);
52*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawOval(emptyRect, paint);
53*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawRect(emptyRect, paint);
54*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawRRect(SkRRect::MakeRect(emptyRect), paint);
55*c8dee2aaSAndroid Build Coastguard Worker }
56*c8dee2aaSAndroid Build Coastguard Worker 
fill_and_stroke(SkCanvas * canvas,const SkPath & p1,const SkPath & p2,sk_sp<SkPathEffect> effect)57*c8dee2aaSAndroid Build Coastguard Worker static void fill_and_stroke(SkCanvas* canvas, const SkPath& p1, const SkPath& p2,
58*c8dee2aaSAndroid Build Coastguard Worker                             sk_sp<SkPathEffect> effect) {
59*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paint;
60*c8dee2aaSAndroid Build Coastguard Worker     paint.setAntiAlias(true);
61*c8dee2aaSAndroid Build Coastguard Worker     paint.setPathEffect(effect);
62*c8dee2aaSAndroid Build Coastguard Worker 
63*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawPath(p1, paint);
64*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawPath(p2, paint);
65*c8dee2aaSAndroid Build Coastguard Worker 
66*c8dee2aaSAndroid Build Coastguard Worker     paint.setStyle(SkPaint::kStroke_Style);
67*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawPath(p1, paint);
68*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawPath(p2, paint);
69*c8dee2aaSAndroid Build Coastguard Worker }
70*c8dee2aaSAndroid Build Coastguard Worker 
test_drawSameRectOvals(skiatest::Reporter *,SkCanvas * canvas)71*c8dee2aaSAndroid Build Coastguard Worker static void test_drawSameRectOvals(skiatest::Reporter*, SkCanvas* canvas) {
72*c8dee2aaSAndroid Build Coastguard Worker     // Drawing ovals with similar bounds but different points order should not crash.
73*c8dee2aaSAndroid Build Coastguard Worker 
74*c8dee2aaSAndroid Build Coastguard Worker     SkPath oval1, oval2;
75*c8dee2aaSAndroid Build Coastguard Worker     const SkRect rect = SkRect::MakeWH(100, 50);
76*c8dee2aaSAndroid Build Coastguard Worker     oval1.addOval(rect, SkPathDirection::kCW);
77*c8dee2aaSAndroid Build Coastguard Worker     oval2.addOval(rect, SkPathDirection::kCCW);
78*c8dee2aaSAndroid Build Coastguard Worker 
79*c8dee2aaSAndroid Build Coastguard Worker     fill_and_stroke(canvas, oval1, oval2, nullptr);
80*c8dee2aaSAndroid Build Coastguard Worker 
81*c8dee2aaSAndroid Build Coastguard Worker     const SkScalar intervals[] = { 1, 1 };
82*c8dee2aaSAndroid Build Coastguard Worker     fill_and_stroke(canvas, oval1, oval2, SkDashPathEffect::Make(intervals, 2, 0));
83*c8dee2aaSAndroid Build Coastguard Worker }
84*c8dee2aaSAndroid Build Coastguard Worker 
DEF_GANESH_TEST_FOR_GL_CONTEXT(GpuDrawPath,reporter,ctxInfo,CtsEnforcement::kNever)85*c8dee2aaSAndroid Build Coastguard Worker DEF_GANESH_TEST_FOR_GL_CONTEXT(GpuDrawPath, reporter, ctxInfo, CtsEnforcement::kNever) {
86*c8dee2aaSAndroid Build Coastguard Worker     for (auto& test_func : { &test_drawPathEmpty, &test_drawSameRectOvals }) {
87*c8dee2aaSAndroid Build Coastguard Worker         for (auto& sampleCount : {1, 4, 16}) {
88*c8dee2aaSAndroid Build Coastguard Worker             SkImageInfo info = SkImageInfo::MakeN32Premul(255, 255);
89*c8dee2aaSAndroid Build Coastguard Worker             auto surface(SkSurfaces::RenderTarget(
90*c8dee2aaSAndroid Build Coastguard Worker                     ctxInfo.directContext(), skgpu::Budgeted::kNo, info, sampleCount, nullptr));
91*c8dee2aaSAndroid Build Coastguard Worker             if (!surface) {
92*c8dee2aaSAndroid Build Coastguard Worker                 continue;
93*c8dee2aaSAndroid Build Coastguard Worker             }
94*c8dee2aaSAndroid Build Coastguard Worker             test_func(reporter, surface->getCanvas());
95*c8dee2aaSAndroid Build Coastguard Worker         }
96*c8dee2aaSAndroid Build Coastguard Worker     }
97*c8dee2aaSAndroid Build Coastguard Worker }
98*c8dee2aaSAndroid Build Coastguard Worker 
DEF_GANESH_TEST_FOR_ALL_CONTEXTS(GrDrawCollapsedPath,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)99*c8dee2aaSAndroid Build Coastguard Worker DEF_GANESH_TEST_FOR_ALL_CONTEXTS(GrDrawCollapsedPath,
100*c8dee2aaSAndroid Build Coastguard Worker                                  reporter,
101*c8dee2aaSAndroid Build Coastguard Worker                                  ctxInfo,
102*c8dee2aaSAndroid Build Coastguard Worker                                  CtsEnforcement::kApiLevel_T) {
103*c8dee2aaSAndroid Build Coastguard Worker     // From https://bugs.fuchsia.dev/p/fuchsia/issues/detail?id=37330, it's possible for a convex
104*c8dee2aaSAndroid Build Coastguard Worker     // path to be accepted by AAConvexPathRenderer, then be transformed to something without a
105*c8dee2aaSAndroid Build Coastguard Worker     // computable first direction by a perspective matrix.
106*c8dee2aaSAndroid Build Coastguard Worker     SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100);
107*c8dee2aaSAndroid Build Coastguard Worker     auto dContext = ctxInfo.directContext();
108*c8dee2aaSAndroid Build Coastguard Worker     auto surface(SkSurfaces::RenderTarget(dContext, skgpu::Budgeted::kNo, info));
109*c8dee2aaSAndroid Build Coastguard Worker 
110*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paint;
111*c8dee2aaSAndroid Build Coastguard Worker     paint.setAntiAlias(true);
112*c8dee2aaSAndroid Build Coastguard Worker 
113*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
114*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(0, 0);
115*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(50, 0);
116*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(0, 50);
117*c8dee2aaSAndroid Build Coastguard Worker     path.close();
118*c8dee2aaSAndroid Build Coastguard Worker 
119*c8dee2aaSAndroid Build Coastguard Worker     SkMatrix m;
120*c8dee2aaSAndroid Build Coastguard Worker     m.setAll( 0.966006875f   , -0.125156224f  , 72.0899811f,
121*c8dee2aaSAndroid Build Coastguard Worker              -0.00885376986f , -0.112347461f  , 64.7121124f,
122*c8dee2aaSAndroid Build Coastguard Worker              -8.94321693e-06f, -0.00173384184f, 0.998692870f);
123*c8dee2aaSAndroid Build Coastguard Worker     surface->getCanvas()->setMatrix(m);
124*c8dee2aaSAndroid Build Coastguard Worker     surface->getCanvas()->drawPath(path, paint);
125*c8dee2aaSAndroid Build Coastguard Worker     dContext->flushAndSubmit(surface.get(), GrSyncCpu::kNo);
126*c8dee2aaSAndroid Build Coastguard Worker }
127*c8dee2aaSAndroid Build Coastguard Worker 
DEF_GANESH_TEST_FOR_ALL_CONTEXTS(PathTest_CrBug1232834,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)128*c8dee2aaSAndroid Build Coastguard Worker DEF_GANESH_TEST_FOR_ALL_CONTEXTS(PathTest_CrBug1232834,
129*c8dee2aaSAndroid Build Coastguard Worker                                  reporter,
130*c8dee2aaSAndroid Build Coastguard Worker                                  ctxInfo,
131*c8dee2aaSAndroid Build Coastguard Worker                                  CtsEnforcement::kApiLevel_T) {
132*c8dee2aaSAndroid Build Coastguard Worker     // AAHairlinePathRenderer chops this path to quads that include infinities (and then NaNs).
133*c8dee2aaSAndroid Build Coastguard Worker     // It used to trigger asserts, now the degenerate quad segments should cause it to be rejected.
134*c8dee2aaSAndroid Build Coastguard Worker     SkImageInfo info = SkImageInfo::MakeN32Premul(256, 256);
135*c8dee2aaSAndroid Build Coastguard Worker     auto dContext = ctxInfo.directContext();
136*c8dee2aaSAndroid Build Coastguard Worker     auto surface(SkSurfaces::RenderTarget(dContext, skgpu::Budgeted::kNo, info));
137*c8dee2aaSAndroid Build Coastguard Worker 
138*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paint;
139*c8dee2aaSAndroid Build Coastguard Worker     paint.setAntiAlias(true);
140*c8dee2aaSAndroid Build Coastguard Worker     paint.setStyle(SkPaint::kStroke_Style);
141*c8dee2aaSAndroid Build Coastguard Worker 
142*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
143*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(9.0072E15f, 60);
144*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(0, 3.40282e+38f, 0, 3.40282e+38f, 0, 0);
145*c8dee2aaSAndroid Build Coastguard Worker 
146*c8dee2aaSAndroid Build Coastguard Worker     surface->getCanvas()->drawPath(path, paint);
147*c8dee2aaSAndroid Build Coastguard Worker     dContext->flushAndSubmit(surface.get(), GrSyncCpu::kNo);
148*c8dee2aaSAndroid Build Coastguard Worker }
149*c8dee2aaSAndroid Build Coastguard Worker 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(StrokeCircle_Bug356182429,reporter,ctxInfo,CtsEnforcement::kNextRelease)150*c8dee2aaSAndroid Build Coastguard Worker DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(StrokeCircle_Bug356182429,
151*c8dee2aaSAndroid Build Coastguard Worker                                        reporter,
152*c8dee2aaSAndroid Build Coastguard Worker                                        ctxInfo,
153*c8dee2aaSAndroid Build Coastguard Worker                                        CtsEnforcement::kNextRelease) {
154*c8dee2aaSAndroid Build Coastguard Worker     SkImageInfo info = SkImageInfo::MakeN32Premul(256, 256);
155*c8dee2aaSAndroid Build Coastguard Worker     auto dContext = ctxInfo.directContext();
156*c8dee2aaSAndroid Build Coastguard Worker     auto surface(SkSurfaces::RenderTarget(dContext, skgpu::Budgeted::kNo, info));
157*c8dee2aaSAndroid Build Coastguard Worker 
158*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paint;
159*c8dee2aaSAndroid Build Coastguard Worker     paint.setAntiAlias(true);
160*c8dee2aaSAndroid Build Coastguard Worker     paint.setStyle(SkPaint::kStroke_Style);
161*c8dee2aaSAndroid Build Coastguard Worker     paint.setStrokeCap(SkPaint::kRound_Cap);
162*c8dee2aaSAndroid Build Coastguard Worker     paint.setStrokeWidth(15.4375f);
163*c8dee2aaSAndroid Build Coastguard Worker     paint.setStrokeMiter(2.85207834E9f);
164*c8dee2aaSAndroid Build Coastguard Worker 
165*c8dee2aaSAndroid Build Coastguard Worker     // This draw ends up in the CircleOp, and asserted because round caps are requested,
166*c8dee2aaSAndroid Build Coastguard Worker     // but the stroke is ultimately excluded (due to the negative inner stroke radius).
167*c8dee2aaSAndroid Build Coastguard Worker     // Along the way, several other bad things happen (but they don't appear relevant to the bug):
168*c8dee2aaSAndroid Build Coastguard Worker     // - MakeArcOp asserts that sweepAngle is non-zero (and it is). After converting degrees to
169*c8dee2aaSAndroid Build Coastguard Worker     //   radians, it flushes to zero, so the sweep angle stored in the ArcParams is zero.
170*c8dee2aaSAndroid Build Coastguard Worker     // - The radius of the "circle" is tiny, but it *also* flushes to zero when we call
171*c8dee2aaSAndroid Build Coastguard Worker     //   `viewMatrix.mapRadius()`, despite the view matrix being identity. This is a result of
172*c8dee2aaSAndroid Build Coastguard Worker     //   the implementation of mapRadius (computing geometric mean of the lengths of two vectors).
173*c8dee2aaSAndroid Build Coastguard Worker     SkRect oval = SkRect::MakeLTRB(0, 0, 1.83670992E-40f, 1.21223864E-38f);
174*c8dee2aaSAndroid Build Coastguard Worker     surface->getCanvas()->drawArc(oval, 8.17909887E-41f, 2.24207754E-44f, false, paint);
175*c8dee2aaSAndroid Build Coastguard Worker     dContext->flushAndSubmit(surface.get(), GrSyncCpu::kNo);
176*c8dee2aaSAndroid Build Coastguard Worker }
177