| /* | 
 |  * 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 GrGLProgramDesc_DEFINED | 
 | #define GrGLProgramDesc_DEFINED | 
 |  | 
 | #include "GrGLEffect.h" | 
 | #include "GrDrawState.h" | 
 | #include "GrGpu.h" | 
 |  | 
 | class GrGpuGL; | 
 |  | 
 | #ifdef SK_DEBUG | 
 |   // Optionally compile the experimental GS code. Set to SK_DEBUG so that debug build bots will | 
 |   // execute the code. | 
 |   #define GR_GL_EXPERIMENTAL_GS 1 | 
 | #else | 
 |   #define GR_GL_EXPERIMENTAL_GS 0 | 
 | #endif | 
 |  | 
 |  | 
 | /** This class describes a program to generate. It also serves as a program cache key. Very little | 
 |     of this is GL-specific. The GL-specific parts could be factored out into a subclass. */ | 
 | class GrGLProgramDesc { | 
 | public: | 
 |     GrGLProgramDesc() {} | 
 |     GrGLProgramDesc(const GrGLProgramDesc& desc) { *this = desc; } | 
 |  | 
 |     // Returns this as a uint32_t array to be used as a key in the program cache. | 
 |     const uint32_t* asKey() const { | 
 |         return reinterpret_cast<const uint32_t*>(fKey.begin()); | 
 |     } | 
 |  | 
 |     // Gets the number of bytes in asKey(). It will be a 4-byte aligned value. When comparing two | 
 |     // keys the size of either key can be used with memcmp() since the lengths themselves begin the | 
 |     // keys and thus the memcmp will exit early if the keys are of different lengths. | 
 |     uint32_t keyLength() const { return *this->atOffset<uint32_t, kLengthOffset>(); } | 
 |  | 
 |     // Gets the a checksum of the key. Can be used as a hash value for a fast lookup in a cache. | 
 |     uint32_t getChecksum() const { return *this->atOffset<uint32_t, kChecksumOffset>(); } | 
 |  | 
 |     // For unit testing. | 
 |     bool setRandom(SkRandom*, | 
 |                    const GrGpuGL* gpu, | 
 |                    const GrRenderTarget* dummyDstRenderTarget, | 
 |                    const GrTexture* dummyDstCopyTexture, | 
 |                    const GrEffectStage* stages[], | 
 |                    int numColorStages, | 
 |                    int numCoverageStages, | 
 |                    int currAttribIndex); | 
 |  | 
 |     /** | 
 |      * Builds a program descriptor from a GrDrawState. Whether the primitive type is points, the | 
 |      * output of GrDrawState::getBlendOpts, and the caps of the GrGpuGL are also inputs. It also | 
 |      * outputs the color and coverage stages referenced by the generated descriptor. This may | 
 |      * not contain all stages from the draw state and coverage stages from the drawState may | 
 |      * be treated as color stages in the output. | 
 |      */ | 
 |     static bool Build(const GrDrawState&, | 
 |                       GrGpu::DrawType drawType, | 
 |                       GrDrawState::BlendOptFlags, | 
 |                       GrBlendCoeff srcCoeff, | 
 |                       GrBlendCoeff dstCoeff, | 
 |                       const GrGpuGL* gpu, | 
 |                       const GrDeviceCoordTexture* dstCopy, | 
 |                       SkTArray<const GrEffectStage*, true>* outColorStages, | 
 |                       SkTArray<const GrEffectStage*, true>* outCoverageStages, | 
 |                       GrGLProgramDesc* outDesc); | 
 |  | 
 |     int numColorEffects() const { | 
 |         return this->getHeader().fColorEffectCnt; | 
 |     } | 
 |  | 
 |     int numCoverageEffects() const { | 
 |         return this->getHeader().fCoverageEffectCnt; | 
 |     } | 
 |  | 
 |     int numTotalEffects() const { return this->numColorEffects() + this->numCoverageEffects(); } | 
 |  | 
 |     GrGLProgramDesc& operator= (const GrGLProgramDesc& other); | 
 |  | 
 |     bool operator== (const GrGLProgramDesc& other) const { | 
 |         // The length is masked as a hint to the compiler that the address will be 4 byte aligned. | 
 |         return 0 == memcmp(this->asKey(), other.asKey(), this->keyLength() & ~0x3); | 
 |     } | 
 |  | 
 |     bool operator!= (const GrGLProgramDesc& other) const { | 
 |         return !(*this == other); | 
 |     } | 
 |  | 
 |     static bool Less(const GrGLProgramDesc& a, const GrGLProgramDesc& b) { | 
 |         return memcmp(a.asKey(), b.asKey(), a.keyLength() & ~0x3) < 0; | 
 |     } | 
 |  | 
 | private: | 
 |     // Specifies where the initial color comes from before the stages are applied. | 
 |     enum ColorInput { | 
 |         kSolidWhite_ColorInput, | 
 |         kAttribute_ColorInput, | 
 |         kUniform_ColorInput, | 
 |  | 
 |         kColorInputCnt | 
 |     }; | 
 |  | 
 |     enum CoverageOutput { | 
 |         // modulate color and coverage, write result as the color output. | 
 |         kModulate_CoverageOutput, | 
 |         // Writes color*coverage as the primary color output and also writes coverage as the | 
 |         // secondary output. Only set if dual source blending is supported. | 
 |         kSecondaryCoverage_CoverageOutput, | 
 |         // Writes color*coverage as the primary color output and also writes coverage * (1 - colorA) | 
 |         // as the secondary output. Only set if dual source blending is supported. | 
 |         kSecondaryCoverageISA_CoverageOutput, | 
 |         // Writes color*coverage as the primary color output and also writes coverage * | 
 |         // (1 - colorRGB) as the secondary output. Only set if dual source blending is supported. | 
 |         kSecondaryCoverageISC_CoverageOutput, | 
 |         // Combines the coverage, dst, and color as coverage * color + (1 - coverage) * dst. This | 
 |         // can only be set if fDstReadKey is non-zero. | 
 |         kCombineWithDst_CoverageOutput, | 
 |  | 
 |         kCoverageOutputCnt | 
 |     }; | 
 |  | 
 |     static bool CoverageOutputUsesSecondaryOutput(CoverageOutput co) { | 
 |         switch (co) { | 
 |             case kSecondaryCoverage_CoverageOutput: //  fallthru | 
 |             case kSecondaryCoverageISA_CoverageOutput: | 
 |             case kSecondaryCoverageISC_CoverageOutput: | 
 |                 return true; | 
 |             default: | 
 |                 return false; | 
 |         } | 
 |     } | 
 |  | 
 |     struct KeyHeader { | 
 |         uint8_t                     fDstReadKey;        // set by GrGLShaderBuilder if there | 
 |                                                         // are effects that must read the dst. | 
 |                                                         // Otherwise, 0. | 
 |         uint8_t                     fFragPosKey;        // set by GrGLShaderBuilder if there are | 
 |                                                         // effects that read the fragment position. | 
 |                                                         // Otherwise, 0. | 
 |         ColorInput                  fColorInput : 8; | 
 |         ColorInput                  fCoverageInput : 8; | 
 |         CoverageOutput              fCoverageOutput : 8; | 
 |  | 
 |         SkBool8                     fHasVertexCode; | 
 |         SkBool8                     fEmitsPointSize; | 
 |  | 
 |         // To enable experimental geometry shader code (not for use in | 
 |         // production) | 
 | #if GR_GL_EXPERIMENTAL_GS | 
 |         SkBool8                     fExperimentalGS; | 
 | #endif | 
 |  | 
 |         int8_t                      fPositionAttributeIndex; | 
 |         int8_t                      fLocalCoordAttributeIndex; | 
 |         int8_t                      fColorAttributeIndex; | 
 |         int8_t                      fCoverageAttributeIndex; | 
 |  | 
 |         int8_t                      fColorEffectCnt; | 
 |         int8_t                      fCoverageEffectCnt; | 
 |     }; | 
 |  | 
 |     // The key, stored in fKey, is composed of five parts: | 
 |     // 1. uint32_t for total key length. | 
 |     // 2. uint32_t for a checksum. | 
 |     // 3. Header struct defined above. | 
 |     // 4. An array of offsets to effect keys and their sizes (see 5). uint16_t for each | 
 |     //    offset and size. | 
 |     // 5. per-effect keys. Each effect's key is a variable length array of uint32_t. | 
 |     enum { | 
 |         // Part 1. | 
 |         kLengthOffset = 0, | 
 |         // Part 2. | 
 |         kChecksumOffset = kLengthOffset + sizeof(uint32_t), | 
 |         // Part 3. | 
 |         kHeaderOffset = kChecksumOffset + sizeof(uint32_t), | 
 |         kHeaderSize = SkAlign4(sizeof(KeyHeader)), | 
 |         // Part 4. | 
 |         // This is the offset in the overall key to the array of per-effect offset,length pairs. | 
 |         kEffectKeyOffsetsAndLengthOffset = kHeaderOffset + kHeaderSize, | 
 |     }; | 
 |  | 
 |     template<typename T, size_t OFFSET> T* atOffset() { | 
 |         return reinterpret_cast<T*>(reinterpret_cast<intptr_t>(fKey.begin()) + OFFSET); | 
 |     } | 
 |  | 
 |     template<typename T, size_t OFFSET> const T* atOffset() const { | 
 |         return reinterpret_cast<const T*>(reinterpret_cast<intptr_t>(fKey.begin()) + OFFSET); | 
 |     } | 
 |  | 
 |     KeyHeader* header() { return this->atOffset<KeyHeader, kHeaderOffset>(); } | 
 |  | 
 |     // Shared code between setRandom() and Build(). | 
 |     static bool GetEffectKeyAndUpdateStats(const GrEffectStage& stage, | 
 |                                            const GrGLCaps& caps, | 
 |                                            bool useExplicitLocalCoords, | 
 |                                            GrEffectKeyBuilder* b, | 
 |                                            uint16_t* effectKeySize, | 
 |                                            bool* setTrueIfReadsDst, | 
 |                                            bool* setTrueIfReadsPos, | 
 |                                            bool* setTrueIfHasVertexCode); | 
 |  | 
 |     void finalize(); | 
 |  | 
 |     const KeyHeader& getHeader() const { return *this->atOffset<KeyHeader, kHeaderOffset>(); } | 
 |  | 
 |     /** Used to provide effects' keys to their emitCode() function. */ | 
 |     class EffectKeyProvider { | 
 |     public: | 
 |         enum EffectType { | 
 |             kColor_EffectType, | 
 |             kCoverage_EffectType, | 
 |         }; | 
 |  | 
 |         EffectKeyProvider(const GrGLProgramDesc* desc, EffectType type) : fDesc(desc) { | 
 |             // Coverage effect key offsets begin immediately after those of the color effects. | 
 |             fBaseIndex = kColor_EffectType == type ? 0 : desc->numColorEffects(); | 
 |         } | 
 |  | 
 |         GrEffectKey get(int index) const { | 
 |             const uint16_t* offsetsAndLengths = reinterpret_cast<const uint16_t*>( | 
 |                 fDesc->fKey.begin() + kEffectKeyOffsetsAndLengthOffset); | 
 |             // We store two uint16_ts per effect, one for the offset to the effect's key and one for | 
 |             // its length. Here we just need the offset. | 
 |             uint16_t offset = offsetsAndLengths[2 * (fBaseIndex + index) + 0]; | 
 |             uint16_t length = offsetsAndLengths[2 * (fBaseIndex + index) + 1]; | 
 |             // Currently effects must add to the key in units of uint32_t. | 
 |             SkASSERT(0 == (length % sizeof(uint32_t))); | 
 |             return GrEffectKey(reinterpret_cast<const uint32_t*>(fDesc->fKey.begin() + offset), | 
 |                                length / sizeof(uint32_t)); | 
 |         } | 
 |     private: | 
 |         const GrGLProgramDesc*  fDesc; | 
 |         int                     fBaseIndex; | 
 |     }; | 
 |  | 
 |     enum { | 
 |         kMaxPreallocEffects = 8, | 
 |         kIntsPerEffect      = 4,    // This is an overestimate of the average effect key size. | 
 |         kPreAllocSize = kEffectKeyOffsetsAndLengthOffset + | 
 |                         kMaxPreallocEffects * sizeof(uint32_t) * kIntsPerEffect, | 
 |     }; | 
 |  | 
 |     SkSTArray<kPreAllocSize, uint8_t, true> fKey; | 
 |  | 
 |     // GrGLProgram and GrGLShaderBuilder read the private fields to generate code. TODO: Split out | 
 |     // part of GrGLShaderBuilder that is used by effects so that this header doesn't need to be | 
 |     // visible to GrGLEffects. Then make public accessors as necessary and remove friends. | 
 |     friend class GrGLProgram; | 
 |     friend class GrGLShaderBuilder; | 
 |     friend class GrGLFullShaderBuilder; | 
 |     friend class GrGLFragmentOnlyShaderBuilder; | 
 | }; | 
 |  | 
 | #endif |