blob: 2a640347111460ef34764c513e0ccb2d0ccfaca9 [file] [log] [blame]
Chris Dalton5b5403e2019-06-05 11:54:39 -06001/*
2 * Copyright 2019 Google LLC.
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
10#include "include/core/SkPath.h"
11#include "include/gpu/GrContext.h"
12#include "include/gpu/GrContextOptions.h"
Robert Phillipsb7bfbc22020-07-01 12:55:01 -040013#include "include/gpu/GrRecordingContext.h"
Chris Dalton5b5403e2019-06-05 11:54:39 -060014#include "src/gpu/GrContextPriv.h"
15#include "src/gpu/GrDrawingManager.h"
Robert Phillips95c250c2020-06-29 15:36:12 -040016#include "src/gpu/GrRecordingContextPriv.h"
Chris Dalton5b5403e2019-06-05 11:54:39 -060017#include "src/gpu/GrRenderTargetContext.h"
18#include "src/gpu/ccpr/GrCCPathCache.h"
19#include "src/gpu/ccpr/GrCoverageCountingPathRenderer.h"
20#include "tools/ToolUtils.h"
21
22namespace skiagm {
23
24#define ERR_MSG_ASSERT(COND) \
25 do { \
26 if (!(COND)) { \
27 errorMsg->printf("preservefillrule.cpp(%i): assert(%s)", \
28 __LINE__, #COND); \
29 return DrawResult::kFail; \
30 } \
31 } while (false)
32
33
34/**
35 * This test ensures that the ccpr path cache preserves fill rules properly, both in the case where
36 * we copy paths into a8 literal coverage atlases, as well as in the case where we just reuse a
37 * stashed fp16 coverage count atlas.
38 */
39class PreserveFillRuleGM : public GpuGM {
40public:
41 // fStarSize affects whether ccpr copies the paths to an a8 literal coverage atlas, or just
42 // leaves them stashed in an fp16 coverage count atlas. The threshold for copying to a8 is
43 // currently 256x256 total pixels copied. If this ever changes, there is code in onDraw that
44 // will detect the unexpected behavior and draw a failure message.
45 PreserveFillRuleGM(bool literalCoverageAtlas)
46 : fLiteralCoverageAtlas(literalCoverageAtlas)
47 , fStarSize((fLiteralCoverageAtlas) ? 200 : 20) {
48 }
49
50private:
51 SkString onShortName() override {
52 SkString name("preservefillrule");
53 name += (fLiteralCoverageAtlas) ? "_big" : "_little";
54 return name;
55 }
56 SkISize onISize() override { return SkISize::Make(fStarSize * 2, fStarSize * 2); }
57
58 void modifyGrContextOptions(GrContextOptions* ctxOptions) override {
59 ctxOptions->fGpuPathRenderers = GpuPathRenderers::kCoverageCounting;
60 ctxOptions->fAllowPathMaskCaching = true;
61 }
62
Robert Phillips95c250c2020-06-29 15:36:12 -040063 DrawResult onDraw(GrRecordingContext* ctx, GrRenderTargetContext* rtc, SkCanvas* canvas,
Chris Dalton5b5403e2019-06-05 11:54:39 -060064 SkString* errorMsg) override {
65 using CoverageType = GrCCAtlas::CoverageType;
66
Chris Daltonc3318f02019-07-19 14:20:53 -060067 if (rtc->numSamples() > 1) {
68 errorMsg->set("ccpr is currently only used for coverage AA");
69 return DrawResult::kSkip;
70 }
71
Chris Dalton5b5403e2019-06-05 11:54:39 -060072 auto* ccpr = ctx->priv().drawingManager()->getCoverageCountingPathRenderer();
73 if (!ccpr) {
74 errorMsg->set("ccpr only");
75 return DrawResult::kSkip;
76 }
77
78 auto pathCache = ccpr->testingOnly_getPathCache();
79 if (!pathCache) {
80 errorMsg->set("ccpr is not in caching mode. "
81 "Are you using viewer? Launch with \"--cachePathMasks true\".");
82 return DrawResult::kFail;
83 }
84
85 auto starRect = SkRect::MakeWH(fStarSize, fStarSize);
86 SkPath star7_winding = ToolUtils::make_star(starRect, 7);
Mike Reed7d34dc72019-11-26 12:17:17 -050087 star7_winding.setFillType(SkPathFillType::kWinding);
Chris Dalton5b5403e2019-06-05 11:54:39 -060088
89 SkPath star7_evenOdd = star7_winding;
Mike Reed1f607332020-05-21 12:11:27 -040090 star7_evenOdd.transform(SkMatrix::Translate(0, fStarSize));
Mike Reed7d34dc72019-11-26 12:17:17 -050091 star7_evenOdd.setFillType(SkPathFillType::kEvenOdd);
Chris Dalton5b5403e2019-06-05 11:54:39 -060092
93 SkPath star5_winding = ToolUtils::make_star(starRect, 5);
Mike Reed1f607332020-05-21 12:11:27 -040094 star5_winding.transform(SkMatrix::Translate(fStarSize, 0));
Mike Reed7d34dc72019-11-26 12:17:17 -050095 star5_winding.setFillType(SkPathFillType::kWinding);
Chris Dalton5b5403e2019-06-05 11:54:39 -060096
97 SkPath star5_evenOdd = star5_winding;
Mike Reed1f607332020-05-21 12:11:27 -040098 star5_evenOdd.transform(SkMatrix::Translate(0, fStarSize));
Mike Reed7d34dc72019-11-26 12:17:17 -050099 star5_evenOdd.setFillType(SkPathFillType::kEvenOdd);
Chris Dalton5b5403e2019-06-05 11:54:39 -0600100
101 SkPaint paint;
102 paint.setColor(SK_ColorGREEN);
103 paint.setAntiAlias(true);
104
105 for (int i = 0; i < 3; ++i) {
106 canvas->clear(SK_ColorWHITE);
107 canvas->drawPath(star7_winding, paint);
108 canvas->drawPath(star7_evenOdd, paint);
109 canvas->drawPath(star5_winding, paint);
110 canvas->drawPath(star5_evenOdd, paint);
Greg Daniel9efe3862020-06-11 11:51:06 -0400111 rtc->flush(SkSurface::BackendSurfaceAccess::kNoAccess, GrFlushInfo(), nullptr);
Chris Dalton5b5403e2019-06-05 11:54:39 -0600112
113 // Ensure the path cache is behaving in such a way that we are actually testing what we
114 // think we are.
115 int numCachedPaths = 0;
116 for (GrCCPathCacheEntry* entry : pathCache->testingOnly_getLRU()) {
117 if (0 == i) {
118 // We don't cache an atlas on the first hit.
119 ERR_MSG_ASSERT(!entry->cachedAtlas());
120 } else {
121 // The stars should be cached in an atlas now.
122 ERR_MSG_ASSERT(entry->cachedAtlas());
123
124 CoverageType atlasCoverageType = entry->cachedAtlas()->coverageType();
125 if (i < 2) {
126 // We never copy to an a8 atlas before the second hit.
Chris Daltonc3318f02019-07-19 14:20:53 -0600127 ERR_MSG_ASSERT(ccpr->coverageType() == atlasCoverageType);
Chris Dalton5b5403e2019-06-05 11:54:39 -0600128 } else if (fLiteralCoverageAtlas) {
129 // Verify fStarSize is large enough that the paths got copied to an a8
130 // atlas.
131 ERR_MSG_ASSERT(CoverageType::kA8_LiteralCoverage == atlasCoverageType);
132 } else {
133 // Verify fStarSize is small enough that the paths did *NOT* get copied to
134 // an a8 atlas.
Chris Daltonc3318f02019-07-19 14:20:53 -0600135 ERR_MSG_ASSERT(ccpr->coverageType() == atlasCoverageType);
Chris Dalton5b5403e2019-06-05 11:54:39 -0600136 }
137 }
138 ++numCachedPaths;
139 }
140 // Verify all 4 paths are tracked by the path cache.
141 ERR_MSG_ASSERT(4 == numCachedPaths);
142 }
143
144 return DrawResult::kOk;
145 }
146
147private:
148 const bool fLiteralCoverageAtlas;
149 const int fStarSize;
150};
151
152DEF_GM( return new PreserveFillRuleGM(true); )
153DEF_GM( return new PreserveFillRuleGM(false); )
154
155}