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