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:
parent
497365778e
commit
4524e84a74
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
|
@ -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,
|
||||
|
@ -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(
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user