| Index: src/gpu/gl/GrGLProgramDesc.h
|
| diff --git a/src/gpu/gl/GrGLProgramDesc.h b/src/gpu/gl/GrGLProgramDesc.h
|
| index b49cb722c017f0f5b67bcbcb5e3c69bf9ce755db..f83275dd464122f8fa12c67e1372c0695b15b882 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>(); }
|
| +
|
| + // 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.
|
| 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,37 @@ 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);
|
| + // 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 {
|
| @@ -96,37 +136,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).
|
|
|