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