mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-07-11 09:35:09 +02:00
Merge pull request #16572 from hrydgard/pipeline-cache-fix
Vulkan pipeline cache: Make it more lenient to useFlags changes
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user