• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 GrGeometryProcessor_DEFINED
9 #define GrGeometryProcessor_DEFINED
10 
11 #include "src/gpu/GrColor.h"
12 #include "src/gpu/GrFragmentProcessor.h"
13 #include "src/gpu/GrProcessor.h"
14 #include "src/gpu/GrShaderCaps.h"
15 #include "src/gpu/GrShaderVar.h"
16 #include "src/gpu/GrSwizzle.h"
17 #include "src/gpu/glsl/GrGLSLProgramDataManager.h"
18 #include "src/gpu/glsl/GrGLSLUniformHandler.h"
19 #include "src/gpu/glsl/GrGLSLVarying.h"
20 
21 #include <unordered_map>
22 
23 class GrGLSLFPFragmentBuilder;
24 class GrGLSLVaryingHandler;
25 class GrGLSLUniformHandler;
26 class GrGLSLVertexBuilder;
27 
28 /**
29  * The GrGeometryProcessor represents some kind of geometric primitive.  This includes the shape
30  * of the primitive and the inherent color of the primitive.  The GrGeometryProcessor is
31  * responsible for providing a color and coverage input into the Ganesh rendering pipeline. Through
32  * optimization, Ganesh may decide a different color, no color, and / or no coverage are required
33  * from the GrGeometryProcessor, so the GrGeometryProcessor must be able to support this
34  * functionality.
35  *
36  * There are two feedback loops between the GrFragmentProcessors, the GrXferProcessor, and the
37  * GrGeometryProcessor. These loops run on the CPU and to determine known properties of the final
38  * color and coverage inputs to the GrXferProcessor in order to perform optimizations that preserve
39  * correctness. The GrDrawOp seeds these loops with initial color and coverage, in its
40  * getProcessorAnalysisInputs implementation. These seed values are processed by the
41  * subsequent stages of the rendering pipeline and the output is then fed back into the GrDrawOp
42  * in the applyPipelineOptimizations call, where the op can use the information to inform
43  * decisions about GrGeometryProcessor creation.
44  *
45  * Note that all derived classes should hide their constructors and provide a Make factory
46  * function that takes an arena (except for Tesselation-specific classes). This is because
47  * geometry processors can be created in either the record-time or flush-time arenas which
48  * define their lifetimes (i.e., a DDLs life time in the first case and a single flush in
49  * the second case).
50  */
51 class GrGeometryProcessor : public GrProcessor {
52 public:
53     /**
54      * Every GrGeometryProcessor must be capable of creating a subclass of ProgramImpl. The
55      * ProgramImpl emits the shader code that implements the GrGeometryProcessor, is attached to the
56      * generated backend API pipeline/program and used to extract uniform data from
57      * GrGeometryProcessor instances.
58      */
59     class ProgramImpl;
60 
61     class TextureSampler;
62 
63     /** Describes a vertex or instance attribute. */
64     class Attribute {
65     public:
66         constexpr Attribute() = default;
Attribute(const char * name,GrVertexAttribType cpuType,GrSLType gpuType)67         constexpr Attribute(const char* name,
68                             GrVertexAttribType cpuType,
69                             GrSLType gpuType)
70                 : fName(name), fCPUType(cpuType), fGPUType(gpuType) {
71             SkASSERT(name && gpuType != kVoid_GrSLType);
72         }
73         constexpr Attribute(const Attribute&) = default;
74 
75         Attribute& operator=(const Attribute&) = default;
76 
isInitialized()77         constexpr bool isInitialized() const { return fGPUType != kVoid_GrSLType; }
78 
name()79         constexpr const char* name() const { return fName; }
cpuType()80         constexpr GrVertexAttribType cpuType() const { return fCPUType; }
gpuType()81         constexpr GrSLType           gpuType() const { return fGPUType; }
82 
83         inline constexpr size_t size() const;
sizeAlign4()84         constexpr size_t sizeAlign4() const { return SkAlign4(this->size()); }
85 
asShaderVar()86         GrShaderVar asShaderVar() const {
87             return {fName, fGPUType, GrShaderVar::TypeModifier::In};
88         }
89 
90     private:
91         const char* fName = nullptr;
92         GrVertexAttribType fCPUType = kFloat_GrVertexAttribType;
93         GrSLType fGPUType = kVoid_GrSLType;
94     };
95 
96     class Iter {
97     public:
Iter()98         Iter() : fCurr(nullptr), fRemaining(0) {}
Iter(const Iter & iter)99         Iter(const Iter& iter) : fCurr(iter.fCurr), fRemaining(iter.fRemaining) {}
100         Iter& operator= (const Iter& iter) {
101             fCurr = iter.fCurr;
102             fRemaining = iter.fRemaining;
103             return *this;
104         }
Iter(const Attribute * attrs,int count)105         Iter(const Attribute* attrs, int count) : fCurr(attrs), fRemaining(count) {
106             this->skipUninitialized();
107         }
108 
109         bool operator!=(const Iter& that) const { return fCurr != that.fCurr; }
110         const Attribute& operator*() const { return *fCurr; }
111         void operator++() {
112             if (fRemaining) {
113                 fRemaining--;
114                 fCurr++;
115                 this->skipUninitialized();
116             }
117         }
118 
119     private:
skipUninitialized()120         void skipUninitialized() {
121             if (!fRemaining) {
122                 fCurr = nullptr;
123             } else {
124                 while (!fCurr->isInitialized()) {
125                     ++fCurr;
126                 }
127             }
128         }
129 
130         const Attribute* fCurr;
131         int fRemaining;
132     };
133 
134     class AttributeSet {
135     public:
begin()136         Iter begin() const { return Iter(fAttributes, fCount); }
end()137         Iter end() const { return Iter(); }
138 
count()139         int count() const { return fCount; }
stride()140         size_t stride() const { return fStride; }
141 
142     private:
143         friend class GrGeometryProcessor;
144 
init(const Attribute * attrs,int count)145         void init(const Attribute* attrs, int count) {
146             fAttributes = attrs;
147             fRawCount = count;
148             fCount = 0;
149             fStride = 0;
150             for (int i = 0; i < count; ++i) {
151                 if (attrs[i].isInitialized()) {
152                     fCount++;
153                     fStride += attrs[i].sizeAlign4();
154                 }
155             }
156         }
157 
158         const Attribute* fAttributes = nullptr;
159         int              fRawCount = 0;
160         int              fCount = 0;
161         size_t           fStride = 0;
162     };
163 
164     GrGeometryProcessor(ClassID);
165 
numTextureSamplers()166     int numTextureSamplers() const { return fTextureSamplerCnt; }
167     const TextureSampler& textureSampler(int index) const;
numVertexAttributes()168     int numVertexAttributes() const { return fVertexAttributes.fCount; }
vertexAttributes()169     const AttributeSet& vertexAttributes() const { return fVertexAttributes; }
numInstanceAttributes()170     int numInstanceAttributes() const { return fInstanceAttributes.fCount; }
instanceAttributes()171     const AttributeSet& instanceAttributes() const { return fInstanceAttributes; }
172 
hasVertexAttributes()173     bool hasVertexAttributes() const { return SkToBool(fVertexAttributes.fCount); }
hasInstanceAttributes()174     bool hasInstanceAttributes() const { return SkToBool(fInstanceAttributes.fCount); }
175 
176     /**
177      * A common practice is to populate the the vertex/instance's memory using an implicit array of
178      * structs. In this case, it is best to assert that:
179      *     stride == sizeof(struct)
180      */
vertexStride()181     size_t vertexStride() const { return fVertexAttributes.fStride; }
instanceStride()182     size_t instanceStride() const { return fInstanceAttributes.fStride; }
183 
willUseTessellationShaders()184     bool willUseTessellationShaders() const {
185         return fShaders & (kTessControl_GrShaderFlag | kTessEvaluation_GrShaderFlag);
186     }
187 
188     /**
189      * Computes a key for the transforms owned by an FP based on the shader code that will be
190      * emitted by the primitive processor to implement them.
191      */
192     static uint32_t ComputeCoordTransformsKey(const GrFragmentProcessor& fp);
193 
194     inline static constexpr int kCoordTransformKeyBits = 4;
195 
196     /**
197      * Adds a key on the GrProcessorKeyBuilder that reflects any variety in the code that the
198      * geometry processor subclass can emit.
199      */
200     virtual void addToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const = 0;
201 
getAttributeKey(GrProcessorKeyBuilder * b)202     void getAttributeKey(GrProcessorKeyBuilder* b) const {
203         // Ensure that our CPU and GPU type fields fit together in a 32-bit value, and we never
204         // collide with the "uninitialized" value.
205         static_assert(kGrVertexAttribTypeCount < (1 << 8), "");
206         static_assert(kGrSLTypeCount           < (1 << 8), "");
207 
208         auto add_attributes = [=](const Attribute* attrs, int attrCount) {
209             for (int i = 0; i < attrCount; ++i) {
210                 const Attribute& attr = attrs[i];
211                 b->appendComment(attr.isInitialized() ? attr.name() : "unusedAttr");
212                 b->addBits(8, attr.isInitialized() ? attr.cpuType() : 0xff, "attrType");
213                 b->addBits(8, attr.isInitialized() ? attr.gpuType() : 0xff, "attrGpuType");
214             }
215         };
216         b->add32(fVertexAttributes.fRawCount, "numVertexAttributes");
217         add_attributes(fVertexAttributes.fAttributes, fVertexAttributes.fRawCount);
218         b->add32(fInstanceAttributes.fRawCount, "numInstanceAttributes");
219         add_attributes(fInstanceAttributes.fAttributes, fInstanceAttributes.fRawCount);
220     }
221 
222     /**
223      * Returns a new instance of the appropriate implementation class for the given
224      * GrGeometryProcessor.
225      */
226     virtual std::unique_ptr<ProgramImpl> makeProgramImpl(const GrShaderCaps&) const = 0;
227 
228 protected:
229     // GPs that need to use either float or ubyte colors can just call this to get a correctly
230     // configured Attribute struct
MakeColorAttribute(const char * name,bool wideColor)231     static Attribute MakeColorAttribute(const char* name, bool wideColor) {
232         return { name,
233                  wideColor ? kFloat4_GrVertexAttribType : kUByte4_norm_GrVertexAttribType,
234                  kHalf4_GrSLType };
235     }
236 
setVertexAttributes(const Attribute * attrs,int attrCount)237     void setVertexAttributes(const Attribute* attrs, int attrCount) {
238         fVertexAttributes.init(attrs, attrCount);
239     }
setInstanceAttributes(const Attribute * attrs,int attrCount)240     void setInstanceAttributes(const Attribute* attrs, int attrCount) {
241         SkASSERT(attrCount >= 0);
242         fInstanceAttributes.init(attrs, attrCount);
243     }
setWillUseTessellationShaders()244     void setWillUseTessellationShaders() {
245         fShaders |= kTessControl_GrShaderFlag | kTessEvaluation_GrShaderFlag;
246     }
setTextureSamplerCnt(int cnt)247     void setTextureSamplerCnt(int cnt) {
248         SkASSERT(cnt >= 0);
249         fTextureSamplerCnt = cnt;
250     }
251 
252     /**
253      * Helper for implementing onTextureSampler(). E.g.:
254      * return IthTexureSampler(i, fMyFirstSampler, fMySecondSampler, fMyThirdSampler);
255      */
256     template <typename... Args>
IthTextureSampler(int i,const TextureSampler & samp0,const Args &...samps)257     static const TextureSampler& IthTextureSampler(int i, const TextureSampler& samp0,
258                                                    const Args&... samps) {
259         return (0 == i) ? samp0 : IthTextureSampler(i - 1, samps...);
260     }
261     inline static const TextureSampler& IthTextureSampler(int i);
262 
263 private:
onTextureSampler(int)264     virtual const TextureSampler& onTextureSampler(int) const { return IthTextureSampler(0); }
265 
266     GrShaderFlags fShaders = kVertex_GrShaderFlag | kFragment_GrShaderFlag;
267 
268     AttributeSet fVertexAttributes;
269     AttributeSet fInstanceAttributes;
270 
271     int fTextureSamplerCnt = 0;
272     using INHERITED = GrProcessor;
273 };
274 
275 //////////////////////////////////////////////////////////////////////////////
276 
277 class GrGeometryProcessor::ProgramImpl {
278 public:
279     using UniformHandle = GrGLSLProgramDataManager::UniformHandle;
280     using SamplerHandle = GrGLSLUniformHandler::SamplerHandle;
281     /**
282      * Struct of optional varying that replaces the input coords and bool indicating whether the FP
283      * should take a coord param as an argument. The latter may be false if the coords are simply
284      * unused or if the GP has lifted their computation to a varying emitted by the VS.
285      */
286     struct FPCoords {GrShaderVar coordsVarying; bool hasCoordsParam;};
287     using FPCoordsMap = std::unordered_map<const GrFragmentProcessor*, FPCoords>;
288 
289     virtual ~ProgramImpl() = default;
290 
291     struct EmitArgs {
EmitArgsEmitArgs292         EmitArgs(GrGLSLVertexBuilder* vertBuilder,
293                  GrGLSLFPFragmentBuilder* fragBuilder,
294                  GrGLSLVaryingHandler* varyingHandler,
295                  GrGLSLUniformHandler* uniformHandler,
296                  const GrShaderCaps* caps,
297                  const GrGeometryProcessor& geomProc,
298                  const char* outputColor,
299                  const char* outputCoverage,
300                  const SamplerHandle* texSamplers)
301                 : fVertBuilder(vertBuilder)
302                 , fFragBuilder(fragBuilder)
303                 , fVaryingHandler(varyingHandler)
304                 , fUniformHandler(uniformHandler)
305                 , fShaderCaps(caps)
306                 , fGeomProc(geomProc)
307                 , fOutputColor(outputColor)
308                 , fOutputCoverage(outputCoverage)
309                 , fTexSamplers(texSamplers) {}
310         GrGLSLVertexBuilder* fVertBuilder;
311         GrGLSLFPFragmentBuilder* fFragBuilder;
312         GrGLSLVaryingHandler* fVaryingHandler;
313         GrGLSLUniformHandler* fUniformHandler;
314         const GrShaderCaps* fShaderCaps;
315         const GrGeometryProcessor& fGeomProc;
316         const char* fOutputColor;
317         const char* fOutputCoverage;
318         const SamplerHandle* fTexSamplers;
319     };
320 
321     /**
322      * Emits the code from this geometry processor into the shaders. For any FP in the pipeline that
323      * has its input coords implemented by the GP as a varying, the varying will be accessible in
324      * the returned map and should be used when the FP code is emitted.
325      **/
326     FPCoordsMap emitCode(EmitArgs&, const GrPipeline& pipeline);
327 
328     /**
329      * Called after all effect emitCode() functions, to give the processor a chance to write out
330      * additional transformation code now that all uniforms have been emitted.
331      * It generates the final code for assigning transformed coordinates to the varyings recorded
332      * in the call to collectTransforms(). This must happen after FP code emission so that it has
333      * access to any uniforms the FPs registered for uniform sample matrix invocations.
334      */
335     void emitTransformCode(GrGLSLVertexBuilder* vb, GrGLSLUniformHandler* uniformHandler);
336 
337     /**
338      * A ProgramImpl instance can be reused with any GrGeometryProcessor that produces the same key.
339      * This function reads data from a GrGeometryProcessor and updates any uniform variables
340      * required by the shaders created in emitCode(). The GrGeometryProcessor parameter is
341      * guaranteed to be of the same type and to have an identical processor key as the
342      * GrGeometryProcessor that created this ProgramImpl.
343      */
344     virtual void setData(const GrGLSLProgramDataManager&,
345                          const GrShaderCaps&,
346                          const GrGeometryProcessor&) = 0;
347 
348     // We use these methods as a temporary back door to inject OpenGL tessellation code. Once
349     // tessellation is supported by SkSL we can remove these.
getTessControlShaderGLSL(const GrGeometryProcessor &,const char * versionAndExtensionDecls,const GrGLSLUniformHandler &,const GrShaderCaps &)350     virtual SkString getTessControlShaderGLSL(const GrGeometryProcessor&,
351                                               const char* versionAndExtensionDecls,
352                                               const GrGLSLUniformHandler&,
353                                               const GrShaderCaps&) const {
354         SK_ABORT("Not implemented.");
355     }
getTessEvaluationShaderGLSL(const GrGeometryProcessor &,const char * versionAndExtensionDecls,const GrGLSLUniformHandler &,const GrShaderCaps &)356     virtual SkString getTessEvaluationShaderGLSL(const GrGeometryProcessor&,
357                                                  const char* versionAndExtensionDecls,
358                                                  const GrGLSLUniformHandler&,
359                                                  const GrShaderCaps&) const {
360         SK_ABORT("Not implemented.");
361     }
362 
363     // GPs that use writeOutputPosition and/or writeLocalCoord must incorporate the matrix type
364     // into their key, and should use this function or one of the other related helpers.
ComputeMatrixKey(const GrShaderCaps & caps,const SkMatrix & mat)365     static uint32_t ComputeMatrixKey(const GrShaderCaps& caps, const SkMatrix& mat) {
366         if (!caps.reducedShaderMode()) {
367             if (mat.isIdentity()) {
368                 return 0b00;
369             }
370             if (mat.isScaleTranslate()) {
371                 return 0b01;
372             }
373         }
374         if (!mat.hasPerspective()) {
375             return 0b10;
376         }
377         return 0b11;
378     }
379 
ComputeMatrixKeys(const GrShaderCaps & shaderCaps,const SkMatrix & viewMatrix,const SkMatrix & localMatrix)380     static uint32_t ComputeMatrixKeys(const GrShaderCaps& shaderCaps,
381                                       const SkMatrix& viewMatrix,
382                                       const SkMatrix& localMatrix) {
383         return (ComputeMatrixKey(shaderCaps, viewMatrix) << kMatrixKeyBits) |
384                ComputeMatrixKey(shaderCaps, localMatrix);
385     }
386 
AddMatrixKeys(const GrShaderCaps & shaderCaps,uint32_t flags,const SkMatrix & viewMatrix,const SkMatrix & localMatrix)387     static uint32_t AddMatrixKeys(const GrShaderCaps& shaderCaps,
388                                   uint32_t flags,
389                                   const SkMatrix& viewMatrix,
390                                   const SkMatrix& localMatrix) {
391         // Shifting to make room for the matrix keys shouldn't lose bits
392         SkASSERT(((flags << (2 * kMatrixKeyBits)) >> (2 * kMatrixKeyBits)) == flags);
393         return (flags << (2 * kMatrixKeyBits)) |
394                ComputeMatrixKeys(shaderCaps, viewMatrix, localMatrix);
395     }
396     inline static constexpr int kMatrixKeyBits = 2;
397 
398 protected:
399     void setupUniformColor(GrGLSLFPFragmentBuilder* fragBuilder,
400                            GrGLSLUniformHandler* uniformHandler,
401                            const char* outputName,
402                            UniformHandle* colorUniform);
403 
404     // A helper for setting the matrix on a uniform handle initialized through
405     // writeOutputPosition or writeLocalCoord. Automatically handles elided uniforms,
406     // scale+translate matrices, and state tracking (if provided state pointer is non-null).
407     static void SetTransform(const GrGLSLProgramDataManager&,
408                              const GrShaderCaps&,
409                              const UniformHandle& uniform,
410                              const SkMatrix& matrix,
411                              SkMatrix* state = nullptr);
412 
413     struct GrGPArgs {
414         // Used to specify the output variable used by the GP to store its device position. It can
415         // either be a float2 or a float3 (in order to handle perspective). The subclass sets this
416         // in its onEmitCode().
417         GrShaderVar fPositionVar;
418         // Used to specify the variable storing the draw's local coordinates. It can be either a
419         // float2, float3, or void. It can only be void when no FP needs local coordinates. This
420         // variable can be an attribute or local variable, but should not itself be a varying.
421         // ProgramImpl automatically determines if this must be passed to a FS.
422         GrShaderVar fLocalCoordVar;
423     };
424 
425     // Helpers for adding code to write the transformed vertex position. The first simple version
426     // just writes a variable named by 'posName' into the position output variable with the
427     // assumption that the position is 2D. The second version transforms the input position by a
428     // view matrix and the output variable is 2D or 3D depending on whether the view matrix is
429     // perspective. Both versions declare the output position variable and will set
430     // GrGPArgs::fPositionVar.
431     static void WriteOutputPosition(GrGLSLVertexBuilder*, GrGPArgs*, const char* posName);
432     static void WriteOutputPosition(GrGLSLVertexBuilder*,
433                                     GrGLSLUniformHandler*,
434                                     const GrShaderCaps&,
435                                     GrGPArgs*,
436                                     const char* posName,
437                                     const SkMatrix& viewMatrix,
438                                     UniformHandle* viewMatrixUniform);
439 
440     // Helper to transform an existing variable by a given local matrix (e.g. the inverse view
441     // matrix). It will declare the transformed local coord variable and will set
442     // GrGPArgs::fLocalCoordVar.
443     static void WriteLocalCoord(GrGLSLVertexBuilder*,
444                                 GrGLSLUniformHandler*,
445                                 const GrShaderCaps&,
446                                 GrGPArgs*,
447                                 GrShaderVar localVar,
448                                 const SkMatrix& localMatrix,
449                                 UniformHandle* localMatrixUniform);
450 
451 private:
452     virtual void onEmitCode(EmitArgs&, GrGPArgs*) = 0;
453 
454     // Iterates over the FPs beginning with the passed iter to register additional varyings and
455     // uniforms to support VS-promoted local coord evaluation for the FPs.
456     //
457     // This must happen before FP code emission so that the FPs can find the appropriate varying
458     // handles they use in place of explicit coord sampling; it is automatically called after
459     // onEmitCode() returns using the value stored in GpArgs::fLocalCoordVar and
460     // GpArgs::fPositionVar.
461     FPCoordsMap collectTransforms(GrGLSLVertexBuilder* vb,
462                                   GrGLSLVaryingHandler* varyingHandler,
463                                   GrGLSLUniformHandler* uniformHandler,
464                                   const GrShaderVar& localCoordsVar,
465                                   const GrShaderVar& positionVar,
466                                   const GrPipeline& pipeline);
467     struct TransformInfo {
468         // The varying that conveys the coordinates to one or more FPs in the FS.
469         GrGLSLVarying varying;
470         // The coordinate to be transformed. varying is computed from this.
471         GrShaderVar   inputCoords;
472         // Used to sort so that ancestor FP varyings are initialized before descendant FP varyings.
473         int           traversalOrder;
474     };
475     // Populated by collectTransforms() for use in emitTransformCode(). When we lift the computation
476     // of a FP's input coord to a varying we propagate that varying up the FP tree to the highest
477     // node that shares the same coordinates. This allows multiple FPs in a subtree to share a
478     // varying.
479     std::unordered_map<const GrFragmentProcessor*, TransformInfo> fTransformVaryingsMap;
480 };
481 
482 ///////////////////////////////////////////////////////////////////////////
483 
484 /**
485  * Used to capture the properties of the GrTextureProxies required/expected by a primitiveProcessor
486  * along with an associated GrSamplerState. The actual proxies used are stored in either the
487  * fixed or dynamic state arrays. TextureSamplers don't perform any coord manipulation to account
488  * for texture origin.
489  */
490 class GrGeometryProcessor::TextureSampler {
491 public:
492     TextureSampler() = default;
493 
494     TextureSampler(GrSamplerState, const GrBackendFormat&, const GrSwizzle&);
495 
496     TextureSampler(const TextureSampler&) = delete;
497     TextureSampler& operator=(const TextureSampler&) = delete;
498 
499     void reset(GrSamplerState, const GrBackendFormat&, const GrSwizzle&);
500 
backendFormat()501     const GrBackendFormat& backendFormat() const { return fBackendFormat; }
textureType()502     GrTextureType textureType() const { return fBackendFormat.textureType(); }
503 
samplerState()504     GrSamplerState samplerState() const { return fSamplerState; }
swizzle()505     const GrSwizzle& swizzle() const { return fSwizzle; }
506 
isInitialized()507     bool isInitialized() const { return fIsInitialized; }
508 
509 private:
510     GrSamplerState  fSamplerState;
511     GrBackendFormat fBackendFormat;
512     GrSwizzle       fSwizzle;
513     bool            fIsInitialized = false;
514 };
515 
IthTextureSampler(int i)516 const GrGeometryProcessor::TextureSampler& GrGeometryProcessor::IthTextureSampler(int i) {
517     SK_ABORT("Illegal texture sampler index");
518     static const TextureSampler kBogus;
519     return kBogus;
520 }
521 
522 //////////////////////////////////////////////////////////////////////////////
523 
524 /**
525  * Returns the size of the attrib type in bytes.
526  * This was moved from include/private/GrTypesPriv.h in service of Skia dependents that build
527  * with C++11.
528  */
GrVertexAttribTypeSize(GrVertexAttribType type)529 static constexpr inline size_t GrVertexAttribTypeSize(GrVertexAttribType type) {
530     switch (type) {
531         case kFloat_GrVertexAttribType:
532             return sizeof(float);
533         case kFloat2_GrVertexAttribType:
534             return 2 * sizeof(float);
535         case kFloat3_GrVertexAttribType:
536             return 3 * sizeof(float);
537         case kFloat4_GrVertexAttribType:
538             return 4 * sizeof(float);
539         case kHalf_GrVertexAttribType:
540             return sizeof(uint16_t);
541         case kHalf2_GrVertexAttribType:
542             return 2 * sizeof(uint16_t);
543         case kHalf4_GrVertexAttribType:
544             return 4 * sizeof(uint16_t);
545         case kInt2_GrVertexAttribType:
546             return 2 * sizeof(int32_t);
547         case kInt3_GrVertexAttribType:
548             return 3 * sizeof(int32_t);
549         case kInt4_GrVertexAttribType:
550             return 4 * sizeof(int32_t);
551         case kByte_GrVertexAttribType:
552             return 1 * sizeof(char);
553         case kByte2_GrVertexAttribType:
554             return 2 * sizeof(char);
555         case kByte4_GrVertexAttribType:
556             return 4 * sizeof(char);
557         case kUByte_GrVertexAttribType:
558             return 1 * sizeof(char);
559         case kUByte2_GrVertexAttribType:
560             return 2 * sizeof(char);
561         case kUByte4_GrVertexAttribType:
562             return 4 * sizeof(char);
563         case kUByte_norm_GrVertexAttribType:
564             return 1 * sizeof(char);
565         case kUByte4_norm_GrVertexAttribType:
566             return 4 * sizeof(char);
567         case kShort2_GrVertexAttribType:
568             return 2 * sizeof(int16_t);
569         case kShort4_GrVertexAttribType:
570             return 4 * sizeof(int16_t);
571         case kUShort2_GrVertexAttribType: // fall through
572         case kUShort2_norm_GrVertexAttribType:
573             return 2 * sizeof(uint16_t);
574         case kInt_GrVertexAttribType:
575             return sizeof(int32_t);
576         case kUInt_GrVertexAttribType:
577             return sizeof(uint32_t);
578         case kUShort_norm_GrVertexAttribType:
579             return sizeof(uint16_t);
580         case kUShort4_norm_GrVertexAttribType:
581             return 4 * sizeof(uint16_t);
582     }
583     // GCC fails because SK_ABORT evaluates to non constexpr. clang and cl.exe think this is
584     // unreachable and don't complain.
585 #if defined(__clang__) || !defined(__GNUC__)
586     SK_ABORT("Unsupported type conversion");
587 #endif
588     return 0;
589 }
590 
size()591 constexpr size_t GrGeometryProcessor::Attribute::size() const {
592     return GrVertexAttribTypeSize(fCPUType);
593 }
594 
595 #endif
596