1fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/*
2fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Copyright 2017 Google Inc.
3fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *
4fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Use of this source code is governed by a BSD-style license that can be
5fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * found in the LICENSE file.
6fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot */
7fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
8fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkTypes.h"
9fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "Test.h"
10fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
11fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if SK_SUPPORT_GPU
12fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
13fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "GrContext.h"
14fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "GrContextPriv.h"
15fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "GrClip.h"
16fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "GrDrawingManager.h"
17fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "GrPathRenderer.h"
18fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "GrPaint.h"
19fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "GrRenderTargetContext.h"
20fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "GrRenderTargetContextPriv.h"
21fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "GrShape.h"
22fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkMatrix.h"
23fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkPathPriv.h"
24fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkRect.h"
25fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "ccpr/GrCoverageCountingPathRenderer.h"
26fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "mock/GrMockTypes.h"
27fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include <cmath>
28fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
29fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic constexpr int kCanvasSize = 100;
30fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
31fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotclass CCPRClip : public GrClip {
32fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotpublic:
33fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    CCPRClip(GrCoverageCountingPathRenderer* ccpr, const SkPath& path) : fCCPR(ccpr), fPath(path) {}
34fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
35fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotprivate:
36fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool apply(GrContext* context, GrRenderTargetContext* rtc, bool, bool, GrAppliedClip* out,
37fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot               SkRect* bounds) const override {
38fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
39fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        out->addCoverageFP(fCCPR->makeClipProcessor(proxyProvider,
40fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                    rtc->priv().testingOnly_getOpListID(), fPath,
41fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                    SkIRect::MakeWH(rtc->width(), rtc->height()),
42fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                    rtc->width(), rtc->height()));
43fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return true;
44fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
45fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool quickContains(const SkRect&) const final { return false; }
46fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool isRRect(const SkRect& rtBounds, SkRRect* rr, GrAA*) const final { return false; }
47fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void getConservativeBounds(int width, int height, SkIRect* rect, bool* iior) const final {
48fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        rect->set(0, 0, width, height);
49fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (iior) {
50fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            *iior = false;
51fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
52fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
53fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    GrCoverageCountingPathRenderer* const fCCPR;
54fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkPath fPath;
55fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot};
56fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
57fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotclass CCPRPathDrawer {
58fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotpublic:
59fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    CCPRPathDrawer(GrContext* ctx, skiatest::Reporter* reporter)
60fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            : fCtx(ctx)
61fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            , fCCPR(fCtx->contextPriv().drawingManager()->getCoverageCountingPathRenderer())
62fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            , fRTC(fCtx->makeDeferredRenderTargetContext(SkBackingFit::kExact, kCanvasSize,
63fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                         kCanvasSize, kRGBA_8888_GrPixelConfig,
64fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                         nullptr)) {
65fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (!fCCPR) {
66fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            ERRORF(reporter, "ccpr not enabled in GrContext for ccpr tests");
67fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
68fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (!fRTC) {
69fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            ERRORF(reporter, "failed to create GrRenderTargetContext for ccpr tests");
70fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
71fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
72fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
73fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool valid() const { return fCCPR && fRTC; }
74fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void clear() const { fRTC->clear(nullptr, 0, GrRenderTargetContext::CanClearFullscreen::kYes); }
75fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void abandonGrContext() { fCtx = nullptr; fCCPR = nullptr; fRTC = nullptr; }
76fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
77fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void drawPath(SkPath path, GrColor4f color = GrColor4f(0, 1, 0, 1)) const {
78fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(this->valid());
79fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
80fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        GrPaint paint;
81fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        paint.setColor4f(color);
82fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
83fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        GrNoClip noClip;
84fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkIRect clipBounds = SkIRect::MakeWH(kCanvasSize, kCanvasSize);
85fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
86fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkMatrix matrix = SkMatrix::I();
87fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
88fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        path.setIsVolatile(true);
89fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        GrShape shape(path);
90fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
91fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fCCPR->drawPath({fCtx, std::move(paint), &GrUserStencilSettings::kUnused, fRTC.get(),
92fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                         &noClip, &clipBounds, &matrix, &shape, GrAAType::kCoverage, false});
93fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
94fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
95fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void clipFullscreenRect(SkPath clipPath, GrColor4f color = GrColor4f(0, 1, 0, 1)) {
96fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(this->valid());
97fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
98fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        GrPaint paint;
99fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        paint.setColor4f(color);
100fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
101fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fRTC->drawRect(CCPRClip(fCCPR, clipPath), std::move(paint), GrAA::kYes, SkMatrix::I(),
102fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                       SkRect::MakeIWH(kCanvasSize, kCanvasSize));
103fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
104fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
105fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void flush() const {
106fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(this->valid());
107fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fCtx->flush();
108fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
109fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
110fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotprivate:
111fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    GrContext*                        fCtx;
112fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    GrCoverageCountingPathRenderer*   fCCPR;
113fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    sk_sp<GrRenderTargetContext>      fRTC;
114fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot};
115fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
116fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotclass CCPRTest {
117fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotpublic:
118fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void run(skiatest::Reporter* reporter) {
119fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        GrMockOptions mockOptions;
120fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        mockOptions.fInstanceAttribSupport = true;
121fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        mockOptions.fMapBufferFlags = GrCaps::kCanMap_MapFlag;
122fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        mockOptions.fConfigOptions[kAlpha_half_GrPixelConfig].fRenderable[0] = true;
123fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        mockOptions.fConfigOptions[kAlpha_half_GrPixelConfig].fTexturable = true;
124fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        mockOptions.fGeometryShaderSupport = true;
125fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        mockOptions.fIntegerSupport = true;
126fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        mockOptions.fFlatInterpolationSupport = true;
127fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
128fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        GrContextOptions ctxOptions;
129fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ctxOptions.fAllowPathMaskCaching = false;
130fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ctxOptions.fGpuPathRenderers = GpuPathRenderers::kCoverageCounting;
131fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
132fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fMockContext = GrContext::MakeMock(&mockOptions, ctxOptions);
133fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (!fMockContext) {
134fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            ERRORF(reporter, "could not create mock context");
135fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return;
136fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
137fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (!fMockContext->unique()) {
138fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            ERRORF(reporter, "mock context is not unique");
139fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return;
140fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
141fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
142fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        CCPRPathDrawer ccpr(fMockContext.get(), reporter);
143fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (!ccpr.valid()) {
144fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return;
145fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
146fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
147fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fPath.moveTo(0, 0);
148fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fPath.cubicTo(50, 50, 0, 50, 50, 0);
149fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        this->onRun(reporter, ccpr);
150fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
151fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
152fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    virtual ~CCPRTest() {}
153fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
154fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotprotected:
155fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    virtual void onRun(skiatest::Reporter* reporter, CCPRPathDrawer& ccpr) = 0;
156fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
157fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    sk_sp<GrContext>   fMockContext;
158fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkPath             fPath;
159fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot};
160fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
161fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#define DEF_CCPR_TEST(name)                      \
162fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    DEF_GPUTEST(name, reporter, /* options */) { \
163fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        name test;                               \
164fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        test.run(reporter);                      \
165fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
166fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
167fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotclass GrCCPRTest_cleanup : public CCPRTest {
168fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void onRun(skiatest::Reporter* reporter, CCPRPathDrawer& ccpr) override {
169fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        REPORTER_ASSERT(reporter, SkPathPriv::TestingOnly_unique(fPath));
170fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
171fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // Ensure paths get unreffed.
172fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        for (int i = 0; i < 10; ++i) {
173fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            ccpr.drawPath(fPath);
174fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            ccpr.clipFullscreenRect(fPath);
175fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
176fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        REPORTER_ASSERT(reporter, !SkPathPriv::TestingOnly_unique(fPath));
177fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ccpr.flush();
178fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        REPORTER_ASSERT(reporter, SkPathPriv::TestingOnly_unique(fPath));
179fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
180fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // Ensure paths get unreffed when we delete the context without flushing.
181fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        for (int i = 0; i < 10; ++i) {
182fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            ccpr.drawPath(fPath);
183fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            ccpr.clipFullscreenRect(fPath);
184fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
185fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ccpr.abandonGrContext();
186fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        REPORTER_ASSERT(reporter, !SkPathPriv::TestingOnly_unique(fPath));
187fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fMockContext.reset();
188fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        REPORTER_ASSERT(reporter, SkPathPriv::TestingOnly_unique(fPath));
189fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
190fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot};
191fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotDEF_CCPR_TEST(GrCCPRTest_cleanup)
192fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
193fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotclass GrCCPRTest_unregisterCulledOps : public CCPRTest {
194fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void onRun(skiatest::Reporter* reporter, CCPRPathDrawer& ccpr) override {
195fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        REPORTER_ASSERT(reporter, SkPathPriv::TestingOnly_unique(fPath));
196fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
197fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // Ensure Ops get unregistered from CCPR when culled early.
198fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ccpr.drawPath(fPath);
199fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        REPORTER_ASSERT(reporter, !SkPathPriv::TestingOnly_unique(fPath));
200fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ccpr.clear(); // Clear should delete the CCPR Op.
201fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        REPORTER_ASSERT(reporter, SkPathPriv::TestingOnly_unique(fPath));
202fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ccpr.flush(); // Should not crash (DrawPathsOp should have unregistered itself).
203fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
204fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // Ensure Op unregisters work when we delete the context without flushing.
205fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ccpr.drawPath(fPath);
206fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        REPORTER_ASSERT(reporter, !SkPathPriv::TestingOnly_unique(fPath));
207fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ccpr.clear(); // Clear should delete the CCPR DrawPathsOp.
208fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        REPORTER_ASSERT(reporter, SkPathPriv::TestingOnly_unique(fPath));
209fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ccpr.abandonGrContext();
210fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fMockContext.reset(); // Should not crash (DrawPathsOp should have unregistered itself).
211fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
212fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot};
213fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotDEF_CCPR_TEST(GrCCPRTest_unregisterCulledOps)
214fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
215fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotclass GrCCPRTest_parseEmptyPath : public CCPRTest {
216fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void onRun(skiatest::Reporter* reporter, CCPRPathDrawer& ccpr) override {
217fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        REPORTER_ASSERT(reporter, SkPathPriv::TestingOnly_unique(fPath));
218fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
219fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // Make a path large enough that ccpr chooses to crop it by the RT bounds, and ends up with
220fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // an empty path.
221fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkPath largeOutsidePath;
222fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        largeOutsidePath.moveTo(-1e30f, -1e30f);
223fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        largeOutsidePath.lineTo(-1e30f, +1e30f);
224fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        largeOutsidePath.lineTo(-1e10f, +1e30f);
225fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ccpr.drawPath(largeOutsidePath);
226fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
227fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // Normally an empty path is culled before reaching ccpr, however we use a back door for
228fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // testing so this path will make it.
229fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkPath emptyPath;
230fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(emptyPath.isEmpty());
231fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ccpr.drawPath(emptyPath);
232fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
233fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // This is the test. It will exercise various internal asserts and verify we do not crash.
234fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ccpr.flush();
235fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
236fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // Now try again with clips.
237fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ccpr.clipFullscreenRect(largeOutsidePath);
238fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ccpr.clipFullscreenRect(emptyPath);
239fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ccpr.flush();
240fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
241fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // ... and both.
242fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ccpr.drawPath(largeOutsidePath);
243fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ccpr.clipFullscreenRect(largeOutsidePath);
244fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ccpr.drawPath(emptyPath);
245fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ccpr.clipFullscreenRect(emptyPath);
246fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ccpr.flush();
247fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
248fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot};
249fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotDEF_CCPR_TEST(GrCCPRTest_parseEmptyPath)
250fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
251fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotclass CCPRRenderingTest {
252fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotpublic:
253fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void run(skiatest::Reporter* reporter, GrContext* ctx) const {
254fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (!ctx->contextPriv().drawingManager()->getCoverageCountingPathRenderer()) {
255fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return; // CCPR is not enabled on this GPU.
256fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
257fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        CCPRPathDrawer ccpr(ctx, reporter);
258fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (!ccpr.valid()) {
259fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return;
260fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
261fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        this->onRun(reporter, ccpr);
262fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
263fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
264fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    virtual ~CCPRRenderingTest() {}
265fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
266fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotprotected:
267fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    virtual void onRun(skiatest::Reporter* reporter, const CCPRPathDrawer& ccpr) const = 0;
268fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot};
269fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
270fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#define DEF_CCPR_RENDERING_TEST(name) \
271fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    DEF_GPUTEST_FOR_RENDERING_CONTEXTS(name, reporter, ctxInfo) { \
272fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        name test; \
273fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        test.run(reporter, ctxInfo.grContext()); \
274fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
275fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
276fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotclass GrCCPRTest_busyPath : public CCPRRenderingTest {
277fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void onRun(skiatest::Reporter* reporter, const CCPRPathDrawer& ccpr) const override {
278fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        static constexpr int kNumBusyVerbs = 1 << 17;
279fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ccpr.clear();
280fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkPath busyPath;
281fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        busyPath.moveTo(0, 0); // top left
282fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        busyPath.lineTo(kCanvasSize, kCanvasSize); // bottom right
283fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        for (int i = 2; i < kNumBusyVerbs; ++i) {
284fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            float offset = i * ((float)kCanvasSize / kNumBusyVerbs);
285fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            busyPath.lineTo(kCanvasSize - offset, kCanvasSize + offset); // offscreen
286fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
287fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ccpr.drawPath(busyPath);
288fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
289fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ccpr.flush(); // If this doesn't crash, the test passed.
290fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                      // If it does, maybe fiddle with fMaxInstancesPerDrawArraysWithoutCrashing in
291fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                      // your platform's GrGLCaps.
292fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
293fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot};
294fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotDEF_CCPR_RENDERING_TEST(GrCCPRTest_busyPath)
295fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
296fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
297