1 /*
2  * Copyright 2016 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 gr_instanced_InstancedRendering_DEFINED
9 #define gr_instanced_InstancedRendering_DEFINED
10 
11 #include "../private/GrInstancedPipelineInfo.h"
12 #include "GrGpu.h"
13 #include "GrMemoryPool.h"
14 #include "SkTInternalLList.h"
15 #include "instanced/InstancedRenderingTypes.h"
16 #include "ops/GrDrawOp.h"
17 
18 class GrResourceProvider;
19 
20 namespace gr_instanced {
21 
22 class InstanceProcessor;
23 
24 /**
25  * This class serves as a centralized clearinghouse for instanced rendering. It accumulates data for
26  * instanced draws into one location, and creates special ops that pull from this data. The
27  * nature of instanced rendering allows these ops to combine well and render efficiently.
28  *
29  * During a flush, this class assembles the accumulated draw data into a single vertex and texel
30  * buffer, and its subclass draws the ops using backend-specific instanced rendering APIs.
31  *
32  * This class is responsible for the CPU side of instanced rendering. Shaders are implemented by
33  * InstanceProcessor.
34  */
35 class InstancedRendering : public SkNoncopyable {
36 public:
~InstancedRendering()37     virtual ~InstancedRendering() { SkASSERT(State::kRecordingDraws == fState); }
38 
gpu()39     GrGpu* gpu() const { return fGpu.get(); }
40 
41     /**
42      * These methods make a new record internally for an instanced draw, and return an op that is
43      * effectively just an index to that record. The returned op is not self-contained, but
44      * rather relies on this class to handle the rendering. The client must call beginFlush() on
45      * this class before attempting to flush ops returned by it. It is invalid to record new
46      * draws between beginFlush() and endFlush().
47      */
48     std::unique_ptr<GrDrawOp> SK_WARN_UNUSED_RESULT recordRect(const SkRect&, const SkMatrix&,
49                                                                GrPaint&&, GrAA,
50                                                                const GrInstancedPipelineInfo&);
51 
52     std::unique_ptr<GrDrawOp> SK_WARN_UNUSED_RESULT recordRect(const SkRect&, const SkMatrix&,
53                                                                GrPaint&&, const SkRect& localRect,
54                                                                GrAA,
55                                                                const GrInstancedPipelineInfo&);
56 
57     std::unique_ptr<GrDrawOp> SK_WARN_UNUSED_RESULT recordRect(const SkRect&, const SkMatrix&,
58                                                                GrPaint&&,
59                                                                const SkMatrix& localMatrix, GrAA,
60                                                                const GrInstancedPipelineInfo&);
61 
62     std::unique_ptr<GrDrawOp> SK_WARN_UNUSED_RESULT recordOval(const SkRect&, const SkMatrix&,
63                                                                GrPaint&&, GrAA,
64                                                                const GrInstancedPipelineInfo&);
65 
66     std::unique_ptr<GrDrawOp> SK_WARN_UNUSED_RESULT recordRRect(const SkRRect&, const SkMatrix&,
67                                                                 GrPaint&&, GrAA,
68                                                                 const GrInstancedPipelineInfo&);
69 
70     std::unique_ptr<GrDrawOp> SK_WARN_UNUSED_RESULT recordDRRect(const SkRRect& outer,
71                                                                  const SkRRect& inner,
72                                                                  const SkMatrix&, GrPaint&&, GrAA,
73                                                                  const GrInstancedPipelineInfo&);
74 
75     /**
76      * Compiles all recorded draws into GPU buffers and allows the client to begin flushing the
77      * ops created by this class.
78      */
79     void beginFlush(GrResourceProvider*);
80 
81     /**
82      * Called once the ops created previously by this class have all been released. Allows the
83      * client to begin recording draws again.
84      */
85     void endFlush();
86 
87     enum class ResetType : bool {
88         kDestroy,
89         kAbandon
90     };
91 
92     /**
93      * Resets all GPU resources, including those that are held long term. They will be lazily
94      * reinitialized if the class begins to be used again.
95      */
96     void resetGpuResources(ResetType);
97 
98 protected:
99     class Op : public GrDrawOp {
100     public:
101         SK_DECLARE_INTERNAL_LLIST_INTERFACE(Op);
102 
103         ~Op() override;
name()104         const char* name() const override { return "InstancedRendering::Op"; }
105 
dumpInfo()106         SkString dumpInfo() const override {
107             SkString string;
108             string.printf(
109                     "AA: %d, ShapeTypes: 0x%02x, IShapeTypes: 0x%02x, Persp %d, "
110                     "NonSquare: %d, PLoad: %0.2f, Tracked: %d, NumDraws: %d, "
111                     "GeomChanges: %d\n",
112                     (unsigned)fInfo.fAAType,
113                     fInfo.fShapeTypes,
114                     fInfo.fInnerShapeTypes,
115                     fInfo.fHasPerspective,
116                     fInfo.fNonSquare,
117                     fPixelLoad,
118                     fIsTracked,
119                     fNumDraws,
120                     fNumChangesInGeometry);
121             string.append(INHERITED::dumpInfo());
122             return string;
123         }
124 
125         struct Draw {
126             Instance     fInstance;
127             IndexRange   fGeometry;
128             Draw*        fNext;
129         };
130 
getSingleDraw()131         Draw& getSingleDraw() const { SkASSERT(fHeadDraw && !fHeadDraw->fNext); return *fHeadDraw; }
getSingleInstance()132         Instance& getSingleInstance() const { return this->getSingleDraw().fInstance; }
133 
134         void appendRRectParams(const SkRRect&);
135         void appendParamsTexel(const SkScalar* vals, int count);
136         void appendParamsTexel(SkScalar x, SkScalar y, SkScalar z, SkScalar w);
137         void appendParamsTexel(SkScalar x, SkScalar y, SkScalar z);
fixedFunctionFlags()138         FixedFunctionFlags fixedFunctionFlags() const override {
139             return GrAATypeIsHW(fInfo.aaType()) ? FixedFunctionFlags::kUsesHWAA
140                                                 : FixedFunctionFlags::kNone;
141         }
142         bool xpRequiresDstTexture(const GrCaps&, const GrAppliedClip*) override;
143 
144         // Registers the op with the InstancedRendering list of tracked ops.
145         void wasRecorded() override;
146 
147     protected:
148         Op(uint32_t classID, GrPaint&&, InstancedRendering*);
149 
150         InstancedRendering* const fInstancedRendering;
151         OpInfo fInfo;
152         SkScalar fPixelLoad;
153         GrProcessorSet fProcessors;
154         SkSTArray<5, ParamsTexel, true> fParams;
155         bool fIsTracked : 1;
156         bool fDrawColorsAreOpaque : 1;
157         bool fDrawColorsAreSame : 1;
158         int fNumDraws;
159         int fNumChangesInGeometry;
160         Draw* fHeadDraw;
161         Draw* fTailDraw;
162 
163     private:
164         bool onCombineIfPossible(GrOp* other, const GrCaps& caps) override;
onPrepare(GrOpFlushState *)165         void onPrepare(GrOpFlushState*) override {}
166         void onExecute(GrOpFlushState*) override;
167 
168         typedef GrDrawOp INHERITED;
169 
170         friend class InstancedRendering;
171     };
172 
173     typedef SkTInternalLList<Op> OpList;
174 
175     InstancedRendering(GrGpu* gpu);
176 
trackedOps()177     const OpList& trackedOps() const { return fTrackedOps; }
vertexBuffer()178     const GrBuffer* vertexBuffer() const { SkASSERT(fVertexBuffer); return fVertexBuffer.get(); }
indexBuffer()179     const GrBuffer* indexBuffer() const { SkASSERT(fIndexBuffer); return fIndexBuffer.get(); }
180 
181     virtual void onBeginFlush(GrResourceProvider*) = 0;
182     virtual void onDraw(const GrPipeline&, const InstanceProcessor&, const Op*) = 0;
183     virtual void onEndFlush() = 0;
184     virtual void onResetGpuResources(ResetType) = 0;
185 
186 private:
187     enum class State : bool {
188         kRecordingDraws,
189         kFlushing
190     };
191 
192     std::unique_ptr<Op> SK_WARN_UNUSED_RESULT recordShape(ShapeType, const SkRect& bounds,
193                                                           const SkMatrix& viewMatrix, GrPaint&&,
194                                                           const SkRect& localRect, GrAA aa,
195                                                           const GrInstancedPipelineInfo&);
196 
197     bool selectAntialiasMode(const SkMatrix& viewMatrix, GrAA aa, const GrInstancedPipelineInfo&,
198                              GrAAType*);
199 
200     virtual std::unique_ptr<Op> makeOp(GrPaint&&) = 0;
201 
202     const sk_sp<GrGpu> fGpu;
203     State fState;
204     GrObjectMemoryPool<Op::Draw> fDrawPool;
205     SkSTArray<1024, ParamsTexel, true> fParams;
206     OpList fTrackedOps;
207     sk_sp<const GrBuffer> fVertexBuffer;
208     sk_sp<const GrBuffer> fIndexBuffer;
209     sk_sp<GrBuffer> fParamsBuffer;
210 };
211 
212 }
213 
214 #endif
215