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