• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2020 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 "gm/gm.h"
9 #include "include/core/SkCanvas.h"
10 #include "include/core/SkPath.h"
11 #include "include/core/SkPoint.h"
12 #include "include/gpu/GrContextOptions.h"
13 #include "include/gpu/GrDirectContext.h"
14 #include "include/utils/SkRandom.h"
15 #include "src/gpu/GrCaps.h"
16 #include "src/gpu/GrDirectContextPriv.h"
17 #include "src/gpu/GrDrawingManager.h"
18 #include "src/gpu/GrRecordingContextPriv.h"
19 #include "src/gpu/ops/TessellationPathRenderer.h"
20 
21 static constexpr float kStrokeWidth = 100;
22 static constexpr int kTestWidth = 120 * 4;
23 static constexpr int kTestHeight = 120 * 3 + 140;
24 
draw_strokes(SkCanvas * canvas,SkRandom * rand,const SkPath & path,const SkPath & cubic)25 static void draw_strokes(SkCanvas* canvas, SkRandom* rand, const SkPath& path,
26                          const SkPath& cubic) {
27     SkPaint strokePaint;
28     strokePaint.setAntiAlias(true);
29     strokePaint.setStrokeWidth(kStrokeWidth);
30     strokePaint.setStyle(SkPaint::kStroke_Style);
31 
32     SkAutoCanvasRestore arc(canvas, true);
33     strokePaint.setStrokeJoin(SkPaint::kBevel_Join);
34     strokePaint.setColor(rand->nextU() | 0xff808080);
35     canvas->drawPath(path, strokePaint);
36 
37     canvas->translate(120, 0);
38     strokePaint.setStrokeJoin(SkPaint::kRound_Join);
39     strokePaint.setColor(rand->nextU() | 0xff808080);
40     canvas->drawPath(path, strokePaint);
41 
42     canvas->translate(120, 0);
43     strokePaint.setStrokeJoin(SkPaint::kMiter_Join);
44     strokePaint.setColor(rand->nextU() | 0xff808080);
45     canvas->drawPath(path, strokePaint);
46 
47     canvas->translate(120, 0);
48     strokePaint.setColor(rand->nextU() | 0xff808080);
49     canvas->drawPath(cubic, strokePaint);
50 }
51 
draw_test(SkCanvas * canvas)52 static void draw_test(SkCanvas* canvas) {
53     SkRandom rand;
54 
55     if (canvas->recordingContext() &&
56         canvas->recordingContext()->priv().caps()->shaderCaps()->tessellationSupport() &&
57         canvas->recordingContext()->priv().caps()->shaderCaps()->maxTessellationSegments() == 5) {
58         // The caller successfully overrode the max tessellation segments to 5. Indicate this in the
59         // background color.
60         canvas->clear(SkColorSetARGB(255, 64, 0, 0));
61     } else {
62         canvas->clear(SK_ColorBLACK);
63     }
64 
65     SkAutoCanvasRestore arc(canvas, true);
66     canvas->translate(60, 60);
67 
68     draw_strokes(canvas, &rand,
69             SkPath().lineTo(10,0).lineTo(10,10),
70             SkPath().cubicTo(10,0, 10,0, 10,10));
71     canvas->translate(0, 120);
72 
73     draw_strokes(canvas, &rand,
74             SkPath().lineTo(0,-10).lineTo(0,10),
75             SkPath().cubicTo(0,-10, 0,-10, 0,10));
76     canvas->translate(0, 120);
77 
78     draw_strokes(canvas, &rand,
79             SkPath().lineTo(0,-10).lineTo(10,-10).lineTo(10,10).lineTo(0,10),
80             SkPath().cubicTo(0,-10, 10,10, 0,10));
81     canvas->translate(0, 140);
82 
83     draw_strokes(canvas, &rand,
84             SkPath().lineTo(0,-10).lineTo(10,-10).lineTo(10,0).lineTo(0,0),
85             SkPath().cubicTo(0,-10, 10,0, 0,0));
86     canvas->translate(0, 120);
87 }
88 
DEF_SIMPLE_GM(widebuttcaps,canvas,kTestWidth,kTestHeight)89 DEF_SIMPLE_GM(widebuttcaps, canvas, kTestWidth, kTestHeight) {
90     canvas->clear(SK_ColorBLACK);
91     draw_test(canvas);
92 }
93 
94 class WideButtCaps_tess_segs_5 : public skiagm::GM {
onShortName()95     SkString onShortName() override {
96         return SkString("widebuttcaps_tess_segs_5");
97     }
98 
onISize()99     SkISize onISize() override {
100         return SkISize::Make(kTestWidth, kTestHeight);
101     }
102 
103     // Pick a very small, odd (and better yet, prime) number of segments.
104     //
105     // - Odd because it makes the tessellation strip asymmetric, which will be important to test for
106     //   future plans that involve drawing in reverse order.
107     //
108     // - >=4 because the tessellator code will just assume we have enough to combine a miter join
109     //   and line in a single patch. (Requires 4 segments. Spec required minimum is 64.)
110     inline static constexpr int kMaxTessellationSegmentsOverride = 5;
111 
modifyGrContextOptions(GrContextOptions * options)112     void modifyGrContextOptions(GrContextOptions* options) override {
113         options->fMaxTessellationSegmentsOverride = kMaxTessellationSegmentsOverride;
114         options->fAlwaysPreferHardwareTessellation = true;
115         // Only allow the tessellation path renderer.
116         options->fGpuPathRenderers = (GpuPathRenderers)((int)options->fGpuPathRenderers &
117                                                         (int)GpuPathRenderers::kTessellation);
118     }
119 
onDraw(SkCanvas * canvas,SkString * errorMsg)120     DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
121         auto dContext = GrAsDirectContext(canvas->recordingContext());
122         if (!dContext) {
123             *errorMsg = "GM relies on having access to a live direct context.";
124             return DrawResult::kSkip;
125         }
126 
127         if (!dContext->priv().caps()->shaderCaps()->tessellationSupport() ||
128             !skgpu::v1::TessellationPathRenderer::IsSupported(*dContext->priv().caps())) {
129             errorMsg->set("Tessellation not supported.");
130             return DrawResult::kSkip;
131         }
132         auto opts = dContext->priv().drawingManager()->testingOnly_getOptionsForPathRendererChain();
133         if (!(opts.fGpuPathRenderers & GpuPathRenderers::kTessellation)) {
134             errorMsg->set("TessellationPathRenderer disabled.");
135             return DrawResult::kSkip;
136         }
137         if (dContext->priv().caps()->shaderCaps()->maxTessellationSegments() !=
138             kMaxTessellationSegmentsOverride) {
139             errorMsg->set("modifyGrContextOptions() did not limit maxTessellationSegments. "
140                           "(Are you running viewer? If so use '--maxTessellationSegments 5'.)");
141             return DrawResult::kFail;
142         }
143         // Suppress a tessellator warning message that caps.maxTessellationSegments is too small.
144         GrRecordingContextPriv::AutoSuppressWarningMessages aswm(dContext);
145         draw_test(canvas);
146         return DrawResult::kOk;
147     }
148 };
149 
150 DEF_GM( return new WideButtCaps_tess_segs_5; )
151