Chromium Code Reviews| Index: src/gpu/gl/GrGLProgramDesc.h |
| diff --git a/src/gpu/gl/GrGLProgramDesc.h b/src/gpu/gl/GrGLProgramDesc.h |
| index b49cb722c017f0f5b67bcbcb5e3c69bf9ce755db..639e905cac35a78854b543f2b8216b656867a6e9 100644 |
| --- a/src/gpu/gl/GrGLProgramDesc.h |
| +++ b/src/gpu/gl/GrGLProgramDesc.h |
| @@ -25,26 +25,37 @@ class GrGpuGL; |
| to be API-neutral then so could this class. */ |
| class GrGLProgramDesc { |
| public: |
| - GrGLProgramDesc() { |
| - // since we use this as part of a key we can't have any uninitialized padding |
| - memset(this, 0, sizeof(GrGLProgramDesc)); |
| - } |
| + GrGLProgramDesc() : fInitialized(false) {} |
| + GrGLProgramDesc(const GrGLProgramDesc& desc) { *this = desc; } |
| - // Returns this as a uint32_t array to be used as a key in the program cache |
| + // 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*>(this); |
| + GrAssert(fInitialized); |
| + return reinterpret_cast<const uint32_t*>(fKey.get()); |
| } |
| + // 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>(); } |
| + |
|
robertphillips
2013/05/21 19:22:37
hache -> cache
bsalomon
2013/05/22 14:11:25
Done. (actually hash)
|
| + // Gets the a checksum of the key. Can be used as a hache value for a fast lookup in a cache. |
| + uint32_t getChecksum() const { return *this->atOffset<uint32_t, kChecksumOffset>(); } |
| + |
| // For unit testing. |
| void setRandom(SkMWCRandom*, |
| const GrGpuGL* gpu, |
| - const GrTexture* dummyDstTexture, |
| - const GrEffectStage* stages[GrDrawState::kNumStages], |
| + 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. |
| + * output of GrDrawState::getBlendOpts, and the caps of the GrGpuGL are also inputs. It also |
| + * writes a tightly packed array of GrEffectStage* from the drawState. |
| */ |
| static void Build(const GrDrawState&, |
| bool isPoints, |
| @@ -53,8 +64,36 @@ public: |
| GrBlendCoeff dstCoeff, |
| const GrGpuGL* gpu, |
| const GrDeviceCoordTexture* dstCopy, |
| + const GrEffectStage* outStages[GrDrawState::kNumStages], |
| GrGLProgramDesc* outDesc); |
| + int numColorEffects() const { |
| + GrAssert(fInitialized); |
| + return this->getHeader().fColorEffectCnt; |
| + } |
| + |
| + int numCoverageEffects() const { |
| + GrAssert(fInitialized); |
| + return this->getHeader().fCoverageEffectCnt; |
| + } |
| + |
| + int numTotalEffects() const { return this->numColorEffects() + this->numCoverageEffects(); } |
| + |
| + GrGLProgramDesc& operator= (const GrGLProgramDesc& other); |
| + |
| + bool operator== (const GrGLProgramDesc& other) const { |
| + GrAssert(fInitialized && other.fInitialized); |
|
robertphillips
2013/05/21 19:22:37
Is the ~0x3 necessary here?
bsalomon
2013/05/22 14:11:25
No... but I was hoping the compiler would see that
|
| + 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 { |
| @@ -96,37 +135,78 @@ private: |
| } |
| } |
| - /** Non-zero if this stage has an effect */ |
| - GrGLEffect::EffectKey fEffectKeys[GrDrawState::kNumStages]; |
| - |
| - // To enable experimental geometry shader code (not for use in |
| - // production) |
| -#if GR_GL_EXPERIMENTAL_GS |
| - bool fExperimentalGS; |
| -#endif |
| - |
| - GrGLShaderBuilder::DstReadKey fDstReadKey; // set by GrGLShaderBuilder if there |
| + struct KeyHeader { |
| + GrGLShaderBuilder::DstReadKey fDstReadKey; // set by GrGLShaderBuilder if there |
| // are effects that must read the dst. |
| // Otherwise, 0. |
| - GrGLShaderBuilder::FragPosKey fFragPosKey; // set by GrGLShaderBuilder if there are |
| + GrGLShaderBuilder::FragPosKey fFragPosKey; // set by GrGLShaderBuilder if there are |
| // effects that read the fragment position. |
| // Otherwise, 0. |
| - // should the FS discard if the coverage is zero (to avoid stencil manipulation) |
| - SkBool8 fDiscardIfZeroCoverage; |
| + // should the FS discard if the coverage is zero (to avoid stencil manipulation) |
| + SkBool8 fDiscardIfZeroCoverage; |
| - uint8_t fColorInput; // casts to enum ColorInput |
| - uint8_t fCoverageInput; // casts to enum ColorInput |
| - uint8_t fCoverageOutput; // casts to enum CoverageOutput |
| + uint8_t fColorInput; // casts to enum ColorInput |
| + uint8_t fCoverageInput; // casts to enum ColorInput |
| + uint8_t fCoverageOutput; // casts to enum CoverageOutput |
| - int8_t fFirstCoverageStage; |
| - SkBool8 fEmitsPointSize; |
| - uint8_t fColorFilterXfermode; // casts to enum SkXfermode::Mode |
| + SkBool8 fEmitsPointSize; |
| + uint8_t fColorFilterXfermode; // casts to enum SkXfermode::Mode |
| + |
| + // 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 is 1 uint32_t for the length, followed another for the checksum, the header, and then |
| + // the effect keys. Everything is fixed length except the effect key array. |
| + enum { |
| + kLengthOffset = 0, |
| + kChecksumOffset = kLengthOffset + sizeof(uint32_t), |
| + kHeaderOffset = kChecksumOffset + sizeof(uint32_t), |
| + kHeaderSize = SkAlign4(sizeof(KeyHeader)), |
| + kEffectKeyOffset = kHeaderOffset + kHeaderSize, |
| + }; |
| + |
| + template<typename T, size_t OFFSET> T* atOffset() { |
| + return reinterpret_cast<T*>(reinterpret_cast<intptr_t>(fKey.get()) + OFFSET); |
| + } |
| + |
| + template<typename T, size_t OFFSET> const T* atOffset() const { |
| + return reinterpret_cast<const T*>(reinterpret_cast<intptr_t>(fKey.get()) + OFFSET); |
| + } |
| + |
| + typedef GrGLEffect::EffectKey EffectKey; |
| + |
| + uint32_t* checksum() { return this->atOffset<uint32_t, kChecksumOffset>(); } |
| + KeyHeader* header() { return this->atOffset<KeyHeader, kHeaderOffset>(); } |
| + EffectKey* effectKeys() { return this->atOffset<EffectKey, kEffectKeyOffset>(); } |
| + |
| + const KeyHeader& getHeader() const { return *this->atOffset<KeyHeader, kHeaderOffset>(); } |
| + const EffectKey* getEffectKeys() const { return this->atOffset<EffectKey, kEffectKeyOffset>(); } |
| + |
| + static size_t KeyLength(int effectCnt) { |
| + GR_STATIC_ASSERT(!(sizeof(EffectKey) & 0x3)); |
| + return kEffectKeyOffset + effectCnt * sizeof(EffectKey); |
| + } |
| + |
| + enum { |
| + kMaxPreallocEffects = 16, |
| + kPreAllocSize = kEffectKeyOffset + kMaxPreallocEffects * sizeof(EffectKey), |
| + }; |
| - int8_t fPositionAttributeIndex; |
| - int8_t fLocalCoordAttributeIndex; |
| - int8_t fColorAttributeIndex; |
| - int8_t fCoverageAttributeIndex; |
| + SkAutoSMalloc<kPreAllocSize> fKey; |
| + bool fInitialized; |
| // GrGLProgram and GrGLShaderBuilder read the private fields to generate code. TODO: Move all |
| // code generation to GrGLShaderBuilder (and maybe add getters rather than friending). |