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