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