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