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/gpu/vk/GrVulkanTrackerInterface.h"
11 #include "include/private/GrImageContext.h"
12 #include "src/gpu/GrDstProxyView.h"
13 #include "src/gpu/GrImageContextPriv.h"
14 #include "src/gpu/GrProxyProvider.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 GR_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 #ifdef SKIA_OHOS
82 HITRACE_OHOS_NAME_FMT_LEVEL(DebugTraceLevel::DETAIL, "SurfaceFillContext::addDrawOp - %s",
83 op->name());
84 #endif
85 SkRect bounds = owner->bounds();
86 // We shouldn't have coverage AA or hairline draws in fill contexts.
87 SkASSERT(!op->hasAABloat() && !op->hasZeroArea());
88 if (!bounds.intersect(this->asSurfaceProxy()->getBoundsRect())) {
89 return;
90 }
91 op->setClippedBounds(op->bounds());
92 SkDEBUGCODE(op->fAddDrawOpCalled = true;)
93
94 GrDstProxyView dstProxyView;
95 this->getOpsTask()->addDrawOp(fContext->priv().drawingManager(),
96 std::move(owner),
97 op->usesMSAA(),
98 analysis,
99 std::move(clip),
100 dstProxyView,
101 GrTextureResolveManager(this->drawingManager()),
102 caps);
103 }
104
ClearToGrPaint(std::array<float,4> color,GrPaint * paint)105 void SurfaceFillContext::ClearToGrPaint(std::array<float, 4> color, GrPaint* paint) {
106 paint->setColor4f({color[0], color[1], color[2], color[3]});
107 if (color[3] == 1.f) {
108 // Can just rely on the src-over blend mode to do the right thing.
109 // This may improve batching.
110 paint->setPorterDuffXPFactory(SkBlendMode::kSrcOver);
111 } else {
112 // A clear overwrites the prior color, so even if it's transparent, it behaves as if it
113 // were src blended
114 paint->setPorterDuffXPFactory(SkBlendMode::kSrc);
115 }
116 }
117
addOp(GrOp::Owner op)118 void SurfaceFillContext::addOp(GrOp::Owner op) {
119 auto direct = fContext->priv().asDirectContext();
120 if (direct && op) {
121 auto grTag = direct->getCurrentGrResourceTag();
122 #ifdef SKIA_DFX_FOR_RECORD_VKIMAGE
123 grTag.fCid = ParallelDebug::GetNodeId();
124 if (grTag.fWid == 0 && grTag.fCid != 0) {
125 int pidBits = 32;
126 grTag.fPid = static_cast<uint32_t>(grTag.fCid >> pidBits);
127 }
128 #endif
129 op->setGrOpTag(grTag);
130 }
131 GrDrawingManager* drawingMgr = this->drawingManager();
132 this->getOpsTask()->addOp(drawingMgr,
133 std::move(op),
134 GrTextureResolveManager(drawingMgr),
135 *this->caps());
136 }
137
getOpsTask()138 OpsTask* SurfaceFillContext::getOpsTask() {
139 ASSERT_SINGLE_OWNER
140 SkDEBUGCODE(this->validate();)
141
142 if (!fOpsTask || fOpsTask->isClosed()) {
143 this->replaceOpsTask();
144 }
145 SkASSERT(!fOpsTask->isClosed());
146 return fOpsTask.get();
147 }
148
refRenderTask()149 sk_sp<GrRenderTask> SurfaceFillContext::refRenderTask() {
150 return sk_ref_sp(this->getOpsTask());
151 }
152
replaceOpsTask()153 OpsTask* SurfaceFillContext::replaceOpsTask() {
154 sk_sp<OpsTask> newOpsTask = this->drawingManager()->newOpsTask(
155 this->writeSurfaceView(), this->arenas(), fFlushTimeOpsTask);
156 this->willReplaceOpsTask(fOpsTask.get(), newOpsTask.get());
157 fOpsTask = std::move(newOpsTask);
158 return fOpsTask.get();
159 }
160
161 #ifdef SK_DEBUG
onValidate() const162 void SurfaceFillContext::onValidate() const {
163 if (fOpsTask && !fOpsTask->isClosed()) {
164 SkASSERT(this->drawingManager()->getLastRenderTask(fWriteView.proxy()) == fOpsTask.get());
165 }
166 }
167 #endif
168
discard()169 void SurfaceFillContext::discard() {
170 ASSERT_SINGLE_OWNER
171 RETURN_IF_ABANDONED
172 SkDEBUGCODE(this->validate();)
173 GR_CREATE_TRACE_MARKER_CONTEXT("v1::SurfaceFillContext", "discard", fContext);
174
175 AutoCheckFlush acf(this->drawingManager());
176
177 this->getOpsTask()->discard();
178 }
179
internalClear(const SkIRect * scissor,std::array<float,4> color,bool upgradePartialToFull)180 void SurfaceFillContext::internalClear(const SkIRect* scissor,
181 std::array<float, 4> color,
182 bool upgradePartialToFull) {
183 ASSERT_SINGLE_OWNER
184 RETURN_IF_ABANDONED
185 SkDEBUGCODE(this->validate();)
186 GR_CREATE_TRACE_MARKER_CONTEXT("v1::SurfaceFillContext", "clear", fContext);
187
188 // There are three ways clears are handled: load ops, native clears, and draws. Load ops are
189 // only for fullscreen clears; native clears can be fullscreen or with scissors if the backend
190 // supports then. Drawing an axis-aligned rect is the fallback path.
191 GrScissorState scissorState(this->asSurfaceProxy()->backingStoreDimensions());
192 if (scissor && !scissorState.set(*scissor)) {
193 // The clear is offscreen, so skip it (normally this would be handled by addDrawOp,
194 // except clear ops are not draw ops).
195 return;
196 }
197
198 // If we have a scissor but it's okay to clear beyond it for performance reasons, then disable
199 // the test. We only do this when the clear would be handled by a load op or natively.
200 if (scissorState.enabled() && !this->caps()->performColorClearsAsDraws()) {
201 if (upgradePartialToFull && (this->caps()->preferFullscreenClears() ||
202 this->caps()->shouldInitializeTextures())) {
203 // TODO: wrt the shouldInitializeTextures path, it would be more performant to
204 // only clear the entire target if we knew it had not been cleared before. As
205 // is this could end up doing a lot of redundant clears.
206 scissorState.setDisabled();
207 } else {
208 // Unlike with stencil clears, we also allow clears up to the logical dimensions of the
209 // render target to overflow into any approx-fit padding of the backing store dimensions
210 scissorState.relaxTest(this->dimensions());
211 }
212 }
213
214 if (!scissorState.enabled()) {
215 // This is a fullscreen clear, so could be handled as a load op. Regardless, we can also
216 // discard all prior ops in the current task since the color buffer will be overwritten.
217 auto opsTask = this->getOpsTask();
218 if (opsTask->resetForFullscreenClear(this->canDiscardPreviousOpsOnFullClear()) &&
219 !this->caps()->performColorClearsAsDraws()) {
220 color = this->writeSurfaceView().swizzle().applyTo(color);
221 // The op list was emptied and native clears are allowed, so just use the load op
222 opsTask->setColorLoadOp(GrLoadOp::kClear, color);
223 return;
224 } else {
225 // Will use an op for the clear, reset the load op to discard since the op will
226 // blow away the color buffer contents
227 opsTask->setColorLoadOp(GrLoadOp::kDiscard);
228 }
229 }
230
231 // At this point we are either a partial clear or a fullscreen clear that couldn't be applied
232 // as a load op.
233 bool clearAsDraw = this->caps()->performColorClearsAsDraws() ||
234 (scissorState.enabled() && this->caps()->performPartialClearsAsDraws());
235 if (clearAsDraw) {
236 GrPaint paint;
237 ClearToGrPaint(color, &paint);
238 auto op = FillRectOp::MakeNonAARect(fContext, std::move(paint), SkMatrix::I(),
239 SkRect::Make(scissorState.rect()));
240 this->addDrawOp(std::move(op));
241 } else {
242 color = this->writeSurfaceView().swizzle().applyTo(color);
243 this->addOp(ClearOp::MakeColor(fContext, scissorState, color));
244 }
245 }
246
blitTexture(GrSurfaceProxyView view,const SkIRect & srcRect,const SkIPoint & dstPoint)247 bool SurfaceFillContext::blitTexture(GrSurfaceProxyView view,
248 const SkIRect& srcRect,
249 const SkIPoint& dstPoint) {
250 SkASSERT(view.asTextureProxy());
251 SkIRect clippedSrcRect;
252 SkIPoint clippedDstPoint;
253 if (!GrClipSrcRectAndDstPoint(this->dimensions(),
254 view.dimensions(),
255 srcRect,
256 dstPoint,
257 &clippedSrcRect,
258 &clippedDstPoint)) {
259 return false;
260 }
261
262 auto fp = GrTextureEffect::Make(std::move(view), kUnknown_SkAlphaType);
263 auto dstRect = SkIRect::MakePtSize(clippedDstPoint, clippedSrcRect.size());
264 auto srcRectF = SkRect::Make(clippedSrcRect);
265 this->fillRectToRectWithFP(srcRectF, dstRect, std::move(fp));
266 return true;
267 }
268
269 } // namespace skgpu::v1
270