Update SPIRV caching to use SkWriter32/SkReader32 and allow inspection

Change-Id: I6656d971c05f0ed3515f095ffcd41ae73a5c483f
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/206687
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
This commit is contained in:
Brian Osman 2019-04-08 15:01:32 -04:00 committed by Skia Commit-Bot
parent c328be8947
commit a5a010b8cd
3 changed files with 49 additions and 108 deletions

View File

@ -14,7 +14,9 @@
#include "SkSLString.h" #include "SkSLString.h"
#include "SkWriter32.h" #include "SkWriter32.h"
// Pack/unpack functions, to be shared by backend and debugging utils? // The GrPersistentCache stores opaque blobs, as far as clients are concerned. It's helpful to
// inspect certain kinds of cached data within our tools, so for those cases (GLSL, SPIR-V), we
// put the serialization logic here, to be shared by the backend code and the tool code.
namespace GrPersistentCacheUtils { namespace GrPersistentCacheUtils {
static inline void PackCachedGLSL(SkWriter32& writer, const SkSL::Program::Inputs& inputs, static inline void PackCachedGLSL(SkWriter32& writer, const SkSL::Program::Inputs& inputs,
@ -35,6 +37,24 @@ static inline void UnpackCachedGLSL(SkReader32& reader, SkSL::Program::Inputs* i
} }
} }
static inline void PackCachedSPIRV(SkWriter32& writer, const SkSL::String shaders[],
const SkSL::Program::Inputs inputs[]) {
for (int i = 0; i < kGrShaderTypeCount; ++i) {
writer.writeString(shaders[i].c_str(), shaders[i].size());
writer.writePad(&inputs[i], sizeof(inputs[i]));
}
}
static inline void UnpackCachedSPIRV(SkReader32& reader, SkSL::String shaders[],
SkSL::Program::Inputs inputs[]) {
for (int i = 0; i < kGrShaderTypeCount; ++i) {
size_t stringLen = 0;
const char* string = reader.readString(&stringLen);
shaders[i] = SkSL::String(string, stringLen);
reader.read(&inputs[i], sizeof(inputs[i]));
}
}
} }
#endif #endif

View File

@ -8,6 +8,7 @@
#include "vk/GrVkPipelineStateBuilder.h" #include "vk/GrVkPipelineStateBuilder.h"
#include "GrContext.h" #include "GrContext.h"
#include "GrContextPriv.h" #include "GrContextPriv.h"
#include "GrPersistentCacheUtils.h"
#include "GrShaderCaps.h" #include "GrShaderCaps.h"
#include "GrStencilSettings.h" #include "GrStencilSettings.h"
#include "GrVkRenderTarget.h" #include "GrVkRenderTarget.h"
@ -113,118 +114,47 @@ int GrVkPipelineStateBuilder::loadShadersFromCache(const SkData& cached,
VkShaderModule* outFragShaderModule, VkShaderModule* outFragShaderModule,
VkShaderModule* outGeomShaderModule, VkShaderModule* outGeomShaderModule,
VkPipelineShaderStageCreateInfo* outStageInfo) { VkPipelineShaderStageCreateInfo* outStageInfo) {
// format for shader cache entries is: SkSL::String shaders[kGrShaderTypeCount];
// shader_size vertSize; SkSL::Program::Inputs inputs[kGrShaderTypeCount];
// char[vertSize] vert;
// SkSL::Program::Inputs vertInputs;
// shader_size fragSize;
// char[fragSize] frag;
// SkSL::Program::Inputs fragInputs;
// shader_size geomSize;
// char[geomSize] geom;
// SkSL::Program::Inputs geomInputs;
size_t offset = 0;
// vertex shader SkReader32 reader(cached.data(), cached.size());
shader_size vertSize = *((shader_size*) ((char*) cached.data() + offset)); GrPersistentCacheUtils::UnpackCachedSPIRV(reader, shaders, inputs);
offset += sizeof(shader_size);
SkSL::String vert((char*) cached.data() + offset, vertSize);
offset += vertSize;
SkSL::Program::Inputs vertInputs;
memcpy(&vertInputs, (char*) cached.data() + offset, sizeof(vertInputs));
offset += sizeof(vertInputs);
// fragment shader
shader_size fragSize = *((shader_size*) ((char*) cached.data() + offset));
offset += sizeof(shader_size);
SkSL::String frag((char*) cached.data() + offset, fragSize);
offset += fragSize;
SkSL::Program::Inputs fragInputs;
memcpy(&fragInputs, (char*) cached.data() + offset, sizeof(fragInputs));
offset += sizeof(fragInputs);
// geometry shader
shader_size geomSize = *((shader_size*) ((char*) cached.data() + offset));
offset += sizeof(shader_size);
SkSL::String geom((char*) cached.data() + offset, geomSize);
offset += geomSize;
SkSL::Program::Inputs geomInputs;
memcpy(&geomInputs, (char*) cached.data() + offset, sizeof(geomInputs));
offset += sizeof(geomInputs);
SkASSERT(offset == cached.size());
SkAssertResult(this->installVkShaderModule(VK_SHADER_STAGE_VERTEX_BIT, SkAssertResult(this->installVkShaderModule(VK_SHADER_STAGE_VERTEX_BIT,
fVS, fVS,
outVertShaderModule, outVertShaderModule,
&outStageInfo[0], &outStageInfo[0],
vert, shaders[kVertex_GrShaderType],
vertInputs)); inputs[kVertex_GrShaderType]));
SkAssertResult(this->installVkShaderModule(VK_SHADER_STAGE_FRAGMENT_BIT, SkAssertResult(this->installVkShaderModule(VK_SHADER_STAGE_FRAGMENT_BIT,
fFS, fFS,
outFragShaderModule, outFragShaderModule,
&outStageInfo[1], &outStageInfo[1],
frag, shaders[kFragment_GrShaderType],
fragInputs)); inputs[kFragment_GrShaderType]));
if (geomSize) { if (!shaders[kGeometry_GrShaderType].empty()) {
SkAssertResult(this->installVkShaderModule(VK_SHADER_STAGE_GEOMETRY_BIT, SkAssertResult(this->installVkShaderModule(VK_SHADER_STAGE_GEOMETRY_BIT,
fGS, fGS,
outGeomShaderModule, outGeomShaderModule,
&outStageInfo[2], &outStageInfo[2],
geom, shaders[kGeometry_GrShaderType],
geomInputs)); inputs[kGeometry_GrShaderType]));
return 3; return 3;
} else { } else {
return 2; return 2;
} }
} }
void GrVkPipelineStateBuilder::storeShadersInCache(const SkSL::String& vert, void GrVkPipelineStateBuilder::storeShadersInCache(const SkSL::String shaders[],
const SkSL::Program::Inputs& vertInputs, const SkSL::Program::Inputs inputs[]) {
const SkSL::String& frag,
const SkSL::Program::Inputs& fragInputs,
const SkSL::String& geom,
const SkSL::Program::Inputs& geomInputs) {
Desc* desc = static_cast<Desc*>(this->desc()); Desc* desc = static_cast<Desc*>(this->desc());
// see loadShadersFromCache for the layout of cache entries
sk_sp<SkData> key = SkData::MakeWithoutCopy(desc->asKey(), desc->shaderKeyLength()); sk_sp<SkData> key = SkData::MakeWithoutCopy(desc->asKey(), desc->shaderKeyLength());
size_t dataLength = (sizeof(shader_size) + sizeof(SkSL::Program::Inputs)) * 3 + vert.length() + SkWriter32 writer;
frag.length() + geom.length(); GrPersistentCacheUtils::PackCachedSPIRV(writer, shaders, inputs);
std::unique_ptr<uint8_t[]> data(new uint8_t[dataLength]); auto data = writer.snapshotAsData();
size_t offset = 0; this->gpu()->getContext()->priv().getPersistentCache()->store(*key, *data);
// vertex shader
*((shader_size*) (data.get() + offset)) = (shader_size) vert.length();
offset += sizeof(shader_size);
memcpy(data.get() + offset, vert.data(), vert.length());
offset += vert.length();
memcpy(data.get() + offset, &vertInputs, sizeof(vertInputs));
offset += sizeof(vertInputs);
// fragment shader
*((shader_size*) (data.get() + offset)) = (shader_size) frag.length();
offset += sizeof(shader_size);
memcpy(data.get() + offset, frag.data(), frag.length());
offset += frag.length();
memcpy(data.get() + offset, &fragInputs, sizeof(fragInputs));
offset += sizeof(fragInputs);
// geometry shader
*((shader_size*) (data.get() + offset)) = (shader_size) geom.length();
offset += sizeof(shader_size);
memcpy(data.get() + offset, geom.data(), geom.length());
offset += geom.length();
memcpy(data.get() + offset, &geomInputs, sizeof(geomInputs));
offset += sizeof(geomInputs);
SkASSERT(offset == dataLength);
this->gpu()->getContext()->priv().getPersistentCache()->store(
*key,
*SkData::MakeWithoutCopy(data.get(), dataLength));
} }
GrVkPipelineState* GrVkPipelineStateBuilder::finalize(const GrStencilSettings& stencil, GrVkPipelineState* GrVkPipelineStateBuilder::finalize(const GrStencilSettings& stencil,
@ -292,20 +222,16 @@ GrVkPipelineState* GrVkPipelineStateBuilder::finalize(const GrStencilSettings& s
&geomShaderModule, shaderStageInfo); &geomShaderModule, shaderStageInfo);
} else { } else {
numShaderStages = 2; // We always have at least vertex and fragment stages. numShaderStages = 2; // We always have at least vertex and fragment stages.
SkSL::String vert; SkSL::String shaders[kGrShaderTypeCount];
SkSL::Program::Inputs vertInputs; SkSL::Program::Inputs inputs[kGrShaderTypeCount];
SkSL::String frag;
SkSL::Program::Inputs fragInputs;
SkSL::String geom;
SkSL::Program::Inputs geomInputs;
SkAssertResult(this->createVkShaderModule(VK_SHADER_STAGE_VERTEX_BIT, SkAssertResult(this->createVkShaderModule(VK_SHADER_STAGE_VERTEX_BIT,
fVS, fVS,
&vertShaderModule, &vertShaderModule,
&shaderStageInfo[0], &shaderStageInfo[0],
settings, settings,
desc, desc,
&vert, &shaders[kVertex_GrShaderType],
&vertInputs)); &inputs[kVertex_GrShaderType]));
SkAssertResult(this->createVkShaderModule(VK_SHADER_STAGE_FRAGMENT_BIT, SkAssertResult(this->createVkShaderModule(VK_SHADER_STAGE_FRAGMENT_BIT,
fFS, fFS,
@ -313,8 +239,8 @@ GrVkPipelineState* GrVkPipelineStateBuilder::finalize(const GrStencilSettings& s
&shaderStageInfo[1], &shaderStageInfo[1],
settings, settings,
desc, desc,
&frag, &shaders[kFragment_GrShaderType],
&fragInputs)); &inputs[kFragment_GrShaderType]));
if (this->primitiveProcessor().willUseGeoShader()) { if (this->primitiveProcessor().willUseGeoShader()) {
SkAssertResult(this->createVkShaderModule(VK_SHADER_STAGE_GEOMETRY_BIT, SkAssertResult(this->createVkShaderModule(VK_SHADER_STAGE_GEOMETRY_BIT,
@ -323,12 +249,12 @@ GrVkPipelineState* GrVkPipelineStateBuilder::finalize(const GrStencilSettings& s
&shaderStageInfo[2], &shaderStageInfo[2],
settings, settings,
desc, desc,
&geom, &shaders[kGeometry_GrShaderType],
&geomInputs)); &inputs[kGeometry_GrShaderType]));
++numShaderStages; ++numShaderStages;
} }
if (persistentCache) { if (persistentCache) {
this->storeShadersInCache(vert, vertInputs, frag, fragInputs, geom, geomInputs); this->storeShadersInCache(shaders, inputs);
} }
} }
GrVkPipeline* pipeline = resourceProvider.createPipeline( GrVkPipeline* pipeline = resourceProvider.createPipeline(

View File

@ -97,12 +97,7 @@ private:
VkShaderModule* outGeomShaderModule, VkShaderModule* outGeomShaderModule,
VkPipelineShaderStageCreateInfo* outStageInfo); VkPipelineShaderStageCreateInfo* outStageInfo);
void storeShadersInCache(const SkSL::String& vert, void storeShadersInCache(const SkSL::String shaders[], const SkSL::Program::Inputs inputs[]);
const SkSL::Program::Inputs& vertInputs,
const SkSL::String& frag,
const SkSL::Program::Inputs& fragInputs,
const SkSL::String& geom,
const SkSL::Program::Inputs& geomInputs);
bool createVkShaderModule(VkShaderStageFlagBits stage, bool createVkShaderModule(VkShaderStageFlagBits stage,
const GrGLSLShaderBuilder& builder, const GrGLSLShaderBuilder& builder,