blob: aea6b491168c65395ce2687ffd0bc473487c71ff [file] [log] [blame]
joshualitt30ba4362014-08-21 20:18:45 -07001/*
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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/gpu/gl/builders/GrGLProgramBuilder.h"
joshualitt8072caa2015-02-12 14:20:52 -08009
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "include/gpu/GrContext.h"
11#include "src/core/SkATrace.h"
12#include "src/core/SkAutoMalloc.h"
Brian Osman9e4e4c72020-06-10 07:19:34 -040013#include "src/core/SkReadBuffer.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050014#include "src/core/SkTraceEvent.h"
Brian Osman9e4e4c72020-06-10 07:19:34 -040015#include "src/core/SkWriteBuffer.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050016#include "src/gpu/GrAutoLocaleSetter.h"
17#include "src/gpu/GrContextPriv.h"
18#include "src/gpu/GrCoordTransform.h"
19#include "src/gpu/GrPersistentCacheUtils.h"
20#include "src/gpu/GrProgramDesc.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050021#include "src/gpu/GrShaderCaps.h"
Brian Osmanac9be9d2019-05-01 10:29:34 -040022#include "src/gpu/GrShaderUtils.h"
Brian Salomon3ec1f542019-06-17 17:54:57 +000023#include "src/gpu/GrSwizzle.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050024#include "src/gpu/gl/GrGLGpu.h"
25#include "src/gpu/gl/GrGLProgram.h"
26#include "src/gpu/gl/builders/GrGLProgramBuilder.h"
27#include "src/gpu/gl/builders/GrGLShaderStringBuilder.h"
28#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
29#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
30#include "src/gpu/glsl/GrGLSLProgramDataManager.h"
31#include "src/gpu/glsl/GrGLSLXferProcessor.h"
joshualitt30ba4362014-08-21 20:18:45 -070032
joshualitt30ba4362014-08-21 20:18:45 -070033#define GL_CALL(X) GR_GL_CALL(this->gpu()->glInterface(), X)
34#define GL_CALL_RET(R, X) GR_GL_CALL_RET(this->gpu()->glInterface(), R, X)
35
Brian Osmaned58e002019-09-06 14:42:43 -040036static void cleanup_shaders(GrGLGpu* gpu, const SkTDArray<GrGLuint>& shaderIDs) {
37 for (int i = 0; i < shaderIDs.count(); ++i) {
38 GR_GL_CALL(gpu->glInterface(), DeleteShader(shaderIDs[i]));
39 }
40}
41
42static void cleanup_program(GrGLGpu* gpu, GrGLuint programID,
43 const SkTDArray<GrGLuint>& shaderIDs) {
44 GR_GL_CALL(gpu->glInterface(), DeleteProgram(programID));
45 cleanup_shaders(gpu, shaderIDs);
46}
47
Stephen Whiteb1857852020-02-07 15:33:23 +000048sk_sp<GrGLProgram> GrGLProgramBuilder::CreateProgram(
Austin Eng77fdf662020-02-07 01:26:16 +000049 GrGLGpu* gpu,
Stephen Whiteb1857852020-02-07 15:33:23 +000050 GrRenderTarget* renderTarget,
51 const GrProgramDesc& desc,
52 const GrProgramInfo& programInfo,
Brian Osmaned58e002019-09-06 14:42:43 -040053 const GrGLPrecompiledProgram* precompiledProgram) {
Stan Iliev43324e72020-01-13 16:17:48 -050054 ATRACE_ANDROID_FRAMEWORK_ALWAYS("shader_compile");
bsalomon3318ee72015-03-16 11:56:29 -070055 GrAutoLocaleSetter als("C");
56
joshualitt47bb3822014-10-07 16:43:25 -070057 // create a builder. This will be handed off to effects so they can use it to add
58 // uniforms, varyings, textures, etc
Stephen Whiteb1857852020-02-07 15:33:23 +000059 GrGLProgramBuilder builder(gpu, renderTarget, desc, programInfo);
joshualitt47bb3822014-10-07 16:43:25 -070060
Robert Phillips9da87e02019-02-04 13:26:26 -050061 auto persistentCache = gpu->getContext()->priv().getPersistentCache();
Brian Osmaned58e002019-09-06 14:42:43 -040062 if (persistentCache && !precompiledProgram) {
Stephen Whiteb1857852020-02-07 15:33:23 +000063 sk_sp<SkData> key = SkData::MakeWithoutCopy(desc.asKey(), desc.keyLength());
Robert Phillips0c4b7b12018-03-06 08:20:37 -050064 builder.fCached = persistentCache->load(*key);
Ethan Nicholasd1b2eec2017-11-01 15:45:43 -040065 // the eventual end goal is to completely skip emitAndInstallProcs on a cache hit, but it's
66 // doing necessary setup in addition to generating the SkSL code. Currently we are only able
67 // to skip the SkSL->GLSL step on a cache hit.
68 }
Ethan Nicholas2983f402017-05-08 09:36:08 -040069 if (!builder.emitAndInstallProcs()) {
halcanary96fcdcc2015-08-27 07:41:13 -070070 return nullptr;
joshualitt6c891102015-05-13 08:51:49 -070071 }
Brian Osmaned58e002019-09-06 14:42:43 -040072 return builder.finalize(precompiledProgram);
joshualitt47bb3822014-10-07 16:43:25 -070073}
74
joshualitt47bb3822014-10-07 16:43:25 -070075/////////////////////////////////////////////////////////////////////////////
76
egdaniel0e1853c2016-03-17 11:35:45 -070077GrGLProgramBuilder::GrGLProgramBuilder(GrGLGpu* gpu,
Robert Phillipsd0fe8752019-01-31 14:13:59 -050078 GrRenderTarget* renderTarget,
Stephen Whiteb1857852020-02-07 15:33:23 +000079 const GrProgramDesc& desc,
80 const GrProgramInfo& programInfo)
81 : INHERITED(renderTarget, desc, programInfo)
Brian Salomon802cb312018-06-08 18:05:20 -040082 , fGpu(gpu)
83 , fVaryingHandler(this)
84 , fUniformHandler(this)
Brian Salomon92be2f72018-06-19 14:33:47 -040085 , fVertexAttributeCnt(0)
86 , fInstanceAttributeCnt(0)
Brian Salomon802cb312018-06-08 18:05:20 -040087 , fVertexStride(0)
88 , fInstanceStride(0) {}
joshualitt30ba4362014-08-21 20:18:45 -070089
egdanielfa896322016-01-13 12:19:30 -080090const GrCaps* GrGLProgramBuilder::caps() const {
91 return fGpu->caps();
92}
93
Brian Osmanac9be9d2019-05-01 10:29:34 -040094bool GrGLProgramBuilder::compileAndAttachShaders(const SkSL::String& glsl,
egdaniel574a4c12015-11-02 06:22:44 -080095 GrGLuint programId,
96 GrGLenum type,
Ethan Nicholas941e7e22016-12-12 15:33:30 -050097 SkTDArray<GrGLuint>* shaderIds,
Brian Osman5e7fbfd2019-05-03 13:13:35 -040098 GrContextOptions::ShaderErrorHandler* errHandler) {
egdaniel574a4c12015-11-02 06:22:44 -080099 GrGLGpu* gpu = this->gpu();
100 GrGLuint shaderId = GrGLCompileAndAttachShader(gpu->glContext(),
101 programId,
102 type,
Ethan Nicholasd1b2eec2017-11-01 15:45:43 -0400103 glsl,
Brian Osman8518f2e2019-05-01 14:13:41 -0400104 gpu->stats(),
Brian Osman5e7fbfd2019-05-03 13:13:35 -0400105 errHandler);
egdaniel574a4c12015-11-02 06:22:44 -0800106 if (!shaderId) {
107 return false;
108 }
109
110 *shaderIds->append() = shaderId;
egdaniel574a4c12015-11-02 06:22:44 -0800111 return true;
112}
113
Ethan Nicholasad77dce2018-07-11 13:59:03 -0400114void GrGLProgramBuilder::computeCountsAndStrides(GrGLuint programID,
115 const GrPrimitiveProcessor& primProc,
116 bool bindAttribLocations) {
117 fVertexAttributeCnt = primProc.numVertexAttributes();
118 fInstanceAttributeCnt = primProc.numInstanceAttributes();
119 fAttributes.reset(
120 new GrGLProgram::Attribute[fVertexAttributeCnt + fInstanceAttributeCnt]);
121 auto addAttr = [&](int i, const auto& a, size_t* stride) {
Brian Osman4a3f5c82018-09-18 16:16:38 -0400122 fAttributes[i].fCPUType = a.cpuType();
123 fAttributes[i].fGPUType = a.gpuType();
Ethan Nicholasad77dce2018-07-11 13:59:03 -0400124 fAttributes[i].fOffset = *stride;
125 *stride += a.sizeAlign4();
126 fAttributes[i].fLocation = i;
127 if (bindAttribLocations) {
128 GL_CALL(BindAttribLocation(programID, i, a.name()));
129 }
130 };
131 fVertexStride = 0;
132 int i = 0;
Brian Osmanf04fb3c2018-11-12 15:34:00 -0500133 for (const auto& attr : primProc.vertexAttributes()) {
134 addAttr(i++, attr, &fVertexStride);
Ethan Nicholasad77dce2018-07-11 13:59:03 -0400135 }
Brian Osmanf04fb3c2018-11-12 15:34:00 -0500136 SkASSERT(fVertexStride == primProc.vertexStride());
Ethan Nicholasad77dce2018-07-11 13:59:03 -0400137 fInstanceStride = 0;
Brian Osmanf04fb3c2018-11-12 15:34:00 -0500138 for (const auto& attr : primProc.instanceAttributes()) {
139 addAttr(i++, attr, &fInstanceStride);
Ethan Nicholasad77dce2018-07-11 13:59:03 -0400140 }
Brian Osmanf04fb3c2018-11-12 15:34:00 -0500141 SkASSERT(fInstanceStride == primProc.instanceStride());
Ethan Nicholasad77dce2018-07-11 13:59:03 -0400142}
143
Ethan Nicholascd700e92018-08-24 16:43:57 -0400144void GrGLProgramBuilder::addInputVars(const SkSL::Program::Inputs& inputs) {
145 if (inputs.fRTWidth) {
146 this->addRTWidthUniform(SKSL_RTWIDTH_NAME);
147 }
148 if (inputs.fRTHeight) {
149 this->addRTHeightUniform(SKSL_RTHEIGHT_NAME);
150 }
151}
152
Brian Osmana085a412019-04-25 09:44:43 -0400153static constexpr SkFourByteTag kSKSL_Tag = SkSetFourByteTag('S', 'K', 'S', 'L');
154static constexpr SkFourByteTag kGLSL_Tag = SkSetFourByteTag('G', 'L', 'S', 'L');
Brian Osmana66081d2019-09-03 14:59:26 -0400155static constexpr SkFourByteTag kGLPB_Tag = SkSetFourByteTag('G', 'L', 'P', 'B');
Brian Osmana085a412019-04-25 09:44:43 -0400156
Ethan Nicholas8d058832019-01-07 10:49:58 -0500157void GrGLProgramBuilder::storeShaderInCache(const SkSL::Program::Inputs& inputs, GrGLuint programID,
Brian Osmaned58e002019-09-06 14:42:43 -0400158 const SkSL::String shaders[], bool isSkSL,
Brian Osman4524e842019-09-24 16:03:41 -0400159 SkSL::Program::Settings* settings) {
Robert Phillips9da87e02019-02-04 13:26:26 -0500160 if (!this->gpu()->getContext()->priv().getPersistentCache()) {
Ethan Nicholas8d058832019-01-07 10:49:58 -0500161 return;
162 }
Stephen Whiteb1857852020-02-07 15:33:23 +0000163 sk_sp<SkData> key = SkData::MakeWithoutCopy(this->desc().asKey(), this->desc().keyLength());
Ethan Nicholas8d058832019-01-07 10:49:58 -0500164 if (fGpu->glCaps().programBinarySupport()) {
165 // binary cache
166 GrGLsizei length = 0;
167 GL_CALL(GetProgramiv(programID, GL_PROGRAM_BINARY_LENGTH, &length));
168 if (length > 0) {
Brian Osman9e4e4c72020-06-10 07:19:34 -0400169 SkBinaryWriteBuffer writer;
170 writer.writeInt(GrPersistentCacheUtils::kCurrentVersion);
171 writer.writeUInt(kGLPB_Tag);
Brian Osmana66081d2019-09-03 14:59:26 -0400172
Brian Osman9e4e4c72020-06-10 07:19:34 -0400173 writer.writePad32(&inputs, sizeof(inputs));
Brian Osman6b797fe2019-04-08 13:56:36 -0400174
Brian Osman9e4e4c72020-06-10 07:19:34 -0400175 SkAutoSMalloc<2048> binary(length);
Ethan Nicholas8d058832019-01-07 10:49:58 -0500176 GrGLenum binaryFormat;
Brian Osman9e4e4c72020-06-10 07:19:34 -0400177 GL_CALL(GetProgramBinary(programID, length, &length, &binaryFormat, binary.get()));
178
179 writer.writeUInt(binaryFormat);
180 writer.writeInt(length);
181 writer.writePad32(binary.get(), length);
Brian Osman6b797fe2019-04-08 13:56:36 -0400182
183 auto data = writer.snapshotAsData();
184 this->gpu()->getContext()->priv().getPersistentCache()->store(*key, *data);
Ethan Nicholas8d058832019-01-07 10:49:58 -0500185 }
186 } else {
Brian Osman4524e842019-09-24 16:03:41 -0400187 // source cache, plus metadata to allow for a complete precompile
188 GrPersistentCacheUtils::ShaderMetadata meta;
189 meta.fSettings = settings;
190 meta.fHasCustomColorOutput = fFS.hasCustomColorOutput();
191 meta.fHasSecondaryColorOutput = fFS.hasSecondaryOutput();
192 for (const auto& attr : this->primitiveProcessor().vertexAttributes()) {
193 meta.fAttributeNames.emplace_back(attr.name());
194 }
195 for (const auto& attr : this->primitiveProcessor().instanceAttributes()) {
196 meta.fAttributeNames.emplace_back(attr.name());
197 }
198
Brian Osmana085a412019-04-25 09:44:43 -0400199 auto data = GrPersistentCacheUtils::PackCachedShaders(isSkSL ? kSKSL_Tag : kGLSL_Tag,
Brian Osman4524e842019-09-24 16:03:41 -0400200 shaders, &inputs, 1, &meta);
Brian Osman6b797fe2019-04-08 13:56:36 -0400201 this->gpu()->getContext()->priv().getPersistentCache()->store(*key, *data);
Ethan Nicholas8d058832019-01-07 10:49:58 -0500202 }
203}
204
Stephen Whiteb1857852020-02-07 15:33:23 +0000205sk_sp<GrGLProgram> GrGLProgramBuilder::finalize(const GrGLPrecompiledProgram* precompiledProgram) {
Brian Salomon5f394272019-07-02 14:07:49 -0400206 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
Ryan Macnak38a10ad2017-07-10 10:36:34 -0700207
joshualitt47bb3822014-10-07 16:43:25 -0700208 // verify we can get a program id
209 GrGLuint programID;
Brian Osmaned58e002019-09-06 14:42:43 -0400210 if (precompiledProgram) {
211 programID = precompiledProgram->fProgramID;
212 } else {
213 GL_CALL_RET(programID, CreateProgram());
214 }
joshualitt47bb3822014-10-07 16:43:25 -0700215 if (0 == programID) {
halcanary96fcdcc2015-08-27 07:41:13 -0700216 return nullptr;
joshualitt30ba4362014-08-21 20:18:45 -0700217 }
218
Ethan Nicholas06d55fb2017-11-08 09:48:50 -0500219 if (this->gpu()->glCaps().programBinarySupport() &&
Brian Osman064729e2019-06-18 17:22:59 -0400220 this->gpu()->glCaps().programParameterSupport() &&
Brian Osmaned58e002019-09-06 14:42:43 -0400221 this->gpu()->getContext()->priv().getPersistentCache() &&
222 !precompiledProgram) {
Ethan Nicholasd1b2eec2017-11-01 15:45:43 -0400223 GL_CALL(ProgramParameteri(programID, GR_GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GR_GL_TRUE));
224 }
225
egdaniel9f1d4152016-02-10 09:50:38 -0800226 this->finalizeShaders();
227
joshualitt47bb3822014-10-07 16:43:25 -0700228 // compile shaders and bind attributes / uniforms
Brian Osman5e7fbfd2019-05-03 13:13:35 -0400229 auto errorHandler = this->gpu()->getContext()->priv().getShaderErrorHandler();
Ethan Nicholasd1b2eec2017-11-01 15:45:43 -0400230 const GrPrimitiveProcessor& primProc = this->primitiveProcessor();
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500231 SkSL::Program::Settings settings;
232 settings.fCaps = this->gpu()->glCaps().shaderCaps();
Robert Phillipsd0fe8752019-01-31 14:13:59 -0500233 settings.fFlipY = this->origin() != kTopLeft_GrSurfaceOrigin;
Robert Phillipsc1541ae2019-02-04 12:05:37 -0500234 settings.fSharpenTextures =
Robert Phillips9da87e02019-02-04 13:26:26 -0500235 this->gpu()->getContext()->priv().options().fSharpenMipmappedTextures;
Brian Salomondc092132018-04-04 10:14:16 -0400236 settings.fFragColorIsInOut = this->fragColorIsInOut();
237
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500238 SkSL::Program::Inputs inputs;
joshualitt30ba4362014-08-21 20:18:45 -0700239 SkTDArray<GrGLuint> shadersToDelete;
Brian Salomond8575452020-02-25 12:13:29 -0500240
241 bool checkLinked = !fGpu->glCaps().skipErrorChecks();
242
Ethan Nicholas8d058832019-01-07 10:49:58 -0500243 bool cached = fCached.get() != nullptr;
Brian Osman2c60a382019-06-26 15:19:30 -0400244 bool usedProgramBinaries = false;
Brian Osman6b797fe2019-04-08 13:56:36 -0400245 SkSL::String glsl[kGrShaderTypeCount];
Brian Osmancbc33b82019-04-19 14:16:19 -0400246 SkSL::String* sksl[kGrShaderTypeCount] = {
247 &fVS.fCompilerString,
248 &fGS.fCompilerString,
249 &fFS.fCompilerString,
250 };
Brian Osmancbc33b82019-04-19 14:16:19 -0400251 SkSL::String cached_sksl[kGrShaderTypeCount];
Brian Osmaned58e002019-09-06 14:42:43 -0400252 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);
Brian Osman4524e842019-09-24 16:03:41 -0400256 this->computeCountsAndStrides(programID, primProc, false);
Brian Osmaned58e002019-09-06 14:42:43 -0400257 usedProgramBinaries = true;
258 } else if (cached) {
Stan Iliev43324e72020-01-13 16:17:48 -0500259 ATRACE_ANDROID_FRAMEWORK_ALWAYS("cache_hit");
Brian Osman9e4e4c72020-06-10 07:19:34 -0400260 SkReadBuffer reader(fCached->data(), fCached->size());
Brian Osman1facd5e2020-03-16 16:21:24 -0400261 SkFourByteTag shaderType = GrPersistentCacheUtils::GetType(&reader);
Brian Osmana66081d2019-09-03 14:59:26 -0400262
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;
Ethan Nicholas8d058832019-01-07 10:49:58 -0500270 }
Brian Osman9e4e4c72020-06-10 07:19:34 -0400271 reader.readPad32(&inputs, sizeof(inputs));
272 GrGLenum binaryFormat = reader.readUInt();
273 GrGLsizei length = reader.readInt();
Brian Osmana66081d2019-09-03 14:59:26 -0400274 const void* binary = reader.skip(length);
Brian Osman9e4e4c72020-06-10 07:19:34 -0400275 if (!reader.isValid()) {
276 break;
277 }
Brian Osmana66081d2019-09-03 14:59:26 -0400278 GrGLClearErr(this->gpu()->glInterface());
279 GR_GL_CALL_NOERRCHECK(this->gpu()->glInterface(),
280 ProgramBinary(programID, binaryFormat,
281 const_cast<void*>(binary), length));
282 if (GR_GL_GET_ERROR(this->gpu()->glInterface()) == 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, primProc, false);
289 }
290 } else {
291 cached = false;
Ethan Nicholas8d058832019-01-07 10:49:58 -0500292 }
Brian Osmana66081d2019-09-03 14:59:26 -0400293 usedProgramBinaries = cached;
294 break;
Ethan Nicholasad77dce2018-07-11 13:59:03 -0400295 }
Brian Osmana66081d2019-09-03 14:59:26 -0400296
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
Brian Osman9e4e4c72020-06-10 07:19:34 -0400304 if (GrPersistentCacheUtils::UnpackCachedShaders(&reader, cached_sksl, &inputs, 1)) {
305 for (int i = 0; i < kGrShaderTypeCount; ++i) {
306 sksl[i] = &cached_sksl[i];
307 }
Brian Osmana085a412019-04-25 09:44:43 -0400308 }
Brian Osmana66081d2019-09-03 14:59:26 -0400309 break;
Brian Osman43f443f2020-06-05 11:11:36 -0400310
311 default:
312 // We got something invalid, so pretend it wasn't there
Brian Osman9e4e4c72020-06-10 07:19:34 -0400313 reader.validate(false);
Brian Osman43f443f2020-06-05 11:11:36 -0400314 break;
Ethan Nicholas98ad5b72018-03-13 09:53:02 -0400315 }
Brian Osman9e4e4c72020-06-10 07:19:34 -0400316 if (!reader.isValid()) {
317 cached = false;
318 }
Ethan Nicholas98ad5b72018-03-13 09:53:02 -0400319 }
Brian Osmana66081d2019-09-03 14:59:26 -0400320 if (!usedProgramBinaries) {
Stan Iliev43324e72020-01-13 16:17:48 -0500321 ATRACE_ANDROID_FRAMEWORK_ALWAYS("cache_miss");
Brian Osmanf7924452019-09-24 10:44:37 -0400322 // Either a cache miss, or we got something other than binaries from the cache
323
324 /*
325 Fragment Shader
326 */
Brian Osman6b797fe2019-04-08 13:56:36 -0400327 if (glsl[kFragment_GrShaderType].empty()) {
Brian Osmanf71b0702019-04-03 13:04:16 -0400328 // Don't have cached GLSL, need to compile SkSL->GLSL
Ethan Nicholas8d058832019-01-07 10:49:58 -0500329 if (fFS.fForceHighPrecision) {
330 settings.fForceHighPrecision = true;
331 }
332 std::unique_ptr<SkSL::Program> fs = GrSkSLtoGLSL(gpu()->glContext(),
Brian Osmanac9be9d2019-05-01 10:29:34 -0400333 SkSL::Program::kFragment_Kind,
Brian Osmancbc33b82019-04-19 14:16:19 -0400334 *sksl[kFragment_GrShaderType],
Ethan Nicholas8d058832019-01-07 10:49:58 -0500335 settings,
Brian Osman5e7fbfd2019-05-03 13:13:35 -0400336 &glsl[kFragment_GrShaderType],
337 errorHandler);
Ethan Nicholas8d058832019-01-07 10:49:58 -0500338 if (!fs) {
Brian Osmaned58e002019-09-06 14:42:43 -0400339 cleanup_program(fGpu, programID, shadersToDelete);
Ethan Nicholas8d058832019-01-07 10:49:58 -0500340 return nullptr;
341 }
342 inputs = fs->fInputs;
egdaniel8dcdedc2015-11-11 06:27:20 -0800343 }
Brian Osmanf7924452019-09-24 10:44:37 -0400344
345 this->addInputVars(inputs);
Brian Osmanac9be9d2019-05-01 10:29:34 -0400346 if (!this->compileAndAttachShaders(glsl[kFragment_GrShaderType], programID,
Brian Osmane11dfd32019-07-23 10:29:41 -0400347 GR_GL_FRAGMENT_SHADER, &shadersToDelete, errorHandler)) {
Brian Osmaned58e002019-09-06 14:42:43 -0400348 cleanup_program(fGpu, programID, shadersToDelete);
Ethan Nicholasd1b2eec2017-11-01 15:45:43 -0400349 return nullptr;
350 }
351
Brian Osmanf7924452019-09-24 10:44:37 -0400352 /*
353 Vertex Shader
354 */
Brian Osman6b797fe2019-04-08 13:56:36 -0400355 if (glsl[kVertex_GrShaderType].empty()) {
Brian Osmanf71b0702019-04-03 13:04:16 -0400356 // Don't have cached GLSL, need to compile SkSL->GLSL
357 std::unique_ptr<SkSL::Program> vs = GrSkSLtoGLSL(gpu()->glContext(),
Brian Osmanac9be9d2019-05-01 10:29:34 -0400358 SkSL::Program::kVertex_Kind,
Brian Osmancbc33b82019-04-19 14:16:19 -0400359 *sksl[kVertex_GrShaderType],
Brian Osmanf71b0702019-04-03 13:04:16 -0400360 settings,
Brian Osman5e7fbfd2019-05-03 13:13:35 -0400361 &glsl[kVertex_GrShaderType],
362 errorHandler);
Brian Osmanf71b0702019-04-03 13:04:16 -0400363 if (!vs) {
Brian Osmaned58e002019-09-06 14:42:43 -0400364 cleanup_program(fGpu, programID, shadersToDelete);
Brian Osmanf71b0702019-04-03 13:04:16 -0400365 return nullptr;
366 }
367 }
Brian Osmanac9be9d2019-05-01 10:29:34 -0400368 if (!this->compileAndAttachShaders(glsl[kVertex_GrShaderType], programID,
Brian Osmane11dfd32019-07-23 10:29:41 -0400369 GR_GL_VERTEX_SHADER, &shadersToDelete, errorHandler)) {
Brian Osmaned58e002019-09-06 14:42:43 -0400370 cleanup_program(fGpu, programID, shadersToDelete);
Ethan Nicholasd1b2eec2017-11-01 15:45:43 -0400371 return nullptr;
372 }
373
Brian Osmanf7924452019-09-24 10:44:37 -0400374 // This also binds vertex attribute locations. NVPR doesn't really use vertices,
375 // even though it requires a vertex shader in the program.
376 if (!primProc.isPathRendering()) {
Ethan Nicholasad77dce2018-07-11 13:59:03 -0400377 this->computeCountsAndStrides(programID, primProc, true);
Ethan Nicholasd1b2eec2017-11-01 15:45:43 -0400378 }
379
Brian Osmanf7924452019-09-24 10:44:37 -0400380 /*
Chris Dalton5a2f9622019-12-27 14:56:38 -0700381 Tessellation Shaders
382 */
383 if (fProgramInfo.primProc().willUseTessellationShaders()) {
384 // Tessellation shaders are not currently supported by SkSL. So here, we temporarily
385 // generate GLSL strings directly using back door methods on GrPrimitiveProcessor, and
386 // pass those raw strings on to the driver.
387 SkString versionAndExtensionDecls;
388 versionAndExtensionDecls.appendf("%s\n", this->shaderCaps()->versionDeclString());
389 if (const char* extensionString = this->shaderCaps()->tessellationExtensionString()) {
390 versionAndExtensionDecls.appendf("#extension %s : require\n", extensionString);
391 }
392
393 SkString tessControlShader = primProc.getTessControlShaderGLSL(
394 versionAndExtensionDecls.c_str(), *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 = primProc.getTessEvaluationShaderGLSL(
403 versionAndExtensionDecls.c_str(), *this->shaderCaps());
404 if (!this->compileAndAttachShaders(tessEvaluationShader.c_str(), programID,
405 GR_GL_TESS_EVALUATION_SHADER, &shadersToDelete,
406 errorHandler)) {
407 cleanup_program(fGpu, programID, shadersToDelete);
408 return nullptr;
409 }
410 }
411
412 /*
Brian Osmanf7924452019-09-24 10:44:37 -0400413 Geometry Shader
414 */
Ethan Nicholasd1b2eec2017-11-01 15:45:43 -0400415 if (primProc.willUseGeoShader()) {
Brian Osman6b797fe2019-04-08 13:56:36 -0400416 if (glsl[kGeometry_GrShaderType].empty()) {
Brian Osmanf71b0702019-04-03 13:04:16 -0400417 // Don't have cached GLSL, need to compile SkSL->GLSL
418 std::unique_ptr<SkSL::Program> gs;
419 gs = GrSkSLtoGLSL(gpu()->glContext(),
Brian Osmanac9be9d2019-05-01 10:29:34 -0400420 SkSL::Program::kGeometry_Kind,
Brian Osmancbc33b82019-04-19 14:16:19 -0400421 *sksl[kGeometry_GrShaderType],
Brian Osmanf71b0702019-04-03 13:04:16 -0400422 settings,
Brian Osman5e7fbfd2019-05-03 13:13:35 -0400423 &glsl[kGeometry_GrShaderType],
424 errorHandler);
Brian Osmanf71b0702019-04-03 13:04:16 -0400425 if (!gs) {
Brian Osmaned58e002019-09-06 14:42:43 -0400426 cleanup_program(fGpu, programID, shadersToDelete);
Brian Osmanf71b0702019-04-03 13:04:16 -0400427 return nullptr;
428 }
429 }
Brian Osmanac9be9d2019-05-01 10:29:34 -0400430 if (!this->compileAndAttachShaders(glsl[kGeometry_GrShaderType], programID,
Brian Osmane11dfd32019-07-23 10:29:41 -0400431 GR_GL_GEOMETRY_SHADER, &shadersToDelete,
Brian Osman5e7fbfd2019-05-03 13:13:35 -0400432 errorHandler)) {
Brian Osmaned58e002019-09-06 14:42:43 -0400433 cleanup_program(fGpu, programID, shadersToDelete);
Ethan Nicholasd1b2eec2017-11-01 15:45:43 -0400434 return nullptr;
435 }
Ethan Nicholasd1b2eec2017-11-01 15:45:43 -0400436 }
437 this->bindProgramResourceLocations(programID);
438
439 GL_CALL(LinkProgram(programID));
Ethan Nicholas5a0338c2019-01-02 11:48:56 -0500440 if (checkLinked) {
Brian Osman5e7fbfd2019-05-03 13:13:35 -0400441 if (!this->checkLinkStatus(programID, errorHandler, sksl, glsl)) {
Brian Osman2ab2ac02019-09-09 13:54:54 -0400442 cleanup_program(fGpu, programID, shadersToDelete);
Ethan Nicholas5a0338c2019-01-02 11:48:56 -0500443 return nullptr;
Brian Salomone334c592017-05-15 11:00:58 -0400444 }
Brian Salomone334c592017-05-15 11:00:58 -0400445 }
joshualittfe1233c2014-10-07 12:16:35 -0700446 }
Brian Osman2c60a382019-06-26 15:19:30 -0400447 this->resolveProgramResourceLocations(programID, usedProgramBinaries);
joshualittdb0d3ca2014-10-07 12:42:26 -0700448
Brian Osmaned58e002019-09-06 14:42:43 -0400449 cleanup_shaders(fGpu, shadersToDelete);
Brian Osmane4c88bb2019-06-27 16:15:11 -0400450
Chris Dalton5a2f9622019-12-27 14:56:38 -0700451 // We temporarily can't cache tessellation shaders while using back door GLSL.
452 //
Brian Osmaned58e002019-09-06 14:42:43 -0400453 // We also can't cache SkSL or GLSL if we were given a precompiled program, but there's not
454 // much point in doing so.
Brian Osman0b22f3b2020-03-23 13:21:24 -0400455 if (!cached && !primProc.willUseTessellationShaders() && !precompiledProgram) {
Chris Dalton8dae7eb2019-12-27 22:20:55 -0700456 // FIXME: Remove the check for tessellation shaders in the above 'if' once the back door
457 // GLSL mechanism is removed.
458 (void)&GrPrimitiveProcessor::getTessControlShaderGLSL;
Brian Osmana085a412019-04-25 09:44:43 -0400459 bool isSkSL = false;
Brian Osmana66081d2019-09-03 14:59:26 -0400460 if (fGpu->getContext()->priv().options().fShaderCacheStrategy ==
461 GrContextOptions::ShaderCacheStrategy::kSkSL) {
Brian Osmancbc33b82019-04-19 14:16:19 -0400462 for (int i = 0; i < kGrShaderTypeCount; ++i) {
Brian Osmanac9be9d2019-05-01 10:29:34 -0400463 glsl[i] = GrShaderUtils::PrettyPrint(*sksl[i]);
Brian Osmancbc33b82019-04-19 14:16:19 -0400464 }
Brian Osmana085a412019-04-25 09:44:43 -0400465 isSkSL = true;
Brian Osmancbc33b82019-04-19 14:16:19 -0400466 }
Brian Osman4524e842019-09-24 16:03:41 -0400467 this->storeShaderInCache(inputs, programID, glsl, isSkSL, &settings);
Ethan Nicholasd1b2eec2017-11-01 15:45:43 -0400468 }
joshualitt47bb3822014-10-07 16:43:25 -0700469 return this->createProgram(programID);
470}
471
kkinnunen7aedda52015-06-29 23:01:28 -0700472void GrGLProgramBuilder::bindProgramResourceLocations(GrGLuint programID) {
egdaniel7ea439b2015-12-03 09:20:44 -0800473 fUniformHandler.bindUniformLocations(programID, fGpu->glCaps());
kkinnunen7aedda52015-06-29 23:01:28 -0700474
egdaniel8dcdedc2015-11-11 06:27:20 -0800475 const GrGLCaps& caps = this->gpu()->glCaps();
476 if (fFS.hasCustomColorOutput() && caps.bindFragDataLocationSupport()) {
477 GL_CALL(BindFragDataLocation(programID, 0,
egdaniel2d721d32015-11-11 13:06:05 -0800478 GrGLSLFragmentShaderBuilder::DeclaredColorOutputName()));
egdaniel8dcdedc2015-11-11 06:27:20 -0800479 }
Brian Salomon1edc5b92016-11-29 13:43:46 -0500480 if (fFS.hasSecondaryOutput() && caps.shaderCaps()->mustDeclareFragmentShaderOutput()) {
egdaniel8dcdedc2015-11-11 06:27:20 -0800481 GL_CALL(BindFragDataLocationIndexed(programID, 0, 1,
egdaniel2d721d32015-11-11 13:06:05 -0800482 GrGLSLFragmentShaderBuilder::DeclaredSecondaryColorOutputName()));
egdaniel8dcdedc2015-11-11 06:27:20 -0800483 }
joshualittd8dd47b2015-09-11 11:45:01 -0700484
485 // handle NVPR separable varyings
486 if (!fGpu->glCaps().shaderCaps()->pathRenderingSupport() ||
487 !fGpu->glPathRendering()->shouldBindFragmentInputs()) {
488 return;
489 }
Michael Ludwig45191342020-03-24 12:29:39 -0400490 int i = 0;
491 for (auto& varying : fVaryingHandler.fPathProcVaryingInfos.items()) {
492 GL_CALL(BindFragmentInputLocation(programID, i, varying.fVariable.c_str()));
493 varying.fLocation = i;
494 ++i;
joshualittd8dd47b2015-09-11 11:45:01 -0700495 }
joshualitt47bb3822014-10-07 16:43:25 -0700496}
497
Brian Osman5e7fbfd2019-05-03 13:13:35 -0400498bool GrGLProgramBuilder::checkLinkStatus(GrGLuint programID,
499 GrContextOptions::ShaderErrorHandler* errorHandler,
500 SkSL::String* sksl[], const SkSL::String glsl[]) {
joshualitt47bb3822014-10-07 16:43:25 -0700501 GrGLint linked = GR_GL_INIT_ZERO;
502 GL_CALL(GetProgramiv(programID, GR_GL_LINK_STATUS, &linked));
503 if (!linked) {
Brian Osman5e7fbfd2019-05-03 13:13:35 -0400504 SkSL::String allShaders;
505 if (sksl) {
506 allShaders.appendf("// Vertex SKSL\n%s\n", sksl[kVertex_GrShaderType]->c_str());
507 if (!sksl[kGeometry_GrShaderType]->empty()) {
508 allShaders.appendf("// Geometry SKSL\n%s\n", sksl[kGeometry_GrShaderType]->c_str());
509 }
510 allShaders.appendf("// Fragment SKSL\n%s\n", sksl[kFragment_GrShaderType]->c_str());
511 }
512 if (glsl) {
513 allShaders.appendf("// Vertex GLSL\n%s\n", glsl[kVertex_GrShaderType].c_str());
514 if (!glsl[kGeometry_GrShaderType].empty()) {
515 allShaders.appendf("// Geometry GLSL\n%s\n", glsl[kGeometry_GrShaderType].c_str());
516 }
517 allShaders.appendf("// Fragment GLSL\n%s\n", glsl[kFragment_GrShaderType].c_str());
518 }
joshualitt47bb3822014-10-07 16:43:25 -0700519 GrGLint infoLen = GR_GL_INIT_ZERO;
520 GL_CALL(GetProgramiv(programID, GR_GL_INFO_LOG_LENGTH, &infoLen));
521 SkAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
522 if (infoLen > 0) {
523 // retrieve length even though we don't need it to workaround
524 // bug in chrome cmd buffer param validation.
525 GrGLsizei length = GR_GL_INIT_ZERO;
Brian Osman5e7fbfd2019-05-03 13:13:35 -0400526 GL_CALL(GetProgramInfoLog(programID, infoLen+1, &length, (char*)log.get()));
joshualitt47bb3822014-10-07 16:43:25 -0700527 }
Brian Osman5e7fbfd2019-05-03 13:13:35 -0400528 errorHandler->compileError(allShaders.c_str(), infoLen > 0 ? (const char*)log.get() : "");
joshualitt47bb3822014-10-07 16:43:25 -0700529 }
530 return SkToBool(linked);
531}
532
Brian Osman2c60a382019-06-26 15:19:30 -0400533void GrGLProgramBuilder::resolveProgramResourceLocations(GrGLuint programID, bool force) {
534 fUniformHandler.getUniformLocations(programID, fGpu->glCaps(), force);
joshualittd8dd47b2015-09-11 11:45:01 -0700535
536 // handle NVPR separable varyings
537 if (!fGpu->glCaps().shaderCaps()->pathRenderingSupport() ||
kkinnunen7bdb05d2016-01-25 00:47:23 -0800538 fGpu->glPathRendering()->shouldBindFragmentInputs()) {
joshualittd8dd47b2015-09-11 11:45:01 -0700539 return;
540 }
Michael Ludwig45191342020-03-24 12:29:39 -0400541 for (auto& varying : fVaryingHandler.fPathProcVaryingInfos.items()) {
joshualittd8dd47b2015-09-11 11:45:01 -0700542 GrGLint location;
egdaniel0eafe792015-11-20 14:01:22 -0800543 GL_CALL_RET(location, GetProgramResourceLocation(
544 programID,
545 GR_GL_FRAGMENT_INPUT,
Michael Ludwig45191342020-03-24 12:29:39 -0400546 varying.fVariable.c_str()));
547 varying.fLocation = location;
joshualittd8dd47b2015-09-11 11:45:01 -0700548 }
joshualitt30ba4362014-08-21 20:18:45 -0700549}
550
Stephen Whiteb1857852020-02-07 15:33:23 +0000551sk_sp<GrGLProgram> GrGLProgramBuilder::createProgram(GrGLuint programID) {
Robert Phillipsdf546db2020-05-29 09:42:54 -0400552 return GrGLProgram::Make(fGpu,
553 fUniformHandles,
554 programID,
555 fUniformHandler.fUniforms,
556 fUniformHandler.fSamplers,
557 fVaryingHandler.fPathProcVaryingInfos,
558 std::move(fGeometryProcessor),
559 std::move(fXferProcessor),
560 std::move(fFragmentProcessors),
561 fFragmentProcessorCnt,
562 std::move(fAttributes),
563 fVertexAttributeCnt,
564 fInstanceAttributeCnt,
565 fVertexStride,
566 fInstanceStride);
joshualitt47bb3822014-10-07 16:43:25 -0700567}
Brian Osmaned58e002019-09-06 14:42:43 -0400568
569bool GrGLProgramBuilder::PrecompileProgram(GrGLPrecompiledProgram* precompiledProgram,
570 GrGLGpu* gpu,
571 const SkData& cachedData) {
Brian Osman9e4e4c72020-06-10 07:19:34 -0400572 SkReadBuffer reader(cachedData.data(), cachedData.size());
Brian Osman1facd5e2020-03-16 16:21:24 -0400573 SkFourByteTag shaderType = GrPersistentCacheUtils::GetType(&reader);
Brian Osmaned58e002019-09-06 14:42:43 -0400574 if (shaderType != kSKSL_Tag) {
575 // TODO: Support GLSL, and maybe even program binaries, too?
576 return false;
577 }
578
579 const GrGLInterface* gl = gpu->glInterface();
580 auto errorHandler = gpu->getContext()->priv().getShaderErrorHandler();
Brian Osmaned58e002019-09-06 14:42:43 -0400581
582 SkSL::Program::Settings settings;
Brian Osman4524e842019-09-24 16:03:41 -0400583 const GrGLCaps& caps = gpu->glCaps();
584 settings.fCaps = caps.shaderCaps();
Brian Osmaned58e002019-09-06 14:42:43 -0400585 settings.fSharpenTextures = gpu->getContext()->priv().options().fSharpenMipmappedTextures;
Brian Osman4524e842019-09-24 16:03:41 -0400586 GrPersistentCacheUtils::ShaderMetadata meta;
587 meta.fSettings = &settings;
Brian Osmaned58e002019-09-06 14:42:43 -0400588
589 SkSL::String shaders[kGrShaderTypeCount];
590 SkSL::Program::Inputs inputs;
Brian Osman9e4e4c72020-06-10 07:19:34 -0400591 if (!GrPersistentCacheUtils::UnpackCachedShaders(&reader, shaders, &inputs, 1, &meta)) {
592 return false;
593 }
594
595 GrGLuint programID;
596 GR_GL_CALL_RET(gl, programID, CreateProgram());
597 if (0 == programID) {
598 return false;
599 }
600
601 SkTDArray<GrGLuint> shadersToDelete;
Brian Osmaned58e002019-09-06 14:42:43 -0400602
603 auto compileShader = [&](SkSL::Program::Kind kind, const SkSL::String& sksl, GrGLenum type) {
604 SkSL::String glsl;
605 auto program = GrSkSLtoGLSL(gpu->glContext(), kind, sksl, settings, &glsl, errorHandler);
606 if (!program) {
607 return false;
608 }
609
610 if (GrGLuint shaderID = GrGLCompileAndAttachShader(gpu->glContext(), programID, type, glsl,
611 gpu->stats(), errorHandler)) {
612 shadersToDelete.push_back(shaderID);
613 return true;
614 } else {
615 return false;
616 }
617 };
618
619 if (!compileShader(SkSL::Program::kFragment_Kind,
620 shaders[kFragment_GrShaderType],
621 GR_GL_FRAGMENT_SHADER) ||
622 !compileShader(SkSL::Program::kVertex_Kind,
623 shaders[kVertex_GrShaderType],
624 GR_GL_VERTEX_SHADER) ||
625 (!shaders[kGeometry_GrShaderType].empty() &&
626 !compileShader(SkSL::Program::kGeometry_Kind,
627 shaders[kGeometry_GrShaderType],
628 GR_GL_GEOMETRY_SHADER))) {
629 cleanup_program(gpu, programID, shadersToDelete);
630 return false;
631 }
632
Brian Osman4524e842019-09-24 16:03:41 -0400633 for (int i = 0; i < meta.fAttributeNames.count(); ++i) {
634 GR_GL_CALL(gpu->glInterface(), BindAttribLocation(programID, i,
635 meta.fAttributeNames[i].c_str()));
636 }
637
638 if (meta.fHasCustomColorOutput && caps.bindFragDataLocationSupport()) {
639 GR_GL_CALL(gpu->glInterface(), BindFragDataLocation(programID, 0,
640 GrGLSLFragmentShaderBuilder::DeclaredColorOutputName()));
641 }
642 if (meta.fHasSecondaryColorOutput && caps.shaderCaps()->mustDeclareFragmentShaderOutput()) {
643 GR_GL_CALL(gpu->glInterface(), BindFragDataLocationIndexed(programID, 0, 1,
644 GrGLSLFragmentShaderBuilder::DeclaredSecondaryColorOutputName()));
645 }
646
Brian Osmaned58e002019-09-06 14:42:43 -0400647 GR_GL_CALL(gpu->glInterface(), LinkProgram(programID));
648 GrGLint linked = GR_GL_INIT_ZERO;
649 GR_GL_CALL(gpu->glInterface(), GetProgramiv(programID, GR_GL_LINK_STATUS, &linked));
650 if (!linked) {
651 cleanup_program(gpu, programID, shadersToDelete);
652 return false;
653 }
654
655 cleanup_shaders(gpu, shadersToDelete);
656
657 precompiledProgram->fProgramID = programID;
658 precompiledProgram->fInputs = inputs;
659 return true;
660}