blob: 6c1279418f025c181db2d8d8eb2f219d3cd4b11c [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 Phillips65a77752019-10-02 15:22:24 -040048GrGLProgram* GrGLProgramBuilder::CreateProgram(GrRenderTarget* renderTarget,
Robert Phillips901aff02019-10-08 12:32:56 -040049 const GrProgramInfo& programInfo,
Ethan Nicholas38657112017-02-09 17:01:22 -050050 GrProgramDesc* desc,
Brian Osmaned58e002019-09-06 14:42:43 -040051 GrGLGpu* gpu,
52 const GrGLPrecompiledProgram* precompiledProgram) {
Stan Iliev43324e72020-01-13 16:17:48 -050053 ATRACE_ANDROID_FRAMEWORK_ALWAYS("shader_compile");
bsalomon3318ee72015-03-16 11:56:29 -070054 GrAutoLocaleSetter als("C");
55
joshualitt47bb3822014-10-07 16:43:25 -070056 // create a builder. This will be handed off to effects so they can use it to add
57 // uniforms, varyings, textures, etc
Robert Phillips901aff02019-10-08 12:32:56 -040058 GrGLProgramBuilder builder(gpu, renderTarget, programInfo, desc);
joshualitt47bb3822014-10-07 16:43:25 -070059
Robert Phillips9da87e02019-02-04 13:26:26 -050060 auto persistentCache = gpu->getContext()->priv().getPersistentCache();
Brian Osmaned58e002019-09-06 14:42:43 -040061 if (persistentCache && !precompiledProgram) {
Ethan Nicholasd1b2eec2017-11-01 15:45:43 -040062 sk_sp<SkData> key = SkData::MakeWithoutCopy(desc->asKey(), desc->keyLength());
Robert Phillips0c4b7b12018-03-06 08:20:37 -050063 builder.fCached = persistentCache->load(*key);
Ethan Nicholasd1b2eec2017-11-01 15:45:43 -040064 // the eventual end goal is to completely skip emitAndInstallProcs on a cache hit, but it's
65 // doing necessary setup in addition to generating the SkSL code. Currently we are only able
66 // to skip the SkSL->GLSL step on a cache hit.
67 }
Ethan Nicholas2983f402017-05-08 09:36:08 -040068 if (!builder.emitAndInstallProcs()) {
halcanary96fcdcc2015-08-27 07:41:13 -070069 return nullptr;
joshualitt6c891102015-05-13 08:51:49 -070070 }
Brian Osmaned58e002019-09-06 14:42:43 -040071 return builder.finalize(precompiledProgram);
joshualitt47bb3822014-10-07 16:43:25 -070072}
73
joshualitt47bb3822014-10-07 16:43:25 -070074/////////////////////////////////////////////////////////////////////////////
75
egdaniel0e1853c2016-03-17 11:35:45 -070076GrGLProgramBuilder::GrGLProgramBuilder(GrGLGpu* gpu,
Robert Phillipsd0fe8752019-01-31 14:13:59 -050077 GrRenderTarget* renderTarget,
Robert Phillips901aff02019-10-08 12:32:56 -040078 const GrProgramInfo& programInfo,
Ethan Nicholas38657112017-02-09 17:01:22 -050079 GrProgramDesc* desc)
Robert Phillips901aff02019-10-08 12:32:56 -040080 : INHERITED(renderTarget, programInfo, desc)
Brian Salomon802cb312018-06-08 18:05:20 -040081 , fGpu(gpu)
82 , fVaryingHandler(this)
83 , fUniformHandler(this)
Brian Salomon92be2f72018-06-19 14:33:47 -040084 , fVertexAttributeCnt(0)
85 , fInstanceAttributeCnt(0)
Brian Salomon802cb312018-06-08 18:05:20 -040086 , fVertexStride(0)
87 , fInstanceStride(0) {}
joshualitt30ba4362014-08-21 20:18:45 -070088
egdanielfa896322016-01-13 12:19:30 -080089const GrCaps* GrGLProgramBuilder::caps() const {
90 return fGpu->caps();
91}
92
Brian Osmanac9be9d2019-05-01 10:29:34 -040093bool GrGLProgramBuilder::compileAndAttachShaders(const SkSL::String& glsl,
egdaniel574a4c12015-11-02 06:22:44 -080094 GrGLuint programId,
95 GrGLenum type,
Ethan Nicholas941e7e22016-12-12 15:33:30 -050096 SkTDArray<GrGLuint>* shaderIds,
Brian Osman5e7fbfd2019-05-03 13:13:35 -040097 GrContextOptions::ShaderErrorHandler* errHandler) {
egdaniel574a4c12015-11-02 06:22:44 -080098 GrGLGpu* gpu = this->gpu();
99 GrGLuint shaderId = GrGLCompileAndAttachShader(gpu->glContext(),
100 programId,
101 type,
Ethan Nicholasd1b2eec2017-11-01 15:45:43 -0400102 glsl,
Brian Osman8518f2e2019-05-01 14:13:41 -0400103 gpu->stats(),
Brian Osman5e7fbfd2019-05-03 13:13:35 -0400104 errHandler);
egdaniel574a4c12015-11-02 06:22:44 -0800105 if (!shaderId) {
106 return false;
107 }
108
109 *shaderIds->append() = shaderId;
egdaniel574a4c12015-11-02 06:22:44 -0800110 return true;
111}
112
Ethan Nicholasad77dce2018-07-11 13:59:03 -0400113void GrGLProgramBuilder::computeCountsAndStrides(GrGLuint programID,
114 const GrPrimitiveProcessor& primProc,
115 bool bindAttribLocations) {
116 fVertexAttributeCnt = primProc.numVertexAttributes();
117 fInstanceAttributeCnt = primProc.numInstanceAttributes();
118 fAttributes.reset(
119 new GrGLProgram::Attribute[fVertexAttributeCnt + fInstanceAttributeCnt]);
120 auto addAttr = [&](int i, const auto& a, size_t* stride) {
Brian Osman4a3f5c82018-09-18 16:16:38 -0400121 fAttributes[i].fCPUType = a.cpuType();
122 fAttributes[i].fGPUType = a.gpuType();
Ethan Nicholasad77dce2018-07-11 13:59:03 -0400123 fAttributes[i].fOffset = *stride;
124 *stride += a.sizeAlign4();
125 fAttributes[i].fLocation = i;
126 if (bindAttribLocations) {
127 GL_CALL(BindAttribLocation(programID, i, a.name()));
128 }
129 };
130 fVertexStride = 0;
131 int i = 0;
Brian Osmanf04fb3c2018-11-12 15:34:00 -0500132 for (const auto& attr : primProc.vertexAttributes()) {
133 addAttr(i++, attr, &fVertexStride);
Ethan Nicholasad77dce2018-07-11 13:59:03 -0400134 }
Brian Osmanf04fb3c2018-11-12 15:34:00 -0500135 SkASSERT(fVertexStride == primProc.vertexStride());
Ethan Nicholasad77dce2018-07-11 13:59:03 -0400136 fInstanceStride = 0;
Brian Osmanf04fb3c2018-11-12 15:34:00 -0500137 for (const auto& attr : primProc.instanceAttributes()) {
138 addAttr(i++, attr, &fInstanceStride);
Ethan Nicholasad77dce2018-07-11 13:59:03 -0400139 }
Brian Osmanf04fb3c2018-11-12 15:34:00 -0500140 SkASSERT(fInstanceStride == primProc.instanceStride());
Ethan Nicholasad77dce2018-07-11 13:59:03 -0400141}
142
Ethan Nicholascd700e92018-08-24 16:43:57 -0400143void GrGLProgramBuilder::addInputVars(const SkSL::Program::Inputs& inputs) {
144 if (inputs.fRTWidth) {
145 this->addRTWidthUniform(SKSL_RTWIDTH_NAME);
146 }
147 if (inputs.fRTHeight) {
148 this->addRTHeightUniform(SKSL_RTHEIGHT_NAME);
149 }
150}
151
Brian Osmana085a412019-04-25 09:44:43 -0400152static constexpr SkFourByteTag kSKSL_Tag = SkSetFourByteTag('S', 'K', 'S', 'L');
153static constexpr SkFourByteTag kGLSL_Tag = SkSetFourByteTag('G', 'L', 'S', 'L');
Brian Osmana66081d2019-09-03 14:59:26 -0400154static constexpr SkFourByteTag kGLPB_Tag = SkSetFourByteTag('G', 'L', 'P', 'B');
Brian Osmana085a412019-04-25 09:44:43 -0400155
Ethan Nicholas8d058832019-01-07 10:49:58 -0500156void GrGLProgramBuilder::storeShaderInCache(const SkSL::Program::Inputs& inputs, GrGLuint programID,
Brian Osmaned58e002019-09-06 14:42:43 -0400157 const SkSL::String shaders[], bool isSkSL,
Brian Osman4524e842019-09-24 16:03:41 -0400158 SkSL::Program::Settings* settings) {
Robert Phillips9da87e02019-02-04 13:26:26 -0500159 if (!this->gpu()->getContext()->priv().getPersistentCache()) {
Ethan Nicholas8d058832019-01-07 10:49:58 -0500160 return;
161 }
Robert Phillips901aff02019-10-08 12:32:56 -0400162 sk_sp<SkData> key = SkData::MakeWithoutCopy(this->desc()->asKey(), this->desc()->keyLength());
Ethan Nicholas8d058832019-01-07 10:49:58 -0500163 if (fGpu->glCaps().programBinarySupport()) {
164 // binary cache
165 GrGLsizei length = 0;
166 GL_CALL(GetProgramiv(programID, GL_PROGRAM_BINARY_LENGTH, &length));
167 if (length > 0) {
Brian Osman6b797fe2019-04-08 13:56:36 -0400168 SkWriter32 writer;
Brian Osmana66081d2019-09-03 14:59:26 -0400169 writer.write32(kGLPB_Tag);
170
Brian Osman6b797fe2019-04-08 13:56:36 -0400171 writer.writePad(&inputs, sizeof(inputs));
172 writer.write32(length);
173
174 void* binary = writer.reservePad(length);
Ethan Nicholas8d058832019-01-07 10:49:58 -0500175 GrGLenum binaryFormat;
Brian Osman6b797fe2019-04-08 13:56:36 -0400176 GL_CALL(GetProgramBinary(programID, length, &length, &binaryFormat, binary));
177 writer.write32(binaryFormat);
178
179 auto data = writer.snapshotAsData();
180 this->gpu()->getContext()->priv().getPersistentCache()->store(*key, *data);
Ethan Nicholas8d058832019-01-07 10:49:58 -0500181 }
182 } else {
Brian Osman4524e842019-09-24 16:03:41 -0400183 // source cache, plus metadata to allow for a complete precompile
184 GrPersistentCacheUtils::ShaderMetadata meta;
185 meta.fSettings = settings;
186 meta.fHasCustomColorOutput = fFS.hasCustomColorOutput();
187 meta.fHasSecondaryColorOutput = fFS.hasSecondaryOutput();
188 for (const auto& attr : this->primitiveProcessor().vertexAttributes()) {
189 meta.fAttributeNames.emplace_back(attr.name());
190 }
191 for (const auto& attr : this->primitiveProcessor().instanceAttributes()) {
192 meta.fAttributeNames.emplace_back(attr.name());
193 }
194
Brian Osmana085a412019-04-25 09:44:43 -0400195 auto data = GrPersistentCacheUtils::PackCachedShaders(isSkSL ? kSKSL_Tag : kGLSL_Tag,
Brian Osman4524e842019-09-24 16:03:41 -0400196 shaders, &inputs, 1, &meta);
Brian Osman6b797fe2019-04-08 13:56:36 -0400197 this->gpu()->getContext()->priv().getPersistentCache()->store(*key, *data);
Ethan Nicholas8d058832019-01-07 10:49:58 -0500198 }
199}
200
Brian Osmaned58e002019-09-06 14:42:43 -0400201GrGLProgram* GrGLProgramBuilder::finalize(const GrGLPrecompiledProgram* precompiledProgram) {
Brian Salomon5f394272019-07-02 14:07:49 -0400202 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
Ryan Macnak38a10ad2017-07-10 10:36:34 -0700203
joshualitt47bb3822014-10-07 16:43:25 -0700204 // verify we can get a program id
205 GrGLuint programID;
Brian Osmaned58e002019-09-06 14:42:43 -0400206 if (precompiledProgram) {
207 programID = precompiledProgram->fProgramID;
208 } else {
209 GL_CALL_RET(programID, CreateProgram());
210 }
joshualitt47bb3822014-10-07 16:43:25 -0700211 if (0 == programID) {
halcanary96fcdcc2015-08-27 07:41:13 -0700212 return nullptr;
joshualitt30ba4362014-08-21 20:18:45 -0700213 }
214
Ethan Nicholas06d55fb2017-11-08 09:48:50 -0500215 if (this->gpu()->glCaps().programBinarySupport() &&
Brian Osman064729e2019-06-18 17:22:59 -0400216 this->gpu()->glCaps().programParameterSupport() &&
Brian Osmaned58e002019-09-06 14:42:43 -0400217 this->gpu()->getContext()->priv().getPersistentCache() &&
218 !precompiledProgram) {
Ethan Nicholasd1b2eec2017-11-01 15:45:43 -0400219 GL_CALL(ProgramParameteri(programID, GR_GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GR_GL_TRUE));
220 }
221
egdaniel9f1d4152016-02-10 09:50:38 -0800222 this->finalizeShaders();
223
joshualitt47bb3822014-10-07 16:43:25 -0700224 // compile shaders and bind attributes / uniforms
Brian Osman5e7fbfd2019-05-03 13:13:35 -0400225 auto errorHandler = this->gpu()->getContext()->priv().getShaderErrorHandler();
Ethan Nicholasd1b2eec2017-11-01 15:45:43 -0400226 const GrPrimitiveProcessor& primProc = this->primitiveProcessor();
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500227 SkSL::Program::Settings settings;
228 settings.fCaps = this->gpu()->glCaps().shaderCaps();
Robert Phillipsd0fe8752019-01-31 14:13:59 -0500229 settings.fFlipY = this->origin() != kTopLeft_GrSurfaceOrigin;
Robert Phillipsc1541ae2019-02-04 12:05:37 -0500230 settings.fSharpenTextures =
Robert Phillips9da87e02019-02-04 13:26:26 -0500231 this->gpu()->getContext()->priv().options().fSharpenMipmappedTextures;
Brian Salomondc092132018-04-04 10:14:16 -0400232 settings.fFragColorIsInOut = this->fragColorIsInOut();
233
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500234 SkSL::Program::Inputs inputs;
joshualitt30ba4362014-08-21 20:18:45 -0700235 SkTDArray<GrGLuint> shadersToDelete;
Ethan Nicholas5a0338c2019-01-02 11:48:56 -0500236 // Calling GetProgramiv is expensive in Chromium. Assume success in release builds.
237 bool checkLinked = kChromium_GrGLDriver != fGpu->ctxInfo().driver();
238#ifdef SK_DEBUG
239 checkLinked = true;
240#endif
Ethan Nicholas8d058832019-01-07 10:49:58 -0500241 bool cached = fCached.get() != nullptr;
Brian Osman2c60a382019-06-26 15:19:30 -0400242 bool usedProgramBinaries = false;
Brian Osman6b797fe2019-04-08 13:56:36 -0400243 SkSL::String glsl[kGrShaderTypeCount];
Brian Osmancbc33b82019-04-19 14:16:19 -0400244 SkSL::String* sksl[kGrShaderTypeCount] = {
245 &fVS.fCompilerString,
246 &fGS.fCompilerString,
247 &fFS.fCompilerString,
248 };
Brian Osmancbc33b82019-04-19 14:16:19 -0400249 SkSL::String cached_sksl[kGrShaderTypeCount];
Brian Osmaned58e002019-09-06 14:42:43 -0400250 if (precompiledProgram) {
251 // This is very similar to when we get program binaries. We even set that flag, as it's
252 // used to prevent other compile work later, and to force re-querying uniform locations.
253 this->addInputVars(precompiledProgram->fInputs);
Brian Osman4524e842019-09-24 16:03:41 -0400254 this->computeCountsAndStrides(programID, primProc, false);
Brian Osmaned58e002019-09-06 14:42:43 -0400255 usedProgramBinaries = true;
256 } else if (cached) {
Stan Iliev43324e72020-01-13 16:17:48 -0500257 ATRACE_ANDROID_FRAMEWORK_ALWAYS("cache_hit");
Brian Osmana66081d2019-09-03 14:59:26 -0400258 SkReader32 reader(fCached->data(), fCached->size());
259 SkFourByteTag shaderType = reader.readU32();
260
261 switch (shaderType) {
262 case kGLPB_Tag: {
263 // Program binary cache hit. We may opt not to use this if we don't trust program
264 // binaries on this driver
265 if (!fGpu->glCaps().programBinarySupport()) {
266 cached = false;
267 break;
Ethan Nicholas8d058832019-01-07 10:49:58 -0500268 }
Brian Osmana66081d2019-09-03 14:59:26 -0400269 reader.read(&inputs, sizeof(inputs));
270 GrGLsizei length = reader.readInt();
271 const void* binary = reader.skip(length);
272 GrGLenum binaryFormat = reader.readU32();
273 GrGLClearErr(this->gpu()->glInterface());
274 GR_GL_CALL_NOERRCHECK(this->gpu()->glInterface(),
275 ProgramBinary(programID, binaryFormat,
276 const_cast<void*>(binary), length));
277 if (GR_GL_GET_ERROR(this->gpu()->glInterface()) == GR_GL_NO_ERROR) {
278 if (checkLinked) {
279 cached = this->checkLinkStatus(programID, errorHandler, nullptr, nullptr);
280 }
281 if (cached) {
282 this->addInputVars(inputs);
283 this->computeCountsAndStrides(programID, primProc, false);
284 }
285 } else {
286 cached = false;
Ethan Nicholas8d058832019-01-07 10:49:58 -0500287 }
Brian Osmana66081d2019-09-03 14:59:26 -0400288 usedProgramBinaries = cached;
289 break;
Ethan Nicholasad77dce2018-07-11 13:59:03 -0400290 }
Brian Osmana66081d2019-09-03 14:59:26 -0400291
292 case kGLSL_Tag:
293 // Source cache hit, we don't need to compile the SkSL->GLSL
294 GrPersistentCacheUtils::UnpackCachedShaders(&reader, glsl, &inputs, 1);
295 break;
296
297 case kSKSL_Tag:
298 // SkSL cache hit, this should only happen in tools overriding the generated SkSL
299 GrPersistentCacheUtils::UnpackCachedShaders(&reader, cached_sksl, &inputs, 1);
Brian Osmana085a412019-04-25 09:44:43 -0400300 for (int i = 0; i < kGrShaderTypeCount; ++i) {
301 sksl[i] = &cached_sksl[i];
302 }
Brian Osmana66081d2019-09-03 14:59:26 -0400303 break;
Ethan Nicholas98ad5b72018-03-13 09:53:02 -0400304 }
305 }
Brian Osmana66081d2019-09-03 14:59:26 -0400306 if (!usedProgramBinaries) {
Stan Iliev43324e72020-01-13 16:17:48 -0500307 ATRACE_ANDROID_FRAMEWORK_ALWAYS("cache_miss");
Brian Osmanf7924452019-09-24 10:44:37 -0400308 // Either a cache miss, or we got something other than binaries from the cache
309
310 /*
311 Fragment Shader
312 */
Brian Osman6b797fe2019-04-08 13:56:36 -0400313 if (glsl[kFragment_GrShaderType].empty()) {
Brian Osmanf71b0702019-04-03 13:04:16 -0400314 // Don't have cached GLSL, need to compile SkSL->GLSL
Ethan Nicholas8d058832019-01-07 10:49:58 -0500315 if (fFS.fForceHighPrecision) {
316 settings.fForceHighPrecision = true;
317 }
318 std::unique_ptr<SkSL::Program> fs = GrSkSLtoGLSL(gpu()->glContext(),
Brian Osmanac9be9d2019-05-01 10:29:34 -0400319 SkSL::Program::kFragment_Kind,
Brian Osmancbc33b82019-04-19 14:16:19 -0400320 *sksl[kFragment_GrShaderType],
Ethan Nicholas8d058832019-01-07 10:49:58 -0500321 settings,
Brian Osman5e7fbfd2019-05-03 13:13:35 -0400322 &glsl[kFragment_GrShaderType],
323 errorHandler);
Ethan Nicholas8d058832019-01-07 10:49:58 -0500324 if (!fs) {
Brian Osmaned58e002019-09-06 14:42:43 -0400325 cleanup_program(fGpu, programID, shadersToDelete);
Ethan Nicholas8d058832019-01-07 10:49:58 -0500326 return nullptr;
327 }
328 inputs = fs->fInputs;
egdaniel8dcdedc2015-11-11 06:27:20 -0800329 }
Brian Osmanf7924452019-09-24 10:44:37 -0400330
331 this->addInputVars(inputs);
Brian Osmanac9be9d2019-05-01 10:29:34 -0400332 if (!this->compileAndAttachShaders(glsl[kFragment_GrShaderType], programID,
Brian Osmane11dfd32019-07-23 10:29:41 -0400333 GR_GL_FRAGMENT_SHADER, &shadersToDelete, errorHandler)) {
Brian Osmaned58e002019-09-06 14:42:43 -0400334 cleanup_program(fGpu, programID, shadersToDelete);
Ethan Nicholasd1b2eec2017-11-01 15:45:43 -0400335 return nullptr;
336 }
337
Brian Osmanf7924452019-09-24 10:44:37 -0400338 /*
339 Vertex Shader
340 */
Brian Osman6b797fe2019-04-08 13:56:36 -0400341 if (glsl[kVertex_GrShaderType].empty()) {
Brian Osmanf71b0702019-04-03 13:04:16 -0400342 // Don't have cached GLSL, need to compile SkSL->GLSL
343 std::unique_ptr<SkSL::Program> vs = GrSkSLtoGLSL(gpu()->glContext(),
Brian Osmanac9be9d2019-05-01 10:29:34 -0400344 SkSL::Program::kVertex_Kind,
Brian Osmancbc33b82019-04-19 14:16:19 -0400345 *sksl[kVertex_GrShaderType],
Brian Osmanf71b0702019-04-03 13:04:16 -0400346 settings,
Brian Osman5e7fbfd2019-05-03 13:13:35 -0400347 &glsl[kVertex_GrShaderType],
348 errorHandler);
Brian Osmanf71b0702019-04-03 13:04:16 -0400349 if (!vs) {
Brian Osmaned58e002019-09-06 14:42:43 -0400350 cleanup_program(fGpu, programID, shadersToDelete);
Brian Osmanf71b0702019-04-03 13:04:16 -0400351 return nullptr;
352 }
353 }
Brian Osmanac9be9d2019-05-01 10:29:34 -0400354 if (!this->compileAndAttachShaders(glsl[kVertex_GrShaderType], programID,
Brian Osmane11dfd32019-07-23 10:29:41 -0400355 GR_GL_VERTEX_SHADER, &shadersToDelete, errorHandler)) {
Brian Osmaned58e002019-09-06 14:42:43 -0400356 cleanup_program(fGpu, programID, shadersToDelete);
Ethan Nicholasd1b2eec2017-11-01 15:45:43 -0400357 return nullptr;
358 }
359
Brian Osmanf7924452019-09-24 10:44:37 -0400360 // This also binds vertex attribute locations. NVPR doesn't really use vertices,
361 // even though it requires a vertex shader in the program.
362 if (!primProc.isPathRendering()) {
Ethan Nicholasad77dce2018-07-11 13:59:03 -0400363 this->computeCountsAndStrides(programID, primProc, true);
Ethan Nicholasd1b2eec2017-11-01 15:45:43 -0400364 }
365
Brian Osmanf7924452019-09-24 10:44:37 -0400366 /*
Chris Dalton5a2f9622019-12-27 14:56:38 -0700367 Tessellation Shaders
368 */
369 if (fProgramInfo.primProc().willUseTessellationShaders()) {
370 // Tessellation shaders are not currently supported by SkSL. So here, we temporarily
371 // generate GLSL strings directly using back door methods on GrPrimitiveProcessor, and
372 // pass those raw strings on to the driver.
373 SkString versionAndExtensionDecls;
374 versionAndExtensionDecls.appendf("%s\n", this->shaderCaps()->versionDeclString());
375 if (const char* extensionString = this->shaderCaps()->tessellationExtensionString()) {
376 versionAndExtensionDecls.appendf("#extension %s : require\n", extensionString);
377 }
378
379 SkString tessControlShader = primProc.getTessControlShaderGLSL(
380 versionAndExtensionDecls.c_str(), *this->shaderCaps());
381 if (!this->compileAndAttachShaders(tessControlShader.c_str(), programID,
382 GR_GL_TESS_CONTROL_SHADER, &shadersToDelete,
383 errorHandler)) {
384 cleanup_program(fGpu, programID, shadersToDelete);
385 return nullptr;
386 }
387
388 SkString tessEvaluationShader = primProc.getTessEvaluationShaderGLSL(
389 versionAndExtensionDecls.c_str(), *this->shaderCaps());
390 if (!this->compileAndAttachShaders(tessEvaluationShader.c_str(), programID,
391 GR_GL_TESS_EVALUATION_SHADER, &shadersToDelete,
392 errorHandler)) {
393 cleanup_program(fGpu, programID, shadersToDelete);
394 return nullptr;
395 }
396 }
397
398 /*
Brian Osmanf7924452019-09-24 10:44:37 -0400399 Geometry Shader
400 */
Ethan Nicholasd1b2eec2017-11-01 15:45:43 -0400401 if (primProc.willUseGeoShader()) {
Brian Osman6b797fe2019-04-08 13:56:36 -0400402 if (glsl[kGeometry_GrShaderType].empty()) {
Brian Osmanf71b0702019-04-03 13:04:16 -0400403 // Don't have cached GLSL, need to compile SkSL->GLSL
404 std::unique_ptr<SkSL::Program> gs;
405 gs = GrSkSLtoGLSL(gpu()->glContext(),
Brian Osmanac9be9d2019-05-01 10:29:34 -0400406 SkSL::Program::kGeometry_Kind,
Brian Osmancbc33b82019-04-19 14:16:19 -0400407 *sksl[kGeometry_GrShaderType],
Brian Osmanf71b0702019-04-03 13:04:16 -0400408 settings,
Brian Osman5e7fbfd2019-05-03 13:13:35 -0400409 &glsl[kGeometry_GrShaderType],
410 errorHandler);
Brian Osmanf71b0702019-04-03 13:04:16 -0400411 if (!gs) {
Brian Osmaned58e002019-09-06 14:42:43 -0400412 cleanup_program(fGpu, programID, shadersToDelete);
Brian Osmanf71b0702019-04-03 13:04:16 -0400413 return nullptr;
414 }
415 }
Brian Osmanac9be9d2019-05-01 10:29:34 -0400416 if (!this->compileAndAttachShaders(glsl[kGeometry_GrShaderType], programID,
Brian Osmane11dfd32019-07-23 10:29:41 -0400417 GR_GL_GEOMETRY_SHADER, &shadersToDelete,
Brian Osman5e7fbfd2019-05-03 13:13:35 -0400418 errorHandler)) {
Brian Osmaned58e002019-09-06 14:42:43 -0400419 cleanup_program(fGpu, programID, shadersToDelete);
Ethan Nicholasd1b2eec2017-11-01 15:45:43 -0400420 return nullptr;
421 }
Ethan Nicholasd1b2eec2017-11-01 15:45:43 -0400422 }
423 this->bindProgramResourceLocations(programID);
424
425 GL_CALL(LinkProgram(programID));
Ethan Nicholas5a0338c2019-01-02 11:48:56 -0500426 if (checkLinked) {
Brian Osman5e7fbfd2019-05-03 13:13:35 -0400427 if (!this->checkLinkStatus(programID, errorHandler, sksl, glsl)) {
Brian Osman2ab2ac02019-09-09 13:54:54 -0400428 cleanup_program(fGpu, programID, shadersToDelete);
Ethan Nicholas5a0338c2019-01-02 11:48:56 -0500429 return nullptr;
Brian Salomone334c592017-05-15 11:00:58 -0400430 }
Brian Salomone334c592017-05-15 11:00:58 -0400431 }
joshualittfe1233c2014-10-07 12:16:35 -0700432 }
Brian Osman2c60a382019-06-26 15:19:30 -0400433 this->resolveProgramResourceLocations(programID, usedProgramBinaries);
joshualittdb0d3ca2014-10-07 12:42:26 -0700434
Brian Osmaned58e002019-09-06 14:42:43 -0400435 cleanup_shaders(fGpu, shadersToDelete);
Brian Osmane4c88bb2019-06-27 16:15:11 -0400436
437 // With ANGLE, we can't cache path-rendering programs. We use ProgramPathFragmentInputGen,
438 // and ANGLE's deserialized program state doesn't restore enough state to handle that.
439 // The native NVIDIA drivers do, but this is such an edge case that it's easier to just
440 // black-list caching these programs in all cases. See: anglebug.com/3619
Chris Dalton5a2f9622019-12-27 14:56:38 -0700441 //
442 // We temporarily can't cache tessellation shaders while using back door GLSL.
443 //
Brian Osmaned58e002019-09-06 14:42:43 -0400444 // We also can't cache SkSL or GLSL if we were given a precompiled program, but there's not
445 // much point in doing so.
Chris Dalton5a2f9622019-12-27 14:56:38 -0700446 if (!cached && !primProc.isPathRendering() && !primProc.willUseTessellationShaders() &&
447 !precompiledProgram) {
Chris Dalton8dae7eb2019-12-27 22:20:55 -0700448 // FIXME: Remove the check for tessellation shaders in the above 'if' once the back door
449 // GLSL mechanism is removed.
450 (void)&GrPrimitiveProcessor::getTessControlShaderGLSL;
Brian Osmana085a412019-04-25 09:44:43 -0400451 bool isSkSL = false;
Brian Osmana66081d2019-09-03 14:59:26 -0400452 if (fGpu->getContext()->priv().options().fShaderCacheStrategy ==
453 GrContextOptions::ShaderCacheStrategy::kSkSL) {
Brian Osmancbc33b82019-04-19 14:16:19 -0400454 for (int i = 0; i < kGrShaderTypeCount; ++i) {
Brian Osmanac9be9d2019-05-01 10:29:34 -0400455 glsl[i] = GrShaderUtils::PrettyPrint(*sksl[i]);
Brian Osmancbc33b82019-04-19 14:16:19 -0400456 }
Brian Osmana085a412019-04-25 09:44:43 -0400457 isSkSL = true;
Brian Osmancbc33b82019-04-19 14:16:19 -0400458 }
Brian Osman4524e842019-09-24 16:03:41 -0400459 this->storeShaderInCache(inputs, programID, glsl, isSkSL, &settings);
Ethan Nicholasd1b2eec2017-11-01 15:45:43 -0400460 }
joshualitt47bb3822014-10-07 16:43:25 -0700461 return this->createProgram(programID);
462}
463
kkinnunen7aedda52015-06-29 23:01:28 -0700464void GrGLProgramBuilder::bindProgramResourceLocations(GrGLuint programID) {
egdaniel7ea439b2015-12-03 09:20:44 -0800465 fUniformHandler.bindUniformLocations(programID, fGpu->glCaps());
kkinnunen7aedda52015-06-29 23:01:28 -0700466
egdaniel8dcdedc2015-11-11 06:27:20 -0800467 const GrGLCaps& caps = this->gpu()->glCaps();
468 if (fFS.hasCustomColorOutput() && caps.bindFragDataLocationSupport()) {
469 GL_CALL(BindFragDataLocation(programID, 0,
egdaniel2d721d32015-11-11 13:06:05 -0800470 GrGLSLFragmentShaderBuilder::DeclaredColorOutputName()));
egdaniel8dcdedc2015-11-11 06:27:20 -0800471 }
Brian Salomon1edc5b92016-11-29 13:43:46 -0500472 if (fFS.hasSecondaryOutput() && caps.shaderCaps()->mustDeclareFragmentShaderOutput()) {
egdaniel8dcdedc2015-11-11 06:27:20 -0800473 GL_CALL(BindFragDataLocationIndexed(programID, 0, 1,
egdaniel2d721d32015-11-11 13:06:05 -0800474 GrGLSLFragmentShaderBuilder::DeclaredSecondaryColorOutputName()));
egdaniel8dcdedc2015-11-11 06:27:20 -0800475 }
joshualittd8dd47b2015-09-11 11:45:01 -0700476
477 // handle NVPR separable varyings
478 if (!fGpu->glCaps().shaderCaps()->pathRenderingSupport() ||
479 !fGpu->glPathRendering()->shouldBindFragmentInputs()) {
480 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) {
egdaniel0eafe792015-11-20 14:01:22 -0800484 GL_CALL(BindFragmentInputLocation(programID, i,
485 fVaryingHandler.fPathProcVaryingInfos[i].fVariable.c_str()));
486 fVaryingHandler.fPathProcVaryingInfos[i].fLocation = i;
joshualittd8dd47b2015-09-11 11:45:01 -0700487 }
joshualitt47bb3822014-10-07 16:43:25 -0700488}
489
Brian Osman5e7fbfd2019-05-03 13:13:35 -0400490bool GrGLProgramBuilder::checkLinkStatus(GrGLuint programID,
491 GrContextOptions::ShaderErrorHandler* errorHandler,
492 SkSL::String* sksl[], const SkSL::String glsl[]) {
joshualitt47bb3822014-10-07 16:43:25 -0700493 GrGLint linked = GR_GL_INIT_ZERO;
494 GL_CALL(GetProgramiv(programID, GR_GL_LINK_STATUS, &linked));
495 if (!linked) {
Brian Osman5e7fbfd2019-05-03 13:13:35 -0400496 SkSL::String allShaders;
497 if (sksl) {
498 allShaders.appendf("// Vertex SKSL\n%s\n", sksl[kVertex_GrShaderType]->c_str());
499 if (!sksl[kGeometry_GrShaderType]->empty()) {
500 allShaders.appendf("// Geometry SKSL\n%s\n", sksl[kGeometry_GrShaderType]->c_str());
501 }
502 allShaders.appendf("// Fragment SKSL\n%s\n", sksl[kFragment_GrShaderType]->c_str());
503 }
504 if (glsl) {
505 allShaders.appendf("// Vertex GLSL\n%s\n", glsl[kVertex_GrShaderType].c_str());
506 if (!glsl[kGeometry_GrShaderType].empty()) {
507 allShaders.appendf("// Geometry GLSL\n%s\n", glsl[kGeometry_GrShaderType].c_str());
508 }
509 allShaders.appendf("// Fragment GLSL\n%s\n", glsl[kFragment_GrShaderType].c_str());
510 }
joshualitt47bb3822014-10-07 16:43:25 -0700511 GrGLint infoLen = GR_GL_INIT_ZERO;
512 GL_CALL(GetProgramiv(programID, GR_GL_INFO_LOG_LENGTH, &infoLen));
513 SkAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
514 if (infoLen > 0) {
515 // retrieve length even though we don't need it to workaround
516 // bug in chrome cmd buffer param validation.
517 GrGLsizei length = GR_GL_INIT_ZERO;
Brian Osman5e7fbfd2019-05-03 13:13:35 -0400518 GL_CALL(GetProgramInfoLog(programID, infoLen+1, &length, (char*)log.get()));
joshualitt47bb3822014-10-07 16:43:25 -0700519 }
Brian Osman5e7fbfd2019-05-03 13:13:35 -0400520 errorHandler->compileError(allShaders.c_str(), infoLen > 0 ? (const char*)log.get() : "");
joshualitt47bb3822014-10-07 16:43:25 -0700521 }
522 return SkToBool(linked);
523}
524
Brian Osman2c60a382019-06-26 15:19:30 -0400525void GrGLProgramBuilder::resolveProgramResourceLocations(GrGLuint programID, bool force) {
526 fUniformHandler.getUniformLocations(programID, fGpu->glCaps(), force);
joshualittd8dd47b2015-09-11 11:45:01 -0700527
528 // handle NVPR separable varyings
529 if (!fGpu->glCaps().shaderCaps()->pathRenderingSupport() ||
kkinnunen7bdb05d2016-01-25 00:47:23 -0800530 fGpu->glPathRendering()->shouldBindFragmentInputs()) {
joshualittd8dd47b2015-09-11 11:45:01 -0700531 return;
532 }
egdaniel0eafe792015-11-20 14:01:22 -0800533 int count = fVaryingHandler.fPathProcVaryingInfos.count();
joshualittd8dd47b2015-09-11 11:45:01 -0700534 for (int i = 0; i < count; ++i) {
535 GrGLint location;
egdaniel0eafe792015-11-20 14:01:22 -0800536 GL_CALL_RET(location, GetProgramResourceLocation(
537 programID,
538 GR_GL_FRAGMENT_INPUT,
539 fVaryingHandler.fPathProcVaryingInfos[i].fVariable.c_str()));
540 fVaryingHandler.fPathProcVaryingInfos[i].fLocation = location;
joshualittd8dd47b2015-09-11 11:45:01 -0700541 }
joshualitt30ba4362014-08-21 20:18:45 -0700542}
543
joshualitt47bb3822014-10-07 16:43:25 -0700544GrGLProgram* GrGLProgramBuilder::createProgram(GrGLuint programID) {
egdaniel7ea439b2015-12-03 09:20:44 -0800545 return new GrGLProgram(fGpu,
egdaniel7ea439b2015-12-03 09:20:44 -0800546 fUniformHandles,
547 programID,
548 fUniformHandler.fUniforms,
egdaniel09aa1fc2016-04-20 07:09:46 -0700549 fUniformHandler.fSamplers,
egdaniel0eafe792015-11-20 14:01:22 -0800550 fVaryingHandler.fPathProcVaryingInfos,
Robert Phillips369e8b72017-08-01 16:13:04 -0400551 std::move(fGeometryProcessor),
552 std::move(fXferProcessor),
Brian Salomon4d3f5172018-06-07 14:42:52 -0400553 std::move(fFragmentProcessors),
Brian Salomon802cb312018-06-08 18:05:20 -0400554 fFragmentProcessorCnt,
555 std::move(fAttributes),
Brian Salomon92be2f72018-06-19 14:33:47 -0400556 fVertexAttributeCnt,
557 fInstanceAttributeCnt,
Brian Salomon802cb312018-06-08 18:05:20 -0400558 fVertexStride,
559 fInstanceStride);
joshualitt47bb3822014-10-07 16:43:25 -0700560}
Brian Osmaned58e002019-09-06 14:42:43 -0400561
562bool GrGLProgramBuilder::PrecompileProgram(GrGLPrecompiledProgram* precompiledProgram,
563 GrGLGpu* gpu,
564 const SkData& cachedData) {
565 SkReader32 reader(cachedData.data(), cachedData.size());
566 SkFourByteTag shaderType = reader.readU32();
567 if (shaderType != kSKSL_Tag) {
568 // TODO: Support GLSL, and maybe even program binaries, too?
569 return false;
570 }
571
572 const GrGLInterface* gl = gpu->glInterface();
573 auto errorHandler = gpu->getContext()->priv().getShaderErrorHandler();
574 GrGLuint programID;
575 GR_GL_CALL_RET(gl, programID, CreateProgram());
576 if (0 == programID) {
577 return false;
578 }
579
580 SkTDArray<GrGLuint> shadersToDelete;
581
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 Osman4524e842019-09-24 16:03:41 -0400591 GrPersistentCacheUtils::UnpackCachedShaders(&reader, shaders, &inputs, 1, &meta);
Brian Osmaned58e002019-09-06 14:42:43 -0400592
593 auto compileShader = [&](SkSL::Program::Kind kind, const SkSL::String& sksl, GrGLenum type) {
594 SkSL::String glsl;
595 auto program = GrSkSLtoGLSL(gpu->glContext(), kind, sksl, settings, &glsl, errorHandler);
596 if (!program) {
597 return false;
598 }
599
600 if (GrGLuint shaderID = GrGLCompileAndAttachShader(gpu->glContext(), programID, type, glsl,
601 gpu->stats(), errorHandler)) {
602 shadersToDelete.push_back(shaderID);
603 return true;
604 } else {
605 return false;
606 }
607 };
608
609 if (!compileShader(SkSL::Program::kFragment_Kind,
610 shaders[kFragment_GrShaderType],
611 GR_GL_FRAGMENT_SHADER) ||
612 !compileShader(SkSL::Program::kVertex_Kind,
613 shaders[kVertex_GrShaderType],
614 GR_GL_VERTEX_SHADER) ||
615 (!shaders[kGeometry_GrShaderType].empty() &&
616 !compileShader(SkSL::Program::kGeometry_Kind,
617 shaders[kGeometry_GrShaderType],
618 GR_GL_GEOMETRY_SHADER))) {
619 cleanup_program(gpu, programID, shadersToDelete);
620 return false;
621 }
622
Brian Osman4524e842019-09-24 16:03:41 -0400623 for (int i = 0; i < meta.fAttributeNames.count(); ++i) {
624 GR_GL_CALL(gpu->glInterface(), BindAttribLocation(programID, i,
625 meta.fAttributeNames[i].c_str()));
626 }
627
628 if (meta.fHasCustomColorOutput && caps.bindFragDataLocationSupport()) {
629 GR_GL_CALL(gpu->glInterface(), BindFragDataLocation(programID, 0,
630 GrGLSLFragmentShaderBuilder::DeclaredColorOutputName()));
631 }
632 if (meta.fHasSecondaryColorOutput && caps.shaderCaps()->mustDeclareFragmentShaderOutput()) {
633 GR_GL_CALL(gpu->glInterface(), BindFragDataLocationIndexed(programID, 0, 1,
634 GrGLSLFragmentShaderBuilder::DeclaredSecondaryColorOutputName()));
635 }
636
Brian Osmaned58e002019-09-06 14:42:43 -0400637 GR_GL_CALL(gpu->glInterface(), LinkProgram(programID));
638 GrGLint linked = GR_GL_INIT_ZERO;
639 GR_GL_CALL(gpu->glInterface(), GetProgramiv(programID, GR_GL_LINK_STATUS, &linked));
640 if (!linked) {
641 cleanup_program(gpu, programID, shadersToDelete);
642 return false;
643 }
644
645 cleanup_shaders(gpu, shadersToDelete);
646
647 precompiledProgram->fProgramID = programID;
648 precompiledProgram->fInputs = inputs;
649 return true;
650}