OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2013 Google Inc. | 2 * Copyright 2013 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #ifndef GrGeometryProcessor_DEFINED | 8 #ifndef GrGeometryProcessor_DEFINED |
9 #define GrGeometryProcessor_DEFINED | 9 #define GrGeometryProcessor_DEFINED |
10 | 10 |
11 #include "GrColor.h" | 11 #include "GrColor.h" |
12 #include "GrGeometryData.h" | 12 #include "GrGeometryData.h" |
13 #include "GrProcessor.h" | 13 #include "GrProcessor.h" |
14 #include "GrShaderVar.h" | 14 #include "GrShaderVar.h" |
15 | 15 |
16 /* | 16 /* |
17 * The GrPrimitiveProcessor represents some kind of geometric primitive. This i ncludes the shape | |
bsalomon
2014/12/15 15:31:13
This comment is great!
Two minor suggestions:
ma
| |
18 * of the primitive and the inherent color of the primitive. The GrPrimitivePro cessor is | |
19 * responsible for providing a color and coverage input into the Ganesh renderin g pipeline. Through | |
20 * optimization, Ganesh may decide a different color, no color, and / or no cove rage are required | |
21 * from the GrPrimitiveProcessor, so the GrPrimitiveProcessor must be able to su pport this | |
22 * functionality. We also use the GrPrimitiveProcessor to make batching decisio ns. | |
23 * | |
24 * There are two feedback loops between the GrFragmentProcessors, the GrXferProc essor, and the | |
25 * GrPrimitiveProcessor. The GrPrimitiveProcessor seeds these loops, one with i nitial color and one | |
26 * with initial coverage, in its onComputeInvariantColor / Coverage calls. Thes e seed values are | |
27 * processed by the subsequent stages of the rendering pipeline and the output i s then fed back | |
28 * into the GrPrimitiveProcessor in the initBatchTracker call, where the GrPrimi tiveProcessor can | |
29 * then initialize the GrBatchTracker struct with the appropriate values. | |
30 * | |
31 * In a deferred geometry world, the GrPrimitiveProcessor can always 'batch' To do this, each | |
32 * primitive type is associated with one GrPrimitiveProcessor, who has complete control of how | |
33 * it draws. Each primitive draw will bundle all required data to perform the d raw, and these | |
34 * bundles of data will be owned by an instance of the associated GrPrimitivePro cessor. Bundles | |
35 * can be updated alongside the GrBatchTracker struct itself, ultimately allowin g the | |
36 * GrPrimitiveProcessor complete control of how it gets data into the fragment s hader as long as | |
37 * it emits the appropriate color, or none at all, as directed. | |
38 */ | |
39 | |
40 /* | |
17 * A struct for tracking batching decisions. While this lives on GrOptState, it is managed | 41 * A struct for tracking batching decisions. While this lives on GrOptState, it is managed |
18 * entirely by the derived classes of the GP. | 42 * entirely by the derived classes of the GP. |
19 */ | 43 */ |
20 class GrBatchTracker { | 44 class GrBatchTracker { |
21 public: | 45 public: |
22 template <typename T> const T& cast() const { | 46 template <typename T> const T& cast() const { |
23 SkASSERT(sizeof(T) <= kMaxSize); | 47 SkASSERT(sizeof(T) <= kMaxSize); |
24 return *reinterpret_cast<const T*>(fData); | 48 return *reinterpret_cast<const T*>(fData.get()); |
25 } | 49 } |
26 | 50 |
27 template <typename T> T* cast() { | 51 template <typename T> T* cast() { |
28 SkASSERT(sizeof(T) <= kMaxSize); | 52 SkASSERT(sizeof(T) <= kMaxSize); |
29 return reinterpret_cast<T*>(fData); | 53 return reinterpret_cast<T*>(fData.get()); |
30 } | 54 } |
31 | 55 |
32 static const size_t kMaxSize = 32; | 56 static const size_t kMaxSize = 32; |
33 | 57 |
34 private: | 58 private: |
35 uint8_t fData[kMaxSize]; | 59 mutable SkAlignedSStorage<kMaxSize> fData; |
bsalomon
2014/12/15 15:31:13
still unclear to me why this is mutable and the th
| |
36 }; | 60 }; |
37 | 61 |
38 class GrGLCaps; | 62 class GrGLCaps; |
39 class GrGLGeometryProcessor; | 63 class GrGLGeometryProcessor; |
40 class GrOptDrawState; | 64 class GrOptDrawState; |
41 | 65 |
42 struct GrInitInvariantOutput; | 66 struct GrInitInvariantOutput; |
43 | 67 |
44 /* | 68 /* |
45 * GrGeometryProcessors and GrPathProcessors may effect invariantColor | 69 * GrPrimitiveProcessor defines an interface which all subclasses must implement . All |
70 * GrPrimitiveProcessors must proivide seed color and coverage for the Ganesh co lor / coverage | |
71 * pipelines, and they must provide some notion of equality | |
46 */ | 72 */ |
47 class GrPrimitiveProcessor : public GrProcessor { | 73 class GrPrimitiveProcessor : public GrProcessor { |
48 public: | 74 public: |
49 // TODO GPs and PPs have to provide an initial coverage because the coverage invariant code is | 75 virtual bool canMakeEqual(const GrBatchTracker& mine, |
50 // broken right now | 76 const GrPrimitiveProcessor& that, |
51 virtual uint8_t coverage() const = 0; | 77 const GrBatchTracker& theirs) const = 0; |
78 | |
79 /* | |
80 * We always call canMakeEqual before makeEqual so there is no need to do an y kind of equality | |
81 * testing here | |
82 * TODO make this pure virtual when primProcs can actually use it | |
83 */ | |
84 virtual void makeEqual(GrBatchTracker*, const GrBatchTracker&) const {} | |
85 | |
52 virtual void getInvariantOutputColor(GrInitInvariantOutput* out) const = 0; | 86 virtual void getInvariantOutputColor(GrInitInvariantOutput* out) const = 0; |
53 virtual void getInvariantOutputCoverage(GrInitInvariantOutput* out) const = 0; | 87 virtual void getInvariantOutputCoverage(GrInitInvariantOutput* out) const = 0; |
54 | 88 |
55 private: | 89 private: |
56 typedef GrProcessor INHERITED; | 90 typedef GrProcessor INHERITED; |
57 }; | 91 }; |
58 | 92 |
93 /* | |
94 * This enum is shared by GrPrimitiveProcessors and GrGLPrimitiveProcessors to c oordinate shaders | |
95 * with vertex attributes / uniforms. | |
96 */ | |
97 enum GrGPInput { | |
98 kAllOnes_GrGPInput, | |
99 kAttribute_GrGPInput, | |
100 kUniform_GrGPInput, | |
101 kIgnored_GrGPInput, | |
102 }; | |
103 | |
59 /** | 104 /** |
60 * A GrGeometryProcessor is used to perform computation in the vertex shader and | 105 * A GrGeometryProcessor is a flexible method for rendering a primitive. The Gr GeometryProcessor |
61 * add support for custom vertex attributes. A GrGemeotryProcessor is typically | 106 * has complete control over vertex attributes and uniforms(aside from the rende r target) but it |
62 * tied to the code that does a specific type of high-level primitive rendering | 107 * must obey the same contract as any GrPrimitiveProcessor, specifically it must emit a color and |
63 * (e.g. anti-aliased circle rendering). The GrGeometryProcessor used for a draw is | 108 * coverage into the fragment shader. Where this color and coverage come from i s completely the |
64 * specified using GrDrawState. There can only be one geometry processor active for | 109 * responsibility of the GrGeometryProcessor. |
bsalomon
2014/12/15 15:31:13
nice
| |
65 * a draw. The custom vertex attributes required by the geometry processor must be | |
66 * added to the vertex attribute array specified on the GrDrawState. | |
67 * GrGeometryProcessor subclasses should be immutable after construction. | |
68 */ | 110 */ |
69 class GrGeometryProcessor : public GrPrimitiveProcessor { | 111 class GrGeometryProcessor : public GrPrimitiveProcessor { |
70 public: | 112 public: |
71 // TODO the Hint can be handled in a much more clean way when we have deferr ed geometry or | 113 // TODO the Hint can be handled in a much more clean way when we have deferr ed geometry or |
72 // atleast bundles | 114 // atleast bundles |
73 GrGeometryProcessor(GrColor color, bool opaqueVertexColors = false, uint8_t coverage = 0xff) | 115 GrGeometryProcessor(GrColor color, bool opaqueVertexColors = false) |
74 : fVertexStride(0) | 116 : fVertexStride(0) |
75 , fColor(color) | 117 , fColor(color) |
76 , fCoverage(coverage) | |
77 , fOpaqueVertexColors(opaqueVertexColors) | 118 , fOpaqueVertexColors(opaqueVertexColors) |
78 , fWillUseGeoShader(false) | 119 , fWillUseGeoShader(false) |
79 , fHasVertexColor(false) | 120 , fHasVertexColor(false) |
80 , fHasVertexCoverage(false) | |
81 , fHasLocalCoords(false) {} | 121 , fHasLocalCoords(false) {} |
82 | 122 |
83 virtual const char* name() const = 0; | 123 virtual const char* name() const = 0; |
84 | 124 |
85 /** | 125 /** |
86 * Sets a unique key on the GrProcessorKeyBuilder that is directly associate d with this geometry | 126 * Sets a unique key on the GrProcessorKeyBuilder that is directly associate d with this geometry |
87 * processor's GL backend implementation. | 127 * processor's GL backend implementation. |
88 */ | 128 */ |
89 virtual void getGLProcessorKey(const GrBatchTracker& bt, | 129 virtual void getGLProcessorKey(const GrBatchTracker& bt, |
90 const GrGLCaps& caps, | 130 const GrGLCaps& caps, |
(...skipping 25 matching lines...) Expand all Loading... | |
116 | 156 |
117 const VertexAttribArray& getAttribs() const { return fAttribs; } | 157 const VertexAttribArray& getAttribs() const { return fAttribs; } |
118 | 158 |
119 // Returns the vertex stride of the GP. A common use case is to request geo metry from a | 159 // Returns the vertex stride of the GP. A common use case is to request geo metry from a |
120 // drawtarget based off of the stride, and to populate this memory using an implicit array of | 160 // drawtarget based off of the stride, and to populate this memory using an implicit array of |
121 // structs. In this case, it is best to assert the vertexstride == sizeof(V ertexStruct). | 161 // structs. In this case, it is best to assert the vertexstride == sizeof(V ertexStruct). |
122 size_t getVertexStride() const { return fVertexStride; } | 162 size_t getVertexStride() const { return fVertexStride; } |
123 | 163 |
124 bool willUseGeoShader() const { return fWillUseGeoShader; } | 164 bool willUseGeoShader() const { return fWillUseGeoShader; } |
125 | 165 |
126 /** Returns true if this and other processor conservatively draw identically . It can only return | 166 /* |
127 true when the two prcoessors are of the same subclass (i.e. they return the same object from | 167 * In an ideal world, two GrGeometryProcessors with the same class id and te xture accesses |
128 from getFactory()). | 168 * would ALWAYS be able to batch together. If two GrGeometryProcesosrs are the same then we |
129 A return value of true from isEqual() should not be used to test whether the processors | 169 * will only keep one of them. The remaining GrGeometryProcessor then updat es its |
130 would generate the same shader code. To test for identical code generati on use the | 170 * GrBatchTracker to incorporate the draw information from the GrGeometryPro cessor we discard. |
131 processors' keys computed by the GrBackendEffectFactory. */ | 171 * Any bundles associated with the discarded GrGeometryProcessor will be att ached to the |
132 bool isEqual(const GrGeometryProcessor& that) const { | 172 * remaining GrGeometryProcessor. |
173 */ | |
174 bool canMakeEqual(const GrBatchTracker& mine, | |
175 const GrPrimitiveProcessor& that, | |
176 const GrBatchTracker& theirs) const SK_OVERRIDE { | |
133 if (this->classID() != that.classID() || !this->hasSameTextureAccesses(t hat)) { | 177 if (this->classID() != that.classID() || !this->hasSameTextureAccesses(t hat)) { |
134 return false; | 178 return false; |
135 } | 179 } |
136 | 180 |
137 // TODO remove the hint | 181 // TODO remove the hint |
138 if (fHasVertexColor && fOpaqueVertexColors != that.fOpaqueVertexColors) { | 182 const GrGeometryProcessor& other = that.cast<GrGeometryProcessor>(); |
183 if (fHasVertexColor && fOpaqueVertexColors != other.fOpaqueVertexColors) { | |
139 return false; | 184 return false; |
140 } | 185 } |
141 | 186 |
142 if (!fHasVertexColor && this->color() != that.color()) { | 187 if (!fHasVertexColor && this->color() != other.color()) { |
143 return false; | 188 return false; |
144 } | 189 } |
145 | 190 return this->onCanMakeEqual(mine, theirs); |
146 // TODO this is fragile, most gps set their coverage to 0xff so this is okay. In the long | |
147 // term this should move to subclasses which set explicit coverage | |
148 if (!fHasVertexCoverage && this->coverage() != that.coverage()) { | |
149 return false; | |
150 } | |
151 return this->onIsEqual(that); | |
152 } | 191 } |
153 | 192 |
193 virtual bool onCanMakeEqual(const GrBatchTracker& mine, const GrBatchTracker & theirs) const = 0; | |
bsalomon
2014/12/15 15:31:13
move to private?
| |
194 | |
195 /* | |
196 * This struct allows the optstate to communicate requirements to the GP. | |
197 */ | |
154 struct InitBT { | 198 struct InitBT { |
155 bool fOutputColor; | 199 bool fColorIgnored; |
156 bool fOutputCoverage; | 200 bool fCoverageIgnored; |
157 GrColor fColor; | 201 GrColor fOverrideColor; |
158 GrColor fCoverage; | |
159 }; | 202 }; |
160 | 203 |
161 virtual void initBatchTracker(GrBatchTracker*, const InitBT&) const {} | 204 virtual void initBatchTracker(GrBatchTracker*, const InitBT&) const = 0; |
205 | |
206 // TODO we can remove color from the GrGeometryProcessor base class once we have bundles of | |
207 // primitive data | |
208 GrColor color() const { return fColor; } | |
162 | 209 |
163 GrColor color() const { return fColor; } | 210 // TODO this is a total hack until the gp can do deferred geometry |
164 uint8_t coverage() const { return fCoverage; } | 211 bool hasVertexColor() const { return fHasVertexColor; } |
165 | 212 |
166 // TODO this is a total hack until the gp can own whether or not it uses uni form | 213 // TODO this is a total hack until gp can setup and manage local coords |
167 // color / coverage | |
168 bool hasVertexColor() const { return fHasVertexColor; } | |
169 bool hasVertexCoverage() const { return fHasVertexCoverage; } | |
170 bool hasLocalCoords() const { return fHasLocalCoords; } | 214 bool hasLocalCoords() const { return fHasLocalCoords; } |
171 | 215 |
172 void getInvariantOutputColor(GrInitInvariantOutput* out) const SK_OVERRIDE; | 216 void getInvariantOutputColor(GrInitInvariantOutput* out) const SK_OVERRIDE; |
173 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRID E; | 217 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRID E; |
174 | 218 |
175 protected: | 219 protected: |
220 /* | |
221 * A simple helper function to determine by what means the GrGeometryProcess or should use to | |
bsalomon
2014/12/15 15:31:13
Can you throw in the word "optional" ? Just want t
| |
222 * provide color. If we are given an override color(ie the given overrideco lor is NOT illegal) | |
bsalomon
2014/12/15 15:31:13
can you say GrColor_ILLEGAL? I think it might be c
| |
223 * then we must always emit that color via a uniform. Otherwise, if our col or is ignored | |
bsalomon
2014/12/15 15:31:13
Does it have to be via a uniform? A GP could rewr
| |
224 * then we should not emit a color. Lastly, if we don't have vertex colors then we must emit | |
225 * a color via uniform | |
226 * TODO this function changes quite a bit with deferred geometry. There the GrGeometryProcessor | |
227 * can upload a new color via attribute if needed. | |
228 */ | |
229 static GrGPInput GetColorInputType(GrColor* color, GrColor primitiveColor, c onst InitBT& init, | |
230 bool hasVertexColor) { | |
231 if (GrColor_ILLEGAL != init.fOverrideColor) { | |
232 *color = init.fOverrideColor; | |
233 return kUniform_GrGPInput; | |
234 } else if (init.fColorIgnored) { | |
235 *color = GrColor_ILLEGAL; | |
236 return kIgnored_GrGPInput; | |
237 } | |
238 | |
239 *color = primitiveColor; | |
240 if (hasVertexColor) { | |
241 return kAttribute_GrGPInput; | |
242 } else { | |
243 return kUniform_GrGPInput; | |
244 } | |
245 } | |
246 | |
247 /* | |
248 * CanCombineOutput will return true if two draws are 'batchable' from a col or perspective. | |
249 * TODO remove this when GPs can upgrade to attribute color | |
250 */ | |
251 static bool CanCombineOutput(GrGPInput left, GrColor lColor, GrGPInput right , GrColor rColor) { | |
252 if (left != right) { | |
253 return false; | |
254 } | |
255 | |
256 if (kUniform_GrGPInput == left && lColor != rColor) { | |
257 return false; | |
258 } | |
259 | |
260 return true; | |
261 } | |
262 | |
176 /** | 263 /** |
177 * Subclasses call this from their constructor to register vertex attributes . Attributes | 264 * Subclasses call this from their constructor to register vertex attributes . Attributes |
178 * will be padded to the nearest 4 bytes for performance reasons. | 265 * will be padded to the nearest 4 bytes for performance reasons. |
179 * TODO After deferred geometry, we should do all of this inline in Generate Geometry alongside | 266 * TODO After deferred geometry, we should do all of this inline in Generate Geometry alongside |
180 * the struct used to actually populate the attributes | 267 * the struct used to actually populate the attributes |
181 */ | 268 */ |
182 const GrAttribute& addVertexAttrib(const GrAttribute& attribute) { | 269 const GrAttribute& addVertexAttrib(const GrAttribute& attribute) { |
183 fVertexStride += attribute.fOffset; | 270 fVertexStride += attribute.fOffset; |
184 return fAttribs.push_back(attribute); | 271 return fAttribs.push_back(attribute); |
185 } | 272 } |
186 | 273 |
187 void setWillUseGeoShader() { fWillUseGeoShader = true; } | 274 void setWillUseGeoShader() { fWillUseGeoShader = true; } |
188 | 275 |
189 // TODO hack see above | 276 // TODO hack see above |
190 void setHasVertexColor() { fHasVertexColor = true; } | 277 void setHasVertexColor() { fHasVertexColor = true; } |
191 void setHasVertexCoverage() { fHasVertexCoverage = true; } | |
192 void setHasLocalCoords() { fHasLocalCoords = true; } | 278 void setHasLocalCoords() { fHasLocalCoords = true; } |
193 | 279 |
194 virtual void onGetInvariantOutputColor(GrInitInvariantOutput*) const {} | 280 virtual void onGetInvariantOutputColor(GrInitInvariantOutput*) const {} |
195 virtual void onGetInvariantOutputCoverage(GrInitInvariantOutput*) const = 0; | 281 virtual void onGetInvariantOutputCoverage(GrInitInvariantOutput*) const = 0; |
196 | 282 |
197 private: | 283 private: |
198 virtual bool onIsEqual(const GrGeometryProcessor&) const = 0; | 284 virtual bool onIsEqual(const GrGeometryProcessor&) const = 0; |
199 | 285 |
200 SkSTArray<kMaxVertexAttribs, GrAttribute, true> fAttribs; | 286 SkSTArray<kMaxVertexAttribs, GrAttribute, true> fAttribs; |
201 size_t fVertexStride; | 287 size_t fVertexStride; |
202 GrColor fColor; | 288 GrColor fColor; |
203 uint8_t fCoverage; | |
204 bool fOpaqueVertexColors; | 289 bool fOpaqueVertexColors; |
205 bool fWillUseGeoShader; | 290 bool fWillUseGeoShader; |
206 bool fHasVertexColor; | 291 bool fHasVertexColor; |
207 bool fHasVertexCoverage; | |
208 bool fHasLocalCoords; | 292 bool fHasLocalCoords; |
209 | 293 |
210 typedef GrProcessor INHERITED; | 294 typedef GrProcessor INHERITED; |
211 }; | 295 }; |
212 | 296 |
213 /* | 297 /* |
214 * The path equivalent of the GP. For now this just manages color. In the long term we plan on | 298 * The path equivalent of the GP. For now this just manages color. In the long term we plan on |
215 * extending this class to handle all nvpr uniform / varying / program work. | 299 * extending this class to handle all nvpr uniform / varying / program work. |
216 */ | 300 */ |
217 class GrPathProcessor : public GrPrimitiveProcessor { | 301 class GrPathProcessor : public GrPrimitiveProcessor { |
218 public: | 302 public: |
219 static GrPathProcessor* Create(GrColor color) { | 303 static GrPathProcessor* Create(GrColor color) { |
220 return SkNEW_ARGS(GrPathProcessor, (color)); | 304 return SkNEW_ARGS(GrPathProcessor, (color)); |
221 } | 305 } |
222 | 306 |
307 bool canMakeEqual(const GrBatchTracker& mine, | |
308 const GrPrimitiveProcessor& that, | |
309 const GrBatchTracker& theirs) const SK_OVERRIDE { | |
310 if (this->classID() != that.classID() || !this->hasSameTextureAccesses(t hat)) { | |
bsalomon
2014/12/15 15:31:13
Seems a little weird that path procs can even have
| |
311 return false; | |
312 } | |
313 const GrPathProcessor& other = that.cast<GrPathProcessor>(); | |
314 return other.color() == this->color(); | |
bsalomon
2014/12/15 15:31:13
So if there is an override these two colors would
| |
315 } | |
316 | |
223 const char* name() const SK_OVERRIDE { return "PathProcessor"; } | 317 const char* name() const SK_OVERRIDE { return "PathProcessor"; } |
224 uint8_t coverage() const SK_OVERRIDE { return 0xff; } | 318 GrColor color() const { return fColor; } |
225 void getInvariantOutputColor(GrInitInvariantOutput* out) const SK_OVERRIDE; | 319 void getInvariantOutputColor(GrInitInvariantOutput* out) const SK_OVERRIDE; |
226 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRID E; | 320 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRID E; |
227 | 321 |
228 private: | 322 private: |
229 GrPathProcessor(GrColor color) : fColor(color) {} | 323 GrPathProcessor(GrColor color); |
230 GrColor fColor; | 324 GrColor fColor; |
231 | 325 |
232 typedef GrProcessor INHERITED; | 326 typedef GrProcessor INHERITED; |
233 }; | 327 }; |
234 #endif | 328 #endif |
OLD | NEW |