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 
GrGLProgram(GrGLGpu * gpu,const GrProgramDesc & desc,const BuiltinUniformHandles & builtinUniforms,GrGLuint programID,const UniformInfoArray & uniforms,const UniformInfoArray & samplers,const UniformInfoArray & imageStorages,const VaryingInfoArray & pathProcVaryings,GrGLSLPrimitiveProcessor * geometryProcessor,GrGLSLXferProcessor * xferProcessor,const GrGLSLFragProcs & fragmentProcessors)28 GrGLProgram::GrGLProgram(GrGLGpu* gpu,
29                          const GrProgramDesc& desc,
30                          const BuiltinUniformHandles& builtinUniforms,
31                          GrGLuint programID,
32                          const UniformInfoArray& uniforms,
33                          const UniformInfoArray& samplers,
34                          const UniformInfoArray& imageStorages,
35                          const VaryingInfoArray& pathProcVaryings,
36                          GrGLSLPrimitiveProcessor* geometryProcessor,
37                          GrGLSLXferProcessor* xferProcessor,
38                          const GrGLSLFragProcs& fragmentProcessors)
39     : fBuiltinUniformHandles(builtinUniforms)
40     , fProgramID(programID)
41     , fGeometryProcessor(geometryProcessor)
42     , fXferProcessor(xferProcessor)
43     , fFragmentProcessors(fragmentProcessors)
44     , fDesc(desc)
45     , fGpu(gpu)
46     , fProgramDataManager(gpu, programID, uniforms, pathProcVaryings) {
47     // Assign texture units to sampler uniforms one time up front.
48     GL_CALL(UseProgram(fProgramID));
49     fProgramDataManager.setSamplers(samplers);
50     fProgramDataManager.setImageStorages(imageStorages);
51 }
52 
~GrGLProgram()53 GrGLProgram::~GrGLProgram() {
54     if (fProgramID) {
55         GL_CALL(DeleteProgram(fProgramID));
56     }
57     for (int i = 0; i < fFragmentProcessors.count(); ++i) {
58         delete fFragmentProcessors[i];
59     }
60 }
61 
abandon()62 void GrGLProgram::abandon() {
63     fProgramID = 0;
64 }
65 
66 ///////////////////////////////////////////////////////////////////////////////
67 
setData(const GrPrimitiveProcessor & primProc,const GrPipeline & pipeline)68 void GrGLProgram::setData(const GrPrimitiveProcessor& primProc, const GrPipeline& pipeline) {
69     this->setRenderTargetState(primProc, pipeline);
70 
71     // we set the textures, and uniforms for installed processors in a generic way, but subclasses
72     // of GLProgram determine how to set coord transforms
73     int nextSamplerIdx = 0;
74     fGeometryProcessor->setData(fProgramDataManager, primProc,
75                                 GrFragmentProcessor::CoordTransformIter(pipeline));
76     this->bindTextures(primProc, pipeline.getAllowSRGBInputs(), &nextSamplerIdx);
77 
78     this->setFragmentData(primProc, pipeline, &nextSamplerIdx);
79 
80     const GrXferProcessor& xp = pipeline.getXferProcessor();
81     fXferProcessor->setData(fProgramDataManager, xp);
82     this->bindTextures(xp, pipeline.getAllowSRGBInputs(), &nextSamplerIdx);
83 }
84 
generateMipmaps(const GrPrimitiveProcessor & primProc,const GrPipeline & pipeline)85 void GrGLProgram::generateMipmaps(const GrPrimitiveProcessor& primProc,
86                                   const GrPipeline& pipeline) {
87     this->generateMipmaps(primProc, pipeline.getAllowSRGBInputs());
88 
89     GrFragmentProcessor::Iter iter(pipeline);
90     while (const GrFragmentProcessor* fp  = iter.next()) {
91         this->generateMipmaps(*fp, pipeline.getAllowSRGBInputs());
92     }
93 }
94 
setFragmentData(const GrPrimitiveProcessor & primProc,const GrPipeline & pipeline,int * nextSamplerIdx)95 void GrGLProgram::setFragmentData(const GrPrimitiveProcessor& primProc,
96                                   const GrPipeline& pipeline,
97                                   int* nextSamplerIdx) {
98     GrFragmentProcessor::Iter iter(pipeline);
99     GrGLSLFragmentProcessor::Iter glslIter(fFragmentProcessors.begin(),
100                                            fFragmentProcessors.count());
101     const GrFragmentProcessor* fp = iter.next();
102     GrGLSLFragmentProcessor* glslFP = glslIter.next();
103     while (fp && glslFP) {
104         glslFP->setData(fProgramDataManager, *fp);
105         this->bindTextures(*fp, pipeline.getAllowSRGBInputs(), nextSamplerIdx);
106         fp = iter.next();
107         glslFP = glslIter.next();
108     }
109     SkASSERT(!fp && !glslFP);
110 }
111 
112 
setRenderTargetState(const GrPrimitiveProcessor & primProc,const GrPipeline & pipeline)113 void GrGLProgram::setRenderTargetState(const GrPrimitiveProcessor& primProc,
114                                        const GrPipeline& pipeline) {
115     // Load the RT height uniform if it is needed to y-flip gl_FragCoord.
116     if (fBuiltinUniformHandles.fRTHeightUni.isValid() &&
117         fRenderTargetState.fRenderTargetSize.fHeight != pipeline.getRenderTarget()->height()) {
118         fProgramDataManager.set1f(fBuiltinUniformHandles.fRTHeightUni,
119                                    SkIntToScalar(pipeline.getRenderTarget()->height()));
120     }
121 
122     // set RT adjustment
123     const GrRenderTarget* rt = pipeline.getRenderTarget();
124     SkISize size;
125     size.set(rt->width(), rt->height());
126     if (!primProc.isPathRendering()) {
127         if (fRenderTargetState.fRenderTargetOrigin != rt->origin() ||
128             fRenderTargetState.fRenderTargetSize != size) {
129             fRenderTargetState.fRenderTargetSize = size;
130             fRenderTargetState.fRenderTargetOrigin = rt->origin();
131 
132             float rtAdjustmentVec[4];
133             fRenderTargetState.getRTAdjustmentVec(rtAdjustmentVec);
134             fProgramDataManager.set4fv(fBuiltinUniformHandles.fRTAdjustmentUni, 1, rtAdjustmentVec);
135         }
136     } else {
137         SkASSERT(fGpu->glCaps().shaderCaps()->pathRenderingSupport());
138         const GrPathProcessor& pathProc = primProc.cast<GrPathProcessor>();
139         fGpu->glPathRendering()->setProjectionMatrix(pathProc.viewMatrix(),
140                                                      size, rt->origin());
141     }
142 }
143 
bindTextures(const GrProcessor & processor,bool allowSRGBInputs,int * nextSamplerIdx)144 void GrGLProgram::bindTextures(const GrProcessor& processor,
145                                bool allowSRGBInputs,
146                                int* nextSamplerIdx) {
147     for (int i = 0; i < processor.numTextureSamplers(); ++i) {
148         const GrProcessor::TextureSampler& sampler = processor.textureSampler(i);
149         fGpu->bindTexture((*nextSamplerIdx)++, sampler.params(),
150                           allowSRGBInputs, static_cast<GrGLTexture*>(sampler.texture()));
151     }
152     for (int i = 0; i < processor.numBuffers(); ++i) {
153         const GrProcessor::BufferAccess& access = processor.bufferAccess(i);
154         fGpu->bindTexelBuffer((*nextSamplerIdx)++, access.texelConfig(),
155                               static_cast<GrGLBuffer*>(access.buffer()));
156     }
157     for (int i = 0; i < processor.numImageStorages(); ++i) {
158         const GrProcessor::ImageStorageAccess& access = processor.imageStorageAccess(i);
159         fGpu->bindImageStorage((*nextSamplerIdx)++, access.ioType(),
160                                static_cast<GrGLTexture *>(access.texture()));
161     }
162 }
163 
generateMipmaps(const GrProcessor & processor,bool allowSRGBInputs)164 void GrGLProgram::generateMipmaps(const GrProcessor& processor,
165                                   bool allowSRGBInputs) {
166     for (int i = 0; i < processor.numTextureSamplers(); ++i) {
167         const GrProcessor::TextureSampler& sampler = processor.textureSampler(i);
168         fGpu->generateMipmaps(sampler.params(), allowSRGBInputs,
169                               static_cast<GrGLTexture*>(sampler.texture()));
170     }
171 }
172