blob: f56298be5ab1901c4035c4a483e872729160b9e9 [file] [log] [blame]
Chris Daltoncc604e52017-10-06 16:27:32 -06001/*
2 * Copyright 2017 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 "SkTypes.h"
9#include "Test.h"
10
11#if SK_SUPPORT_GPU
12
13#include "GrContext.h"
14#include "GrContextPriv.h"
15#include "GrClip.h"
Chris Daltonfddb6c02017-11-04 15:22:22 -060016#include "GrDrawingManager.h"
17#include "GrPathRenderer.h"
18#include "GrPaint.h"
Chris Daltoncc604e52017-10-06 16:27:32 -060019#include "GrRenderTargetContext.h"
20#include "GrRenderTargetContextPriv.h"
21#include "GrShape.h"
Chris Daltoncc604e52017-10-06 16:27:32 -060022#include "SkMatrix.h"
Chris Daltonfddb6c02017-11-04 15:22:22 -060023#include "SkPathPriv.h"
Chris Daltoncc604e52017-10-06 16:27:32 -060024#include "SkRect.h"
25#include "ccpr/GrCoverageCountingPathRenderer.h"
Chris Daltonfddb6c02017-11-04 15:22:22 -060026#include "mock/GrMockTypes.h"
Chris Daltoncc604e52017-10-06 16:27:32 -060027#include <cmath>
28
29static constexpr int kCanvasSize = 100;
30
31class CCPRPathDrawer {
32public:
Chris Daltonfddb6c02017-11-04 15:22:22 -060033 CCPRPathDrawer(GrContext* ctx, skiatest::Reporter* reporter)
Chris Daltoncc604e52017-10-06 16:27:32 -060034 : fCtx(ctx)
Chris Daltonfddb6c02017-11-04 15:22:22 -060035 , fCCPR(fCtx->contextPriv().drawingManager()->getCoverageCountingPathRenderer())
Chris Daltoncc604e52017-10-06 16:27:32 -060036 , fRTC(fCtx->makeDeferredRenderTargetContext(SkBackingFit::kExact, kCanvasSize,
37 kCanvasSize, kRGBA_8888_GrPixelConfig,
38 nullptr)) {
Chris Daltonfddb6c02017-11-04 15:22:22 -060039 if (!fCCPR) {
40 ERRORF(reporter, "ccpr not enabled in GrContext for ccpr tests");
41 }
42 if (!fRTC) {
43 ERRORF(reporter, "failed to create GrRenderTargetContext for ccpr tests");
Chris Daltoncc604e52017-10-06 16:27:32 -060044 }
45 }
46
Chris Daltonfddb6c02017-11-04 15:22:22 -060047 bool valid() const { return fCCPR && fRTC; }
48 void clear() const { fRTC->clear(nullptr, 0, true); }
49 void abandonGrContext() { fCtx = nullptr; fCCPR = nullptr; fRTC = nullptr; }
Chris Daltoncc604e52017-10-06 16:27:32 -060050
Chris Daltonfddb6c02017-11-04 15:22:22 -060051 void drawPath(SkPath path, GrColor4f color = GrColor4f(0, 1, 0, 1)) const {
52 SkASSERT(this->valid());
Chris Daltoncc604e52017-10-06 16:27:32 -060053
Chris Daltoncc604e52017-10-06 16:27:32 -060054 GrPaint paint;
55 paint.setColor4f(color);
Chris Daltonfddb6c02017-11-04 15:22:22 -060056
Chris Daltoncc604e52017-10-06 16:27:32 -060057 GrNoClip noClip;
58 SkIRect clipBounds = SkIRect::MakeWH(kCanvasSize, kCanvasSize);
Chris Daltonfddb6c02017-11-04 15:22:22 -060059
Chris Daltoncc604e52017-10-06 16:27:32 -060060 SkMatrix matrix = SkMatrix::I();
Chris Daltonfddb6c02017-11-04 15:22:22 -060061
62 path.setIsVolatile(true);
Chris Daltoncc604e52017-10-06 16:27:32 -060063 GrShape shape(path);
Chris Daltonfddb6c02017-11-04 15:22:22 -060064
Chris Daltoncc604e52017-10-06 16:27:32 -060065 fCCPR->drawPath({fCtx, std::move(paint), &GrUserStencilSettings::kUnused, fRTC.get(),
66 &noClip, &clipBounds, &matrix, &shape, GrAAType::kCoverage, false});
67 }
68
Chris Daltonfddb6c02017-11-04 15:22:22 -060069 void flush() const {
70 SkASSERT(this->valid());
Chris Daltoncc604e52017-10-06 16:27:32 -060071 fCtx->flush();
72 }
73
74private:
Chris Daltonfddb6c02017-11-04 15:22:22 -060075 GrContext* fCtx;
76 GrCoverageCountingPathRenderer* fCCPR;
77 sk_sp<GrRenderTargetContext> fRTC;
Chris Daltoncc604e52017-10-06 16:27:32 -060078};
79
Chris Daltonfddb6c02017-11-04 15:22:22 -060080class CCPRTest {
81public:
82 void run(skiatest::Reporter* reporter) {
83 GrMockOptions mockOptions;
84 mockOptions.fInstanceAttribSupport = true;
85 mockOptions.fMapBufferFlags = GrCaps::kCanMap_MapFlag;
86 mockOptions.fConfigOptions[kAlpha_half_GrPixelConfig].fRenderable[0] = true;
87 mockOptions.fConfigOptions[kAlpha_half_GrPixelConfig].fTexturable = true;
88 mockOptions.fGeometryShaderSupport = true;
89 mockOptions.fTexelBufferSupport = true;
90 mockOptions.fIntegerSupport = true;
91 mockOptions.fFlatInterpolationSupport = true;
92 mockOptions.fMaxVertexSamplers = 1;
93
94 GrContextOptions ctxOptions;
95 ctxOptions.fAllowPathMaskCaching = false;
96 ctxOptions.fGpuPathRenderers = GpuPathRenderers::kCoverageCounting;
97
98 fMockContext = GrContext::MakeMock(&mockOptions, ctxOptions);
99 if (!fMockContext) {
100 ERRORF(reporter, "could not create mock context");
101 return;
102 }
103 if (!fMockContext->unique()) {
104 ERRORF(reporter, "mock context is not unique");
105 return;
106 }
107
108 CCPRPathDrawer ccpr(fMockContext.get(), reporter);
109 if (!ccpr.valid()) {
110 return;
111 }
112
113 fPath.moveTo(0, 0);
114 fPath.cubicTo(50, 50, 0, 50, 50, 0);
115 this->onRun(reporter, ccpr);
Chris Daltoncc604e52017-10-06 16:27:32 -0600116 }
117
Chris Daltonfddb6c02017-11-04 15:22:22 -0600118 virtual ~CCPRTest() {}
119
120protected:
121 virtual void onRun(skiatest::Reporter* reporter, CCPRPathDrawer& ccpr) = 0;
122
123 sk_sp<GrContext> fMockContext;
124 SkPath fPath;
125};
126
127#define DEF_CCPR_TEST(name) \
128 DEF_GPUTEST(name, reporter, factory) { \
129 name test; \
130 test.run(reporter); \
Chris Daltoncc604e52017-10-06 16:27:32 -0600131 }
132
Chris Daltonfddb6c02017-11-04 15:22:22 -0600133class GrCCPRTest_cleanup : public CCPRTest {
134 void onRun(skiatest::Reporter* reporter, CCPRPathDrawer& ccpr) override {
135 REPORTER_ASSERT(reporter, SkPathPriv::TestingOnly_unique(fPath));
Chris Daltoncc604e52017-10-06 16:27:32 -0600136
Chris Daltonfddb6c02017-11-04 15:22:22 -0600137 // Ensure paths get unreffed.
138 for (int i = 0; i < 10; ++i) {
139 ccpr.drawPath(fPath);
140 }
141 REPORTER_ASSERT(reporter, !SkPathPriv::TestingOnly_unique(fPath));
142 ccpr.flush();
143 REPORTER_ASSERT(reporter, SkPathPriv::TestingOnly_unique(fPath));
144
145 // Ensure paths get unreffed when we delete the context without flushing.
146 for (int i = 0; i < 10; ++i) {
147 ccpr.drawPath(fPath);
148 }
149 ccpr.abandonGrContext();
150 REPORTER_ASSERT(reporter, !SkPathPriv::TestingOnly_unique(fPath));
151 fMockContext.reset();
152 REPORTER_ASSERT(reporter, SkPathPriv::TestingOnly_unique(fPath));
153 }
154};
155DEF_CCPR_TEST(GrCCPRTest_cleanup)
156
157class CCPRRenderingTest {
158public:
159 void run(skiatest::Reporter* reporter, GrContext* ctx) const {
160 if (!ctx->contextPriv().drawingManager()->getCoverageCountingPathRenderer()) {
161 return; // CCPR is not enabled on this GPU.
162 }
163 CCPRPathDrawer ccpr(ctx, reporter);
164 if (!ccpr.valid()) {
165 return;
166 }
167 this->onRun(reporter, ccpr);
168 }
169
170 virtual ~CCPRRenderingTest() {}
171
172protected:
173 virtual void onRun(skiatest::Reporter* reporter, const CCPRPathDrawer& ccpr) const = 0;
174};
175
176#define DEF_CCPR_RENDERING_TEST(name) \
177 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(name, reporter, ctxInfo) { \
178 name test; \
179 test.run(reporter, ctxInfo.grContext()); \
180 }
181
182class GrCCPRTest_busyPath : public CCPRRenderingTest {
183 void onRun(skiatest::Reporter* reporter, const CCPRPathDrawer& ccpr) const override {
184 static constexpr int kNumBusyVerbs = 1 << 17;
185 ccpr.clear();
186 SkPath busyPath;
187 busyPath.moveTo(0, 0); // top left
188 busyPath.lineTo(kCanvasSize, kCanvasSize); // bottom right
189 for (int i = 2; i < kNumBusyVerbs; ++i) {
190 float offset = i * ((float)kCanvasSize / kNumBusyVerbs);
191 busyPath.lineTo(kCanvasSize - offset, kCanvasSize + offset); // offscreen
192 }
193 ccpr.drawPath(busyPath);
194
195 ccpr.flush(); // If this doesn't crash, the test passed.
196 // If it does, maybe fiddle with fMaxInstancesPerDrawArraysWithoutCrashing in
197 // your platform's GrGLCaps.
198 }
199};
200DEF_CCPR_RENDERING_TEST(GrCCPRTest_busyPath)
Chris Daltoncc604e52017-10-06 16:27:32 -0600201
202#endif