• 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 "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