| /* | 
 |  * Copyright 2013 Google Inc. | 
 |  * | 
 |  * Use of this source code is governed by a BSD-style license that can be | 
 |  * found in the LICENSE file. | 
 |  */ | 
 |  | 
 | #ifndef GrPrimitiveProcessor_DEFINED | 
 | #define GrPrimitiveProcessor_DEFINED | 
 |  | 
 | #include "GrColor.h" | 
 | #include "GrNonAtomicRef.h" | 
 | #include "GrProcessor.h" | 
 | #include "GrProxyRef.h" | 
 | #include "GrShaderVar.h" | 
 |  | 
 | class GrCoordTransform; | 
 |  | 
 | /* | 
 |  * The GrPrimitiveProcessor represents some kind of geometric primitive.  This includes the shape | 
 |  * of the primitive and the inherent color of the primitive.  The GrPrimitiveProcessor is | 
 |  * responsible for providing a color and coverage input into the Ganesh rendering pipeline.  Through | 
 |  * optimization, Ganesh may decide a different color, no color, and / or no coverage are required | 
 |  * from the GrPrimitiveProcessor, so the GrPrimitiveProcessor must be able to support this | 
 |  * functionality. | 
 |  * | 
 |  * There are two feedback loops between the GrFragmentProcessors, the GrXferProcessor, and the | 
 |  * GrPrimitiveProcessor. These loops run on the CPU and to determine known properties of the final | 
 |  * color and coverage inputs to the GrXferProcessor in order to perform optimizations that preserve | 
 |  * correctness. The GrDrawOp seeds these loops with initial color and coverage, in its | 
 |  * getProcessorAnalysisInputs implementation. These seed values are processed by the | 
 |  * subsequent | 
 |  * stages of the rendering pipeline and the output is then fed back into the GrDrawOp in | 
 |  * the applyPipelineOptimizations call, where the op can use the information to inform decisions | 
 |  * about GrPrimitiveProcessor creation. | 
 |  */ | 
 |  | 
 | class GrGLSLPrimitiveProcessor; | 
 |  | 
 | /** | 
 |  * GrPrimitiveProcessor defines an interface which all subclasses must implement.  All | 
 |  * GrPrimitiveProcessors must proivide seed color and coverage for the Ganesh color / coverage | 
 |  * pipelines, and they must provide some notion of equality | 
 |  * | 
 |  * TODO: This class does not really need to be ref counted. Instances should be allocated using | 
 |  * GrOpFlushState's arena and destroyed when the arena is torn down. | 
 |  */ | 
 | class GrPrimitiveProcessor : public GrProcessor, public GrNonAtomicRef<GrPrimitiveProcessor> { | 
 | public: | 
 |     class TextureSampler; | 
 |  | 
 |     /** Describes a vertex or instance attribute. */ | 
 |     class Attribute { | 
 |     public: | 
 |         constexpr Attribute() = default; | 
 |         constexpr Attribute(const char* name, | 
 |                             GrVertexAttribType cpuType, | 
 |                             GrSLType gpuType) | 
 |             : fName(name), fCPUType(cpuType), fGPUType(gpuType) {} | 
 |         constexpr Attribute(const Attribute&) = default; | 
 |  | 
 |         Attribute& operator=(const Attribute&) = default; | 
 |  | 
 |         constexpr bool isInitialized() const { return SkToBool(fName); } | 
 |  | 
 |         constexpr const char* name() const { return fName; } | 
 |         constexpr GrVertexAttribType cpuType() const { return fCPUType; } | 
 |         constexpr GrSLType           gpuType() const { return fGPUType; } | 
 |  | 
 |         inline constexpr size_t size() const; | 
 |         constexpr size_t sizeAlign4() const { return SkAlign4(this->size()); } | 
 |  | 
 |         GrShaderVar asShaderVar() const { | 
 |             return {fName, fGPUType, GrShaderVar::kIn_TypeModifier}; | 
 |         } | 
 |  | 
 |     private: | 
 |         const char* fName = nullptr; | 
 |         GrVertexAttribType fCPUType = kFloat_GrVertexAttribType; | 
 |         GrSLType fGPUType = kFloat_GrSLType; | 
 |     }; | 
 |  | 
 |     class Iter { | 
 |     public: | 
 |         Iter() : fCurr(nullptr), fRemaining(0) {} | 
 |         Iter(const Iter& iter) : fCurr(iter.fCurr), fRemaining(iter.fRemaining) {} | 
 |         Iter& operator= (const Iter& iter) { | 
 |             fCurr = iter.fCurr; | 
 |             fRemaining = iter.fRemaining; | 
 |             return *this; | 
 |         } | 
 |         Iter(const Attribute* attrs, int count) : fCurr(attrs), fRemaining(count) { | 
 |             this->skipUninitialized(); | 
 |         } | 
 |  | 
 |         bool operator!=(const Iter& that) const { return fCurr != that.fCurr; } | 
 |         const Attribute& operator*() const { return *fCurr; } | 
 |         void operator++() { | 
 |             if (fRemaining) { | 
 |                 fRemaining--; | 
 |                 fCurr++; | 
 |                 this->skipUninitialized(); | 
 |             } | 
 |         } | 
 |  | 
 |     private: | 
 |         void skipUninitialized() { | 
 |             if (!fRemaining) { | 
 |                 fCurr = nullptr; | 
 |             } else { | 
 |                 while (!fCurr->isInitialized()) { | 
 |                     ++fCurr; | 
 |                 } | 
 |             } | 
 |         } | 
 |  | 
 |         const Attribute* fCurr; | 
 |         int fRemaining; | 
 |     }; | 
 |  | 
 |     class AttributeSet { | 
 |     public: | 
 |         Iter begin() const { return Iter(fAttributes, fCount); } | 
 |         Iter end() const { return Iter(); } | 
 |  | 
 |     private: | 
 |         friend class GrPrimitiveProcessor; | 
 |  | 
 |         void init(const Attribute* attrs, int count) { | 
 |             fAttributes = attrs; | 
 |             fRawCount = count; | 
 |             fCount = 0; | 
 |             fStride = 0; | 
 |             for (int i = 0; i < count; ++i) { | 
 |                 if (attrs[i].isInitialized()) { | 
 |                     fCount++; | 
 |                     fStride += attrs[i].sizeAlign4(); | 
 |                 } | 
 |             } | 
 |         } | 
 |  | 
 |         const Attribute* fAttributes = nullptr; | 
 |         int              fRawCount = 0; | 
 |         int              fCount = 0; | 
 |         size_t           fStride = 0; | 
 |     }; | 
 |  | 
 |     GrPrimitiveProcessor(ClassID); | 
 |  | 
 |     int numTextureSamplers() const { return fTextureSamplerCnt; } | 
 |     const TextureSampler& textureSampler(int index) const; | 
 |     int numVertexAttributes() const { return fVertexAttributes.fCount; } | 
 |     const AttributeSet& vertexAttributes() const { return fVertexAttributes; } | 
 |     int numInstanceAttributes() const { return fInstanceAttributes.fCount; } | 
 |     const AttributeSet& instanceAttributes() const { return fInstanceAttributes; } | 
 |  | 
 |     bool hasVertexAttributes() const { return SkToBool(fVertexAttributes.fCount); } | 
 |     bool hasInstanceAttributes() const { return SkToBool(fInstanceAttributes.fCount); } | 
 |  | 
 |     /** | 
 |      * A common practice is to populate the the vertex/instance's memory using an implicit array of | 
 |      * structs. In this case, it is best to assert that: | 
 |      *     stride == sizeof(struct) | 
 |      */ | 
 |     size_t vertexStride() const { return fVertexAttributes.fStride; } | 
 |     size_t instanceStride() const { return fInstanceAttributes.fStride; } | 
 |  | 
 |     // Only the GrGeometryProcessor subclass actually has a geo shader or vertex attributes, but | 
 |     // we put these calls on the base class to prevent having to cast | 
 |     virtual bool willUseGeoShader() const = 0; | 
 |  | 
 |     /** | 
 |      * Computes a transformKey from an array of coord transforms. Will only look at the first | 
 |      * <numCoords> transforms in the array. | 
 |      * | 
 |      * TODO: A better name for this function  would be "compute" instead of "get". | 
 |      */ | 
 |     uint32_t getTransformKey(const SkTArray<const GrCoordTransform*, true>& coords, | 
 |                              int numCoords) const; | 
 |  | 
 |     /** | 
 |      * Sets a unique key on the GrProcessorKeyBuilder that is directly associated with this geometry | 
 |      * processor's GL backend implementation. | 
 |      * | 
 |      * TODO: A better name for this function  would be "compute" instead of "get". | 
 |      */ | 
 |     virtual void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const = 0; | 
 |  | 
 |  | 
 |     void getAttributeKey(GrProcessorKeyBuilder* b) const { | 
 |         // Ensure that our CPU and GPU type fields fit together in a 32-bit value, and we never | 
 |         // collide with the "uninitialized" value. | 
 |         static_assert(kGrVertexAttribTypeCount < (1 << 8), ""); | 
 |         static_assert(kGrSLTypeCount           < (1 << 8), ""); | 
 |  | 
 |         auto add_attributes = [=](const Attribute* attrs, int attrCount) { | 
 |             for (int i = 0; i < attrCount; ++i) { | 
 |                 b->add32(attrs[i].isInitialized() ? (attrs[i].cpuType() << 16) | attrs[i].gpuType() | 
 |                                                   : ~0); | 
 |             } | 
 |         }; | 
 |         add_attributes(fVertexAttributes.fAttributes, fVertexAttributes.fRawCount); | 
 |         add_attributes(fInstanceAttributes.fAttributes, fInstanceAttributes.fRawCount); | 
 |     } | 
 |  | 
 |     /** Returns a new instance of the appropriate *GL* implementation class | 
 |         for the given GrProcessor; caller is responsible for deleting | 
 |         the object. */ | 
 |     virtual GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const = 0; | 
 |  | 
 |     virtual bool isPathRendering() const { return false; } | 
 |  | 
 | protected: | 
 |     void setVertexAttributes(const Attribute* attrs, int attrCount) { | 
 |         fVertexAttributes.init(attrs, attrCount); | 
 |     } | 
 |     void setInstanceAttributes(const Attribute* attrs, int attrCount) { | 
 |         SkASSERT(attrCount >= 0); | 
 |         fInstanceAttributes.init(attrs, attrCount); | 
 |     } | 
 |     void setTextureSamplerCnt(int cnt) { | 
 |         SkASSERT(cnt >= 0); | 
 |         fTextureSamplerCnt = cnt; | 
 |     } | 
 |  | 
 |     /** | 
 |      * Helper for implementing onTextureSampler(). E.g.: | 
 |      * return IthTexureSampler(i, fMyFirstSampler, fMySecondSampler, fMyThirdSampler); | 
 |      */ | 
 |     template <typename... Args> | 
 |     static const TextureSampler& IthTextureSampler(int i, const TextureSampler& samp0, | 
 |                                                    const Args&... samps) { | 
 |         return (0 == i) ? samp0 : IthTextureSampler(i - 1, samps...); | 
 |     } | 
 |     inline static const TextureSampler& IthTextureSampler(int i); | 
 |  | 
 | private: | 
 |     virtual const TextureSampler& onTextureSampler(int) const { return IthTextureSampler(0); } | 
 |  | 
 |     AttributeSet fVertexAttributes; | 
 |     AttributeSet fInstanceAttributes; | 
 |  | 
 |     int fTextureSamplerCnt = 0; | 
 |     typedef GrProcessor INHERITED; | 
 | }; | 
 |  | 
 | ////////////////////////////////////////////////////////////////////////////// | 
 |  | 
 | /** | 
 |  * Used to represent a texture that is required by a GrPrimitiveProcessor. It holds a GrTextureProxy | 
 |  * along with an associated GrSamplerState. TextureSamplers don't perform any coord manipulation to | 
 |  * account for texture origin. | 
 |  */ | 
 | class GrPrimitiveProcessor::TextureSampler { | 
 | public: | 
 |     TextureSampler() = default; | 
 |  | 
 |     TextureSampler(GrTextureType, GrPixelConfig, const GrSamplerState&, uint32_t extraSamplerKey); | 
 |  | 
 |     explicit TextureSampler(GrTextureType, GrPixelConfig, | 
 |                             GrSamplerState::Filter = GrSamplerState::Filter::kNearest, | 
 |                             GrSamplerState::WrapMode wrapXAndY = GrSamplerState::WrapMode::kClamp); | 
 |  | 
 |     TextureSampler(const TextureSampler&) = delete; | 
 |     TextureSampler& operator=(const TextureSampler&) = delete; | 
 |  | 
 |     void reset(GrTextureType, GrPixelConfig, const GrSamplerState&, uint32_t extraSamplerKey = 0); | 
 |     void reset(GrTextureType, GrPixelConfig, | 
 |                GrSamplerState::Filter, | 
 |                GrSamplerState::WrapMode wrapXAndY); | 
 |  | 
 |     GrTextureType textureType() const { return fTextureType; } | 
 |     GrPixelConfig config() const { return fConfig; } | 
 |  | 
 |     const GrSamplerState& samplerState() const { return fSamplerState; } | 
 |  | 
 |     uint32_t extraSamplerKey() const { return fExtraSamplerKey; } | 
 |  | 
 |     bool isInitialized() const { return fConfig != kUnknown_GrPixelConfig; } | 
 |  | 
 | private: | 
 |     GrSamplerState fSamplerState; | 
 |     GrTextureType fTextureType = GrTextureType::k2D; | 
 |     GrPixelConfig fConfig = kUnknown_GrPixelConfig; | 
 |     uint32_t fExtraSamplerKey = 0; | 
 | }; | 
 |  | 
 | const GrPrimitiveProcessor::TextureSampler& GrPrimitiveProcessor::IthTextureSampler(int i) { | 
 |     SK_ABORT("Illegal texture sampler index"); | 
 |     static const TextureSampler kBogus; | 
 |     return kBogus; | 
 | } | 
 |  | 
 | ////////////////////////////////////////////////////////////////////////////// | 
 |  | 
 | /** | 
 |  * Returns the size of the attrib type in bytes. | 
 |  * This was moved from include/private/GrTypesPriv.h in service of Skia dependents that build | 
 |  * with C++11. | 
 |  */ | 
 | static constexpr inline size_t GrVertexAttribTypeSize(GrVertexAttribType type) { | 
 |     switch (type) { | 
 |         case kFloat_GrVertexAttribType: | 
 |             return sizeof(float); | 
 |         case kFloat2_GrVertexAttribType: | 
 |             return 2 * sizeof(float); | 
 |         case kFloat3_GrVertexAttribType: | 
 |             return 3 * sizeof(float); | 
 |         case kFloat4_GrVertexAttribType: | 
 |             return 4 * sizeof(float); | 
 |         case kHalf_GrVertexAttribType: | 
 |             return sizeof(uint16_t); | 
 |         case kHalf2_GrVertexAttribType: | 
 |             return 2 * sizeof(uint16_t); | 
 |         case kHalf3_GrVertexAttribType: | 
 |             return 3 * sizeof(uint16_t); | 
 |         case kHalf4_GrVertexAttribType: | 
 |             return 4 * sizeof(uint16_t); | 
 |         case kInt2_GrVertexAttribType: | 
 |             return 2 * sizeof(int32_t); | 
 |         case kInt3_GrVertexAttribType: | 
 |             return 3 * sizeof(int32_t); | 
 |         case kInt4_GrVertexAttribType: | 
 |             return 4 * sizeof(int32_t); | 
 |         case kByte_GrVertexAttribType: | 
 |             return 1 * sizeof(char); | 
 |         case kByte2_GrVertexAttribType: | 
 |             return 2 * sizeof(char); | 
 |         case kByte3_GrVertexAttribType: | 
 |             return 3 * sizeof(char); | 
 |         case kByte4_GrVertexAttribType: | 
 |             return 4 * sizeof(char); | 
 |         case kUByte_GrVertexAttribType: | 
 |             return 1 * sizeof(char); | 
 |         case kUByte2_GrVertexAttribType: | 
 |             return 2 * sizeof(char); | 
 |         case kUByte3_GrVertexAttribType: | 
 |             return 3 * sizeof(char); | 
 |         case kUByte4_GrVertexAttribType: | 
 |             return 4 * sizeof(char); | 
 |         case kUByte_norm_GrVertexAttribType: | 
 |             return 1 * sizeof(char); | 
 |         case kUByte4_norm_GrVertexAttribType: | 
 |             return 4 * sizeof(char); | 
 |         case kShort2_GrVertexAttribType: | 
 |             return 2 * sizeof(int16_t); | 
 |         case kShort4_GrVertexAttribType: | 
 |             return 4 * sizeof(int16_t); | 
 |         case kUShort2_GrVertexAttribType: // fall through | 
 |         case kUShort2_norm_GrVertexAttribType: | 
 |             return 2 * sizeof(uint16_t); | 
 |         case kInt_GrVertexAttribType: | 
 |             return sizeof(int32_t); | 
 |         case kUint_GrVertexAttribType: | 
 |             return sizeof(uint32_t); | 
 |     } | 
 |     // GCC fails because SK_ABORT evaluates to non constexpr. clang and cl.exe think this is | 
 |     // unreachable and don't complain. | 
 | #if defined(__clang__) || !defined(__GNUC__) | 
 |     SK_ABORT("Unsupported type conversion"); | 
 | #endif | 
 |     return 0; | 
 | } | 
 |  | 
 | constexpr size_t GrPrimitiveProcessor::Attribute::size() const { | 
 |     return GrVertexAttribTypeSize(fCPUType); | 
 | } | 
 |  | 
 | #endif |