• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2021 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/ganesh/ops/AtlasRenderTask.h"
9 
10 #include "src/core/SkBlendModePriv.h"
11 #include "src/core/SkIPoint16.h"
12 #include "src/gpu/ganesh/GrGpu.h"
13 #include "src/gpu/ganesh/GrNativeRect.h"
14 #include "src/gpu/ganesh/GrOpFlushState.h"
15 #include "src/gpu/ganesh/GrOpsTypes.h"
16 #include "src/gpu/ganesh/GrSurfaceProxyPriv.h"
17 #include "src/gpu/ganesh/GrXferProcessor.h"
18 #include "src/gpu/ganesh/geometry/GrQuad.h"
19 #include "src/gpu/ganesh/ops/FillRectOp.h"
20 #include "src/gpu/ganesh/ops/PathStencilCoverOp.h"
21 
22 namespace skgpu::ganesh {
23 
AtlasRenderTask(GrRecordingContext * rContext,sk_sp<GrArenas> arenas,std::unique_ptr<GrDynamicAtlas> dynamicAtlas)24 AtlasRenderTask::AtlasRenderTask(GrRecordingContext* rContext,
25                                  sk_sp<GrArenas> arenas,
26                                  std::unique_ptr<GrDynamicAtlas> dynamicAtlas)
27         : OpsTask(rContext->priv().drawingManager(),
28                   dynamicAtlas->writeView(*rContext->priv().caps()),
29                   rContext->priv().auditTrail(),
30                   std::move(arenas))
31         , fDynamicAtlas(std::move(dynamicAtlas)) {
32 }
33 
addPath(const SkMatrix & viewMatrix,const SkPath & path,SkIPoint pathDevTopLeft,int widthInAtlas,int heightInAtlas,bool transposedInAtlas,SkIPoint16 * locationInAtlas)34 bool AtlasRenderTask::addPath(const SkMatrix& viewMatrix, const SkPath& path,
35                               SkIPoint pathDevTopLeft, int widthInAtlas, int heightInAtlas,
36                               bool transposedInAtlas, SkIPoint16* locationInAtlas) {
37     SkASSERT(!this->isClosed());
38     SkASSERT(this->isEmpty());
39     SkASSERT(!fDynamicAtlas->isInstantiated());  // Paths can't be added after instantiate().
40 
41     if (!fDynamicAtlas->addRect(widthInAtlas, heightInAtlas, locationInAtlas)) {
42         return false;
43     }
44 
45     SkMatrix pathToAtlasMatrix = viewMatrix;
46     if (transposedInAtlas) {
47         std::swap(pathToAtlasMatrix[0], pathToAtlasMatrix[3]);
48         std::swap(pathToAtlasMatrix[1], pathToAtlasMatrix[4]);
49         float tx=pathToAtlasMatrix.getTranslateX(), ty=pathToAtlasMatrix.getTranslateY();
50         pathToAtlasMatrix.setTranslateX(ty - pathDevTopLeft.y() + locationInAtlas->x());
51         pathToAtlasMatrix.setTranslateY(tx - pathDevTopLeft.x() + locationInAtlas->y());
52     } else {
53         pathToAtlasMatrix.postTranslate(locationInAtlas->x() - pathDevTopLeft.x(),
54                                         locationInAtlas->y() - pathDevTopLeft.y());
55     }
56 
57     if (GrFillRuleForSkPath(path) == GrFillRule::kNonzero) {
58         fWindingPathList.add(&fPathDrawAllocator, pathToAtlasMatrix, path);
59     } else {
60         fEvenOddPathList.add(&fPathDrawAllocator, pathToAtlasMatrix, path);
61     }
62     return true;
63 }
64 
onMakeClosed(GrRecordingContext * rContext,SkIRect * targetUpdateBounds)65 GrRenderTask::ExpectedOutcome AtlasRenderTask::onMakeClosed(GrRecordingContext* rContext,
66                                                             SkIRect* targetUpdateBounds) {
67     // We don't add our ops until now, at which point we know the atlas is done being built.
68     SkASSERT(this->isEmpty());
69     SkASSERT(!fDynamicAtlas->isInstantiated());  // Instantiation happens after makeClosed().
70 
71     const GrCaps& caps = *rContext->priv().caps();
72 
73     // Set our dimensions now. OpsTask will need them when we add our ops.
74     this->target(0)->priv().setLazyDimensions(fDynamicAtlas->drawBounds());
75     this->target(0)->asRenderTargetProxy()->setNeedsStencil();
76     SkRect drawRect = target(0)->getBoundsRect();
77 
78     // Clear the atlas.
79     if (caps.performColorClearsAsDraws() || caps.performStencilClearsAsDraws()) {
80         this->setColorLoadOp(GrLoadOp::kDiscard);
81         this->setInitialStencilContent(StencilContent::kDontCare);
82 
83         constexpr static GrUserStencilSettings kClearStencil(
84             GrUserStencilSettings::StaticInit<
85                 0x0000,
86                 GrUserStencilTest::kAlways,
87                 0xffff,
88                 GrUserStencilOp::kReplace,
89                 GrUserStencilOp::kReplace,
90                 0xffff>());
91 
92         this->stencilAtlasRect(rContext, drawRect, SK_PMColor4fTRANSPARENT, &kClearStencil);
93     } else {
94         this->setColorLoadOp(GrLoadOp::kClear);
95         this->setInitialStencilContent(StencilContent::kUserBitsCleared);
96     }
97 
98     // Add ops to stencil the atlas paths.
99     for (const auto* pathList : {&fWindingPathList, &fEvenOddPathList}) {
100         if (pathList->pathCount() > 0) {
101             auto op = GrOp::Make<PathStencilCoverOp>(
102                     rContext,
103                     pathList->pathDrawList(),
104                     pathList->totalCombinedPathVerbCnt(),
105                     pathList->pathCount(),
106                     GrPaint(),
107                     GrAAType::kMSAA,
108                     FillPathFlags::kStencilOnly,
109                     drawRect);
110             this->addAtlasDrawOp(std::move(op), caps);
111         }
112     }
113 
114     // Finally, draw a fullscreen rect to cover our stencilled paths.
115     const GrUserStencilSettings* stencil;
116     if (caps.discardStencilValuesAfterRenderPass()) {
117         constexpr static GrUserStencilSettings kTestStencil(
118             GrUserStencilSettings::StaticInit<
119                 0x0000,
120                 GrUserStencilTest::kNotEqual,
121                 0xffff,
122                 GrUserStencilOp::kKeep,
123                 GrUserStencilOp::kKeep,
124                 0xffff>());
125 
126         // This is the final op in the task. Since Ganesh is planning to discard the stencil values
127         // anyway, there is no need to reset the stencil values back to 0.
128         stencil = &kTestStencil;
129     } else {
130         constexpr static GrUserStencilSettings kTestAndResetStencil(
131             GrUserStencilSettings::StaticInit<
132                 0x0000,
133                 GrUserStencilTest::kNotEqual,
134                 0xffff,
135                 GrUserStencilOp::kZero,
136                 GrUserStencilOp::kKeep,
137                 0xffff>());
138 
139         // Outset the cover rect to make extra sure we clear every stencil value touched by the
140         // atlas.
141         drawRect.outset(1, 1);
142         stencil = &kTestAndResetStencil;
143     }
144     this->stencilAtlasRect(rContext, drawRect, SK_PMColor4fWHITE, stencil);
145 
146     this->OpsTask::onMakeClosed(rContext, targetUpdateBounds);
147 
148     // Don't mark msaa dirty. Since this op defers being closed, the drawing manager's dirty
149     // tracking doesn't work anyway. We will just resolve msaa manually during onExecute.
150     return ExpectedOutcome::kTargetUnchanged;
151 }
152 
stencilAtlasRect(GrRecordingContext * rContext,const SkRect & rect,const SkPMColor4f & color,const GrUserStencilSettings * stencil)153 void AtlasRenderTask::stencilAtlasRect(GrRecordingContext* rContext, const SkRect& rect,
154                                        const SkPMColor4f& color,
155                                        const GrUserStencilSettings* stencil) {
156     GrPaint paint;
157     paint.setColor4f(color);
158     paint.setXPFactory(GrXPFactory::FromBlendMode(SkBlendMode::kSrc));
159     GrQuad quad(rect);
160     DrawQuad drawQuad{quad, quad, GrQuadAAFlags::kAll};
161     auto op = FillRectOp::Make(rContext, std::move(paint), GrAAType::kMSAA, &drawQuad, stencil);
162     this->addAtlasDrawOp(std::move(op), *rContext->priv().caps());
163 }
164 
addAtlasDrawOp(GrOp::Owner op,const GrCaps & caps)165 void AtlasRenderTask::addAtlasDrawOp(GrOp::Owner op, const GrCaps& caps) {
166     SkASSERT(!this->isClosed());
167 
168     auto drawOp = static_cast<GrDrawOp*>(op.get());
169     SkDEBUGCODE(drawOp->fAddDrawOpCalled = true;)
170 
171     auto processorAnalysis = drawOp->finalize(caps, nullptr,
172                                               GrColorTypeClampType(fDynamicAtlas->colorType()));
173     SkASSERT(!processorAnalysis.requiresDstTexture());
174     SkASSERT(!processorAnalysis.usesNonCoherentHWBlending());
175 
176     drawOp->setClippedBounds(drawOp->bounds());
177     this->recordOp(std::move(op), true/*usesMSAA*/, processorAnalysis, nullptr, nullptr, caps);
178 }
179 
onExecute(GrOpFlushState * flushState)180 bool AtlasRenderTask::onExecute(GrOpFlushState* flushState) {
181     if (!this->OpsTask::onExecute(flushState)) {
182         return false;
183     }
184     if (this->target(0)->requiresManualMSAAResolve()) {
185         // Since atlases don't get closed until they are done being built, the drawingManager
186         // doesn't detect that they need an MSAA resolve. Do it here manually.
187         auto nativeRect = GrNativeRect::MakeIRectRelativeTo(
188                 GrDynamicAtlas::kTextureOrigin,
189                 this->target(0)->backingStoreDimensions().height(),
190                 SkIRect::MakeSize(fDynamicAtlas->drawBounds()));
191         flushState->gpu()->resolveRenderTarget(this->target(0)->peekRenderTarget(), nativeRect);
192     }
193     return true;
194 }
195 
196 }  // namespace skgpu::ganesh
197