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