From e294fa8c919b2043fdbd742e5b4ec9b67a5cdaeb Mon Sep 17 00:00:00 2001 From: PixelyIon Date: Mon, 28 Mar 2022 14:41:37 +0530 Subject: [PATCH] Add subpass limit quirk to fix Adreno driver bug Older Adreno proprietary drivers (5xx and below) will segfault while destroying the renderpass and associated objects if more than 64 subpasses are within a renderpass due to internal driver implementation details. This commit introduces checks to automatically break up a renderpass when that limit is hit. --- .idea/scopes/ShaderCompiler.xml | 2 +- .../main/cpp/skyline/gpu/interconnect/command_executor.cpp | 6 +++++- .../main/cpp/skyline/gpu/interconnect/command_executor.h | 1 + app/src/main/cpp/skyline/gpu/texture/texture.cpp | 2 +- app/src/main/cpp/skyline/gpu/trait_manager.cpp | 6 ++++-- app/src/main/cpp/skyline/gpu/trait_manager.h | 1 + 6 files changed, 13 insertions(+), 5 deletions(-) diff --git a/.idea/scopes/ShaderCompiler.xml b/.idea/scopes/ShaderCompiler.xml index 0077ad7f..54e6e2d6 100644 --- a/.idea/scopes/ShaderCompiler.xml +++ b/.idea/scopes/ShaderCompiler.xml @@ -1,3 +1,3 @@ - + \ No newline at end of file diff --git a/app/src/main/cpp/skyline/gpu/interconnect/command_executor.cpp b/app/src/main/cpp/skyline/gpu/interconnect/command_executor.cpp index 099bb8a1..29ba9b54 100644 --- a/app/src/main/cpp/skyline/gpu/interconnect/command_executor.cpp +++ b/app/src/main/cpp/skyline/gpu/interconnect/command_executor.cpp @@ -12,15 +12,18 @@ namespace skyline::gpu::interconnect { } bool CommandExecutor::CreateRenderPass(vk::Rect2D renderArea) { - if (renderPass && renderPass->renderArea != renderArea) { + if (renderPass && (renderPass->renderArea != renderArea || subpassCount > gpu.traits.quirks.maxSubpassCount)) { nodes.emplace_back(std::in_place_type_t()); renderPass = nullptr; + subpassCount = 0; } bool newRenderPass{renderPass == nullptr}; if (newRenderPass) // We need to create a render pass if one doesn't already exist or the current one isn't compatible renderPass = &std::get(nodes.emplace_back(std::in_place_type_t(), renderArea)); + else + subpassCount++; return newRenderPass; } @@ -119,6 +122,7 @@ namespace skyline::gpu::interconnect { if (renderPass) { nodes.emplace_back(std::in_place_type_t()); renderPass = nullptr; + subpassCount = 0; } { diff --git a/app/src/main/cpp/skyline/gpu/interconnect/command_executor.h b/app/src/main/cpp/skyline/gpu/interconnect/command_executor.h index 88fea99a..3388cd7b 100644 --- a/app/src/main/cpp/skyline/gpu/interconnect/command_executor.h +++ b/app/src/main/cpp/skyline/gpu/interconnect/command_executor.h @@ -18,6 +18,7 @@ namespace skyline::gpu::interconnect { CommandScheduler::ActiveCommandBuffer activeCommandBuffer; boost::container::stable_vector nodes; node::RenderPassNode *renderPass{}; + size_t subpassCount{}; //!< The number of subpasses in the current render pass std::unordered_set syncTextures; //!< All textures that need to be synced prior to and after execution using SharedBufferDelegate = std::shared_ptr; diff --git a/app/src/main/cpp/skyline/gpu/texture/texture.cpp b/app/src/main/cpp/skyline/gpu/texture/texture.cpp index 6058a983..31155aa8 100644 --- a/app/src/main/cpp/skyline/gpu/texture/texture.cpp +++ b/app/src/main/cpp/skyline/gpu/texture/texture.cpp @@ -529,7 +529,7 @@ namespace skyline::gpu { } if (gpu.traits.quirks.vkImageMutableFormatCostly && pFormat->vkFormat != format->vkFormat) - Logger::Warn("Creating a view of a texture with a different format without mutable format"); + Logger::Warn("Creating a view of a texture with a different format without mutable format: {} - {}", vk::to_string(pFormat->vkFormat), vk::to_string(format->vkFormat)); auto view{std::make_shared(shared_from_this(), type, range, pFormat, mapping)}; views.push_back(view); diff --git a/app/src/main/cpp/skyline/gpu/trait_manager.cpp b/app/src/main/cpp/skyline/gpu/trait_manager.cpp index a39651aa..b3475c53 100644 --- a/app/src/main/cpp/skyline/gpu/trait_manager.cpp +++ b/app/src/main/cpp/skyline/gpu/trait_manager.cpp @@ -133,6 +133,8 @@ namespace skyline::gpu { needsIndividualTextureBindingWrites = true; vkImageMutableFormatCostly = true; // Disables UBWC brokenDescriptorAliasing = true; + if (deviceProperties.driverVersion < VK_MAKE_VERSION(512, 600, 0)) + maxSubpassCount = 64; // Driver will segfault while destroying the renderpass and associated objects if this is exceeded on all 5xx and below drivers break; } @@ -148,8 +150,8 @@ namespace skyline::gpu { std::string TraitManager::QuirkManager::Summary() { return fmt::format( - "\n* Needs Individual Texture Binding Writes: {}\n* VkImage Mutable Format is costly: {}", - needsIndividualTextureBindingWrites, vkImageMutableFormatCostly + "\n* Needs Individual Texture Binding Writes: {}\n* VkImage Mutable Format is costly: {}\n* Broken Descriptor Aliasing: {}\n* Max Subpass Count: {}", + needsIndividualTextureBindingWrites, vkImageMutableFormatCostly, brokenDescriptorAliasing, maxSubpassCount ); } diff --git a/app/src/main/cpp/skyline/gpu/trait_manager.h b/app/src/main/cpp/skyline/gpu/trait_manager.h index 41a19c9f..5a23aa3e 100644 --- a/app/src/main/cpp/skyline/gpu/trait_manager.h +++ b/app/src/main/cpp/skyline/gpu/trait_manager.h @@ -42,6 +42,7 @@ namespace skyline::gpu { bool needsIndividualTextureBindingWrites{}; //!< [Adreno Proprietary] A bug that requires descriptor set writes for VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER to be done individually with descriptorCount = 1 rather than batched bool vkImageMutableFormatCostly{}; //!< [Adreno Proprietary/Freedreno] An indication that VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT is costly and should not be enabled unless absolutely necessary (Disables UBWC on Adreno GPUs) bool brokenDescriptorAliasing{}; //!< [Adreno Proprietary] A bug that causes alised descriptor sets to be incorrectly interpreted by the shader compiler leading to it buggering up LLVM function argument types and crashing + u32 maxSubpassCount{std::numeric_limits::max()}; //!< The maximum amount of subpasses within a renderpass, this is limited to 64 on older Adreno proprietary drivers QuirkManager() = default;