blob: 2dbd1a6684346244a01c52e1b550dc9def5cb0a5 [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"
Adlai Hollera0693042020-10-14 11:23:11 -040013#include "src/gpu/GrDirectContextPriv.h"
Chris Dalton5b5403e2019-06-05 11:54:39 -060014#include "src/gpu/GrDrawingManager.h"
Robert Phillips95c250c2020-06-29 15:36:12 -040015#include "src/gpu/GrRecordingContextPriv.h"
Brian Salomoneebe7352020-12-09 16:37:04 -050016#include "src/gpu/GrSurfaceDrawContext.h"
Chris Dalton5b5403e2019-06-05 11:54:39 -060017#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
Brian Salomoneebe7352020-12-09 16:37:04 -050062 DrawResult onDraw(GrRecordingContext* rContext, GrSurfaceDrawContext* 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
Robert Phillips27f283f2020-10-14 11:46:51 -040071 auto* ccpr = rContext->priv().drawingManager()->getCoverageCountingPathRenderer();
Chris Dalton5b5403e2019-06-05 11:54:39 -060072 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
Robert Phillips27f283f2020-10-14 11:46:51 -040084 auto dContext = GrAsDirectContext(rContext);
Robert Phillips267826c2020-11-10 11:10:09 -050085 if (!dContext) {
86 *errorMsg = "Requires a direct context.";
87 return skiagm::DrawResult::kSkip;
88 }
Robert Phillips27f283f2020-10-14 11:46:51 -040089
Chris Dalton5b5403e2019-06-05 11:54:39 -060090 auto starRect = SkRect::MakeWH(fStarSize, fStarSize);
91 SkPath star7_winding = ToolUtils::make_star(starRect, 7);
Mike Reed7d34dc72019-11-26 12:17:17 -050092 star7_winding.setFillType(SkPathFillType::kWinding);
Chris Dalton5b5403e2019-06-05 11:54:39 -060093
94 SkPath star7_evenOdd = star7_winding;
Mike Reed1f607332020-05-21 12:11:27 -040095 star7_evenOdd.transform(SkMatrix::Translate(0, fStarSize));
Mike Reed7d34dc72019-11-26 12:17:17 -050096 star7_evenOdd.setFillType(SkPathFillType::kEvenOdd);
Chris Dalton5b5403e2019-06-05 11:54:39 -060097
98 SkPath star5_winding = ToolUtils::make_star(starRect, 5);
Mike Reed1f607332020-05-21 12:11:27 -040099 star5_winding.transform(SkMatrix::Translate(fStarSize, 0));
Mike Reed7d34dc72019-11-26 12:17:17 -0500100 star5_winding.setFillType(SkPathFillType::kWinding);
Chris Dalton5b5403e2019-06-05 11:54:39 -0600101
102 SkPath star5_evenOdd = star5_winding;
Mike Reed1f607332020-05-21 12:11:27 -0400103 star5_evenOdd.transform(SkMatrix::Translate(0, fStarSize));
Mike Reed7d34dc72019-11-26 12:17:17 -0500104 star5_evenOdd.setFillType(SkPathFillType::kEvenOdd);
Chris Dalton5b5403e2019-06-05 11:54:39 -0600105
106 SkPaint paint;
107 paint.setColor(SK_ColorGREEN);
108 paint.setAntiAlias(true);
109
110 for (int i = 0; i < 3; ++i) {
111 canvas->clear(SK_ColorWHITE);
112 canvas->drawPath(star7_winding, paint);
113 canvas->drawPath(star7_evenOdd, paint);
114 canvas->drawPath(star5_winding, paint);
115 canvas->drawPath(star5_evenOdd, paint);
Robert Phillips80bfda82020-11-12 09:23:36 -0500116 dContext->priv().flushSurface(rtc->asSurfaceProxy());
Chris Dalton5b5403e2019-06-05 11:54:39 -0600117
118 // Ensure the path cache is behaving in such a way that we are actually testing what we
119 // think we are.
120 int numCachedPaths = 0;
121 for (GrCCPathCacheEntry* entry : pathCache->testingOnly_getLRU()) {
122 if (0 == i) {
123 // We don't cache an atlas on the first hit.
124 ERR_MSG_ASSERT(!entry->cachedAtlas());
125 } else {
126 // The stars should be cached in an atlas now.
127 ERR_MSG_ASSERT(entry->cachedAtlas());
128
129 CoverageType atlasCoverageType = entry->cachedAtlas()->coverageType();
130 if (i < 2) {
131 // We never copy to an a8 atlas before the second hit.
Chris Daltonc3318f02019-07-19 14:20:53 -0600132 ERR_MSG_ASSERT(ccpr->coverageType() == atlasCoverageType);
Chris Dalton5b5403e2019-06-05 11:54:39 -0600133 } else if (fLiteralCoverageAtlas) {
134 // Verify fStarSize is large enough that the paths got copied to an a8
135 // atlas.
136 ERR_MSG_ASSERT(CoverageType::kA8_LiteralCoverage == atlasCoverageType);
137 } else {
138 // Verify fStarSize is small enough that the paths did *NOT* get copied to
139 // an a8 atlas.
Chris Daltonc3318f02019-07-19 14:20:53 -0600140 ERR_MSG_ASSERT(ccpr->coverageType() == atlasCoverageType);
Chris Dalton5b5403e2019-06-05 11:54:39 -0600141 }
142 }
143 ++numCachedPaths;
144 }
Robert Phillips27f283f2020-10-14 11:46:51 -0400145
146 if (dContext) {
147 // Verify all 4 paths are tracked by the path cache.
148 ERR_MSG_ASSERT(4 == numCachedPaths);
149 }
Chris Dalton5b5403e2019-06-05 11:54:39 -0600150 }
151
152 return DrawResult::kOk;
153 }
154
155private:
156 const bool fLiteralCoverageAtlas;
157 const int fStarSize;
158};
159
160DEF_GM( return new PreserveFillRuleGM(true); )
161DEF_GM( return new PreserveFillRuleGM(false); )
162
John Stilesa6841be2020-08-06 14:11:56 -0400163} // namespace skiagm