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
Create(GrGpuGL * gpu,const GrGLProgramDesc & desc,const GrEffectStage * colorStages[],const GrEffectStage * coverageStages[])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
GrGLProgram(GrGpuGL * gpu,const GrGLProgramDesc & desc,const GrEffectStage * colorStages[],const GrEffectStage * coverageStages[])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
~GrGLProgram()65 GrGLProgram::~GrGLProgram() {
66 if (fProgramID) {
67 GL_CALL(DeleteProgram(fProgramID));
68 }
69 }
70
abandon()71 void GrGLProgram::abandon() {
72 fProgramID = 0;
73 }
74
overrideBlend(GrBlendCoeff * srcCoeff,GrBlendCoeff * dstCoeff) const75 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
genProgram(GrGLShaderBuilder * builder,const GrEffectStage * colorStages[],const GrEffectStage * coverageStages[])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 // discard if coverage is zero
124 if (header.fDiscardIfZeroCoverage && !inCoverage.isOnes()) {
125 if (inCoverage.isZeros()) {
126 // This is unfortunate.
127 builder->fsCodeAppend("\tdiscard;\n");
128 } else {
129 builder->fsCodeAppendf("\tif (all(lessThanEqual(%s, vec4(0.0)))) {\n\t\tdiscard;\n\t}\n",
130 inCoverage.c_str());
131 }
132 }
133
134 if (GrGLProgramDesc::CoverageOutputUsesSecondaryOutput(header.fCoverageOutput)) {
135 const char* secondaryOutputName = builder->enableSecondaryOutput();
136
137 // default coeff to ones for kCoverage_DualSrcOutput
138 GrGLSLExpr4 coeff(1);
139 if (GrGLProgramDesc::kSecondaryCoverageISA_CoverageOutput == header.fCoverageOutput) {
140 // Get (1-A) into coeff
141 coeff = GrGLSLExpr4::VectorCast(GrGLSLExpr1(1) - inColor.a());
142 } else if (GrGLProgramDesc::kSecondaryCoverageISC_CoverageOutput == header.fCoverageOutput) {
143 // Get (1-RGBA) into coeff
144 coeff = GrGLSLExpr4(1) - inColor;
145 }
146 // Get coeff * coverage into modulate and then write that to the dual source output.
147 builder->fsCodeAppendf("\t%s = %s;\n", secondaryOutputName, (coeff * inCoverage).c_str());
148 }
149
150 ///////////////////////////////////////////////////////////////////////////
151 // combine color and coverage as frag color
152
153 // Get "color * coverage" into fragColor
154 GrGLSLExpr4 fragColor = inColor * inCoverage;
155 // Now tack on "+(1-coverage)dst onto the frag color if we were asked to do so.
156 if (GrGLProgramDesc::kCombineWithDst_CoverageOutput == header.fCoverageOutput) {
157 GrGLSLExpr4 dstCoeff = GrGLSLExpr4(1) - inCoverage;
158
159 GrGLSLExpr4 dstContribution = dstCoeff * GrGLSLExpr4(builder->dstColor());
160
161 fragColor = fragColor + dstContribution;
162 }
163 builder->fsCodeAppendf("\t%s = %s;\n", builder->getColorOutputName(), fragColor.c_str());
164
165 if (!builder->finish(&fProgramID)) {
166 return false;
167 }
168
169 fUniformHandles.fRTHeightUni = builder->getRTHeightUniform();
170 fUniformHandles.fDstCopyTopLeftUni = builder->getDstCopyTopLeftUniform();
171 fUniformHandles.fDstCopyScaleUni = builder->getDstCopyScaleUniform();
172 fUniformHandles.fColorUni = builder->getColorUniform();
173 fUniformHandles.fCoverageUni = builder->getCoverageUniform();
174 fUniformHandles.fDstCopySamplerUni = builder->getDstCopySamplerUniform();
175 // This must be called after we set fDstCopySamplerUni above.
176 this->initSamplerUniforms();
177
178 return true;
179 }
180
initSamplerUniforms()181 void GrGLProgram::initSamplerUniforms() {
182 GL_CALL(UseProgram(fProgramID));
183 GrGLint texUnitIdx = 0;
184 if (fUniformHandles.fDstCopySamplerUni.isValid()) {
185 fUniformManager.setSampler(fUniformHandles.fDstCopySamplerUni, texUnitIdx);
186 fDstCopyTexUnit = texUnitIdx++;
187 }
188 fColorEffects->initSamplers(fUniformManager, &texUnitIdx);
189 fCoverageEffects->initSamplers(fUniformManager, &texUnitIdx);
190 }
191
192 ///////////////////////////////////////////////////////////////////////////////
193
setData(GrDrawState::BlendOptFlags blendOpts,const GrEffectStage * colorStages[],const GrEffectStage * coverageStages[],const GrDeviceCoordTexture * dstCopy,SharedGLState * sharedState)194 void GrGLProgram::setData(GrDrawState::BlendOptFlags blendOpts,
195 const GrEffectStage* colorStages[],
196 const GrEffectStage* coverageStages[],
197 const GrDeviceCoordTexture* dstCopy,
198 SharedGLState* sharedState) {
199 const GrDrawState& drawState = fGpu->getDrawState();
200
201 GrColor color;
202 GrColor coverage;
203 if (blendOpts & GrDrawState::kEmitTransBlack_BlendOptFlag) {
204 color = 0;
205 coverage = 0;
206 } else if (blendOpts & GrDrawState::kEmitCoverage_BlendOptFlag) {
207 color = 0xffffffff;
208 coverage = drawState.getCoverageColor();
209 } else {
210 color = drawState.getColor();
211 coverage = drawState.getCoverageColor();
212 }
213
214 this->setColor(drawState, color, sharedState);
215 this->setCoverage(drawState, coverage, sharedState);
216 this->setMatrixAndRenderTargetHeight(drawState);
217
218 if (NULL != dstCopy) {
219 if (fUniformHandles.fDstCopyTopLeftUni.isValid()) {
220 fUniformManager.set2f(fUniformHandles.fDstCopyTopLeftUni,
221 static_cast<GrGLfloat>(dstCopy->offset().fX),
222 static_cast<GrGLfloat>(dstCopy->offset().fY));
223 fUniformManager.set2f(fUniformHandles.fDstCopyScaleUni,
224 1.f / dstCopy->texture()->width(),
225 1.f / dstCopy->texture()->height());
226 GrGLTexture* texture = static_cast<GrGLTexture*>(dstCopy->texture());
227 static GrTextureParams kParams; // the default is clamp, nearest filtering.
228 fGpu->bindTexture(fDstCopyTexUnit, kParams, texture);
229 } else {
230 SkASSERT(!fUniformHandles.fDstCopyScaleUni.isValid());
231 SkASSERT(!fUniformHandles.fDstCopySamplerUni.isValid());
232 }
233 } else {
234 SkASSERT(!fUniformHandles.fDstCopyTopLeftUni.isValid());
235 SkASSERT(!fUniformHandles.fDstCopyScaleUni.isValid());
236 SkASSERT(!fUniformHandles.fDstCopySamplerUni.isValid());
237 }
238
239 fColorEffects->setData(fGpu, fUniformManager, colorStages);
240 fCoverageEffects->setData(fGpu, fUniformManager, coverageStages);
241
242
243 // TexGen state applies to the the fixed function vertex shader. For custom shaders, it's
244 // ignored, so we don't need to change the texgen settings in that case.
245 if (!fHasVertexShader) {
246 fGpu->flushTexGenSettings(fNumTexCoordSets);
247 }
248 }
249
setColor(const GrDrawState & drawState,GrColor color,SharedGLState * sharedState)250 void GrGLProgram::setColor(const GrDrawState& drawState,
251 GrColor color,
252 SharedGLState* sharedState) {
253 const GrGLProgramDesc::KeyHeader& header = fDesc.getHeader();
254 if (!drawState.hasColorVertexAttribute()) {
255 switch (header.fColorInput) {
256 case GrGLProgramDesc::kAttribute_ColorInput:
257 SkASSERT(-1 != header.fColorAttributeIndex);
258 if (sharedState->fConstAttribColor != color ||
259 sharedState->fConstAttribColorIndex != header.fColorAttributeIndex) {
260 // OpenGL ES only supports the float varieties of glVertexAttrib
261 GrGLfloat c[4];
262 GrColorToRGBAFloat(color, c);
263 GL_CALL(VertexAttrib4fv(header.fColorAttributeIndex, c));
264 sharedState->fConstAttribColor = color;
265 sharedState->fConstAttribColorIndex = header.fColorAttributeIndex;
266 }
267 break;
268 case GrGLProgramDesc::kUniform_ColorInput:
269 if (fColor != color && fUniformHandles.fColorUni.isValid()) {
270 // OpenGL ES doesn't support unsigned byte varieties of glUniform
271 GrGLfloat c[4];
272 GrColorToRGBAFloat(color, c);
273 fUniformManager.set4fv(fUniformHandles.fColorUni, 1, c);
274 fColor = color;
275 }
276 sharedState->fConstAttribColorIndex = -1;
277 break;
278 case GrGLProgramDesc::kSolidWhite_ColorInput:
279 case GrGLProgramDesc::kTransBlack_ColorInput:
280 sharedState->fConstAttribColorIndex = -1;
281 break;
282 default:
283 GrCrash("Unknown color type.");
284 }
285 } else {
286 sharedState->fConstAttribColorIndex = -1;
287 }
288 }
289
setCoverage(const GrDrawState & drawState,GrColor coverage,SharedGLState * sharedState)290 void GrGLProgram::setCoverage(const GrDrawState& drawState,
291 GrColor coverage,
292 SharedGLState* sharedState) {
293 const GrGLProgramDesc::KeyHeader& header = fDesc.getHeader();
294 if (!drawState.hasCoverageVertexAttribute()) {
295 switch (header.fCoverageInput) {
296 case GrGLProgramDesc::kAttribute_ColorInput:
297 if (sharedState->fConstAttribCoverage != coverage ||
298 sharedState->fConstAttribCoverageIndex != header.fCoverageAttributeIndex) {
299 // OpenGL ES only supports the float varieties of glVertexAttrib
300 GrGLfloat c[4];
301 GrColorToRGBAFloat(coverage, c);
302 GL_CALL(VertexAttrib4fv(header.fCoverageAttributeIndex, c));
303 sharedState->fConstAttribCoverage = coverage;
304 sharedState->fConstAttribCoverageIndex = header.fCoverageAttributeIndex;
305 }
306 break;
307 case GrGLProgramDesc::kUniform_ColorInput:
308 if (fCoverage != coverage) {
309 // OpenGL ES doesn't support unsigned byte varieties of glUniform
310 GrGLfloat c[4];
311 GrColorToRGBAFloat(coverage, c);
312 fUniformManager.set4fv(fUniformHandles.fCoverageUni, 1, c);
313 fCoverage = coverage;
314 }
315 sharedState->fConstAttribCoverageIndex = -1;
316 break;
317 case GrGLProgramDesc::kSolidWhite_ColorInput:
318 case GrGLProgramDesc::kTransBlack_ColorInput:
319 sharedState->fConstAttribCoverageIndex = -1;
320 break;
321 default:
322 GrCrash("Unknown coverage type.");
323 }
324 } else {
325 sharedState->fConstAttribCoverageIndex = -1;
326 }
327 }
328
setMatrixAndRenderTargetHeight(const GrDrawState & drawState)329 void GrGLProgram::setMatrixAndRenderTargetHeight(const GrDrawState& drawState) {
330 const GrRenderTarget* rt = drawState.getRenderTarget();
331 SkISize size;
332 size.set(rt->width(), rt->height());
333
334 // Load the RT height uniform if it is needed to y-flip gl_FragCoord.
335 if (fUniformHandles.fRTHeightUni.isValid() &&
336 fMatrixState.fRenderTargetSize.fHeight != size.fHeight) {
337 fUniformManager.set1f(fUniformHandles.fRTHeightUni, SkIntToScalar(size.fHeight));
338 }
339
340 if (!fHasVertexShader) {
341 SkASSERT(!fUniformHandles.fViewMatrixUni.isValid());
342 fGpu->setProjectionMatrix(drawState.getViewMatrix(), size, rt->origin());
343 } else if (fMatrixState.fRenderTargetOrigin != rt->origin() ||
344 fMatrixState.fRenderTargetSize != size ||
345 !fMatrixState.fViewMatrix.cheapEqualTo(drawState.getViewMatrix())) {
346 SkASSERT(fUniformHandles.fViewMatrixUni.isValid());
347
348 fMatrixState.fViewMatrix = drawState.getViewMatrix();
349 fMatrixState.fRenderTargetSize = size;
350 fMatrixState.fRenderTargetOrigin = rt->origin();
351
352 GrGLfloat viewMatrix[3 * 3];
353 fMatrixState.getGLMatrix<3>(viewMatrix);
354 fUniformManager.setMatrix3f(fUniformHandles.fViewMatrixUni, viewMatrix);
355 }
356 }
357