1 | /* |
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 GrPrimitiveProcessor_DEFINED |
9 | #define GrPrimitiveProcessor_DEFINED |
10 | |
11 | #include "src/gpu/GrColor.h" |
12 | #include "src/gpu/GrNonAtomicRef.h" |
13 | #include "src/gpu/GrProcessor.h" |
14 | #include "src/gpu/GrShaderVar.h" |
15 | #include "src/gpu/GrSwizzle.h" |
16 | |
17 | class GrCoordTransform; |
18 | |
19 | /* |
20 | * The GrPrimitiveProcessor represents some kind of geometric primitive. This includes the shape |
21 | * of the primitive and the inherent color of the primitive. The GrPrimitiveProcessor is |
22 | * responsible for providing a color and coverage input into the Ganesh rendering pipeline. Through |
23 | * optimization, Ganesh may decide a different color, no color, and / or no coverage are required |
24 | * from the GrPrimitiveProcessor, so the GrPrimitiveProcessor must be able to support this |
25 | * functionality. |
26 | * |
27 | * There are two feedback loops between the GrFragmentProcessors, the GrXferProcessor, and the |
28 | * GrPrimitiveProcessor. These loops run on the CPU and to determine known properties of the final |
29 | * color and coverage inputs to the GrXferProcessor in order to perform optimizations that preserve |
30 | * correctness. The GrDrawOp seeds these loops with initial color and coverage, in its |
31 | * getProcessorAnalysisInputs implementation. These seed values are processed by the |
32 | * subsequent |
33 | * stages of the rendering pipeline and the output is then fed back into the GrDrawOp in |
34 | * the applyPipelineOptimizations call, where the op can use the information to inform decisions |
35 | * about GrPrimitiveProcessor creation. |
36 | */ |
37 | |
38 | class GrGLSLPrimitiveProcessor; |
39 | |
40 | /** |
41 | * GrPrimitiveProcessor defines an interface which all subclasses must implement. All |
42 | * GrPrimitiveProcessors must proivide seed color and coverage for the Ganesh color / coverage |
43 | * pipelines, and they must provide some notion of equality |
44 | * |
45 | * TODO: This class does not really need to be ref counted. Instances should be allocated using |
46 | * GrOpFlushState's arena and destroyed when the arena is torn down. |
47 | */ |
48 | class GrPrimitiveProcessor : public GrProcessor, public GrNonAtomicRef<GrPrimitiveProcessor> { |
49 | public: |
50 | class TextureSampler; |
51 | |
52 | /** Describes a vertex or instance attribute. */ |
53 | class Attribute { |
54 | public: |
55 | constexpr Attribute() = default; |
56 | constexpr Attribute(const char* name, |
57 | GrVertexAttribType cpuType, |
58 | GrSLType gpuType) |
59 | : fName(name), fCPUType(cpuType), fGPUType(gpuType) {} |
60 | constexpr Attribute(const Attribute&) = default; |
61 | |
62 | Attribute& operator=(const Attribute&) = default; |
63 | |
64 | constexpr bool isInitialized() const { return SkToBool(fName); } |
65 | |
66 | constexpr const char* name() const { return fName; } |
67 | constexpr GrVertexAttribType cpuType() const { return fCPUType; } |
68 | constexpr GrSLType gpuType() const { return fGPUType; } |
69 | |
70 | inline constexpr size_t size() const; |
71 | constexpr size_t sizeAlign4() const { return SkAlign4(this->size()); } |
72 | |
73 | GrShaderVar asShaderVar() const { |
74 | return {fName, fGPUType, GrShaderVar::TypeModifier::In}; |
75 | } |
76 | |
77 | private: |
78 | const char* fName = nullptr; |
79 | GrVertexAttribType fCPUType = kFloat_GrVertexAttribType; |
80 | GrSLType fGPUType = kFloat_GrSLType; |
81 | }; |
82 | |
83 | class Iter { |
84 | public: |
85 | Iter() : fCurr(nullptr), fRemaining(0) {} |
86 | Iter(const Iter& iter) : fCurr(iter.fCurr), fRemaining(iter.fRemaining) {} |
87 | Iter& operator= (const Iter& iter) { |
88 | fCurr = iter.fCurr; |
89 | fRemaining = iter.fRemaining; |
90 | return *this; |
91 | } |
92 | Iter(const Attribute* attrs, int count) : fCurr(attrs), fRemaining(count) { |
93 | this->skipUninitialized(); |
94 | } |
95 | |
96 | bool operator!=(const Iter& that) const { return fCurr != that.fCurr; } |
97 | const Attribute& operator*() const { return *fCurr; } |
98 | void operator++() { |
99 | if (fRemaining) { |
100 | fRemaining--; |
101 | fCurr++; |
102 | this->skipUninitialized(); |
103 | } |
104 | } |
105 | |
106 | private: |
107 | void skipUninitialized() { |
108 | if (!fRemaining) { |
109 | fCurr = nullptr; |
110 | } else { |
111 | while (!fCurr->isInitialized()) { |
112 | ++fCurr; |
113 | } |
114 | } |
115 | } |
116 | |
117 | const Attribute* fCurr; |
118 | int fRemaining; |
119 | }; |
120 | |
121 | class AttributeSet { |
122 | public: |
123 | Iter begin() const { return Iter(fAttributes, fCount); } |
124 | Iter end() const { return Iter(); } |
125 | |
126 | private: |
127 | friend class GrPrimitiveProcessor; |
128 | |
129 | void init(const Attribute* attrs, int count) { |
130 | fAttributes = attrs; |
131 | fRawCount = count; |
132 | fCount = 0; |
133 | fStride = 0; |
134 | for (int i = 0; i < count; ++i) { |
135 | if (attrs[i].isInitialized()) { |
136 | fCount++; |
137 | fStride += attrs[i].sizeAlign4(); |
138 | } |
139 | } |
140 | } |
141 | |
142 | const Attribute* fAttributes = nullptr; |
143 | int fRawCount = 0; |
144 | int fCount = 0; |
145 | size_t fStride = 0; |
146 | }; |
147 | |
148 | GrPrimitiveProcessor(ClassID); |
149 | |
150 | int numTextureSamplers() const { return fTextureSamplerCnt; } |
151 | const TextureSampler& textureSampler(int index) const; |
152 | int numVertexAttributes() const { return fVertexAttributes.fCount; } |
153 | const AttributeSet& vertexAttributes() const { return fVertexAttributes; } |
154 | int numInstanceAttributes() const { return fInstanceAttributes.fCount; } |
155 | const AttributeSet& instanceAttributes() const { return fInstanceAttributes; } |
156 | |
157 | bool hasVertexAttributes() const { return SkToBool(fVertexAttributes.fCount); } |
158 | bool hasInstanceAttributes() const { return SkToBool(fInstanceAttributes.fCount); } |
159 | |
160 | /** |
161 | * A common practice is to populate the the vertex/instance's memory using an implicit array of |
162 | * structs. In this case, it is best to assert that: |
163 | * stride == sizeof(struct) |
164 | */ |
165 | size_t vertexStride() const { return fVertexAttributes.fStride; } |
166 | size_t instanceStride() const { return fInstanceAttributes.fStride; } |
167 | |
168 | bool willUseTessellationShaders() const { |
169 | return fShaders & (kTessControl_GrShaderFlag | kTessEvaluation_GrShaderFlag); |
170 | } |
171 | |
172 | bool willUseGeoShader() const { |
173 | return fShaders & kGeometry_GrShaderFlag; |
174 | } |
175 | |
176 | /** |
177 | * Computes a key for the transforms owned by an FP based on the shader code that will be |
178 | * emitted by the primitive processor to implement them. |
179 | */ |
180 | uint32_t computeCoordTransformsKey(const GrFragmentProcessor& fp) const; |
181 | |
182 | /** |
183 | * Sets a unique key on the GrProcessorKeyBuilder that is directly associated with this geometry |
184 | * processor's GL backend implementation. |
185 | * |
186 | * TODO: A better name for this function would be "compute" instead of "get". |
187 | */ |
188 | virtual void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const = 0; |
189 | |
190 | |
191 | void getAttributeKey(GrProcessorKeyBuilder* b) const { |
192 | // Ensure that our CPU and GPU type fields fit together in a 32-bit value, and we never |
193 | // collide with the "uninitialized" value. |
194 | static_assert(kGrVertexAttribTypeCount < (1 << 8), "" ); |
195 | static_assert(kGrSLTypeCount < (1 << 8), "" ); |
196 | |
197 | auto add_attributes = [=](const Attribute* attrs, int attrCount) { |
198 | for (int i = 0; i < attrCount; ++i) { |
199 | b->add32(attrs[i].isInitialized() ? (attrs[i].cpuType() << 16) | attrs[i].gpuType() |
200 | : ~0); |
201 | } |
202 | }; |
203 | add_attributes(fVertexAttributes.fAttributes, fVertexAttributes.fRawCount); |
204 | add_attributes(fInstanceAttributes.fAttributes, fInstanceAttributes.fRawCount); |
205 | } |
206 | |
207 | /** Returns a new instance of the appropriate *GL* implementation class |
208 | for the given GrProcessor; caller is responsible for deleting |
209 | the object. */ |
210 | virtual GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const = 0; |
211 | |
212 | virtual bool isPathRendering() const { return false; } |
213 | |
214 | // We use these methods as a temporary back door to inject OpenGL tessellation code. Once |
215 | // tessellation is supported by SkSL we can remove these. |
216 | virtual SkString getTessControlShaderGLSL(const char* versionAndExtensionDecls, |
217 | const GrShaderCaps&) const { |
218 | SK_ABORT("Not implemented." ); |
219 | } |
220 | virtual SkString getTessEvaluationShaderGLSL(const char* versionAndExtensionDecls, |
221 | const GrShaderCaps&) const { |
222 | SK_ABORT("Not implemented." ); |
223 | } |
224 | |
225 | protected: |
226 | void setVertexAttributes(const Attribute* attrs, int attrCount) { |
227 | fVertexAttributes.init(attrs, attrCount); |
228 | } |
229 | void setInstanceAttributes(const Attribute* attrs, int attrCount) { |
230 | SkASSERT(attrCount >= 0); |
231 | fInstanceAttributes.init(attrs, attrCount); |
232 | } |
233 | void setWillUseTessellationShaders() { |
234 | fShaders |= kTessControl_GrShaderFlag | kTessEvaluation_GrShaderFlag; |
235 | } |
236 | void setWillUseGeoShader() { fShaders |= kGeometry_GrShaderFlag; } |
237 | void setTextureSamplerCnt(int cnt) { |
238 | SkASSERT(cnt >= 0); |
239 | fTextureSamplerCnt = cnt; |
240 | } |
241 | |
242 | /** |
243 | * Helper for implementing onTextureSampler(). E.g.: |
244 | * return IthTexureSampler(i, fMyFirstSampler, fMySecondSampler, fMyThirdSampler); |
245 | */ |
246 | template <typename... Args> |
247 | static const TextureSampler& IthTextureSampler(int i, const TextureSampler& samp0, |
248 | const Args&... samps) { |
249 | return (0 == i) ? samp0 : IthTextureSampler(i - 1, samps...); |
250 | } |
251 | inline static const TextureSampler& IthTextureSampler(int i); |
252 | |
253 | private: |
254 | virtual const TextureSampler& onTextureSampler(int) const { return IthTextureSampler(0); } |
255 | |
256 | GrShaderFlags fShaders = kVertex_GrShaderFlag | kFragment_GrShaderFlag; |
257 | |
258 | AttributeSet fVertexAttributes; |
259 | AttributeSet fInstanceAttributes; |
260 | |
261 | int fTextureSamplerCnt = 0; |
262 | typedef GrProcessor INHERITED; |
263 | }; |
264 | |
265 | ////////////////////////////////////////////////////////////////////////////// |
266 | |
267 | /** |
268 | * Used to capture the properties of the GrTextureProxies required/expected by a primitiveProcessor |
269 | * along with an associated GrSamplerState. The actual proxies used are stored in either the |
270 | * fixed or dynamic state arrays. TextureSamplers don't perform any coord manipulation to account |
271 | * for texture origin. |
272 | */ |
273 | class GrPrimitiveProcessor::TextureSampler { |
274 | public: |
275 | TextureSampler() = default; |
276 | |
277 | TextureSampler(GrSamplerState, const GrBackendFormat&, const GrSwizzle&); |
278 | |
279 | TextureSampler(const TextureSampler&) = delete; |
280 | TextureSampler& operator=(const TextureSampler&) = delete; |
281 | |
282 | void reset(GrSamplerState, const GrBackendFormat&, const GrSwizzle&); |
283 | |
284 | const GrBackendFormat& backendFormat() const { return fBackendFormat; } |
285 | GrTextureType textureType() const { return fBackendFormat.textureType(); } |
286 | |
287 | GrSamplerState samplerState() const { return fSamplerState; } |
288 | const GrSwizzle& swizzle() const { return fSwizzle; } |
289 | |
290 | bool isInitialized() const { return fIsInitialized; } |
291 | |
292 | private: |
293 | GrSamplerState fSamplerState; |
294 | GrBackendFormat fBackendFormat; |
295 | GrSwizzle fSwizzle; |
296 | bool fIsInitialized = false; |
297 | }; |
298 | |
299 | const GrPrimitiveProcessor::TextureSampler& GrPrimitiveProcessor::IthTextureSampler(int i) { |
300 | SK_ABORT("Illegal texture sampler index" ); |
301 | static const TextureSampler kBogus; |
302 | return kBogus; |
303 | } |
304 | |
305 | ////////////////////////////////////////////////////////////////////////////// |
306 | |
307 | /** |
308 | * Returns the size of the attrib type in bytes. |
309 | * This was moved from include/private/GrTypesPriv.h in service of Skia dependents that build |
310 | * with C++11. |
311 | */ |
312 | static constexpr inline size_t GrVertexAttribTypeSize(GrVertexAttribType type) { |
313 | switch (type) { |
314 | case kFloat_GrVertexAttribType: |
315 | return sizeof(float); |
316 | case kFloat2_GrVertexAttribType: |
317 | return 2 * sizeof(float); |
318 | case kFloat3_GrVertexAttribType: |
319 | return 3 * sizeof(float); |
320 | case kFloat4_GrVertexAttribType: |
321 | return 4 * sizeof(float); |
322 | case kHalf_GrVertexAttribType: |
323 | return sizeof(uint16_t); |
324 | case kHalf2_GrVertexAttribType: |
325 | return 2 * sizeof(uint16_t); |
326 | case kHalf4_GrVertexAttribType: |
327 | return 4 * sizeof(uint16_t); |
328 | case kInt2_GrVertexAttribType: |
329 | return 2 * sizeof(int32_t); |
330 | case kInt3_GrVertexAttribType: |
331 | return 3 * sizeof(int32_t); |
332 | case kInt4_GrVertexAttribType: |
333 | return 4 * sizeof(int32_t); |
334 | case kByte_GrVertexAttribType: |
335 | return 1 * sizeof(char); |
336 | case kByte2_GrVertexAttribType: |
337 | return 2 * sizeof(char); |
338 | case kByte4_GrVertexAttribType: |
339 | return 4 * sizeof(char); |
340 | case kUByte_GrVertexAttribType: |
341 | return 1 * sizeof(char); |
342 | case kUByte2_GrVertexAttribType: |
343 | return 2 * sizeof(char); |
344 | case kUByte4_GrVertexAttribType: |
345 | return 4 * sizeof(char); |
346 | case kUByte_norm_GrVertexAttribType: |
347 | return 1 * sizeof(char); |
348 | case kUByte4_norm_GrVertexAttribType: |
349 | return 4 * sizeof(char); |
350 | case kShort2_GrVertexAttribType: |
351 | return 2 * sizeof(int16_t); |
352 | case kShort4_GrVertexAttribType: |
353 | return 4 * sizeof(int16_t); |
354 | case kUShort2_GrVertexAttribType: // fall through |
355 | case kUShort2_norm_GrVertexAttribType: |
356 | return 2 * sizeof(uint16_t); |
357 | case kInt_GrVertexAttribType: |
358 | return sizeof(int32_t); |
359 | case kUint_GrVertexAttribType: |
360 | return sizeof(uint32_t); |
361 | case kUShort_norm_GrVertexAttribType: |
362 | return sizeof(uint16_t); |
363 | case kUShort4_norm_GrVertexAttribType: |
364 | return 4 * sizeof(uint16_t); |
365 | } |
366 | // GCC fails because SK_ABORT evaluates to non constexpr. clang and cl.exe think this is |
367 | // unreachable and don't complain. |
368 | #if defined(__clang__) || !defined(__GNUC__) |
369 | SK_ABORT("Unsupported type conversion" ); |
370 | #endif |
371 | return 0; |
372 | } |
373 | |
374 | constexpr size_t GrPrimitiveProcessor::Attribute::size() const { |
375 | return GrVertexAttribTypeSize(fCPUType); |
376 | } |
377 | |
378 | #endif |
379 | |