1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2019 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker *
4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker */
7*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/ops/OpsTask.h"
8*c8dee2aaSAndroid Build Coastguard Worker
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSize.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/GpuTypes.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrRecordingContext.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkPoint_impl.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkArenaAlloc.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkScopeExit.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkRectPriv.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkStringUtils.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkTraceEvent.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrAppliedClip.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrAttachment.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrAuditTrail.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrCaps.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrGpu.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrNativeRect.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrOpFlushState.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrOpsRenderPass.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrRecordingContextPriv.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrRenderTarget.h"
29*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrRenderTargetProxy.h"
30*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrResourceAllocator.h"
31*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrResourceProvider.h"
32*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrSurfaceProxyView.h"
33*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrTextureProxy.h"
34*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrTextureResolveManager.h"
35*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/geometry/GrRect.h"
36*c8dee2aaSAndroid Build Coastguard Worker
37*c8dee2aaSAndroid Build Coastguard Worker #include <algorithm>
38*c8dee2aaSAndroid Build Coastguard Worker #include <cstddef>
39*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
40*c8dee2aaSAndroid Build Coastguard Worker #include <functional>
41*c8dee2aaSAndroid Build Coastguard Worker #include <memory>
42*c8dee2aaSAndroid Build Coastguard Worker #include <utility>
43*c8dee2aaSAndroid Build Coastguard Worker
44*c8dee2aaSAndroid Build Coastguard Worker class GrDrawingManager;
45*c8dee2aaSAndroid Build Coastguard Worker enum GrSurfaceOrigin : int;
46*c8dee2aaSAndroid Build Coastguard Worker
47*c8dee2aaSAndroid Build Coastguard Worker using namespace skia_private;
48*c8dee2aaSAndroid Build Coastguard Worker
49*c8dee2aaSAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////////
50*c8dee2aaSAndroid Build Coastguard Worker
51*c8dee2aaSAndroid Build Coastguard Worker namespace {
52*c8dee2aaSAndroid Build Coastguard Worker
53*c8dee2aaSAndroid Build Coastguard Worker // Experimentally we have found that most combining occurs within the first 10 comparisons.
54*c8dee2aaSAndroid Build Coastguard Worker static const int kMaxOpMergeDistance = 10;
55*c8dee2aaSAndroid Build Coastguard Worker static const int kMaxOpChainDistance = 10;
56*c8dee2aaSAndroid Build Coastguard Worker
57*c8dee2aaSAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////////
58*c8dee2aaSAndroid Build Coastguard Worker
can_reorder(const SkRect & a,const SkRect & b)59*c8dee2aaSAndroid Build Coastguard Worker inline bool can_reorder(const SkRect& a, const SkRect& b) { return !GrRectsOverlap(a, b); }
60*c8dee2aaSAndroid Build Coastguard Worker
create_render_pass(GrGpu * gpu,GrRenderTarget * rt,bool useMSAASurface,GrAttachment * stencil,GrSurfaceOrigin origin,const SkIRect & bounds,GrLoadOp colorLoadOp,const std::array<float,4> & loadClearColor,GrLoadOp stencilLoadOp,GrStoreOp stencilStoreOp,const TArray<GrSurfaceProxy *,true> & sampledProxies,GrXferBarrierFlags renderPassXferBarriers)61*c8dee2aaSAndroid Build Coastguard Worker GrOpsRenderPass* create_render_pass(GrGpu* gpu,
62*c8dee2aaSAndroid Build Coastguard Worker GrRenderTarget* rt,
63*c8dee2aaSAndroid Build Coastguard Worker bool useMSAASurface,
64*c8dee2aaSAndroid Build Coastguard Worker GrAttachment* stencil,
65*c8dee2aaSAndroid Build Coastguard Worker GrSurfaceOrigin origin,
66*c8dee2aaSAndroid Build Coastguard Worker const SkIRect& bounds,
67*c8dee2aaSAndroid Build Coastguard Worker GrLoadOp colorLoadOp,
68*c8dee2aaSAndroid Build Coastguard Worker const std::array<float, 4>& loadClearColor,
69*c8dee2aaSAndroid Build Coastguard Worker GrLoadOp stencilLoadOp,
70*c8dee2aaSAndroid Build Coastguard Worker GrStoreOp stencilStoreOp,
71*c8dee2aaSAndroid Build Coastguard Worker const TArray<GrSurfaceProxy*, true>& sampledProxies,
72*c8dee2aaSAndroid Build Coastguard Worker GrXferBarrierFlags renderPassXferBarriers) {
73*c8dee2aaSAndroid Build Coastguard Worker const GrOpsRenderPass::LoadAndStoreInfo kColorLoadStoreInfo {
74*c8dee2aaSAndroid Build Coastguard Worker colorLoadOp,
75*c8dee2aaSAndroid Build Coastguard Worker GrStoreOp::kStore,
76*c8dee2aaSAndroid Build Coastguard Worker loadClearColor
77*c8dee2aaSAndroid Build Coastguard Worker };
78*c8dee2aaSAndroid Build Coastguard Worker
79*c8dee2aaSAndroid Build Coastguard Worker // TODO:
80*c8dee2aaSAndroid Build Coastguard Worker // We would like to (at this level) only ever clear & discard. We would need
81*c8dee2aaSAndroid Build Coastguard Worker // to stop splitting up higher level OpsTasks for copyOps to achieve that.
82*c8dee2aaSAndroid Build Coastguard Worker // Note: we would still need SB loads and stores but they would happen at a
83*c8dee2aaSAndroid Build Coastguard Worker // lower level (inside the VK command buffer).
84*c8dee2aaSAndroid Build Coastguard Worker const GrOpsRenderPass::StencilLoadAndStoreInfo stencilLoadAndStoreInfo {
85*c8dee2aaSAndroid Build Coastguard Worker stencilLoadOp,
86*c8dee2aaSAndroid Build Coastguard Worker stencilStoreOp,
87*c8dee2aaSAndroid Build Coastguard Worker };
88*c8dee2aaSAndroid Build Coastguard Worker
89*c8dee2aaSAndroid Build Coastguard Worker return gpu->getOpsRenderPass(rt, useMSAASurface, stencil, origin, bounds, kColorLoadStoreInfo,
90*c8dee2aaSAndroid Build Coastguard Worker stencilLoadAndStoreInfo, sampledProxies, renderPassXferBarriers);
91*c8dee2aaSAndroid Build Coastguard Worker }
92*c8dee2aaSAndroid Build Coastguard Worker
93*c8dee2aaSAndroid Build Coastguard Worker } // anonymous namespace
94*c8dee2aaSAndroid Build Coastguard Worker
95*c8dee2aaSAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////////
96*c8dee2aaSAndroid Build Coastguard Worker
97*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu::ganesh {
98*c8dee2aaSAndroid Build Coastguard Worker
List(GrOp::Owner op)99*c8dee2aaSAndroid Build Coastguard Worker inline OpsTask::OpChain::List::List(GrOp::Owner op)
100*c8dee2aaSAndroid Build Coastguard Worker : fHead(std::move(op)), fTail(fHead.get()) {
101*c8dee2aaSAndroid Build Coastguard Worker this->validate();
102*c8dee2aaSAndroid Build Coastguard Worker }
103*c8dee2aaSAndroid Build Coastguard Worker
List(List && that)104*c8dee2aaSAndroid Build Coastguard Worker inline OpsTask::OpChain::List::List(List&& that) { *this = std::move(that); }
105*c8dee2aaSAndroid Build Coastguard Worker
operator =(List && that)106*c8dee2aaSAndroid Build Coastguard Worker inline OpsTask::OpChain::List& OpsTask::OpChain::List::operator=(List&& that) {
107*c8dee2aaSAndroid Build Coastguard Worker fHead = std::move(that.fHead);
108*c8dee2aaSAndroid Build Coastguard Worker fTail = that.fTail;
109*c8dee2aaSAndroid Build Coastguard Worker that.fTail = nullptr;
110*c8dee2aaSAndroid Build Coastguard Worker this->validate();
111*c8dee2aaSAndroid Build Coastguard Worker return *this;
112*c8dee2aaSAndroid Build Coastguard Worker }
113*c8dee2aaSAndroid Build Coastguard Worker
popHead()114*c8dee2aaSAndroid Build Coastguard Worker inline GrOp::Owner OpsTask::OpChain::List::popHead() {
115*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fHead);
116*c8dee2aaSAndroid Build Coastguard Worker auto temp = fHead->cutChain();
117*c8dee2aaSAndroid Build Coastguard Worker std::swap(temp, fHead);
118*c8dee2aaSAndroid Build Coastguard Worker if (!fHead) {
119*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fTail == temp.get());
120*c8dee2aaSAndroid Build Coastguard Worker fTail = nullptr;
121*c8dee2aaSAndroid Build Coastguard Worker }
122*c8dee2aaSAndroid Build Coastguard Worker return temp;
123*c8dee2aaSAndroid Build Coastguard Worker }
124*c8dee2aaSAndroid Build Coastguard Worker
removeOp(GrOp * op)125*c8dee2aaSAndroid Build Coastguard Worker inline GrOp::Owner OpsTask::OpChain::List::removeOp(GrOp* op) {
126*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG
127*c8dee2aaSAndroid Build Coastguard Worker auto head = op;
128*c8dee2aaSAndroid Build Coastguard Worker while (head->prevInChain()) { head = head->prevInChain(); }
129*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(head == fHead.get());
130*c8dee2aaSAndroid Build Coastguard Worker #endif
131*c8dee2aaSAndroid Build Coastguard Worker auto prev = op->prevInChain();
132*c8dee2aaSAndroid Build Coastguard Worker if (!prev) {
133*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(op == fHead.get());
134*c8dee2aaSAndroid Build Coastguard Worker return this->popHead();
135*c8dee2aaSAndroid Build Coastguard Worker }
136*c8dee2aaSAndroid Build Coastguard Worker auto temp = prev->cutChain();
137*c8dee2aaSAndroid Build Coastguard Worker if (auto next = temp->cutChain()) {
138*c8dee2aaSAndroid Build Coastguard Worker prev->chainConcat(std::move(next));
139*c8dee2aaSAndroid Build Coastguard Worker } else {
140*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fTail == op);
141*c8dee2aaSAndroid Build Coastguard Worker fTail = prev;
142*c8dee2aaSAndroid Build Coastguard Worker }
143*c8dee2aaSAndroid Build Coastguard Worker this->validate();
144*c8dee2aaSAndroid Build Coastguard Worker return temp;
145*c8dee2aaSAndroid Build Coastguard Worker }
146*c8dee2aaSAndroid Build Coastguard Worker
pushHead(GrOp::Owner op)147*c8dee2aaSAndroid Build Coastguard Worker inline void OpsTask::OpChain::List::pushHead(GrOp::Owner op) {
148*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(op);
149*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(op->isChainHead());
150*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(op->isChainTail());
151*c8dee2aaSAndroid Build Coastguard Worker if (fHead) {
152*c8dee2aaSAndroid Build Coastguard Worker op->chainConcat(std::move(fHead));
153*c8dee2aaSAndroid Build Coastguard Worker fHead = std::move(op);
154*c8dee2aaSAndroid Build Coastguard Worker } else {
155*c8dee2aaSAndroid Build Coastguard Worker fHead = std::move(op);
156*c8dee2aaSAndroid Build Coastguard Worker fTail = fHead.get();
157*c8dee2aaSAndroid Build Coastguard Worker }
158*c8dee2aaSAndroid Build Coastguard Worker }
159*c8dee2aaSAndroid Build Coastguard Worker
pushTail(GrOp::Owner op)160*c8dee2aaSAndroid Build Coastguard Worker inline void OpsTask::OpChain::List::pushTail(GrOp::Owner op) {
161*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(op->isChainTail());
162*c8dee2aaSAndroid Build Coastguard Worker fTail->chainConcat(std::move(op));
163*c8dee2aaSAndroid Build Coastguard Worker fTail = fTail->nextInChain();
164*c8dee2aaSAndroid Build Coastguard Worker }
165*c8dee2aaSAndroid Build Coastguard Worker
validate() const166*c8dee2aaSAndroid Build Coastguard Worker inline void OpsTask::OpChain::List::validate() const {
167*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG
168*c8dee2aaSAndroid Build Coastguard Worker if (fHead) {
169*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fTail);
170*c8dee2aaSAndroid Build Coastguard Worker fHead->validateChain(fTail);
171*c8dee2aaSAndroid Build Coastguard Worker }
172*c8dee2aaSAndroid Build Coastguard Worker #endif
173*c8dee2aaSAndroid Build Coastguard Worker }
174*c8dee2aaSAndroid Build Coastguard Worker
175*c8dee2aaSAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////////
176*c8dee2aaSAndroid Build Coastguard Worker
OpChain(GrOp::Owner op,GrProcessorSet::Analysis processorAnalysis,GrAppliedClip * appliedClip,const GrDstProxyView * dstProxyView)177*c8dee2aaSAndroid Build Coastguard Worker OpsTask::OpChain::OpChain(GrOp::Owner op, GrProcessorSet::Analysis processorAnalysis,
178*c8dee2aaSAndroid Build Coastguard Worker GrAppliedClip* appliedClip, const GrDstProxyView* dstProxyView)
179*c8dee2aaSAndroid Build Coastguard Worker : fList{std::move(op)}
180*c8dee2aaSAndroid Build Coastguard Worker , fProcessorAnalysis(processorAnalysis)
181*c8dee2aaSAndroid Build Coastguard Worker , fAppliedClip(appliedClip) {
182*c8dee2aaSAndroid Build Coastguard Worker if (fProcessorAnalysis.requiresDstTexture()) {
183*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(dstProxyView && dstProxyView->proxy());
184*c8dee2aaSAndroid Build Coastguard Worker fDstProxyView = *dstProxyView;
185*c8dee2aaSAndroid Build Coastguard Worker }
186*c8dee2aaSAndroid Build Coastguard Worker fBounds = fList.head()->bounds();
187*c8dee2aaSAndroid Build Coastguard Worker }
188*c8dee2aaSAndroid Build Coastguard Worker
visitProxies(const GrVisitProxyFunc & func) const189*c8dee2aaSAndroid Build Coastguard Worker void OpsTask::OpChain::visitProxies(const GrVisitProxyFunc& func) const {
190*c8dee2aaSAndroid Build Coastguard Worker if (fList.empty()) {
191*c8dee2aaSAndroid Build Coastguard Worker return;
192*c8dee2aaSAndroid Build Coastguard Worker }
193*c8dee2aaSAndroid Build Coastguard Worker for (const auto& op : GrOp::ChainRange<>(fList.head())) {
194*c8dee2aaSAndroid Build Coastguard Worker op.visitProxies(func);
195*c8dee2aaSAndroid Build Coastguard Worker }
196*c8dee2aaSAndroid Build Coastguard Worker if (fDstProxyView.proxy()) {
197*c8dee2aaSAndroid Build Coastguard Worker func(fDstProxyView.proxy(), skgpu::Mipmapped::kNo);
198*c8dee2aaSAndroid Build Coastguard Worker }
199*c8dee2aaSAndroid Build Coastguard Worker if (fAppliedClip) {
200*c8dee2aaSAndroid Build Coastguard Worker fAppliedClip->visitProxies(func);
201*c8dee2aaSAndroid Build Coastguard Worker }
202*c8dee2aaSAndroid Build Coastguard Worker }
203*c8dee2aaSAndroid Build Coastguard Worker
deleteOps()204*c8dee2aaSAndroid Build Coastguard Worker void OpsTask::OpChain::deleteOps() {
205*c8dee2aaSAndroid Build Coastguard Worker while (!fList.empty()) {
206*c8dee2aaSAndroid Build Coastguard Worker // Since the value goes out of scope immediately, the GrOp::Owner deletes the op.
207*c8dee2aaSAndroid Build Coastguard Worker fList.popHead();
208*c8dee2aaSAndroid Build Coastguard Worker }
209*c8dee2aaSAndroid Build Coastguard Worker }
210*c8dee2aaSAndroid Build Coastguard Worker
211*c8dee2aaSAndroid Build Coastguard Worker // Concatenates two op chains and attempts to merge ops across the chains. Assumes that we know that
212*c8dee2aaSAndroid Build Coastguard Worker // the two chains are chainable. Returns the new chain.
DoConcat(List chainA,List chainB,const GrCaps & caps,SkArenaAlloc * opsTaskArena,GrAuditTrail * auditTrail)213*c8dee2aaSAndroid Build Coastguard Worker OpsTask::OpChain::List OpsTask::OpChain::DoConcat(List chainA, List chainB, const GrCaps& caps,
214*c8dee2aaSAndroid Build Coastguard Worker SkArenaAlloc* opsTaskArena,
215*c8dee2aaSAndroid Build Coastguard Worker GrAuditTrail* auditTrail) {
216*c8dee2aaSAndroid Build Coastguard Worker // We process ops in chain b from head to tail. We attempt to merge with nodes in a, starting
217*c8dee2aaSAndroid Build Coastguard Worker // at chain a's tail and working toward the head. We produce one of the following outcomes:
218*c8dee2aaSAndroid Build Coastguard Worker // 1) b's head is merged into an op in a.
219*c8dee2aaSAndroid Build Coastguard Worker // 2) An op from chain a is merged into b's head. (In this case b's head gets processed again.)
220*c8dee2aaSAndroid Build Coastguard Worker // 3) b's head is popped from chain a and added at the tail of a.
221*c8dee2aaSAndroid Build Coastguard Worker // After result 3 we don't want to attempt to merge the next head of b with the new tail of a,
222*c8dee2aaSAndroid Build Coastguard Worker // as we assume merges were already attempted when chain b was created. So we keep track of the
223*c8dee2aaSAndroid Build Coastguard Worker // original tail of a and start our iteration of a there. We also track the bounds of the nodes
224*c8dee2aaSAndroid Build Coastguard Worker // appended to chain a that will be skipped for bounds testing. If the original tail of a is
225*c8dee2aaSAndroid Build Coastguard Worker // merged into an op in b (case 2) then we advance the "original tail" towards the head of a.
226*c8dee2aaSAndroid Build Coastguard Worker GrOp* origATail = chainA.tail();
227*c8dee2aaSAndroid Build Coastguard Worker SkRect skipBounds = SkRectPriv::MakeLargestInverted();
228*c8dee2aaSAndroid Build Coastguard Worker do {
229*c8dee2aaSAndroid Build Coastguard Worker int numMergeChecks = 0;
230*c8dee2aaSAndroid Build Coastguard Worker bool merged = false;
231*c8dee2aaSAndroid Build Coastguard Worker bool noSkip = (origATail == chainA.tail());
232*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(noSkip == (skipBounds == SkRectPriv::MakeLargestInverted()));
233*c8dee2aaSAndroid Build Coastguard Worker bool canBackwardMerge = noSkip || can_reorder(chainB.head()->bounds(), skipBounds);
234*c8dee2aaSAndroid Build Coastguard Worker SkRect forwardMergeBounds = skipBounds;
235*c8dee2aaSAndroid Build Coastguard Worker GrOp* a = origATail;
236*c8dee2aaSAndroid Build Coastguard Worker while (a) {
237*c8dee2aaSAndroid Build Coastguard Worker bool canForwardMerge =
238*c8dee2aaSAndroid Build Coastguard Worker (a == chainA.tail()) || can_reorder(a->bounds(), forwardMergeBounds);
239*c8dee2aaSAndroid Build Coastguard Worker if (canForwardMerge || canBackwardMerge) {
240*c8dee2aaSAndroid Build Coastguard Worker auto result = a->combineIfPossible(chainB.head(), opsTaskArena, caps);
241*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(result != GrOp::CombineResult::kCannotCombine);
242*c8dee2aaSAndroid Build Coastguard Worker merged = (result == GrOp::CombineResult::kMerged);
243*c8dee2aaSAndroid Build Coastguard Worker GrOP_INFO("\t\t: (%s opID: %u) -> Combining with (%s, opID: %u)\n",
244*c8dee2aaSAndroid Build Coastguard Worker chainB.head()->name(), chainB.head()->uniqueID(), a->name(),
245*c8dee2aaSAndroid Build Coastguard Worker a->uniqueID());
246*c8dee2aaSAndroid Build Coastguard Worker }
247*c8dee2aaSAndroid Build Coastguard Worker if (merged) {
248*c8dee2aaSAndroid Build Coastguard Worker GR_AUDIT_TRAIL_OPS_RESULT_COMBINED(auditTrail, a, chainB.head());
249*c8dee2aaSAndroid Build Coastguard Worker if (canBackwardMerge) {
250*c8dee2aaSAndroid Build Coastguard Worker // The GrOp::Owner releases the op.
251*c8dee2aaSAndroid Build Coastguard Worker chainB.popHead();
252*c8dee2aaSAndroid Build Coastguard Worker } else {
253*c8dee2aaSAndroid Build Coastguard Worker // We merged the contents of b's head into a. We will replace b's head with a in
254*c8dee2aaSAndroid Build Coastguard Worker // chain b.
255*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(canForwardMerge);
256*c8dee2aaSAndroid Build Coastguard Worker if (a == origATail) {
257*c8dee2aaSAndroid Build Coastguard Worker origATail = a->prevInChain();
258*c8dee2aaSAndroid Build Coastguard Worker }
259*c8dee2aaSAndroid Build Coastguard Worker GrOp::Owner detachedA = chainA.removeOp(a);
260*c8dee2aaSAndroid Build Coastguard Worker // The GrOp::Owner releases the op.
261*c8dee2aaSAndroid Build Coastguard Worker chainB.popHead();
262*c8dee2aaSAndroid Build Coastguard Worker chainB.pushHead(std::move(detachedA));
263*c8dee2aaSAndroid Build Coastguard Worker if (chainA.empty()) {
264*c8dee2aaSAndroid Build Coastguard Worker // We merged all the nodes in chain a to chain b.
265*c8dee2aaSAndroid Build Coastguard Worker return chainB;
266*c8dee2aaSAndroid Build Coastguard Worker }
267*c8dee2aaSAndroid Build Coastguard Worker }
268*c8dee2aaSAndroid Build Coastguard Worker break;
269*c8dee2aaSAndroid Build Coastguard Worker } else {
270*c8dee2aaSAndroid Build Coastguard Worker if (++numMergeChecks == kMaxOpMergeDistance) {
271*c8dee2aaSAndroid Build Coastguard Worker break;
272*c8dee2aaSAndroid Build Coastguard Worker }
273*c8dee2aaSAndroid Build Coastguard Worker forwardMergeBounds.joinNonEmptyArg(a->bounds());
274*c8dee2aaSAndroid Build Coastguard Worker canBackwardMerge =
275*c8dee2aaSAndroid Build Coastguard Worker canBackwardMerge && can_reorder(chainB.head()->bounds(), a->bounds());
276*c8dee2aaSAndroid Build Coastguard Worker a = a->prevInChain();
277*c8dee2aaSAndroid Build Coastguard Worker }
278*c8dee2aaSAndroid Build Coastguard Worker }
279*c8dee2aaSAndroid Build Coastguard Worker // If we weren't able to merge b's head then pop b's head from chain b and make it the new
280*c8dee2aaSAndroid Build Coastguard Worker // tail of a.
281*c8dee2aaSAndroid Build Coastguard Worker if (!merged) {
282*c8dee2aaSAndroid Build Coastguard Worker chainA.pushTail(chainB.popHead());
283*c8dee2aaSAndroid Build Coastguard Worker skipBounds.joinNonEmptyArg(chainA.tail()->bounds());
284*c8dee2aaSAndroid Build Coastguard Worker }
285*c8dee2aaSAndroid Build Coastguard Worker } while (!chainB.empty());
286*c8dee2aaSAndroid Build Coastguard Worker return chainA;
287*c8dee2aaSAndroid Build Coastguard Worker }
288*c8dee2aaSAndroid Build Coastguard Worker
289*c8dee2aaSAndroid Build Coastguard Worker // Attempts to concatenate the given chain onto our own and merge ops across the chains. Returns
290*c8dee2aaSAndroid Build Coastguard Worker // whether the operation succeeded. On success, the provided list will be returned empty.
tryConcat(List * list,GrProcessorSet::Analysis processorAnalysis,const GrDstProxyView & dstProxyView,const GrAppliedClip * appliedClip,const SkRect & bounds,const GrCaps & caps,SkArenaAlloc * opsTaskArena,GrAuditTrail * auditTrail)291*c8dee2aaSAndroid Build Coastguard Worker bool OpsTask::OpChain::tryConcat(
292*c8dee2aaSAndroid Build Coastguard Worker List* list, GrProcessorSet::Analysis processorAnalysis, const GrDstProxyView& dstProxyView,
293*c8dee2aaSAndroid Build Coastguard Worker const GrAppliedClip* appliedClip, const SkRect& bounds, const GrCaps& caps,
294*c8dee2aaSAndroid Build Coastguard Worker SkArenaAlloc* opsTaskArena, GrAuditTrail* auditTrail) {
295*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!fList.empty());
296*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!list->empty());
297*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fProcessorAnalysis.requiresDstTexture() == SkToBool(fDstProxyView.proxy()));
298*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(processorAnalysis.requiresDstTexture() == SkToBool(dstProxyView.proxy()));
299*c8dee2aaSAndroid Build Coastguard Worker // All returns use explicit tuple constructor rather than {a, b} to work around old GCC bug.
300*c8dee2aaSAndroid Build Coastguard Worker if (fList.head()->classID() != list->head()->classID() ||
301*c8dee2aaSAndroid Build Coastguard Worker SkToBool(fAppliedClip) != SkToBool(appliedClip) ||
302*c8dee2aaSAndroid Build Coastguard Worker (fAppliedClip && *fAppliedClip != *appliedClip) ||
303*c8dee2aaSAndroid Build Coastguard Worker (fProcessorAnalysis.requiresNonOverlappingDraws() !=
304*c8dee2aaSAndroid Build Coastguard Worker processorAnalysis.requiresNonOverlappingDraws()) ||
305*c8dee2aaSAndroid Build Coastguard Worker (fProcessorAnalysis.requiresNonOverlappingDraws() &&
306*c8dee2aaSAndroid Build Coastguard Worker // Non-overlaping draws are only required when Ganesh will either insert a barrier,
307*c8dee2aaSAndroid Build Coastguard Worker // or read back a new dst texture between draws. In either case, we can neither
308*c8dee2aaSAndroid Build Coastguard Worker // chain nor combine overlapping Ops.
309*c8dee2aaSAndroid Build Coastguard Worker GrRectsTouchOrOverlap(fBounds, bounds)) ||
310*c8dee2aaSAndroid Build Coastguard Worker (fProcessorAnalysis.requiresDstTexture() != processorAnalysis.requiresDstTexture()) ||
311*c8dee2aaSAndroid Build Coastguard Worker (fProcessorAnalysis.requiresDstTexture() && fDstProxyView != dstProxyView)) {
312*c8dee2aaSAndroid Build Coastguard Worker return false;
313*c8dee2aaSAndroid Build Coastguard Worker }
314*c8dee2aaSAndroid Build Coastguard Worker
315*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(bool first = true;)
316*c8dee2aaSAndroid Build Coastguard Worker do {
317*c8dee2aaSAndroid Build Coastguard Worker switch (fList.tail()->combineIfPossible(list->head(), opsTaskArena, caps))
318*c8dee2aaSAndroid Build Coastguard Worker {
319*c8dee2aaSAndroid Build Coastguard Worker case GrOp::CombineResult::kCannotCombine:
320*c8dee2aaSAndroid Build Coastguard Worker // If an op supports chaining then it is required that chaining is transitive and
321*c8dee2aaSAndroid Build Coastguard Worker // that if any two ops in two different chains can merge then the two chains
322*c8dee2aaSAndroid Build Coastguard Worker // may also be chained together. Thus, we should only hit this on the first
323*c8dee2aaSAndroid Build Coastguard Worker // iteration.
324*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(first);
325*c8dee2aaSAndroid Build Coastguard Worker return false;
326*c8dee2aaSAndroid Build Coastguard Worker case GrOp::CombineResult::kMayChain:
327*c8dee2aaSAndroid Build Coastguard Worker fList = DoConcat(std::move(fList), std::exchange(*list, List()), caps, opsTaskArena,
328*c8dee2aaSAndroid Build Coastguard Worker auditTrail);
329*c8dee2aaSAndroid Build Coastguard Worker // The above exchange cleared out 'list'. The list needs to be empty now for the
330*c8dee2aaSAndroid Build Coastguard Worker // loop to terminate.
331*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(list->empty());
332*c8dee2aaSAndroid Build Coastguard Worker break;
333*c8dee2aaSAndroid Build Coastguard Worker case GrOp::CombineResult::kMerged: {
334*c8dee2aaSAndroid Build Coastguard Worker GrOP_INFO("\t\t: (%s opID: %u) -> Combining with (%s, opID: %u)\n",
335*c8dee2aaSAndroid Build Coastguard Worker list->tail()->name(), list->tail()->uniqueID(), list->head()->name(),
336*c8dee2aaSAndroid Build Coastguard Worker list->head()->uniqueID());
337*c8dee2aaSAndroid Build Coastguard Worker GR_AUDIT_TRAIL_OPS_RESULT_COMBINED(auditTrail, fList.tail(), list->head());
338*c8dee2aaSAndroid Build Coastguard Worker // The GrOp::Owner releases the op.
339*c8dee2aaSAndroid Build Coastguard Worker list->popHead();
340*c8dee2aaSAndroid Build Coastguard Worker break;
341*c8dee2aaSAndroid Build Coastguard Worker }
342*c8dee2aaSAndroid Build Coastguard Worker }
343*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(first = false);
344*c8dee2aaSAndroid Build Coastguard Worker } while (!list->empty());
345*c8dee2aaSAndroid Build Coastguard Worker
346*c8dee2aaSAndroid Build Coastguard Worker // The new ops were successfully merged and/or chained onto our own.
347*c8dee2aaSAndroid Build Coastguard Worker fBounds.joinPossiblyEmptyRect(bounds);
348*c8dee2aaSAndroid Build Coastguard Worker return true;
349*c8dee2aaSAndroid Build Coastguard Worker }
350*c8dee2aaSAndroid Build Coastguard Worker
prependChain(OpChain * that,const GrCaps & caps,SkArenaAlloc * opsTaskArena,GrAuditTrail * auditTrail)351*c8dee2aaSAndroid Build Coastguard Worker bool OpsTask::OpChain::prependChain(OpChain* that, const GrCaps& caps, SkArenaAlloc* opsTaskArena,
352*c8dee2aaSAndroid Build Coastguard Worker GrAuditTrail* auditTrail) {
353*c8dee2aaSAndroid Build Coastguard Worker if (!that->tryConcat(&fList, fProcessorAnalysis, fDstProxyView, fAppliedClip, fBounds, caps,
354*c8dee2aaSAndroid Build Coastguard Worker opsTaskArena, auditTrail)) {
355*c8dee2aaSAndroid Build Coastguard Worker this->validate();
356*c8dee2aaSAndroid Build Coastguard Worker // append failed
357*c8dee2aaSAndroid Build Coastguard Worker return false;
358*c8dee2aaSAndroid Build Coastguard Worker }
359*c8dee2aaSAndroid Build Coastguard Worker
360*c8dee2aaSAndroid Build Coastguard Worker // 'that' owns the combined chain. Move it into 'this'.
361*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fList.empty());
362*c8dee2aaSAndroid Build Coastguard Worker fList = std::move(that->fList);
363*c8dee2aaSAndroid Build Coastguard Worker fBounds = that->fBounds;
364*c8dee2aaSAndroid Build Coastguard Worker
365*c8dee2aaSAndroid Build Coastguard Worker that->fDstProxyView.setProxyView({});
366*c8dee2aaSAndroid Build Coastguard Worker if (that->fAppliedClip && that->fAppliedClip->hasCoverageFragmentProcessor()) {
367*c8dee2aaSAndroid Build Coastguard Worker // Obliterates the processor.
368*c8dee2aaSAndroid Build Coastguard Worker that->fAppliedClip->detachCoverageFragmentProcessor();
369*c8dee2aaSAndroid Build Coastguard Worker }
370*c8dee2aaSAndroid Build Coastguard Worker this->validate();
371*c8dee2aaSAndroid Build Coastguard Worker return true;
372*c8dee2aaSAndroid Build Coastguard Worker }
373*c8dee2aaSAndroid Build Coastguard Worker
appendOp(GrOp::Owner op,GrProcessorSet::Analysis processorAnalysis,const GrDstProxyView * dstProxyView,const GrAppliedClip * appliedClip,const GrCaps & caps,SkArenaAlloc * opsTaskArena,GrAuditTrail * auditTrail)374*c8dee2aaSAndroid Build Coastguard Worker GrOp::Owner OpsTask::OpChain::appendOp(
375*c8dee2aaSAndroid Build Coastguard Worker GrOp::Owner op, GrProcessorSet::Analysis processorAnalysis,
376*c8dee2aaSAndroid Build Coastguard Worker const GrDstProxyView* dstProxyView, const GrAppliedClip* appliedClip, const GrCaps& caps,
377*c8dee2aaSAndroid Build Coastguard Worker SkArenaAlloc* opsTaskArena, GrAuditTrail* auditTrail) {
378*c8dee2aaSAndroid Build Coastguard Worker const GrDstProxyView noDstProxyView;
379*c8dee2aaSAndroid Build Coastguard Worker if (!dstProxyView) {
380*c8dee2aaSAndroid Build Coastguard Worker dstProxyView = &noDstProxyView;
381*c8dee2aaSAndroid Build Coastguard Worker }
382*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(op->isChainHead() && op->isChainTail());
383*c8dee2aaSAndroid Build Coastguard Worker SkRect opBounds = op->bounds();
384*c8dee2aaSAndroid Build Coastguard Worker List chain(std::move(op));
385*c8dee2aaSAndroid Build Coastguard Worker if (!this->tryConcat(&chain, processorAnalysis, *dstProxyView, appliedClip, opBounds, caps,
386*c8dee2aaSAndroid Build Coastguard Worker opsTaskArena, auditTrail)) {
387*c8dee2aaSAndroid Build Coastguard Worker // append failed, give the op back to the caller.
388*c8dee2aaSAndroid Build Coastguard Worker this->validate();
389*c8dee2aaSAndroid Build Coastguard Worker return chain.popHead();
390*c8dee2aaSAndroid Build Coastguard Worker }
391*c8dee2aaSAndroid Build Coastguard Worker
392*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(chain.empty());
393*c8dee2aaSAndroid Build Coastguard Worker this->validate();
394*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
395*c8dee2aaSAndroid Build Coastguard Worker }
396*c8dee2aaSAndroid Build Coastguard Worker
validate() const397*c8dee2aaSAndroid Build Coastguard Worker inline void OpsTask::OpChain::validate() const {
398*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG
399*c8dee2aaSAndroid Build Coastguard Worker fList.validate();
400*c8dee2aaSAndroid Build Coastguard Worker for (const auto& op : GrOp::ChainRange<>(fList.head())) {
401*c8dee2aaSAndroid Build Coastguard Worker // Not using SkRect::contains because we allow empty rects.
402*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fBounds.fLeft <= op.bounds().fLeft && fBounds.fTop <= op.bounds().fTop &&
403*c8dee2aaSAndroid Build Coastguard Worker fBounds.fRight >= op.bounds().fRight && fBounds.fBottom >= op.bounds().fBottom);
404*c8dee2aaSAndroid Build Coastguard Worker }
405*c8dee2aaSAndroid Build Coastguard Worker #endif
406*c8dee2aaSAndroid Build Coastguard Worker }
407*c8dee2aaSAndroid Build Coastguard Worker
408*c8dee2aaSAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////////
409*c8dee2aaSAndroid Build Coastguard Worker
OpsTask(GrDrawingManager * drawingMgr,GrSurfaceProxyView view,GrAuditTrail * auditTrail,sk_sp<GrArenas> arenas)410*c8dee2aaSAndroid Build Coastguard Worker OpsTask::OpsTask(GrDrawingManager* drawingMgr,
411*c8dee2aaSAndroid Build Coastguard Worker GrSurfaceProxyView view,
412*c8dee2aaSAndroid Build Coastguard Worker GrAuditTrail* auditTrail,
413*c8dee2aaSAndroid Build Coastguard Worker sk_sp<GrArenas> arenas)
414*c8dee2aaSAndroid Build Coastguard Worker : GrRenderTask()
415*c8dee2aaSAndroid Build Coastguard Worker , fAuditTrail(auditTrail)
416*c8dee2aaSAndroid Build Coastguard Worker , fUsesMSAASurface(view.asRenderTargetProxy()->numSamples() > 1)
417*c8dee2aaSAndroid Build Coastguard Worker , fTargetSwizzle(view.swizzle())
418*c8dee2aaSAndroid Build Coastguard Worker , fTargetOrigin(view.origin())
419*c8dee2aaSAndroid Build Coastguard Worker , fArenas{std::move(arenas)}
420*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(, fNumClips(0)) {
421*c8dee2aaSAndroid Build Coastguard Worker this->addTarget(drawingMgr, view.detachProxy());
422*c8dee2aaSAndroid Build Coastguard Worker }
423*c8dee2aaSAndroid Build Coastguard Worker
deleteOps()424*c8dee2aaSAndroid Build Coastguard Worker void OpsTask::deleteOps() {
425*c8dee2aaSAndroid Build Coastguard Worker for (auto& chain : fOpChains) {
426*c8dee2aaSAndroid Build Coastguard Worker chain.deleteOps();
427*c8dee2aaSAndroid Build Coastguard Worker }
428*c8dee2aaSAndroid Build Coastguard Worker fOpChains.clear();
429*c8dee2aaSAndroid Build Coastguard Worker }
430*c8dee2aaSAndroid Build Coastguard Worker
~OpsTask()431*c8dee2aaSAndroid Build Coastguard Worker OpsTask::~OpsTask() {
432*c8dee2aaSAndroid Build Coastguard Worker this->deleteOps();
433*c8dee2aaSAndroid Build Coastguard Worker }
434*c8dee2aaSAndroid Build Coastguard Worker
addOp(GrDrawingManager * drawingMgr,GrOp::Owner op,GrTextureResolveManager textureResolveManager,const GrCaps & caps)435*c8dee2aaSAndroid Build Coastguard Worker void OpsTask::addOp(GrDrawingManager* drawingMgr, GrOp::Owner op,
436*c8dee2aaSAndroid Build Coastguard Worker GrTextureResolveManager textureResolveManager, const GrCaps& caps) {
437*c8dee2aaSAndroid Build Coastguard Worker auto addDependency = [&](GrSurfaceProxy* p, skgpu::Mipmapped mipmapped) {
438*c8dee2aaSAndroid Build Coastguard Worker this->addDependency(drawingMgr, p, mipmapped, textureResolveManager, caps);
439*c8dee2aaSAndroid Build Coastguard Worker };
440*c8dee2aaSAndroid Build Coastguard Worker
441*c8dee2aaSAndroid Build Coastguard Worker op->visitProxies(addDependency);
442*c8dee2aaSAndroid Build Coastguard Worker
443*c8dee2aaSAndroid Build Coastguard Worker this->recordOp(std::move(op), false/*usesMSAA*/, GrProcessorSet::EmptySetAnalysis(), nullptr,
444*c8dee2aaSAndroid Build Coastguard Worker nullptr, caps);
445*c8dee2aaSAndroid Build Coastguard Worker }
446*c8dee2aaSAndroid Build Coastguard Worker
addDrawOp(GrDrawingManager * drawingMgr,GrOp::Owner op,bool usesMSAA,const GrProcessorSet::Analysis & processorAnalysis,GrAppliedClip && clip,const GrDstProxyView & dstProxyView,GrTextureResolveManager textureResolveManager,const GrCaps & caps)447*c8dee2aaSAndroid Build Coastguard Worker void OpsTask::addDrawOp(GrDrawingManager* drawingMgr, GrOp::Owner op, bool usesMSAA,
448*c8dee2aaSAndroid Build Coastguard Worker const GrProcessorSet::Analysis& processorAnalysis, GrAppliedClip&& clip,
449*c8dee2aaSAndroid Build Coastguard Worker const GrDstProxyView& dstProxyView,
450*c8dee2aaSAndroid Build Coastguard Worker GrTextureResolveManager textureResolveManager, const GrCaps& caps) {
451*c8dee2aaSAndroid Build Coastguard Worker auto addDependency = [&](GrSurfaceProxy* p, skgpu::Mipmapped mipmapped) {
452*c8dee2aaSAndroid Build Coastguard Worker this->addSampledTexture(p);
453*c8dee2aaSAndroid Build Coastguard Worker this->addDependency(drawingMgr, p, mipmapped, textureResolveManager, caps);
454*c8dee2aaSAndroid Build Coastguard Worker };
455*c8dee2aaSAndroid Build Coastguard Worker
456*c8dee2aaSAndroid Build Coastguard Worker op->visitProxies(addDependency);
457*c8dee2aaSAndroid Build Coastguard Worker clip.visitProxies(addDependency);
458*c8dee2aaSAndroid Build Coastguard Worker if (dstProxyView.proxy()) {
459*c8dee2aaSAndroid Build Coastguard Worker if (!(dstProxyView.dstSampleFlags() & GrDstSampleFlags::kAsInputAttachment)) {
460*c8dee2aaSAndroid Build Coastguard Worker this->addSampledTexture(dstProxyView.proxy());
461*c8dee2aaSAndroid Build Coastguard Worker }
462*c8dee2aaSAndroid Build Coastguard Worker if (dstProxyView.dstSampleFlags() & GrDstSampleFlags::kRequiresTextureBarrier) {
463*c8dee2aaSAndroid Build Coastguard Worker fRenderPassXferBarriers |= GrXferBarrierFlags::kTexture;
464*c8dee2aaSAndroid Build Coastguard Worker }
465*c8dee2aaSAndroid Build Coastguard Worker addDependency(dstProxyView.proxy(), skgpu::Mipmapped::kNo);
466*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!(dstProxyView.dstSampleFlags() & GrDstSampleFlags::kAsInputAttachment) ||
467*c8dee2aaSAndroid Build Coastguard Worker dstProxyView.offset().isZero());
468*c8dee2aaSAndroid Build Coastguard Worker }
469*c8dee2aaSAndroid Build Coastguard Worker
470*c8dee2aaSAndroid Build Coastguard Worker if (processorAnalysis.usesNonCoherentHWBlending()) {
471*c8dee2aaSAndroid Build Coastguard Worker fRenderPassXferBarriers |= GrXferBarrierFlags::kBlend;
472*c8dee2aaSAndroid Build Coastguard Worker }
473*c8dee2aaSAndroid Build Coastguard Worker
474*c8dee2aaSAndroid Build Coastguard Worker this->recordOp(std::move(op), usesMSAA, processorAnalysis, clip.doesClip() ? &clip : nullptr,
475*c8dee2aaSAndroid Build Coastguard Worker &dstProxyView, caps);
476*c8dee2aaSAndroid Build Coastguard Worker }
477*c8dee2aaSAndroid Build Coastguard Worker
endFlush(GrDrawingManager * drawingMgr)478*c8dee2aaSAndroid Build Coastguard Worker void OpsTask::endFlush(GrDrawingManager* drawingMgr) {
479*c8dee2aaSAndroid Build Coastguard Worker fLastClipStackGenID = SK_InvalidUniqueID;
480*c8dee2aaSAndroid Build Coastguard Worker this->deleteOps();
481*c8dee2aaSAndroid Build Coastguard Worker
482*c8dee2aaSAndroid Build Coastguard Worker fDeferredProxies.clear();
483*c8dee2aaSAndroid Build Coastguard Worker fSampledProxies.clear();
484*c8dee2aaSAndroid Build Coastguard Worker fAuditTrail = nullptr;
485*c8dee2aaSAndroid Build Coastguard Worker
486*c8dee2aaSAndroid Build Coastguard Worker GrRenderTask::endFlush(drawingMgr);
487*c8dee2aaSAndroid Build Coastguard Worker }
488*c8dee2aaSAndroid Build Coastguard Worker
onPrePrepare(GrRecordingContext * context)489*c8dee2aaSAndroid Build Coastguard Worker void OpsTask::onPrePrepare(GrRecordingContext* context) {
490*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(this->isClosed());
491*c8dee2aaSAndroid Build Coastguard Worker // TODO: remove the check for discard here once reduced op splitting is turned on. Currently we
492*c8dee2aaSAndroid Build Coastguard Worker // can end up with OpsTasks that only have a discard load op and no ops. For vulkan validation
493*c8dee2aaSAndroid Build Coastguard Worker // we need to keep that discard and not drop it. Once we have reduce op list splitting enabled
494*c8dee2aaSAndroid Build Coastguard Worker // we shouldn't end up with OpsTasks with only discard.
495*c8dee2aaSAndroid Build Coastguard Worker if (this->isColorNoOp() ||
496*c8dee2aaSAndroid Build Coastguard Worker (fClippedContentBounds.isEmpty() && fColorLoadOp != GrLoadOp::kDiscard)) {
497*c8dee2aaSAndroid Build Coastguard Worker return;
498*c8dee2aaSAndroid Build Coastguard Worker }
499*c8dee2aaSAndroid Build Coastguard Worker TRACE_EVENT0("skia.gpu", TRACE_FUNC);
500*c8dee2aaSAndroid Build Coastguard Worker
501*c8dee2aaSAndroid Build Coastguard Worker GrSurfaceProxyView dstView(sk_ref_sp(this->target(0)), fTargetOrigin, fTargetSwizzle);
502*c8dee2aaSAndroid Build Coastguard Worker for (const auto& chain : fOpChains) {
503*c8dee2aaSAndroid Build Coastguard Worker if (chain.shouldExecute()) {
504*c8dee2aaSAndroid Build Coastguard Worker chain.head()->prePrepare(context,
505*c8dee2aaSAndroid Build Coastguard Worker dstView,
506*c8dee2aaSAndroid Build Coastguard Worker chain.appliedClip(),
507*c8dee2aaSAndroid Build Coastguard Worker chain.dstProxyView(),
508*c8dee2aaSAndroid Build Coastguard Worker fRenderPassXferBarriers,
509*c8dee2aaSAndroid Build Coastguard Worker fColorLoadOp);
510*c8dee2aaSAndroid Build Coastguard Worker }
511*c8dee2aaSAndroid Build Coastguard Worker }
512*c8dee2aaSAndroid Build Coastguard Worker }
513*c8dee2aaSAndroid Build Coastguard Worker
onPrepare(GrOpFlushState * flushState)514*c8dee2aaSAndroid Build Coastguard Worker void OpsTask::onPrepare(GrOpFlushState* flushState) {
515*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(this->target(0)->peekRenderTarget());
516*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(this->isClosed());
517*c8dee2aaSAndroid Build Coastguard Worker // TODO: remove the check for discard here once reduced op splitting is turned on. Currently we
518*c8dee2aaSAndroid Build Coastguard Worker // can end up with OpsTasks that only have a discard load op and no ops. For vulkan validation
519*c8dee2aaSAndroid Build Coastguard Worker // we need to keep that discard and not drop it. Once we have reduce op list splitting enabled
520*c8dee2aaSAndroid Build Coastguard Worker // we shouldn't end up with OpsTasks with only discard.
521*c8dee2aaSAndroid Build Coastguard Worker if (this->isColorNoOp() ||
522*c8dee2aaSAndroid Build Coastguard Worker (fClippedContentBounds.isEmpty() && fColorLoadOp != GrLoadOp::kDiscard)) {
523*c8dee2aaSAndroid Build Coastguard Worker return;
524*c8dee2aaSAndroid Build Coastguard Worker }
525*c8dee2aaSAndroid Build Coastguard Worker TRACE_EVENT0_ALWAYS("skia.gpu", TRACE_FUNC);
526*c8dee2aaSAndroid Build Coastguard Worker
527*c8dee2aaSAndroid Build Coastguard Worker flushState->setSampledProxyArray(&fSampledProxies);
528*c8dee2aaSAndroid Build Coastguard Worker GrSurfaceProxyView dstView(sk_ref_sp(this->target(0)), fTargetOrigin, fTargetSwizzle);
529*c8dee2aaSAndroid Build Coastguard Worker // Loop over the ops that haven't yet been prepared.
530*c8dee2aaSAndroid Build Coastguard Worker for (const auto& chain : fOpChains) {
531*c8dee2aaSAndroid Build Coastguard Worker if (chain.shouldExecute()) {
532*c8dee2aaSAndroid Build Coastguard Worker GrOpFlushState::OpArgs opArgs(chain.head(),
533*c8dee2aaSAndroid Build Coastguard Worker dstView,
534*c8dee2aaSAndroid Build Coastguard Worker fUsesMSAASurface,
535*c8dee2aaSAndroid Build Coastguard Worker chain.appliedClip(),
536*c8dee2aaSAndroid Build Coastguard Worker chain.dstProxyView(),
537*c8dee2aaSAndroid Build Coastguard Worker fRenderPassXferBarriers,
538*c8dee2aaSAndroid Build Coastguard Worker fColorLoadOp);
539*c8dee2aaSAndroid Build Coastguard Worker
540*c8dee2aaSAndroid Build Coastguard Worker flushState->setOpArgs(&opArgs);
541*c8dee2aaSAndroid Build Coastguard Worker
542*c8dee2aaSAndroid Build Coastguard Worker // Temporary debugging helper: for debugging prePrepare w/o going through DDLs
543*c8dee2aaSAndroid Build Coastguard Worker // Delete once most of the GrOps have an onPrePrepare.
544*c8dee2aaSAndroid Build Coastguard Worker // chain.head()->prePrepare(flushState->gpu()->getContext(), &this->target(0),
545*c8dee2aaSAndroid Build Coastguard Worker // chain.appliedClip());
546*c8dee2aaSAndroid Build Coastguard Worker
547*c8dee2aaSAndroid Build Coastguard Worker // GrOp::prePrepare may or may not have been called at this point
548*c8dee2aaSAndroid Build Coastguard Worker chain.head()->prepare(flushState);
549*c8dee2aaSAndroid Build Coastguard Worker flushState->setOpArgs(nullptr);
550*c8dee2aaSAndroid Build Coastguard Worker }
551*c8dee2aaSAndroid Build Coastguard Worker }
552*c8dee2aaSAndroid Build Coastguard Worker flushState->setSampledProxyArray(nullptr);
553*c8dee2aaSAndroid Build Coastguard Worker }
554*c8dee2aaSAndroid Build Coastguard Worker
555*c8dee2aaSAndroid Build Coastguard Worker // TODO: this is where GrOp::renderTarget is used (which is fine since it
556*c8dee2aaSAndroid Build Coastguard Worker // is at flush time). However, we need to store the RenderTargetProxy in the
557*c8dee2aaSAndroid Build Coastguard Worker // Ops and instantiate them here.
onExecute(GrOpFlushState * flushState)558*c8dee2aaSAndroid Build Coastguard Worker bool OpsTask::onExecute(GrOpFlushState* flushState) {
559*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(this->numTargets() == 1);
560*c8dee2aaSAndroid Build Coastguard Worker GrRenderTargetProxy* proxy = this->target(0)->asRenderTargetProxy();
561*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(proxy);
562*c8dee2aaSAndroid Build Coastguard Worker SK_AT_SCOPE_EXIT(proxy->clearArenas());
563*c8dee2aaSAndroid Build Coastguard Worker
564*c8dee2aaSAndroid Build Coastguard Worker if (this->isColorNoOp() || fClippedContentBounds.isEmpty()) {
565*c8dee2aaSAndroid Build Coastguard Worker return false;
566*c8dee2aaSAndroid Build Coastguard Worker }
567*c8dee2aaSAndroid Build Coastguard Worker TRACE_EVENT0_ALWAYS("skia.gpu", TRACE_FUNC);
568*c8dee2aaSAndroid Build Coastguard Worker
569*c8dee2aaSAndroid Build Coastguard Worker // Make sure load ops are not kClear if the GPU needs to use draws for clears
570*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fColorLoadOp != GrLoadOp::kClear ||
571*c8dee2aaSAndroid Build Coastguard Worker !flushState->gpu()->caps()->performColorClearsAsDraws());
572*c8dee2aaSAndroid Build Coastguard Worker
573*c8dee2aaSAndroid Build Coastguard Worker const GrCaps& caps = *flushState->gpu()->caps();
574*c8dee2aaSAndroid Build Coastguard Worker GrRenderTarget* renderTarget = proxy->peekRenderTarget();
575*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(renderTarget);
576*c8dee2aaSAndroid Build Coastguard Worker
577*c8dee2aaSAndroid Build Coastguard Worker GrAttachment* stencil = nullptr;
578*c8dee2aaSAndroid Build Coastguard Worker if (proxy->needsStencil()) {
579*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(proxy->canUseStencil(caps));
580*c8dee2aaSAndroid Build Coastguard Worker if (!flushState->resourceProvider()->attachStencilAttachment(renderTarget,
581*c8dee2aaSAndroid Build Coastguard Worker fUsesMSAASurface)) {
582*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("WARNING: failed to attach a stencil buffer. Rendering will be skipped.\n");
583*c8dee2aaSAndroid Build Coastguard Worker return false;
584*c8dee2aaSAndroid Build Coastguard Worker }
585*c8dee2aaSAndroid Build Coastguard Worker stencil = renderTarget->getStencilAttachment(fUsesMSAASurface);
586*c8dee2aaSAndroid Build Coastguard Worker }
587*c8dee2aaSAndroid Build Coastguard Worker
588*c8dee2aaSAndroid Build Coastguard Worker GrLoadOp stencilLoadOp;
589*c8dee2aaSAndroid Build Coastguard Worker switch (fInitialStencilContent) {
590*c8dee2aaSAndroid Build Coastguard Worker case StencilContent::kDontCare:
591*c8dee2aaSAndroid Build Coastguard Worker stencilLoadOp = GrLoadOp::kDiscard;
592*c8dee2aaSAndroid Build Coastguard Worker break;
593*c8dee2aaSAndroid Build Coastguard Worker case StencilContent::kUserBitsCleared:
594*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!caps.performStencilClearsAsDraws());
595*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(stencil);
596*c8dee2aaSAndroid Build Coastguard Worker if (caps.discardStencilValuesAfterRenderPass()) {
597*c8dee2aaSAndroid Build Coastguard Worker // Always clear the stencil if it is being discarded after render passes. This is
598*c8dee2aaSAndroid Build Coastguard Worker // also an optimization because we are on a tiler and it avoids loading the values
599*c8dee2aaSAndroid Build Coastguard Worker // from memory.
600*c8dee2aaSAndroid Build Coastguard Worker stencilLoadOp = GrLoadOp::kClear;
601*c8dee2aaSAndroid Build Coastguard Worker break;
602*c8dee2aaSAndroid Build Coastguard Worker }
603*c8dee2aaSAndroid Build Coastguard Worker if (!stencil->hasPerformedInitialClear()) {
604*c8dee2aaSAndroid Build Coastguard Worker stencilLoadOp = GrLoadOp::kClear;
605*c8dee2aaSAndroid Build Coastguard Worker stencil->markHasPerformedInitialClear();
606*c8dee2aaSAndroid Build Coastguard Worker break;
607*c8dee2aaSAndroid Build Coastguard Worker }
608*c8dee2aaSAndroid Build Coastguard Worker // SurfaceDrawContexts are required to leave the user stencil bits in a cleared state
609*c8dee2aaSAndroid Build Coastguard Worker // once finished, meaning the stencil values will always remain cleared after the
610*c8dee2aaSAndroid Build Coastguard Worker // initial clear. Just fall through to reloading the existing (cleared) stencil values
611*c8dee2aaSAndroid Build Coastguard Worker // from memory.
612*c8dee2aaSAndroid Build Coastguard Worker [[fallthrough]];
613*c8dee2aaSAndroid Build Coastguard Worker case StencilContent::kPreserved:
614*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(stencil);
615*c8dee2aaSAndroid Build Coastguard Worker stencilLoadOp = GrLoadOp::kLoad;
616*c8dee2aaSAndroid Build Coastguard Worker break;
617*c8dee2aaSAndroid Build Coastguard Worker }
618*c8dee2aaSAndroid Build Coastguard Worker
619*c8dee2aaSAndroid Build Coastguard Worker // NOTE: If fMustPreserveStencil is set, then we are executing a surfaceDrawContext that split
620*c8dee2aaSAndroid Build Coastguard Worker // its opsTask.
621*c8dee2aaSAndroid Build Coastguard Worker //
622*c8dee2aaSAndroid Build Coastguard Worker // FIXME: We don't currently flag render passes that don't use stencil at all. In that case
623*c8dee2aaSAndroid Build Coastguard Worker // their store op might be "discard", and we currently make the assumption that a discard will
624*c8dee2aaSAndroid Build Coastguard Worker // not invalidate what's already in main memory. This is probably ok for now, but certainly
625*c8dee2aaSAndroid Build Coastguard Worker // something we want to address soon.
626*c8dee2aaSAndroid Build Coastguard Worker GrStoreOp stencilStoreOp = (caps.discardStencilValuesAfterRenderPass() && !fMustPreserveStencil)
627*c8dee2aaSAndroid Build Coastguard Worker ? GrStoreOp::kDiscard
628*c8dee2aaSAndroid Build Coastguard Worker : GrStoreOp::kStore;
629*c8dee2aaSAndroid Build Coastguard Worker
630*c8dee2aaSAndroid Build Coastguard Worker GrOpsRenderPass* renderPass = create_render_pass(flushState->gpu(),
631*c8dee2aaSAndroid Build Coastguard Worker proxy->peekRenderTarget(),
632*c8dee2aaSAndroid Build Coastguard Worker fUsesMSAASurface,
633*c8dee2aaSAndroid Build Coastguard Worker stencil,
634*c8dee2aaSAndroid Build Coastguard Worker fTargetOrigin,
635*c8dee2aaSAndroid Build Coastguard Worker fClippedContentBounds,
636*c8dee2aaSAndroid Build Coastguard Worker fColorLoadOp,
637*c8dee2aaSAndroid Build Coastguard Worker fLoadClearColor,
638*c8dee2aaSAndroid Build Coastguard Worker stencilLoadOp,
639*c8dee2aaSAndroid Build Coastguard Worker stencilStoreOp,
640*c8dee2aaSAndroid Build Coastguard Worker fSampledProxies,
641*c8dee2aaSAndroid Build Coastguard Worker fRenderPassXferBarriers);
642*c8dee2aaSAndroid Build Coastguard Worker
643*c8dee2aaSAndroid Build Coastguard Worker if (!renderPass) {
644*c8dee2aaSAndroid Build Coastguard Worker return false;
645*c8dee2aaSAndroid Build Coastguard Worker }
646*c8dee2aaSAndroid Build Coastguard Worker flushState->setOpsRenderPass(renderPass);
647*c8dee2aaSAndroid Build Coastguard Worker renderPass->begin();
648*c8dee2aaSAndroid Build Coastguard Worker
649*c8dee2aaSAndroid Build Coastguard Worker GrSurfaceProxyView dstView(sk_ref_sp(this->target(0)), fTargetOrigin, fTargetSwizzle);
650*c8dee2aaSAndroid Build Coastguard Worker
651*c8dee2aaSAndroid Build Coastguard Worker // Draw all the generated geometry.
652*c8dee2aaSAndroid Build Coastguard Worker for (const auto& chain : fOpChains) {
653*c8dee2aaSAndroid Build Coastguard Worker if (!chain.shouldExecute()) {
654*c8dee2aaSAndroid Build Coastguard Worker continue;
655*c8dee2aaSAndroid Build Coastguard Worker }
656*c8dee2aaSAndroid Build Coastguard Worker
657*c8dee2aaSAndroid Build Coastguard Worker GrOpFlushState::OpArgs opArgs(chain.head(),
658*c8dee2aaSAndroid Build Coastguard Worker dstView,
659*c8dee2aaSAndroid Build Coastguard Worker fUsesMSAASurface,
660*c8dee2aaSAndroid Build Coastguard Worker chain.appliedClip(),
661*c8dee2aaSAndroid Build Coastguard Worker chain.dstProxyView(),
662*c8dee2aaSAndroid Build Coastguard Worker fRenderPassXferBarriers,
663*c8dee2aaSAndroid Build Coastguard Worker fColorLoadOp);
664*c8dee2aaSAndroid Build Coastguard Worker
665*c8dee2aaSAndroid Build Coastguard Worker flushState->setOpArgs(&opArgs);
666*c8dee2aaSAndroid Build Coastguard Worker chain.head()->execute(flushState, chain.bounds());
667*c8dee2aaSAndroid Build Coastguard Worker flushState->setOpArgs(nullptr);
668*c8dee2aaSAndroid Build Coastguard Worker }
669*c8dee2aaSAndroid Build Coastguard Worker
670*c8dee2aaSAndroid Build Coastguard Worker renderPass->end();
671*c8dee2aaSAndroid Build Coastguard Worker flushState->gpu()->submit(renderPass);
672*c8dee2aaSAndroid Build Coastguard Worker flushState->setOpsRenderPass(nullptr);
673*c8dee2aaSAndroid Build Coastguard Worker
674*c8dee2aaSAndroid Build Coastguard Worker return true;
675*c8dee2aaSAndroid Build Coastguard Worker }
676*c8dee2aaSAndroid Build Coastguard Worker
setColorLoadOp(GrLoadOp op,std::array<float,4> color)677*c8dee2aaSAndroid Build Coastguard Worker void OpsTask::setColorLoadOp(GrLoadOp op, std::array<float, 4> color) {
678*c8dee2aaSAndroid Build Coastguard Worker fColorLoadOp = op;
679*c8dee2aaSAndroid Build Coastguard Worker fLoadClearColor = color;
680*c8dee2aaSAndroid Build Coastguard Worker if (GrLoadOp::kClear == fColorLoadOp) {
681*c8dee2aaSAndroid Build Coastguard Worker GrSurfaceProxy* proxy = this->target(0);
682*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(proxy);
683*c8dee2aaSAndroid Build Coastguard Worker fTotalBounds = proxy->backingStoreBoundsRect();
684*c8dee2aaSAndroid Build Coastguard Worker }
685*c8dee2aaSAndroid Build Coastguard Worker }
686*c8dee2aaSAndroid Build Coastguard Worker
reset()687*c8dee2aaSAndroid Build Coastguard Worker void OpsTask::reset() {
688*c8dee2aaSAndroid Build Coastguard Worker fDeferredProxies.clear();
689*c8dee2aaSAndroid Build Coastguard Worker fSampledProxies.clear();
690*c8dee2aaSAndroid Build Coastguard Worker fClippedContentBounds = SkIRect::MakeEmpty();
691*c8dee2aaSAndroid Build Coastguard Worker fTotalBounds = SkRect::MakeEmpty();
692*c8dee2aaSAndroid Build Coastguard Worker this->deleteOps();
693*c8dee2aaSAndroid Build Coastguard Worker fRenderPassXferBarriers = GrXferBarrierFlags::kNone;
694*c8dee2aaSAndroid Build Coastguard Worker }
695*c8dee2aaSAndroid Build Coastguard Worker
canMerge(const OpsTask * opsTask) const696*c8dee2aaSAndroid Build Coastguard Worker bool OpsTask::canMerge(const OpsTask* opsTask) const {
697*c8dee2aaSAndroid Build Coastguard Worker return this->target(0) == opsTask->target(0) &&
698*c8dee2aaSAndroid Build Coastguard Worker fArenas == opsTask->fArenas &&
699*c8dee2aaSAndroid Build Coastguard Worker !opsTask->fCannotMergeBackward;
700*c8dee2aaSAndroid Build Coastguard Worker }
701*c8dee2aaSAndroid Build Coastguard Worker
mergeFrom(SkSpan<const sk_sp<GrRenderTask>> tasks)702*c8dee2aaSAndroid Build Coastguard Worker int OpsTask::mergeFrom(SkSpan<const sk_sp<GrRenderTask>> tasks) {
703*c8dee2aaSAndroid Build Coastguard Worker int mergedCount = 0;
704*c8dee2aaSAndroid Build Coastguard Worker for (const sk_sp<GrRenderTask>& task : tasks) {
705*c8dee2aaSAndroid Build Coastguard Worker auto opsTask = task->asOpsTask();
706*c8dee2aaSAndroid Build Coastguard Worker if (!opsTask || !this->canMerge(opsTask)) {
707*c8dee2aaSAndroid Build Coastguard Worker break;
708*c8dee2aaSAndroid Build Coastguard Worker }
709*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fTargetSwizzle == opsTask->fTargetSwizzle);
710*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fTargetOrigin == opsTask->fTargetOrigin);
711*c8dee2aaSAndroid Build Coastguard Worker if (GrLoadOp::kClear == opsTask->fColorLoadOp) {
712*c8dee2aaSAndroid Build Coastguard Worker // TODO(11903): Go back to actually dropping ops tasks when we are merged with
713*c8dee2aaSAndroid Build Coastguard Worker // color clear.
714*c8dee2aaSAndroid Build Coastguard Worker return 0;
715*c8dee2aaSAndroid Build Coastguard Worker }
716*c8dee2aaSAndroid Build Coastguard Worker mergedCount += 1;
717*c8dee2aaSAndroid Build Coastguard Worker }
718*c8dee2aaSAndroid Build Coastguard Worker if (0 == mergedCount) {
719*c8dee2aaSAndroid Build Coastguard Worker return 0;
720*c8dee2aaSAndroid Build Coastguard Worker }
721*c8dee2aaSAndroid Build Coastguard Worker
722*c8dee2aaSAndroid Build Coastguard Worker SkSpan<const sk_sp<OpsTask>> mergingNodes(
723*c8dee2aaSAndroid Build Coastguard Worker reinterpret_cast<const sk_sp<OpsTask>*>(tasks.data()), SkToSizeT(mergedCount));
724*c8dee2aaSAndroid Build Coastguard Worker int addlDeferredProxyCount = 0;
725*c8dee2aaSAndroid Build Coastguard Worker int addlProxyCount = 0;
726*c8dee2aaSAndroid Build Coastguard Worker int addlOpChainCount = 0;
727*c8dee2aaSAndroid Build Coastguard Worker for (const auto& toMerge : mergingNodes) {
728*c8dee2aaSAndroid Build Coastguard Worker addlDeferredProxyCount += toMerge->fDeferredProxies.size();
729*c8dee2aaSAndroid Build Coastguard Worker addlProxyCount += toMerge->fSampledProxies.size();
730*c8dee2aaSAndroid Build Coastguard Worker addlOpChainCount += toMerge->fOpChains.size();
731*c8dee2aaSAndroid Build Coastguard Worker fClippedContentBounds.join(toMerge->fClippedContentBounds);
732*c8dee2aaSAndroid Build Coastguard Worker fTotalBounds.join(toMerge->fTotalBounds);
733*c8dee2aaSAndroid Build Coastguard Worker fRenderPassXferBarriers |= toMerge->fRenderPassXferBarriers;
734*c8dee2aaSAndroid Build Coastguard Worker if (fInitialStencilContent == StencilContent::kDontCare) {
735*c8dee2aaSAndroid Build Coastguard Worker // Propogate the first stencil content that isn't kDontCare.
736*c8dee2aaSAndroid Build Coastguard Worker //
737*c8dee2aaSAndroid Build Coastguard Worker // Once the stencil has any kind of initial content that isn't kDontCare, then the
738*c8dee2aaSAndroid Build Coastguard Worker // inital contents of subsequent opsTasks that get merged in don't matter.
739*c8dee2aaSAndroid Build Coastguard Worker //
740*c8dee2aaSAndroid Build Coastguard Worker // (This works because the opsTask all target the same render target and are in
741*c8dee2aaSAndroid Build Coastguard Worker // painter's order. kPreserved obviously happens automatically with a merge, and kClear
742*c8dee2aaSAndroid Build Coastguard Worker // is also automatic because the contract is for ops to leave the stencil buffer in a
743*c8dee2aaSAndroid Build Coastguard Worker // cleared state when finished.)
744*c8dee2aaSAndroid Build Coastguard Worker fInitialStencilContent = toMerge->fInitialStencilContent;
745*c8dee2aaSAndroid Build Coastguard Worker }
746*c8dee2aaSAndroid Build Coastguard Worker fUsesMSAASurface |= toMerge->fUsesMSAASurface;
747*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(fNumClips += toMerge->fNumClips);
748*c8dee2aaSAndroid Build Coastguard Worker }
749*c8dee2aaSAndroid Build Coastguard Worker
750*c8dee2aaSAndroid Build Coastguard Worker fLastClipStackGenID = SK_InvalidUniqueID;
751*c8dee2aaSAndroid Build Coastguard Worker fDeferredProxies.reserve_exact(fDeferredProxies.size() + addlDeferredProxyCount);
752*c8dee2aaSAndroid Build Coastguard Worker fSampledProxies.reserve_exact(fSampledProxies.size() + addlProxyCount);
753*c8dee2aaSAndroid Build Coastguard Worker fOpChains.reserve_exact(fOpChains.size() + addlOpChainCount);
754*c8dee2aaSAndroid Build Coastguard Worker for (const auto& toMerge : mergingNodes) {
755*c8dee2aaSAndroid Build Coastguard Worker for (GrRenderTask* renderTask : toMerge->dependents()) {
756*c8dee2aaSAndroid Build Coastguard Worker renderTask->replaceDependency(toMerge.get(), this);
757*c8dee2aaSAndroid Build Coastguard Worker }
758*c8dee2aaSAndroid Build Coastguard Worker for (GrRenderTask* renderTask : toMerge->dependencies()) {
759*c8dee2aaSAndroid Build Coastguard Worker renderTask->replaceDependent(toMerge.get(), this);
760*c8dee2aaSAndroid Build Coastguard Worker }
761*c8dee2aaSAndroid Build Coastguard Worker fDeferredProxies.move_back_n(toMerge->fDeferredProxies.size(),
762*c8dee2aaSAndroid Build Coastguard Worker toMerge->fDeferredProxies.data());
763*c8dee2aaSAndroid Build Coastguard Worker fSampledProxies.move_back_n(toMerge->fSampledProxies.size(),
764*c8dee2aaSAndroid Build Coastguard Worker toMerge->fSampledProxies.data());
765*c8dee2aaSAndroid Build Coastguard Worker fOpChains.move_back_n(toMerge->fOpChains.size(),
766*c8dee2aaSAndroid Build Coastguard Worker toMerge->fOpChains.data());
767*c8dee2aaSAndroid Build Coastguard Worker toMerge->fDeferredProxies.clear();
768*c8dee2aaSAndroid Build Coastguard Worker toMerge->fSampledProxies.clear();
769*c8dee2aaSAndroid Build Coastguard Worker toMerge->fOpChains.clear();
770*c8dee2aaSAndroid Build Coastguard Worker }
771*c8dee2aaSAndroid Build Coastguard Worker fMustPreserveStencil = mergingNodes.back()->fMustPreserveStencil;
772*c8dee2aaSAndroid Build Coastguard Worker return mergedCount;
773*c8dee2aaSAndroid Build Coastguard Worker }
774*c8dee2aaSAndroid Build Coastguard Worker
resetForFullscreenClear(CanDiscardPreviousOps canDiscardPreviousOps)775*c8dee2aaSAndroid Build Coastguard Worker bool OpsTask::resetForFullscreenClear(CanDiscardPreviousOps canDiscardPreviousOps) {
776*c8dee2aaSAndroid Build Coastguard Worker if (CanDiscardPreviousOps::kYes == canDiscardPreviousOps || this->isEmpty()) {
777*c8dee2aaSAndroid Build Coastguard Worker this->deleteOps();
778*c8dee2aaSAndroid Build Coastguard Worker fDeferredProxies.clear();
779*c8dee2aaSAndroid Build Coastguard Worker fSampledProxies.clear();
780*c8dee2aaSAndroid Build Coastguard Worker
781*c8dee2aaSAndroid Build Coastguard Worker // If the opsTask is using a render target which wraps a vulkan command buffer, we can't do
782*c8dee2aaSAndroid Build Coastguard Worker // a clear load since we cannot change the render pass that we are using. Thus we fall back
783*c8dee2aaSAndroid Build Coastguard Worker // to making a clear op in this case.
784*c8dee2aaSAndroid Build Coastguard Worker return !this->target(0)->asRenderTargetProxy()->wrapsVkSecondaryCB();
785*c8dee2aaSAndroid Build Coastguard Worker }
786*c8dee2aaSAndroid Build Coastguard Worker
787*c8dee2aaSAndroid Build Coastguard Worker // Could not empty the task, so an op must be added to handle the clear
788*c8dee2aaSAndroid Build Coastguard Worker return false;
789*c8dee2aaSAndroid Build Coastguard Worker }
790*c8dee2aaSAndroid Build Coastguard Worker
discard()791*c8dee2aaSAndroid Build Coastguard Worker void OpsTask::discard() {
792*c8dee2aaSAndroid Build Coastguard Worker // Discard calls to in-progress opsTasks are ignored. Calls at the start update the
793*c8dee2aaSAndroid Build Coastguard Worker // opsTasks' color & stencil load ops.
794*c8dee2aaSAndroid Build Coastguard Worker if (this->isEmpty()) {
795*c8dee2aaSAndroid Build Coastguard Worker fColorLoadOp = GrLoadOp::kDiscard;
796*c8dee2aaSAndroid Build Coastguard Worker fInitialStencilContent = StencilContent::kDontCare;
797*c8dee2aaSAndroid Build Coastguard Worker fTotalBounds.setEmpty();
798*c8dee2aaSAndroid Build Coastguard Worker }
799*c8dee2aaSAndroid Build Coastguard Worker }
800*c8dee2aaSAndroid Build Coastguard Worker
801*c8dee2aaSAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////////
802*c8dee2aaSAndroid Build Coastguard Worker
803*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
dump(const SkString & label,SkString indent,bool printDependencies,bool close) const804*c8dee2aaSAndroid Build Coastguard Worker void OpsTask::dump(const SkString& label,
805*c8dee2aaSAndroid Build Coastguard Worker SkString indent,
806*c8dee2aaSAndroid Build Coastguard Worker bool printDependencies,
807*c8dee2aaSAndroid Build Coastguard Worker bool close) const {
808*c8dee2aaSAndroid Build Coastguard Worker GrRenderTask::dump(label, indent, printDependencies, false);
809*c8dee2aaSAndroid Build Coastguard Worker
810*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("%sfColorLoadOp: ", indent.c_str());
811*c8dee2aaSAndroid Build Coastguard Worker switch (fColorLoadOp) {
812*c8dee2aaSAndroid Build Coastguard Worker case GrLoadOp::kLoad:
813*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("kLoad\n");
814*c8dee2aaSAndroid Build Coastguard Worker break;
815*c8dee2aaSAndroid Build Coastguard Worker case GrLoadOp::kClear:
816*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("kClear {%g, %g, %g, %g}\n",
817*c8dee2aaSAndroid Build Coastguard Worker fLoadClearColor[0],
818*c8dee2aaSAndroid Build Coastguard Worker fLoadClearColor[1],
819*c8dee2aaSAndroid Build Coastguard Worker fLoadClearColor[2],
820*c8dee2aaSAndroid Build Coastguard Worker fLoadClearColor[3]);
821*c8dee2aaSAndroid Build Coastguard Worker break;
822*c8dee2aaSAndroid Build Coastguard Worker case GrLoadOp::kDiscard:
823*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("kDiscard\n");
824*c8dee2aaSAndroid Build Coastguard Worker break;
825*c8dee2aaSAndroid Build Coastguard Worker }
826*c8dee2aaSAndroid Build Coastguard Worker
827*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("%sfInitialStencilContent: ", indent.c_str());
828*c8dee2aaSAndroid Build Coastguard Worker switch (fInitialStencilContent) {
829*c8dee2aaSAndroid Build Coastguard Worker case StencilContent::kDontCare:
830*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("kDontCare\n");
831*c8dee2aaSAndroid Build Coastguard Worker break;
832*c8dee2aaSAndroid Build Coastguard Worker case StencilContent::kUserBitsCleared:
833*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("kUserBitsCleared\n");
834*c8dee2aaSAndroid Build Coastguard Worker break;
835*c8dee2aaSAndroid Build Coastguard Worker case StencilContent::kPreserved:
836*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("kPreserved\n");
837*c8dee2aaSAndroid Build Coastguard Worker break;
838*c8dee2aaSAndroid Build Coastguard Worker }
839*c8dee2aaSAndroid Build Coastguard Worker
840*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("%s%d ops:\n", indent.c_str(), fOpChains.size());
841*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < fOpChains.size(); ++i) {
842*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("%s*******************************\n", indent.c_str());
843*c8dee2aaSAndroid Build Coastguard Worker if (!fOpChains[i].head()) {
844*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("%s%d: <combined forward or failed instantiation>\n", indent.c_str(), i);
845*c8dee2aaSAndroid Build Coastguard Worker } else {
846*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("%s%d: %s\n", indent.c_str(), i, fOpChains[i].head()->name());
847*c8dee2aaSAndroid Build Coastguard Worker SkRect bounds = fOpChains[i].bounds();
848*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("%sClippedBounds: [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n",
849*c8dee2aaSAndroid Build Coastguard Worker indent.c_str(),
850*c8dee2aaSAndroid Build Coastguard Worker bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
851*c8dee2aaSAndroid Build Coastguard Worker for (const auto& op : GrOp::ChainRange<>(fOpChains[i].head())) {
852*c8dee2aaSAndroid Build Coastguard Worker SkString info = SkTabString(op.dumpInfo(), 1);
853*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("%s%s\n", indent.c_str(), info.c_str());
854*c8dee2aaSAndroid Build Coastguard Worker bounds = op.bounds();
855*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("%s\tClippedBounds: [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n",
856*c8dee2aaSAndroid Build Coastguard Worker indent.c_str(),
857*c8dee2aaSAndroid Build Coastguard Worker bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
858*c8dee2aaSAndroid Build Coastguard Worker }
859*c8dee2aaSAndroid Build Coastguard Worker }
860*c8dee2aaSAndroid Build Coastguard Worker }
861*c8dee2aaSAndroid Build Coastguard Worker
862*c8dee2aaSAndroid Build Coastguard Worker if (close) {
863*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("%s--------------------------------------------------------------\n\n",
864*c8dee2aaSAndroid Build Coastguard Worker indent.c_str());
865*c8dee2aaSAndroid Build Coastguard Worker }
866*c8dee2aaSAndroid Build Coastguard Worker }
867*c8dee2aaSAndroid Build Coastguard Worker #endif
868*c8dee2aaSAndroid Build Coastguard Worker
869*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG
visitProxies_debugOnly(const GrVisitProxyFunc & func) const870*c8dee2aaSAndroid Build Coastguard Worker void OpsTask::visitProxies_debugOnly(const GrVisitProxyFunc& func) const {
871*c8dee2aaSAndroid Build Coastguard Worker auto textureFunc = [func](GrSurfaceProxy* tex, skgpu::Mipmapped mipmapped) {
872*c8dee2aaSAndroid Build Coastguard Worker func(tex, mipmapped);
873*c8dee2aaSAndroid Build Coastguard Worker };
874*c8dee2aaSAndroid Build Coastguard Worker
875*c8dee2aaSAndroid Build Coastguard Worker for (const OpChain& chain : fOpChains) {
876*c8dee2aaSAndroid Build Coastguard Worker chain.visitProxies(textureFunc);
877*c8dee2aaSAndroid Build Coastguard Worker }
878*c8dee2aaSAndroid Build Coastguard Worker }
879*c8dee2aaSAndroid Build Coastguard Worker
880*c8dee2aaSAndroid Build Coastguard Worker #endif
881*c8dee2aaSAndroid Build Coastguard Worker
882*c8dee2aaSAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////////
883*c8dee2aaSAndroid Build Coastguard Worker
onMakeSkippable()884*c8dee2aaSAndroid Build Coastguard Worker void OpsTask::onMakeSkippable() {
885*c8dee2aaSAndroid Build Coastguard Worker this->deleteOps();
886*c8dee2aaSAndroid Build Coastguard Worker fDeferredProxies.clear();
887*c8dee2aaSAndroid Build Coastguard Worker fColorLoadOp = GrLoadOp::kLoad;
888*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(this->isColorNoOp());
889*c8dee2aaSAndroid Build Coastguard Worker }
890*c8dee2aaSAndroid Build Coastguard Worker
onIsUsed(GrSurfaceProxy * proxyToCheck) const891*c8dee2aaSAndroid Build Coastguard Worker bool OpsTask::onIsUsed(GrSurfaceProxy* proxyToCheck) const {
892*c8dee2aaSAndroid Build Coastguard Worker bool used = false;
893*c8dee2aaSAndroid Build Coastguard Worker for (GrSurfaceProxy* proxy : fSampledProxies) {
894*c8dee2aaSAndroid Build Coastguard Worker if (proxy == proxyToCheck) {
895*c8dee2aaSAndroid Build Coastguard Worker used = true;
896*c8dee2aaSAndroid Build Coastguard Worker break;
897*c8dee2aaSAndroid Build Coastguard Worker }
898*c8dee2aaSAndroid Build Coastguard Worker }
899*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG
900*c8dee2aaSAndroid Build Coastguard Worker bool usedSlow = false;
901*c8dee2aaSAndroid Build Coastguard Worker auto visit = [proxyToCheck, &usedSlow](GrSurfaceProxy* p, skgpu::Mipmapped) {
902*c8dee2aaSAndroid Build Coastguard Worker if (p == proxyToCheck) {
903*c8dee2aaSAndroid Build Coastguard Worker usedSlow = true;
904*c8dee2aaSAndroid Build Coastguard Worker }
905*c8dee2aaSAndroid Build Coastguard Worker };
906*c8dee2aaSAndroid Build Coastguard Worker this->visitProxies_debugOnly(visit);
907*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(used == usedSlow);
908*c8dee2aaSAndroid Build Coastguard Worker #endif
909*c8dee2aaSAndroid Build Coastguard Worker
910*c8dee2aaSAndroid Build Coastguard Worker return used;
911*c8dee2aaSAndroid Build Coastguard Worker }
912*c8dee2aaSAndroid Build Coastguard Worker
gatherProxyIntervals(GrResourceAllocator * alloc) const913*c8dee2aaSAndroid Build Coastguard Worker void OpsTask::gatherProxyIntervals(GrResourceAllocator* alloc) const {
914*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(this->isClosed());
915*c8dee2aaSAndroid Build Coastguard Worker if (this->isColorNoOp()) {
916*c8dee2aaSAndroid Build Coastguard Worker return;
917*c8dee2aaSAndroid Build Coastguard Worker }
918*c8dee2aaSAndroid Build Coastguard Worker
919*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < fDeferredProxies.size(); ++i) {
920*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!fDeferredProxies[i]->isInstantiated());
921*c8dee2aaSAndroid Build Coastguard Worker // We give all the deferred proxies a write usage at the very start of flushing. This
922*c8dee2aaSAndroid Build Coastguard Worker // locks them out of being reused for the entire flush until they are read - and then
923*c8dee2aaSAndroid Build Coastguard Worker // they can be recycled. This is a bit unfortunate because a flush can proceed in waves
924*c8dee2aaSAndroid Build Coastguard Worker // with sub-flushes. The deferred proxies only need to be pinned from the start of
925*c8dee2aaSAndroid Build Coastguard Worker // the sub-flush in which they appear.
926*c8dee2aaSAndroid Build Coastguard Worker alloc->addInterval(fDeferredProxies[i], 0, 0, GrResourceAllocator::ActualUse::kNo,
927*c8dee2aaSAndroid Build Coastguard Worker GrResourceAllocator::AllowRecycling::kYes);
928*c8dee2aaSAndroid Build Coastguard Worker }
929*c8dee2aaSAndroid Build Coastguard Worker
930*c8dee2aaSAndroid Build Coastguard Worker GrSurfaceProxy* targetSurface = this->target(0);
931*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(targetSurface);
932*c8dee2aaSAndroid Build Coastguard Worker GrRenderTargetProxy* targetProxy = targetSurface->asRenderTargetProxy();
933*c8dee2aaSAndroid Build Coastguard Worker
934*c8dee2aaSAndroid Build Coastguard Worker // Add the interval for all the writes to this OpsTasks's target
935*c8dee2aaSAndroid Build Coastguard Worker if (!fOpChains.empty()) {
936*c8dee2aaSAndroid Build Coastguard Worker unsigned int cur = alloc->curOp();
937*c8dee2aaSAndroid Build Coastguard Worker
938*c8dee2aaSAndroid Build Coastguard Worker alloc->addInterval(targetProxy, cur, cur + fOpChains.size() - 1,
939*c8dee2aaSAndroid Build Coastguard Worker GrResourceAllocator::ActualUse::kYes,
940*c8dee2aaSAndroid Build Coastguard Worker GrResourceAllocator::AllowRecycling::kYes);
941*c8dee2aaSAndroid Build Coastguard Worker } else {
942*c8dee2aaSAndroid Build Coastguard Worker // This can happen if there is a loadOp (e.g., a clear) but no other draws. In this case we
943*c8dee2aaSAndroid Build Coastguard Worker // still need to add an interval for the destination so we create a fake op# for
944*c8dee2aaSAndroid Build Coastguard Worker // the missing clear op.
945*c8dee2aaSAndroid Build Coastguard Worker alloc->addInterval(targetProxy, alloc->curOp(), alloc->curOp(),
946*c8dee2aaSAndroid Build Coastguard Worker GrResourceAllocator::ActualUse::kYes,
947*c8dee2aaSAndroid Build Coastguard Worker GrResourceAllocator::AllowRecycling::kYes);
948*c8dee2aaSAndroid Build Coastguard Worker alloc->incOps();
949*c8dee2aaSAndroid Build Coastguard Worker }
950*c8dee2aaSAndroid Build Coastguard Worker
951*c8dee2aaSAndroid Build Coastguard Worker GrResourceAllocator::AllowRecycling allowRecycling =
952*c8dee2aaSAndroid Build Coastguard Worker targetProxy->wrapsVkSecondaryCB() ? GrResourceAllocator::AllowRecycling::kNo
953*c8dee2aaSAndroid Build Coastguard Worker : GrResourceAllocator::AllowRecycling::kYes;
954*c8dee2aaSAndroid Build Coastguard Worker
955*c8dee2aaSAndroid Build Coastguard Worker auto gather = [alloc, allowRecycling SkDEBUGCODE(, this)](GrSurfaceProxy* p, skgpu::Mipmapped) {
956*c8dee2aaSAndroid Build Coastguard Worker alloc->addInterval(p,
957*c8dee2aaSAndroid Build Coastguard Worker alloc->curOp(),
958*c8dee2aaSAndroid Build Coastguard Worker alloc->curOp(),
959*c8dee2aaSAndroid Build Coastguard Worker GrResourceAllocator::ActualUse::kYes,
960*c8dee2aaSAndroid Build Coastguard Worker allowRecycling
961*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(, this->target(0) == p));
962*c8dee2aaSAndroid Build Coastguard Worker };
963*c8dee2aaSAndroid Build Coastguard Worker // TODO: visitProxies is expensive. Can we do this with fSampledProxies instead?
964*c8dee2aaSAndroid Build Coastguard Worker for (const OpChain& recordedOp : fOpChains) {
965*c8dee2aaSAndroid Build Coastguard Worker recordedOp.visitProxies(gather);
966*c8dee2aaSAndroid Build Coastguard Worker
967*c8dee2aaSAndroid Build Coastguard Worker // Even though the op may have been (re)moved we still need to increment the op count to
968*c8dee2aaSAndroid Build Coastguard Worker // keep all the math consistent.
969*c8dee2aaSAndroid Build Coastguard Worker alloc->incOps();
970*c8dee2aaSAndroid Build Coastguard Worker }
971*c8dee2aaSAndroid Build Coastguard Worker }
972*c8dee2aaSAndroid Build Coastguard Worker
recordOp(GrOp::Owner op,bool usesMSAA,GrProcessorSet::Analysis processorAnalysis,GrAppliedClip * clip,const GrDstProxyView * dstProxyView,const GrCaps & caps)973*c8dee2aaSAndroid Build Coastguard Worker void OpsTask::recordOp(
974*c8dee2aaSAndroid Build Coastguard Worker GrOp::Owner op, bool usesMSAA, GrProcessorSet::Analysis processorAnalysis,
975*c8dee2aaSAndroid Build Coastguard Worker GrAppliedClip* clip, const GrDstProxyView* dstProxyView, const GrCaps& caps) {
976*c8dee2aaSAndroid Build Coastguard Worker GrSurfaceProxy* proxy = this->target(0);
977*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG
978*c8dee2aaSAndroid Build Coastguard Worker op->validate();
979*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(processorAnalysis.requiresDstTexture() == (dstProxyView && dstProxyView->proxy()));
980*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(proxy);
981*c8dee2aaSAndroid Build Coastguard Worker // A closed OpsTask should never receive new/more ops
982*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!this->isClosed());
983*c8dee2aaSAndroid Build Coastguard Worker // Ensure we can support dynamic msaa if the caller is trying to trigger it.
984*c8dee2aaSAndroid Build Coastguard Worker if (proxy->asRenderTargetProxy()->numSamples() == 1 && usesMSAA) {
985*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(caps.supportsDynamicMSAA(proxy->asRenderTargetProxy()));
986*c8dee2aaSAndroid Build Coastguard Worker }
987*c8dee2aaSAndroid Build Coastguard Worker #endif
988*c8dee2aaSAndroid Build Coastguard Worker
989*c8dee2aaSAndroid Build Coastguard Worker if (!op->bounds().isFinite()) {
990*c8dee2aaSAndroid Build Coastguard Worker return;
991*c8dee2aaSAndroid Build Coastguard Worker }
992*c8dee2aaSAndroid Build Coastguard Worker
993*c8dee2aaSAndroid Build Coastguard Worker fUsesMSAASurface |= usesMSAA;
994*c8dee2aaSAndroid Build Coastguard Worker
995*c8dee2aaSAndroid Build Coastguard Worker // Account for this op's bounds before we attempt to combine.
996*c8dee2aaSAndroid Build Coastguard Worker // NOTE: The caller should have already called "op->setClippedBounds()" by now, if applicable.
997*c8dee2aaSAndroid Build Coastguard Worker fTotalBounds.join(op->bounds());
998*c8dee2aaSAndroid Build Coastguard Worker
999*c8dee2aaSAndroid Build Coastguard Worker // Check if there is an op we can combine with by linearly searching back until we either
1000*c8dee2aaSAndroid Build Coastguard Worker // 1) check every op
1001*c8dee2aaSAndroid Build Coastguard Worker // 2) intersect with something
1002*c8dee2aaSAndroid Build Coastguard Worker // 3) find a 'blocker'
1003*c8dee2aaSAndroid Build Coastguard Worker GR_AUDIT_TRAIL_ADD_OP(fAuditTrail, op.get(), proxy->uniqueID());
1004*c8dee2aaSAndroid Build Coastguard Worker GrOP_INFO("opsTask: %d Recording (%s, opID: %u)\n"
1005*c8dee2aaSAndroid Build Coastguard Worker "\tBounds [L: %.2f, T: %.2f R: %.2f B: %.2f]\n",
1006*c8dee2aaSAndroid Build Coastguard Worker this->uniqueID(),
1007*c8dee2aaSAndroid Build Coastguard Worker op->name(),
1008*c8dee2aaSAndroid Build Coastguard Worker op->uniqueID(),
1009*c8dee2aaSAndroid Build Coastguard Worker op->bounds().fLeft, op->bounds().fTop,
1010*c8dee2aaSAndroid Build Coastguard Worker op->bounds().fRight, op->bounds().fBottom);
1011*c8dee2aaSAndroid Build Coastguard Worker GrOP_INFO(SkTabString(op->dumpInfo(), 1).c_str());
1012*c8dee2aaSAndroid Build Coastguard Worker GrOP_INFO("\tOutcome:\n");
1013*c8dee2aaSAndroid Build Coastguard Worker int maxCandidates = std::min(kMaxOpChainDistance, fOpChains.size());
1014*c8dee2aaSAndroid Build Coastguard Worker if (maxCandidates) {
1015*c8dee2aaSAndroid Build Coastguard Worker int i = 0;
1016*c8dee2aaSAndroid Build Coastguard Worker while (true) {
1017*c8dee2aaSAndroid Build Coastguard Worker OpChain& candidate = fOpChains.fromBack(i);
1018*c8dee2aaSAndroid Build Coastguard Worker op = candidate.appendOp(std::move(op), processorAnalysis, dstProxyView, clip, caps,
1019*c8dee2aaSAndroid Build Coastguard Worker fArenas->arenaAlloc(), fAuditTrail);
1020*c8dee2aaSAndroid Build Coastguard Worker if (!op) {
1021*c8dee2aaSAndroid Build Coastguard Worker return;
1022*c8dee2aaSAndroid Build Coastguard Worker }
1023*c8dee2aaSAndroid Build Coastguard Worker // Stop going backwards if we would cause a painter's order violation.
1024*c8dee2aaSAndroid Build Coastguard Worker if (!can_reorder(candidate.bounds(), op->bounds())) {
1025*c8dee2aaSAndroid Build Coastguard Worker GrOP_INFO("\t\tBackward: Intersects with chain (%s, head opID: %u)\n",
1026*c8dee2aaSAndroid Build Coastguard Worker candidate.head()->name(), candidate.head()->uniqueID());
1027*c8dee2aaSAndroid Build Coastguard Worker break;
1028*c8dee2aaSAndroid Build Coastguard Worker }
1029*c8dee2aaSAndroid Build Coastguard Worker if (++i == maxCandidates) {
1030*c8dee2aaSAndroid Build Coastguard Worker GrOP_INFO("\t\tBackward: Reached max lookback or beginning of op array %d\n", i);
1031*c8dee2aaSAndroid Build Coastguard Worker break;
1032*c8dee2aaSAndroid Build Coastguard Worker }
1033*c8dee2aaSAndroid Build Coastguard Worker }
1034*c8dee2aaSAndroid Build Coastguard Worker } else {
1035*c8dee2aaSAndroid Build Coastguard Worker GrOP_INFO("\t\tBackward: FirstOp\n");
1036*c8dee2aaSAndroid Build Coastguard Worker }
1037*c8dee2aaSAndroid Build Coastguard Worker if (clip) {
1038*c8dee2aaSAndroid Build Coastguard Worker clip = fArenas->arenaAlloc()->make<GrAppliedClip>(std::move(*clip));
1039*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(fNumClips++;)
1040*c8dee2aaSAndroid Build Coastguard Worker }
1041*c8dee2aaSAndroid Build Coastguard Worker fOpChains.emplace_back(std::move(op), processorAnalysis, clip, dstProxyView);
1042*c8dee2aaSAndroid Build Coastguard Worker }
1043*c8dee2aaSAndroid Build Coastguard Worker
forwardCombine(const GrCaps & caps)1044*c8dee2aaSAndroid Build Coastguard Worker void OpsTask::forwardCombine(const GrCaps& caps) {
1045*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!this->isClosed());
1046*c8dee2aaSAndroid Build Coastguard Worker GrOP_INFO("opsTask: %d ForwardCombine %d ops:\n", this->uniqueID(), fOpChains.size());
1047*c8dee2aaSAndroid Build Coastguard Worker
1048*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < fOpChains.size() - 1; ++i) {
1049*c8dee2aaSAndroid Build Coastguard Worker OpChain& chain = fOpChains[i];
1050*c8dee2aaSAndroid Build Coastguard Worker int maxCandidateIdx = std::min(i + kMaxOpChainDistance, fOpChains.size() - 1);
1051*c8dee2aaSAndroid Build Coastguard Worker int j = i + 1;
1052*c8dee2aaSAndroid Build Coastguard Worker while (true) {
1053*c8dee2aaSAndroid Build Coastguard Worker OpChain& candidate = fOpChains[j];
1054*c8dee2aaSAndroid Build Coastguard Worker if (candidate.prependChain(&chain, caps, fArenas->arenaAlloc(), fAuditTrail)) {
1055*c8dee2aaSAndroid Build Coastguard Worker break;
1056*c8dee2aaSAndroid Build Coastguard Worker }
1057*c8dee2aaSAndroid Build Coastguard Worker // Stop traversing if we would cause a painter's order violation.
1058*c8dee2aaSAndroid Build Coastguard Worker if (!can_reorder(chain.bounds(), candidate.bounds())) {
1059*c8dee2aaSAndroid Build Coastguard Worker GrOP_INFO(
1060*c8dee2aaSAndroid Build Coastguard Worker "\t\t%d: chain (%s head opID: %u) -> "
1061*c8dee2aaSAndroid Build Coastguard Worker "Intersects with chain (%s, head opID: %u)\n",
1062*c8dee2aaSAndroid Build Coastguard Worker i, chain.head()->name(), chain.head()->uniqueID(), candidate.head()->name(),
1063*c8dee2aaSAndroid Build Coastguard Worker candidate.head()->uniqueID());
1064*c8dee2aaSAndroid Build Coastguard Worker break;
1065*c8dee2aaSAndroid Build Coastguard Worker }
1066*c8dee2aaSAndroid Build Coastguard Worker if (++j > maxCandidateIdx) {
1067*c8dee2aaSAndroid Build Coastguard Worker GrOP_INFO("\t\t%d: chain (%s opID: %u) -> Reached max lookahead or end of array\n",
1068*c8dee2aaSAndroid Build Coastguard Worker i, chain.head()->name(), chain.head()->uniqueID());
1069*c8dee2aaSAndroid Build Coastguard Worker break;
1070*c8dee2aaSAndroid Build Coastguard Worker }
1071*c8dee2aaSAndroid Build Coastguard Worker }
1072*c8dee2aaSAndroid Build Coastguard Worker }
1073*c8dee2aaSAndroid Build Coastguard Worker }
1074*c8dee2aaSAndroid Build Coastguard Worker
onMakeClosed(GrRecordingContext * rContext,SkIRect * targetUpdateBounds)1075*c8dee2aaSAndroid Build Coastguard Worker GrRenderTask::ExpectedOutcome OpsTask::onMakeClosed(GrRecordingContext* rContext,
1076*c8dee2aaSAndroid Build Coastguard Worker SkIRect* targetUpdateBounds) {
1077*c8dee2aaSAndroid Build Coastguard Worker this->forwardCombine(*rContext->priv().caps());
1078*c8dee2aaSAndroid Build Coastguard Worker if (!this->isColorNoOp()) {
1079*c8dee2aaSAndroid Build Coastguard Worker GrSurfaceProxy* proxy = this->target(0);
1080*c8dee2aaSAndroid Build Coastguard Worker // Use the entire backing store bounds since the GPU doesn't clip automatically to the
1081*c8dee2aaSAndroid Build Coastguard Worker // logical dimensions.
1082*c8dee2aaSAndroid Build Coastguard Worker SkRect clippedContentBounds = proxy->backingStoreBoundsRect();
1083*c8dee2aaSAndroid Build Coastguard Worker // TODO: If we can fix up GLPrograms test to always intersect the target proxy bounds
1084*c8dee2aaSAndroid Build Coastguard Worker // then we can simply assert here that the bounds intersect.
1085*c8dee2aaSAndroid Build Coastguard Worker if (clippedContentBounds.intersect(fTotalBounds)) {
1086*c8dee2aaSAndroid Build Coastguard Worker clippedContentBounds.roundOut(&fClippedContentBounds);
1087*c8dee2aaSAndroid Build Coastguard Worker *targetUpdateBounds = GrNativeRect::MakeIRectRelativeTo(
1088*c8dee2aaSAndroid Build Coastguard Worker fTargetOrigin,
1089*c8dee2aaSAndroid Build Coastguard Worker this->target(0)->backingStoreDimensions().height(),
1090*c8dee2aaSAndroid Build Coastguard Worker fClippedContentBounds);
1091*c8dee2aaSAndroid Build Coastguard Worker return ExpectedOutcome::kTargetDirty;
1092*c8dee2aaSAndroid Build Coastguard Worker }
1093*c8dee2aaSAndroid Build Coastguard Worker }
1094*c8dee2aaSAndroid Build Coastguard Worker return ExpectedOutcome::kTargetUnchanged;
1095*c8dee2aaSAndroid Build Coastguard Worker }
1096*c8dee2aaSAndroid Build Coastguard Worker
1097*c8dee2aaSAndroid Build Coastguard Worker } // namespace skgpu::ganesh
1098