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