1 /*
2  * Copyright 2019 Google LLC
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 GrRenderTask_DEFINED
9 #define GrRenderTask_DEFINED
10 
11 #include "include/core/SkRefCnt.h"
12 #include "include/private/SkColorData.h"
13 #include "include/private/SkTDArray.h"
14 #include "src/gpu/GrSurfaceProxyView.h"
15 #include "src/gpu/GrTextureProxy.h"
16 #include "src/gpu/GrTextureResolveManager.h"
17 #include "src/gpu/ops/GrOp.h"
18 
19 class GrOpFlushState;
20 class GrOpsTask;
21 class GrResourceAllocator;
22 class GrTextureResolveRenderTask;
23 
24 // This class abstracts a task that targets a single GrSurfaceProxy, participates in the
25 // GrDrawingManager's DAG, and implements the onExecute method to modify its target proxy's
26 // contents. (e.g., an opsTask that executes a command buffer, a task to regenerate mipmaps, etc.)
27 class GrRenderTask : public SkRefCnt {
28 public:
29     GrRenderTask();
30     SkDEBUGCODE(~GrRenderTask() override);
31 
32     void makeClosed(const GrCaps&);
33 
prePrepare(GrRecordingContext * context)34     void prePrepare(GrRecordingContext* context) { this->onPrePrepare(context); }
35 
36     // These two methods are only invoked at flush time
37     void prepare(GrOpFlushState* flushState);
execute(GrOpFlushState * flushState)38     bool execute(GrOpFlushState* flushState) { return this->onExecute(flushState); }
39 
40     // Called when this class will survive a flush and needs to truncate its ops and start over.
41     // TODO: ultimately it should be invalid for an op list to survive a flush.
42     // https://bugs.chromium.org/p/skia/issues/detail?id=7111
endFlush(GrDrawingManager *)43     virtual void endFlush(GrDrawingManager*) {}
44 
45     // This method "disowns" all the GrSurfaceProxies this RenderTask modifies. In
46     // practice this just means telling the drawingManager to forget the relevant
47     // mappings from surface proxy to last modifying rendertask.
48     virtual void disown(GrDrawingManager*);
49 
isClosed()50     bool isClosed() const { return this->isSetFlag(kClosed_Flag); }
51 
52     /*
53      * Notify this GrRenderTask that it relies on the contents of 'dependedOn'
54      */
55     void addDependency(GrDrawingManager*, GrSurfaceProxy* dependedOn, GrMipmapped,
56                        GrTextureResolveManager, const GrCaps& caps);
57 
58     /*
59      * Notify this GrRenderTask that it relies on the contents of all GrRenderTasks which otherTask
60      * depends on.
61      */
62     void addDependenciesFromOtherTask(GrRenderTask* otherTask);
63 
64     /*
65      * Does this renderTask depend on 'dependedOn'?
66      */
67     bool dependsOn(const GrRenderTask* dependedOn) const;
68 
uniqueID()69     uint32_t uniqueID() const { return fUniqueID; }
numTargets()70     int numTargets() const { return fTargets.count(); }
target(int i)71     const GrSurfaceProxyView& target(int i) const { return fTargets[i]; }
72 
73     /*
74      * Safely cast this GrRenderTask to a GrOpsTask (if possible).
75      */
asOpsTask()76     virtual GrOpsTask* asOpsTask() { return nullptr; }
77 
78 #if GR_TEST_UTILS
79     /*
80      * Dump out the GrRenderTask dependency DAG
81      */
82     virtual void dump(bool printDependencies) const;
83     virtual const char* name() const = 0;
84 #endif
85 
86 #ifdef SK_DEBUG
numClips()87     virtual int numClips() const { return 0; }
88 
89     virtual void visitProxies_debugOnly(const GrOp::VisitProxyFunc&) const = 0;
90 
visitTargetAndSrcProxies_debugOnly(const GrOp::VisitProxyFunc & fn)91     void visitTargetAndSrcProxies_debugOnly(const GrOp::VisitProxyFunc& fn) const {
92         this->visitProxies_debugOnly(fn);
93         for (int i = 0; i < this->numTargets(); ++i) {
94             fn(this->target(i).proxy(), GrMipmapped::kNo);
95         }
96     }
97 #endif
98 
99 protected:
100     // In addition to just the GrSurface being allocated, has the stencil buffer been allocated (if
101     // it is required)?
102     bool isInstantiated() const;
103 
104     SkDEBUGCODE(bool deferredProxiesAreInstantiated() const;)
105 
106     // Add a target surface proxy to the list of targets for this task.
107     // This also informs the drawing manager to update the lastRenderTask association.
108     void addTarget(GrDrawingManager*, GrSurfaceProxyView);
109 
110     enum class ExpectedOutcome : bool {
111         kTargetUnchanged,
112         kTargetDirty,
113     };
114 
115     // Performs any work to finalize this renderTask prior to execution. If returning
116     // ExpectedOutcome::kTargetDiry, the caller is also responsible to fill out the area it will
117     // modify in targetUpdateBounds.
118     //
119     // targetUpdateBounds must not extend beyond the proxy bounds.
120     virtual ExpectedOutcome onMakeClosed(const GrCaps&, SkIRect* targetUpdateBounds) = 0;
121 
122     SkSTArray<1, GrSurfaceProxyView> fTargets;
123 
124     // List of texture proxies whose contents are being prepared on a worker thread
125     // TODO: this list exists so we can fire off the proper upload when an renderTask begins
126     // executing. Can this be replaced?
127     SkTArray<GrTextureProxy*, true> fDeferredProxies;
128 
129 private:
130     // for resetFlag, TopoSortTraits, gatherProxyIntervals, handleInternalAllocationFailure
131     friend class GrDrawingManager;
132 
133     // Drops any pending operations that reference proxies that are not instantiated.
134     // NOTE: Derived classes don't need to check targets. That is handled when the
135     // drawingManager calls isInstantiated.
136     virtual void handleInternalAllocationFailure() = 0;
137 
138     // Derived classes can override to indicate usage of proxies _other than target proxies_.
139     // GrRenderTask itself will handle checking the target proxies.
140     virtual bool onIsUsed(GrSurfaceProxy*) const = 0;
141 
isUsed(GrSurfaceProxy * proxy)142     bool isUsed(GrSurfaceProxy* proxy) const {
143         for (const GrSurfaceProxyView& target : fTargets) {
144             if (target.proxy() == proxy) {
145                 return true;
146             }
147         }
148 
149         return this->onIsUsed(proxy);
150     }
151 
152     void addDependency(GrRenderTask* dependedOn);
153     void addDependent(GrRenderTask* dependent);
154     SkDEBUGCODE(bool isDependedent(const GrRenderTask* dependent) const;)
155     SkDEBUGCODE(void validate() const;)
156     void closeThoseWhoDependOnMe(const GrCaps&);
157 
158     // Feed proxy usage intervals to the GrResourceAllocator class
159     virtual void gatherProxyIntervals(GrResourceAllocator*) const = 0;
160 
161     static uint32_t CreateUniqueID();
162 
163     enum Flags {
164         kClosed_Flag    = 0x01,   //!< This task can't accept any more dependencies.
165         kDisowned_Flag  = 0x02,   //!< This task is disowned by its creating GrDrawingManager.
166 
167         kWasOutput_Flag = 0x04,   //!< Flag for topological sorting
168         kTempMark_Flag  = 0x08,   //!< Flag for topological sorting
169     };
170 
setFlag(uint32_t flag)171     void setFlag(uint32_t flag) {
172         fFlags |= flag;
173     }
174 
resetFlag(uint32_t flag)175     void resetFlag(uint32_t flag) {
176         fFlags &= ~flag;
177     }
178 
isSetFlag(uint32_t flag)179     bool isSetFlag(uint32_t flag) const {
180         return SkToBool(fFlags & flag);
181     }
182 
183     struct TopoSortTraits {
OutputTopoSortTraits184         static void Output(GrRenderTask* renderTask, int /* index */) {
185             renderTask->setFlag(kWasOutput_Flag);
186         }
WasOutputTopoSortTraits187         static bool WasOutput(const GrRenderTask* renderTask) {
188             return renderTask->isSetFlag(kWasOutput_Flag);
189         }
SetTempMarkTopoSortTraits190         static void SetTempMark(GrRenderTask* renderTask) {
191             renderTask->setFlag(kTempMark_Flag);
192         }
ResetTempMarkTopoSortTraits193         static void ResetTempMark(GrRenderTask* renderTask) {
194             renderTask->resetFlag(kTempMark_Flag);
195         }
IsTempMarkedTopoSortTraits196         static bool IsTempMarked(const GrRenderTask* renderTask) {
197             return renderTask->isSetFlag(kTempMark_Flag);
198         }
NumDependenciesTopoSortTraits199         static int NumDependencies(const GrRenderTask* renderTask) {
200             return renderTask->fDependencies.count();
201         }
DependencyTopoSortTraits202         static GrRenderTask* Dependency(GrRenderTask* renderTask, int index) {
203             return renderTask->fDependencies[index];
204         }
205     };
206 
207     // Only the GrOpsTask currently overrides this virtual
onPrePrepare(GrRecordingContext *)208     virtual void onPrePrepare(GrRecordingContext*) {}
onPrepare(GrOpFlushState *)209     virtual void onPrepare(GrOpFlushState*) {} // Only the GrOpsTask overrides this virtual
210     virtual bool onExecute(GrOpFlushState* flushState) = 0;
211 
212     const uint32_t         fUniqueID;
213     uint32_t               fFlags;
214 
215     // 'this' GrRenderTask relies on the output of the GrRenderTasks in 'fDependencies'
216     SkSTArray<1, GrRenderTask*, true> fDependencies;
217     // 'this' GrRenderTask's output is relied on by the GrRenderTasks in 'fDependents'
218     SkSTArray<1, GrRenderTask*, true> fDependents;
219 
220     // For performance reasons, we should perform texture resolves back-to-back as much as possible.
221     // (http://skbug.com/9406). To accomplish this, we make and reuse one single resolve task for
222     // each render task, then add it as a dependency during makeClosed().
223     GrTextureResolveRenderTask* fTextureResolveTask = nullptr;
224 
225     SkDEBUGCODE(GrDrawingManager *fDrawingMgr = nullptr;)
226 };
227 
228 #endif
229