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