OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2014 Google Inc. | 2 * Copyright 2014 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "GrGLFragmentShaderBuilder.h" | 8 #include "GrGLFragmentShaderBuilder.h" |
9 #include "GrGLShaderStringBuilder.h" | 9 #include "GrGLShaderStringBuilder.h" |
10 #include "GrGLProgramBuilder.h" | 10 #include "GrGLProgramBuilder.h" |
11 #include "../GrGpuGL.h" | 11 #include "../GrGpuGL.h" |
12 | 12 |
13 #define GL_CALL(X) GR_GL_CALL(fProgramBuilder->gpu()->glInterface(), X) | 13 namespace { |
14 #define GL_CALL_RET(R, X) GR_GL_CALL_RET(fProgramBuilder->gpu()->glInterface(),
R, X) | 14 #define GL_CALL(X) GR_GL_CALL(gpu->glInterface(), X) |
15 | 15 #define GL_CALL_RET(R, X) GR_GL_CALL_RET(gpu->glInterface(), R, X) |
16 // ES2 FS only guarantees mediump and lowp support | 16 // ES2 FS only guarantees mediump and lowp support |
17 static const GrGLShaderVar::Precision kDefaultFragmentPrecision = GrGLShaderVar:
:kMedium_Precision; | 17 static const GrGLShaderVar::Precision kDefaultFragmentPrecision = GrGLShaderVar:
:kMedium_Precision; |
18 const char* GrGLFragmentShaderBuilder::kDstCopyColorName = "_dstColor"; | 18 static const char kDstCopyColorName[] = "_dstColor"; |
19 static const char* declared_color_output_name() { return "fsColorOut"; } | 19 inline const char* declared_color_output_name() { return "fsColorOut"; } |
20 static const char* dual_source_output_name() { return "dualSourceOut"; } | 20 inline const char* dual_source_output_name() { return "dualSourceOut"; } |
21 static void append_default_precision_qualifier(GrGLShaderVar::Precision p, | 21 inline void append_default_precision_qualifier(GrGLShaderVar::Precision p, |
22 GrGLStandard standard, | 22 GrGLStandard standard, |
23 SkString* str) { | 23 SkString* str) { |
24 // Desktop GLSL has added precision qualifiers but they don't do anything. | 24 // Desktop GLSL has added precision qualifiers but they don't do anything. |
25 if (kGLES_GrGLStandard == standard) { | 25 if (kGLES_GrGLStandard == standard) { |
26 switch (p) { | 26 switch (p) { |
27 case GrGLShaderVar::kHigh_Precision: | 27 case GrGLShaderVar::kHigh_Precision: |
28 str->append("precision highp float;\n"); | 28 str->append("precision highp float;\n"); |
29 break; | 29 break; |
30 case GrGLShaderVar::kMedium_Precision: | 30 case GrGLShaderVar::kMedium_Precision: |
31 str->append("precision mediump float;\n"); | 31 str->append("precision mediump float;\n"); |
32 break; | 32 break; |
33 case GrGLShaderVar::kLow_Precision: | 33 case GrGLShaderVar::kLow_Precision: |
34 str->append("precision lowp float;\n"); | 34 str->append("precision lowp float;\n"); |
35 break; | 35 break; |
36 case GrGLShaderVar::kDefault_Precision: | 36 case GrGLShaderVar::kDefault_Precision: |
37 SkFAIL("Default precision now allowed."); | 37 SkFAIL("Default precision now allowed."); |
38 default: | 38 default: |
39 SkFAIL("Unknown precision value."); | 39 SkFAIL("Unknown precision value."); |
40 } | 40 } |
41 } | 41 } |
42 } | 42 } |
| 43 } |
43 | 44 |
44 GrGLFragmentShaderBuilder::DstReadKey | 45 GrGLFragmentShaderBuilder::DstReadKey GrGLFragmentShaderBuilder::KeyForDstRead( |
45 GrGLFragmentShaderBuilder::KeyForDstRead(const GrTexture* dstCopy, | 46 const GrTexture* dstCopy, const GrGLCaps& caps) { |
46 const GrGLCaps&
caps) { | |
47 uint32_t key = kYesDstRead_DstReadKeyBit; | 47 uint32_t key = kYesDstRead_DstReadKeyBit; |
48 if (caps.fbFetchSupport()) { | 48 if (caps.fbFetchSupport()) { |
49 return key; | 49 return key; |
50 } | 50 } |
51 SkASSERT(dstCopy); | 51 SkASSERT(dstCopy); |
52 if (!caps.textureSwizzleSupport() && GrPixelConfigIsAlphaOnly(dstCopy->confi
g())) { | 52 if (!caps.textureSwizzleSupport() && GrPixelConfigIsAlphaOnly(dstCopy->confi
g())) { |
53 // The fact that the config is alpha-only must be considered when genera
ting code. | 53 // The fact that the config is alpha-only must be considered when genera
ting code. |
54 key |= kUseAlphaConfig_DstReadKeyBit; | 54 key |= kUseAlphaConfig_DstReadKeyBit; |
55 } | 55 } |
56 if (kTopLeft_GrSurfaceOrigin == dstCopy->origin()) { | 56 if (kTopLeft_GrSurfaceOrigin == dstCopy->origin()) { |
57 key |= kTopLeftOrigin_DstReadKeyBit; | 57 key |= kTopLeftOrigin_DstReadKeyBit; |
58 } | 58 } |
59 SkASSERT(static_cast<DstReadKey>(key) == key); | 59 SkASSERT(static_cast<DstReadKey>(key) == key); |
60 return static_cast<DstReadKey>(key); | 60 return static_cast<DstReadKey>(key); |
61 } | 61 } |
62 | 62 |
63 GrGLFragmentShaderBuilder::FragPosKey | 63 GrGLFragmentShaderBuilder::FragPosKey GrGLFragmentShaderBuilder::KeyForFragmentP
osition( |
64 GrGLFragmentShaderBuilder::KeyForFragmentPosition(const GrRenderTarget* dst, | 64 const GrRenderTarget* dst, const GrGLCaps&) { |
65 const
GrGLCaps&) { | |
66 if (kTopLeft_GrSurfaceOrigin == dst->origin()) { | 65 if (kTopLeft_GrSurfaceOrigin == dst->origin()) { |
67 return kTopLeftFragPosRead_FragPosKey; | 66 return kTopLeftFragPosRead_FragPosKey; |
68 } else { | 67 } else { |
69 return kBottomLeftFragPosRead_FragPosKey; | 68 return kBottomLeftFragPosRead_FragPosKey; |
70 } | 69 } |
71 } | 70 } |
72 | 71 |
73 GrGLFragmentShaderBuilder::GrGLFragmentShaderBuilder(GrGLProgramBuilder* program
, | 72 GrGLFragmentShaderBuilder::GrGLFragmentShaderBuilder(GrGLProgramBuilder* program
, |
74 const GrGLProgramDesc& desc
) | 73 const GrGLProgramDesc& desc
) |
75 : INHERITED(program) | 74 : INHERITED(program) |
76 , fHasCustomColorOutput(false) | 75 , fHasCustomColorOutput(false) |
77 , fHasSecondaryOutput(false) | 76 , fHasSecondaryOutput(false) |
78 , fSetupFragPosition(false) | 77 , fSetupFragPosition(false) |
79 , fTopLeftFragPosRead(kTopLeftFragPosRead_FragPosKey == desc.getHeader().fFr
agPosKey) | 78 , fTopLeftFragPosRead(kTopLeftFragPosRead_FragPosKey == desc.getHeader().fFr
agPosKey){ |
80 , fHasReadDstColor(false) | 79 } |
81 , fHasReadFragmentPosition(false) { | 80 |
| 81 const char* GrGLFragmentShaderBuilder::dstColor() { |
| 82 if (fProgramBuilder->fCodeStage.inStageCode()) { |
| 83 const GrProcessor* effect = fProgramBuilder->fCodeStage.effectStage()->g
etProcessor(); |
| 84 // TODO GPs can't read dst color, and full program builder only returns
a pointer to the |
| 85 // base fragment shader builder which does not have this function. Unfo
rtunately, |
| 86 // the code stage class only has a GrProcessor pointer so this is requir
ed for the time |
| 87 // being |
| 88 if (!static_cast<const GrFragmentProcessor*>(effect)->willReadDstColor()
) { |
| 89 SkDEBUGFAIL("GrGLProcessor asked for dst color but its generating Gr
Processor " |
| 90 "did not request access."); |
| 91 return ""; |
| 92 } |
| 93 } |
| 94 |
| 95 GrGpuGL* gpu = fProgramBuilder->gpu(); |
| 96 if (gpu->glCaps().fbFetchSupport()) { |
| 97 this->addFeature(1 << (GrGLFragmentShaderBuilder::kLastGLSLPrivateFeatur
e + 1), |
| 98 gpu->glCaps().fbFetchExtensionString()); |
| 99 return gpu->glCaps().fbFetchColorName(); |
| 100 } else if (fProgramBuilder->fUniformHandles.fDstCopySamplerUni.isValid()) { |
| 101 return kDstCopyColorName; |
| 102 } else { |
| 103 return ""; |
| 104 } |
82 } | 105 } |
83 | 106 |
84 bool GrGLFragmentShaderBuilder::enableFeature(GLSLFeature feature) { | 107 bool GrGLFragmentShaderBuilder::enableFeature(GLSLFeature feature) { |
85 switch (feature) { | 108 switch (feature) { |
86 case kStandardDerivatives_GLSLFeature: { | 109 case kStandardDerivatives_GLSLFeature: { |
87 GrGpuGL* gpu = fProgramBuilder->gpu(); | 110 GrGpuGL* gpu = fProgramBuilder->gpu(); |
88 if (!gpu->glCaps().shaderDerivativeSupport()) { | 111 if (!gpu->glCaps().shaderDerivativeSupport()) { |
89 return false; | 112 return false; |
90 } | 113 } |
91 if (kGLES_GrGLStandard == gpu->glStandard()) { | 114 if (kGLES_GrGLStandard == gpu->glStandard()) { |
(...skipping 18 matching lines...) Expand all Loading... |
110 SkString coords2D("coords2D"); | 133 SkString coords2D("coords2D"); |
111 if (0 != index) { | 134 if (0 != index) { |
112 coords2D.appendf("_%i", index); | 135 coords2D.appendf("_%i", index); |
113 } | 136 } |
114 this->codeAppendf("\tvec2 %s = %s.xy / %s.z;", | 137 this->codeAppendf("\tvec2 %s = %s.xy / %s.z;", |
115 coords2D.c_str(), coords[index].c_str(), coords[index].c_s
tr()); | 138 coords2D.c_str(), coords[index].c_str(), coords[index].c_s
tr()); |
116 return coords2D; | 139 return coords2D; |
117 } | 140 } |
118 | 141 |
119 const char* GrGLFragmentShaderBuilder::fragmentPosition() { | 142 const char* GrGLFragmentShaderBuilder::fragmentPosition() { |
120 fHasReadFragmentPosition = true; | 143 GrGLProgramBuilder::CodeStage* cs = &fProgramBuilder->fCodeStage; |
| 144 if (cs->inStageCode()) { |
| 145 const GrProcessor* effect = cs->effectStage()->getProcessor(); |
| 146 if (!effect->willReadFragmentPosition()) { |
| 147 SkDEBUGFAIL("GrGLProcessor asked for frag position but its generatin
g GrProcessor " |
| 148 "did not request access."); |
| 149 return ""; |
| 150 } |
| 151 } |
121 | 152 |
122 GrGpuGL* gpu = fProgramBuilder->gpu(); | 153 GrGpuGL* gpu = fProgramBuilder->gpu(); |
123 // We only declare "gl_FragCoord" when we're in the case where we want to us
e layout qualifiers | 154 // We only declare "gl_FragCoord" when we're in the case where we want to us
e layout qualifiers |
124 // to reverse y. Otherwise it isn't necessary and whether the "in" qualifier
appears in the | 155 // to reverse y. Otherwise it isn't necessary and whether the "in" qualifier
appears in the |
125 // declaration varies in earlier GLSL specs. So it is simpler to omit it. | 156 // declaration varies in earlier GLSL specs. So it is simpler to omit it. |
126 if (fTopLeftFragPosRead) { | 157 if (fTopLeftFragPosRead) { |
127 fSetupFragPosition = true; | 158 fSetupFragPosition = true; |
128 return "gl_FragCoord"; | 159 return "gl_FragCoord"; |
129 } else if (gpu->glCaps().fragCoordConventionsSupport()) { | 160 } else if (gpu->glCaps().fragCoordConventionsSupport()) { |
130 if (!fSetupFragPosition) { | 161 if (!fSetupFragPosition) { |
131 if (gpu->glslGeneration() < k150_GrGLSLGeneration) { | 162 if (gpu->glslGeneration() < k150_GrGLSLGeneration) { |
132 this->addFeature(1 << kFragCoordConventions_GLSLPrivateFeature, | 163 this->addFeature(1 << kFragCoordConventions_GLSLPrivateFeature, |
133 "GL_ARB_fragment_coord_conventions"); | 164 "GL_ARB_fragment_coord_conventions"); |
134 } | 165 } |
135 fInputs.push_back().set(kVec4f_GrSLType, | 166 fInputs.push_back().set(kVec4f_GrSLType, |
136 GrGLShaderVar::kIn_TypeModifier, | 167 GrGLShaderVar::kIn_TypeModifier, |
137 "gl_FragCoord", | 168 "gl_FragCoord", |
138 GrGLShaderVar::kDefault_Precision, | 169 GrGLShaderVar::kDefault_Precision, |
139 GrGLShaderVar::kUpperLeft_Origin); | 170 GrGLShaderVar::kUpperLeft_Origin); |
140 fSetupFragPosition = true; | 171 fSetupFragPosition = true; |
141 } | 172 } |
142 return "gl_FragCoord"; | 173 return "gl_FragCoord"; |
143 } else { | 174 } else { |
144 static const char* kCoordName = "fragCoordYDown"; | 175 static const char* kCoordName = "fragCoordYDown"; |
145 if (!fSetupFragPosition) { | 176 if (!fSetupFragPosition) { |
146 // temporarily change the stage index because we're inserting non-st
age code. | 177 // temporarily change the stage index because we're inserting non-st
age code. |
147 GrGLProgramBuilder::AutoStageRestore asr(fProgramBuilder); | 178 GrGLProgramBuilder::CodeStage::AutoStageRestore csar(cs, NULL); |
| 179 |
148 SkASSERT(!fProgramBuilder->fUniformHandles.fRTHeightUni.isValid()); | 180 SkASSERT(!fProgramBuilder->fUniformHandles.fRTHeightUni.isValid()); |
149 const char* rtHeightName; | 181 const char* rtHeightName; |
150 | 182 |
151 fProgramBuilder->fUniformHandles.fRTHeightUni = | 183 fProgramBuilder->fUniformHandles.fRTHeightUni = |
152 fProgramBuilder->addUniform(GrGLProgramBuilder::kFragment_Vi
sibility, | 184 fProgramBuilder->addUniform(GrGLProgramBuilder::kFragment_Vi
sibility, |
153 kFloat_GrSLType, | 185 kFloat_GrSLType, |
154 "RTHeight", | 186 "RTHeight", |
155 &rtHeightName); | 187 &rtHeightName); |
156 | 188 |
157 // Using glFragCoord.zw for the last two components tickles an Adren
o driver bug that | 189 // Using glFragCoord.zw for the last two components tickles an Adren
o driver bug that |
158 // causes programs to fail to link. Making this function return a ve
c2() didn't fix the | 190 // causes programs to fail to link. Making this function return a ve
c2() didn't fix the |
159 // problem but using 1.0 for the last two components does. | 191 // problem but using 1.0 for the last two components does. |
160 this->codePrependf("\tvec4 %s = vec4(gl_FragCoord.x, %s - gl_FragCoo
rd.y, 1.0, " | 192 this->codePrependf("\tvec4 %s = vec4(gl_FragCoord.x, %s - gl_FragCoo
rd.y, 1.0, " |
161 "1.0);\n", kCoordName, rtHeightName); | 193 "1.0);\n", kCoordName, rtHeightName); |
162 fSetupFragPosition = true; | 194 fSetupFragPosition = true; |
163 } | 195 } |
164 SkASSERT(fProgramBuilder->fUniformHandles.fRTHeightUni.isValid()); | 196 SkASSERT(fProgramBuilder->fUniformHandles.fRTHeightUni.isValid()); |
165 return kCoordName; | 197 return kCoordName; |
166 } | 198 } |
167 } | 199 } |
168 | 200 |
169 const char* GrGLFragmentShaderBuilder::dstColor() { | |
170 fHasReadDstColor = true; | |
171 | |
172 GrGpuGL* gpu = fProgramBuilder->gpu(); | |
173 if (gpu->glCaps().fbFetchSupport()) { | |
174 this->addFeature(1 << (GrGLFragmentShaderBuilder::kLastGLSLPrivateFeatur
e + 1), | |
175 gpu->glCaps().fbFetchExtensionString()); | |
176 return gpu->glCaps().fbFetchColorName(); | |
177 } else if (fProgramBuilder->fUniformHandles.fDstCopySamplerUni.isValid()) { | |
178 return kDstCopyColorName; | |
179 } else { | |
180 return ""; | |
181 } | |
182 } | |
183 | |
184 void GrGLFragmentShaderBuilder::emitCodeToReadDstTexture() { | |
185 bool topDown = SkToBool(kTopLeftOrigin_DstReadKeyBit & fProgramBuilder->head
er().fDstReadKey); | |
186 const char* dstCopyTopLeftName; | |
187 const char* dstCopyCoordScaleName; | |
188 const char* dstCopySamplerName; | |
189 uint32_t configMask; | |
190 if (SkToBool(kUseAlphaConfig_DstReadKeyBit & fProgramBuilder->header().fDstR
eadKey)) { | |
191 configMask = kA_GrColorComponentFlag; | |
192 } else { | |
193 configMask = kRGBA_GrColorComponentFlags; | |
194 } | |
195 fProgramBuilder->fUniformHandles.fDstCopySamplerUni = | |
196 fProgramBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility
, | |
197 kSampler2D_GrSLType, | |
198 "DstCopySampler", | |
199 &dstCopySamplerName); | |
200 fProgramBuilder->fUniformHandles.fDstCopyTopLeftUni = | |
201 fProgramBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility
, | |
202 kVec2f_GrSLType, | |
203 "DstCopyUpperLeft", | |
204 &dstCopyTopLeftName); | |
205 fProgramBuilder->fUniformHandles.fDstCopyScaleUni = | |
206 fProgramBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility
, | |
207 kVec2f_GrSLType, | |
208 "DstCopyCoordScale", | |
209 &dstCopyCoordScaleName); | |
210 const char* fragPos = this->fragmentPosition(); | |
211 | |
212 this->codeAppend("// Read color from copy of the destination.\n"); | |
213 this->codeAppendf("vec2 _dstTexCoord = (%s.xy - %s) * %s;", | |
214 fragPos, dstCopyTopLeftName, dstCopyCoordScaleName); | |
215 if (!topDown) { | |
216 this->codeAppend("_dstTexCoord.y = 1.0 - _dstTexCoord.y;"); | |
217 } | |
218 this->codeAppendf("vec4 %s = ", GrGLFragmentShaderBuilder::kDstCopyColorName
); | |
219 this->appendTextureLookup(dstCopySamplerName, | |
220 "_dstTexCoord", | |
221 configMask, | |
222 "rgba"); | |
223 this->codeAppend(";"); | |
224 } | |
225 | |
226 void GrGLFragmentShaderBuilder::enableCustomOutput() { | |
227 SkASSERT(!fHasCustomColorOutput); | |
228 fHasCustomColorOutput = true; | |
229 fOutputs.push_back().set(kVec4f_GrSLType, | |
230 GrGLShaderVar::kOut_TypeModifier, | |
231 declared_color_output_name()); | |
232 } | |
233 | |
234 void GrGLFragmentShaderBuilder::enableSecondaryOutput() { | |
235 SkASSERT(!fHasSecondaryOutput); | |
236 fHasSecondaryOutput = true; | |
237 fOutputs.push_back().set(kVec4f_GrSLType, GrGLShaderVar::kOut_TypeModifier, | |
238 dual_source_output_name()); | |
239 } | |
240 | |
241 const char* GrGLFragmentShaderBuilder::getPrimaryColorOutputName() const { | |
242 return fHasCustomColorOutput ? declared_color_output_name() : "gl_FragColor"
; | |
243 } | |
244 | |
245 const char* GrGLFragmentShaderBuilder::getSecondaryColorOutputName() const { | |
246 return dual_source_output_name(); | |
247 } | |
248 | |
249 void GrGLFragmentShaderBuilder::enableSecondaryOutput(const GrGLSLExpr4& inputCo
lor, | |
250 const GrGLSLExpr4& inputCo
verage) { | |
251 this->enableSecondaryOutput(); | |
252 const char* secondaryOutputName = this->getSecondaryColorOutputName(); | |
253 GrGLSLExpr4 coeff(1); | |
254 switch (fProgramBuilder->header().fSecondaryOutputType) { | |
255 case GrOptDrawState::kCoverage_SecondaryOutputType: | |
256 break; | |
257 case GrOptDrawState::kCoverageISA_SecondaryOutputType: | |
258 // Get (1-A) into coeff | |
259 coeff = GrGLSLExpr4::VectorCast(GrGLSLExpr1(1) - inputColor.a()); | |
260 break; | |
261 case GrOptDrawState::kCoverageISC_SecondaryOutputType: | |
262 // Get (1-RGBA) into coeff | |
263 coeff = GrGLSLExpr4(1) - inputColor; | |
264 break; | |
265 default: | |
266 SkFAIL("Unexpected Secondary Output"); | |
267 } | |
268 // Get coeff * coverage into modulate and then write that to the dual source
output. | |
269 this->codeAppendf("\t%s = %s;\n", secondaryOutputName, (coeff * inputCoverag
e).c_str()); | |
270 } | |
271 | |
272 void GrGLFragmentShaderBuilder::combineColorAndCoverage(const GrGLSLExpr4& input
Color, | |
273 const GrGLSLExpr4& input
Coverage) { | |
274 GrGLSLExpr4 fragColor = inputColor * inputCoverage; | |
275 switch (fProgramBuilder->header().fPrimaryOutputType) { | |
276 case GrOptDrawState::kModulate_PrimaryOutputType: | |
277 break; | |
278 case GrOptDrawState::kCombineWithDst_PrimaryOutputType: | |
279 { | |
280 // Tack on "+(1-coverage)dst onto the frag color. | |
281 GrGLSLExpr4 dstCoeff = GrGLSLExpr4(1) - inputCoverage; | |
282 GrGLSLExpr4 dstContribution = dstCoeff * GrGLSLExpr4(this->dstCo
lor()); | |
283 fragColor = fragColor + dstContribution; | |
284 } | |
285 break; | |
286 default: | |
287 SkFAIL("Unknown Primary Output"); | |
288 } | |
289 | |
290 // On any post 1.10 GLSL supporting GPU, we declare custom output | |
291 if (k110_GrGLSLGeneration != fProgramBuilder->gpu()->glslGeneration()) { | |
292 this->enableCustomOutput(); | |
293 } | |
294 | |
295 this->codeAppendf("\t%s = %s;\n", this->getPrimaryColorOutputName(), fragCol
or.c_str()); | |
296 } | |
297 | |
298 bool GrGLFragmentShaderBuilder::compileAndAttachShaders(GrGLuint programId, | |
299 SkTDArray<GrGLuint>* sha
derIds) const { | |
300 GrGpuGL* gpu = fProgramBuilder->gpu(); | |
301 SkString fragShaderSrc(GrGetGLSLVersionDecl(gpu->ctxInfo())); | |
302 fragShaderSrc.append(fExtensions); | |
303 append_default_precision_qualifier(kDefaultFragmentPrecision, | |
304 gpu->glStandard(), | |
305 &fragShaderSrc); | |
306 fProgramBuilder->appendUniformDecls(GrGLProgramBuilder::kFragment_Visibility
, &fragShaderSrc); | |
307 this->appendDecls(fInputs, &fragShaderSrc); | |
308 // We shouldn't have declared outputs on 1.10 | |
309 SkASSERT(k110_GrGLSLGeneration != gpu->glslGeneration() || fOutputs.empty())
; | |
310 this->appendDecls(fOutputs, &fragShaderSrc); | |
311 fragShaderSrc.append(fFunctions); | |
312 fragShaderSrc.append("void main() {\n"); | |
313 fragShaderSrc.append(fCode); | |
314 fragShaderSrc.append("}\n"); | |
315 | |
316 GrGLuint fragShaderId = GrGLCompileAndAttachShader(gpu->glContext(), program
Id, | |
317 GR_GL_FRAGMENT_SHADER, fr
agShaderSrc, | |
318 gpu->gpuStats()); | |
319 if (!fragShaderId) { | |
320 return false; | |
321 } | |
322 | |
323 *shaderIds->append() = fragShaderId; | |
324 | |
325 return true; | |
326 } | |
327 | |
328 void GrGLFragmentShaderBuilder::bindFragmentShaderLocations(GrGLuint programID)
{ | |
329 if (fHasCustomColorOutput) { | |
330 GL_CALL(BindFragDataLocation(programID, 0, declared_color_output_name())
); | |
331 } | |
332 if (fHasSecondaryOutput) { | |
333 GL_CALL(BindFragDataLocationIndexed(programID, 0, 1, dual_source_output_
name())); | |
334 } | |
335 } | |
336 | |
337 void GrGLFragmentShaderBuilder::addVarying(GrSLType type, | 201 void GrGLFragmentShaderBuilder::addVarying(GrSLType type, |
338 const char* name, | 202 const char* name, |
339 const char** fsInName, | 203 const char** fsInName, |
340 GrGLShaderVar::Precision fsPrecision) { | 204 GrGLShaderVar::Precision fsPrecision) { |
341 fInputs.push_back().set(type, GrGLShaderVar::kVaryingIn_TypeModifier, name,
fsPrecision); | 205 fInputs.push_back().set(type, GrGLShaderVar::kVaryingIn_TypeModifier, name,
fsPrecision); |
342 if (fsInName) { | 206 if (fsInName) { |
343 *fsInName = name; | 207 *fsInName = name; |
344 } | 208 } |
345 } | 209 } |
| 210 |
| 211 void GrGLFragmentShaderBuilder::bindProgramLocations(GrGLuint programId) { |
| 212 GrGpuGL* gpu = fProgramBuilder->gpu(); |
| 213 if (fHasCustomColorOutput) { |
| 214 GL_CALL(BindFragDataLocation(programId, 0, declared_color_output_name())
); |
| 215 } |
| 216 if (fHasSecondaryOutput) { |
| 217 GL_CALL(BindFragDataLocationIndexed(programId, 0, 1, dual_source_output_
name())); |
| 218 } |
| 219 } |
| 220 |
| 221 bool GrGLFragmentShaderBuilder::compileAndAttachShaders(GrGLuint programId, |
| 222 SkTDArray<GrGLuint>* sha
derIds) const { |
| 223 GrGpuGL* gpu = fProgramBuilder->gpu(); |
| 224 SkString fragShaderSrc(GrGetGLSLVersionDecl(gpu->ctxInfo())); |
| 225 fragShaderSrc.append(fExtensions); |
| 226 append_default_precision_qualifier(kDefaultFragmentPrecision, |
| 227 gpu->glStandard(), |
| 228 &fragShaderSrc); |
| 229 fProgramBuilder->appendUniformDecls(GrGLProgramBuilder::kFragment_Visibility
, &fragShaderSrc); |
| 230 fProgramBuilder->appendDecls(fInputs, &fragShaderSrc); |
| 231 // We shouldn't have declared outputs on 1.10 |
| 232 SkASSERT(k110_GrGLSLGeneration != gpu->glslGeneration() || fOutputs.empty())
; |
| 233 fProgramBuilder->appendDecls(fOutputs, &fragShaderSrc); |
| 234 fragShaderSrc.append(fFunctions); |
| 235 fragShaderSrc.append("void main() {\n"); |
| 236 fragShaderSrc.append(fCode); |
| 237 fragShaderSrc.append("}\n"); |
| 238 |
| 239 GrGLuint fragShaderId = GrGLCompileAndAttachShader(gpu->glContext(), program
Id, |
| 240 GR_GL_FRAGMENT_SHADER, fr
agShaderSrc, |
| 241 gpu->gpuStats()); |
| 242 if (!fragShaderId) { |
| 243 return false; |
| 244 } |
| 245 |
| 246 *shaderIds->append() = fragShaderId; |
| 247 |
| 248 return true; |
| 249 } |
| 250 |
| 251 void GrGLFragmentShaderBuilder::emitCodeBeforeEffects() { |
| 252 const GrGLProgramDesc::KeyHeader& header = fProgramBuilder->desc().getHeader
(); |
| 253 GrGpuGL* gpu = fProgramBuilder->gpu(); |
| 254 |
| 255 /////////////////////////////////////////////////////////////////////////// |
| 256 // emit code to read the dst copy texture, if necessary |
| 257 if (kNoDstRead_DstReadKey != header.fDstReadKey && !gpu->glCaps().fbFetchSup
port()) { |
| 258 bool topDown = SkToBool(kTopLeftOrigin_DstReadKeyBit & header.fDstReadKe
y); |
| 259 const char* dstCopyTopLeftName; |
| 260 const char* dstCopyCoordScaleName; |
| 261 const char* dstCopySamplerName; |
| 262 uint32_t configMask; |
| 263 if (SkToBool(kUseAlphaConfig_DstReadKeyBit & header.fDstReadKey)) { |
| 264 configMask = kA_GrColorComponentFlag; |
| 265 } else { |
| 266 configMask = kRGBA_GrColorComponentFlags; |
| 267 } |
| 268 fProgramBuilder->fUniformHandles.fDstCopySamplerUni = |
| 269 fProgramBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility
, |
| 270 kSampler2D_GrSLType, |
| 271 "DstCopySampler", |
| 272 &dstCopySamplerName); |
| 273 fProgramBuilder->fUniformHandles.fDstCopyTopLeftUni = |
| 274 fProgramBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility
, |
| 275 kVec2f_GrSLType, |
| 276 "DstCopyUpperLeft", |
| 277 &dstCopyTopLeftName); |
| 278 fProgramBuilder->fUniformHandles.fDstCopyScaleUni = |
| 279 fProgramBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility
, |
| 280 kVec2f_GrSLType, |
| 281 "DstCopyCoordScale", |
| 282 &dstCopyCoordScaleName); |
| 283 const char* fragPos = fragmentPosition(); |
| 284 |
| 285 this->codeAppend("// Read color from copy of the destination.\n"); |
| 286 this->codeAppendf("vec2 _dstTexCoord = (%s.xy - %s) * %s;", |
| 287 fragPos, dstCopyTopLeftName, dstCopyCoordScaleName); |
| 288 if (!topDown) { |
| 289 this->codeAppend("_dstTexCoord.y = 1.0 - _dstTexCoord.y;"); |
| 290 } |
| 291 this->codeAppendf("vec4 %s = ", kDstCopyColorName); |
| 292 this->appendTextureLookup(dstCopySamplerName, |
| 293 "_dstTexCoord", |
| 294 configMask, |
| 295 "rgba"); |
| 296 this->codeAppend(";"); |
| 297 } |
| 298 |
| 299 if (k110_GrGLSLGeneration != gpu->glslGeneration()) { |
| 300 fOutputs.push_back().set(kVec4f_GrSLType, |
| 301 GrGLShaderVar::kOut_TypeModifier, |
| 302 declared_color_output_name()); |
| 303 fHasCustomColorOutput = true; |
| 304 } |
| 305 } |
| 306 |
| 307 void GrGLFragmentShaderBuilder::emitCodeAfterEffects(const GrGLSLExpr4& inputCol
or, const GrGLSLExpr4& inputCoverage) { |
| 308 const GrGLProgramDesc::KeyHeader& header = fProgramBuilder->desc().getHeader
(); |
| 309 |
| 310 /////////////////////////////////////////////////////////////////////////// |
| 311 // write the secondary color output if necessary |
| 312 if (GrOptDrawState::kNone_SecondaryOutputType != header.fSecondaryOutputType
) { |
| 313 const char* secondaryOutputName = this->enableSecondaryOutput(); |
| 314 GrGLSLExpr4 coeff(1); |
| 315 switch (header.fSecondaryOutputType) { |
| 316 case GrOptDrawState::kCoverage_SecondaryOutputType: |
| 317 break; |
| 318 case GrOptDrawState::kCoverageISA_SecondaryOutputType: |
| 319 // Get (1-A) into coeff |
| 320 coeff = GrGLSLExpr4::VectorCast(GrGLSLExpr1(1) - inputColor.a())
; |
| 321 break; |
| 322 case GrOptDrawState::kCoverageISC_SecondaryOutputType: |
| 323 // Get (1-RGBA) into coeff |
| 324 coeff = GrGLSLExpr4(1) - inputColor; |
| 325 break; |
| 326 default: |
| 327 SkFAIL("Unexpected Secondary Output"); |
| 328 } |
| 329 // Get coeff * coverage into modulate and then write that to the dual so
urce output. |
| 330 codeAppendf("\t%s = %s;\n", secondaryOutputName, (coeff * inputCoverage)
.c_str()); |
| 331 } |
| 332 |
| 333 /////////////////////////////////////////////////////////////////////////// |
| 334 // combine color and coverage as frag color |
| 335 |
| 336 // Get "color * coverage" into fragColor |
| 337 GrGLSLExpr4 fragColor = inputColor * inputCoverage; |
| 338 switch (header.fPrimaryOutputType) { |
| 339 case GrOptDrawState::kModulate_PrimaryOutputType: |
| 340 break; |
| 341 case GrOptDrawState::kCombineWithDst_PrimaryOutputType: |
| 342 { |
| 343 // Tack on "+(1-coverage)dst onto the frag color. |
| 344 GrGLSLExpr4 dstCoeff = GrGLSLExpr4(1) - inputCoverage; |
| 345 GrGLSLExpr4 dstContribution = dstCoeff * GrGLSLExpr4(dstColor())
; |
| 346 fragColor = fragColor + dstContribution; |
| 347 } |
| 348 break; |
| 349 default: |
| 350 SkFAIL("Unknown Primary Output"); |
| 351 } |
| 352 codeAppendf("\t%s = %s;\n", this->getColorOutputName(), fragColor.c_str()); |
| 353 } |
| 354 |
| 355 const char* GrGLFragmentShaderBuilder::enableSecondaryOutput() { |
| 356 if (!fHasSecondaryOutput) { |
| 357 fOutputs.push_back().set(kVec4f_GrSLType, |
| 358 GrGLShaderVar::kOut_TypeModifier, |
| 359 dual_source_output_name()); |
| 360 fHasSecondaryOutput = true; |
| 361 } |
| 362 return dual_source_output_name(); |
| 363 } |
| 364 |
| 365 const char* GrGLFragmentShaderBuilder::getColorOutputName() const { |
| 366 return fHasCustomColorOutput ? declared_color_output_name() : "gl_FragColor"
; |
| 367 } |
| 368 |
OLD | NEW |