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