xref: /aosp_15_r20/external/skia/src/gpu/ganesh/ops/OpsTask.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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