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