Merge pull request #16572 from hrydgard/pipeline-cache-fix

Vulkan pipeline cache: Make it more lenient to useFlags changes
This commit is contained in:
Unknown W. Brackets
2022-12-13 18:08:15 -08:00
committed by GitHub
5 changed files with 54 additions and 27 deletions
+11 -10
View File
@@ -546,17 +546,18 @@ VKRGraphicsPipeline *VulkanRenderManager::CreateGraphicsPipeline(VKRGraphicsPipe
RenderPassType rpType = (RenderPassType)i;
// Sanity check - don't compile incompatible types (could be caused by corrupt caches, changes in data structures, etc).
if (pipelineFlags & PipelineFlags::USES_DEPTH_STENCIL) {
if (!RenderPassTypeHasDepth(rpType)) {
WARN_LOG(G3D, "Not compiling pipeline that requires depth, for non depth renderpass type");
continue;
}
if ((pipelineFlags & PipelineFlags::USES_DEPTH_STENCIL) && !RenderPassTypeHasDepth(rpType)) {
WARN_LOG(G3D, "Not compiling pipeline that requires depth, for non depth renderpass type");
continue;
}
if (pipelineFlags & PipelineFlags::USES_INPUT_ATTACHMENT) {
if (!RenderPassTypeHasInput(rpType)) {
WARN_LOG(G3D, "Not compiling pipeline that requires input attachment, for non input renderpass type");
continue;
}
if ((pipelineFlags & PipelineFlags::USES_INPUT_ATTACHMENT) && !RenderPassTypeHasInput(rpType)) {
WARN_LOG(G3D, "Not compiling pipeline that requires input attachment, for non input renderpass type");
continue;
}
// Shouldn't hit this, these should have been filtered elsewhere. However, still a good check to do.
if (sampleCount == VK_SAMPLE_COUNT_1_BIT && RenderPassTypeHasMultisample(rpType)) {
WARN_LOG(G3D, "Not compiling single sample pipeline for a multisampled render pass type");
continue;
}
pipeline->pipeline[i] = Promise<VkPipeline>::CreateEmpty();
+3 -3
View File
@@ -139,8 +139,8 @@ void GPU_Vulkan::LoadCache(const Path &filename) {
WARN_LOG(G3D, "ShaderManagerVulkan failed to load cache.");
}
if (result) {
// WARNING: See comment in LoadCache if you are tempted to flip the second parameter to true.
result = pipelineManager_->LoadCache(f, false, shaderManagerVulkan_, draw_, drawEngine_.GetPipelineLayout());
// WARNING: See comment in LoadPipelineCache if you are tempted to flip the second parameter to true.
result = pipelineManager_->LoadPipelineCache(f, false, shaderManagerVulkan_, draw_, drawEngine_.GetPipelineLayout());
}
fclose(f);
if (!result) {
@@ -169,7 +169,7 @@ void GPU_Vulkan::SaveCache(const Path &filename) {
return;
shaderManagerVulkan_->SaveCache(f);
// WARNING: See comment in LoadCache if you are tempted to flip the second parameter to true.
pipelineManager_->SaveCache(f, false, shaderManagerVulkan_, draw_);
pipelineManager_->SavePipelineCache(f, false, shaderManagerVulkan_, draw_);
INFO_LOG(G3D, "Saved Vulkan pipeline cache");
fclose(f);
}
+23 -7
View File
@@ -578,7 +578,7 @@ struct StoredVulkanPipelineKey {
// If you're looking for how to invalidate the cache, it's done in ShaderManagerVulkan, look for CACHE_VERSION and increment it.
// (Header of the same file this is stored in).
void PipelineManagerVulkan::SaveCache(FILE *file, bool saveRawPipelineCache, ShaderManagerVulkan *shaderManager, Draw::DrawContext *drawContext) {
void PipelineManagerVulkan::SavePipelineCache(FILE *file, bool saveRawPipelineCache, ShaderManagerVulkan *shaderManager, Draw::DrawContext *drawContext) {
VulkanRenderManager *rm = (VulkanRenderManager *)drawContext->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
VulkanQueueRunner *queueRunner = rm->GetQueueRunner();
@@ -667,10 +667,12 @@ void PipelineManagerVulkan::SaveCache(FILE *file, bool saveRawPipelineCache, Sha
}
}
bool PipelineManagerVulkan::LoadCache(FILE *file, bool loadRawPipelineCache, ShaderManagerVulkan *shaderManager, Draw::DrawContext *drawContext, VkPipelineLayout layout) {
bool PipelineManagerVulkan::LoadPipelineCache(FILE *file, bool loadRawPipelineCache, ShaderManagerVulkan *shaderManager, Draw::DrawContext *drawContext, VkPipelineLayout layout) {
VulkanRenderManager *rm = (VulkanRenderManager *)drawContext->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
VulkanQueueRunner *queueRunner = rm->GetQueueRunner();
cancelCache_ = false;
uint32_t size = 0;
if (loadRawPipelineCache) {
NOTICE_LOG(G3D, "WARNING: Using the badly tested raw pipeline cache path!!!!");
@@ -727,6 +729,7 @@ bool PipelineManagerVulkan::LoadCache(FILE *file, bool loadRawPipelineCache, Sha
NOTICE_LOG(G3D, "Creating %d pipelines from cache...", size);
int pipelineCreateFailCount = 0;
int shaderFailCount = 0;
for (uint32_t i = 0; i < size; i++) {
if (failed || cancelCache_) {
break;
@@ -734,21 +737,33 @@ bool PipelineManagerVulkan::LoadCache(FILE *file, bool loadRawPipelineCache, Sha
StoredVulkanPipelineKey key;
failed = failed || fread(&key, sizeof(key), 1, file) != 1;
if (failed) {
ERROR_LOG(G3D, "Truncated Vulkan pipeline cache file");
continue;
ERROR_LOG(G3D, "Truncated Vulkan pipeline cache file, stopping.");
break;
}
VulkanVertexShader *vs = shaderManager->GetVertexShaderFromID(key.vShaderID);
VulkanFragmentShader *fs = shaderManager->GetFragmentShaderFromID(key.fShaderID);
VulkanGeometryShader *gs = shaderManager->GetGeometryShaderFromID(key.gShaderID);
if (!vs || !fs || (!gs && key.gShaderID.Bit(GS_BIT_ENABLED))) {
failed = true;
ERROR_LOG(G3D, "Failed to find vs or fs in of pipeline %d in cache", (int)i);
// We just ignore this one, it'll get created later if needed.
// Probably some useFlags mismatch.
WARN_LOG(G3D, "Failed to find vs or fs in pipeline %d in cache, skipping pipeline", (int)i);
continue;
}
// Avoid creating multisampled shaders if it's not enabled, as that results in an invalid combination.
u32 variantsToBuild = key.variants;
if (g_Config.iMultiSampleLevel == 0) {
for (u32 i = 0; i < (int)RenderPassType::TYPE_COUNT; i++) {
if (RenderPassTypeHasMultisample((RenderPassType)i)) {
variantsToBuild &= ~(1 << i);
}
}
}
DecVtxFormat fmt;
fmt.InitializeFromID(key.vtxFmtId);
VulkanPipeline *pipeline = GetOrCreatePipeline(rm, layout, key.raster, key.useHWTransform ? &fmt : 0, vs, fs, gs, key.useHWTransform, key.variants);
VulkanPipeline *pipeline = GetOrCreatePipeline(
rm, layout, key.raster, key.useHWTransform ? &fmt : 0, vs, fs, gs, key.useHWTransform, variantsToBuild);
if (!pipeline) {
pipelineCreateFailCount += 1;
}
@@ -757,6 +772,7 @@ bool PipelineManagerVulkan::LoadCache(FILE *file, bool loadRawPipelineCache, Sha
rm->NudgeCompilerThread();
NOTICE_LOG(G3D, "Recreated Vulkan pipeline cache (%d pipelines, %d failed).", (int)size, pipelineCreateFailCount);
// We just ignore any failures.
return true;
}
+2 -2
View File
@@ -98,8 +98,8 @@ public:
std::vector<std::string> DebugGetObjectIDs(DebugShaderType type);
// Saves data for faster creation next time.
void SaveCache(FILE *file, bool saveRawPipelineCache, ShaderManagerVulkan *shaderManager, Draw::DrawContext *drawContext);
bool LoadCache(FILE *file, bool loadRawPipelineCache, ShaderManagerVulkan *shaderManager, Draw::DrawContext *drawContext, VkPipelineLayout layout);
void SavePipelineCache(FILE *file, bool saveRawPipelineCache, ShaderManagerVulkan *shaderManager, Draw::DrawContext *drawContext);
bool LoadPipelineCache(FILE *file, bool loadRawPipelineCache, ShaderManagerVulkan *shaderManager, Draw::DrawContext *drawContext, VkPipelineLayout layout);
void CancelCache();
private:
+15 -5
View File
@@ -515,11 +515,15 @@ bool ShaderManagerVulkan::LoadCache(FILE *f) {
WARN_LOG(G3D, "Shader cache version mismatch, %d, expected %d", header.version, CACHE_VERSION);
return false;
}
if (header.useFlags != gstate_c.GetUseFlags()) {
// This can simply be a result of sawExactEqualDepth_ having been flipped to true in the previous run.
// Let's just keep going.
WARN_LOG(G3D, "Shader cache useFlags mismatch, %08x, expected %08x", header.useFlags, gstate_c.GetUseFlags());
return false;
}
int failCount = 0;
VulkanContext *vulkan = (VulkanContext *)draw_->GetNativeObject(Draw::NativeObject::CONTEXT);
for (int i = 0; i < header.numVertexShaders; i++) {
VShaderID id;
@@ -534,7 +538,9 @@ bool ShaderManagerVulkan::LoadCache(FILE *f) {
VertexShaderFlags flags;
if (!GenerateVertexShader(id, codeBuffer_, compat_, draw_->GetBugs(), &attributeMask, &uniformMask, &flags, &genErrorString)) {
WARN_LOG(G3D, "Failed to generate vertex shader during cache load");
return false;
// We just ignore this one and carry on.
failCount++;
continue;
}
_assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "VS length error: %d", (int)strlen(codeBuffer_));
VulkanVertexShader *vs = new VulkanVertexShader(vulkan, id, flags, codeBuffer_, useHWTransform);
@@ -553,7 +559,9 @@ bool ShaderManagerVulkan::LoadCache(FILE *f) {
FragmentShaderFlags flags;
if (!GenerateFragmentShader(id, codeBuffer_, compat_, draw_->GetBugs(), &uniformMask, &flags, &genErrorString)) {
WARN_LOG(G3D, "Failed to generate fragment shader during cache load");
return false;
// We just ignore this one and carry on.
failCount++;
continue;
}
_assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "FS length error: %d", (int)strlen(codeBuffer_));
VulkanFragmentShader *fs = new VulkanFragmentShader(vulkan, id, flags, codeBuffer_);
@@ -569,14 +577,16 @@ bool ShaderManagerVulkan::LoadCache(FILE *f) {
std::string genErrorString;
if (!GenerateGeometryShader(id, codeBuffer_, compat_, draw_->GetBugs(), &genErrorString)) {
WARN_LOG(G3D, "Failed to generate geometry shader during cache load");
return false;
// We just ignore this one and carry on.
failCount++;
continue;
}
_assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "GS length error: %d", (int)strlen(codeBuffer_));
VulkanGeometryShader *gs = new VulkanGeometryShader(vulkan, id, codeBuffer_);
gsCache_.Insert(id, gs);
}
NOTICE_LOG(G3D, "ShaderCache: Loaded %d vertex, %d fragment shaders and %d geometry shaders", header.numVertexShaders, header.numFragmentShaders, header.numGeometryShaders);
NOTICE_LOG(G3D, "ShaderCache: Loaded %d vertex, %d fragment shaders and %d geometry shaders (failed %d)", header.numVertexShaders, header.numFragmentShaders, header.numGeometryShaders, failCount);
return true;
}