1 /*
2  * Copyright 2015 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 GrMeshDrawOp_DEFINED
9 #define GrMeshDrawOp_DEFINED
10 
11 #include "GrDrawOp.h"
12 #include "GrGeometryProcessor.h"
13 #include "GrMesh.h"
14 #include "GrPendingProgramElement.h"
15 
16 #include "SkTLList.h"
17 
18 class GrCaps;
19 class GrOpFlushState;
20 
21 /**
22  * Base class for mesh-drawing GrDrawOps.
23  */
24 class GrMeshDrawOp : public GrDrawOp {
25 public:
26     class Target;
27 
28     /**
29      * Performs analysis of the fragment processors in GrProcessorSet and GrAppliedClip using the
30      * initial color and coverage from this op's geometry processor.
31      */
analyzeProcessors(GrProcessorSet::FragmentProcessorAnalysis * analysis,const GrProcessorSet & processors,const GrAppliedClip * appliedClip,const GrCaps & caps)32     void analyzeProcessors(GrProcessorSet::FragmentProcessorAnalysis* analysis,
33                            const GrProcessorSet& processors,
34                            const GrAppliedClip* appliedClip,
35                            const GrCaps& caps) const {
36         GrPipelineAnalysisColor inputColor;
37         GrPipelineAnalysisCoverage inputCoverage;
38         this->getFragmentProcessorAnalysisInputs(&inputColor, &inputCoverage);
39         analysis->init(inputColor, inputCoverage, processors, appliedClip, caps);
40     }
41 
initPipeline(const GrPipeline::InitArgs & args)42     void initPipeline(const GrPipeline::InitArgs& args) {
43         this->applyPipelineOptimizations(fPipeline.init(args));
44     }
45 
46     /**
47      * Mesh draw ops use a legacy system in GrRenderTargetContext where the pipeline is created when
48      * the op is recorded. These methods are unnecessary as this information is in the pipeline.
49      */
fixedFunctionFlags()50     FixedFunctionFlags fixedFunctionFlags() const override {
51         SkFAIL("This should never be called for mesh draw ops.");
52         return FixedFunctionFlags::kNone;
53     }
xpRequiresDstTexture(const GrCaps &,const GrAppliedClip *)54     bool xpRequiresDstTexture(const GrCaps&, const GrAppliedClip*) override {
55         SkFAIL("Should never be called for mesh draw ops.");
56         return false;
57     }
58 
59 protected:
60     GrMeshDrawOp(uint32_t classID);
61 
62     /** Helper for rendering instances using an instanced index index buffer. This class creates the
63         space for the vertices and flushes the draws to the GrMeshDrawOp::Target. */
64     class InstancedHelper {
65     public:
InstancedHelper()66         InstancedHelper() {}
67         /** Returns the allocated storage for the vertices. The caller should populate the vertices
68             before calling recordDraws(). */
69         void* init(Target*, GrPrimitiveType, size_t vertexStride, const GrBuffer*,
70                    int verticesPerInstance, int indicesPerInstance, int instancesToDraw);
71 
72         /** Call after init() to issue draws to the GrMeshDrawOp::Target.*/
73         void recordDraw(Target*, const GrGeometryProcessor*);
74 
75     private:
76         GrMesh fMesh;
77     };
78 
79     static const int kVerticesPerQuad = 4;
80     static const int kIndicesPerQuad = 6;
81 
82     /** A specialization of InstanceHelper for quad rendering. */
83     class QuadHelper : private InstancedHelper {
84     public:
QuadHelper()85         QuadHelper() : INHERITED() {}
86         /** Finds the cached quad index buffer and reserves vertex space. Returns nullptr on failure
87             and on success a pointer to the vertex data that the caller should populate before
88             calling recordDraws(). */
89         void* init(Target*, size_t vertexStride, int quadsToDraw);
90 
91         using InstancedHelper::recordDraw;
92 
93     private:
94         typedef InstancedHelper INHERITED;
95     };
96 
pipeline()97     const GrPipeline* pipeline() const {
98         SkASSERT(fPipeline.isInitialized());
99         return &fPipeline;
100     }
101 
102 private:
103     /**
104      * Provides information about the GrPrimitiveProccesor color and coverage outputs which become
105      * inputs to the first color and coverage fragment processors.
106      */
107     virtual void getFragmentProcessorAnalysisInputs(GrPipelineAnalysisColor*,
108                                                     GrPipelineAnalysisCoverage*) const = 0;
109 
110     /**
111      * After GrPipeline analysis is complete this is called so that the op can use the analysis
112      * results when constructing its GrPrimitiveProcessor.
113      */
114     virtual void applyPipelineOptimizations(const GrPipelineOptimizations&) = 0;
115 
116     void onPrepare(GrOpFlushState* state) final;
117     void onExecute(GrOpFlushState* state) final;
118 
119     virtual void onPrepareDraws(Target*) const = 0;
120 
121     // A set of contiguous draws that share a draw token and primitive processor. The draws all use
122     // the op's pipeline. The meshes for the draw are stored in the fMeshes array and each
123     // Queued draw uses fMeshCnt meshes from the fMeshes array. The reason for coallescing meshes
124     // that share a primitive processor into a QueuedDraw is that it allows the Gpu object to setup
125     // the shared state once and then issue draws for each mesh.
126     struct QueuedDraw {
127         int fMeshCnt = 0;
128         GrPendingProgramElement<const GrGeometryProcessor> fGeometryProcessor;
129     };
130 
131     // All draws in all the GrMeshDrawOps have implicit tokens based on the order they are enqueued
132     // globally across all ops. This is the offset of the first entry in fQueuedDraws.
133     // fQueuedDraws[i]'s token is fBaseDrawToken + i.
134     GrDrawOpUploadToken fBaseDrawToken;
135     GrPipeline fPipeline;
136     SkSTArray<4, GrMesh> fMeshes;
137     SkSTArray<4, QueuedDraw, true> fQueuedDraws;
138 
139     typedef GrDrawOp INHERITED;
140 };
141 
142 #endif
143