• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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