blob: b8e3db9c10f6bbbbe8044b514366408bb2eb74ce [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
Chris Dalton080baa42017-11-06 14:19:19 -0700157class GrCCPRTest_unregisterCulledOps : public CCPRTest {
158 void onRun(skiatest::Reporter* reporter, CCPRPathDrawer& ccpr) override {
159 REPORTER_ASSERT(reporter, SkPathPriv::TestingOnly_unique(fPath));
160
161 // Ensure Ops get unregistered from CCPR when culled early.
162 ccpr.drawPath(fPath);
163 REPORTER_ASSERT(reporter, !SkPathPriv::TestingOnly_unique(fPath));
164 ccpr.clear(); // Clear should delete the CCPR Op.
165 REPORTER_ASSERT(reporter, SkPathPriv::TestingOnly_unique(fPath));
166 ccpr.flush(); // Should not crash (DrawPathsOp should have unregistered itself).
167
168 // Ensure Op unregisters work when we delete the context without flushing.
169 ccpr.drawPath(fPath);
170 REPORTER_ASSERT(reporter, !SkPathPriv::TestingOnly_unique(fPath));
171 ccpr.clear(); // Clear should delete the CCPR DrawPathsOp.
172 REPORTER_ASSERT(reporter, SkPathPriv::TestingOnly_unique(fPath));
173 ccpr.abandonGrContext();
174 fMockContext.reset(); // Should not crash (DrawPathsOp should have unregistered itself).
175 }
176};
177DEF_CCPR_TEST(GrCCPRTest_unregisterCulledOps)
178
Chris Daltonfddb6c02017-11-04 15:22:22 -0600179class CCPRRenderingTest {
180public:
181 void run(skiatest::Reporter* reporter, GrContext* ctx) const {
182 if (!ctx->contextPriv().drawingManager()->getCoverageCountingPathRenderer()) {
183 return; // CCPR is not enabled on this GPU.
184 }
185 CCPRPathDrawer ccpr(ctx, reporter);
186 if (!ccpr.valid()) {
187 return;
188 }
189 this->onRun(reporter, ccpr);
190 }
191
192 virtual ~CCPRRenderingTest() {}
193
194protected:
195 virtual void onRun(skiatest::Reporter* reporter, const CCPRPathDrawer& ccpr) const = 0;
196};
197
198#define DEF_CCPR_RENDERING_TEST(name) \
199 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(name, reporter, ctxInfo) { \
200 name test; \
201 test.run(reporter, ctxInfo.grContext()); \
202 }
203
204class GrCCPRTest_busyPath : public CCPRRenderingTest {
205 void onRun(skiatest::Reporter* reporter, const CCPRPathDrawer& ccpr) const override {
206 static constexpr int kNumBusyVerbs = 1 << 17;
207 ccpr.clear();
208 SkPath busyPath;
209 busyPath.moveTo(0, 0); // top left
210 busyPath.lineTo(kCanvasSize, kCanvasSize); // bottom right
211 for (int i = 2; i < kNumBusyVerbs; ++i) {
212 float offset = i * ((float)kCanvasSize / kNumBusyVerbs);
213 busyPath.lineTo(kCanvasSize - offset, kCanvasSize + offset); // offscreen
214 }
215 ccpr.drawPath(busyPath);
216
217 ccpr.flush(); // If this doesn't crash, the test passed.
218 // If it does, maybe fiddle with fMaxInstancesPerDrawArraysWithoutCrashing in
219 // your platform's GrGLCaps.
220 }
221};
222DEF_CCPR_RENDERING_TEST(GrCCPRTest_busyPath)
Chris Daltoncc604e52017-10-06 16:27:32 -0600223
224#endif