Serialise pipeline cache in vkshaders.cache

This commit is contained in:
baldurk
2020-04-22 15:11:53 +01:00
parent e034defb0e
commit ed799cb1e3
6 changed files with 149 additions and 12 deletions
+6 -6
View File
@@ -170,8 +170,8 @@ static void create(WrappedVulkan *driver, const char *objName, const int line, V
0,
};
VkResult vkr = driver->vkCreateComputePipelines(driver->GetDev(), VK_NULL_HANDLE, 1,
&compPipeInfo, NULL, pipe);
VkResult vkr = driver->vkCreateComputePipelines(
driver->GetDev(), driver->GetShaderCache()->GetPipeCache(), 1, &compPipeInfo, NULL, pipe);
if(vkr != VK_SUCCESS)
RDCERR("Failed creating object %s at line %i, vkr was %s", objName, line, ToStr(vkr).c_str());
}
@@ -213,8 +213,8 @@ static void create(WrappedVulkan *driver, const char *objName, const int line, V
0,
};
vkr = driver->vkCreateComputePipelines(driver->GetDev(), VK_NULL_HANDLE, 1, &compPipeInfo, NULL,
pipe);
vkr = driver->vkCreateComputePipelines(driver->GetDev(), driver->GetShaderCache()->GetPipeCache(),
1, &compPipeInfo, NULL, pipe);
if(vkr != VK_SUCCESS)
RDCERR("Failed creating object %s at line %i, vkr was %s", objName, line, ToStr(vkr).c_str());
@@ -389,8 +389,8 @@ static void create(WrappedVulkan *driver, const char *objName, const int line, V
-1, // base pipeline index
};
VkResult vkr = driver->vkCreateGraphicsPipelines(driver->GetDev(), VK_NULL_HANDLE, 1,
&graphicsPipeInfo, NULL, pipe);
VkResult vkr = driver->vkCreateGraphicsPipelines(
driver->GetDev(), driver->GetShaderCache()->GetPipeCache(), 1, &graphicsPipeInfo, NULL, pipe);
if(vkr != VK_SUCCESS)
RDCERR("Failed creating object %s at line %i, vkr was %s", objName, line, ToStr(vkr).c_str());
}
+3
View File
@@ -69,6 +69,7 @@ public:
void CopyArrayToTex2DMS(VkImage destMS, VkImage srcArray, VkExtent3D extent, uint32_t layers,
uint32_t samples, VkFormat fmt);
VkPipelineCache GetPipelineCache() { return m_PipelineCache; }
VkPipeline GetCustomPipeline() { return m_Custom.TexPipeline; }
VkImage GetCustomTexture() { return m_Custom.TexImg; }
VkFramebuffer GetCustomFramebuffer() { return m_Custom.TexFB; }
@@ -132,6 +133,8 @@ private:
// one per depth/stencil output format, per sample count
VkPipeline m_DepthArray2MSPipe[6][4] = {{VK_NULL_HANDLE}};
VkPipelineCache m_PipelineCache = VK_NULL_HANDLE;
struct CustomShaderRendering
{
void Destroy(WrappedVulkan *driver);
+127
View File
@@ -120,6 +120,15 @@ struct VulkanBlobShaderCallbacks
const byte *GetData(SPIRVBlob blob) const { return (const byte *)blob->data(); }
} VulkanShaderCacheCallbacks;
struct VkPipeCacheHeader
{
uint32_t length;
VkPipelineCacheHeaderVersion version;
uint32_t vendorID;
uint32_t deviceID;
byte uuid[VK_UUID_SIZE];
};
VulkanShaderCache::VulkanShaderCache(WrappedVulkan *driver)
{
// Load shader cache, if present
@@ -224,11 +233,79 @@ VulkanShaderCache::VulkanShaderCache(WrappedVulkan *driver)
}
}
{
VkPipelineCacheCreateInfo createInfo = {VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO};
GetPipeCacheBlob();
if(!m_PipeCacheBlob.empty())
{
if(m_PipeCacheBlob.size() < sizeof(VkPipeCacheHeader))
{
m_PipeCacheBlob.clear();
}
else
{
VkPipeCacheHeader *header = (VkPipeCacheHeader *)m_PipeCacheBlob.data();
// check explicitly for incompatibility
if(header->length != sizeof(VkPipeCacheHeader))
{
m_PipeCacheBlob.clear();
RDCLOG("Pipeline cache header length %u is unexpected, not using cache", header->length);
}
else if(header->version != VK_PIPELINE_CACHE_HEADER_VERSION_ONE)
{
m_PipeCacheBlob.clear();
RDCLOG("Pipeline cache header version %u is unexpected, not using cache", header->version);
}
else if(header->vendorID != m_pDriver->GetDeviceProps().vendorID)
{
m_PipeCacheBlob.clear();
RDCLOG("Pipeline cache header vendorID %u doesn't match %u", header->vendorID,
m_pDriver->GetDeviceProps().vendorID);
}
else if(header->deviceID != m_pDriver->GetDeviceProps().deviceID)
{
m_PipeCacheBlob.clear();
RDCLOG("Pipeline cache header deviceID %u doesn't match %u", header->deviceID,
m_pDriver->GetDeviceProps().deviceID);
}
else if(memcmp(header->uuid, m_pDriver->GetDeviceProps().pipelineCacheUUID, VK_UUID_SIZE) != 0)
{
m_PipeCacheBlob.clear();
RDCLOG("Pipeline cache UUID doesn't match");
}
}
}
if(!m_PipeCacheBlob.empty())
{
createInfo.initialDataSize = m_PipeCacheBlob.size();
createInfo.pInitialData = m_PipeCacheBlob.data();
}
VkResult vkr = driver->vkCreatePipelineCache(m_Device, &createInfo, NULL, &m_PipelineCache);
RDCASSERTEQUAL(vkr, VK_SUCCESS);
}
SetCaching(false);
}
VulkanShaderCache::~VulkanShaderCache()
{
if(m_PipelineCache != VK_NULL_HANDLE)
{
bytebuf blob;
size_t size = 0;
ObjDisp(m_Device)->GetPipelineCacheData(Unwrap(m_Device), Unwrap(m_PipelineCache), &size, NULL);
blob.resize(size);
ObjDisp(m_Device)->GetPipelineCacheData(Unwrap(m_Device), Unwrap(m_PipelineCache), &size,
blob.data());
SetPipeCacheBlob(blob);
m_pDriver->vkDestroyPipelineCache(m_Device, m_PipelineCache, NULL);
}
if(m_ShaderCacheDirty)
{
SaveShaderCache("vkshaders.cache", m_ShaderCacheMagic, m_ShaderCacheVersion, m_ShaderCache,
@@ -289,6 +366,56 @@ rdcstr VulkanShaderCache::GetSPIRVBlob(const rdcspv::CompilationSettings &settin
return errors;
}
void VulkanShaderCache::GetPipeCacheBlob()
{
m_PipeCacheBlob.clear();
uint32_t hash = strhash(StringFormat::Fmt("PipelineCache%x%x", m_pDriver->GetDeviceProps().vendorID,
m_pDriver->GetDeviceProps().deviceID)
.c_str());
auto it = m_ShaderCache.find(hash);
if(it != m_ShaderCache.end())
{
SPIRVBlob blob = it->second;
// first uint32_t is the real byte size, since we rounded up to the nearest uint32 to store in a
// SPIRVBlob
uint32_t size = blob->at(0);
if(size == rdcspv::MagicNumber)
{
RDCLOG("Hash collision - pipeline cache trampled");
return;
}
m_PipeCacheBlob.resize(size);
memcpy(m_PipeCacheBlob.data(), blob->data() + 1, m_PipeCacheBlob.size());
}
}
void VulkanShaderCache::SetPipeCacheBlob(bytebuf &blob)
{
if(m_PipeCacheBlob == blob)
return;
VkPipeCacheHeader *header = (VkPipeCacheHeader *)blob.data();
uint32_t hash =
strhash(StringFormat::Fmt("PipelineCache%x%x", header->vendorID, header->deviceID).c_str());
rdcarray<uint32_t> *spirvBlob = new rdcarray<uint32_t>();
// align the size up to the nearest 4, and add one extra for us to store the real byte size
spirvBlob->resize(AlignUp4(blob.size()) / 4 + 1);
// store the size, then the real data after that
(*spirvBlob)[0] = (uint32_t)blob.size();
memcpy(spirvBlob->data() + 1, blob.data(), blob.size());
m_ShaderCache[hash] = spirvBlob;
m_ShaderCacheDirty = true;
}
void VulkanShaderCache::MakeGraphicsPipelineInfo(VkGraphicsPipelineCreateInfo &pipeCreateInfo,
ResourceId pipeline)
{
+7 -1
View File
@@ -74,7 +74,7 @@ public:
{
return m_BuiltinShaderModules[(size_t)builtin];
}
VkPipelineCache GetPipeCache() { return m_PipelineCache; }
void MakeGraphicsPipelineInfo(VkGraphicsPipelineCreateInfo &pipeCreateInfo, ResourceId pipeline);
void MakeComputePipelineInfo(VkComputePipelineCreateInfo &pipeCreateInfo, ResourceId pipeline);
@@ -84,9 +84,15 @@ private:
static const uint32_t m_ShaderCacheMagic = 0xf00d00d5;
static const uint32_t m_ShaderCacheVersion = 1;
void GetPipeCacheBlob();
void SetPipeCacheBlob(bytebuf &blob);
WrappedVulkan *m_pDriver = NULL;
VkDevice m_Device = VK_NULL_HANDLE;
bytebuf m_PipeCacheBlob;
VkPipelineCache m_PipelineCache = VK_NULL_HANDLE;
rdcstr m_GlobalDefines;
bool m_ShaderCacheDirty = false, m_CacheShaders = false;
+5 -4
View File
@@ -1170,8 +1170,9 @@ private:
};
VkPipeline pipe = VK_NULL_HANDLE;
VkResult vkr = m_pDriver->vkCreateGraphicsPipelines(m_pDriver->GetDev(), VK_NULL_HANDLE, 1,
&graphicsPipeInfo, NULL, &pipe);
VkResult vkr = m_pDriver->vkCreateGraphicsPipelines(m_pDriver->GetDev(),
m_pDriver->GetShaderCache()->GetPipeCache(),
1, &graphicsPipeInfo, NULL, &pipe);
if(vkr != VK_SUCCESS)
{
RDCERR("Failed creating debug pipeline");
@@ -3121,8 +3122,8 @@ ShaderDebugTrace *VulkanReplay::DebugPixel(uint32_t eventId, uint32_t x, uint32_
}
VkPipeline inputsPipe;
vkr =
m_pDriver->vkCreateGraphicsPipelines(dev, VK_NULL_HANDLE, 1, &graphicsInfo, NULL, &inputsPipe);
vkr = m_pDriver->vkCreateGraphicsPipelines(dev, m_pDriver->GetShaderCache()->GetPipeCache(), 1,
&graphicsInfo, NULL, &inputsPipe);
RDCASSERTEQUAL(vkr, VK_SUCCESS);
// make copy of state to draw from
@@ -394,7 +394,7 @@ VkResult WrappedVulkan::vkGetPipelineCacheData(VkDevice device, VkPipelineCache
uint32_t *ptr = (uint32_t *)pData;
ptr[0] = (uint32_t)totalSize;
ptr[0] = 16 + VK_UUID_SIZE;
ptr[1] = VK_PIPELINE_CACHE_HEADER_VERSION_ONE;
// just in case the user expects a valid vendorID/deviceID, write the real one
// MULTIDEVICE need to get the right physical device for this device