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 GrGLProgramDesc_DEFINED 9 #define GrGLProgramDesc_DEFINED 10 11 #include "GrGLProcessor.h" 12 #include "GrDrawState.h" 13 #include "GrGpu.h" 14 #include "GrOptDrawState.h" 15 16 class GrGpuGL; 17 18 #ifdef SK_DEBUG 19 // Optionally compile the experimental GS code. Set to SK_DEBUG so that debug build bots will 20 // execute the code. 21 #define GR_GL_EXPERIMENTAL_GS 1 22 #else 23 #define GR_GL_EXPERIMENTAL_GS 0 24 #endif 25 26 27 /** This class describes a program to generate. It also serves as a program cache key. Very little 28 of this is GL-specific. The GL-specific parts could be factored out into a subclass. */ 29 class GrGLProgramDesc { 30 public: GrGLProgramDesc()31 GrGLProgramDesc() {} GrGLProgramDesc(const GrGLProgramDesc & desc)32 GrGLProgramDesc(const GrGLProgramDesc& desc) { *this = desc; } 33 34 // Returns this as a uint32_t array to be used as a key in the program cache. asKey()35 const uint32_t* asKey() const { 36 return reinterpret_cast<const uint32_t*>(fKey.begin()); 37 } 38 39 // Gets the number of bytes in asKey(). It will be a 4-byte aligned value. When comparing two 40 // keys the size of either key can be used with memcmp() since the lengths themselves begin the 41 // keys and thus the memcmp will exit early if the keys are of different lengths. keyLength()42 uint32_t keyLength() const { return *this->atOffset<uint32_t, kLengthOffset>(); } 43 44 // Gets the a checksum of the key. Can be used as a hash value for a fast lookup in a cache. getChecksum()45 uint32_t getChecksum() const { return *this->atOffset<uint32_t, kChecksumOffset>(); } 46 47 // For unit testing. 48 bool setRandom(SkRandom*, 49 GrGpuGL*, 50 const GrRenderTarget* dummyDstRenderTarget, 51 const GrTexture* dummyDstCopyTexture, 52 const GrGeometryStage* geometryProcessor, 53 const GrFragmentStage* stages[], 54 int numColorStages, 55 int numCoverageStages, 56 int currAttribIndex, 57 GrGpu::DrawType); 58 59 /** 60 * Builds a program descriptor from a GrOptDrawState. Whether the primitive type is points, and 61 * the caps of the GrGpuGL are also inputs. It also outputs the color and coverage stages 62 * referenced by the generated descriptor. Coverage stages from the drawState may be treated as 63 * color stages in the output. 64 */ 65 static bool Build(const GrOptDrawState&, 66 GrGpu::DrawType, 67 GrBlendCoeff srcCoeff, 68 GrBlendCoeff dstCoeff, 69 GrGpuGL*, 70 const GrDeviceCoordTexture* dstCopy, 71 const GrGeometryStage** geometryProcessor, 72 SkTArray<const GrFragmentStage*, true>* colorStages, 73 SkTArray<const GrFragmentStage*, true>* coverageStages, 74 GrGLProgramDesc*); 75 hasGeometryProcessor()76 bool hasGeometryProcessor() const { 77 return SkToBool(this->getHeader().fHasGeometryProcessor); 78 } 79 numColorEffects()80 int numColorEffects() const { 81 return this->getHeader().fColorEffectCnt; 82 } 83 numCoverageEffects()84 int numCoverageEffects() const { 85 return this->getHeader().fCoverageEffectCnt; 86 } 87 numTotalEffects()88 int numTotalEffects() const { return this->numColorEffects() + this->numCoverageEffects(); } 89 90 GrGLProgramDesc& operator= (const GrGLProgramDesc& other); 91 92 bool operator== (const GrGLProgramDesc& other) const { 93 // The length is masked as a hint to the compiler that the address will be 4 byte aligned. 94 return 0 == memcmp(this->asKey(), other.asKey(), this->keyLength() & ~0x3); 95 } 96 97 bool operator!= (const GrGLProgramDesc& other) const { 98 return !(*this == other); 99 } 100 Less(const GrGLProgramDesc & a,const GrGLProgramDesc & b)101 static bool Less(const GrGLProgramDesc& a, const GrGLProgramDesc& b) { 102 return memcmp(a.asKey(), b.asKey(), a.keyLength() & ~0x3) < 0; 103 } 104 105 private: 106 // Specifies where the initial color comes from before the stages are applied. 107 enum ColorInput { 108 kAllOnes_ColorInput, 109 kAttribute_ColorInput, 110 kUniform_ColorInput, 111 112 kColorInputCnt 113 }; 114 115 struct KeyHeader { 116 uint8_t fDstReadKey; // set by GrGLShaderBuilder if there 117 // are effects that must read the dst. 118 // Otherwise, 0. 119 uint8_t fFragPosKey; // set by GrGLShaderBuilder if there are 120 // effects that read the fragment position. 121 // Otherwise, 0. 122 123 SkBool8 fUseFragShaderOnly; 124 SkBool8 fEmitsPointSize; 125 126 ColorInput fColorInput : 8; 127 ColorInput fCoverageInput : 8; 128 129 GrOptDrawState::PrimaryOutputType fPrimaryOutputType : 8; 130 GrOptDrawState::SecondaryOutputType fSecondaryOutputType : 8; 131 132 133 // To enable experimental geometry shader code (not for use in 134 // production) 135 #if GR_GL_EXPERIMENTAL_GS 136 SkBool8 fExperimentalGS; 137 #endif 138 139 int8_t fPositionAttributeIndex; 140 int8_t fLocalCoordAttributeIndex; 141 int8_t fColorAttributeIndex; 142 int8_t fCoverageAttributeIndex; 143 144 SkBool8 fHasGeometryProcessor; 145 int8_t fColorEffectCnt; 146 int8_t fCoverageEffectCnt; 147 }; 148 149 // The key, stored in fKey, is composed of five parts: 150 // 1. uint32_t for total key length. 151 // 2. uint32_t for a checksum. 152 // 3. Header struct defined above. 153 // 4. An array of offsets to effect keys and their sizes (see 5). uint16_t for each 154 // offset and size. 155 // 5. per-effect keys. Each effect's key is a variable length array of uint32_t. 156 enum { 157 // Part 1. 158 kLengthOffset = 0, 159 // Part 2. 160 kChecksumOffset = kLengthOffset + sizeof(uint32_t), 161 // Part 3. 162 kHeaderOffset = kChecksumOffset + sizeof(uint32_t), 163 kHeaderSize = SkAlign4(sizeof(KeyHeader)), 164 // Part 4. 165 // This is the offset in the overall key to the array of per-effect offset,length pairs. 166 kEffectKeyOffsetsAndLengthOffset = kHeaderOffset + kHeaderSize, 167 }; 168 atOffset()169 template<typename T, size_t OFFSET> T* atOffset() { 170 return reinterpret_cast<T*>(reinterpret_cast<intptr_t>(fKey.begin()) + OFFSET); 171 } 172 atOffset()173 template<typename T, size_t OFFSET> const T* atOffset() const { 174 return reinterpret_cast<const T*>(reinterpret_cast<intptr_t>(fKey.begin()) + OFFSET); 175 } 176 header()177 KeyHeader* header() { return this->atOffset<KeyHeader, kHeaderOffset>(); } 178 179 // Shared code between setRandom() and Build(). 180 static bool GetProcessorKey(const GrProcessorStage& stage, 181 const GrGLCaps& caps, 182 bool useExplicitLocalCoords, 183 GrProcessorKeyBuilder* b, 184 uint16_t* effectKeySize); 185 186 static bool GetGeometryProcessorKey(const GrGeometryStage& stage, 187 const GrGLCaps& caps, 188 bool useExplicitLocalCoords, 189 GrProcessorKeyBuilder* b, 190 uint16_t* effectKeySize); 191 void finalize(); 192 getHeader()193 const KeyHeader& getHeader() const { return *this->atOffset<KeyHeader, kHeaderOffset>(); } 194 195 /** Used to provide effects' keys to their emitCode() function. */ 196 class EffectKeyProvider { 197 public: 198 enum EffectType { 199 kGeometryProcessor_EffectType, 200 kColor_EffectType, 201 kCoverage_EffectType, 202 }; 203 EffectKeyProvider(const GrGLProgramDesc * desc,EffectType type)204 EffectKeyProvider(const GrGLProgramDesc* desc, EffectType type) : fDesc(desc) { 205 switch (type) { 206 case kGeometryProcessor_EffectType: 207 // there can be only one 208 fBaseIndex = 0; 209 break; 210 case kColor_EffectType: 211 fBaseIndex = desc->hasGeometryProcessor() ? 1 : 0; 212 break; 213 case kCoverage_EffectType: 214 fBaseIndex = desc->numColorEffects() + (desc->hasGeometryProcessor() ? 1 : 0); 215 break; 216 } 217 } 218 get(int index)219 GrProcessorKey get(int index) const { 220 const uint16_t* offsetsAndLengths = reinterpret_cast<const uint16_t*>( 221 fDesc->fKey.begin() + kEffectKeyOffsetsAndLengthOffset); 222 // We store two uint16_ts per effect, one for the offset to the effect's key and one for 223 // its length. Here we just need the offset. 224 uint16_t offset = offsetsAndLengths[2 * (fBaseIndex + index) + 0]; 225 uint16_t length = offsetsAndLengths[2 * (fBaseIndex + index) + 1]; 226 // Currently effects must add to the key in units of uint32_t. 227 SkASSERT(0 == (length % sizeof(uint32_t))); 228 return GrProcessorKey(reinterpret_cast<const uint32_t*>(fDesc->fKey.begin() + offset), 229 length / sizeof(uint32_t)); 230 } 231 private: 232 const GrGLProgramDesc* fDesc; 233 int fBaseIndex; 234 }; 235 236 enum { 237 kMaxPreallocEffects = 8, 238 kIntsPerEffect = 4, // This is an overestimate of the average effect key size. 239 kPreAllocSize = kEffectKeyOffsetsAndLengthOffset + 240 kMaxPreallocEffects * sizeof(uint32_t) * kIntsPerEffect, 241 }; 242 243 SkSTArray<kPreAllocSize, uint8_t, true> fKey; 244 245 // GrGLProgram and GrGLShaderBuilder read the private fields to generate code. TODO: Split out 246 // part of GrGLShaderBuilder that is used by effects so that this header doesn't need to be 247 // visible to GrGLProcessors. Then make public accessors as necessary and remove friends. 248 friend class GrGLProgram; 249 friend class GrGLProgramBuilder; 250 friend class GrGLFullProgramBuilder; 251 friend class GrGLFragmentOnlyProgramBuilder; 252 friend class GrGLVertexShaderBuilder; 253 friend class GrGLFragmentShaderBuilder; 254 friend class GrGLGeometryShaderBuilder; 255 }; 256 257 #endif 258