| bsalomon@google.com | 31ec798 | 2013-03-27 18:14:57 +0000 | [diff] [blame] | 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 "GrGLEffect.h" | 
| bsalomon@google.com | 798c8c4 | 2013-03-27 19:50:27 +0000 | [diff] [blame] | 12 | #include "GrDrawState.h" | 
| bsalomon@google.com | 26e18b5 | 2013-03-29 19:22:36 +0000 | [diff] [blame] | 13 | #include "GrGLShaderBuilder.h" | 
| bsalomon@google.com | 31ec798 | 2013-03-27 18:14:57 +0000 | [diff] [blame] | 14 |  | 
|  | 15 | class GrGpuGL; | 
|  | 16 |  | 
| commit-bot@chromium.org | 515dcd3 | 2013-08-28 14:17:03 +0000 | [diff] [blame] | 17 | #ifdef SK_DEBUG | 
|  | 18 | // Optionally compile the experimental GS code. Set to SK_DEBUG so that debug build bots will | 
|  | 19 | // execute the code. | 
|  | 20 | #define GR_GL_EXPERIMENTAL_GS 1 | 
|  | 21 | #else | 
|  | 22 | #define GR_GL_EXPERIMENTAL_GS 0 | 
|  | 23 | #endif | 
| bsalomon@google.com | 31ec798 | 2013-03-27 18:14:57 +0000 | [diff] [blame] | 24 |  | 
|  | 25 |  | 
| bsalomon@google.com | 26e18b5 | 2013-03-29 19:22:36 +0000 | [diff] [blame] | 26 | /** This class describes a program to generate. It also serves as a program cache key. Very little | 
|  | 27 | of this is GL-specific. There is the generation of GrGLEffect::EffectKeys and the dst-read part | 
|  | 28 | of the key set by GrGLShaderBuilder. If the interfaces that set those portions were abstracted | 
|  | 29 | to be API-neutral then so could this class. */ | 
| bsalomon@google.com | 31ec798 | 2013-03-27 18:14:57 +0000 | [diff] [blame] | 30 | class GrGLProgramDesc { | 
|  | 31 | public: | 
| bsalomon@google.com | 2db3ded | 2013-05-22 14:34:04 +0000 | [diff] [blame] | 32 | GrGLProgramDesc() : fInitialized(false) {} | 
|  | 33 | GrGLProgramDesc(const GrGLProgramDesc& desc) { *this = desc; } | 
|  | 34 |  | 
| skia.committer@gmail.com | 2d816ad | 2013-05-23 07:01:22 +0000 | [diff] [blame] | 35 | // Returns this as a uint32_t array to be used as a key in the program cache. | 
| bsalomon@google.com | 2db3ded | 2013-05-22 14:34:04 +0000 | [diff] [blame] | 36 | const uint32_t* asKey() const { | 
| tfarina@chromium.org | f6de475 | 2013-08-17 00:02:59 +0000 | [diff] [blame] | 37 | SkASSERT(fInitialized); | 
| bsalomon@google.com | 2db3ded | 2013-05-22 14:34:04 +0000 | [diff] [blame] | 38 | return reinterpret_cast<const uint32_t*>(fKey.get()); | 
| bsalomon@google.com | 31ec798 | 2013-03-27 18:14:57 +0000 | [diff] [blame] | 39 | } | 
|  | 40 |  | 
| bsalomon@google.com | 2db3ded | 2013-05-22 14:34:04 +0000 | [diff] [blame] | 41 | // Gets the number of bytes in asKey(). It will be a 4-byte aligned value. When comparing two | 
|  | 42 | // keys the size of either key can be used with memcmp() since the lengths themselves begin the | 
|  | 43 | // keys and thus the memcmp will exit early if the keys are of different lengths. | 
|  | 44 | uint32_t keyLength() const { return *this->atOffset<uint32_t, kLengthOffset>(); } | 
|  | 45 |  | 
|  | 46 | // Gets the a checksum of the key. Can be used as a hash value for a fast lookup in a cache. | 
|  | 47 | uint32_t getChecksum() const { return *this->atOffset<uint32_t, kChecksumOffset>(); } | 
| bsalomon@google.com | 31ec798 | 2013-03-27 18:14:57 +0000 | [diff] [blame] | 48 |  | 
|  | 49 | // For unit testing. | 
| commit-bot@chromium.org | e0e7cfe | 2013-09-09 20:09:12 +0000 | [diff] [blame] | 50 | void setRandom(SkRandom*, | 
| bsalomon@google.com | 31ec798 | 2013-03-27 18:14:57 +0000 | [diff] [blame] | 51 | const GrGpuGL* gpu, | 
| bsalomon@google.com | 2db3ded | 2013-05-22 14:34:04 +0000 | [diff] [blame] | 52 | const GrRenderTarget* dummyDstRenderTarget, | 
|  | 53 | const GrTexture* dummyDstCopyTexture, | 
|  | 54 | const GrEffectStage* stages[], | 
|  | 55 | int numColorStages, | 
|  | 56 | int numCoverageStages, | 
| jvanverth@google.com | 054ae99 | 2013-04-01 20:06:51 +0000 | [diff] [blame] | 57 | int currAttribIndex); | 
| bsalomon@google.com | 31ec798 | 2013-03-27 18:14:57 +0000 | [diff] [blame] | 58 |  | 
|  | 59 | /** | 
|  | 60 | * Builds a program descriptor from a GrDrawState. Whether the primitive type is points, the | 
| bsalomon@google.com | 2db3ded | 2013-05-22 14:34:04 +0000 | [diff] [blame] | 61 | * output of GrDrawState::getBlendOpts, and the caps of the GrGpuGL are also inputs. It also | 
| bsalomon@google.com | 2c84aa3 | 2013-06-06 20:28:57 +0000 | [diff] [blame] | 62 | * outputs the color and coverage stages referenced by the generated descriptor. This may | 
|  | 63 | * not contain all stages from the draw state and coverage stages from the drawState may | 
|  | 64 | * be treated as color stages in the output. | 
| bsalomon@google.com | 31ec798 | 2013-03-27 18:14:57 +0000 | [diff] [blame] | 65 | */ | 
|  | 66 | static void Build(const GrDrawState&, | 
|  | 67 | bool isPoints, | 
|  | 68 | GrDrawState::BlendOptFlags, | 
|  | 69 | GrBlendCoeff srcCoeff, | 
|  | 70 | GrBlendCoeff dstCoeff, | 
|  | 71 | const GrGpuGL* gpu, | 
| bsalomon@google.com | 26e18b5 | 2013-03-29 19:22:36 +0000 | [diff] [blame] | 72 | const GrDeviceCoordTexture* dstCopy, | 
| bsalomon@google.com | 2c84aa3 | 2013-06-06 20:28:57 +0000 | [diff] [blame] | 73 | SkTArray<const GrEffectStage*, true>* outColorStages, | 
|  | 74 | SkTArray<const GrEffectStage*, true>* outCoverageStages, | 
| bsalomon@google.com | 31ec798 | 2013-03-27 18:14:57 +0000 | [diff] [blame] | 75 | GrGLProgramDesc* outDesc); | 
|  | 76 |  | 
| bsalomon@google.com | 2db3ded | 2013-05-22 14:34:04 +0000 | [diff] [blame] | 77 | int numColorEffects() const { | 
| tfarina@chromium.org | f6de475 | 2013-08-17 00:02:59 +0000 | [diff] [blame] | 78 | SkASSERT(fInitialized); | 
| bsalomon@google.com | 2db3ded | 2013-05-22 14:34:04 +0000 | [diff] [blame] | 79 | return this->getHeader().fColorEffectCnt; | 
|  | 80 | } | 
|  | 81 |  | 
|  | 82 | int numCoverageEffects() const { | 
| tfarina@chromium.org | f6de475 | 2013-08-17 00:02:59 +0000 | [diff] [blame] | 83 | SkASSERT(fInitialized); | 
| bsalomon@google.com | 2db3ded | 2013-05-22 14:34:04 +0000 | [diff] [blame] | 84 | return this->getHeader().fCoverageEffectCnt; | 
|  | 85 | } | 
|  | 86 |  | 
|  | 87 | int numTotalEffects() const { return this->numColorEffects() + this->numCoverageEffects(); } | 
|  | 88 |  | 
|  | 89 | GrGLProgramDesc& operator= (const GrGLProgramDesc& other); | 
|  | 90 |  | 
|  | 91 | bool operator== (const GrGLProgramDesc& other) const { | 
| tfarina@chromium.org | f6de475 | 2013-08-17 00:02:59 +0000 | [diff] [blame] | 92 | SkASSERT(fInitialized && other.fInitialized); | 
| bsalomon@google.com | 2db3ded | 2013-05-22 14:34:04 +0000 | [diff] [blame] | 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 |  | 
|  | 101 | static bool Less(const GrGLProgramDesc& a, const GrGLProgramDesc& b) { | 
|  | 102 | return memcmp(a.asKey(), b.asKey(), a.keyLength() & ~0x3) < 0; | 
|  | 103 | } | 
|  | 104 |  | 
| bsalomon@google.com | 31ec798 | 2013-03-27 18:14:57 +0000 | [diff] [blame] | 105 | private: | 
|  | 106 | // Specifies where the initial color comes from before the stages are applied. | 
|  | 107 | enum ColorInput { | 
|  | 108 | kSolidWhite_ColorInput, | 
|  | 109 | kTransBlack_ColorInput, | 
|  | 110 | kAttribute_ColorInput, | 
|  | 111 | kUniform_ColorInput, | 
|  | 112 |  | 
|  | 113 | kColorInputCnt | 
|  | 114 | }; | 
| bsalomon@google.com | 31ec798 | 2013-03-27 18:14:57 +0000 | [diff] [blame] | 115 |  | 
| bsalomon@google.com | 5920ac2 | 2013-04-19 13:14:45 +0000 | [diff] [blame] | 116 | enum CoverageOutput { | 
|  | 117 | // modulate color and coverage, write result as the color output. | 
|  | 118 | kModulate_CoverageOutput, | 
|  | 119 | // Writes color*coverage as the primary color output and also writes coverage as the | 
|  | 120 | // secondary output. Only set if dual source blending is supported. | 
|  | 121 | kSecondaryCoverage_CoverageOutput, | 
|  | 122 | // Writes color*coverage as the primary color output and also writes coverage * (1 - colorA) | 
|  | 123 | // as the secondary output. Only set if dual source blending is supported. | 
|  | 124 | kSecondaryCoverageISA_CoverageOutput, | 
|  | 125 | // Writes color*coverage as the primary color output and also writes coverage * | 
|  | 126 | // (1 - colorRGB) as the secondary output. Only set if dual source blending is supported. | 
|  | 127 | kSecondaryCoverageISC_CoverageOutput, | 
|  | 128 | // Combines the coverage, dst, and color as coverage * color + (1 - coverage) * dst. This | 
| bsalomon@google.com | b515881 | 2013-05-13 18:50:25 +0000 | [diff] [blame] | 129 | // can only be set if fDstReadKey is non-zero. | 
| bsalomon@google.com | 5920ac2 | 2013-04-19 13:14:45 +0000 | [diff] [blame] | 130 | kCombineWithDst_CoverageOutput, | 
|  | 131 |  | 
|  | 132 | kCoverageOutputCnt | 
| bsalomon@google.com | 31ec798 | 2013-03-27 18:14:57 +0000 | [diff] [blame] | 133 | }; | 
|  | 134 |  | 
| bsalomon@google.com | 5920ac2 | 2013-04-19 13:14:45 +0000 | [diff] [blame] | 135 | static bool CoverageOutputUsesSecondaryOutput(CoverageOutput co) { | 
|  | 136 | switch (co) { | 
|  | 137 | case kSecondaryCoverage_CoverageOutput: //  fallthru | 
|  | 138 | case kSecondaryCoverageISA_CoverageOutput: | 
|  | 139 | case kSecondaryCoverageISC_CoverageOutput: | 
|  | 140 | return true; | 
|  | 141 | default: | 
|  | 142 | return false; | 
|  | 143 | } | 
|  | 144 | } | 
|  | 145 |  | 
| bsalomon@google.com | 2db3ded | 2013-05-22 14:34:04 +0000 | [diff] [blame] | 146 | struct KeyHeader { | 
|  | 147 | GrGLShaderBuilder::DstReadKey fDstReadKey;      // set by GrGLShaderBuilder if there | 
| bsalomon@google.com | 26e18b5 | 2013-03-29 19:22:36 +0000 | [diff] [blame] | 148 | // are effects that must read the dst. | 
|  | 149 | // Otherwise, 0. | 
| bsalomon@google.com | 2db3ded | 2013-05-22 14:34:04 +0000 | [diff] [blame] | 150 | GrGLShaderBuilder::FragPosKey fFragPosKey;      // set by GrGLShaderBuilder if there are | 
| bsalomon@google.com | b515881 | 2013-05-13 18:50:25 +0000 | [diff] [blame] | 151 | // effects that read the fragment position. | 
|  | 152 | // Otherwise, 0. | 
| bsalomon@google.com | 26e18b5 | 2013-03-29 19:22:36 +0000 | [diff] [blame] | 153 |  | 
| bsalomon@google.com | 2db3ded | 2013-05-22 14:34:04 +0000 | [diff] [blame] | 154 | // should the FS discard if the coverage is zero (to avoid stencil manipulation) | 
|  | 155 | SkBool8                     fDiscardIfZeroCoverage; | 
| jvanverth@google.com | 054ae99 | 2013-04-01 20:06:51 +0000 | [diff] [blame] | 156 |  | 
| commit-bot@chromium.org | 949eef0 | 2013-10-01 18:43:29 +0000 | [diff] [blame] | 157 | ColorInput                  fColorInput : 8; | 
|  | 158 | ColorInput                  fCoverageInput : 8; | 
|  | 159 | CoverageOutput              fCoverageOutput : 8; | 
| jvanverth@google.com | 054ae99 | 2013-04-01 20:06:51 +0000 | [diff] [blame] | 160 |  | 
| commit-bot@chromium.org | 234d4fb | 2013-09-30 19:55:49 +0000 | [diff] [blame] | 161 | SkBool8                     fHasVertexCode; | 
| bsalomon@google.com | 2db3ded | 2013-05-22 14:34:04 +0000 | [diff] [blame] | 162 | SkBool8                     fEmitsPointSize; | 
| bsalomon@google.com | 31ec798 | 2013-03-27 18:14:57 +0000 | [diff] [blame] | 163 |  | 
| bsalomon@google.com | 2db3ded | 2013-05-22 14:34:04 +0000 | [diff] [blame] | 164 | // To enable experimental geometry shader code (not for use in | 
|  | 165 | // production) | 
|  | 166 | #if GR_GL_EXPERIMENTAL_GS | 
|  | 167 | SkBool8                     fExperimentalGS; | 
|  | 168 | #endif | 
|  | 169 |  | 
|  | 170 | int8_t                      fPositionAttributeIndex; | 
|  | 171 | int8_t                      fLocalCoordAttributeIndex; | 
|  | 172 | int8_t                      fColorAttributeIndex; | 
|  | 173 | int8_t                      fCoverageAttributeIndex; | 
| skia.committer@gmail.com | 2d816ad | 2013-05-23 07:01:22 +0000 | [diff] [blame] | 174 |  | 
| bsalomon@google.com | 2db3ded | 2013-05-22 14:34:04 +0000 | [diff] [blame] | 175 | int8_t                      fColorEffectCnt; | 
|  | 176 | int8_t                      fCoverageEffectCnt; | 
|  | 177 | }; | 
|  | 178 |  | 
|  | 179 | // The key is 1 uint32_t for the length, followed another for the checksum, the header, and then | 
|  | 180 | // the effect keys. Everything is fixed length except the effect key array. | 
|  | 181 | enum { | 
|  | 182 | kLengthOffset = 0, | 
|  | 183 | kChecksumOffset = kLengthOffset + sizeof(uint32_t), | 
|  | 184 | kHeaderOffset = kChecksumOffset + sizeof(uint32_t), | 
|  | 185 | kHeaderSize = SkAlign4(sizeof(KeyHeader)), | 
|  | 186 | kEffectKeyOffset = kHeaderOffset + kHeaderSize, | 
|  | 187 | }; | 
|  | 188 |  | 
|  | 189 | template<typename T, size_t OFFSET> T* atOffset() { | 
|  | 190 | return reinterpret_cast<T*>(reinterpret_cast<intptr_t>(fKey.get()) + OFFSET); | 
|  | 191 | } | 
|  | 192 |  | 
|  | 193 | template<typename T, size_t OFFSET> const T* atOffset() const { | 
|  | 194 | return reinterpret_cast<const T*>(reinterpret_cast<intptr_t>(fKey.get()) + OFFSET); | 
|  | 195 | } | 
|  | 196 |  | 
|  | 197 | typedef GrGLEffect::EffectKey EffectKey; | 
|  | 198 |  | 
|  | 199 | uint32_t* checksum() { return this->atOffset<uint32_t, kChecksumOffset>(); } | 
|  | 200 | KeyHeader* header() { return this->atOffset<KeyHeader, kHeaderOffset>(); } | 
|  | 201 | EffectKey* effectKeys() { return this->atOffset<EffectKey, kEffectKeyOffset>(); } | 
|  | 202 |  | 
|  | 203 | const KeyHeader& getHeader() const { return *this->atOffset<KeyHeader, kHeaderOffset>(); } | 
|  | 204 | const EffectKey* getEffectKeys() const { return this->atOffset<EffectKey, kEffectKeyOffset>(); } | 
|  | 205 |  | 
|  | 206 | static size_t KeyLength(int effectCnt) { | 
|  | 207 | GR_STATIC_ASSERT(!(sizeof(EffectKey) & 0x3)); | 
|  | 208 | return kEffectKeyOffset + effectCnt * sizeof(EffectKey); | 
|  | 209 | } | 
|  | 210 |  | 
|  | 211 | enum { | 
|  | 212 | kMaxPreallocEffects = 16, | 
|  | 213 | kPreAllocSize = kEffectKeyOffset +  kMaxPreallocEffects * sizeof(EffectKey), | 
|  | 214 | }; | 
|  | 215 |  | 
|  | 216 | SkAutoSMalloc<kPreAllocSize> fKey; | 
|  | 217 | bool fInitialized; | 
| bsalomon@google.com | 31ec798 | 2013-03-27 18:14:57 +0000 | [diff] [blame] | 218 |  | 
| bsalomon@google.com | 26e18b5 | 2013-03-29 19:22:36 +0000 | [diff] [blame] | 219 | // GrGLProgram and GrGLShaderBuilder read the private fields to generate code. TODO: Move all | 
|  | 220 | // code generation to GrGLShaderBuilder (and maybe add getters rather than friending). | 
| bsalomon@google.com | 31ec798 | 2013-03-27 18:14:57 +0000 | [diff] [blame] | 221 | friend class GrGLProgram; | 
| bsalomon@google.com | 26e18b5 | 2013-03-29 19:22:36 +0000 | [diff] [blame] | 222 | friend class GrGLShaderBuilder; | 
| commit-bot@chromium.org | 261dc56 | 2013-10-04 15:42:56 +0000 | [diff] [blame] | 223 | friend class GrGLFullShaderBuilder; | 
| commit-bot@chromium.org | 6b30e45 | 2013-10-04 20:02:53 +0000 | [diff] [blame] | 224 | friend class GrGLFragmentOnlyShaderBuilder; | 
| bsalomon@google.com | 31ec798 | 2013-03-27 18:14:57 +0000 | [diff] [blame] | 225 | }; | 
|  | 226 |  | 
|  | 227 | #endif |