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 "GrProcessor.h"
12#include "GrCoordTransform.h"
13#include "GrGLGeometryProcessor.h"
14#include "GrGLGpu.h"
15#include "GrGLPathProcessor.h"
16#include "GrGLPathRendering.h"
17#include "GrGLShaderVar.h"
18#include "GrGLSL.h"
19#include "GrGLXferProcessor.h"
20#include "GrPipeline.h"
21#include "GrXferProcessor.h"
22#include "SkXfermode.h"
23
24#define GL_CALL(X) GR_GL_CALL(fGpu->glInterface(), X)
25#define GL_CALL_RET(R, X) GR_GL_CALL_RET(fGpu->glInterface(), R, X)
26
27///////////////////////////////////////////////////////////////////////////////////////////////////
28
29GrGLProgram::GrGLProgram(GrGLGpu* gpu,
30                         const GrProgramDesc& desc,
31                         const BuiltinUniformHandles& builtinUniforms,
32                         GrGLuint programID,
33                         const UniformInfoArray& uniforms,
34                         GrGLInstalledGeoProc* geometryProcessor,
35                         GrGLInstalledXferProc* xferProcessor,
36                         GrGLInstalledFragProcs* fragmentProcessors)
37    : fColor(GrColor_ILLEGAL)
38    , fCoverage(0)
39    , fDstCopyTexUnit(-1)
40    , fBuiltinUniformHandles(builtinUniforms)
41    , fProgramID(programID)
42    , fGeometryProcessor(geometryProcessor)
43    , fXferProcessor(xferProcessor)
44    , fFragmentProcessors(SkRef(fragmentProcessors))
45    , fDesc(desc)
46    , fGpu(gpu)
47    , fProgramDataManager(gpu, uniforms) {
48    this->initSamplerUniforms();
49}
50
51GrGLProgram::~GrGLProgram() {
52    if (fProgramID) {
53        GL_CALL(DeleteProgram(fProgramID));
54    }
55}
56
57void GrGLProgram::abandon() {
58    fProgramID = 0;
59}
60
61void GrGLProgram::initSamplerUniforms() {
62    GL_CALL(UseProgram(fProgramID));
63    GrGLint texUnitIdx = 0;
64    this->initSamplers(fGeometryProcessor.get(), &texUnitIdx);
65    if (fXferProcessor.get()) {
66        this->initSamplers(fXferProcessor.get(), &texUnitIdx);
67    }
68    int numProcs = fFragmentProcessors->fProcs.count();
69    for (int i = 0; i < numProcs; i++) {
70        this->initSamplers(fFragmentProcessors->fProcs[i], &texUnitIdx);
71    }
72}
73
74template <class Proc>
75void GrGLProgram::initSamplers(Proc* ip, int* texUnitIdx) {
76    SkTArray<typename Proc::Sampler, true>& samplers = ip->fSamplers;
77    int numSamplers = samplers.count();
78    for (int s = 0; s < numSamplers; ++s) {
79        SkASSERT(samplers[s].fUniform.isValid());
80        fProgramDataManager.setSampler(samplers[s].fUniform, *texUnitIdx);
81        samplers[s].fTextureUnit = (*texUnitIdx)++;
82    }
83}
84
85template <class Proc>
86void GrGLProgram::bindTextures(const Proc* ip, const GrProcessor& processor) {
87    const SkTArray<typename Proc::Sampler, true>& samplers = ip->fSamplers;
88    int numSamplers = samplers.count();
89    SkASSERT(numSamplers == processor.numTextures());
90    for (int s = 0; s < numSamplers; ++s) {
91        SkASSERT(samplers[s].fTextureUnit >= 0);
92        const GrTextureAccess& textureAccess = processor.textureAccess(s);
93        fGpu->bindTexture(samplers[s].fTextureUnit,
94                          textureAccess.getParams(),
95                          static_cast<GrGLTexture*>(textureAccess.getTexture()));
96    }
97}
98
99
100///////////////////////////////////////////////////////////////////////////////
101
102void GrGLProgram::setData(const GrPrimitiveProcessor& primProc, const GrPipeline& pipeline,
103                          const GrBatchTracker& batchTracker) {
104    this->setRenderTargetState(primProc, pipeline);
105
106    // we set the textures, and uniforms for installed processors in a generic way, but subclasses
107    // of GLProgram determine how to set coord transforms
108    fGeometryProcessor->fGLProc->setData(fProgramDataManager, primProc, batchTracker);
109    this->bindTextures(fGeometryProcessor.get(), primProc);
110
111    const GrXferProcessor& xp = *pipeline.getXferProcessor();
112    fXferProcessor->fGLProc->setData(fProgramDataManager, xp);
113    this->bindTextures(fXferProcessor.get(), xp);
114
115    this->setFragmentData(primProc, pipeline);
116
117    // Some of GrGLProgram subclasses need to update state here
118    this->didSetData();
119}
120
121void GrGLProgram::setFragmentData(const GrPrimitiveProcessor& primProc,
122                                  const GrPipeline& pipeline) {
123    int numProcessors = fFragmentProcessors->fProcs.count();
124    for (int e = 0; e < numProcessors; ++e) {
125        const GrPendingFragmentStage& stage = pipeline.getFragmentStage(e);
126        const GrProcessor& processor = *stage.processor();
127        fFragmentProcessors->fProcs[e]->fGLProc->setData(fProgramDataManager, processor);
128        this->setTransformData(primProc,
129                               stage,
130                               e,
131                               fFragmentProcessors->fProcs[e]);
132        this->bindTextures(fFragmentProcessors->fProcs[e], processor);
133    }
134}
135void GrGLProgram::setTransformData(const GrPrimitiveProcessor& primProc,
136                                   const GrPendingFragmentStage& processor,
137                                   int index,
138                                   GrGLInstalledFragProc* ip) {
139    GrGLGeometryProcessor* gp =
140            static_cast<GrGLGeometryProcessor*>(fGeometryProcessor.get()->fGLProc.get());
141    gp->setTransformData(primProc, fProgramDataManager, index,
142                         processor.processor()->coordTransforms());
143}
144
145void GrGLProgram::setRenderTargetState(const GrPrimitiveProcessor& primProc,
146                                       const GrPipeline& pipeline) {
147    // Load the RT height uniform if it is needed to y-flip gl_FragCoord.
148    if (fBuiltinUniformHandles.fRTHeightUni.isValid() &&
149        fRenderTargetState.fRenderTargetSize.fHeight != pipeline.getRenderTarget()->height()) {
150        fProgramDataManager.set1f(fBuiltinUniformHandles.fRTHeightUni,
151                                   SkIntToScalar(pipeline.getRenderTarget()->height()));
152    }
153
154    // call subclasses to set the actual view matrix
155    this->onSetRenderTargetState(primProc, pipeline);
156}
157
158void GrGLProgram::onSetRenderTargetState(const GrPrimitiveProcessor&,
159                                         const GrPipeline& pipeline) {
160    const GrRenderTarget* rt = pipeline.getRenderTarget();
161    SkISize size;
162    size.set(rt->width(), rt->height());
163    if (fRenderTargetState.fRenderTargetOrigin != rt->origin() ||
164        fRenderTargetState.fRenderTargetSize != size) {
165        fRenderTargetState.fRenderTargetSize = size;
166        fRenderTargetState.fRenderTargetOrigin = rt->origin();
167
168        GrGLfloat rtAdjustmentVec[4];
169        fRenderTargetState.getRTAdjustmentVec(rtAdjustmentVec);
170        fProgramDataManager.set4fv(fBuiltinUniformHandles.fRTAdjustmentUni, 1, rtAdjustmentVec);
171    }
172}
173
174/////////////////////////////////////////////////////////////////////////////////////////
175
176GrGLNvprProgram::GrGLNvprProgram(GrGLGpu* gpu,
177                                 const GrProgramDesc& desc,
178                                 const BuiltinUniformHandles& builtinUniforms,
179                                 GrGLuint programID,
180                                 const UniformInfoArray& uniforms,
181                                 GrGLInstalledGeoProc* primProc,
182                                 GrGLInstalledXferProc* xferProcessor,
183                                 GrGLInstalledFragProcs* fragmentProcessors)
184    : INHERITED(gpu, desc, builtinUniforms, programID, uniforms, primProc,
185                xferProcessor, fragmentProcessors) {
186}
187void GrGLNvprProgram::didSetData() {
188    GrGLPathProcessor* pathProc =
189            static_cast<GrGLPathProcessor*>(fGeometryProcessor.get()->fGLProc.get());
190    pathProc->didSetData(fGpu->glPathRendering());
191}
192
193void GrGLNvprProgram::setTransformData(const GrPrimitiveProcessor& primProc,
194                                       const GrPendingFragmentStage& proc,
195                                       int index,
196                                       GrGLInstalledFragProc* ip) {
197    GrGLPathProcessor* pathProc =
198            static_cast<GrGLPathProcessor*>(fGeometryProcessor.get()->fGLProc.get());
199    pathProc->setTransformData(primProc, index, proc.processor()->coordTransforms(),
200                               fGpu->glPathRendering(), fProgramID);
201}
202
203void GrGLNvprProgram::onSetRenderTargetState(const GrPrimitiveProcessor& primProc,
204                                             const GrPipeline& pipeline) {
205    SkASSERT(!primProc.willUseGeoShader() && primProc.numAttribs() == 0);
206    const GrRenderTarget* rt = pipeline.getRenderTarget();
207    SkISize size;
208    size.set(rt->width(), rt->height());
209    const GrPathProcessor& pathProc = primProc.cast<GrPathProcessor>();
210    fGpu->glPathRendering()->setProjectionMatrix(pathProc.viewMatrix(),
211                                                 size, rt->origin());
212}
213