• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2019 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #ifndef OpsTask_DEFINED
9 #define OpsTask_DEFINED
10 
11 #include "include/core/SkMatrix.h"
12 #include "include/core/SkRefCnt.h"
13 #include "include/core/SkSpan.h"
14 #include "include/core/SkStrokeRec.h"
15 #include "include/core/SkTypes.h"
16 #include "include/gpu/GrRecordingContext.h"
17 #include "include/private/SkTArray.h"
18 #include "include/private/SkTDArray.h"
19 #include "src/core/SkArenaAlloc.h"
20 #include "src/core/SkClipStack.h"
21 #include "src/core/SkStringUtils.h"
22 #include "src/core/SkTLazy.h"
23 #include "src/gpu/GrAppliedClip.h"
24 #include "src/gpu/GrDstProxyView.h"
25 #include "src/gpu/GrGeometryProcessor.h"
26 #include "src/gpu/GrProcessorSet.h"
27 #include "src/gpu/GrRenderTask.h"
28 #include "src/gpu/ops/GrOp.h"
29 
30 class GrAuditTrail;
31 class GrCaps;
32 class GrClearOp;
33 class GrGpuBuffer;
34 class GrRenderTargetProxy;
35 class OpsTaskTestingAccess;
36 
37 namespace skgpu::v1 {
38 
39 class SurfaceDrawContext;
40 
41 class OpsTask : public GrRenderTask {
42 public:
43     // Manage the arenas life time by maintaining are reference to it.
44     OpsTask(GrDrawingManager*, GrSurfaceProxyView, GrAuditTrail*, sk_sp<GrArenas>);
45     ~OpsTask() override;
46 
asOpsTask()47     OpsTask* asOpsTask() override { return this; }
48 
isEmpty()49     bool isEmpty() const { return fOpChains.empty(); }
usesMSAASurface()50     bool usesMSAASurface() const { return fUsesMSAASurface; }
renderPassXferBarriers()51     GrXferBarrierFlags renderPassXferBarriers() const { return fRenderPassXferBarriers; }
52 
53     /**
54      * Empties the draw buffer of any queued up draws.
55      */
56     void endFlush(GrDrawingManager*) override;
57 
58     void onPrePrepare(GrRecordingContext*) override;
59     /**
60      * Together these two functions flush all queued up draws to GrCommandBuffer. The return value
61      * of onExecute() indicates whether any commands were actually issued to the GPU.
62      */
63     void onPrepare(GrOpFlushState* flushState) override;
64     bool onExecute(GrOpFlushState* flushState) override;
65 
addSampledTexture(GrSurfaceProxy * proxy)66     void addSampledTexture(GrSurfaceProxy* proxy) {
67         // This function takes a GrSurfaceProxy because all subsequent uses of the proxy do not
68         // require the specifics of GrTextureProxy, so this avoids a number of unnecessary virtual
69         // asTextureProxy() calls. However, sampling the proxy implicitly requires that the proxy
70         // be a texture. Eventually, when proxies are a unified type with flags, this can just
71         // assert that capability.
72         SkASSERT(proxy->asTextureProxy());
73         fSampledProxies.push_back(proxy);
74     }
75 
76     void addOp(GrDrawingManager*, GrOp::Owner, GrTextureResolveManager, const GrCaps&);
77 
78     void addDrawOp(GrDrawingManager*, GrOp::Owner, bool usesMSAA, const GrProcessorSet::Analysis&,
79                    GrAppliedClip&&, const GrDstProxyView&, GrTextureResolveManager, const GrCaps&);
80 
81     void discard();
82 
83     enum class CanDiscardPreviousOps : bool {
84         kYes = true,
85         kNo = false
86     };
87 
88     // Perform book-keeping for a fullscreen clear, regardless of how the clear is implemented later
89     // (i.e. setColorLoadOp(), adding a ClearOp, or adding a FillRectOp that covers the device).
90     // Returns true if the clear can be converted into a load op (barring device caps).
91     bool resetForFullscreenClear(CanDiscardPreviousOps);
92 
93     // Must only be called if native color buffer clearing is enabled.
94     void setColorLoadOp(GrLoadOp op, std::array<float, 4> color = {0, 0, 0, 0});
95 
96     // Returns whether the given opsTask can be appended at the end of this one.
97     bool canMerge(const OpsTask*) const;
98 
99     // Merge as many opsTasks as possible from the head of 'tasks'. They should all be
100     // renderPass compatible. Return the number of tasks merged into 'this'.
101     int mergeFrom(SkSpan<const sk_sp<GrRenderTask>> tasks);
102 
103 #ifdef SK_DEBUG
numClips()104     int numClips() const override { return fNumClips; }
105     void visitProxies_debugOnly(const GrVisitProxyFunc&) const override;
106 #endif
107 
108 #if GR_TEST_UTILS
109     void dump(const SkString& label,
110               SkString indent,
111               bool printDependencies,
112               bool close) const override;
name()113     const char* name() const final { return "Ops"; }
numOpChains()114     int numOpChains() const { return fOpChains.count(); }
getChain(int index)115     const GrOp* getChain(int index) const { return fOpChains[index].head(); }
116 #endif
117 
118 protected:
119     enum class StencilContent {
120         kDontCare,
121         kUserBitsCleared,  // User bits: cleared
122                            // Clip bit: don't care (Ganesh always pre-clears the clip bit.)
123         kPreserved
124     };
125 
126     // Lets the caller specify what the content of the stencil buffer should be at the beginning
127     // of the render pass.
128     //
129     // When requesting kClear: Tilers will load the stencil buffer with a "clear" op; non-tilers
130     // will clear the stencil on first load, and then preserve it on subsequent loads. (Preserving
131     // works because SurfaceDrawContexts are required to leave the user bits in a cleared state
132     // once finished.)
133     //
134     // NOTE: initialContent must not be kClear if caps.performStencilClearsAsDraws() is true.
setInitialStencilContent(StencilContent initialContent)135     void setInitialStencilContent(StencilContent initialContent) {
136         fInitialStencilContent = initialContent;
137     }
138 
139     void recordOp(GrOp::Owner, bool usesMSAA, GrProcessorSet::Analysis, GrAppliedClip*,
140                   const GrDstProxyView*, const GrCaps&);
141 
142     ExpectedOutcome onMakeClosed(GrRecordingContext*, SkIRect* targetUpdateBounds) override;
143 
144 private:
isColorNoOp()145     bool isColorNoOp() const {
146         // TODO: GrLoadOp::kDiscard (i.e., storing a discard) should also be grounds for skipping
147         // execution. We currently don't because of Vulkan. See http://skbug.com/9373.
148         return fOpChains.empty() && GrLoadOp::kLoad == fColorLoadOp;
149     }
150 
151     void deleteOps();
152 
153     // If a surfaceDrawContext splits its opsTask, it uses this method to guarantee stencil values
154     // get preserved across its split tasks.
setMustPreserveStencil()155     void setMustPreserveStencil() { fMustPreserveStencil = true; }
156 
157     // Prevents this opsTask from merging backward. This is used by DMSAA when a non-multisampled
158     // opsTask cannot be promoted to MSAA, or when we split a multisampled opsTask in order to
159     // resolve its texture.
setCannotMergeBackward()160     void setCannotMergeBackward() { fCannotMergeBackward = true; }
161 
162     class OpChain {
163     public:
164         OpChain(GrOp::Owner, GrProcessorSet::Analysis, GrAppliedClip*, const GrDstProxyView*);
~OpChain()165         ~OpChain() {
166             // The ops are stored in a GrMemoryPool and must be explicitly deleted via the pool.
167             SkASSERT(fList.empty());
168         }
169 
170         OpChain(const OpChain&) = delete;
171         OpChain& operator=(const OpChain&) = delete;
172         OpChain(OpChain&&) = default;
173         OpChain& operator=(OpChain&&) = default;
174 
175         void visitProxies(const GrVisitProxyFunc&) const;
176 
head()177         GrOp* head() const { return fList.head(); }
178 
appliedClip()179         GrAppliedClip* appliedClip() const { return fAppliedClip; }
dstProxyView()180         const GrDstProxyView& dstProxyView() const { return fDstProxyView; }
bounds()181         const SkRect& bounds() const { return fBounds; }
182 
183         // Deletes all the ops in the chain.
184         void deleteOps();
185 
186         // Attempts to move the ops from the passed chain to this chain at the head. Also attempts
187         // to merge ops between the chains. Upon success the passed chain is empty.
188         // Fails when the chains aren't of the same op type, have different clips or dst proxies.
189         bool prependChain(OpChain*, const GrCaps&, SkArenaAlloc* opsTaskArena, GrAuditTrail*);
190 
191         // Attempts to add 'op' to this chain either by merging or adding to the tail. Returns
192         // 'op' to the caller upon failure, otherwise null. Fails when the op and chain aren't of
193         // the same op type, have different clips or dst proxies.
194         GrOp::Owner appendOp(GrOp::Owner op, GrProcessorSet::Analysis, const GrDstProxyView*,
195                              const GrAppliedClip*, const GrCaps&, SkArenaAlloc* opsTaskArena,
196                              GrAuditTrail*);
197 
shouldExecute()198         bool shouldExecute() const {
199             return SkToBool(this->head());
200         }
201 
202     private:
203         class List {
204         public:
205             List() = default;
206             List(GrOp::Owner);
207             List(List&&);
208             List& operator=(List&& that);
209 
empty()210             bool empty() const { return !SkToBool(fHead); }
head()211             GrOp* head() const { return fHead.get(); }
tail()212             GrOp* tail() const { return fTail; }
213 
214             GrOp::Owner popHead();
215             GrOp::Owner removeOp(GrOp* op);
216             void pushHead(GrOp::Owner op);
217             void pushTail(GrOp::Owner);
218 
219             void validate() const;
220 
221         private:
222             GrOp::Owner fHead{nullptr};
223             GrOp* fTail{nullptr};
224         };
225 
226         void validate() const;
227 
228         bool tryConcat(List*, GrProcessorSet::Analysis, const GrDstProxyView&, const GrAppliedClip*,
229                        const SkRect& bounds, const GrCaps&, SkArenaAlloc* opsTaskArena,
230                        GrAuditTrail*);
231         static List DoConcat(List, List, const GrCaps&, SkArenaAlloc* opsTaskArena, GrAuditTrail*);
232 
233         List fList;
234         GrProcessorSet::Analysis fProcessorAnalysis;
235         GrDstProxyView fDstProxyView;
236         GrAppliedClip* fAppliedClip;
237         SkRect fBounds;
238     };
239 
240     void onMakeSkippable() override;
241 
242     bool onIsUsed(GrSurfaceProxy*) const override;
243 
244     void gatherProxyIntervals(GrResourceAllocator*) const override;
245 
246     void forwardCombine(const GrCaps&);
247 
248     // Remove all ops, proxies, etc. Used in the merging algorithm when tasks can be skipped.
249     void reset();
250 
251     friend class ::OpsTaskTestingAccess;
252 
253     // The SDC and OpsTask have to work together to handle buffer clears. In most cases, buffer
254     // clearing can be done natively, in which case the op list's load ops are sufficient. In other
255     // cases, draw ops must be used, which makes the SDC the best place for those decisions. This,
256     // however, requires that the SDC be able to coordinate with the op list to achieve similar ends
257     friend class skgpu::v1::SurfaceDrawContext;
258 
259     GrAuditTrail* fAuditTrail;
260 
261     bool fUsesMSAASurface;
262     GrSwizzle fTargetSwizzle;
263     GrSurfaceOrigin fTargetOrigin;
264 
265     GrLoadOp fColorLoadOp = GrLoadOp::kLoad;
266     std::array<float, 4> fLoadClearColor = {0, 0, 0, 0};
267     StencilContent fInitialStencilContent = StencilContent::kDontCare;
268     bool fMustPreserveStencil = false;
269     bool fCannotMergeBackward = false;
270 
271     uint32_t fLastClipStackGenID = SK_InvalidUniqueID;
272     SkIRect fLastDevClipBounds;
273     int fLastClipNumAnalyticElements;
274 
275     GrXferBarrierFlags fRenderPassXferBarriers = GrXferBarrierFlags::kNone;
276 
277     // For ops/opsTask we have mean: 5 stdDev: 28
278     SkSTArray<25, OpChain> fOpChains;
279 
280     sk_sp<GrArenas> fArenas;
281     SkDEBUGCODE(int fNumClips;)
282 
283     // TODO: We could look into this being a set if we find we're adding a lot of duplicates that is
284     // causing slow downs.
285     SkTArray<GrSurfaceProxy*, true> fSampledProxies;
286 
287     SkRect fTotalBounds = SkRect::MakeEmpty();
288     SkIRect fClippedContentBounds = SkIRect::MakeEmpty();
289 };
290 
291 } // namespace skgpu::v1
292 
293 #endif // OpsTask_DEFINED
294