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 "src/gpu/gl/builders/GrGLProgramBuilder.h"
9
10 #include "include/gpu/GrDirectContext.h"
11 #include "src/core/SkATrace.h"
12 #include "src/core/SkAutoMalloc.h"
13 #include "src/core/SkReadBuffer.h"
14 #include "src/core/SkTraceEvent.h"
15 #include "src/core/SkWriteBuffer.h"
16 #include "src/gpu/GrAutoLocaleSetter.h"
17 #include "src/gpu/GrDirectContextPriv.h"
18 #include "src/gpu/GrFragmentProcessor.h"
19 #include "src/gpu/GrGeometryProcessor.h"
20 #include "src/gpu/GrPersistentCacheUtils.h"
21 #include "src/gpu/GrProgramDesc.h"
22 #include "src/gpu/GrShaderCaps.h"
23 #include "src/gpu/GrShaderUtils.h"
24 #include "src/gpu/GrSwizzle.h"
25 #include "src/gpu/GrXferProcessor.h"
26 #include "src/gpu/gl/GrGLGpu.h"
27 #include "src/gpu/gl/GrGLProgram.h"
28 #include "src/gpu/gl/builders/GrGLProgramBuilder.h"
29
30 #include <memory>
31 #include "src/gpu/gl/builders/GrGLShaderStringBuilder.h"
32 #include "src/gpu/glsl/GrGLSLProgramDataManager.h"
33
34 #define GL_CALL(X) GR_GL_CALL(this->gpu()->glInterface(), X)
35 #define GL_CALL_RET(R, X) GR_GL_CALL_RET(this->gpu()->glInterface(), R, X)
36
cleanup_shaders(GrGLGpu * gpu,const SkTDArray<GrGLuint> & shaderIDs)37 static void cleanup_shaders(GrGLGpu* gpu, const SkTDArray<GrGLuint>& shaderIDs) {
38 for (int i = 0; i < shaderIDs.count(); ++i) {
39 GR_GL_CALL(gpu->glInterface(), DeleteShader(shaderIDs[i]));
40 }
41 }
42
cleanup_program(GrGLGpu * gpu,GrGLuint programID,const SkTDArray<GrGLuint> & shaderIDs)43 static void cleanup_program(GrGLGpu* gpu, GrGLuint programID,
44 const SkTDArray<GrGLuint>& shaderIDs) {
45 GR_GL_CALL(gpu->glInterface(), DeleteProgram(programID));
46 cleanup_shaders(gpu, shaderIDs);
47 }
48
CreateProgram(GrDirectContext * dContext,const GrProgramDesc & desc,const GrProgramInfo & programInfo,const GrGLPrecompiledProgram * precompiledProgram)49 sk_sp<GrGLProgram> GrGLProgramBuilder::CreateProgram(
50 GrDirectContext* dContext,
51 const GrProgramDesc& desc,
52 const GrProgramInfo& programInfo,
53 const GrGLPrecompiledProgram* precompiledProgram) {
54 TRACE_EVENT0_ALWAYS("skia.shaders", "shader_compile");
55 GrAutoLocaleSetter als("C");
56
57 GrGLGpu* glGpu = static_cast<GrGLGpu*>(dContext->priv().getGpu());
58
59 // create a builder. This will be handed off to effects so they can use it to add
60 // uniforms, varyings, textures, etc
61 GrGLProgramBuilder builder(glGpu, desc, programInfo);
62
63 auto persistentCache = dContext->priv().getPersistentCache();
64 if (persistentCache && !precompiledProgram) {
65 sk_sp<SkData> key = SkData::MakeWithoutCopy(desc.asKey(), desc.keyLength());
66 builder.fCached = persistentCache->load(*key);
67 // the eventual end goal is to completely skip emitAndInstallProcs on a cache hit, but it's
68 // doing necessary setup in addition to generating the SkSL code. Currently we are only able
69 // to skip the SkSL->GLSL step on a cache hit.
70 }
71 if (!builder.emitAndInstallProcs()) {
72 return nullptr;
73 }
74 return builder.finalize(precompiledProgram);
75 }
76
77 /////////////////////////////////////////////////////////////////////////////
78
GrGLProgramBuilder(GrGLGpu * gpu,const GrProgramDesc & desc,const GrProgramInfo & programInfo)79 GrGLProgramBuilder::GrGLProgramBuilder(GrGLGpu* gpu,
80 const GrProgramDesc& desc,
81 const GrProgramInfo& programInfo)
82 : INHERITED(desc, programInfo)
83 , fGpu(gpu)
84 , fVaryingHandler(this)
85 , fUniformHandler(this)
86 , fVertexAttributeCnt(0)
87 , fInstanceAttributeCnt(0)
88 , fVertexStride(0)
89 , fInstanceStride(0) {}
90
caps() const91 const GrCaps* GrGLProgramBuilder::caps() const {
92 return fGpu->caps();
93 }
94
shaderCompiler() const95 SkSL::Compiler* GrGLProgramBuilder::shaderCompiler() const {
96 return fGpu->shaderCompiler();
97 }
98
compileAndAttachShaders(const SkSL::String & glsl,GrGLuint programId,GrGLenum type,SkTDArray<GrGLuint> * shaderIds,GrContextOptions::ShaderErrorHandler * errHandler)99 bool GrGLProgramBuilder::compileAndAttachShaders(const SkSL::String& glsl,
100 GrGLuint programId,
101 GrGLenum type,
102 SkTDArray<GrGLuint>* shaderIds,
103 GrContextOptions::ShaderErrorHandler* errHandler) {
104 GrGLGpu* gpu = this->gpu();
105 GrGLuint shaderId = GrGLCompileAndAttachShader(gpu->glContext(),
106 programId,
107 type,
108 glsl,
109 gpu->pipelineBuilder()->stats(),
110 errHandler);
111 if (!shaderId) {
112 return false;
113 }
114
115 *shaderIds->append() = shaderId;
116 return true;
117 }
118
computeCountsAndStrides(GrGLuint programID,const GrGeometryProcessor & geomProc,bool bindAttribLocations)119 void GrGLProgramBuilder::computeCountsAndStrides(GrGLuint programID,
120 const GrGeometryProcessor& geomProc,
121 bool bindAttribLocations) {
122 fVertexAttributeCnt = geomProc.numVertexAttributes();
123 fInstanceAttributeCnt = geomProc.numInstanceAttributes();
124 fAttributes = std::make_unique<GrGLProgram::Attribute[]>(
125 fVertexAttributeCnt + fInstanceAttributeCnt);
126 auto addAttr = [&](int i, const auto& a, size_t* stride) {
127 fAttributes[i].fCPUType = a.cpuType();
128 fAttributes[i].fGPUType = a.gpuType();
129 fAttributes[i].fOffset = *stride;
130 *stride += a.sizeAlign4();
131 fAttributes[i].fLocation = i;
132 if (bindAttribLocations) {
133 GL_CALL(BindAttribLocation(programID, i, a.name()));
134 }
135 };
136 fVertexStride = 0;
137 int i = 0;
138 for (const auto& attr : geomProc.vertexAttributes()) {
139 addAttr(i++, attr, &fVertexStride);
140 }
141 SkASSERT(fVertexStride == geomProc.vertexStride());
142 fInstanceStride = 0;
143 for (const auto& attr : geomProc.instanceAttributes()) {
144 addAttr(i++, attr, &fInstanceStride);
145 }
146 SkASSERT(fInstanceStride == geomProc.instanceStride());
147 }
148
addInputVars(const SkSL::Program::Inputs & inputs)149 void GrGLProgramBuilder::addInputVars(const SkSL::Program::Inputs& inputs) {
150 if (inputs.fUseFlipRTUniform) {
151 this->addRTFlipUniform(SKSL_RTFLIP_NAME);
152 }
153 }
154
155 static constexpr SkFourByteTag kSKSL_Tag = SkSetFourByteTag('S', 'K', 'S', 'L');
156 static constexpr SkFourByteTag kGLSL_Tag = SkSetFourByteTag('G', 'L', 'S', 'L');
157 static constexpr SkFourByteTag kGLPB_Tag = SkSetFourByteTag('G', 'L', 'P', 'B');
158
storeShaderInCache(const SkSL::Program::Inputs & inputs,GrGLuint programID,const SkSL::String shaders[],bool isSkSL,SkSL::Program::Settings * settings)159 void GrGLProgramBuilder::storeShaderInCache(const SkSL::Program::Inputs& inputs, GrGLuint programID,
160 const SkSL::String shaders[], bool isSkSL,
161 SkSL::Program::Settings* settings) {
162 if (!this->gpu()->getContext()->priv().getPersistentCache()) {
163 return;
164 }
165 sk_sp<SkData> key = SkData::MakeWithoutCopy(this->desc().asKey(), this->desc().keyLength());
166 SkString description = GrProgramDesc::Describe(fProgramInfo, *fGpu->caps());
167 if (fGpu->glCaps().programBinarySupport()) {
168 // binary cache
169 GrGLsizei length = 0;
170 GL_CALL(GetProgramiv(programID, GL_PROGRAM_BINARY_LENGTH, &length));
171 if (length > 0) {
172 SkBinaryWriteBuffer writer;
173 writer.writeInt(GrPersistentCacheUtils::GetCurrentVersion());
174 writer.writeUInt(kGLPB_Tag);
175
176 writer.writePad32(&inputs, sizeof(inputs));
177
178 SkAutoSMalloc<2048> binary(length);
179 GrGLenum binaryFormat;
180 GL_CALL(GetProgramBinary(programID, length, &length, &binaryFormat, binary.get()));
181
182 writer.writeUInt(binaryFormat);
183 writer.writeInt(length);
184 writer.writePad32(binary.get(), length);
185
186 auto data = writer.snapshotAsData();
187 this->gpu()->getContext()->priv().getPersistentCache()->store(*key, *data, description);
188 }
189 } else {
190 // source cache, plus metadata to allow for a complete precompile
191 GrPersistentCacheUtils::ShaderMetadata meta;
192 meta.fSettings = settings;
193 meta.fHasCustomColorOutput = fFS.hasCustomColorOutput();
194 meta.fHasSecondaryColorOutput = fFS.hasSecondaryOutput();
195 for (const auto& attr : this->geometryProcessor().vertexAttributes()) {
196 meta.fAttributeNames.emplace_back(attr.name());
197 }
198 for (const auto& attr : this->geometryProcessor().instanceAttributes()) {
199 meta.fAttributeNames.emplace_back(attr.name());
200 }
201
202 auto data = GrPersistentCacheUtils::PackCachedShaders(isSkSL ? kSKSL_Tag : kGLSL_Tag,
203 shaders, &inputs, 1, &meta);
204 this->gpu()->getContext()->priv().getPersistentCache()->store(*key, *data, description);
205 }
206 }
207
finalize(const GrGLPrecompiledProgram * precompiledProgram)208 sk_sp<GrGLProgram> GrGLProgramBuilder::finalize(const GrGLPrecompiledProgram* precompiledProgram) {
209 TRACE_EVENT0("skia.shaders", TRACE_FUNC);
210
211 // verify we can get a program id
212 GrGLuint programID;
213 if (precompiledProgram) {
214 programID = precompiledProgram->fProgramID;
215 } else {
216 GL_CALL_RET(programID, CreateProgram());
217 }
218 if (0 == programID) {
219 return nullptr;
220 }
221
222 if (this->gpu()->glCaps().programBinarySupport() &&
223 this->gpu()->glCaps().programParameterSupport() &&
224 this->gpu()->getContext()->priv().getPersistentCache() &&
225 !precompiledProgram) {
226 GL_CALL(ProgramParameteri(programID, GR_GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GR_GL_TRUE));
227 }
228
229 this->finalizeShaders();
230
231 // compile shaders and bind attributes / uniforms
232 auto errorHandler = this->gpu()->getContext()->priv().getShaderErrorHandler();
233 const GrGeometryProcessor& geomProc = this->geometryProcessor();
234 SkSL::Program::Settings settings;
235 settings.fSharpenTextures =
236 this->gpu()->getContext()->priv().options().fSharpenMipmappedTextures;
237 settings.fFragColorIsInOut = this->fragColorIsInOut();
238
239 SkSL::Program::Inputs inputs;
240 SkTDArray<GrGLuint> shadersToDelete;
241
242 bool checkLinked = !fGpu->glCaps().skipErrorChecks();
243
244 bool cached = fCached.get() != nullptr;
245 bool usedProgramBinaries = false;
246 SkSL::String glsl[kGrShaderTypeCount];
247 SkSL::String* sksl[kGrShaderTypeCount] = {
248 &fVS.fCompilerString,
249 &fFS.fCompilerString,
250 };
251 SkSL::String cached_sksl[kGrShaderTypeCount];
252 if (precompiledProgram) {
253 // This is very similar to when we get program binaries. We even set that flag, as it's
254 // used to prevent other compile work later, and to force re-querying uniform locations.
255 this->addInputVars(precompiledProgram->fInputs);
256 this->computeCountsAndStrides(programID, geomProc, false);
257 usedProgramBinaries = true;
258 } else if (cached) {
259 TRACE_EVENT0_ALWAYS("skia.shaders", "cache_hit");
260 SkReadBuffer reader(fCached->data(), fCached->size());
261 SkFourByteTag shaderType = GrPersistentCacheUtils::GetType(&reader);
262
263 switch (shaderType) {
264 case kGLPB_Tag: {
265 // Program binary cache hit. We may opt not to use this if we don't trust program
266 // binaries on this driver
267 if (!fGpu->glCaps().programBinarySupport()) {
268 cached = false;
269 break;
270 }
271 reader.readPad32(&inputs, sizeof(inputs));
272 GrGLenum binaryFormat = reader.readUInt();
273 GrGLsizei length = reader.readInt();
274 const void* binary = reader.skip(length);
275 if (!reader.isValid()) {
276 break;
277 }
278 this->gpu()->clearErrorsAndCheckForOOM();
279 GR_GL_CALL_NOERRCHECK(this->gpu()->glInterface(),
280 ProgramBinary(programID, binaryFormat,
281 const_cast<void*>(binary), length));
282 if (this->gpu()->getErrorAndCheckForOOM() == GR_GL_NO_ERROR) {
283 if (checkLinked) {
284 cached = this->checkLinkStatus(programID, errorHandler, nullptr, nullptr);
285 }
286 if (cached) {
287 this->addInputVars(inputs);
288 this->computeCountsAndStrides(programID, geomProc, false);
289 }
290 } else {
291 cached = false;
292 }
293 usedProgramBinaries = cached;
294 break;
295 }
296
297 case kGLSL_Tag:
298 // Source cache hit, we don't need to compile the SkSL->GLSL
299 GrPersistentCacheUtils::UnpackCachedShaders(&reader, glsl, &inputs, 1);
300 break;
301
302 case kSKSL_Tag:
303 // SkSL cache hit, this should only happen in tools overriding the generated SkSL
304 if (GrPersistentCacheUtils::UnpackCachedShaders(&reader, cached_sksl, &inputs, 1)) {
305 for (int i = 0; i < kGrShaderTypeCount; ++i) {
306 sksl[i] = &cached_sksl[i];
307 }
308 }
309 break;
310
311 default:
312 // We got something invalid, so pretend it wasn't there
313 reader.validate(false);
314 break;
315 }
316 if (!reader.isValid()) {
317 cached = false;
318 }
319 }
320 if (!usedProgramBinaries) {
321 TRACE_EVENT0_ALWAYS("skia.shaders", "cache_miss");
322 // Either a cache miss, or we got something other than binaries from the cache
323
324 /*
325 Fragment Shader
326 */
327 if (glsl[kFragment_GrShaderType].empty()) {
328 // Don't have cached GLSL, need to compile SkSL->GLSL
329 if (fFS.fForceHighPrecision) {
330 settings.fForceHighPrecision = true;
331 }
332 std::unique_ptr<SkSL::Program> fs = GrSkSLtoGLSL(this->gpu(),
333 SkSL::ProgramKind::kFragment,
334 *sksl[kFragment_GrShaderType],
335 settings,
336 &glsl[kFragment_GrShaderType],
337 errorHandler);
338 if (!fs) {
339 cleanup_program(fGpu, programID, shadersToDelete);
340 return nullptr;
341 }
342 inputs = fs->fInputs;
343 }
344
345 this->addInputVars(inputs);
346 if (!this->compileAndAttachShaders(glsl[kFragment_GrShaderType], programID,
347 GR_GL_FRAGMENT_SHADER, &shadersToDelete, errorHandler)) {
348 cleanup_program(fGpu, programID, shadersToDelete);
349 return nullptr;
350 }
351
352 /*
353 Vertex Shader
354 */
355 if (glsl[kVertex_GrShaderType].empty()) {
356 // Don't have cached GLSL, need to compile SkSL->GLSL
357 std::unique_ptr<SkSL::Program> vs = GrSkSLtoGLSL(this->gpu(),
358 SkSL::ProgramKind::kVertex,
359 *sksl[kVertex_GrShaderType],
360 settings,
361 &glsl[kVertex_GrShaderType],
362 errorHandler);
363 if (!vs) {
364 cleanup_program(fGpu, programID, shadersToDelete);
365 return nullptr;
366 }
367 }
368 if (!this->compileAndAttachShaders(glsl[kVertex_GrShaderType], programID,
369 GR_GL_VERTEX_SHADER, &shadersToDelete, errorHandler)) {
370 cleanup_program(fGpu, programID, shadersToDelete);
371 return nullptr;
372 }
373
374 // This also binds vertex attribute locations.
375 this->computeCountsAndStrides(programID, geomProc, true);
376
377 /*
378 Tessellation Shaders
379 */
380 if (fProgramInfo.geomProc().willUseTessellationShaders()) {
381 // Tessellation shaders are not currently supported by SkSL. So here, we temporarily
382 // generate GLSL strings directly using back door methods on GrGeometryProcessor, and
383 // pass those raw strings on to the driver.
384 SkString versionAndExtensionDecls;
385 versionAndExtensionDecls.appendf("%s\n", this->shaderCaps()->versionDeclString());
386 if (const char* extensionString = this->shaderCaps()->tessellationExtensionString()) {
387 versionAndExtensionDecls.appendf("#extension %s : require\n", extensionString);
388 }
389
390 SkString tessControlShader =
391 fGPImpl->getTessControlShaderGLSL(geomProc,
392 versionAndExtensionDecls.c_str(),
393 fUniformHandler,
394 *this->shaderCaps());
395 if (!this->compileAndAttachShaders(tessControlShader.c_str(), programID,
396 GR_GL_TESS_CONTROL_SHADER, &shadersToDelete,
397 errorHandler)) {
398 cleanup_program(fGpu, programID, shadersToDelete);
399 return nullptr;
400 }
401
402 SkString tessEvaluationShader =
403 fGPImpl->getTessEvaluationShaderGLSL(geomProc,
404 versionAndExtensionDecls.c_str(),
405 fUniformHandler,
406 *this->shaderCaps());
407 if (!this->compileAndAttachShaders(tessEvaluationShader.c_str(), programID,
408 GR_GL_TESS_EVALUATION_SHADER, &shadersToDelete,
409 errorHandler)) {
410 cleanup_program(fGpu, programID, shadersToDelete);
411 return nullptr;
412 }
413 }
414
415 this->bindProgramResourceLocations(programID);
416
417 {
418 TRACE_EVENT0_ALWAYS("skia.shaders", "driver_link_program");
419 GL_CALL(LinkProgram(programID));
420 if (checkLinked) {
421 if (!this->checkLinkStatus(programID, errorHandler, sksl, glsl)) {
422 cleanup_program(fGpu, programID, shadersToDelete);
423 return nullptr;
424 }
425 }
426 }
427 }
428 this->resolveProgramResourceLocations(programID, usedProgramBinaries);
429
430 cleanup_shaders(fGpu, shadersToDelete);
431
432 // We temporarily can't cache tessellation shaders while using back door GLSL.
433 //
434 // We also can't cache SkSL or GLSL if we were given a precompiled program, but there's not
435 // much point in doing so.
436 if (!cached && !geomProc.willUseTessellationShaders() && !precompiledProgram) {
437 // FIXME: Remove the check for tessellation shaders in the above 'if' once the back door
438 // GLSL mechanism is removed.
439 (void)&GrGeometryProcessor::ProgramImpl::getTessControlShaderGLSL;
440 bool isSkSL = false;
441 if (fGpu->getContext()->priv().options().fShaderCacheStrategy ==
442 GrContextOptions::ShaderCacheStrategy::kSkSL) {
443 for (int i = 0; i < kGrShaderTypeCount; ++i) {
444 glsl[i] = GrShaderUtils::PrettyPrint(*sksl[i]);
445 }
446 isSkSL = true;
447 }
448 this->storeShaderInCache(inputs, programID, glsl, isSkSL, &settings);
449 }
450 return this->createProgram(programID);
451 }
452
bindProgramResourceLocations(GrGLuint programID)453 void GrGLProgramBuilder::bindProgramResourceLocations(GrGLuint programID) {
454 fUniformHandler.bindUniformLocations(programID, fGpu->glCaps());
455
456 const GrGLCaps& caps = this->gpu()->glCaps();
457 if (fFS.hasCustomColorOutput() && caps.bindFragDataLocationSupport()) {
458 GL_CALL(BindFragDataLocation(programID, 0,
459 GrGLSLFragmentShaderBuilder::DeclaredColorOutputName()));
460 }
461 if (fFS.hasSecondaryOutput() && caps.shaderCaps()->mustDeclareFragmentShaderOutput()) {
462 GL_CALL(BindFragDataLocationIndexed(programID, 0, 1,
463 GrGLSLFragmentShaderBuilder::DeclaredSecondaryColorOutputName()));
464 }
465 }
466
checkLinkStatus(GrGLuint programID,GrContextOptions::ShaderErrorHandler * errorHandler,SkSL::String * sksl[],const SkSL::String glsl[])467 bool GrGLProgramBuilder::checkLinkStatus(GrGLuint programID,
468 GrContextOptions::ShaderErrorHandler* errorHandler,
469 SkSL::String* sksl[], const SkSL::String glsl[]) {
470 GrGLint linked = GR_GL_INIT_ZERO;
471 GL_CALL(GetProgramiv(programID, GR_GL_LINK_STATUS, &linked));
472 if (!linked) {
473 SkSL::String allShaders;
474 if (sksl) {
475 allShaders.appendf("// Vertex SKSL\n%s\n", sksl[kVertex_GrShaderType]->c_str());
476 allShaders.appendf("// Fragment SKSL\n%s\n", sksl[kFragment_GrShaderType]->c_str());
477 }
478 if (glsl) {
479 allShaders.appendf("// Vertex GLSL\n%s\n", glsl[kVertex_GrShaderType].c_str());
480 allShaders.appendf("// Fragment GLSL\n%s\n", glsl[kFragment_GrShaderType].c_str());
481 }
482 GrGLint infoLen = GR_GL_INIT_ZERO;
483 GL_CALL(GetProgramiv(programID, GR_GL_INFO_LOG_LENGTH, &infoLen));
484 SkAutoMalloc log(infoLen+1);
485 if (infoLen > 0) {
486 // retrieve length even though we don't need it to workaround
487 // bug in chrome cmd buffer param validation.
488 GrGLsizei length = GR_GL_INIT_ZERO;
489 GL_CALL(GetProgramInfoLog(programID, infoLen+1, &length, (char*)log.get()));
490 }
491 const char* errorMsg = (infoLen > 0) ? (const char*)log.get()
492 : "link failed but did not provide an info log";
493 errorHandler->compileError(allShaders.c_str(), errorMsg);
494 }
495 return SkToBool(linked);
496 }
497
resolveProgramResourceLocations(GrGLuint programID,bool force)498 void GrGLProgramBuilder::resolveProgramResourceLocations(GrGLuint programID, bool force) {
499 fUniformHandler.getUniformLocations(programID, fGpu->glCaps(), force);
500 }
501
createProgram(GrGLuint programID)502 sk_sp<GrGLProgram> GrGLProgramBuilder::createProgram(GrGLuint programID) {
503 return GrGLProgram::Make(fGpu,
504 fUniformHandles,
505 programID,
506 fUniformHandler.fUniforms,
507 fUniformHandler.fSamplers,
508 std::move(fGPImpl),
509 std::move(fXPImpl),
510 std::move(fFPImpls),
511 std::move(fAttributes),
512 fVertexAttributeCnt,
513 fInstanceAttributeCnt,
514 fVertexStride,
515 fInstanceStride);
516 }
517
PrecompileProgram(GrDirectContext * dContext,GrGLPrecompiledProgram * precompiledProgram,const SkData & cachedData)518 bool GrGLProgramBuilder::PrecompileProgram(GrDirectContext* dContext,
519 GrGLPrecompiledProgram* precompiledProgram,
520 const SkData& cachedData) {
521 SkReadBuffer reader(cachedData.data(), cachedData.size());
522 SkFourByteTag shaderType = GrPersistentCacheUtils::GetType(&reader);
523 if (shaderType != kSKSL_Tag) {
524 // TODO: Support GLSL, and maybe even program binaries, too?
525 return false;
526 }
527
528 GrGLGpu* glGpu = static_cast<GrGLGpu*>(dContext->priv().getGpu());
529
530 const GrGLInterface* gl = glGpu->glInterface();
531 auto errorHandler = dContext->priv().getShaderErrorHandler();
532
533 SkSL::Program::Settings settings;
534 settings.fSharpenTextures = dContext->priv().options().fSharpenMipmappedTextures;
535 GrPersistentCacheUtils::ShaderMetadata meta;
536 meta.fSettings = &settings;
537
538 SkSL::String shaders[kGrShaderTypeCount];
539 SkSL::Program::Inputs inputs;
540 if (!GrPersistentCacheUtils::UnpackCachedShaders(&reader, shaders, &inputs, 1, &meta)) {
541 return false;
542 }
543
544 GrGLuint programID;
545 GR_GL_CALL_RET(gl, programID, CreateProgram());
546 if (0 == programID) {
547 return false;
548 }
549
550 SkTDArray<GrGLuint> shadersToDelete;
551
552 auto compileShader = [&](SkSL::ProgramKind kind, const SkSL::String& sksl, GrGLenum type) {
553 SkSL::String glsl;
554 auto program = GrSkSLtoGLSL(glGpu, kind, sksl, settings, &glsl, errorHandler);
555 if (!program) {
556 return false;
557 }
558
559 if (GrGLuint shaderID = GrGLCompileAndAttachShader(glGpu->glContext(), programID, type,
560 glsl, glGpu->pipelineBuilder()->stats(),
561 errorHandler)) {
562 shadersToDelete.push_back(shaderID);
563 return true;
564 } else {
565 return false;
566 }
567 };
568
569 if (!compileShader(SkSL::ProgramKind::kFragment,
570 shaders[kFragment_GrShaderType],
571 GR_GL_FRAGMENT_SHADER) ||
572 !compileShader(SkSL::ProgramKind::kVertex,
573 shaders[kVertex_GrShaderType],
574 GR_GL_VERTEX_SHADER)) {
575 cleanup_program(glGpu, programID, shadersToDelete);
576 return false;
577 }
578
579 for (int i = 0; i < meta.fAttributeNames.count(); ++i) {
580 GR_GL_CALL(glGpu->glInterface(), BindAttribLocation(programID, i,
581 meta.fAttributeNames[i].c_str()));
582 }
583
584 const GrGLCaps& caps = glGpu->glCaps();
585 if (meta.fHasCustomColorOutput && caps.bindFragDataLocationSupport()) {
586 GR_GL_CALL(glGpu->glInterface(),
587 BindFragDataLocation(programID, 0,
588 GrGLSLFragmentShaderBuilder::DeclaredColorOutputName()));
589 }
590 if (meta.fHasSecondaryColorOutput && caps.shaderCaps()->mustDeclareFragmentShaderOutput()) {
591 GR_GL_CALL(glGpu->glInterface(),
592 BindFragDataLocationIndexed(programID, 0, 1,
593 GrGLSLFragmentShaderBuilder::DeclaredSecondaryColorOutputName()));
594 }
595
596 GR_GL_CALL(glGpu->glInterface(), LinkProgram(programID));
597 GrGLint linked = GR_GL_INIT_ZERO;
598 GR_GL_CALL(glGpu->glInterface(), GetProgramiv(programID, GR_GL_LINK_STATUS, &linked));
599 if (!linked) {
600 cleanup_program(glGpu, programID, shadersToDelete);
601 return false;
602 }
603
604 cleanup_shaders(glGpu, shadersToDelete);
605
606 precompiledProgram->fProgramID = programID;
607 precompiledProgram->fInputs = inputs;
608 return true;
609 }
610