When precompiling SkSL, avoid the need to re-link

Adds metadata to the SkSL blobs about attributes (and other resources)
so that we can do all necessary work during precompile.

Change-Id: I1846c6c96946d5a43a48112d062853717a6571a0
Bug: skia:9402
Bug: b/140174804
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/243739
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
This commit is contained in:
Brian Osman 2019-09-24 16:03:41 -04:00 committed by Skia Commit-Bot
parent 497365778e
commit 4524e84a74
6 changed files with 84 additions and 31 deletions

View File

@ -20,11 +20,18 @@
// put the serialization logic here, to be shared by the backend code and the tool code.
namespace GrPersistentCacheUtils {
struct ShaderMetadata {
SkSL::Program::Settings* fSettings = nullptr;
SkTArray<SkSL::String> fAttributeNames;
bool fHasCustomColorOutput = false;
bool fHasSecondaryColorOutput = false;
};
static inline sk_sp<SkData> PackCachedShaders(SkFourByteTag shaderType,
const SkSL::String shaders[],
const SkSL::Program::Inputs inputs[],
int numInputs,
const SkSL::Program::Settings* settings) {
const ShaderMetadata* meta = nullptr) {
// For consistency (so tools can blindly pack and unpack cached shaders), we always write
// kGrShaderTypeCount inputs. If the backend gives us fewer, we just replicate the last one.
SkASSERT(numInputs >= 1 && numInputs <= kGrShaderTypeCount);
@ -35,11 +42,22 @@ static inline sk_sp<SkData> PackCachedShaders(SkFourByteTag shaderType,
writer.writeString(shaders[i].c_str(), shaders[i].size());
writer.writePad(&inputs[SkTMin(i, numInputs - 1)], sizeof(SkSL::Program::Inputs));
}
writer.writeBool(SkToBool(settings));
if (settings) {
writer.writeBool(settings->fFlipY);
writer.writeBool(settings->fFragColorIsInOut);
writer.writeBool(settings->fForceHighPrecision);
writer.writeBool(SkToBool(meta));
if (meta) {
writer.writeBool(SkToBool(meta->fSettings));
if (meta->fSettings) {
writer.writeBool(meta->fSettings->fFlipY);
writer.writeBool(meta->fSettings->fFragColorIsInOut);
writer.writeBool(meta->fSettings->fForceHighPrecision);
}
writer.writeInt(meta->fAttributeNames.count());
for (const auto& attr : meta->fAttributeNames) {
writer.writeString(attr.c_str(), attr.size());
}
writer.writeBool(meta->fHasCustomColorOutput);
writer.writeBool(meta->fHasSecondaryColorOutput);
}
return writer.snapshotAsData();
}
@ -48,7 +66,7 @@ static inline void UnpackCachedShaders(SkReader32* reader,
SkSL::String shaders[],
SkSL::Program::Inputs inputs[],
int numInputs,
SkSL::Program::Settings* settings = nullptr) {
ShaderMetadata* meta = nullptr) {
for (int i = 0; i < kGrShaderTypeCount; ++i) {
size_t stringLen = 0;
const char* string = reader->readString(&stringLen);
@ -61,10 +79,24 @@ static inline void UnpackCachedShaders(SkReader32* reader,
reader->skip(sizeof(SkSL::Program::Inputs));
}
}
if (reader->readBool() && settings) {
settings->fFlipY = reader->readBool();
settings->fFragColorIsInOut = reader->readBool();
settings->fForceHighPrecision = reader->readBool();
if (reader->readBool() && meta) {
SkASSERT(meta->fSettings != nullptr);
if (reader->readBool()) {
meta->fSettings->fFlipY = reader->readBool();
meta->fSettings->fFragColorIsInOut = reader->readBool();
meta->fSettings->fForceHighPrecision = reader->readBool();
}
meta->fAttributeNames.resize(reader->readInt());
for (int i = 0; i < meta->fAttributeNames.count(); ++i) {
size_t stringLen = 0;
const char* string = reader->readString(&stringLen);
meta->fAttributeNames[i] = SkSL::String(string, stringLen);
}
meta->fHasCustomColorOutput = reader->readBool();
meta->fHasSecondaryColorOutput = reader->readBool();
}
}

View File

@ -163,7 +163,7 @@ static constexpr SkFourByteTag kGLPB_Tag = SkSetFourByteTag('G', 'L', 'P', 'B');
void GrGLProgramBuilder::storeShaderInCache(const SkSL::Program::Inputs& inputs, GrGLuint programID,
const SkSL::String shaders[], bool isSkSL,
const SkSL::Program::Settings& settings) {
SkSL::Program::Settings* settings) {
if (!this->gpu()->getContext()->priv().getPersistentCache()) {
return;
}
@ -188,9 +188,20 @@ void GrGLProgramBuilder::storeShaderInCache(const SkSL::Program::Inputs& inputs,
this->gpu()->getContext()->priv().getPersistentCache()->store(*key, *data);
}
} else {
// source cache
// source cache, plus metadata to allow for a complete precompile
GrPersistentCacheUtils::ShaderMetadata meta;
meta.fSettings = settings;
meta.fHasCustomColorOutput = fFS.hasCustomColorOutput();
meta.fHasSecondaryColorOutput = fFS.hasSecondaryOutput();
for (const auto& attr : this->primitiveProcessor().vertexAttributes()) {
meta.fAttributeNames.emplace_back(attr.name());
}
for (const auto& attr : this->primitiveProcessor().instanceAttributes()) {
meta.fAttributeNames.emplace_back(attr.name());
}
auto data = GrPersistentCacheUtils::PackCachedShaders(isSkSL ? kSKSL_Tag : kGLSL_Tag,
shaders, &inputs, 1, &settings);
shaders, &inputs, 1, &meta);
this->gpu()->getContext()->priv().getPersistentCache()->store(*key, *data);
}
}
@ -247,12 +258,8 @@ GrGLProgram* GrGLProgramBuilder::finalize(const GrGLPrecompiledProgram* precompi
if (precompiledProgram) {
// This is very similar to when we get program binaries. We even set that flag, as it's
// used to prevent other compile work later, and to force re-querying uniform locations.
// We couldn't bind attribute or program resource locations during the pre-compile, so do
// that now. Those APIs don't take effect until the next link, so re-link the program.
this->addInputVars(precompiledProgram->fInputs);
this->computeCountsAndStrides(programID, primProc, true);
this->bindProgramResourceLocations(programID);
GL_CALL(LinkProgram(programID));
this->computeCountsAndStrides(programID, primProc, false);
usedProgramBinaries = true;
} else if (cached) {
SkReader32 reader(fCached->data(), fCached->size());
@ -416,7 +423,7 @@ GrGLProgram* GrGLProgramBuilder::finalize(const GrGLPrecompiledProgram* precompi
}
isSkSL = true;
}
this->storeShaderInCache(inputs, programID, glsl, isSkSL, settings);
this->storeShaderInCache(inputs, programID, glsl, isSkSL, &settings);
}
return this->createProgram(programID);
}
@ -540,12 +547,15 @@ bool GrGLProgramBuilder::PrecompileProgram(GrGLPrecompiledProgram* precompiledPr
SkTDArray<GrGLuint> shadersToDelete;
SkSL::Program::Settings settings;
settings.fCaps = gpu->glCaps().shaderCaps();
const GrGLCaps& caps = gpu->glCaps();
settings.fCaps = caps.shaderCaps();
settings.fSharpenTextures = gpu->getContext()->priv().options().fSharpenMipmappedTextures;
GrPersistentCacheUtils::ShaderMetadata meta;
meta.fSettings = &settings;
SkSL::String shaders[kGrShaderTypeCount];
SkSL::Program::Inputs inputs;
GrPersistentCacheUtils::UnpackCachedShaders(&reader, shaders, &inputs, 1, &settings);
GrPersistentCacheUtils::UnpackCachedShaders(&reader, shaders, &inputs, 1, &meta);
auto compileShader = [&](SkSL::Program::Kind kind, const SkSL::String& sksl, GrGLenum type) {
SkSL::String glsl;
@ -577,6 +587,20 @@ bool GrGLProgramBuilder::PrecompileProgram(GrGLPrecompiledProgram* precompiledPr
return false;
}
for (int i = 0; i < meta.fAttributeNames.count(); ++i) {
GR_GL_CALL(gpu->glInterface(), BindAttribLocation(programID, i,
meta.fAttributeNames[i].c_str()));
}
if (meta.fHasCustomColorOutput && caps.bindFragDataLocationSupport()) {
GR_GL_CALL(gpu->glInterface(), BindFragDataLocation(programID, 0,
GrGLSLFragmentShaderBuilder::DeclaredColorOutputName()));
}
if (meta.fHasSecondaryColorOutput && caps.shaderCaps()->mustDeclareFragmentShaderOutput()) {
GR_GL_CALL(gpu->glInterface(), BindFragDataLocationIndexed(programID, 0, 1,
GrGLSLFragmentShaderBuilder::DeclaredSecondaryColorOutputName()));
}
GR_GL_CALL(gpu->glInterface(), LinkProgram(programID));
GrGLint linked = GR_GL_INIT_ZERO;
GR_GL_CALL(gpu->glInterface(), GetProgramiv(programID, GR_GL_LINK_STATUS, &linked));

View File

@ -77,7 +77,7 @@ private:
bool bindAttribLocations);
void storeShaderInCache(const SkSL::Program::Inputs& inputs, GrGLuint programID,
const SkSL::String shaders[], bool isSkSL,
const SkSL::Program::Settings& settings);
SkSL::Program::Settings* settings);
GrGLProgram* finalize(const GrGLPrecompiledProgram*);
void bindProgramResourceLocations(GrGLuint programID);
bool checkLinkStatus(GrGLuint programID, GrContextOptions::ShaderErrorHandler* errorHandler,

View File

@ -138,14 +138,12 @@ int GrVkPipelineStateBuilder::loadShadersFromCache(SkReader32* cached,
void GrVkPipelineStateBuilder::storeShadersInCache(const SkSL::String shaders[],
const SkSL::Program::Inputs inputs[],
bool isSkSL,
const SkSL::Program::Settings& settings) {
bool isSkSL) {
Desc* desc = static_cast<Desc*>(this->desc());
sk_sp<SkData> key = SkData::MakeWithoutCopy(desc->asKey(), desc->shaderKeyLength());
sk_sp<SkData> data = GrPersistentCacheUtils::PackCachedShaders(isSkSL ? kSKSL_Tag : kSPIRV_Tag,
shaders,
inputs, kGrShaderTypeCount,
&settings);
inputs, kGrShaderTypeCount);
this->gpu()->getContext()->priv().getPersistentCache()->store(*key, *data);
}
@ -290,7 +288,7 @@ GrVkPipelineState* GrVkPipelineStateBuilder::finalize(const GrStencilSettings& s
}
isSkSL = true;
}
this->storeShadersInCache(shaders, inputs, isSkSL, settings);
this->storeShadersInCache(shaders, inputs, isSkSL);
}
}
GrVkPipeline* pipeline = resourceProvider.createPipeline(

View File

@ -96,7 +96,7 @@ private:
VkPipelineShaderStageCreateInfo* outStageInfo);
void storeShadersInCache(const SkSL::String shaders[], const SkSL::Program::Inputs inputs[],
bool isSkSL, const SkSL::Program::Settings& settings);
bool isSkSL);
bool createVkShaderModule(VkShaderStageFlagBits stage,
const SkSL::String& sksl,

View File

@ -2181,8 +2181,7 @@ void Viewer::drawImGui() {
auto data = GrPersistentCacheUtils::PackCachedShaders(entry.fShaderType,
entry.fShader,
entry.fInputs,
kGrShaderTypeCount,
nullptr);
kGrShaderTypeCount);
fPersistentCache.store(*entry.fKey, *data);
entry.fShader[kFragment_GrShaderType] = backup;