|
1 /* |
|
2 * Copyright 2011 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 #include "GrGLProgram.h" |
|
9 |
|
10 #include "GrAllocator.h" |
|
11 #include "GrEffect.h" |
|
12 #include "GrCoordTransform.h" |
|
13 #include "GrDrawEffect.h" |
|
14 #include "GrGLEffect.h" |
|
15 #include "GrGpuGL.h" |
|
16 #include "GrGLShaderVar.h" |
|
17 #include "GrGLSL.h" |
|
18 #include "SkXfermode.h" |
|
19 |
|
20 #define GL_CALL(X) GR_GL_CALL(fGpu->glInterface(), X) |
|
21 #define GL_CALL_RET(R, X) GR_GL_CALL_RET(fGpu->glInterface(), R, X) |
|
22 |
|
23 GrGLProgram* GrGLProgram::Create(GrGpuGL* gpu, |
|
24 const GrGLProgramDesc& desc, |
|
25 const GrEffectStage* colorStages[], |
|
26 const GrEffectStage* coverageStages[]) { |
|
27 GrGLProgram* program = SkNEW_ARGS(GrGLProgram, (gpu, desc, colorStages, coverageStages)); |
|
28 if (!program->succeeded()) { |
|
29 delete program; |
|
30 program = NULL; |
|
31 } |
|
32 return program; |
|
33 } |
|
34 |
|
35 GrGLProgram::GrGLProgram(GrGpuGL* gpu, |
|
36 const GrGLProgramDesc& desc, |
|
37 const GrEffectStage* colorStages[], |
|
38 const GrEffectStage* coverageStages[]) |
|
39 : fGpu(gpu) |
|
40 , fUniformManager(gpu) |
|
41 , fHasVertexShader(false) |
|
42 , fNumTexCoordSets(0) { |
|
43 fDesc = desc; |
|
44 fProgramID = 0; |
|
45 |
|
46 fDstCopyTexUnit = -1; |
|
47 |
|
48 fColor = GrColor_ILLEGAL; |
|
49 |
|
50 if (fDesc.getHeader().fHasVertexCode || |
|
51 !fGpu->shouldUseFixedFunctionTexturing()) { |
|
52 GrGLFullShaderBuilder fullBuilder(fGpu, fUniformManager, fDesc); |
|
53 if (this->genProgram(&fullBuilder, colorStages, coverageStages)) { |
|
54 fUniformHandles.fViewMatrixUni = fullBuilder.getViewMatrixUniform(); |
|
55 fHasVertexShader = true; |
|
56 } |
|
57 } else { |
|
58 GrGLFragmentOnlyShaderBuilder fragmentOnlyBuilder(fGpu, fUniformManager, fDesc); |
|
59 if (this->genProgram(&fragmentOnlyBuilder, colorStages, coverageStages)) { |
|
60 fNumTexCoordSets = fragmentOnlyBuilder.getNumTexCoordSets(); |
|
61 } |
|
62 } |
|
63 } |
|
64 |
|
65 GrGLProgram::~GrGLProgram() { |
|
66 if (fProgramID) { |
|
67 GL_CALL(DeleteProgram(fProgramID)); |
|
68 } |
|
69 } |
|
70 |
|
71 void GrGLProgram::abandon() { |
|
72 fProgramID = 0; |
|
73 } |
|
74 |
|
75 void GrGLProgram::overrideBlend(GrBlendCoeff* srcCoeff, |
|
76 GrBlendCoeff* dstCoeff) const { |
|
77 switch (fDesc.getHeader().fCoverageOutput) { |
|
78 case GrGLProgramDesc::kModulate_CoverageOutput: |
|
79 break; |
|
80 // The prog will write a coverage value to the secondary |
|
81 // output and the dst is blended by one minus that value. |
|
82 case GrGLProgramDesc::kSecondaryCoverage_CoverageOutput: |
|
83 case GrGLProgramDesc::kSecondaryCoverageISA_CoverageOutput: |
|
84 case GrGLProgramDesc::kSecondaryCoverageISC_CoverageOutput: |
|
85 *dstCoeff = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff; |
|
86 break; |
|
87 case GrGLProgramDesc::kCombineWithDst_CoverageOutput: |
|
88 // We should only have set this if the blend was specified as (1, 0) |
|
89 SkASSERT(kOne_GrBlendCoeff == *srcCoeff && kZero_GrBlendCoeff == *dstCoeff); |
|
90 break; |
|
91 default: |
|
92 GrCrash("Unexpected coverage output"); |
|
93 break; |
|
94 } |
|
95 } |
|
96 |
|
97 bool GrGLProgram::genProgram(GrGLShaderBuilder* builder, |
|
98 const GrEffectStage* colorStages[], |
|
99 const GrEffectStage* coverageStages[]) { |
|
100 SkASSERT(0 == fProgramID); |
|
101 |
|
102 const GrGLProgramDesc::KeyHeader& header = fDesc.getHeader(); |
|
103 |
|
104 // incoming color to current stage being processed. |
|
105 GrGLSLExpr4 inColor = builder->getInputColor(); |
|
106 |
|
107 fColorEffects.reset( |
|
108 builder->createAndEmitEffects(colorStages, |
|
109 fDesc.effectKeys(), |
|
110 fDesc.numColorEffects(), |
|
111 &inColor)); |
|
112 |
|
113 /////////////////////////////////////////////////////////////////////////// |
|
114 // compute the partial coverage |
|
115 GrGLSLExpr4 inCoverage = builder->getInputCoverage(); |
|
116 |
|
117 fCoverageEffects.reset( |
|
118 builder->createAndEmitEffects(coverageStages, |
|
119 fDesc.getEffectKeys() + fDesc.numColorEffects(), |
|
120 fDesc.numCoverageEffects(), |
|
121 &inCoverage)); |
|
122 |
|
123 if (GrGLProgramDesc::CoverageOutputUsesSecondaryOutput(header.fCoverageOutput)) { |
|
124 const char* secondaryOutputName = builder->enableSecondaryOutput(); |
|
125 |
|
126 // default coeff to ones for kCoverage_DualSrcOutput |
|
127 GrGLSLExpr4 coeff(1); |
|
128 if (GrGLProgramDesc::kSecondaryCoverageISA_CoverageOutput == header.fCoverageOutput) { |
|
129 // Get (1-A) into coeff |
|
130 coeff = GrGLSLExpr4::VectorCast(GrGLSLExpr1(1) - inColor.a()); |
|
131 } else if (GrGLProgramDesc::kSecondaryCoverageISC_CoverageOutput == header.fCoverageOutput) { |
|
132 // Get (1-RGBA) into coeff |
|
133 coeff = GrGLSLExpr4(1) - inColor; |
|
134 } |
|
135 // Get coeff * coverage into modulate and then write that to the dual source output. |
|
136 builder->fsCodeAppendf("\t%s = %s;\n", secondaryOutputName, (coeff * inCoverage).c_str()); |
|
137 } |
|
138 |
|
139 /////////////////////////////////////////////////////////////////////////// |
|
140 // combine color and coverage as frag color |
|
141 |
|
142 // Get "color * coverage" into fragColor |
|
143 GrGLSLExpr4 fragColor = inColor * inCoverage; |
|
144 // Now tack on "+(1-coverage)dst onto the frag color if we were asked to do so. |
|
145 if (GrGLProgramDesc::kCombineWithDst_CoverageOutput == header.fCoverageOutput) { |
|
146 GrGLSLExpr4 dstCoeff = GrGLSLExpr4(1) - inCoverage; |
|
147 |
|
148 GrGLSLExpr4 dstContribution = dstCoeff * GrGLSLExpr4(builder->dstColor()); |
|
149 |
|
150 fragColor = fragColor + dstContribution; |
|
151 } |
|
152 builder->fsCodeAppendf("\t%s = %s;\n", builder->getColorOutputName(), fragColor.c_str()); |
|
153 |
|
154 if (!builder->finish(&fProgramID)) { |
|
155 return false; |
|
156 } |
|
157 |
|
158 fUniformHandles.fRTHeightUni = builder->getRTHeightUniform(); |
|
159 fUniformHandles.fDstCopyTopLeftUni = builder->getDstCopyTopLeftUniform(); |
|
160 fUniformHandles.fDstCopyScaleUni = builder->getDstCopyScaleUniform(); |
|
161 fUniformHandles.fColorUni = builder->getColorUniform(); |
|
162 fUniformHandles.fCoverageUni = builder->getCoverageUniform(); |
|
163 fUniformHandles.fDstCopySamplerUni = builder->getDstCopySamplerUniform(); |
|
164 // This must be called after we set fDstCopySamplerUni above. |
|
165 this->initSamplerUniforms(); |
|
166 |
|
167 return true; |
|
168 } |
|
169 |
|
170 void GrGLProgram::initSamplerUniforms() { |
|
171 GL_CALL(UseProgram(fProgramID)); |
|
172 GrGLint texUnitIdx = 0; |
|
173 if (fUniformHandles.fDstCopySamplerUni.isValid()) { |
|
174 fUniformManager.setSampler(fUniformHandles.fDstCopySamplerUni, texUnitIdx); |
|
175 fDstCopyTexUnit = texUnitIdx++; |
|
176 } |
|
177 fColorEffects->initSamplers(fUniformManager, &texUnitIdx); |
|
178 fCoverageEffects->initSamplers(fUniformManager, &texUnitIdx); |
|
179 } |
|
180 |
|
181 /////////////////////////////////////////////////////////////////////////////// |
|
182 |
|
183 void GrGLProgram::setData(GrDrawState::BlendOptFlags blendOpts, |
|
184 const GrEffectStage* colorStages[], |
|
185 const GrEffectStage* coverageStages[], |
|
186 const GrDeviceCoordTexture* dstCopy, |
|
187 SharedGLState* sharedState) { |
|
188 const GrDrawState& drawState = fGpu->getDrawState(); |
|
189 |
|
190 GrColor color; |
|
191 GrColor coverage; |
|
192 if (blendOpts & GrDrawState::kEmitTransBlack_BlendOptFlag) { |
|
193 color = 0; |
|
194 coverage = 0; |
|
195 } else if (blendOpts & GrDrawState::kEmitCoverage_BlendOptFlag) { |
|
196 color = 0xffffffff; |
|
197 coverage = drawState.getCoverageColor(); |
|
198 } else { |
|
199 color = drawState.getColor(); |
|
200 coverage = drawState.getCoverageColor(); |
|
201 } |
|
202 |
|
203 this->setColor(drawState, color, sharedState); |
|
204 this->setCoverage(drawState, coverage, sharedState); |
|
205 this->setMatrixAndRenderTargetHeight(drawState); |
|
206 |
|
207 if (NULL != dstCopy) { |
|
208 if (fUniformHandles.fDstCopyTopLeftUni.isValid()) { |
|
209 fUniformManager.set2f(fUniformHandles.fDstCopyTopLeftUni, |
|
210 static_cast<GrGLfloat>(dstCopy->offset().fX), |
|
211 static_cast<GrGLfloat>(dstCopy->offset().fY)); |
|
212 fUniformManager.set2f(fUniformHandles.fDstCopyScaleUni, |
|
213 1.f / dstCopy->texture()->width(), |
|
214 1.f / dstCopy->texture()->height()); |
|
215 GrGLTexture* texture = static_cast<GrGLTexture*>(dstCopy->texture()); |
|
216 static GrTextureParams kParams; // the default is clamp, nearest filtering. |
|
217 fGpu->bindTexture(fDstCopyTexUnit, kParams, texture); |
|
218 } else { |
|
219 SkASSERT(!fUniformHandles.fDstCopyScaleUni.isValid()); |
|
220 SkASSERT(!fUniformHandles.fDstCopySamplerUni.isValid()); |
|
221 } |
|
222 } else { |
|
223 SkASSERT(!fUniformHandles.fDstCopyTopLeftUni.isValid()); |
|
224 SkASSERT(!fUniformHandles.fDstCopyScaleUni.isValid()); |
|
225 SkASSERT(!fUniformHandles.fDstCopySamplerUni.isValid()); |
|
226 } |
|
227 |
|
228 fColorEffects->setData(fGpu, fUniformManager, colorStages); |
|
229 fCoverageEffects->setData(fGpu, fUniformManager, coverageStages); |
|
230 |
|
231 |
|
232 // TexGen state applies to the the fixed function vertex shader. For custom shaders, it's |
|
233 // ignored, so we don't need to change the texgen settings in that case. |
|
234 if (!fHasVertexShader) { |
|
235 fGpu->flushTexGenSettings(fNumTexCoordSets); |
|
236 } |
|
237 } |
|
238 |
|
239 void GrGLProgram::setColor(const GrDrawState& drawState, |
|
240 GrColor color, |
|
241 SharedGLState* sharedState) { |
|
242 const GrGLProgramDesc::KeyHeader& header = fDesc.getHeader(); |
|
243 if (!drawState.hasColorVertexAttribute()) { |
|
244 switch (header.fColorInput) { |
|
245 case GrGLProgramDesc::kAttribute_ColorInput: |
|
246 SkASSERT(-1 != header.fColorAttributeIndex); |
|
247 if (sharedState->fConstAttribColor != color || |
|
248 sharedState->fConstAttribColorIndex != header.fColorAttributeIndex) { |
|
249 // OpenGL ES only supports the float varieties of glVertexAttrib |
|
250 GrGLfloat c[4]; |
|
251 GrColorToRGBAFloat(color, c); |
|
252 GL_CALL(VertexAttrib4fv(header.fColorAttributeIndex, c)); |
|
253 sharedState->fConstAttribColor = color; |
|
254 sharedState->fConstAttribColorIndex = header.fColorAttributeIndex; |
|
255 } |
|
256 break; |
|
257 case GrGLProgramDesc::kUniform_ColorInput: |
|
258 if (fColor != color && fUniformHandles.fColorUni.isValid()) { |
|
259 // OpenGL ES doesn't support unsigned byte varieties of glUniform |
|
260 GrGLfloat c[4]; |
|
261 GrColorToRGBAFloat(color, c); |
|
262 fUniformManager.set4fv(fUniformHandles.fColorUni, 1, c); |
|
263 fColor = color; |
|
264 } |
|
265 sharedState->fConstAttribColorIndex = -1; |
|
266 break; |
|
267 case GrGLProgramDesc::kSolidWhite_ColorInput: |
|
268 case GrGLProgramDesc::kTransBlack_ColorInput: |
|
269 sharedState->fConstAttribColorIndex = -1; |
|
270 break; |
|
271 default: |
|
272 GrCrash("Unknown color type."); |
|
273 } |
|
274 } else { |
|
275 sharedState->fConstAttribColorIndex = -1; |
|
276 } |
|
277 } |
|
278 |
|
279 void GrGLProgram::setCoverage(const GrDrawState& drawState, |
|
280 GrColor coverage, |
|
281 SharedGLState* sharedState) { |
|
282 const GrGLProgramDesc::KeyHeader& header = fDesc.getHeader(); |
|
283 if (!drawState.hasCoverageVertexAttribute()) { |
|
284 switch (header.fCoverageInput) { |
|
285 case GrGLProgramDesc::kAttribute_ColorInput: |
|
286 if (sharedState->fConstAttribCoverage != coverage || |
|
287 sharedState->fConstAttribCoverageIndex != header.fCoverageAttributeIndex) { |
|
288 // OpenGL ES only supports the float varieties of glVertexAttrib |
|
289 GrGLfloat c[4]; |
|
290 GrColorToRGBAFloat(coverage, c); |
|
291 GL_CALL(VertexAttrib4fv(header.fCoverageAttributeIndex, c)); |
|
292 sharedState->fConstAttribCoverage = coverage; |
|
293 sharedState->fConstAttribCoverageIndex = header.fCoverageAttributeIndex; |
|
294 } |
|
295 break; |
|
296 case GrGLProgramDesc::kUniform_ColorInput: |
|
297 if (fCoverage != coverage) { |
|
298 // OpenGL ES doesn't support unsigned byte varieties of glUniform |
|
299 GrGLfloat c[4]; |
|
300 GrColorToRGBAFloat(coverage, c); |
|
301 fUniformManager.set4fv(fUniformHandles.fCoverageUni, 1, c); |
|
302 fCoverage = coverage; |
|
303 } |
|
304 sharedState->fConstAttribCoverageIndex = -1; |
|
305 break; |
|
306 case GrGLProgramDesc::kSolidWhite_ColorInput: |
|
307 case GrGLProgramDesc::kTransBlack_ColorInput: |
|
308 sharedState->fConstAttribCoverageIndex = -1; |
|
309 break; |
|
310 default: |
|
311 GrCrash("Unknown coverage type."); |
|
312 } |
|
313 } else { |
|
314 sharedState->fConstAttribCoverageIndex = -1; |
|
315 } |
|
316 } |
|
317 |
|
318 void GrGLProgram::setMatrixAndRenderTargetHeight(const GrDrawState& drawState) { |
|
319 const GrRenderTarget* rt = drawState.getRenderTarget(); |
|
320 SkISize size; |
|
321 size.set(rt->width(), rt->height()); |
|
322 |
|
323 // Load the RT height uniform if it is needed to y-flip gl_FragCoord. |
|
324 if (fUniformHandles.fRTHeightUni.isValid() && |
|
325 fMatrixState.fRenderTargetSize.fHeight != size.fHeight) { |
|
326 fUniformManager.set1f(fUniformHandles.fRTHeightUni, SkIntToScalar(size.fHeight)); |
|
327 } |
|
328 |
|
329 if (!fHasVertexShader) { |
|
330 SkASSERT(!fUniformHandles.fViewMatrixUni.isValid()); |
|
331 fGpu->setProjectionMatrix(drawState.getViewMatrix(), size, rt->origin()); |
|
332 } else if (fMatrixState.fRenderTargetOrigin != rt->origin() || |
|
333 fMatrixState.fRenderTargetSize != size || |
|
334 !fMatrixState.fViewMatrix.cheapEqualTo(drawState.getViewMatrix())) { |
|
335 SkASSERT(fUniformHandles.fViewMatrixUni.isValid()); |
|
336 |
|
337 fMatrixState.fViewMatrix = drawState.getViewMatrix(); |
|
338 fMatrixState.fRenderTargetSize = size; |
|
339 fMatrixState.fRenderTargetOrigin = rt->origin(); |
|
340 |
|
341 GrGLfloat viewMatrix[3 * 3]; |
|
342 fMatrixState.getGLMatrix<3>(viewMatrix); |
|
343 fUniformManager.setMatrix3f(fUniformHandles.fViewMatrixUni, viewMatrix); |
|
344 } |
|
345 } |