• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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