blob: d88f3e632aaaedd1882cb6501810fc0070c612da [file] [log] [blame]
joshualittb0a8a372014-09-23 09:50:21 -07001/*
2 * Copyright 2013 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 GrGeometryProcessor_DEFINED
9#define GrGeometryProcessor_DEFINED
10
joshualitt2e3b3e32014-12-09 13:31:14 -080011#include "GrColor.h"
joshualittc07379d2014-11-20 14:50:39 -080012#include "GrGeometryData.h"
joshualittb0a8a372014-09-23 09:50:21 -070013#include "GrProcessor.h"
bsalomon6251d172014-10-15 10:50:36 -070014#include "GrShaderVar.h"
joshualittb0a8a372014-09-23 09:50:21 -070015
joshualitt87f48d92014-12-04 10:41:40 -080016/*
joshualitt9b989322014-12-15 14:16:27 -080017 * The GrPrimitiveProcessor represents some kind of geometric primitive. This includes the shape
18 * of the primitive and the inherent color of the primitive. The GrPrimitiveProcessor is
19 * responsible for providing a color and coverage input into the Ganesh rendering pipeline. Through
20 * optimization, Ganesh may decide a different color, no color, and / or no coverage are required
21 * from the GrPrimitiveProcessor, so the GrPrimitiveProcessor must be able to support this
22 * functionality. We also use the GrPrimitiveProcessor to make batching decisions.
23 *
24 * There are two feedback loops between the GrFragmentProcessors, the GrXferProcessor, and the
25 * GrPrimitiveProcessor. These loops run on the CPU and compute any invariant components which
26 * might be useful for correctness / optimization decisions. The GrPrimitiveProcessor seeds these
27 * loops, one with initial color and one with initial coverage, in its
28 * onComputeInvariantColor / Coverage calls. These seed values are processed by the subsequent
29 * stages of the rendering pipeline and the output is then fed back into the GrPrimitiveProcessor in
30 * the initBatchTracker call, where the GrPrimitiveProcessor can then initialize the GrBatchTracker
31 * struct with the appropriate values.
32 *
33 * We are evolving this system to move towards generating geometric meshes and their associated
34 * vertex data after we have batched and reordered draws. This system, known as 'deferred geometry'
35 * will allow the GrPrimitiveProcessor much greater control over how data is transmitted to shaders.
36 *
37 * In a deferred geometry world, the GrPrimitiveProcessor can always 'batch' To do this, each
38 * primitive type is associated with one GrPrimitiveProcessor, who has complete control of how
39 * it draws. Each primitive draw will bundle all required data to perform the draw, and these
40 * bundles of data will be owned by an instance of the associated GrPrimitiveProcessor. Bundles
41 * can be updated alongside the GrBatchTracker struct itself, ultimately allowing the
42 * GrPrimitiveProcessor complete control of how it gets data into the fragment shader as long as
43 * it emits the appropriate color, or none at all, as directed.
44 */
45
46/*
joshualitt87f48d92014-12-04 10:41:40 -080047 * A struct for tracking batching decisions. While this lives on GrOptState, it is managed
48 * entirely by the derived classes of the GP.
49 */
50class GrBatchTracker {
51public:
52 template <typename T> const T& cast() const {
53 SkASSERT(sizeof(T) <= kMaxSize);
joshualitt9b989322014-12-15 14:16:27 -080054 return *reinterpret_cast<const T*>(fData.get());
joshualitt87f48d92014-12-04 10:41:40 -080055 }
56
57 template <typename T> T* cast() {
58 SkASSERT(sizeof(T) <= kMaxSize);
joshualitt9b989322014-12-15 14:16:27 -080059 return reinterpret_cast<T*>(fData.get());
joshualitt87f48d92014-12-04 10:41:40 -080060 }
61
62 static const size_t kMaxSize = 32;
63
64private:
joshualitt9b989322014-12-15 14:16:27 -080065 SkAlignedSStorage<kMaxSize> fData;
joshualitt87f48d92014-12-04 10:41:40 -080066};
67
joshualitteb2a6762014-12-04 11:35:33 -080068class GrGLCaps;
69class GrGLGeometryProcessor;
joshualitt87f48d92014-12-04 10:41:40 -080070class GrOptDrawState;
71
joshualitt56995b52014-12-11 15:44:02 -080072struct GrInitInvariantOutput;
73
joshualitt9b989322014-12-15 14:16:27 -080074
joshualitt56995b52014-12-11 15:44:02 -080075/*
joshualitt9b989322014-12-15 14:16:27 -080076 * This enum is shared by GrPrimitiveProcessors and GrGLPrimitiveProcessors to coordinate shaders
77 * with vertex attributes / uniforms.
78 */
79enum GrGPInput {
80 kAllOnes_GrGPInput,
81 kAttribute_GrGPInput,
82 kUniform_GrGPInput,
83 kIgnored_GrGPInput,
84};
85
86/*
87 * GrPrimitiveProcessor defines an interface which all subclasses must implement. All
88 * GrPrimitiveProcessors must proivide seed color and coverage for the Ganesh color / coverage
89 * pipelines, and they must provide some notion of equality
joshualitt56995b52014-12-11 15:44:02 -080090 */
91class GrPrimitiveProcessor : public GrProcessor {
92public:
joshualitt290c09b2014-12-19 13:45:20 -080093 // TODO let the PrimProc itself set this in its setData call, this should really live on the
94 // bundle of primitive data
joshualitt8059eb92014-12-29 15:10:07 -080095 const SkMatrix& viewMatrix() const { return fViewMatrix; }
joshualitt290c09b2014-12-19 13:45:20 -080096 const SkMatrix& localMatrix() const { return fLocalMatrix; }
97
joshualitt9b989322014-12-15 14:16:27 -080098 /*
99 * This struct allows the optstate to communicate requirements to the GrPrimitiveProcessor.
100 */
101 struct InitBT {
102 bool fColorIgnored;
103 bool fCoverageIgnored;
104 GrColor fOverrideColor;
joshualitt290c09b2014-12-19 13:45:20 -0800105 bool fUsesLocalCoords;
joshualitt9b989322014-12-15 14:16:27 -0800106 };
107
108 virtual void initBatchTracker(GrBatchTracker*, const InitBT&) const = 0;
109
110 virtual bool canMakeEqual(const GrBatchTracker& mine,
111 const GrPrimitiveProcessor& that,
112 const GrBatchTracker& theirs) const = 0;
113
114 /*
115 * We always call canMakeEqual before makeEqual so there is no need to do any kind of equality
116 * testing here
117 * TODO make this pure virtual when primProcs can actually use it
118 */
119 virtual void makeEqual(GrBatchTracker*, const GrBatchTracker&) const {}
120
joshualitt56995b52014-12-11 15:44:02 -0800121 virtual void getInvariantOutputColor(GrInitInvariantOutput* out) const = 0;
122 virtual void getInvariantOutputCoverage(GrInitInvariantOutput* out) const = 0;
123
egdanielc2304142014-12-11 13:15:13 -0800124 /**
125 * Sets a unique key on the GrProcessorKeyBuilder that is directly associated with this geometry
126 * processor's GL backend implementation.
127 */
joshualitteb2a6762014-12-04 11:35:33 -0800128 virtual void getGLProcessorKey(const GrBatchTracker& bt,
129 const GrGLCaps& caps,
130 GrProcessorKeyBuilder* b) const = 0;
131
132
133 /** Returns a new instance of the appropriate *GL* implementation class
134 for the given GrProcessor; caller is responsible for deleting
135 the object. */
136 virtual GrGLGeometryProcessor* createGLInstance(const GrBatchTracker& bt) const = 0;
joshualittb0a8a372014-09-23 09:50:21 -0700137
joshualitt9b989322014-12-15 14:16:27 -0800138protected:
joshualitt8059eb92014-12-29 15:10:07 -0800139 GrPrimitiveProcessor(const SkMatrix& viewMatrix, const SkMatrix& localMatrix)
140 : fViewMatrix(viewMatrix)
141 , fLocalMatrix(localMatrix) {}
joshualitt290c09b2014-12-19 13:45:20 -0800142
joshualitt9b989322014-12-15 14:16:27 -0800143 /*
144 * CanCombineOutput will return true if two draws are 'batchable' from a color perspective.
145 * TODO remove this when GPs can upgrade to attribute color
146 */
147 static bool CanCombineOutput(GrGPInput left, GrColor lColor, GrGPInput right, GrColor rColor) {
148 if (left != right) {
149 return false;
150 }
151
152 if (kUniform_GrGPInput == left && lColor != rColor) {
153 return false;
154 }
155
156 return true;
157 }
158
joshualitt290c09b2014-12-19 13:45:20 -0800159 static bool CanCombineLocalMatrices(const GrPrimitiveProcessor& left,
160 bool leftUsesLocalCoords,
161 const GrPrimitiveProcessor& right,
162 bool rightUsesLocalCoords) {
163 if (leftUsesLocalCoords != rightUsesLocalCoords) {
164 return false;
165 }
166
167 if (leftUsesLocalCoords && !left.localMatrix().cheapEqualTo(right.localMatrix())) {
168 return false;
169 }
170 return true;
171 }
172
joshualitt9b989322014-12-15 14:16:27 -0800173private:
joshualitt8059eb92014-12-29 15:10:07 -0800174 SkMatrix fViewMatrix;
joshualitt290c09b2014-12-19 13:45:20 -0800175 SkMatrix fLocalMatrix;
176
joshualitt9b989322014-12-15 14:16:27 -0800177 typedef GrProcessor INHERITED;
178};
179
180/**
181 * A GrGeometryProcessor is a flexible method for rendering a primitive. The GrGeometryProcessor
182 * has complete control over vertex attributes and uniforms(aside from the render target) but it
183 * must obey the same contract as any GrPrimitiveProcessor, specifically it must emit a color and
184 * coverage into the fragment shader. Where this color and coverage come from is completely the
185 * responsibility of the GrGeometryProcessor.
186 */
187class GrGeometryProcessor : public GrPrimitiveProcessor {
188public:
189 // TODO the Hint can be handled in a much more clean way when we have deferred geometry or
190 // atleast bundles
joshualitt290c09b2014-12-19 13:45:20 -0800191 GrGeometryProcessor(GrColor color,
joshualitt8059eb92014-12-29 15:10:07 -0800192 const SkMatrix& viewMatrix = SkMatrix::I(),
193 const SkMatrix& localMatrix = SkMatrix::I(),
194 bool opaqueVertexColors = false)
195 : INHERITED(viewMatrix, localMatrix)
joshualitt290c09b2014-12-19 13:45:20 -0800196 , fVertexStride(0)
joshualitt9b989322014-12-15 14:16:27 -0800197 , fColor(color)
198 , fOpaqueVertexColors(opaqueVertexColors)
199 , fWillUseGeoShader(false)
200 , fHasVertexColor(false)
201 , fHasLocalCoords(false) {}
202
joshualittb0a8a372014-09-23 09:50:21 -0700203 /*
joshualitt2dd1ae02014-12-03 06:24:10 -0800204 * This is a safeguard to prevent GPs from going beyond platform specific attribute limits.
205 * This number can almost certainly be raised if required.
joshualittb0a8a372014-09-23 09:50:21 -0700206 */
joshualitt2dd1ae02014-12-03 06:24:10 -0800207 static const int kMaxVertexAttribs = 6;
joshualittb0a8a372014-09-23 09:50:21 -0700208
joshualitt2dd1ae02014-12-03 06:24:10 -0800209 struct GrAttribute {
210 GrAttribute(const char* name, GrVertexAttribType type)
211 : fName(name)
212 , fType(type)
213 , fOffset(SkAlign4(GrVertexAttribTypeSize(type))) {}
214 const char* fName;
215 GrVertexAttribType fType;
216 size_t fOffset;
217 };
218
219 typedef SkTArray<GrAttribute, true> VertexAttribArray;
220
221 const VertexAttribArray& getAttribs() const { return fAttribs; }
222
223 // Returns the vertex stride of the GP. A common use case is to request geometry from a
224 // drawtarget based off of the stride, and to populate this memory using an implicit array of
225 // structs. In this case, it is best to assert the vertexstride == sizeof(VertexStruct).
226 size_t getVertexStride() const { return fVertexStride; }
joshualittb0a8a372014-09-23 09:50:21 -0700227
joshualitt74077b92014-10-24 11:26:03 -0700228 bool willUseGeoShader() const { return fWillUseGeoShader; }
229
joshualitt9b989322014-12-15 14:16:27 -0800230 /*
231 * In an ideal world, two GrGeometryProcessors with the same class id and texture accesses
232 * would ALWAYS be able to batch together. If two GrGeometryProcesosrs are the same then we
233 * will only keep one of them. The remaining GrGeometryProcessor then updates its
234 * GrBatchTracker to incorporate the draw information from the GrGeometryProcessor we discard.
235 * Any bundles associated with the discarded GrGeometryProcessor will be attached to the
236 * remaining GrGeometryProcessor.
237 */
238 bool canMakeEqual(const GrBatchTracker& mine,
239 const GrPrimitiveProcessor& that,
240 const GrBatchTracker& theirs) const SK_OVERRIDE {
joshualitteb2a6762014-12-04 11:35:33 -0800241 if (this->classID() != that.classID() || !this->hasSameTextureAccesses(that)) {
bsalomon0e08fc12014-10-15 08:19:04 -0700242 return false;
243 }
joshualitt2e3b3e32014-12-09 13:31:14 -0800244
joshualitt8059eb92014-12-29 15:10:07 -0800245 // TODO let the GPs decide this
246 if (!this->viewMatrix().cheapEqualTo(that.viewMatrix())) {
247 return false;
248 }
249
joshualitt56995b52014-12-11 15:44:02 -0800250 // TODO remove the hint
joshualitt9b989322014-12-15 14:16:27 -0800251 const GrGeometryProcessor& other = that.cast<GrGeometryProcessor>();
252 if (fHasVertexColor && fOpaqueVertexColors != other.fOpaqueVertexColors) {
joshualitt2e3b3e32014-12-09 13:31:14 -0800253 return false;
254 }
255
joshualitt9b989322014-12-15 14:16:27 -0800256 // TODO this equality test should really be broken up, some of this can live on the batch
257 // tracker test and some of this should be in bundles
258 if (!this->onIsEqual(other)) {
joshualitt56995b52014-12-11 15:44:02 -0800259 return false;
260 }
261
joshualitt290c09b2014-12-19 13:45:20 -0800262 return this->onCanMakeEqual(mine, other, theirs);
bsalomon0e08fc12014-10-15 08:19:04 -0700263 }
264
joshualitt9b989322014-12-15 14:16:27 -0800265
266 // TODO we can remove color from the GrGeometryProcessor base class once we have bundles of
267 // primitive data
joshualitt56995b52014-12-11 15:44:02 -0800268 GrColor color() const { return fColor; }
joshualitt2e3b3e32014-12-09 13:31:14 -0800269
joshualitt9b989322014-12-15 14:16:27 -0800270 // TODO this is a total hack until the gp can do deferred geometry
joshualitt2dd1ae02014-12-03 06:24:10 -0800271 bool hasVertexColor() const { return fHasVertexColor; }
joshualitt9b989322014-12-15 14:16:27 -0800272
273 // TODO this is a total hack until gp can setup and manage local coords
joshualitt2dd1ae02014-12-03 06:24:10 -0800274 bool hasLocalCoords() const { return fHasLocalCoords; }
275
joshualitt56995b52014-12-11 15:44:02 -0800276 void getInvariantOutputColor(GrInitInvariantOutput* out) const SK_OVERRIDE;
277 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRIDE;
joshualitt2e3b3e32014-12-09 13:31:14 -0800278
joshualittb0a8a372014-09-23 09:50:21 -0700279protected:
joshualitt9b989322014-12-15 14:16:27 -0800280 /*
281 * An optional simple helper function to determine by what means the GrGeometryProcessor should
282 * use to provide color. If we are given an override color(ie the given overridecolor is NOT
283 * GrColor_ILLEGAL) then we must always emit that color(currently overrides are only supported
284 * via uniform, but with deferred Geometry we could use attributes). Otherwise, if our color is
285 * ignored then we should not emit a color. Lastly, if we don't have vertex colors then we must
286 * emit a color via uniform
287 * TODO this function changes quite a bit with deferred geometry. There the GrGeometryProcessor
288 * can upload a new color via attribute if needed.
289 */
290 static GrGPInput GetColorInputType(GrColor* color, GrColor primitiveColor, const InitBT& init,
291 bool hasVertexColor) {
292 if (init.fColorIgnored) {
293 *color = GrColor_ILLEGAL;
294 return kIgnored_GrGPInput;
295 } else if (GrColor_ILLEGAL != init.fOverrideColor) {
296 *color = init.fOverrideColor;
297 return kUniform_GrGPInput;
298 }
299
300 *color = primitiveColor;
301 if (hasVertexColor) {
302 return kAttribute_GrGPInput;
303 } else {
304 return kUniform_GrGPInput;
305 }
306 }
307
joshualittb0a8a372014-09-23 09:50:21 -0700308 /**
joshualitt2dd1ae02014-12-03 06:24:10 -0800309 * Subclasses call this from their constructor to register vertex attributes. Attributes
310 * will be padded to the nearest 4 bytes for performance reasons.
311 * TODO After deferred geometry, we should do all of this inline in GenerateGeometry alongside
joshualitt9b989322014-12-15 14:16:27 -0800312 * the struct used to actually populate the attributes. This is all extremely fragile, vertex
313 * attributes have to be added in the order they will appear in the struct which maps memory.
314 * The processor key should reflect the vertex attributes, or there lack thereof in the
315 * GrGeometryProcessor.
joshualittb0a8a372014-09-23 09:50:21 -0700316 */
joshualitt2dd1ae02014-12-03 06:24:10 -0800317 const GrAttribute& addVertexAttrib(const GrAttribute& attribute) {
318 fVertexStride += attribute.fOffset;
319 return fAttribs.push_back(attribute);
joshualittb0a8a372014-09-23 09:50:21 -0700320 }
321
joshualitt74077b92014-10-24 11:26:03 -0700322 void setWillUseGeoShader() { fWillUseGeoShader = true; }
323
joshualitt2dd1ae02014-12-03 06:24:10 -0800324 // TODO hack see above
325 void setHasVertexColor() { fHasVertexColor = true; }
joshualitt2dd1ae02014-12-03 06:24:10 -0800326 void setHasLocalCoords() { fHasLocalCoords = true; }
327
joshualitt56995b52014-12-11 15:44:02 -0800328 virtual void onGetInvariantOutputColor(GrInitInvariantOutput*) const {}
329 virtual void onGetInvariantOutputCoverage(GrInitInvariantOutput*) const = 0;
330
joshualittb0a8a372014-09-23 09:50:21 -0700331private:
joshualitt290c09b2014-12-19 13:45:20 -0800332 virtual bool onCanMakeEqual(const GrBatchTracker& mine,
333 const GrGeometryProcessor& that,
334 const GrBatchTracker& theirs) const = 0;
joshualitt9b989322014-12-15 14:16:27 -0800335 // TODO delete this when we have more advanced equality testing via bundles and the BT
bsalomon0e08fc12014-10-15 08:19:04 -0700336 virtual bool onIsEqual(const GrGeometryProcessor&) const = 0;
337
joshualitt2dd1ae02014-12-03 06:24:10 -0800338 SkSTArray<kMaxVertexAttribs, GrAttribute, true> fAttribs;
339 size_t fVertexStride;
joshualitt2e3b3e32014-12-09 13:31:14 -0800340 GrColor fColor;
joshualitt56995b52014-12-11 15:44:02 -0800341 bool fOpaqueVertexColors;
joshualitt74077b92014-10-24 11:26:03 -0700342 bool fWillUseGeoShader;
joshualitt2dd1ae02014-12-03 06:24:10 -0800343 bool fHasVertexColor;
joshualitt2dd1ae02014-12-03 06:24:10 -0800344 bool fHasLocalCoords;
joshualittb0a8a372014-09-23 09:50:21 -0700345
joshualitt290c09b2014-12-19 13:45:20 -0800346 typedef GrPrimitiveProcessor INHERITED;
joshualittb0a8a372014-09-23 09:50:21 -0700347};
joshualitt56995b52014-12-11 15:44:02 -0800348
349/*
350 * The path equivalent of the GP. For now this just manages color. In the long term we plan on
351 * extending this class to handle all nvpr uniform / varying / program work.
352 */
353class GrPathProcessor : public GrPrimitiveProcessor {
354public:
joshualitt8059eb92014-12-29 15:10:07 -0800355 static GrPathProcessor* Create(GrColor color,
356 const SkMatrix& viewMatrix = SkMatrix::I(),
357 const SkMatrix& localMatrix = SkMatrix::I()) {
358 return SkNEW_ARGS(GrPathProcessor, (color, viewMatrix, localMatrix));
joshualitt56995b52014-12-11 15:44:02 -0800359 }
joshualitt9b989322014-12-15 14:16:27 -0800360
361 void initBatchTracker(GrBatchTracker*, const InitBT&) const SK_OVERRIDE;
362
363 bool canMakeEqual(const GrBatchTracker& mine,
364 const GrPrimitiveProcessor& that,
365 const GrBatchTracker& theirs) const SK_OVERRIDE;
joshualitt56995b52014-12-11 15:44:02 -0800366
367 const char* name() const SK_OVERRIDE { return "PathProcessor"; }
joshualitt9b989322014-12-15 14:16:27 -0800368
369 GrColor color() const { return fColor; }
370
joshualitt56995b52014-12-11 15:44:02 -0800371 void getInvariantOutputColor(GrInitInvariantOutput* out) const SK_OVERRIDE;
372 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRIDE;
373
joshualitt9b989322014-12-15 14:16:27 -0800374 virtual void getGLProcessorKey(const GrBatchTracker& bt,
375 const GrGLCaps& caps,
376 GrProcessorKeyBuilder* b) const SK_OVERRIDE;
377
378 virtual GrGLGeometryProcessor* createGLInstance(const GrBatchTracker& bt) const SK_OVERRIDE;
379
joshualitt56995b52014-12-11 15:44:02 -0800380private:
joshualitt8059eb92014-12-29 15:10:07 -0800381 GrPathProcessor(GrColor color, const SkMatrix& viewMatrix, const SkMatrix& localMatrix);
joshualitt56995b52014-12-11 15:44:02 -0800382 GrColor fColor;
383
joshualitt290c09b2014-12-19 13:45:20 -0800384 typedef GrPrimitiveProcessor INHERITED;
joshualitt56995b52014-12-11 15:44:02 -0800385};
joshualittb0a8a372014-09-23 09:50:21 -0700386#endif