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 "GrContext.h"
12 #include "GrContextPriv.h"
13 #include "GrCoordTransform.h"
14 #include "GrGLProgramBuilder.h"
15 #include "GrProgramDesc.h"
16 #include "GrShaderCaps.h"
17 #include "GrSwizzle.h"
18 #include "SkAutoMalloc.h"
19 #include "SkATrace.h"
20 #include "SkTraceEvent.h"
21 #include "gl/GrGLGpu.h"
22 #include "gl/GrGLProgram.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(GrRenderTarget * renderTarget,GrSurfaceOrigin origin,const GrPrimitiveProcessor & primProc,const GrTextureProxy * const primProcProxies[],const GrPipeline & pipeline,GrProgramDesc * desc,GrGLGpu * gpu)32 GrGLProgram* GrGLProgramBuilder::CreateProgram(GrRenderTarget* renderTarget, GrSurfaceOrigin origin,
33 const GrPrimitiveProcessor& primProc,
34 const GrTextureProxy* const primProcProxies[],
35 const GrPipeline& pipeline,
36 GrProgramDesc* desc,
37 GrGLGpu* gpu) {
38 SkASSERT(!pipeline.isBad());
39
40 ATRACE_ANDROID_FRAMEWORK("Shader Compile");
41 GrAutoLocaleSetter als("C");
42
43 // create a builder. This will be handed off to effects so they can use it to add
44 // uniforms, varyings, textures, etc
45 GrGLProgramBuilder builder(gpu, renderTarget, origin,
46 pipeline, primProc, primProcProxies, desc);
47
48 auto persistentCache = gpu->getContext()->contextPriv().getPersistentCache();
49 if (persistentCache) {
50 sk_sp<SkData> key = SkData::MakeWithoutCopy(desc->asKey(), desc->keyLength());
51 builder.fCached = persistentCache->load(*key);
52 // the eventual end goal is to completely skip emitAndInstallProcs on a cache hit, but it's
53 // doing necessary setup in addition to generating the SkSL code. Currently we are only able
54 // to skip the SkSL->GLSL step on a cache hit.
55 }
56 if (!builder.emitAndInstallProcs()) {
57 return nullptr;
58 }
59 return builder.finalize();
60 }
61
62 /////////////////////////////////////////////////////////////////////////////
63
GrGLProgramBuilder(GrGLGpu * gpu,GrRenderTarget * renderTarget,GrSurfaceOrigin origin,const GrPipeline & pipeline,const GrPrimitiveProcessor & primProc,const GrTextureProxy * const primProcProxies[],GrProgramDesc * desc)64 GrGLProgramBuilder::GrGLProgramBuilder(GrGLGpu* gpu,
65 GrRenderTarget* renderTarget,
66 GrSurfaceOrigin origin,
67 const GrPipeline& pipeline,
68 const GrPrimitiveProcessor& primProc,
69 const GrTextureProxy* const primProcProxies[],
70 GrProgramDesc* desc)
71 : INHERITED(renderTarget, origin, primProc, primProcProxies, pipeline, desc)
72 , fGpu(gpu)
73 , fVaryingHandler(this)
74 , fUniformHandler(this)
75 , fVertexAttributeCnt(0)
76 , fInstanceAttributeCnt(0)
77 , fVertexStride(0)
78 , fInstanceStride(0) {}
79
caps() const80 const GrCaps* GrGLProgramBuilder::caps() const {
81 return fGpu->caps();
82 }
83
compileAndAttachShaders(const char * glsl,int length,GrGLuint programId,GrGLenum type,SkTDArray<GrGLuint> * shaderIds,const SkSL::Program::Settings & settings,const SkSL::Program::Inputs & inputs)84 bool GrGLProgramBuilder::compileAndAttachShaders(const char* glsl,
85 int length,
86 GrGLuint programId,
87 GrGLenum type,
88 SkTDArray<GrGLuint>* shaderIds,
89 const SkSL::Program::Settings& settings,
90 const SkSL::Program::Inputs& inputs) {
91 GrGLGpu* gpu = this->gpu();
92 GrGLuint shaderId = GrGLCompileAndAttachShader(gpu->glContext(),
93 programId,
94 type,
95 glsl,
96 length,
97 gpu->stats(),
98 settings);
99 if (!shaderId) {
100 return false;
101 }
102
103 *shaderIds->append() = shaderId;
104 if (inputs.fFlipY) {
105 GrProgramDesc* d = this->desc();
106 d->setSurfaceOriginKey(GrGLSLFragmentShaderBuilder::KeyForSurfaceOrigin(this->origin()));
107 }
108
109 return true;
110 }
111
compileAndAttachShaders(GrGLSLShaderBuilder & shader,GrGLuint programId,GrGLenum type,SkTDArray<GrGLuint> * shaderIds,const SkSL::Program::Settings & settings,SkSL::Program::Inputs * outInputs)112 bool GrGLProgramBuilder::compileAndAttachShaders(GrGLSLShaderBuilder& shader,
113 GrGLuint programId,
114 GrGLenum type,
115 SkTDArray<GrGLuint>* shaderIds,
116 const SkSL::Program::Settings& settings,
117 SkSL::Program::Inputs* outInputs) {
118 SkSL::String glsl;
119 std::unique_ptr<SkSL::Program> program = GrSkSLtoGLSL(gpu()->glContext(), type,
120 shader.fCompilerStrings.begin(),
121 shader.fCompilerStringLengths.begin(),
122 shader.fCompilerStrings.count(),
123 settings,
124 &glsl);
125 *outInputs = program->fInputs;
126 return this->compileAndAttachShaders(glsl.c_str(),
127 glsl.size(),
128 programId,
129 type,
130 shaderIds,
131 settings,
132 *outInputs);
133 }
134
computeCountsAndStrides(GrGLuint programID,const GrPrimitiveProcessor & primProc,bool bindAttribLocations)135 void GrGLProgramBuilder::computeCountsAndStrides(GrGLuint programID,
136 const GrPrimitiveProcessor& primProc,
137 bool bindAttribLocations) {
138 fVertexAttributeCnt = primProc.numVertexAttributes();
139 fInstanceAttributeCnt = primProc.numInstanceAttributes();
140 fAttributes.reset(
141 new GrGLProgram::Attribute[fVertexAttributeCnt + fInstanceAttributeCnt]);
142 auto addAttr = [&](int i, const auto& a, size_t* stride) {
143 fAttributes[i].fCPUType = a.cpuType();
144 fAttributes[i].fGPUType = a.gpuType();
145 fAttributes[i].fOffset = *stride;
146 *stride += a.sizeAlign4();
147 fAttributes[i].fLocation = i;
148 if (bindAttribLocations) {
149 GL_CALL(BindAttribLocation(programID, i, a.name()));
150 }
151 };
152 fVertexStride = 0;
153 int i = 0;
154 for (const auto& attr : primProc.vertexAttributes()) {
155 addAttr(i++, attr, &fVertexStride);
156 }
157 SkASSERT(fVertexStride == primProc.vertexStride());
158 fInstanceStride = 0;
159 for (const auto& attr : primProc.instanceAttributes()) {
160 addAttr(i++, attr, &fInstanceStride);
161 }
162 SkASSERT(fInstanceStride == primProc.instanceStride());
163 }
164
addInputVars(const SkSL::Program::Inputs & inputs)165 void GrGLProgramBuilder::addInputVars(const SkSL::Program::Inputs& inputs) {
166 if (inputs.fRTWidth) {
167 this->addRTWidthUniform(SKSL_RTWIDTH_NAME);
168 }
169 if (inputs.fRTHeight) {
170 this->addRTHeightUniform(SKSL_RTHEIGHT_NAME);
171 }
172 }
173
storeShaderInCache(const SkSL::Program::Inputs & inputs,GrGLuint programID,const SkSL::String & glsl)174 void GrGLProgramBuilder::storeShaderInCache(const SkSL::Program::Inputs& inputs, GrGLuint programID,
175 const SkSL::String& glsl) {
176 if (!this->gpu()->getContext()->contextPriv().getPersistentCache()) {
177 return;
178 }
179 sk_sp<SkData> key = SkData::MakeWithoutCopy(desc()->asKey(), desc()->keyLength());
180 if (fGpu->glCaps().programBinarySupport()) {
181 // binary cache
182 GrGLsizei length = 0;
183 GL_CALL(GetProgramiv(programID, GL_PROGRAM_BINARY_LENGTH, &length));
184 if (length > 0) {
185 GrGLenum binaryFormat;
186 std::unique_ptr<char[]> binary(new char[length]);
187 GL_CALL(GetProgramBinary(programID, length, &length, &binaryFormat, binary.get()));
188 size_t dataLength = sizeof(inputs) + sizeof(binaryFormat) + length;
189 std::unique_ptr<uint8_t[]> data(new uint8_t[dataLength]);
190 size_t offset = 0;
191 memcpy(data.get() + offset, &inputs, sizeof(inputs));
192 offset += sizeof(inputs);
193 memcpy(data.get() + offset, &binaryFormat, sizeof(binaryFormat));
194 offset += sizeof(binaryFormat);
195 memcpy(data.get() + offset, binary.get(), length);
196 this->gpu()->getContext()->contextPriv().getPersistentCache()->store(
197 *key, *SkData::MakeWithoutCopy(data.get(), dataLength));
198 }
199 } else {
200 // source cache
201 size_t dataLength = sizeof(inputs) + glsl.length();
202 std::unique_ptr<uint8_t[]> data(new uint8_t[dataLength]);
203 size_t offset = 0;
204 memcpy(data.get() + offset, &inputs, sizeof(inputs));
205 offset += sizeof(inputs);
206 memcpy(data.get() + offset, glsl.data(), glsl.length());
207 this->gpu()->getContext()->contextPriv().getPersistentCache()->store(
208 *key, *SkData::MakeWithoutCopy(data.get(), dataLength));
209 }
210 }
211
finalize()212 GrGLProgram* GrGLProgramBuilder::finalize() {
213 TRACE_EVENT0("skia", TRACE_FUNC);
214
215 // verify we can get a program id
216 GrGLuint programID;
217 GL_CALL_RET(programID, CreateProgram());
218 if (0 == programID) {
219 return nullptr;
220 }
221
222 if (this->gpu()->glCaps().programBinarySupport() &&
223 this->gpu()->getContext()->contextPriv().getPersistentCache()) {
224 GL_CALL(ProgramParameteri(programID, GR_GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GR_GL_TRUE));
225 }
226
227 this->finalizeShaders();
228
229 // compile shaders and bind attributes / uniforms
230 const GrPrimitiveProcessor& primProc = this->primitiveProcessor();
231 SkSL::Program::Settings settings;
232 settings.fCaps = this->gpu()->glCaps().shaderCaps();
233 settings.fFlipY = this->origin() != kTopLeft_GrSurfaceOrigin;
234 settings.fSharpenTextures = this->gpu()->getContext()->contextPriv().sharpenMipmappedTextures();
235 settings.fFragColorIsInOut = this->fragColorIsInOut();
236
237 SkSL::Program::Inputs inputs;
238 SkTDArray<GrGLuint> shadersToDelete;
239 // Calling GetProgramiv is expensive in Chromium. Assume success in release builds.
240 bool checkLinked = kChromium_GrGLDriver != fGpu->ctxInfo().driver();
241 #ifdef SK_DEBUG
242 checkLinked = true;
243 #endif
244 bool cached = fCached.get() != nullptr;
245 SkSL::String glsl;
246 if (cached) {
247 const uint8_t* bytes = fCached->bytes();
248 size_t offset = 0;
249 memcpy(&inputs, bytes + offset, sizeof(inputs));
250 offset += sizeof(inputs);
251 if (fGpu->glCaps().programBinarySupport()) {
252 // binary cache hit, just hand the binary to GL
253 int binaryFormat;
254 memcpy(&binaryFormat, bytes + offset, sizeof(binaryFormat));
255 offset += sizeof(binaryFormat);
256 GrGLClearErr(this->gpu()->glInterface());
257 GR_GL_CALL_NOERRCHECK(this->gpu()->glInterface(),
258 ProgramBinary(programID, binaryFormat, (void*) (bytes + offset),
259 fCached->size() - offset));
260 if (GR_GL_GET_ERROR(this->gpu()->glInterface()) == GR_GL_NO_ERROR) {
261 if (checkLinked) {
262 cached = this->checkLinkStatus(programID);
263 }
264 if (cached) {
265 this->addInputVars(inputs);
266 this->computeCountsAndStrides(programID, primProc, false);
267 }
268 } else {
269 cached = false;
270 }
271 } else {
272 // source cache hit, we don't need to compile the SkSL->GLSL
273 glsl = SkSL::String(((const char*) bytes) + offset, fCached->size() - offset);
274 }
275 }
276 if (!cached || !fGpu->glCaps().programBinarySupport()) {
277 // either a cache miss, or we can't store binaries in the cache
278 if (glsl == "" || true) {
279 // don't have cached GLSL, need to compile SkSL->GLSL
280 if (fFS.fForceHighPrecision) {
281 settings.fForceHighPrecision = true;
282 }
283 std::unique_ptr<SkSL::Program> fs = GrSkSLtoGLSL(gpu()->glContext(),
284 GR_GL_FRAGMENT_SHADER,
285 fFS.fCompilerStrings.begin(),
286 fFS.fCompilerStringLengths.begin(),
287 fFS.fCompilerStrings.count(),
288 settings,
289 &glsl);
290 if (!fs) {
291 this->cleanupProgram(programID, shadersToDelete);
292 return nullptr;
293 }
294 inputs = fs->fInputs;
295 } else {
296 // we've pulled GLSL and inputs from the cache, but still need to do some setup
297 this->addInputVars(inputs);
298 this->computeCountsAndStrides(programID, primProc, false);
299 }
300 this->addInputVars(inputs);
301 if (!this->compileAndAttachShaders(glsl.c_str(), glsl.size(), programID,
302 GR_GL_FRAGMENT_SHADER, &shadersToDelete, settings,
303 inputs)) {
304 this->cleanupProgram(programID, shadersToDelete);
305 return nullptr;
306 }
307
308 std::unique_ptr<SkSL::Program> vs = GrSkSLtoGLSL(gpu()->glContext(),
309 GR_GL_VERTEX_SHADER,
310 fVS.fCompilerStrings.begin(),
311 fVS.fCompilerStringLengths.begin(),
312 fVS.fCompilerStrings.count(),
313 settings,
314 &glsl);
315 if (!vs || !this->compileAndAttachShaders(glsl.c_str(), glsl.size(), programID,
316 GR_GL_VERTEX_SHADER, &shadersToDelete, settings,
317 inputs)) {
318 this->cleanupProgram(programID, shadersToDelete);
319 return nullptr;
320 }
321
322 // NVPR actually requires a vertex shader to compile
323 bool useNvpr = primProc.isPathRendering();
324 if (!useNvpr) {
325 this->computeCountsAndStrides(programID, primProc, true);
326 }
327
328 if (primProc.willUseGeoShader()) {
329 std::unique_ptr<SkSL::Program> gs;
330 gs = GrSkSLtoGLSL(gpu()->glContext(),
331 GR_GL_GEOMETRY_SHADER,
332 fGS.fCompilerStrings.begin(),
333 fGS.fCompilerStringLengths.begin(),
334 fGS.fCompilerStrings.count(),
335 settings,
336 &glsl);
337 if (!gs || !this->compileAndAttachShaders(glsl.c_str(), glsl.size(), programID,
338 GR_GL_GEOMETRY_SHADER, &shadersToDelete,
339 settings, inputs)) {
340 this->cleanupProgram(programID, shadersToDelete);
341 return nullptr;
342 }
343 }
344 this->bindProgramResourceLocations(programID);
345
346 GL_CALL(LinkProgram(programID));
347 if (checkLinked) {
348 if (!this->checkLinkStatus(programID)) {
349 GL_CALL(DeleteProgram(programID));
350 SkDebugf("VS:\n");
351 GrGLPrintShader(fGpu->glContext(),
352 GR_GL_VERTEX_SHADER,
353 fVS.fCompilerStrings.begin(),
354 fVS.fCompilerStringLengths.begin(),
355 fVS.fCompilerStrings.count(),
356 settings);
357 if (primProc.willUseGeoShader()) {
358 SkDebugf("\nGS:\n");
359 GrGLPrintShader(fGpu->glContext(),
360 GR_GL_GEOMETRY_SHADER,
361 fGS.fCompilerStrings.begin(),
362 fGS.fCompilerStringLengths.begin(),
363 fGS.fCompilerStrings.count(), settings);
364 }
365 SkDebugf("\nFS:\n");
366 GrGLPrintShader(fGpu->glContext(),
367 GR_GL_FRAGMENT_SHADER,
368 fFS.fCompilerStrings.begin(),
369 fFS.fCompilerStringLengths.begin(),
370 fFS.fCompilerStrings.count(),
371 settings);
372 return nullptr;
373 }
374 }
375 }
376 this->resolveProgramResourceLocations(programID);
377
378 this->cleanupShaders(shadersToDelete);
379 if (!cached) {
380 this->storeShaderInCache(inputs, programID, glsl);
381 }
382 return this->createProgram(programID);
383 }
384
bindProgramResourceLocations(GrGLuint programID)385 void GrGLProgramBuilder::bindProgramResourceLocations(GrGLuint programID) {
386 fUniformHandler.bindUniformLocations(programID, fGpu->glCaps());
387
388 const GrGLCaps& caps = this->gpu()->glCaps();
389 if (fFS.hasCustomColorOutput() && caps.bindFragDataLocationSupport()) {
390 GL_CALL(BindFragDataLocation(programID, 0,
391 GrGLSLFragmentShaderBuilder::DeclaredColorOutputName()));
392 }
393 if (fFS.hasSecondaryOutput() && caps.shaderCaps()->mustDeclareFragmentShaderOutput()) {
394 GL_CALL(BindFragDataLocationIndexed(programID, 0, 1,
395 GrGLSLFragmentShaderBuilder::DeclaredSecondaryColorOutputName()));
396 }
397
398 // handle NVPR separable varyings
399 if (!fGpu->glCaps().shaderCaps()->pathRenderingSupport() ||
400 !fGpu->glPathRendering()->shouldBindFragmentInputs()) {
401 return;
402 }
403 int count = fVaryingHandler.fPathProcVaryingInfos.count();
404 for (int i = 0; i < count; ++i) {
405 GL_CALL(BindFragmentInputLocation(programID, i,
406 fVaryingHandler.fPathProcVaryingInfos[i].fVariable.c_str()));
407 fVaryingHandler.fPathProcVaryingInfos[i].fLocation = i;
408 }
409 }
410
checkLinkStatus(GrGLuint programID)411 bool GrGLProgramBuilder::checkLinkStatus(GrGLuint programID) {
412 GrGLint linked = GR_GL_INIT_ZERO;
413 GL_CALL(GetProgramiv(programID, GR_GL_LINK_STATUS, &linked));
414 if (!linked) {
415 SkDebugf("Program linking failed.\n");
416 GrGLint infoLen = GR_GL_INIT_ZERO;
417 GL_CALL(GetProgramiv(programID, GR_GL_INFO_LOG_LENGTH, &infoLen));
418 SkAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
419 if (infoLen > 0) {
420 // retrieve length even though we don't need it to workaround
421 // bug in chrome cmd buffer param validation.
422 GrGLsizei length = GR_GL_INIT_ZERO;
423 GL_CALL(GetProgramInfoLog(programID,
424 infoLen+1,
425 &length,
426 (char*)log.get()));
427 SkDebugf("%s", (char*)log.get());
428 }
429 }
430 return SkToBool(linked);
431 }
432
resolveProgramResourceLocations(GrGLuint programID)433 void GrGLProgramBuilder::resolveProgramResourceLocations(GrGLuint programID) {
434 fUniformHandler.getUniformLocations(programID, fGpu->glCaps());
435
436 // handle NVPR separable varyings
437 if (!fGpu->glCaps().shaderCaps()->pathRenderingSupport() ||
438 fGpu->glPathRendering()->shouldBindFragmentInputs()) {
439 return;
440 }
441 int count = fVaryingHandler.fPathProcVaryingInfos.count();
442 for (int i = 0; i < count; ++i) {
443 GrGLint location;
444 GL_CALL_RET(location, GetProgramResourceLocation(
445 programID,
446 GR_GL_FRAGMENT_INPUT,
447 fVaryingHandler.fPathProcVaryingInfos[i].fVariable.c_str()));
448 fVaryingHandler.fPathProcVaryingInfos[i].fLocation = location;
449 }
450 }
451
cleanupProgram(GrGLuint programID,const SkTDArray<GrGLuint> & shaderIDs)452 void GrGLProgramBuilder::cleanupProgram(GrGLuint programID, const SkTDArray<GrGLuint>& shaderIDs) {
453 GL_CALL(DeleteProgram(programID));
454 this->cleanupShaders(shaderIDs);
455 }
cleanupShaders(const SkTDArray<GrGLuint> & shaderIDs)456 void GrGLProgramBuilder::cleanupShaders(const SkTDArray<GrGLuint>& shaderIDs) {
457 for (int i = 0; i < shaderIDs.count(); ++i) {
458 GL_CALL(DeleteShader(shaderIDs[i]));
459 }
460 }
461
createProgram(GrGLuint programID)462 GrGLProgram* GrGLProgramBuilder::createProgram(GrGLuint programID) {
463 return new GrGLProgram(fGpu,
464 fUniformHandles,
465 programID,
466 fUniformHandler.fUniforms,
467 fUniformHandler.fSamplers,
468 fVaryingHandler.fPathProcVaryingInfos,
469 std::move(fGeometryProcessor),
470 std::move(fXferProcessor),
471 std::move(fFragmentProcessors),
472 fFragmentProcessorCnt,
473 std::move(fAttributes),
474 fVertexAttributeCnt,
475 fInstanceAttributeCnt,
476 fVertexStride,
477 fInstanceStride);
478 }
479