blob: 98b6a882ee7018e959a031b52bbb61ff820fd401 [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"
13#include "src/core/SkReader32.h"
14#include "src/core/SkTraceEvent.h"
15#include "src/core/SkWriter32.h"
16#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
Robert Phillipsd0fe8752019-01-31 14:13:59 -050048GrGLProgram* GrGLProgramBuilder::CreateProgram(GrRenderTarget* renderTarget, GrSurfaceOrigin origin,
49 const GrPrimitiveProcessor& primProc,
Greg Daniel9a51a862018-11-30 10:18:14 -050050 const GrTextureProxy* const primProcProxies[],
Brian Salomonff168d92018-06-23 15:17:27 -040051 const GrPipeline& pipeline,
Ethan Nicholas38657112017-02-09 17:01:22 -050052 GrProgramDesc* desc,
Brian Osmaned58e002019-09-06 14:42:43 -040053 GrGLGpu* gpu,
54 const GrGLPrecompiledProgram* precompiledProgram) {
Brian Salomon7eae3e02018-08-07 14:02:38 +000055 SkASSERT(!pipeline.isBad());
Robert Phillipsa91e0b72017-05-01 13:12:20 -040056
Derek Sollenberger488f0d62017-03-03 15:48:33 -050057 ATRACE_ANDROID_FRAMEWORK("Shader Compile");
bsalomon3318ee72015-03-16 11:56:29 -070058 GrAutoLocaleSetter als("C");
59
joshualitt47bb3822014-10-07 16:43:25 -070060 // create a builder. This will be handed off to effects so they can use it to add
61 // uniforms, varyings, textures, etc
Robert Phillipsd0fe8752019-01-31 14:13:59 -050062 GrGLProgramBuilder builder(gpu, renderTarget, origin,
63 pipeline, primProc, primProcProxies, desc);
joshualitt47bb3822014-10-07 16:43:25 -070064
Robert Phillips9da87e02019-02-04 13:26:26 -050065 auto persistentCache = gpu->getContext()->priv().getPersistentCache();
Brian Osmaned58e002019-09-06 14:42:43 -040066 if (persistentCache && !precompiledProgram) {
Ethan Nicholasd1b2eec2017-11-01 15:45:43 -040067 sk_sp<SkData> key = SkData::MakeWithoutCopy(desc->asKey(), desc->keyLength());
Robert Phillips0c4b7b12018-03-06 08:20:37 -050068 builder.fCached = persistentCache->load(*key);
Ethan Nicholasd1b2eec2017-11-01 15:45:43 -040069 // the eventual end goal is to completely skip emitAndInstallProcs on a cache hit, but it's
70 // doing necessary setup in addition to generating the SkSL code. Currently we are only able
71 // to skip the SkSL->GLSL step on a cache hit.
72 }
Ethan Nicholas2983f402017-05-08 09:36:08 -040073 if (!builder.emitAndInstallProcs()) {
halcanary96fcdcc2015-08-27 07:41:13 -070074 return nullptr;
joshualitt6c891102015-05-13 08:51:49 -070075 }
Brian Osmaned58e002019-09-06 14:42:43 -040076 return builder.finalize(precompiledProgram);
joshualitt47bb3822014-10-07 16:43:25 -070077}
78
joshualitt47bb3822014-10-07 16:43:25 -070079/////////////////////////////////////////////////////////////////////////////
80
egdaniel0e1853c2016-03-17 11:35:45 -070081GrGLProgramBuilder::GrGLProgramBuilder(GrGLGpu* gpu,
Robert Phillipsd0fe8752019-01-31 14:13:59 -050082 GrRenderTarget* renderTarget,
83 GrSurfaceOrigin origin,
egdaniel0e1853c2016-03-17 11:35:45 -070084 const GrPipeline& pipeline,
85 const GrPrimitiveProcessor& primProc,
Greg Daniel9a51a862018-11-30 10:18:14 -050086 const GrTextureProxy* const primProcProxies[],
Ethan Nicholas38657112017-02-09 17:01:22 -050087 GrProgramDesc* desc)
Robert Phillipsd0fe8752019-01-31 14:13:59 -050088 : INHERITED(renderTarget, origin, primProc, primProcProxies, pipeline, desc)
Brian Salomon802cb312018-06-08 18:05:20 -040089 , fGpu(gpu)
90 , fVaryingHandler(this)
91 , fUniformHandler(this)
Brian Salomon92be2f72018-06-19 14:33:47 -040092 , fVertexAttributeCnt(0)
93 , fInstanceAttributeCnt(0)
Brian Salomon802cb312018-06-08 18:05:20 -040094 , fVertexStride(0)
95 , fInstanceStride(0) {}
joshualitt30ba4362014-08-21 20:18:45 -070096
egdanielfa896322016-01-13 12:19:30 -080097const GrCaps* GrGLProgramBuilder::caps() const {
98 return fGpu->caps();
99}
100
Brian Osmanac9be9d2019-05-01 10:29:34 -0400101bool GrGLProgramBuilder::compileAndAttachShaders(const SkSL::String& glsl,
egdaniel574a4c12015-11-02 06:22:44 -0800102 GrGLuint programId,
103 GrGLenum type,
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500104 SkTDArray<GrGLuint>* shaderIds,
Brian Osman5e7fbfd2019-05-03 13:13:35 -0400105 GrContextOptions::ShaderErrorHandler* errHandler) {
egdaniel574a4c12015-11-02 06:22:44 -0800106 GrGLGpu* gpu = this->gpu();
107 GrGLuint shaderId = GrGLCompileAndAttachShader(gpu->glContext(),
108 programId,
109 type,
Ethan Nicholasd1b2eec2017-11-01 15:45:43 -0400110 glsl,
Brian Osman8518f2e2019-05-01 14:13:41 -0400111 gpu->stats(),
Brian Osman5e7fbfd2019-05-03 13:13:35 -0400112 errHandler);
egdaniel574a4c12015-11-02 06:22:44 -0800113 if (!shaderId) {
114 return false;
115 }
116
117 *shaderIds->append() = shaderId;
egdaniel574a4c12015-11-02 06:22:44 -0800118 return true;
119}
120
Ethan Nicholasad77dce2018-07-11 13:59:03 -0400121void GrGLProgramBuilder::computeCountsAndStrides(GrGLuint programID,
122 const GrPrimitiveProcessor& primProc,
123 bool bindAttribLocations) {
124 fVertexAttributeCnt = primProc.numVertexAttributes();
125 fInstanceAttributeCnt = primProc.numInstanceAttributes();
126 fAttributes.reset(
127 new GrGLProgram::Attribute[fVertexAttributeCnt + fInstanceAttributeCnt]);
128 auto addAttr = [&](int i, const auto& a, size_t* stride) {
Brian Osman4a3f5c82018-09-18 16:16:38 -0400129 fAttributes[i].fCPUType = a.cpuType();
130 fAttributes[i].fGPUType = a.gpuType();
Ethan Nicholasad77dce2018-07-11 13:59:03 -0400131 fAttributes[i].fOffset = *stride;
132 *stride += a.sizeAlign4();
133 fAttributes[i].fLocation = i;
134 if (bindAttribLocations) {
135 GL_CALL(BindAttribLocation(programID, i, a.name()));
136 }
137 };
138 fVertexStride = 0;
139 int i = 0;
Brian Osmanf04fb3c2018-11-12 15:34:00 -0500140 for (const auto& attr : primProc.vertexAttributes()) {
141 addAttr(i++, attr, &fVertexStride);
Ethan Nicholasad77dce2018-07-11 13:59:03 -0400142 }
Brian Osmanf04fb3c2018-11-12 15:34:00 -0500143 SkASSERT(fVertexStride == primProc.vertexStride());
Ethan Nicholasad77dce2018-07-11 13:59:03 -0400144 fInstanceStride = 0;
Brian Osmanf04fb3c2018-11-12 15:34:00 -0500145 for (const auto& attr : primProc.instanceAttributes()) {
146 addAttr(i++, attr, &fInstanceStride);
Ethan Nicholasad77dce2018-07-11 13:59:03 -0400147 }
Brian Osmanf04fb3c2018-11-12 15:34:00 -0500148 SkASSERT(fInstanceStride == primProc.instanceStride());
Ethan Nicholasad77dce2018-07-11 13:59:03 -0400149}
150
Ethan Nicholascd700e92018-08-24 16:43:57 -0400151void GrGLProgramBuilder::addInputVars(const SkSL::Program::Inputs& inputs) {
152 if (inputs.fRTWidth) {
153 this->addRTWidthUniform(SKSL_RTWIDTH_NAME);
154 }
155 if (inputs.fRTHeight) {
156 this->addRTHeightUniform(SKSL_RTHEIGHT_NAME);
157 }
158}
159
Brian Osmana085a412019-04-25 09:44:43 -0400160static constexpr SkFourByteTag kSKSL_Tag = SkSetFourByteTag('S', 'K', 'S', 'L');
161static constexpr SkFourByteTag kGLSL_Tag = SkSetFourByteTag('G', 'L', 'S', 'L');
Brian Osmana66081d2019-09-03 14:59:26 -0400162static constexpr SkFourByteTag kGLPB_Tag = SkSetFourByteTag('G', 'L', 'P', 'B');
Brian Osmana085a412019-04-25 09:44:43 -0400163
Ethan Nicholas8d058832019-01-07 10:49:58 -0500164void GrGLProgramBuilder::storeShaderInCache(const SkSL::Program::Inputs& inputs, GrGLuint programID,
Brian Osmaned58e002019-09-06 14:42:43 -0400165 const SkSL::String shaders[], bool isSkSL,
166 const SkSL::Program::Settings& settings) {
Robert Phillips9da87e02019-02-04 13:26:26 -0500167 if (!this->gpu()->getContext()->priv().getPersistentCache()) {
Ethan Nicholas8d058832019-01-07 10:49:58 -0500168 return;
169 }
170 sk_sp<SkData> key = SkData::MakeWithoutCopy(desc()->asKey(), desc()->keyLength());
171 if (fGpu->glCaps().programBinarySupport()) {
172 // binary cache
173 GrGLsizei length = 0;
174 GL_CALL(GetProgramiv(programID, GL_PROGRAM_BINARY_LENGTH, &length));
175 if (length > 0) {
Brian Osman6b797fe2019-04-08 13:56:36 -0400176 SkWriter32 writer;
Brian Osmana66081d2019-09-03 14:59:26 -0400177 writer.write32(kGLPB_Tag);
178
Brian Osman6b797fe2019-04-08 13:56:36 -0400179 writer.writePad(&inputs, sizeof(inputs));
180 writer.write32(length);
181
182 void* binary = writer.reservePad(length);
Ethan Nicholas8d058832019-01-07 10:49:58 -0500183 GrGLenum binaryFormat;
Brian Osman6b797fe2019-04-08 13:56:36 -0400184 GL_CALL(GetProgramBinary(programID, length, &length, &binaryFormat, binary));
185 writer.write32(binaryFormat);
186
187 auto data = writer.snapshotAsData();
188 this->gpu()->getContext()->priv().getPersistentCache()->store(*key, *data);
Ethan Nicholas8d058832019-01-07 10:49:58 -0500189 }
190 } else {
191 // source cache
Brian Osmana085a412019-04-25 09:44:43 -0400192 auto data = GrPersistentCacheUtils::PackCachedShaders(isSkSL ? kSKSL_Tag : kGLSL_Tag,
Brian Osmaned58e002019-09-06 14:42:43 -0400193 shaders, &inputs, 1, &settings);
Brian Osman6b797fe2019-04-08 13:56:36 -0400194 this->gpu()->getContext()->priv().getPersistentCache()->store(*key, *data);
Ethan Nicholas8d058832019-01-07 10:49:58 -0500195 }
196}
197
Brian Osmaned58e002019-09-06 14:42:43 -0400198GrGLProgram* GrGLProgramBuilder::finalize(const GrGLPrecompiledProgram* precompiledProgram) {
Brian Salomon5f394272019-07-02 14:07:49 -0400199 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
Ryan Macnak38a10ad2017-07-10 10:36:34 -0700200
joshualitt47bb3822014-10-07 16:43:25 -0700201 // verify we can get a program id
202 GrGLuint programID;
Brian Osmaned58e002019-09-06 14:42:43 -0400203 if (precompiledProgram) {
204 programID = precompiledProgram->fProgramID;
205 } else {
206 GL_CALL_RET(programID, CreateProgram());
207 }
joshualitt47bb3822014-10-07 16:43:25 -0700208 if (0 == programID) {
halcanary96fcdcc2015-08-27 07:41:13 -0700209 return nullptr;
joshualitt30ba4362014-08-21 20:18:45 -0700210 }
211
Ethan Nicholas06d55fb2017-11-08 09:48:50 -0500212 if (this->gpu()->glCaps().programBinarySupport() &&
Brian Osman064729e2019-06-18 17:22:59 -0400213 this->gpu()->glCaps().programParameterSupport() &&
Brian Osmaned58e002019-09-06 14:42:43 -0400214 this->gpu()->getContext()->priv().getPersistentCache() &&
215 !precompiledProgram) {
Ethan Nicholasd1b2eec2017-11-01 15:45:43 -0400216 GL_CALL(ProgramParameteri(programID, GR_GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GR_GL_TRUE));
217 }
218
egdaniel9f1d4152016-02-10 09:50:38 -0800219 this->finalizeShaders();
220
joshualitt47bb3822014-10-07 16:43:25 -0700221 // compile shaders and bind attributes / uniforms
Brian Osman5e7fbfd2019-05-03 13:13:35 -0400222 auto errorHandler = this->gpu()->getContext()->priv().getShaderErrorHandler();
Ethan Nicholasd1b2eec2017-11-01 15:45:43 -0400223 const GrPrimitiveProcessor& primProc = this->primitiveProcessor();
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500224 SkSL::Program::Settings settings;
225 settings.fCaps = this->gpu()->glCaps().shaderCaps();
Robert Phillipsd0fe8752019-01-31 14:13:59 -0500226 settings.fFlipY = this->origin() != kTopLeft_GrSurfaceOrigin;
Robert Phillipsc1541ae2019-02-04 12:05:37 -0500227 settings.fSharpenTextures =
Robert Phillips9da87e02019-02-04 13:26:26 -0500228 this->gpu()->getContext()->priv().options().fSharpenMipmappedTextures;
Brian Salomondc092132018-04-04 10:14:16 -0400229 settings.fFragColorIsInOut = this->fragColorIsInOut();
230
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500231 SkSL::Program::Inputs inputs;
joshualitt30ba4362014-08-21 20:18:45 -0700232 SkTDArray<GrGLuint> shadersToDelete;
Ethan Nicholas5a0338c2019-01-02 11:48:56 -0500233 // Calling GetProgramiv is expensive in Chromium. Assume success in release builds.
234 bool checkLinked = kChromium_GrGLDriver != fGpu->ctxInfo().driver();
235#ifdef SK_DEBUG
236 checkLinked = true;
237#endif
Ethan Nicholas8d058832019-01-07 10:49:58 -0500238 bool cached = fCached.get() != nullptr;
Brian Osman2c60a382019-06-26 15:19:30 -0400239 bool usedProgramBinaries = false;
Brian Osman6b797fe2019-04-08 13:56:36 -0400240 SkSL::String glsl[kGrShaderTypeCount];
Brian Osmancbc33b82019-04-19 14:16:19 -0400241 SkSL::String* sksl[kGrShaderTypeCount] = {
242 &fVS.fCompilerString,
243 &fGS.fCompilerString,
244 &fFS.fCompilerString,
245 };
Brian Osmancbc33b82019-04-19 14:16:19 -0400246 SkSL::String cached_sksl[kGrShaderTypeCount];
Brian Osmaned58e002019-09-06 14:42:43 -0400247 if (precompiledProgram) {
248 // This is very similar to when we get program binaries. We even set that flag, as it's
249 // used to prevent other compile work later, and to force re-querying uniform locations.
250 this->addInputVars(precompiledProgram->fInputs);
251 this->computeCountsAndStrides(programID, primProc, false);
252 usedProgramBinaries = true;
253 } else if (cached) {
Brian Osmana66081d2019-09-03 14:59:26 -0400254 SkReader32 reader(fCached->data(), fCached->size());
255 SkFourByteTag shaderType = reader.readU32();
256
257 switch (shaderType) {
258 case kGLPB_Tag: {
259 // Program binary cache hit. We may opt not to use this if we don't trust program
260 // binaries on this driver
261 if (!fGpu->glCaps().programBinarySupport()) {
262 cached = false;
263 break;
Ethan Nicholas8d058832019-01-07 10:49:58 -0500264 }
Brian Osmana66081d2019-09-03 14:59:26 -0400265 reader.read(&inputs, sizeof(inputs));
266 GrGLsizei length = reader.readInt();
267 const void* binary = reader.skip(length);
268 GrGLenum binaryFormat = reader.readU32();
269 GrGLClearErr(this->gpu()->glInterface());
270 GR_GL_CALL_NOERRCHECK(this->gpu()->glInterface(),
271 ProgramBinary(programID, binaryFormat,
272 const_cast<void*>(binary), length));
273 if (GR_GL_GET_ERROR(this->gpu()->glInterface()) == GR_GL_NO_ERROR) {
274 if (checkLinked) {
275 cached = this->checkLinkStatus(programID, errorHandler, nullptr, nullptr);
276 }
277 if (cached) {
278 this->addInputVars(inputs);
279 this->computeCountsAndStrides(programID, primProc, false);
280 }
281 } else {
282 cached = false;
Ethan Nicholas8d058832019-01-07 10:49:58 -0500283 }
Brian Osmana66081d2019-09-03 14:59:26 -0400284 usedProgramBinaries = cached;
285 break;
Ethan Nicholasad77dce2018-07-11 13:59:03 -0400286 }
Brian Osmana66081d2019-09-03 14:59:26 -0400287
288 case kGLSL_Tag:
289 // Source cache hit, we don't need to compile the SkSL->GLSL
290 GrPersistentCacheUtils::UnpackCachedShaders(&reader, glsl, &inputs, 1);
291 break;
292
293 case kSKSL_Tag:
294 // SkSL cache hit, this should only happen in tools overriding the generated SkSL
295 GrPersistentCacheUtils::UnpackCachedShaders(&reader, cached_sksl, &inputs, 1);
Brian Osmana085a412019-04-25 09:44:43 -0400296 for (int i = 0; i < kGrShaderTypeCount; ++i) {
297 sksl[i] = &cached_sksl[i];
298 }
Brian Osmana66081d2019-09-03 14:59:26 -0400299 break;
Ethan Nicholas98ad5b72018-03-13 09:53:02 -0400300 }
301 }
Brian Osmana66081d2019-09-03 14:59:26 -0400302 if (!usedProgramBinaries) {
303 // either a cache miss, or we got something other than binaries from the cache
Brian Osman6b797fe2019-04-08 13:56:36 -0400304 if (glsl[kFragment_GrShaderType].empty()) {
Brian Osmanf71b0702019-04-03 13:04:16 -0400305 // Don't have cached GLSL, need to compile SkSL->GLSL
Ethan Nicholas8d058832019-01-07 10:49:58 -0500306 if (fFS.fForceHighPrecision) {
307 settings.fForceHighPrecision = true;
308 }
309 std::unique_ptr<SkSL::Program> fs = GrSkSLtoGLSL(gpu()->glContext(),
Brian Osmanac9be9d2019-05-01 10:29:34 -0400310 SkSL::Program::kFragment_Kind,
Brian Osmancbc33b82019-04-19 14:16:19 -0400311 *sksl[kFragment_GrShaderType],
Ethan Nicholas8d058832019-01-07 10:49:58 -0500312 settings,
Brian Osman5e7fbfd2019-05-03 13:13:35 -0400313 &glsl[kFragment_GrShaderType],
314 errorHandler);
Ethan Nicholas8d058832019-01-07 10:49:58 -0500315 if (!fs) {
Brian Osmaned58e002019-09-06 14:42:43 -0400316 cleanup_program(fGpu, programID, shadersToDelete);
Ethan Nicholas8d058832019-01-07 10:49:58 -0500317 return nullptr;
318 }
319 inputs = fs->fInputs;
Brian Osmanf71b0702019-04-03 13:04:16 -0400320 this->addInputVars(inputs);
Ethan Nicholas8d058832019-01-07 10:49:58 -0500321 } else {
322 // we've pulled GLSL and inputs from the cache, but still need to do some setup
323 this->addInputVars(inputs);
324 this->computeCountsAndStrides(programID, primProc, false);
egdaniel8dcdedc2015-11-11 06:27:20 -0800325 }
Brian Osmanac9be9d2019-05-01 10:29:34 -0400326 if (!this->compileAndAttachShaders(glsl[kFragment_GrShaderType], programID,
Brian Osmane11dfd32019-07-23 10:29:41 -0400327 GR_GL_FRAGMENT_SHADER, &shadersToDelete, errorHandler)) {
Brian Osmaned58e002019-09-06 14:42:43 -0400328 cleanup_program(fGpu, programID, shadersToDelete);
Ethan Nicholasd1b2eec2017-11-01 15:45:43 -0400329 return nullptr;
330 }
331
Brian Osman6b797fe2019-04-08 13:56:36 -0400332 if (glsl[kVertex_GrShaderType].empty()) {
Brian Osmanf71b0702019-04-03 13:04:16 -0400333 // Don't have cached GLSL, need to compile SkSL->GLSL
334 std::unique_ptr<SkSL::Program> vs = GrSkSLtoGLSL(gpu()->glContext(),
Brian Osmanac9be9d2019-05-01 10:29:34 -0400335 SkSL::Program::kVertex_Kind,
Brian Osmancbc33b82019-04-19 14:16:19 -0400336 *sksl[kVertex_GrShaderType],
Brian Osmanf71b0702019-04-03 13:04:16 -0400337 settings,
Brian Osman5e7fbfd2019-05-03 13:13:35 -0400338 &glsl[kVertex_GrShaderType],
339 errorHandler);
Brian Osmanf71b0702019-04-03 13:04:16 -0400340 if (!vs) {
Brian Osmaned58e002019-09-06 14:42:43 -0400341 cleanup_program(fGpu, programID, shadersToDelete);
Brian Osmanf71b0702019-04-03 13:04:16 -0400342 return nullptr;
343 }
344 }
Brian Osmanac9be9d2019-05-01 10:29:34 -0400345 if (!this->compileAndAttachShaders(glsl[kVertex_GrShaderType], programID,
Brian Osmane11dfd32019-07-23 10:29:41 -0400346 GR_GL_VERTEX_SHADER, &shadersToDelete, errorHandler)) {
Brian Osmaned58e002019-09-06 14:42:43 -0400347 cleanup_program(fGpu, programID, shadersToDelete);
Ethan Nicholasd1b2eec2017-11-01 15:45:43 -0400348 return nullptr;
349 }
350
351 // NVPR actually requires a vertex shader to compile
352 bool useNvpr = primProc.isPathRendering();
353 if (!useNvpr) {
Ethan Nicholasad77dce2018-07-11 13:59:03 -0400354 this->computeCountsAndStrides(programID, primProc, true);
Ethan Nicholasd1b2eec2017-11-01 15:45:43 -0400355 }
356
357 if (primProc.willUseGeoShader()) {
Brian Osman6b797fe2019-04-08 13:56:36 -0400358 if (glsl[kGeometry_GrShaderType].empty()) {
Brian Osmanf71b0702019-04-03 13:04:16 -0400359 // Don't have cached GLSL, need to compile SkSL->GLSL
360 std::unique_ptr<SkSL::Program> gs;
361 gs = GrSkSLtoGLSL(gpu()->glContext(),
Brian Osmanac9be9d2019-05-01 10:29:34 -0400362 SkSL::Program::kGeometry_Kind,
Brian Osmancbc33b82019-04-19 14:16:19 -0400363 *sksl[kGeometry_GrShaderType],
Brian Osmanf71b0702019-04-03 13:04:16 -0400364 settings,
Brian Osman5e7fbfd2019-05-03 13:13:35 -0400365 &glsl[kGeometry_GrShaderType],
366 errorHandler);
Brian Osmanf71b0702019-04-03 13:04:16 -0400367 if (!gs) {
Brian Osmaned58e002019-09-06 14:42:43 -0400368 cleanup_program(fGpu, programID, shadersToDelete);
Brian Osmanf71b0702019-04-03 13:04:16 -0400369 return nullptr;
370 }
371 }
Brian Osmanac9be9d2019-05-01 10:29:34 -0400372 if (!this->compileAndAttachShaders(glsl[kGeometry_GrShaderType], programID,
Brian Osmane11dfd32019-07-23 10:29:41 -0400373 GR_GL_GEOMETRY_SHADER, &shadersToDelete,
Brian Osman5e7fbfd2019-05-03 13:13:35 -0400374 errorHandler)) {
Brian Osmaned58e002019-09-06 14:42:43 -0400375 cleanup_program(fGpu, programID, shadersToDelete);
Ethan Nicholasd1b2eec2017-11-01 15:45:43 -0400376 return nullptr;
377 }
Ethan Nicholasd1b2eec2017-11-01 15:45:43 -0400378 }
379 this->bindProgramResourceLocations(programID);
380
381 GL_CALL(LinkProgram(programID));
Ethan Nicholas5a0338c2019-01-02 11:48:56 -0500382 if (checkLinked) {
Brian Osman5e7fbfd2019-05-03 13:13:35 -0400383 if (!this->checkLinkStatus(programID, errorHandler, sksl, glsl)) {
Ethan Nicholas5a0338c2019-01-02 11:48:56 -0500384 GL_CALL(DeleteProgram(programID));
Ethan Nicholas5a0338c2019-01-02 11:48:56 -0500385 return nullptr;
Brian Salomone334c592017-05-15 11:00:58 -0400386 }
Brian Salomone334c592017-05-15 11:00:58 -0400387 }
joshualittfe1233c2014-10-07 12:16:35 -0700388 }
Brian Osman2c60a382019-06-26 15:19:30 -0400389 this->resolveProgramResourceLocations(programID, usedProgramBinaries);
joshualittdb0d3ca2014-10-07 12:42:26 -0700390
Brian Osmaned58e002019-09-06 14:42:43 -0400391 cleanup_shaders(fGpu, shadersToDelete);
Brian Osmane4c88bb2019-06-27 16:15:11 -0400392
393 // With ANGLE, we can't cache path-rendering programs. We use ProgramPathFragmentInputGen,
394 // and ANGLE's deserialized program state doesn't restore enough state to handle that.
395 // The native NVIDIA drivers do, but this is such an edge case that it's easier to just
396 // black-list caching these programs in all cases. See: anglebug.com/3619
Brian Osmaned58e002019-09-06 14:42:43 -0400397 // We also can't cache SkSL or GLSL if we were given a precompiled program, but there's not
398 // much point in doing so.
399 if (!cached && !primProc.isPathRendering() && !precompiledProgram) {
Brian Osmana085a412019-04-25 09:44:43 -0400400 bool isSkSL = false;
Brian Osmana66081d2019-09-03 14:59:26 -0400401 if (fGpu->getContext()->priv().options().fShaderCacheStrategy ==
402 GrContextOptions::ShaderCacheStrategy::kSkSL) {
Brian Osmancbc33b82019-04-19 14:16:19 -0400403 for (int i = 0; i < kGrShaderTypeCount; ++i) {
Brian Osmanac9be9d2019-05-01 10:29:34 -0400404 glsl[i] = GrShaderUtils::PrettyPrint(*sksl[i]);
Brian Osmancbc33b82019-04-19 14:16:19 -0400405 }
Brian Osmana085a412019-04-25 09:44:43 -0400406 isSkSL = true;
Brian Osmancbc33b82019-04-19 14:16:19 -0400407 }
Brian Osmaned58e002019-09-06 14:42:43 -0400408 this->storeShaderInCache(inputs, programID, glsl, isSkSL, settings);
Ethan Nicholasd1b2eec2017-11-01 15:45:43 -0400409 }
joshualitt47bb3822014-10-07 16:43:25 -0700410 return this->createProgram(programID);
411}
412
kkinnunen7aedda52015-06-29 23:01:28 -0700413void GrGLProgramBuilder::bindProgramResourceLocations(GrGLuint programID) {
egdaniel7ea439b2015-12-03 09:20:44 -0800414 fUniformHandler.bindUniformLocations(programID, fGpu->glCaps());
kkinnunen7aedda52015-06-29 23:01:28 -0700415
egdaniel8dcdedc2015-11-11 06:27:20 -0800416 const GrGLCaps& caps = this->gpu()->glCaps();
417 if (fFS.hasCustomColorOutput() && caps.bindFragDataLocationSupport()) {
418 GL_CALL(BindFragDataLocation(programID, 0,
egdaniel2d721d32015-11-11 13:06:05 -0800419 GrGLSLFragmentShaderBuilder::DeclaredColorOutputName()));
egdaniel8dcdedc2015-11-11 06:27:20 -0800420 }
Brian Salomon1edc5b92016-11-29 13:43:46 -0500421 if (fFS.hasSecondaryOutput() && caps.shaderCaps()->mustDeclareFragmentShaderOutput()) {
egdaniel8dcdedc2015-11-11 06:27:20 -0800422 GL_CALL(BindFragDataLocationIndexed(programID, 0, 1,
egdaniel2d721d32015-11-11 13:06:05 -0800423 GrGLSLFragmentShaderBuilder::DeclaredSecondaryColorOutputName()));
egdaniel8dcdedc2015-11-11 06:27:20 -0800424 }
joshualittd8dd47b2015-09-11 11:45:01 -0700425
426 // handle NVPR separable varyings
427 if (!fGpu->glCaps().shaderCaps()->pathRenderingSupport() ||
428 !fGpu->glPathRendering()->shouldBindFragmentInputs()) {
429 return;
430 }
egdaniel0eafe792015-11-20 14:01:22 -0800431 int count = fVaryingHandler.fPathProcVaryingInfos.count();
joshualittd8dd47b2015-09-11 11:45:01 -0700432 for (int i = 0; i < count; ++i) {
egdaniel0eafe792015-11-20 14:01:22 -0800433 GL_CALL(BindFragmentInputLocation(programID, i,
434 fVaryingHandler.fPathProcVaryingInfos[i].fVariable.c_str()));
435 fVaryingHandler.fPathProcVaryingInfos[i].fLocation = i;
joshualittd8dd47b2015-09-11 11:45:01 -0700436 }
joshualitt47bb3822014-10-07 16:43:25 -0700437}
438
Brian Osman5e7fbfd2019-05-03 13:13:35 -0400439bool GrGLProgramBuilder::checkLinkStatus(GrGLuint programID,
440 GrContextOptions::ShaderErrorHandler* errorHandler,
441 SkSL::String* sksl[], const SkSL::String glsl[]) {
joshualitt47bb3822014-10-07 16:43:25 -0700442 GrGLint linked = GR_GL_INIT_ZERO;
443 GL_CALL(GetProgramiv(programID, GR_GL_LINK_STATUS, &linked));
444 if (!linked) {
Brian Osman5e7fbfd2019-05-03 13:13:35 -0400445 SkSL::String allShaders;
446 if (sksl) {
447 allShaders.appendf("// Vertex SKSL\n%s\n", sksl[kVertex_GrShaderType]->c_str());
448 if (!sksl[kGeometry_GrShaderType]->empty()) {
449 allShaders.appendf("// Geometry SKSL\n%s\n", sksl[kGeometry_GrShaderType]->c_str());
450 }
451 allShaders.appendf("// Fragment SKSL\n%s\n", sksl[kFragment_GrShaderType]->c_str());
452 }
453 if (glsl) {
454 allShaders.appendf("// Vertex GLSL\n%s\n", glsl[kVertex_GrShaderType].c_str());
455 if (!glsl[kGeometry_GrShaderType].empty()) {
456 allShaders.appendf("// Geometry GLSL\n%s\n", glsl[kGeometry_GrShaderType].c_str());
457 }
458 allShaders.appendf("// Fragment GLSL\n%s\n", glsl[kFragment_GrShaderType].c_str());
459 }
joshualitt47bb3822014-10-07 16:43:25 -0700460 GrGLint infoLen = GR_GL_INIT_ZERO;
461 GL_CALL(GetProgramiv(programID, GR_GL_INFO_LOG_LENGTH, &infoLen));
462 SkAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
463 if (infoLen > 0) {
464 // retrieve length even though we don't need it to workaround
465 // bug in chrome cmd buffer param validation.
466 GrGLsizei length = GR_GL_INIT_ZERO;
Brian Osman5e7fbfd2019-05-03 13:13:35 -0400467 GL_CALL(GetProgramInfoLog(programID, infoLen+1, &length, (char*)log.get()));
joshualitt47bb3822014-10-07 16:43:25 -0700468 }
Brian Osman5e7fbfd2019-05-03 13:13:35 -0400469 errorHandler->compileError(allShaders.c_str(), infoLen > 0 ? (const char*)log.get() : "");
joshualitt47bb3822014-10-07 16:43:25 -0700470 }
471 return SkToBool(linked);
472}
473
Brian Osman2c60a382019-06-26 15:19:30 -0400474void GrGLProgramBuilder::resolveProgramResourceLocations(GrGLuint programID, bool force) {
475 fUniformHandler.getUniformLocations(programID, fGpu->glCaps(), force);
joshualittd8dd47b2015-09-11 11:45:01 -0700476
477 // handle NVPR separable varyings
478 if (!fGpu->glCaps().shaderCaps()->pathRenderingSupport() ||
kkinnunen7bdb05d2016-01-25 00:47:23 -0800479 fGpu->glPathRendering()->shouldBindFragmentInputs()) {
joshualittd8dd47b2015-09-11 11:45:01 -0700480 return;
481 }
egdaniel0eafe792015-11-20 14:01:22 -0800482 int count = fVaryingHandler.fPathProcVaryingInfos.count();
joshualittd8dd47b2015-09-11 11:45:01 -0700483 for (int i = 0; i < count; ++i) {
484 GrGLint location;
egdaniel0eafe792015-11-20 14:01:22 -0800485 GL_CALL_RET(location, GetProgramResourceLocation(
486 programID,
487 GR_GL_FRAGMENT_INPUT,
488 fVaryingHandler.fPathProcVaryingInfos[i].fVariable.c_str()));
489 fVaryingHandler.fPathProcVaryingInfos[i].fLocation = location;
joshualittd8dd47b2015-09-11 11:45:01 -0700490 }
joshualitt30ba4362014-08-21 20:18:45 -0700491}
492
joshualitt47bb3822014-10-07 16:43:25 -0700493GrGLProgram* GrGLProgramBuilder::createProgram(GrGLuint programID) {
egdaniel7ea439b2015-12-03 09:20:44 -0800494 return new GrGLProgram(fGpu,
egdaniel7ea439b2015-12-03 09:20:44 -0800495 fUniformHandles,
496 programID,
497 fUniformHandler.fUniforms,
egdaniel09aa1fc2016-04-20 07:09:46 -0700498 fUniformHandler.fSamplers,
egdaniel0eafe792015-11-20 14:01:22 -0800499 fVaryingHandler.fPathProcVaryingInfos,
Robert Phillips369e8b72017-08-01 16:13:04 -0400500 std::move(fGeometryProcessor),
501 std::move(fXferProcessor),
Brian Salomon4d3f5172018-06-07 14:42:52 -0400502 std::move(fFragmentProcessors),
Brian Salomon802cb312018-06-08 18:05:20 -0400503 fFragmentProcessorCnt,
504 std::move(fAttributes),
Brian Salomon92be2f72018-06-19 14:33:47 -0400505 fVertexAttributeCnt,
506 fInstanceAttributeCnt,
Brian Salomon802cb312018-06-08 18:05:20 -0400507 fVertexStride,
508 fInstanceStride);
joshualitt47bb3822014-10-07 16:43:25 -0700509}
Brian Osmaned58e002019-09-06 14:42:43 -0400510
511bool GrGLProgramBuilder::PrecompileProgram(GrGLPrecompiledProgram* precompiledProgram,
512 GrGLGpu* gpu,
513 const SkData& cachedData) {
514 SkReader32 reader(cachedData.data(), cachedData.size());
515 SkFourByteTag shaderType = reader.readU32();
516 if (shaderType != kSKSL_Tag) {
517 // TODO: Support GLSL, and maybe even program binaries, too?
518 return false;
519 }
520
521 const GrGLInterface* gl = gpu->glInterface();
522 auto errorHandler = gpu->getContext()->priv().getShaderErrorHandler();
523 GrGLuint programID;
524 GR_GL_CALL_RET(gl, programID, CreateProgram());
525 if (0 == programID) {
526 return false;
527 }
528
529 SkTDArray<GrGLuint> shadersToDelete;
530
531 SkSL::Program::Settings settings;
532 settings.fCaps = gpu->glCaps().shaderCaps();
533 settings.fSharpenTextures = gpu->getContext()->priv().options().fSharpenMipmappedTextures;
534
535 SkSL::String shaders[kGrShaderTypeCount];
536 SkSL::Program::Inputs inputs;
537 GrPersistentCacheUtils::UnpackCachedShaders(&reader, shaders, &inputs, 1, &settings);
538
539 auto compileShader = [&](SkSL::Program::Kind kind, const SkSL::String& sksl, GrGLenum type) {
540 SkSL::String glsl;
541 auto program = GrSkSLtoGLSL(gpu->glContext(), kind, sksl, settings, &glsl, errorHandler);
542 if (!program) {
543 return false;
544 }
545
546 if (GrGLuint shaderID = GrGLCompileAndAttachShader(gpu->glContext(), programID, type, glsl,
547 gpu->stats(), errorHandler)) {
548 shadersToDelete.push_back(shaderID);
549 return true;
550 } else {
551 return false;
552 }
553 };
554
555 if (!compileShader(SkSL::Program::kFragment_Kind,
556 shaders[kFragment_GrShaderType],
557 GR_GL_FRAGMENT_SHADER) ||
558 !compileShader(SkSL::Program::kVertex_Kind,
559 shaders[kVertex_GrShaderType],
560 GR_GL_VERTEX_SHADER) ||
561 (!shaders[kGeometry_GrShaderType].empty() &&
562 !compileShader(SkSL::Program::kGeometry_Kind,
563 shaders[kGeometry_GrShaderType],
564 GR_GL_GEOMETRY_SHADER))) {
565 cleanup_program(gpu, programID, shadersToDelete);
566 return false;
567 }
568
569 GR_GL_CALL(gpu->glInterface(), LinkProgram(programID));
570 GrGLint linked = GR_GL_INIT_ZERO;
571 GR_GL_CALL(gpu->glInterface(), GetProgramiv(programID, GR_GL_LINK_STATUS, &linked));
572 if (!linked) {
573 cleanup_program(gpu, programID, shadersToDelete);
574 return false;
575 }
576
577 cleanup_shaders(gpu, shadersToDelete);
578
579 precompiledProgram->fProgramID = programID;
580 precompiledProgram->fInputs = inputs;
581 return true;
582}