|
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" |
|
12 #include "GrDrawState.h" |
|
13 #include "GrGLShaderBuilder.h" |
|
14 |
|
15 class GrGpuGL; |
|
16 |
|
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 |
|
24 |
|
25 |
|
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. */ |
|
30 class GrGLProgramDesc { |
|
31 public: |
|
32 GrGLProgramDesc() : fInitialized(false) {} |
|
33 GrGLProgramDesc(const GrGLProgramDesc& desc) { *this = desc; } |
|
34 |
|
35 // Returns this as a uint32_t array to be used as a key in the program cache. |
|
36 const uint32_t* asKey() const { |
|
37 SkASSERT(fInitialized); |
|
38 return reinterpret_cast<const uint32_t*>(fKey.get()); |
|
39 } |
|
40 |
|
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>(); } |
|
48 |
|
49 // For unit testing. |
|
50 void setRandom(SkRandom*, |
|
51 const GrGpuGL* gpu, |
|
52 const GrRenderTarget* dummyDstRenderTarget, |
|
53 const GrTexture* dummyDstCopyTexture, |
|
54 const GrEffectStage* stages[], |
|
55 int numColorStages, |
|
56 int numCoverageStages, |
|
57 int currAttribIndex); |
|
58 |
|
59 /** |
|
60 * Builds a program descriptor from a GrDrawState. Whether the primitive type is points, the |
|
61 * output of GrDrawState::getBlendOpts, and the caps of the GrGpuGL are also inputs. It also |
|
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. |
|
65 */ |
|
66 static void Build(const GrDrawState&, |
|
67 bool isPoints, |
|
68 GrDrawState::BlendOptFlags, |
|
69 GrBlendCoeff srcCoeff, |
|
70 GrBlendCoeff dstCoeff, |
|
71 const GrGpuGL* gpu, |
|
72 const GrDeviceCoordTexture* dstCopy, |
|
73 SkTArray<const GrEffectStage*, true>* outColorStages, |
|
74 SkTArray<const GrEffectStage*, true>* outCoverageStages, |
|
75 GrGLProgramDesc* outDesc); |
|
76 |
|
77 int numColorEffects() const { |
|
78 SkASSERT(fInitialized); |
|
79 return this->getHeader().fColorEffectCnt; |
|
80 } |
|
81 |
|
82 int numCoverageEffects() const { |
|
83 SkASSERT(fInitialized); |
|
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 { |
|
92 SkASSERT(fInitialized && other.fInitialized); |
|
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 |
|
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 }; |
|
115 |
|
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 |
|
129 // can only be set if fDstReadKey is non-zero. |
|
130 kCombineWithDst_CoverageOutput, |
|
131 |
|
132 kCoverageOutputCnt |
|
133 }; |
|
134 |
|
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 |
|
146 struct KeyHeader { |
|
147 GrGLShaderBuilder::DstReadKey fDstReadKey; // set by GrGLShaderBuilder if there |
|
148 // are effects that must read the dst. |
|
149 // Otherwise, 0. |
|
150 GrGLShaderBuilder::FragPosKey fFragPosKey; // set by GrGLShaderBuilder if there are |
|
151 // effects that read the fragment position. |
|
152 // Otherwise, 0. |
|
153 |
|
154 ColorInput fColorInput : 8; |
|
155 ColorInput fCoverageInput : 8; |
|
156 CoverageOutput fCoverageOutput : 8; |
|
157 |
|
158 SkBool8 fHasVertexCode; |
|
159 SkBool8 fEmitsPointSize; |
|
160 |
|
161 // To enable experimental geometry shader code (not for use in |
|
162 // production) |
|
163 #if GR_GL_EXPERIMENTAL_GS |
|
164 SkBool8 fExperimentalGS; |
|
165 #endif |
|
166 |
|
167 int8_t fPositionAttributeIndex; |
|
168 int8_t fLocalCoordAttributeIndex; |
|
169 int8_t fColorAttributeIndex; |
|
170 int8_t fCoverageAttributeIndex; |
|
171 |
|
172 int8_t fColorEffectCnt; |
|
173 int8_t fCoverageEffectCnt; |
|
174 }; |
|
175 |
|
176 // The key is 1 uint32_t for the length, followed another for the checksum, the header, and then |
|
177 // the effect keys. Everything is fixed length except the effect key array. |
|
178 enum { |
|
179 kLengthOffset = 0, |
|
180 kChecksumOffset = kLengthOffset + sizeof(uint32_t), |
|
181 kHeaderOffset = kChecksumOffset + sizeof(uint32_t), |
|
182 kHeaderSize = SkAlign4(sizeof(KeyHeader)), |
|
183 kEffectKeyOffset = kHeaderOffset + kHeaderSize, |
|
184 }; |
|
185 |
|
186 template<typename T, size_t OFFSET> T* atOffset() { |
|
187 return reinterpret_cast<T*>(reinterpret_cast<intptr_t>(fKey.get()) + OFFSET); |
|
188 } |
|
189 |
|
190 template<typename T, size_t OFFSET> const T* atOffset() const { |
|
191 return reinterpret_cast<const T*>(reinterpret_cast<intptr_t>(fKey.get()) + OFFSET); |
|
192 } |
|
193 |
|
194 typedef GrGLEffect::EffectKey EffectKey; |
|
195 |
|
196 uint32_t* checksum() { return this->atOffset<uint32_t, kChecksumOffset>(); } |
|
197 KeyHeader* header() { return this->atOffset<KeyHeader, kHeaderOffset>(); } |
|
198 EffectKey* effectKeys() { return this->atOffset<EffectKey, kEffectKeyOffset>(); } |
|
199 |
|
200 const KeyHeader& getHeader() const { return *this->atOffset<KeyHeader, kHeaderOffset>(); } |
|
201 const EffectKey* getEffectKeys() const { return this->atOffset<EffectKey, kEffectKeyOffset>(); } |
|
202 |
|
203 static size_t KeyLength(int effectCnt) { |
|
204 GR_STATIC_ASSERT(!(sizeof(EffectKey) & 0x3)); |
|
205 return kEffectKeyOffset + effectCnt * sizeof(EffectKey); |
|
206 } |
|
207 |
|
208 enum { |
|
209 kMaxPreallocEffects = 16, |
|
210 kPreAllocSize = kEffectKeyOffset + kMaxPreallocEffects * sizeof(EffectKey), |
|
211 }; |
|
212 |
|
213 SkAutoSMalloc<kPreAllocSize> fKey; |
|
214 bool fInitialized; |
|
215 |
|
216 // GrGLProgram and GrGLShaderBuilder read the private fields to generate code. TODO: Move all |
|
217 // code generation to GrGLShaderBuilder (and maybe add getters rather than friending). |
|
218 friend class GrGLProgram; |
|
219 friend class GrGLShaderBuilder; |
|
220 friend class GrGLFullShaderBuilder; |
|
221 friend class GrGLFragmentOnlyShaderBuilder; |
|
222 }; |
|
223 |
|
224 #endif |