1 /*
2  * Copyright 2010 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 GrRenderTargetOpList_DEFINED
9 #define GrRenderTargetOpList_DEFINED
10 
11 #include "GrAppliedClip.h"
12 #include "GrOpList.h"
13 #include "GrPathRendering.h"
14 #include "GrPrimitiveProcessor.h"
15 #include "ops/GrOp.h"
16 #include "ops/GrDrawOp.h"
17 #include "SkArenaAlloc.h"
18 #include "SkClipStack.h"
19 #include "SkMatrix.h"
20 #include "SkStringUtils.h"
21 #include "SkStrokeRec.h"
22 #include "SkTArray.h"
23 #include "SkTLazy.h"
24 #include "SkTypes.h"
25 
26 class GrAuditTrail;
27 class GrClearOp;
28 class GrCaps;
29 class GrRenderTargetProxy;
30 
31 class GrRenderTargetOpList final : public GrOpList {
32 private:
33     using DstProxy = GrXferProcessor::DstProxy;
34 
35 public:
36     GrRenderTargetOpList(GrResourceProvider*, sk_sp<GrOpMemoryPool>,
37                          GrRenderTargetProxy*, GrAuditTrail*);
38 
39     ~GrRenderTargetOpList() override;
40 
makeClosed(const GrCaps & caps)41     void makeClosed(const GrCaps& caps) override {
42         if (this->isClosed()) {
43             return;
44         }
45 
46         this->forwardCombine(caps);
47 
48         INHERITED::makeClosed(caps);
49     }
50 
isEmpty()51     bool isEmpty() const { return fOpChains.empty(); }
52 
53     /**
54      * Empties the draw buffer of any queued up draws.
55      */
56     void endFlush() override;
57 
58     /**
59      * Together these two functions flush all queued up draws to GrCommandBuffer. The return value
60      * of executeOps() indicates whether any commands were actually issued to the GPU.
61      */
62     void onPrepare(GrOpFlushState* flushState) override;
63     bool onExecute(GrOpFlushState* flushState) override;
64 
addOp(std::unique_ptr<GrOp> op,const GrCaps & caps)65     void addOp(std::unique_ptr<GrOp> op, const GrCaps& caps) {
66         auto addDependency = [ &caps, this ] (GrSurfaceProxy* p) {
67             this->addDependency(p, caps);
68         };
69 
70         op->visitProxies(addDependency);
71 
72         this->recordOp(std::move(op), GrProcessorSet::EmptySetAnalysis(), nullptr, nullptr, caps);
73     }
74 
addWaitOp(std::unique_ptr<GrOp> op,const GrCaps & caps)75     void addWaitOp(std::unique_ptr<GrOp> op, const GrCaps& caps) {
76         fHasWaitOp= true;
77         this->addOp(std::move(op), caps);
78     }
79 
addDrawOp(std::unique_ptr<GrDrawOp> op,const GrProcessorSet::Analysis & processorAnalysis,GrAppliedClip && clip,const DstProxy & dstProxy,const GrCaps & caps)80     void addDrawOp(std::unique_ptr<GrDrawOp> op, const GrProcessorSet::Analysis& processorAnalysis,
81                    GrAppliedClip&& clip, const DstProxy& dstProxy, const GrCaps& caps) {
82         auto addDependency = [ &caps, this ] (GrSurfaceProxy* p) {
83             this->addDependency(p, caps);
84         };
85 
86         op->visitProxies(addDependency);
87         clip.visitProxies(addDependency);
88         if (dstProxy.proxy()) {
89             addDependency(dstProxy.proxy());
90         }
91 
92         this->recordOp(std::move(op), processorAnalysis, clip.doesClip() ? &clip : nullptr,
93                        &dstProxy, caps);
94     }
95 
96     void discard();
97 
98     /**
99      * Copies a pixel rectangle from one surface to another. This call may finalize
100      * reserved vertex/index data (as though a draw call was made). The src pixels
101      * copied are specified by srcRect. They are copied to a rect of the same
102      * size in dst with top left at dstPoint. If the src rect is clipped by the
103      * src bounds then  pixel values in the dst rect corresponding to area clipped
104      * by the src rect are not overwritten. This method is not guaranteed to succeed
105      * depending on the type of surface, configs, etc, and the backend-specific
106      * limitations.
107      */
108     bool copySurface(GrRecordingContext*,
109                      GrSurfaceProxy* dst,
110                      GrSurfaceProxy* src,
111                      const SkIRect& srcRect,
112                      const SkIPoint& dstPoint) override;
113 
asRenderTargetOpList()114     GrRenderTargetOpList* asRenderTargetOpList() override { return this; }
115 
116     SkDEBUGCODE(void dump(bool printDependencies) const override;)
117     SkDEBUGCODE(int numClips() const override { return fNumClips; })
118     SkDEBUGCODE(void visitProxies_debugOnly(const GrOp::VisitProxyFunc&) const;)
119 
120 private:
121     friend class GrRenderTargetContextPriv; // for stencil clip state. TODO: this is invasive
122 
123     // The RTC and RTOpList have to work together to handle buffer clears. In most cases, buffer
124     // clearing can be done natively, in which case the op list's load ops are sufficient. In other
125     // cases, draw ops must be used, which makes the RTC the best place for those decisions. This,
126     // however, requires that the RTC be able to coordinate with the op list to achieve similar ends
127     friend class GrRenderTargetContext;
128 
129     // Must only be called if native stencil buffer clearing is enabled
130     void setStencilLoadOp(GrLoadOp op);
131     // Must only be called if native color buffer clearing is enabled.
132     void setColorLoadOp(GrLoadOp op, const SkPMColor4f& color);
133     // Sets the clear color to transparent black
setColorLoadOp(GrLoadOp op)134     void setColorLoadOp(GrLoadOp op) {
135         static const SkPMColor4f kDefaultClearColor = {0.f, 0.f, 0.f, 0.f};
136         this->setColorLoadOp(op, kDefaultClearColor);
137     }
138 
139     // Perform book-keeping for a fullscreen clear, regardless of how the clear is implemented later
140     // (i.e. setColorLoadOp(), adding a ClearOp, or adding a GrFillRectOp that covers the device).
141     // Returns true if the clear can be converted into a load op (barring device caps).
142     bool resetForFullscreenClear();
143 
144     void deleteOps();
145 
146     class OpChain {
147     public:
148         OpChain(const OpChain&) = delete;
149         OpChain& operator=(const OpChain&) = delete;
150         OpChain(std::unique_ptr<GrOp>, GrProcessorSet::Analysis, GrAppliedClip*, const DstProxy*);
151 
~OpChain()152         ~OpChain() {
153             // The ops are stored in a GrMemoryPool and must be explicitly deleted via the pool.
154             SkASSERT(fList.empty());
155         }
156 
157         void visitProxies(const GrOp::VisitProxyFunc&, GrOp::VisitorType) const;
158 
head()159         GrOp* head() const { return fList.head(); }
160 
appliedClip()161         GrAppliedClip* appliedClip() const { return fAppliedClip; }
dstProxy()162         const DstProxy& dstProxy() const { return fDstProxy; }
bounds()163         const SkRect& bounds() const { return fBounds; }
164 
165         // Deletes all the ops in the chain via the pool.
166         void deleteOps(GrOpMemoryPool* pool);
167 
168         // Attempts to move the ops from the passed chain to this chain at the head. Also attempts
169         // to merge ops between the chains. Upon success the passed chain is empty.
170         // Fails when the chains aren't of the same op type, have different clips or dst proxies.
171         bool prependChain(OpChain*, const GrCaps&, GrOpMemoryPool*, GrAuditTrail*);
172 
173         // Attempts to add 'op' to this chain either by merging or adding to the tail. Returns
174         // 'op' to the caller upon failure, otherwise null. Fails when the op and chain aren't of
175         // the same op type, have different clips or dst proxies.
176         std::unique_ptr<GrOp> appendOp(std::unique_ptr<GrOp> op, GrProcessorSet::Analysis,
177                                        const DstProxy*, const GrAppliedClip*, const GrCaps&,
178                                        GrOpMemoryPool*, GrAuditTrail*);
179 
180     private:
181         class List {
182         public:
183             List() = default;
184             List(std::unique_ptr<GrOp>);
185             List(List&&);
186             List& operator=(List&& that);
187 
empty()188             bool empty() const { return !SkToBool(fHead); }
head()189             GrOp* head() const { return fHead.get(); }
tail()190             GrOp* tail() const { return fTail; }
191 
192             std::unique_ptr<GrOp> popHead();
193             std::unique_ptr<GrOp> removeOp(GrOp* op);
194             void pushHead(std::unique_ptr<GrOp> op);
195             void pushTail(std::unique_ptr<GrOp>);
196 
197             void validate() const;
198 
199         private:
200             std::unique_ptr<GrOp> fHead;
201             GrOp* fTail = nullptr;
202         };
203 
204         void validate() const;
205 
206         bool tryConcat(List*, GrProcessorSet::Analysis, const DstProxy&, const GrAppliedClip*,
207                        const SkRect& bounds, const GrCaps&, GrOpMemoryPool*, GrAuditTrail*);
208         static List DoConcat(List, List, const GrCaps&, GrOpMemoryPool*, GrAuditTrail*);
209 
210         List fList;
211         GrProcessorSet::Analysis fProcessorAnalysis;
212         DstProxy fDstProxy;
213         GrAppliedClip* fAppliedClip;
214         SkRect fBounds;
215     };
216 
217     void purgeOpsWithUninstantiatedProxies() override;
218 
219     void gatherProxyIntervals(GrResourceAllocator*) const override;
220 
221     void recordOp(std::unique_ptr<GrOp>, GrProcessorSet::Analysis, GrAppliedClip*, const DstProxy*,
222                   const GrCaps& caps);
223 
224     void forwardCombine(const GrCaps&);
225 
226     uint32_t                       fLastClipStackGenID;
227     SkIRect                        fLastDevClipBounds;
228     int                            fLastClipNumAnalyticFPs;
229 
230     // We must track if we have a wait op so that we don't delete the op when we have a full clear.
231     bool fHasWaitOp = false;;
232 
233     // For ops/opList we have mean: 5 stdDev: 28
234     SkSTArray<25, OpChain, true> fOpChains;
235 
236     // MDB TODO: 4096 for the first allocation of the clip space will be huge overkill.
237     // Gather statistics to determine the correct size.
238     SkArenaAlloc                   fClipAllocator{4096};
239     SkDEBUGCODE(int                fNumClips;)
240 
241     typedef GrOpList INHERITED;
242 };
243 
244 #endif
245