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