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
18class GrResourceProvider;
19
20namespace gr_instanced {
21
22class 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 */
35class InstancedRendering : public SkNoncopyable {
36public:
37    virtual ~InstancedRendering() { SkASSERT(State::kRecordingDraws == fState); }
38
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
98protected:
99    class Op : public GrDrawOp {
100    public:
101        SK_DECLARE_INTERNAL_LLIST_INTERFACE(Op);
102
103        ~Op() override;
104        const char* name() const override { return "InstancedRendering::Op"; }
105
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
131        Draw& getSingleDraw() const { SkASSERT(fHeadDraw && !fHeadDraw->fNext); return *fHeadDraw; }
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);
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;
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
177    const OpList& trackedOps() const { return fTrackedOps; }
178    const GrBuffer* vertexBuffer() const { SkASSERT(fVertexBuffer); return fVertexBuffer.get(); }
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
186private:
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