• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2021 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 "src/gpu/ganesh/SurfaceFillContext.h"
9 
10 #include "src/gpu/ganesh/GrCaps.h"
11 #include "src/gpu/ganesh/effects/GrMatrixEffect.h"
12 #include "src/gpu/ganesh/effects/GrTextureEffect.h"
13 #include "src/gpu/ganesh/geometry/GrRect.h"
14 #include "src/gpu/ganesh/ops/ClearOp.h"
15 #include "src/gpu/ganesh/ops/FillRectOp.h"
16 
17 #define ASSERT_SINGLE_OWNER        SKGPU_ASSERT_SINGLE_OWNER(this->singleOwner())
18 #define RETURN_IF_ABANDONED        if (fContext->abandoned()) { return; }
19 
20 class AutoCheckFlush {
21 public:
AutoCheckFlush(GrDrawingManager * drawingManager)22     AutoCheckFlush(GrDrawingManager* drawingManager) : fDrawingManager(drawingManager) {
23         SkASSERT(fDrawingManager);
24     }
~AutoCheckFlush()25     ~AutoCheckFlush() { fDrawingManager->flushIfNecessary(); }
26 
27 private:
28     GrDrawingManager* fDrawingManager;
29 };
30 
31 namespace skgpu::v1 {
32 
33 // In MDB mode the reffing of the 'getLastOpsTask' call's result allows in-progress
34 // OpsTask to be picked up and added to by SurfaceFillContext lower in the call
35 // stack. When this occurs with a closed OpsTask, a new one will be allocated
36 // when the SurfaceFillContext attempts to use it (via getOpsTask).
SurfaceFillContext(GrRecordingContext * rContext,GrSurfaceProxyView readView,GrSurfaceProxyView writeView,const GrColorInfo & colorInfo)37 SurfaceFillContext::SurfaceFillContext(GrRecordingContext* rContext,
38                                        GrSurfaceProxyView readView,
39                                        GrSurfaceProxyView writeView,
40                                        const GrColorInfo& colorInfo)
41             : SurfaceContext(rContext, std::move(readView), colorInfo)
42             , fWriteView(std::move(writeView)) {
43     SkASSERT(this->asSurfaceProxy() == fWriteView.proxy());
44     SkASSERT(this->origin() == fWriteView.origin());
45 
46     fOpsTask = sk_ref_sp(rContext->priv().drawingManager()->getLastOpsTask(this->asSurfaceProxy()));
47 
48     SkDEBUGCODE(this->validate();)
49 }
50 
getOpsTask()51 OpsTask* SurfaceFillContext::getOpsTask() {
52     ASSERT_SINGLE_OWNER
53     SkDEBUGCODE(this->validate();)
54 
55     if (!fOpsTask || fOpsTask->isClosed()) {
56         this->replaceOpsTask();
57     }
58     SkASSERT(!fOpsTask->isClosed());
59     return fOpsTask.get();
60 }
61 
discard()62 void SurfaceFillContext::discard() {
63     ASSERT_SINGLE_OWNER
64     RETURN_IF_ABANDONED
65     SkDEBUGCODE(this->validate();)
66     GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceFillContext", "discard", fContext);
67 
68     AutoCheckFlush acf(this->drawingManager());
69 
70     this->getOpsTask()->discard();
71 }
72 
resolveMSAA()73 void SurfaceFillContext::resolveMSAA() {
74     ASSERT_SINGLE_OWNER
75     RETURN_IF_ABANDONED
76     SkDEBUGCODE(this->validate();)
77     GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceFillContext", "resolveMSAA", fContext);
78 
79     AutoCheckFlush acf(this->drawingManager());
80 
81     this->drawingManager()->newTextureResolveRenderTask(this->asSurfaceProxyRef(),
82                                                         GrSurfaceProxy::ResolveFlags::kMSAA,
83                                                         *this->caps());
84 }
85 
fillRectWithFP(const SkIRect & dstRect,std::unique_ptr<GrFragmentProcessor> fp)86 void SurfaceFillContext::fillRectWithFP(const SkIRect& dstRect,
87                                         std::unique_ptr<GrFragmentProcessor> fp) {
88     ASSERT_SINGLE_OWNER
89     RETURN_IF_ABANDONED
90     SkDEBUGCODE(this->validate();)
91     GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceFillContext", "fillRectWithFP", fContext);
92 
93     AutoCheckFlush acf(this->drawingManager());
94 
95     GrPaint paint;
96     paint.setColorFragmentProcessor(std::move(fp));
97     paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
98     auto op = FillRectOp::MakeNonAARect(fContext, std::move(paint), SkMatrix::I(),
99                                         SkRect::Make(dstRect));
100     this->addDrawOp(std::move(op));
101 }
102 
fillRectWithFP(const SkIRect & dstRect,const SkMatrix & localMatrix,std::unique_ptr<GrFragmentProcessor> fp)103 void SurfaceFillContext::fillRectWithFP(const SkIRect& dstRect,
104                                         const SkMatrix& localMatrix,
105                                         std::unique_ptr<GrFragmentProcessor> fp) {
106     fp = GrMatrixEffect::Make(localMatrix, std::move(fp));
107     this->fillRectWithFP(dstRect, std::move(fp));
108 }
109 
blitTexture(GrSurfaceProxyView view,const SkIRect & srcRect,const SkIPoint & dstPoint)110 bool SurfaceFillContext::blitTexture(GrSurfaceProxyView view,
111                                      const SkIRect& srcRect,
112                                      const SkIPoint& dstPoint) {
113     SkASSERT(view.asTextureProxy());
114 
115     SkIPoint clippedDstPoint = dstPoint;
116     SkIRect clippedSrcRect = srcRect;
117     if (!GrClipSrcRectAndDstPoint(this->dimensions(),
118                                   &clippedDstPoint,
119                                   view.dimensions(),
120                                   &clippedSrcRect)) {
121         return false;
122     }
123 
124     SkIRect clippedDstRect = SkIRect::MakePtSize(clippedDstPoint, clippedSrcRect.size());
125 
126     auto fp = GrTextureEffect::Make(std::move(view), kUnknown_SkAlphaType);
127     this->fillRectToRectWithFP(SkRect::Make(clippedSrcRect), clippedDstRect, std::move(fp));
128     return true;
129 }
130 
refRenderTask()131 sk_sp<GrRenderTask> SurfaceFillContext::refRenderTask() {
132     return sk_ref_sp(this->getOpsTask());
133 }
134 
replaceOpsTask()135 OpsTask* SurfaceFillContext::replaceOpsTask() {
136     sk_sp<OpsTask> newOpsTask = this->drawingManager()->newOpsTask(this->writeSurfaceView(),
137                                                                    this->arenas());
138     this->willReplaceOpsTask(fOpsTask.get(), newOpsTask.get());
139     fOpsTask = std::move(newOpsTask);
140     return fOpsTask.get();
141 }
142 
ClearToGrPaint(std::array<float,4> color,GrPaint * paint)143 void SurfaceFillContext::ClearToGrPaint(std::array<float, 4> color, GrPaint* paint) {
144     paint->setColor4f({color[0], color[1], color[2], color[3]});
145     if (color[3] == 1.f) {
146         // Can just rely on the src-over blend mode to do the right thing.
147         // This may improve batching.
148         paint->setPorterDuffXPFactory(SkBlendMode::kSrcOver);
149     } else {
150         // A clear overwrites the prior color, so even if it's transparent, it behaves as if it
151         // were src blended
152         paint->setPorterDuffXPFactory(SkBlendMode::kSrc);
153     }
154 }
155 
addOp(GrOp::Owner op)156 void SurfaceFillContext::addOp(GrOp::Owner op) {
157     GrDrawingManager* drawingMgr = this->drawingManager();
158     this->getOpsTask()->addOp(drawingMgr,
159                               std::move(op),
160                               GrTextureResolveManager(drawingMgr),
161                               *this->caps());
162 }
163 
164 
addDrawOp(GrOp::Owner owner)165 void SurfaceFillContext::addDrawOp(GrOp::Owner owner) {
166     GrDrawOp* op = static_cast<GrDrawOp*>(owner.get());
167     GrClampType clampType = GrColorTypeClampType(this->colorInfo().colorType());
168     auto clip = GrAppliedClip::Disabled();
169     const GrCaps& caps = *this->caps();
170     GrProcessorSet::Analysis analysis = op->finalize(caps, &clip, clampType);
171     SkASSERT(!op->usesStencil());
172     SkASSERT(!analysis.requiresDstTexture());
173     SkRect bounds = owner->bounds();
174     // We shouldn't have coverage AA or hairline draws in fill contexts.
175     SkASSERT(!op->hasAABloat() && !op->hasZeroArea());
176     if (!bounds.intersect(this->asSurfaceProxy()->getBoundsRect())) {
177         return;
178     }
179     op->setClippedBounds(op->bounds());
180     SkDEBUGCODE(op->fAddDrawOpCalled = true;)
181 
182     GrDstProxyView dstProxyView;
183     this->getOpsTask()->addDrawOp(fContext->priv().drawingManager(),
184                                   std::move(owner),
185                                   op->usesMSAA(),
186                                   analysis,
187                                   std::move(clip),
188                                   dstProxyView,
189                                   GrTextureResolveManager(this->drawingManager()),
190                                   caps);
191 }
192 
internalClear(const SkIRect * scissor,std::array<float,4> color,bool upgradePartialToFull)193 void SurfaceFillContext::internalClear(const SkIRect* scissor,
194                                        std::array<float, 4> color,
195                                        bool upgradePartialToFull) {
196     ASSERT_SINGLE_OWNER
197     RETURN_IF_ABANDONED
198     SkDEBUGCODE(this->validate();)
199     GR_CREATE_TRACE_MARKER_CONTEXT("SurfaceFillContext", "clear", fContext);
200 
201     // There are three ways clears are handled: load ops, native clears, and draws. Load ops are
202     // only for fullscreen clears; native clears can be fullscreen or with scissors if the backend
203     // supports then. Drawing an axis-aligned rect is the fallback path.
204     GrScissorState scissorState(this->asSurfaceProxy()->backingStoreDimensions());
205     if (scissor && !scissorState.set(*scissor)) {
206         // The clear is offscreen, so skip it (normally this would be handled by addDrawOp,
207         // except clear ops are not draw ops).
208         return;
209     }
210 
211     // If we have a scissor but it's okay to clear beyond it for performance reasons, then disable
212     // the test. We only do this when the clear would be handled by a load op or natively.
213     if (scissorState.enabled() && !this->caps()->performColorClearsAsDraws()) {
214         if (upgradePartialToFull && (this->caps()->preferFullscreenClears() ||
215                                      this->caps()->shouldInitializeTextures())) {
216             // TODO: wrt the shouldInitializeTextures path, it would be more performant to
217             // only clear the entire target if we knew it had not been cleared before. As
218             // is this could end up doing a lot of redundant clears.
219             scissorState.setDisabled();
220         } else {
221             // Unlike with stencil clears, we also allow clears up to the logical dimensions of the
222             // render target to overflow into any approx-fit padding of the backing store dimensions
223             scissorState.relaxTest(this->dimensions());
224         }
225     }
226 
227     if (!scissorState.enabled()) {
228         // This is a fullscreen clear, so could be handled as a load op. Regardless, we can also
229         // discard all prior ops in the current task since the color buffer will be overwritten.
230         auto opsTask = this->getOpsTask();
231         if (opsTask->resetForFullscreenClear(this->canDiscardPreviousOpsOnFullClear()) &&
232             !this->caps()->performColorClearsAsDraws()) {
233             color = this->writeSurfaceView().swizzle().applyTo(color);
234             // The op list was emptied and native clears are allowed, so just use the load op
235             opsTask->setColorLoadOp(GrLoadOp::kClear, color);
236             return;
237         } else {
238             // Will use an op for the clear, reset the load op to discard since the op will
239             // blow away the color buffer contents
240             opsTask->setColorLoadOp(GrLoadOp::kDiscard);
241         }
242     }
243 
244     // At this point we are either a partial clear or a fullscreen clear that couldn't be applied
245     // as a load op.
246     bool clearAsDraw = this->caps()->performColorClearsAsDraws() ||
247                        (scissorState.enabled() && this->caps()->performPartialClearsAsDraws());
248     if (clearAsDraw) {
249         GrPaint paint;
250         ClearToGrPaint(color, &paint);
251         auto op = FillRectOp::MakeNonAARect(fContext, std::move(paint), SkMatrix::I(),
252                                             SkRect::Make(scissorState.rect()));
253         this->addDrawOp(std::move(op));
254     } else {
255         color = this->writeSurfaceView().swizzle().applyTo(color);
256         this->addOp(ClearOp::MakeColor(fContext, scissorState, color));
257     }
258 }
259 
260 #ifdef SK_DEBUG
onValidate() const261 void SurfaceFillContext::onValidate() const {
262     if (fOpsTask && !fOpsTask->isClosed()) {
263         SkASSERT(this->drawingManager()->getLastRenderTask(fWriteView.proxy()) == fOpsTask.get());
264     }
265 }
266 #endif
267 
268 } // namespace skgpu::v1
269