GrGLProgram.cpp revision 824c346b6e0e114063c1a8ad4ba7c3a669ee2cff
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
20SK_DEFINE_INST_COUNT(GrGLProgram)
21
22#define GL_CALL(X) GR_GL_CALL(fGpu->glInterface(), X)
23#define GL_CALL_RET(R, X) GR_GL_CALL_RET(fGpu->glInterface(), R, X)
24
25GrGLProgram* GrGLProgram::Create(GrGpuGL* gpu,
26                                 const GrGLProgramDesc& desc,
27                                 const GrEffectStage* colorStages[],
28                                 const GrEffectStage* coverageStages[]) {
29    GrGLProgram* program = SkNEW_ARGS(GrGLProgram, (gpu, desc, colorStages, coverageStages));
30    if (!program->succeeded()) {
31        delete program;
32        program = NULL;
33    }
34    return program;
35}
36
37GrGLProgram::GrGLProgram(GrGpuGL* gpu,
38                         const GrGLProgramDesc& desc,
39                         const GrEffectStage* colorStages[],
40                         const GrEffectStage* coverageStages[])
41: fGpu(gpu)
42, fUniformManager(gpu)
43, fHasVertexShader(false)
44, fNumTexCoordSets(0) {
45    fDesc = desc;
46    fProgramID = 0;
47
48    fDstCopyTexUnit = -1;
49
50    fColor = GrColor_ILLEGAL;
51    fColorFilterColor = GrColor_ILLEGAL;
52
53    if (fDesc.getHeader().fHasVertexCode ||
54        !fGpu->glCaps().fixedFunctionSupport() ||
55        !fGpu->glCaps().pathRenderingSupport()) {
56
57        GrGLFullShaderBuilder fullBuilder(fGpu, fUniformManager, fDesc);
58        if (this->genProgram(&fullBuilder, colorStages, coverageStages)) {
59            fUniformHandles.fViewMatrixUni = fullBuilder.getViewMatrixUniform();
60            fHasVertexShader = true;
61        }
62    } else {
63        GrGLFragmentOnlyShaderBuilder fragmentOnlyBuilder(fGpu, fUniformManager, fDesc);
64        if (this->genProgram(&fragmentOnlyBuilder, colorStages, coverageStages)) {
65            fNumTexCoordSets = fragmentOnlyBuilder.getNumTexCoordSets();
66        }
67    }
68}
69
70GrGLProgram::~GrGLProgram() {
71    if (fProgramID) {
72        GL_CALL(DeleteProgram(fProgramID));
73    }
74}
75
76void GrGLProgram::abandon() {
77    fProgramID = 0;
78}
79
80void GrGLProgram::overrideBlend(GrBlendCoeff* srcCoeff,
81                                GrBlendCoeff* dstCoeff) const {
82    switch (fDesc.getHeader().fCoverageOutput) {
83        case GrGLProgramDesc::kModulate_CoverageOutput:
84            break;
85        // The prog will write a coverage value to the secondary
86        // output and the dst is blended by one minus that value.
87        case GrGLProgramDesc::kSecondaryCoverage_CoverageOutput:
88        case GrGLProgramDesc::kSecondaryCoverageISA_CoverageOutput:
89        case GrGLProgramDesc::kSecondaryCoverageISC_CoverageOutput:
90            *dstCoeff = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
91            break;
92        case GrGLProgramDesc::kCombineWithDst_CoverageOutput:
93            // We should only have set this if the blend was specified as (1, 0)
94            SkASSERT(kOne_GrBlendCoeff == *srcCoeff && kZero_GrBlendCoeff == *dstCoeff);
95            break;
96        default:
97            GrCrash("Unexpected coverage output");
98            break;
99    }
100}
101
102namespace {
103// given two blend coefficients determine whether the src
104// and/or dst computation can be omitted.
105inline void need_blend_inputs(SkXfermode::Coeff srcCoeff,
106                              SkXfermode::Coeff dstCoeff,
107                              bool* needSrcValue,
108                              bool* needDstValue) {
109    if (SkXfermode::kZero_Coeff == srcCoeff) {
110        switch (dstCoeff) {
111            // these all read the src
112            case SkXfermode::kSC_Coeff:
113            case SkXfermode::kISC_Coeff:
114            case SkXfermode::kSA_Coeff:
115            case SkXfermode::kISA_Coeff:
116                *needSrcValue = true;
117                break;
118            default:
119                *needSrcValue = false;
120                break;
121        }
122    } else {
123        *needSrcValue = true;
124    }
125    if (SkXfermode::kZero_Coeff == dstCoeff) {
126        switch (srcCoeff) {
127            // these all read the dst
128            case SkXfermode::kDC_Coeff:
129            case SkXfermode::kIDC_Coeff:
130            case SkXfermode::kDA_Coeff:
131            case SkXfermode::kIDA_Coeff:
132                *needDstValue = true;
133                break;
134            default:
135                *needDstValue = false;
136                break;
137        }
138    } else {
139        *needDstValue = true;
140    }
141}
142
143/**
144 * Create a blend_coeff * value string to be used in shader code. Sets empty
145 * string if result is trivially zero.
146 */
147inline void blend_term_string(SkString* str, SkXfermode::Coeff coeff,
148                       const char* src, const char* dst,
149                       const char* value) {
150    switch (coeff) {
151    case SkXfermode::kZero_Coeff:    /** 0 */
152        *str = "";
153        break;
154    case SkXfermode::kOne_Coeff:     /** 1 */
155        *str = value;
156        break;
157    case SkXfermode::kSC_Coeff:
158        str->printf("(%s * %s)", src, value);
159        break;
160    case SkXfermode::kISC_Coeff:
161        str->printf("((vec4(1) - %s) * %s)", src, value);
162        break;
163    case SkXfermode::kDC_Coeff:
164        str->printf("(%s * %s)", dst, value);
165        break;
166    case SkXfermode::kIDC_Coeff:
167        str->printf("((vec4(1) - %s) * %s)", dst, value);
168        break;
169    case SkXfermode::kSA_Coeff:      /** src alpha */
170        str->printf("(%s.a * %s)", src, value);
171        break;
172    case SkXfermode::kISA_Coeff:     /** inverse src alpha (i.e. 1 - sa) */
173        str->printf("((1.0 - %s.a) * %s)", src, value);
174        break;
175    case SkXfermode::kDA_Coeff:      /** dst alpha */
176        str->printf("(%s.a * %s)", dst, value);
177        break;
178    case SkXfermode::kIDA_Coeff:     /** inverse dst alpha (i.e. 1 - da) */
179        str->printf("((1.0 - %s.a) * %s)", dst, value);
180        break;
181    default:
182        GrCrash("Unexpected xfer coeff.");
183        break;
184    }
185}
186/**
187 * Adds a line to the fragment shader code which modifies the color by
188 * the specified color filter.
189 */
190void add_color_filter(GrGLShaderBuilder* builder,
191                      const char * outputVar,
192                      SkXfermode::Coeff uniformCoeff,
193                      SkXfermode::Coeff colorCoeff,
194                      const char* filterColor,
195                      const char* inColor) {
196    SkString colorStr, constStr;
197    blend_term_string(&colorStr, colorCoeff, filterColor, inColor, inColor);
198    blend_term_string(&constStr, uniformCoeff, filterColor, inColor, filterColor);
199    GrGLSLExpr<4> sum;
200    if (colorStr.isEmpty() && constStr.isEmpty()) {
201        sum = GrGLSLExpr<4>(0);
202    } else if (colorStr.isEmpty()) {
203        sum = constStr;
204    } else if (constStr.isEmpty()) {
205        sum = colorStr;
206    } else {
207        sum = GrGLSLExpr<4>(colorStr) + GrGLSLExpr<4>(constStr);
208    }
209    builder->fsCodeAppendf("\t%s = %s;\n", outputVar, sum.c_str());
210}
211}
212
213bool GrGLProgram::genProgram(GrGLShaderBuilder* builder,
214                             const GrEffectStage* colorStages[],
215                             const GrEffectStage* coverageStages[]) {
216    SkASSERT(0 == fProgramID);
217
218    const GrGLProgramDesc::KeyHeader& header = fDesc.getHeader();
219
220    // incoming color to current stage being processed.
221    GrGLSLExpr<4> inColor = builder->getInputColor();
222
223    // Get the coeffs for the Mode-based color filter, determine if color is needed.
224    SkXfermode::Coeff colorCoeff;
225    SkXfermode::Coeff filterColorCoeff;
226    SkAssertResult(
227        SkXfermode::ModeAsCoeff(header.fColorFilterXfermode,
228                                &filterColorCoeff,
229                                &colorCoeff));
230    bool needColor, needFilterColor;
231    need_blend_inputs(filterColorCoeff, colorCoeff, &needFilterColor, &needColor);
232
233    fColorEffects.reset(
234        builder->createAndEmitEffects(colorStages,
235                                      fDesc.effectKeys(),
236                                      needColor ? fDesc.numColorEffects() : 0,
237                                      &inColor));
238
239    // Insert the color filter. This will soon be replaced by a color effect.
240    if (SkXfermode::kDst_Mode != header.fColorFilterXfermode) {
241        const char* colorFilterColorUniName = NULL;
242        fUniformHandles.fColorFilterUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
243                                                              kVec4f_GrSLType, "FilterColor",
244                                                              &colorFilterColorUniName);
245
246        builder->fsCodeAppend("\tvec4 filteredColor;\n");
247        add_color_filter(builder, "filteredColor", filterColorCoeff,
248                         colorCoeff, colorFilterColorUniName, inColor.c_str());
249        inColor = "filteredColor";
250    }
251
252    ///////////////////////////////////////////////////////////////////////////
253    // compute the partial coverage
254    GrGLSLExpr<4> inCoverage = builder->getInputCoverage();
255
256    fCoverageEffects.reset(
257        builder->createAndEmitEffects(coverageStages,
258                                      fDesc.getEffectKeys() + fDesc.numColorEffects(),
259                                      fDesc.numCoverageEffects(),
260                                      &inCoverage));
261
262    // discard if coverage is zero
263    if (header.fDiscardIfZeroCoverage && !inCoverage.isOnes()) {
264        if (inCoverage.isZeros()) {
265            // This is unfortunate.
266            builder->fsCodeAppend("\tdiscard;\n");
267        } else {
268            builder->fsCodeAppendf("\tif (all(lessThanEqual(%s, vec4(0.0)))) {\n\t\tdiscard;\n\t}\n",
269                                   inCoverage.c_str());
270        }
271    }
272
273    if (GrGLProgramDesc::CoverageOutputUsesSecondaryOutput(header.fCoverageOutput)) {
274        const char* secondaryOutputName = builder->enableSecondaryOutput();
275
276        // default coeff to ones for kCoverage_DualSrcOutput
277        GrGLSLExpr<4> coeff(1);
278        if (GrGLProgramDesc::kSecondaryCoverageISA_CoverageOutput == header.fCoverageOutput) {
279            // Get (1-A) into coeff
280            coeff = GrGLSLExprCast4(GrGLSLExpr<1>(1) - GrGLSLExprExtractAlpha(inColor));
281        } else if (GrGLProgramDesc::kSecondaryCoverageISC_CoverageOutput == header.fCoverageOutput) {
282            // Get (1-RGBA) into coeff
283            coeff = GrGLSLExpr<4>(1) - inColor;
284        }
285        // Get coeff * coverage into modulate and then write that to the dual source output.
286        builder->fsCodeAppendf("\t%s = %s;\n", secondaryOutputName, (coeff * inCoverage).c_str());
287    }
288
289    ///////////////////////////////////////////////////////////////////////////
290    // combine color and coverage as frag color
291
292    // Get "color * coverage" into fragColor
293    GrGLSLExpr<4> fragColor = inColor * inCoverage;
294    // Now tack on "+(1-coverage)dst onto the frag color if we were asked to do so.
295    if (GrGLProgramDesc::kCombineWithDst_CoverageOutput == header.fCoverageOutput) {
296        GrGLSLExpr<4> dstCoeff = GrGLSLExpr<4>(1) - inCoverage;
297
298        GrGLSLExpr<4> dstContribution = dstCoeff * GrGLSLExpr<4>(builder->dstColor());
299
300        fragColor = fragColor + dstContribution;
301    }
302    builder->fsCodeAppendf("\t%s = %s;\n", builder->getColorOutputName(), fragColor.c_str());
303
304    if (!builder->finish(&fProgramID)) {
305        return false;
306    }
307
308    fUniformHandles.fRTHeightUni = builder->getRTHeightUniform();
309    fUniformHandles.fDstCopyTopLeftUni = builder->getDstCopyTopLeftUniform();
310    fUniformHandles.fDstCopyScaleUni = builder->getDstCopyScaleUniform();
311    fUniformHandles.fColorUni = builder->getColorUniform();
312    fUniformHandles.fCoverageUni = builder->getCoverageUniform();
313    fUniformHandles.fDstCopySamplerUni = builder->getDstCopySamplerUniform();
314    // This must be called after we set fDstCopySamplerUni above.
315    this->initSamplerUniforms();
316
317    return true;
318}
319
320void GrGLProgram::initSamplerUniforms() {
321    GL_CALL(UseProgram(fProgramID));
322    GrGLint texUnitIdx = 0;
323    if (fUniformHandles.fDstCopySamplerUni.isValid()) {
324        fUniformManager.setSampler(fUniformHandles.fDstCopySamplerUni, texUnitIdx);
325        fDstCopyTexUnit = texUnitIdx++;
326    }
327    fColorEffects->initSamplers(fUniformManager, &texUnitIdx);
328    fCoverageEffects->initSamplers(fUniformManager, &texUnitIdx);
329}
330
331///////////////////////////////////////////////////////////////////////////////
332
333void GrGLProgram::setData(GrDrawState::BlendOptFlags blendOpts,
334                          const GrEffectStage* colorStages[],
335                          const GrEffectStage* coverageStages[],
336                          const GrDeviceCoordTexture* dstCopy,
337                          SharedGLState* sharedState) {
338    const GrDrawState& drawState = fGpu->getDrawState();
339
340    GrColor color;
341    GrColor coverage;
342    if (blendOpts & GrDrawState::kEmitTransBlack_BlendOptFlag) {
343        color = 0;
344        coverage = 0;
345    } else if (blendOpts & GrDrawState::kEmitCoverage_BlendOptFlag) {
346        color = 0xffffffff;
347        coverage = drawState.getCoverage();
348    } else {
349        color = drawState.getColor();
350        coverage = drawState.getCoverage();
351    }
352
353    this->setColor(drawState, color, sharedState);
354    this->setCoverage(drawState, coverage, sharedState);
355    this->setMatrixAndRenderTargetHeight(drawState);
356
357    // Setup the SkXfermode::Mode-based colorfilter uniform if necessary
358    if (fUniformHandles.fColorFilterUni.isValid() &&
359        fColorFilterColor != drawState.getColorFilterColor()) {
360        GrGLfloat c[4];
361        GrColorToRGBAFloat(drawState.getColorFilterColor(), c);
362        fUniformManager.set4fv(fUniformHandles.fColorFilterUni, 0, 1, c);
363        fColorFilterColor = drawState.getColorFilterColor();
364    }
365
366    if (NULL != dstCopy) {
367        if (fUniformHandles.fDstCopyTopLeftUni.isValid()) {
368            fUniformManager.set2f(fUniformHandles.fDstCopyTopLeftUni,
369                                  static_cast<GrGLfloat>(dstCopy->offset().fX),
370                                  static_cast<GrGLfloat>(dstCopy->offset().fY));
371            fUniformManager.set2f(fUniformHandles.fDstCopyScaleUni,
372                                  1.f / dstCopy->texture()->width(),
373                                  1.f / dstCopy->texture()->height());
374            GrGLTexture* texture = static_cast<GrGLTexture*>(dstCopy->texture());
375            static GrTextureParams kParams; // the default is clamp, nearest filtering.
376            fGpu->bindTexture(fDstCopyTexUnit, kParams, texture);
377        } else {
378            SkASSERT(!fUniformHandles.fDstCopyScaleUni.isValid());
379            SkASSERT(!fUniformHandles.fDstCopySamplerUni.isValid());
380        }
381    } else {
382        SkASSERT(!fUniformHandles.fDstCopyTopLeftUni.isValid());
383        SkASSERT(!fUniformHandles.fDstCopyScaleUni.isValid());
384        SkASSERT(!fUniformHandles.fDstCopySamplerUni.isValid());
385    }
386
387    fColorEffects->setData(fGpu, fUniformManager, colorStages);
388    fCoverageEffects->setData(fGpu, fUniformManager, coverageStages);
389
390    if (!fHasVertexShader) {
391        fGpu->disableUnusedTexGen(fNumTexCoordSets);
392    }
393}
394
395void GrGLProgram::setColor(const GrDrawState& drawState,
396                           GrColor color,
397                           SharedGLState* sharedState) {
398    const GrGLProgramDesc::KeyHeader& header = fDesc.getHeader();
399    if (!drawState.hasColorVertexAttribute()) {
400        switch (header.fColorInput) {
401            case GrGLProgramDesc::kAttribute_ColorInput:
402                SkASSERT(-1 != header.fColorAttributeIndex);
403                if (sharedState->fConstAttribColor != color ||
404                    sharedState->fConstAttribColorIndex != header.fColorAttributeIndex) {
405                    // OpenGL ES only supports the float varieties of glVertexAttrib
406                    GrGLfloat c[4];
407                    GrColorToRGBAFloat(color, c);
408                    GL_CALL(VertexAttrib4fv(header.fColorAttributeIndex, c));
409                    sharedState->fConstAttribColor = color;
410                    sharedState->fConstAttribColorIndex = header.fColorAttributeIndex;
411                }
412                break;
413            case GrGLProgramDesc::kUniform_ColorInput:
414                if (fColor != color) {
415                    // OpenGL ES doesn't support unsigned byte varieties of glUniform
416                    GrGLfloat c[4];
417                    GrColorToRGBAFloat(color, c);
418                    fUniformManager.set4fv(fUniformHandles.fColorUni, 0, 1, c);
419                    fColor = color;
420                }
421                sharedState->fConstAttribColorIndex = -1;
422                break;
423            case GrGLProgramDesc::kSolidWhite_ColorInput:
424            case GrGLProgramDesc::kTransBlack_ColorInput:
425                sharedState->fConstAttribColorIndex = -1;
426                break;
427            default:
428                GrCrash("Unknown color type.");
429        }
430    } else {
431        sharedState->fConstAttribColorIndex = -1;
432    }
433}
434
435void GrGLProgram::setCoverage(const GrDrawState& drawState,
436                              GrColor coverage,
437                              SharedGLState* sharedState) {
438    const GrGLProgramDesc::KeyHeader& header = fDesc.getHeader();
439    if (!drawState.hasCoverageVertexAttribute()) {
440        switch (header.fCoverageInput) {
441            case GrGLProgramDesc::kAttribute_ColorInput:
442                if (sharedState->fConstAttribCoverage != coverage ||
443                    sharedState->fConstAttribCoverageIndex != header.fCoverageAttributeIndex) {
444                    // OpenGL ES only supports the float varieties of  glVertexAttrib
445                    GrGLfloat c[4];
446                    GrColorToRGBAFloat(coverage, c);
447                    GL_CALL(VertexAttrib4fv(header.fCoverageAttributeIndex, c));
448                    sharedState->fConstAttribCoverage = coverage;
449                    sharedState->fConstAttribCoverageIndex = header.fCoverageAttributeIndex;
450                }
451                break;
452            case GrGLProgramDesc::kUniform_ColorInput:
453                if (fCoverage != coverage) {
454                    // OpenGL ES doesn't support unsigned byte varieties of glUniform
455                    GrGLfloat c[4];
456                    GrColorToRGBAFloat(coverage, c);
457                    fUniformManager.set4fv(fUniformHandles.fCoverageUni, 0, 1, c);
458                    fCoverage = coverage;
459                }
460                sharedState->fConstAttribCoverageIndex = -1;
461                break;
462            case GrGLProgramDesc::kSolidWhite_ColorInput:
463            case GrGLProgramDesc::kTransBlack_ColorInput:
464                sharedState->fConstAttribCoverageIndex = -1;
465                break;
466            default:
467                GrCrash("Unknown coverage type.");
468        }
469    } else {
470        sharedState->fConstAttribCoverageIndex = -1;
471    }
472}
473
474void GrGLProgram::setMatrixAndRenderTargetHeight(const GrDrawState& drawState) {
475    const GrRenderTarget* rt = drawState.getRenderTarget();
476    SkISize size;
477    size.set(rt->width(), rt->height());
478
479    // Load the RT height uniform if it is needed to y-flip gl_FragCoord.
480    if (fUniformHandles.fRTHeightUni.isValid() &&
481        fMatrixState.fRenderTargetSize.fHeight != size.fHeight) {
482        fUniformManager.set1f(fUniformHandles.fRTHeightUni, SkIntToScalar(size.fHeight));
483    }
484
485    if (!fHasVertexShader) {
486        SkASSERT(!fUniformHandles.fViewMatrixUni.isValid());
487        fGpu->setProjectionMatrix(drawState.getViewMatrix(), size, rt->origin());
488    } else if (fMatrixState.fRenderTargetOrigin != rt->origin() ||
489               fMatrixState.fRenderTargetSize != size ||
490               !fMatrixState.fViewMatrix.cheapEqualTo(drawState.getViewMatrix())) {
491        SkASSERT(fUniformHandles.fViewMatrixUni.isValid());
492
493        fMatrixState.fViewMatrix = drawState.getViewMatrix();
494        fMatrixState.fRenderTargetSize = size;
495        fMatrixState.fRenderTargetOrigin = rt->origin();
496
497        GrGLfloat viewMatrix[3 * 3];
498        fMatrixState.getGLMatrix<3>(viewMatrix);
499        fUniformManager.setMatrix3f(fUniformHandles.fViewMatrixUni, viewMatrix);
500    }
501}
502