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 "GrGLGpu.h"
14#include "GrGLBuffer.h"
15#include "GrGLPathRendering.h"
16#include "GrPathProcessor.h"
17#include "GrPipeline.h"
18#include "GrXferProcessor.h"
19#include "glsl/GrGLSLFragmentProcessor.h"
20#include "glsl/GrGLSLGeometryProcessor.h"
21#include "glsl/GrGLSLXferProcessor.h"
22
23#define GL_CALL(X) GR_GL_CALL(fGpu->glInterface(), X)
24#define GL_CALL_RET(R, X) GR_GL_CALL_RET(fGpu->glInterface(), R, X)
25
26///////////////////////////////////////////////////////////////////////////////////////////////////
27
28GrGLProgram::GrGLProgram(GrGLGpu* gpu,
29                         const GrProgramDesc& desc,
30                         const BuiltinUniformHandles& builtinUniforms,
31                         GrGLuint programID,
32                         const UniformInfoArray& uniforms,
33                         const UniformInfoArray& textureSamplers,
34                         const UniformInfoArray& texelBuffers,
35                         const UniformInfoArray& imageStorages,
36                         const VaryingInfoArray& pathProcVaryings,
37                         GrGLSLPrimitiveProcessor* geometryProcessor,
38                         GrGLSLXferProcessor* xferProcessor,
39                         const GrGLSLFragProcs& fragmentProcessors)
40    : fBuiltinUniformHandles(builtinUniforms)
41    , fProgramID(programID)
42    , fGeometryProcessor(geometryProcessor)
43    , fXferProcessor(xferProcessor)
44    , fFragmentProcessors(fragmentProcessors)
45    , fDesc(desc)
46    , fGpu(gpu)
47    , fProgramDataManager(gpu, programID, uniforms, pathProcVaryings)
48    , fNumTextureSamplers(textureSamplers.count())
49    , fNumTexelBuffers(texelBuffers.count()) {
50    // Assign texture units to sampler uniforms one time up front.
51    GL_CALL(UseProgram(fProgramID));
52    fProgramDataManager.setSamplerUniforms(textureSamplers, 0);
53    fProgramDataManager.setSamplerUniforms(texelBuffers, fNumTextureSamplers);
54    fProgramDataManager.setImageStorages(imageStorages);
55}
56
57GrGLProgram::~GrGLProgram() {
58    if (fProgramID) {
59        GL_CALL(DeleteProgram(fProgramID));
60    }
61    for (int i = 0; i < fFragmentProcessors.count(); ++i) {
62        delete fFragmentProcessors[i];
63    }
64}
65
66void GrGLProgram::abandon() {
67    fProgramID = 0;
68}
69
70///////////////////////////////////////////////////////////////////////////////
71
72void GrGLProgram::setData(const GrPrimitiveProcessor& primProc, const GrPipeline& pipeline) {
73    this->setRenderTargetState(primProc, pipeline.getRenderTarget());
74
75    // we set the textures, and uniforms for installed processors in a generic way, but subclasses
76    // of GLProgram determine how to set coord transforms
77
78    // We must bind to texture units in the same order in which we set the uniforms in
79    // GrGLProgramDataManager. That is first all texture samplers and then texel buffers.
80    // ImageStorages are bound to their own image units so they are tracked separately.
81    // Within each group we will bind them in primProc, fragProcs, XP order.
82    int nextTexSamplerIdx = 0;
83    int nextTexelBufferIdx = fNumTextureSamplers;
84    int nextImageStorageIdx = 0;
85    fGeometryProcessor->setData(fProgramDataManager, primProc,
86                                GrFragmentProcessor::CoordTransformIter(pipeline));
87    this->bindTextures(primProc, pipeline.getAllowSRGBInputs(), &nextTexSamplerIdx,
88                       &nextTexelBufferIdx, &nextImageStorageIdx);
89
90    this->setFragmentData(primProc, pipeline, &nextTexSamplerIdx, &nextTexelBufferIdx,
91                          &nextImageStorageIdx);
92
93    const GrXferProcessor& xp = pipeline.getXferProcessor();
94    SkIPoint offset;
95    GrTexture* dstTexture = pipeline.peekDstTexture(&offset);
96
97    fXferProcessor->setData(fProgramDataManager, xp, dstTexture, offset);
98    if (dstTexture) {
99        fGpu->bindTexture(nextTexSamplerIdx++, GrSamplerParams::ClampNoFilter(), true,
100                          static_cast<GrGLTexture*>(dstTexture));
101    }
102    SkASSERT(nextTexSamplerIdx == fNumTextureSamplers);
103    SkASSERT(nextTexelBufferIdx == fNumTextureSamplers + fNumTexelBuffers);
104}
105
106void GrGLProgram::generateMipmaps(const GrPrimitiveProcessor& primProc,
107                                  const GrPipeline& pipeline) {
108    this->generateMipmaps(primProc, pipeline.getAllowSRGBInputs());
109
110    GrFragmentProcessor::Iter iter(pipeline);
111    while (const GrFragmentProcessor* fp  = iter.next()) {
112        this->generateMipmaps(*fp, pipeline.getAllowSRGBInputs());
113    }
114}
115
116void GrGLProgram::setFragmentData(const GrPrimitiveProcessor& primProc,
117                                  const GrPipeline& pipeline,
118                                  int* nextTexSamplerIdx,
119                                  int* nextTexelBufferIdx,
120                                  int* nextImageStorageIdx) {
121    GrFragmentProcessor::Iter iter(pipeline);
122    GrGLSLFragmentProcessor::Iter glslIter(fFragmentProcessors.begin(),
123                                           fFragmentProcessors.count());
124    const GrFragmentProcessor* fp = iter.next();
125    GrGLSLFragmentProcessor* glslFP = glslIter.next();
126    while (fp && glslFP) {
127        glslFP->setData(fProgramDataManager, *fp);
128        this->bindTextures(*fp, pipeline.getAllowSRGBInputs(), nextTexSamplerIdx,
129                           nextTexelBufferIdx, nextImageStorageIdx);
130        fp = iter.next();
131        glslFP = glslIter.next();
132    }
133    SkASSERT(!fp && !glslFP);
134}
135
136
137void GrGLProgram::setRenderTargetState(const GrPrimitiveProcessor& primProc,
138                                       const GrRenderTarget* rt) {
139    // Load the RT height uniform if it is needed to y-flip gl_FragCoord.
140    if (fBuiltinUniformHandles.fRTHeightUni.isValid() &&
141        fRenderTargetState.fRenderTargetSize.fHeight != rt->height()) {
142        fProgramDataManager.set1f(fBuiltinUniformHandles.fRTHeightUni, SkIntToScalar(rt->height()));
143    }
144
145    // set RT adjustment
146    SkISize size;
147    size.set(rt->width(), rt->height());
148    if (!primProc.isPathRendering()) {
149        if (fRenderTargetState.fRenderTargetOrigin != rt->origin() ||
150            fRenderTargetState.fRenderTargetSize != size) {
151            fRenderTargetState.fRenderTargetSize = size;
152            fRenderTargetState.fRenderTargetOrigin = rt->origin();
153
154            float rtAdjustmentVec[4];
155            fRenderTargetState.getRTAdjustmentVec(rtAdjustmentVec);
156            fProgramDataManager.set4fv(fBuiltinUniformHandles.fRTAdjustmentUni, 1, rtAdjustmentVec);
157        }
158    } else {
159        SkASSERT(fGpu->glCaps().shaderCaps()->pathRenderingSupport());
160        const GrPathProcessor& pathProc = primProc.cast<GrPathProcessor>();
161        fGpu->glPathRendering()->setProjectionMatrix(pathProc.viewMatrix(),
162                                                     size, rt->origin());
163    }
164}
165
166void GrGLProgram::bindTextures(const GrResourceIOProcessor& processor,
167                               bool allowSRGBInputs,
168                               int* nextTexSamplerIdx,
169                               int* nextTexelBufferIdx,
170                               int* nextImageStorageIdx) {
171    for (int i = 0; i < processor.numTextureSamplers(); ++i) {
172        const GrResourceIOProcessor::TextureSampler& sampler = processor.textureSampler(i);
173        fGpu->bindTexture((*nextTexSamplerIdx)++, sampler.params(),
174                          allowSRGBInputs, static_cast<GrGLTexture*>(sampler.peekTexture()));
175    }
176    for (int i = 0; i < processor.numBuffers(); ++i) {
177        const GrResourceIOProcessor::BufferAccess& access = processor.bufferAccess(i);
178        fGpu->bindTexelBuffer((*nextTexelBufferIdx)++, access.texelConfig(),
179                              static_cast<GrGLBuffer*>(access.buffer()));
180    }
181    for (int i = 0; i < processor.numImageStorages(); ++i) {
182        const GrResourceIOProcessor::ImageStorageAccess& access = processor.imageStorageAccess(i);
183        fGpu->bindImageStorage((*nextImageStorageIdx)++, access.ioType(),
184                               static_cast<GrGLTexture *>(access.peekTexture()));
185    }
186}
187
188void GrGLProgram::generateMipmaps(const GrResourceIOProcessor& processor, bool allowSRGBInputs) {
189    for (int i = 0; i < processor.numTextureSamplers(); ++i) {
190        const GrResourceIOProcessor::TextureSampler& sampler = processor.textureSampler(i);
191        fGpu->generateMipmaps(sampler.params(), allowSRGBInputs,
192                              static_cast<GrGLTexture*>(sampler.peekTexture()));
193    }
194}
195