• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2014 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 "GrGLProgramBuilder.h"
9 
10 #include "GrAutoLocaleSetter.h"
11 #include "GrCoordTransform.h"
12 #include "GrGLProgramBuilder.h"
13 #include "GrSwizzle.h"
14 #include "GrTexture.h"
15 #include "SkRTConf.h"
16 #include "SkTraceEvent.h"
17 #include "gl/GrGLGpu.h"
18 #include "gl/GrGLProgram.h"
19 #include "gl/GrGLSLPrettyPrint.h"
20 #include "gl/builders/GrGLShaderStringBuilder.h"
21 #include "glsl/GrGLSLCaps.h"
22 #include "glsl/GrGLSLFragmentProcessor.h"
23 #include "glsl/GrGLSLGeometryProcessor.h"
24 #include "glsl/GrGLSLProgramDataManager.h"
25 #include "glsl/GrGLSLTextureSampler.h"
26 #include "glsl/GrGLSLXferProcessor.h"
27 
28 #define GL_CALL(X) GR_GL_CALL(this->gpu()->glInterface(), X)
29 #define GL_CALL_RET(R, X) GR_GL_CALL_RET(this->gpu()->glInterface(), R, X)
30 
CreateProgram(const DrawArgs & args,GrGLGpu * gpu)31 GrGLProgram* GrGLProgramBuilder::CreateProgram(const DrawArgs& args, GrGLGpu* gpu) {
32     GrAutoLocaleSetter als("C");
33 
34     // create a builder.  This will be handed off to effects so they can use it to add
35     // uniforms, varyings, textures, etc
36     GrGLProgramBuilder builder(gpu, args);
37 
38     // TODO: Once all stages can handle taking a float or vec4 and correctly handling them we can
39     // seed correctly here
40     GrGLSLExpr4 inputColor;
41     GrGLSLExpr4 inputCoverage;
42 
43     if (!builder.emitAndInstallProcs(&inputColor,
44                                      &inputCoverage,
45                                      gpu->glCaps().maxFragmentTextureUnits())) {
46         builder.cleanupFragmentProcessors();
47         return nullptr;
48     }
49 
50     return builder.finalize();
51 }
52 
53 /////////////////////////////////////////////////////////////////////////////
54 
GrGLProgramBuilder(GrGLGpu * gpu,const DrawArgs & args)55 GrGLProgramBuilder::GrGLProgramBuilder(GrGLGpu* gpu, const DrawArgs& args)
56     : INHERITED(args)
57     , fGpu(gpu)
58     , fSamplerUniforms(4)
59     , fVaryingHandler(this)
60     , fUniformHandler(this) {
61 }
62 
caps() const63 const GrCaps* GrGLProgramBuilder::caps() const {
64     return fGpu->caps();
65 }
66 
glslCaps() const67 const GrGLSLCaps* GrGLProgramBuilder::glslCaps() const {
68     return fGpu->ctxInfo().caps()->glslCaps();
69 }
70 
get_sampler_type(const GrTextureAccess & access)71 static GrSLType get_sampler_type(const GrTextureAccess& access) {
72     GrGLTexture* glTexture = static_cast<GrGLTexture*>(access.getTexture());
73     if (glTexture->target() == GR_GL_TEXTURE_EXTERNAL) {
74         return kSamplerExternal_GrSLType;
75     } else if (glTexture->target() == GR_GL_TEXTURE_RECTANGLE) {
76         return kSampler2DRect_GrSLType;
77     } else {
78         SkASSERT(glTexture->target() == GR_GL_TEXTURE_2D);
79         return kSampler2D_GrSLType;
80     }
81 }
82 
emitSamplers(const GrProcessor & processor,GrGLSLTextureSampler::TextureSamplerArray * outSamplers)83 void GrGLProgramBuilder::emitSamplers(const GrProcessor& processor,
84                                       GrGLSLTextureSampler::TextureSamplerArray* outSamplers) {
85     int numTextures = processor.numTextures();
86     UniformHandle* localSamplerUniforms = fSamplerUniforms.push_back_n(numTextures);
87     SkString name;
88     for (int t = 0; t < numTextures; ++t) {
89         name.printf("Sampler%d", t);
90         GrSLType samplerType = get_sampler_type(processor.textureAccess(t));
91         localSamplerUniforms[t] = fUniformHandler.addUniform(kFragment_GrShaderFlag, samplerType,
92                                                              kDefault_GrSLPrecision, name.c_str());
93         outSamplers->emplace_back(localSamplerUniforms[t], processor.textureAccess(t));
94         if (kSamplerExternal_GrSLType == samplerType) {
95             const char* externalFeatureString = this->glslCaps()->externalTextureExtensionString();
96             // We shouldn't ever create a GrGLTexture that requires external sampler type
97             SkASSERT(externalFeatureString);
98             fFS.addFeature(1 << GrGLSLFragmentShaderBuilder::kExternalTexture_GLSLPrivateFeature,
99                            externalFeatureString);
100         }
101     }
102 }
103 
compileAndAttachShaders(GrGLSLShaderBuilder & shader,GrGLuint programId,GrGLenum type,SkTDArray<GrGLuint> * shaderIds)104 bool GrGLProgramBuilder::compileAndAttachShaders(GrGLSLShaderBuilder& shader,
105                                                  GrGLuint programId,
106                                                  GrGLenum type,
107                                                  SkTDArray<GrGLuint>* shaderIds) {
108     GrGLGpu* gpu = this->gpu();
109     GrGLuint shaderId = GrGLCompileAndAttachShader(gpu->glContext(),
110                                                    programId,
111                                                    type,
112                                                    shader.fCompilerStrings.begin(),
113                                                    shader.fCompilerStringLengths.begin(),
114                                                    shader.fCompilerStrings.count(),
115                                                    gpu->stats());
116 
117     if (!shaderId) {
118         return false;
119     }
120 
121     *shaderIds->append() = shaderId;
122 
123     return true;
124 }
125 
finalize()126 GrGLProgram* GrGLProgramBuilder::finalize() {
127     // verify we can get a program id
128     GrGLuint programID;
129     GL_CALL_RET(programID, CreateProgram());
130     if (0 == programID) {
131         this->cleanupFragmentProcessors();
132         return nullptr;
133     }
134 
135     this->finalizeShaders();
136 
137     // compile shaders and bind attributes / uniforms
138     SkTDArray<GrGLuint> shadersToDelete;
139     if (!this->compileAndAttachShaders(fVS, programID, GR_GL_VERTEX_SHADER, &shadersToDelete)) {
140         this->cleanupProgram(programID, shadersToDelete);
141         return nullptr;
142     }
143 
144     // NVPR actually requires a vertex shader to compile
145     bool useNvpr = primitiveProcessor().isPathRendering();
146     if (!useNvpr) {
147         const GrPrimitiveProcessor& primProc = this->primitiveProcessor();
148 
149         int vaCount = primProc.numAttribs();
150         for (int i = 0; i < vaCount; i++) {
151             GL_CALL(BindAttribLocation(programID, i, primProc.getAttrib(i).fName));
152         }
153     }
154 
155     if (!this->compileAndAttachShaders(fFS, programID, GR_GL_FRAGMENT_SHADER, &shadersToDelete)) {
156         this->cleanupProgram(programID, shadersToDelete);
157         return nullptr;
158     }
159 
160     this->bindProgramResourceLocations(programID);
161 
162     GL_CALL(LinkProgram(programID));
163 
164     // Calling GetProgramiv is expensive in Chromium. Assume success in release builds.
165     bool checkLinked = kChromium_GrGLDriver != fGpu->ctxInfo().driver();
166 #ifdef SK_DEBUG
167     checkLinked = true;
168 #endif
169     if (checkLinked) {
170         checkLinkStatus(programID);
171     }
172     this->resolveProgramResourceLocations(programID);
173 
174     this->cleanupShaders(shadersToDelete);
175 
176     return this->createProgram(programID);
177 }
178 
bindProgramResourceLocations(GrGLuint programID)179 void GrGLProgramBuilder::bindProgramResourceLocations(GrGLuint programID) {
180     fUniformHandler.bindUniformLocations(programID, fGpu->glCaps());
181 
182     const GrGLCaps& caps = this->gpu()->glCaps();
183     if (fFS.hasCustomColorOutput() && caps.bindFragDataLocationSupport()) {
184         GL_CALL(BindFragDataLocation(programID, 0,
185                                      GrGLSLFragmentShaderBuilder::DeclaredColorOutputName()));
186     }
187     if (fFS.hasSecondaryOutput() && caps.glslCaps()->mustDeclareFragmentShaderOutput()) {
188         GL_CALL(BindFragDataLocationIndexed(programID, 0, 1,
189                                   GrGLSLFragmentShaderBuilder::DeclaredSecondaryColorOutputName()));
190     }
191 
192     // handle NVPR separable varyings
193     if (!fGpu->glCaps().shaderCaps()->pathRenderingSupport() ||
194         !fGpu->glPathRendering()->shouldBindFragmentInputs()) {
195         return;
196     }
197     int count = fVaryingHandler.fPathProcVaryingInfos.count();
198     for (int i = 0; i < count; ++i) {
199         GL_CALL(BindFragmentInputLocation(programID, i,
200                                        fVaryingHandler.fPathProcVaryingInfos[i].fVariable.c_str()));
201         fVaryingHandler.fPathProcVaryingInfos[i].fLocation = i;
202     }
203 }
204 
checkLinkStatus(GrGLuint programID)205 bool GrGLProgramBuilder::checkLinkStatus(GrGLuint programID) {
206     GrGLint linked = GR_GL_INIT_ZERO;
207     GL_CALL(GetProgramiv(programID, GR_GL_LINK_STATUS, &linked));
208     if (!linked) {
209         GrGLint infoLen = GR_GL_INIT_ZERO;
210         GL_CALL(GetProgramiv(programID, GR_GL_INFO_LOG_LENGTH, &infoLen));
211         SkAutoMalloc log(sizeof(char)*(infoLen+1));  // outside if for debugger
212         if (infoLen > 0) {
213             // retrieve length even though we don't need it to workaround
214             // bug in chrome cmd buffer param validation.
215             GrGLsizei length = GR_GL_INIT_ZERO;
216             GL_CALL(GetProgramInfoLog(programID,
217                                       infoLen+1,
218                                       &length,
219                                       (char*)log.get()));
220             SkDebugf("%s", (char*)log.get());
221         }
222         SkDEBUGFAIL("Error linking program");
223         GL_CALL(DeleteProgram(programID));
224         programID = 0;
225     }
226     return SkToBool(linked);
227 }
228 
resolveProgramResourceLocations(GrGLuint programID)229 void GrGLProgramBuilder::resolveProgramResourceLocations(GrGLuint programID) {
230     fUniformHandler.getUniformLocations(programID, fGpu->glCaps());
231 
232     // handle NVPR separable varyings
233     if (!fGpu->glCaps().shaderCaps()->pathRenderingSupport() ||
234         fGpu->glPathRendering()->shouldBindFragmentInputs()) {
235         return;
236     }
237     int count = fVaryingHandler.fPathProcVaryingInfos.count();
238     for (int i = 0; i < count; ++i) {
239         GrGLint location;
240         GL_CALL_RET(location, GetProgramResourceLocation(
241                                        programID,
242                                        GR_GL_FRAGMENT_INPUT,
243                                        fVaryingHandler.fPathProcVaryingInfos[i].fVariable.c_str()));
244         fVaryingHandler.fPathProcVaryingInfos[i].fLocation = location;
245     }
246 }
247 
cleanupProgram(GrGLuint programID,const SkTDArray<GrGLuint> & shaderIDs)248 void GrGLProgramBuilder::cleanupProgram(GrGLuint programID, const SkTDArray<GrGLuint>& shaderIDs) {
249     GL_CALL(DeleteProgram(programID));
250     this->cleanupShaders(shaderIDs);
251     this->cleanupFragmentProcessors();
252 }
cleanupShaders(const SkTDArray<GrGLuint> & shaderIDs)253 void GrGLProgramBuilder::cleanupShaders(const SkTDArray<GrGLuint>& shaderIDs) {
254     for (int i = 0; i < shaderIDs.count(); ++i) {
255       GL_CALL(DeleteShader(shaderIDs[i]));
256     }
257 }
258 
createProgram(GrGLuint programID)259 GrGLProgram* GrGLProgramBuilder::createProgram(GrGLuint programID) {
260     return new GrGLProgram(fGpu,
261                            this->desc(),
262                            fUniformHandles,
263                            programID,
264                            fUniformHandler.fUniforms,
265                            fVaryingHandler.fPathProcVaryingInfos,
266                            fGeometryProcessor,
267                            fXferProcessor,
268                            fFragmentProcessors,
269                            &fSamplerUniforms);
270 }
271 
272