1 /*
2 * Copyright 2018 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 "src/gpu/ccpr/GrCCPerFlushResources.h"
9
10 #include "include/gpu/GrRecordingContext.h"
11 #include "src/core/SkIPoint16.h"
12 #include "src/gpu/GrFixedClip.h"
13 #include "src/gpu/GrMemoryPool.h"
14 #include "src/gpu/GrOnFlushResourceProvider.h"
15 #include "src/gpu/GrRecordingContextPriv.h"
16 #include "src/gpu/GrSurfaceDrawContext.h"
17 #include "src/gpu/geometry/GrStyledShape.h"
18 #include "src/gpu/ops/GrFillRectOp.h"
19
GrCCPerFlushResources(GrOnFlushResourceProvider * onFlushRP,const GrCCAtlas::Specs & specs)20 GrCCPerFlushResources::GrCCPerFlushResources(GrOnFlushResourceProvider* onFlushRP,
21 const GrCCAtlas::Specs& specs)
22 : fAtlasSpecs(specs) {
23 }
24
renderDeviceSpacePathInAtlas(GrOnFlushResourceProvider * onFlushRP,const SkIRect & clipIBounds,const SkPath & devPath,const SkIRect & devPathIBounds,GrFillRule fillRule,SkIVector * devToAtlasOffset)25 std::unique_ptr<GrCCAtlas> GrCCPerFlushResources::renderDeviceSpacePathInAtlas(
26 GrOnFlushResourceProvider* onFlushRP, const SkIRect& clipIBounds, const SkPath& devPath,
27 const SkIRect& devPathIBounds, GrFillRule fillRule, SkIVector* devToAtlasOffset) {
28 SkASSERT(!devPath.isEmpty());
29 GrScissorTest enableScissorInAtlas;
30 SkIRect clippedPathIBounds;
31 if (clipIBounds.contains(devPathIBounds)) {
32 clippedPathIBounds = devPathIBounds;
33 enableScissorInAtlas = GrScissorTest::kDisabled;
34 } else {
35 SkAssertResult(clippedPathIBounds.intersect(clipIBounds, devPathIBounds));
36 enableScissorInAtlas = GrScissorTest::kEnabled;
37 }
38
39 auto retiredAtlas = this->placeRenderedPathInAtlas(onFlushRP, clippedPathIBounds,
40 enableScissorInAtlas, devToAtlasOffset);
41
42 SkMatrix atlasMatrix = SkMatrix::Translate(devToAtlasOffset->fX, devToAtlasOffset->fY);
43 this->enqueueRenderedPath(devPath, fillRule, clippedPathIBounds, atlasMatrix,
44 enableScissorInAtlas, *devToAtlasOffset);
45
46 return retiredAtlas;
47 }
48
placeRenderedPathInAtlas(GrOnFlushResourceProvider * onFlushRP,const SkIRect & clippedPathIBounds,GrScissorTest scissorTest,SkIVector * devToAtlasOffset)49 std::unique_ptr<GrCCAtlas> GrCCPerFlushResources::placeRenderedPathInAtlas(
50 GrOnFlushResourceProvider* onFlushRP, const SkIRect& clippedPathIBounds,
51 GrScissorTest scissorTest, SkIVector* devToAtlasOffset) {
52 std::unique_ptr<GrCCAtlas> retiredAtlas;
53 SkIPoint16 location;
54 if (!fAtlas ||
55 !fAtlas->addRect(clippedPathIBounds.width(), clippedPathIBounds.height(), &location)) {
56 // The retired atlas is out of room and can't grow any bigger.
57 if (fAtlas) {
58 this->flushRenderedPaths(onFlushRP);
59 retiredAtlas = std::move(fAtlas);
60 }
61 fAtlas = std::make_unique<GrCCAtlas>(fAtlasSpecs, *onFlushRP->caps());
62 SkASSERT(clippedPathIBounds.width() <= fAtlasSpecs.fMinWidth);
63 SkASSERT(clippedPathIBounds.height() <= fAtlasSpecs.fMinHeight);
64 SkAssertResult(fAtlas->addRect(clippedPathIBounds.width(), clippedPathIBounds.height(),
65 &location));
66 }
67 devToAtlasOffset->set(location.x() - clippedPathIBounds.left(),
68 location.y() - clippedPathIBounds.top());
69 return retiredAtlas;
70 }
71
enqueueRenderedPath(const SkPath & path,GrFillRule fillRule,const SkIRect & clippedDevIBounds,const SkMatrix & pathToAtlasMatrix,GrScissorTest enableScissorInAtlas,SkIVector devToAtlasOffset)72 void GrCCPerFlushResources::enqueueRenderedPath(const SkPath& path, GrFillRule fillRule,
73 const SkIRect& clippedDevIBounds,
74 const SkMatrix& pathToAtlasMatrix,
75 GrScissorTest enableScissorInAtlas,
76 SkIVector devToAtlasOffset) {
77 SkPath* atlasPath;
78 if (enableScissorInAtlas == GrScissorTest::kDisabled) {
79 atlasPath = &fAtlasPaths[(int)fillRule].fUberPath;
80 } else {
81 auto& [scissoredPath, scissor] = fAtlasPaths[(int)fillRule].fScissoredPaths.push_back();
82 scissor = clippedDevIBounds.makeOffset(devToAtlasOffset);
83 atlasPath = &scissoredPath;
84 }
85 auto origin = clippedDevIBounds.topLeft() + devToAtlasOffset;
86 atlasPath->moveTo(origin.fX, origin.fY); // Implicit moveTo(0,0).
87 atlasPath->addPath(path, pathToAtlasMatrix);
88 }
89
draw_stencil_to_coverage(GrOnFlushResourceProvider * onFlushRP,GrSurfaceDrawContext * surfaceDrawContext,SkRect && rect)90 static void draw_stencil_to_coverage(GrOnFlushResourceProvider* onFlushRP,
91 GrSurfaceDrawContext* surfaceDrawContext, SkRect&& rect) {
92 auto aaType = GrAAType::kMSAA;
93 auto fillRectFlags = GrSimpleMeshDrawOpHelper::InputFlags::kNone;
94
95 // This will be the final op in the surfaceDrawContext. So if Ganesh is planning to discard the
96 // stencil values anyway, then we might not actually need to reset the stencil values back to 0.
97 bool mustResetStencil = !onFlushRP->caps()->discardStencilValuesAfterRenderPass();
98 const GrUserStencilSettings* stencil;
99 if (mustResetStencil) {
100 constexpr static GrUserStencilSettings kTestAndResetStencil(
101 GrUserStencilSettings::StaticInit<
102 0x0000,
103 GrUserStencilTest::kNotEqual,
104 0xffff,
105 GrUserStencilOp::kZero,
106 GrUserStencilOp::kKeep,
107 0xffff>());
108
109 // Outset the cover rect in case there are T-junctions in the path bounds.
110 rect.outset(1, 1);
111 stencil = &kTestAndResetStencil;
112 } else {
113 constexpr static GrUserStencilSettings kTestStencil(
114 GrUserStencilSettings::StaticInit<
115 0x0000,
116 GrUserStencilTest::kNotEqual,
117 0xffff,
118 GrUserStencilOp::kKeep,
119 GrUserStencilOp::kKeep,
120 0xffff>());
121
122 stencil = &kTestStencil;
123 }
124
125 GrPaint paint;
126 paint.setColor4f(SK_PMColor4fWHITE);
127 GrQuad coverQuad(rect);
128 DrawQuad drawQuad{coverQuad, coverQuad, GrQuadAAFlags::kAll};
129 auto coverOp = GrFillRectOp::Make(surfaceDrawContext->recordingContext(), std::move(paint),
130 aaType, &drawQuad, stencil, fillRectFlags);
131 surfaceDrawContext->addDrawOp(nullptr, std::move(coverOp));
132 }
133
flushRenderedPaths(GrOnFlushResourceProvider * onFlushRP)134 void GrCCPerFlushResources::flushRenderedPaths(GrOnFlushResourceProvider* onFlushRP) {
135 SkASSERT(fAtlas);
136 auto surfaceDrawContext = fAtlas->instantiate(onFlushRP);
137 if (!surfaceDrawContext) {
138 for (int i = 0; i < (int)SK_ARRAY_COUNT(fAtlasPaths); ++i) {
139 fAtlasPaths[i].fUberPath.reset();
140 fAtlasPaths[i].fScissoredPaths.reset();
141 }
142 return;
143 }
144
145 for (int i = 0; i < (int)SK_ARRAY_COUNT(fAtlasPaths); ++i) {
146 SkPathFillType fillType = (i == (int)GrFillRule::kNonzero) ? SkPathFillType::kWinding
147 : SkPathFillType::kEvenOdd;
148 SkPath& uberPath = fAtlasPaths[i].fUberPath;
149 if (!uberPath.isEmpty()) {
150 uberPath.setIsVolatile(true);
151 uberPath.setFillType(fillType);
152 surfaceDrawContext->stencilPath(nullptr, GrAA::kYes, SkMatrix::I(), uberPath);
153 uberPath.reset();
154 }
155 for (auto& [scissoredPath, scissor] : fAtlasPaths[i].fScissoredPaths) {
156 GrFixedClip fixedClip(
157 surfaceDrawContext->asRenderTargetProxy()->backingStoreDimensions(), scissor);
158 scissoredPath.setIsVolatile(true);
159 scissoredPath.setFillType(fillType);
160 surfaceDrawContext->stencilPath(&fixedClip, GrAA::kYes, SkMatrix::I(), scissoredPath);
161 }
162 fAtlasPaths[i].fScissoredPaths.reset();
163 }
164
165 draw_stencil_to_coverage(onFlushRP, surfaceDrawContext.get(),
166 SkRect::MakeSize(SkSize::Make(fAtlas->drawBounds())));
167
168 if (surfaceDrawContext->asSurfaceProxy()->requiresManualMSAAResolve()) {
169 onFlushRP->addTextureResolveTask(sk_ref_sp(surfaceDrawContext->asTextureProxy()),
170 GrSurfaceProxy::ResolveFlags::kMSAA);
171 }
172 }
173
finalize(GrOnFlushResourceProvider * onFlushRP)174 std::unique_ptr<GrCCAtlas> GrCCPerFlushResources::finalize(GrOnFlushResourceProvider* onFlushRP) {
175 if (fAtlas) {
176 this->flushRenderedPaths(onFlushRP);
177 }
178 #ifdef SK_DEBUG
179 // These paths should have been rendered and reset to empty by this point.
180 for (size_t i = 0; i < SK_ARRAY_COUNT(fAtlasPaths); ++i) {
181 SkASSERT(fAtlasPaths[i].fUberPath.isEmpty());
182 SkASSERT(fAtlasPaths[i].fScissoredPaths.empty());
183 }
184 #endif
185 return std::move(fAtlas);
186 }
187