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