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
23GrGLProgram* GrGLProgram::Create(GrGpuGL* gpu,
24                                 const GrGLProgramDesc& desc,
25                                 const GrEffectStage* colorStages[],
26                                 const GrEffectStage* coverageStages[]) {
27    GrGLShaderBuilder::GenProgramOutput output;
28    SkAutoTUnref<GrGLUniformManager> uman(SkNEW_ARGS(GrGLUniformManager, (gpu)));
29    if (GrGLShaderBuilder::GenProgram(gpu, uman, desc, colorStages, coverageStages,
30                                      &output)) {
31        SkASSERT(0 != output.fProgramID);
32        return SkNEW_ARGS(GrGLProgram, (gpu, desc, uman, output));
33    }
34    return NULL;
35}
36
37GrGLProgram::GrGLProgram(GrGpuGL* gpu,
38                         const GrGLProgramDesc& desc,
39                         GrGLUniformManager* uman,
40                         const GrGLShaderBuilder::GenProgramOutput& builderOutput)
41    : fColor(GrColor_ILLEGAL)
42    , fCoverage(GrColor_ILLEGAL)
43    , fDstCopyTexUnit(-1)
44    , fBuilderOutput(builderOutput)
45    , fDesc(desc)
46    , fGpu(gpu)
47    , fUniformManager(SkRef(uman)) {
48    this->initSamplerUniforms();
49}
50
51GrGLProgram::~GrGLProgram() {
52    if (fBuilderOutput.fProgramID) {
53        GL_CALL(DeleteProgram(fBuilderOutput.fProgramID));
54    }
55}
56
57void GrGLProgram::abandon() {
58    fBuilderOutput.fProgramID = 0;
59}
60
61void GrGLProgram::overrideBlend(GrBlendCoeff* srcCoeff,
62                                GrBlendCoeff* dstCoeff) const {
63    switch (fDesc.getHeader().fCoverageOutput) {
64        case GrGLProgramDesc::kModulate_CoverageOutput:
65            break;
66        // The prog will write a coverage value to the secondary
67        // output and the dst is blended by one minus that value.
68        case GrGLProgramDesc::kSecondaryCoverage_CoverageOutput:
69        case GrGLProgramDesc::kSecondaryCoverageISA_CoverageOutput:
70        case GrGLProgramDesc::kSecondaryCoverageISC_CoverageOutput:
71            *dstCoeff = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
72            break;
73        case GrGLProgramDesc::kCombineWithDst_CoverageOutput:
74            // We should only have set this if the blend was specified as (1, 0)
75            SkASSERT(kOne_GrBlendCoeff == *srcCoeff && kZero_GrBlendCoeff == *dstCoeff);
76            break;
77        default:
78            SkFAIL("Unexpected coverage output");
79            break;
80    }
81}
82
83void GrGLProgram::initSamplerUniforms() {
84    GL_CALL(UseProgram(fBuilderOutput.fProgramID));
85    GrGLint texUnitIdx = 0;
86    if (fBuilderOutput.fUniformHandles.fDstCopySamplerUni.isValid()) {
87        fUniformManager->setSampler(fBuilderOutput.fUniformHandles.fDstCopySamplerUni, texUnitIdx);
88        fDstCopyTexUnit = texUnitIdx++;
89    }
90    fBuilderOutput.fColorEffects->initSamplers(*fUniformManager, &texUnitIdx);
91    fBuilderOutput.fCoverageEffects->initSamplers(*fUniformManager, &texUnitIdx);
92}
93
94///////////////////////////////////////////////////////////////////////////////
95
96void GrGLProgram::setData(GrDrawState::BlendOptFlags blendOpts,
97                          const GrEffectStage* colorStages[],
98                          const GrEffectStage* coverageStages[],
99                          const GrDeviceCoordTexture* dstCopy,
100                          SharedGLState* sharedState) {
101    const GrDrawState& drawState = fGpu->getDrawState();
102
103    GrColor color;
104    GrColor coverage;
105    if (blendOpts & GrDrawState::kEmitTransBlack_BlendOptFlag) {
106        color = 0;
107        coverage = 0;
108    } else if (blendOpts & GrDrawState::kEmitCoverage_BlendOptFlag) {
109        color = 0xffffffff;
110        coverage = drawState.getCoverageColor();
111    } else {
112        color = drawState.getColor();
113        coverage = drawState.getCoverageColor();
114    }
115
116    this->setColor(drawState, color, sharedState);
117    this->setCoverage(drawState, coverage, sharedState);
118    this->setMatrixAndRenderTargetHeight(drawState);
119
120    if (NULL != dstCopy) {
121        if (fBuilderOutput.fUniformHandles.fDstCopyTopLeftUni.isValid()) {
122            fUniformManager->set2f(fBuilderOutput.fUniformHandles.fDstCopyTopLeftUni,
123                                   static_cast<GrGLfloat>(dstCopy->offset().fX),
124                                   static_cast<GrGLfloat>(dstCopy->offset().fY));
125            fUniformManager->set2f(fBuilderOutput.fUniformHandles.fDstCopyScaleUni,
126                                   1.f / dstCopy->texture()->width(),
127                                   1.f / dstCopy->texture()->height());
128            GrGLTexture* texture = static_cast<GrGLTexture*>(dstCopy->texture());
129            static GrTextureParams kParams; // the default is clamp, nearest filtering.
130            fGpu->bindTexture(fDstCopyTexUnit, kParams, texture);
131        } else {
132            SkASSERT(!fBuilderOutput.fUniformHandles.fDstCopyScaleUni.isValid());
133            SkASSERT(!fBuilderOutput.fUniformHandles.fDstCopySamplerUni.isValid());
134        }
135    } else {
136        SkASSERT(!fBuilderOutput.fUniformHandles.fDstCopyTopLeftUni.isValid());
137        SkASSERT(!fBuilderOutput.fUniformHandles.fDstCopyScaleUni.isValid());
138        SkASSERT(!fBuilderOutput.fUniformHandles.fDstCopySamplerUni.isValid());
139    }
140
141    fBuilderOutput.fColorEffects->setData(fGpu, *fUniformManager, colorStages);
142    fBuilderOutput.fCoverageEffects->setData(fGpu, *fUniformManager, coverageStages);
143
144
145    // PathTexGen state applies to the the fixed function vertex shader. For
146    // custom shaders, it's ignored, so we don't need to change the texgen
147    // settings in that case.
148    if (!fBuilderOutput.fHasVertexShader) {
149        fGpu->flushPathTexGenSettings(fBuilderOutput.fTexCoordSetCnt);
150    }
151}
152
153void GrGLProgram::setColor(const GrDrawState& drawState,
154                           GrColor color,
155                           SharedGLState* sharedState) {
156    const GrGLProgramDesc::KeyHeader& header = fDesc.getHeader();
157    if (!drawState.hasColorVertexAttribute()) {
158        switch (header.fColorInput) {
159            case GrGLProgramDesc::kAttribute_ColorInput:
160                SkASSERT(-1 != header.fColorAttributeIndex);
161                if (sharedState->fConstAttribColor != color ||
162                    sharedState->fConstAttribColorIndex != header.fColorAttributeIndex) {
163                    // OpenGL ES only supports the float varieties of glVertexAttrib
164                    GrGLfloat c[4];
165                    GrColorToRGBAFloat(color, c);
166                    GL_CALL(VertexAttrib4fv(header.fColorAttributeIndex, c));
167                    sharedState->fConstAttribColor = color;
168                    sharedState->fConstAttribColorIndex = header.fColorAttributeIndex;
169                }
170                break;
171            case GrGLProgramDesc::kUniform_ColorInput:
172                if (fColor != color && fBuilderOutput.fUniformHandles.fColorUni.isValid()) {
173                    // OpenGL ES doesn't support unsigned byte varieties of glUniform
174                    GrGLfloat c[4];
175                    GrColorToRGBAFloat(color, c);
176                    fUniformManager->set4fv(fBuilderOutput.fUniformHandles.fColorUni, 1, c);
177                    fColor = color;
178                }
179                sharedState->fConstAttribColorIndex = -1;
180                break;
181            case GrGLProgramDesc::kSolidWhite_ColorInput:
182            case GrGLProgramDesc::kTransBlack_ColorInput:
183                sharedState->fConstAttribColorIndex = -1;
184                break;
185            default:
186                SkFAIL("Unknown color type.");
187        }
188    } else {
189        sharedState->fConstAttribColorIndex = -1;
190    }
191}
192
193void GrGLProgram::setCoverage(const GrDrawState& drawState,
194                              GrColor coverage,
195                              SharedGLState* sharedState) {
196    const GrGLProgramDesc::KeyHeader& header = fDesc.getHeader();
197    if (!drawState.hasCoverageVertexAttribute()) {
198        switch (header.fCoverageInput) {
199            case GrGLProgramDesc::kAttribute_ColorInput:
200                if (sharedState->fConstAttribCoverage != coverage ||
201                    sharedState->fConstAttribCoverageIndex != header.fCoverageAttributeIndex) {
202                    // OpenGL ES only supports the float varieties of  glVertexAttrib
203                    GrGLfloat c[4];
204                    GrColorToRGBAFloat(coverage, c);
205                    GL_CALL(VertexAttrib4fv(header.fCoverageAttributeIndex, c));
206                    sharedState->fConstAttribCoverage = coverage;
207                    sharedState->fConstAttribCoverageIndex = header.fCoverageAttributeIndex;
208                }
209                break;
210            case GrGLProgramDesc::kUniform_ColorInput:
211                if (fCoverage != coverage) {
212                    // OpenGL ES doesn't support unsigned byte varieties of glUniform
213                    GrGLfloat c[4];
214                    GrColorToRGBAFloat(coverage, c);
215                    fUniformManager->set4fv(fBuilderOutput.fUniformHandles.fCoverageUni, 1, c);
216                    fCoverage = coverage;
217                }
218                sharedState->fConstAttribCoverageIndex = -1;
219                break;
220            case GrGLProgramDesc::kSolidWhite_ColorInput:
221            case GrGLProgramDesc::kTransBlack_ColorInput:
222                sharedState->fConstAttribCoverageIndex = -1;
223                break;
224            default:
225                SkFAIL("Unknown coverage type.");
226        }
227    } else {
228        sharedState->fConstAttribCoverageIndex = -1;
229    }
230}
231
232void GrGLProgram::setMatrixAndRenderTargetHeight(const GrDrawState& drawState) {
233    const GrRenderTarget* rt = drawState.getRenderTarget();
234    SkISize size;
235    size.set(rt->width(), rt->height());
236
237    // Load the RT height uniform if it is needed to y-flip gl_FragCoord.
238    if (fBuilderOutput.fUniformHandles.fRTHeightUni.isValid() &&
239        fMatrixState.fRenderTargetSize.fHeight != size.fHeight) {
240        fUniformManager->set1f(fBuilderOutput.fUniformHandles.fRTHeightUni,
241                               SkIntToScalar(size.fHeight));
242    }
243
244    if (!fBuilderOutput.fHasVertexShader) {
245        SkASSERT(!fBuilderOutput.fUniformHandles.fViewMatrixUni.isValid());
246        SkASSERT(!fBuilderOutput.fUniformHandles.fRTAdjustmentUni.isValid());
247        fGpu->setProjectionMatrix(drawState.getViewMatrix(), size, rt->origin());
248    } else if (fMatrixState.fRenderTargetOrigin != rt->origin() ||
249               fMatrixState.fRenderTargetSize != size ||
250               !fMatrixState.fViewMatrix.cheapEqualTo(drawState.getViewMatrix())) {
251        SkASSERT(fBuilderOutput.fUniformHandles.fViewMatrixUni.isValid());
252
253        fMatrixState.fViewMatrix = drawState.getViewMatrix();
254        fMatrixState.fRenderTargetSize = size;
255        fMatrixState.fRenderTargetOrigin = rt->origin();
256
257        GrGLfloat viewMatrix[3 * 3];
258        fMatrixState.getGLMatrix<3>(viewMatrix);
259        fUniformManager->setMatrix3f(fBuilderOutput.fUniformHandles.fViewMatrixUni, viewMatrix);
260
261        GrGLfloat rtAdjustmentVec[4];
262        fMatrixState.getRTAdjustmentVec(rtAdjustmentVec);
263        fUniformManager->set4fv(fBuilderOutput.fUniformHandles.fRTAdjustmentUni, 1, rtAdjustmentVec);
264    }
265}
266