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