From 8a3e92aa387291471f4e224e520365c65ebc1df3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 1 Dec 2022 23:41:31 +0100 Subject: [PATCH] Not pretty, but with this, you can switch MSAA level at runtime. --- Common/Data/Convert/SmallDataConvert.h | 2 +- Common/GPU/Vulkan/VulkanQueueRunner.cpp | 6 ++---- Common/GPU/Vulkan/VulkanRenderManager.cpp | 7 +++++-- Common/GPU/Vulkan/VulkanRenderManager.h | 4 +++- Common/GPU/Vulkan/thin3d_vulkan.cpp | 2 +- GPU/Common/FramebufferManagerCommon.cpp | 13 ++++++++----- GPU/Common/FramebufferManagerCommon.h | 2 ++ GPU/GPUCommon.h | 2 +- GPU/Vulkan/GPU_Vulkan.cpp | 8 ++++++++ GPU/Vulkan/GPU_Vulkan.h | 1 + GPU/Vulkan/PipelineManagerVulkan.cpp | 6 ++++++ GPU/Vulkan/PipelineManagerVulkan.h | 2 ++ 12 files changed, 40 insertions(+), 15 deletions(-) diff --git a/Common/Data/Convert/SmallDataConvert.h b/Common/Data/Convert/SmallDataConvert.h index 05f92759c7..e1aee3226b 100644 --- a/Common/Data/Convert/SmallDataConvert.h +++ b/Common/Data/Convert/SmallDataConvert.h @@ -21,7 +21,7 @@ extern const float one_over_255_x4[4]; extern const float exactly_255_x4[4]; // Utilities useful for filling in std140-layout uniform buffers, and similar. -// NEON intrinsics: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0491f/BABDCGGF.html +// NEON intrinsics: https://developer.arm.com/documentation/den0018/a/NEON-Intrinsics?lang=en // LSBs in f[0], etc. inline void Uint8x4ToFloat4(float f[4], uint32_t u) { diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.cpp b/Common/GPU/Vulkan/VulkanQueueRunner.cpp index 7f7585c28e..644f019dc0 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.cpp +++ b/Common/GPU/Vulkan/VulkanQueueRunner.cpp @@ -1327,10 +1327,8 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c VkSampleCountFlagBits fbSampleCount = step.render.framebuffer ? step.render.framebuffer->sampleCount : VK_SAMPLE_COUNT_1_BIT; if (RenderPassTypeHasMultisample(rpType) && fbSampleCount != graphicsPipeline->SampleCount()) { - // Sample count might have started mismatching if the user changed multisampling mode. Let's get rid of all variants - // and start over. - // (We could avoid this if sample count was baked into the rpType, but I don't want that to grow too big). - graphicsPipeline->DestroyAllVariants(vulkan_); + // Shouldn't happen, pipeline invalidation after render resized should have taken care of this. + _assert_(false); } if (!graphicsPipeline->pipeline[(size_t)rpType]) { diff --git a/Common/GPU/Vulkan/VulkanRenderManager.cpp b/Common/GPU/Vulkan/VulkanRenderManager.cpp index a8d8e5db42..4f95a24458 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.cpp +++ b/Common/GPU/Vulkan/VulkanRenderManager.cpp @@ -130,10 +130,13 @@ bool VKRGraphicsPipeline::Create(VulkanContext *vulkan, VkRenderPass compatibleR return success; } -void VKRGraphicsPipeline::DestroyAllVariants(VulkanContext *vulkan) { +void VKRGraphicsPipeline::DestroyVariants(VulkanContext *vulkan, bool msaaOnly) { for (size_t i = 0; i < (size_t)RenderPassType::TYPE_COUNT; i++) { if (!this->pipeline[i]) continue; + if (msaaOnly && (i & (int)RenderPassType::MULTISAMPLE) == 0) + continue; + VkPipeline pipeline = this->pipeline[i]->BlockUntilReady(); // pipeline can be nullptr here, if it failed to compile before. if (pipeline) { @@ -145,7 +148,7 @@ void VKRGraphicsPipeline::DestroyAllVariants(VulkanContext *vulkan) { } void VKRGraphicsPipeline::QueueForDeletion(VulkanContext *vulkan) { - DestroyAllVariants(vulkan); + DestroyVariants(vulkan, false); vulkan->Delete().QueueCallback([](void *p) { VKRGraphicsPipeline *pipeline = (VKRGraphicsPipeline *)p; delete pipeline; diff --git a/Common/GPU/Vulkan/VulkanRenderManager.h b/Common/GPU/Vulkan/VulkanRenderManager.h index b729b6b09c..c15d9027a2 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.h +++ b/Common/GPU/Vulkan/VulkanRenderManager.h @@ -124,7 +124,7 @@ struct VKRGraphicsPipeline { bool Create(VulkanContext *vulkan, VkRenderPass compatibleRenderPass, RenderPassType rpType, VkSampleCountFlagBits sampleCount); - void DestroyAllVariants(VulkanContext *vulkan); + void DestroyVariants(VulkanContext *vulkan, bool msaaOnly); // This deletes the whole VKRGraphicsPipeline, you must remove your last pointer to it when doing this. void QueueForDeletion(VulkanContext *vulkan); @@ -458,6 +458,8 @@ public: return outOfDateFrames_ > VulkanContext::MAX_INFLIGHT_FRAMES; } + void Invalidate(InvalidationFlags flags); + void ResetStats(); private: diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index da58b35215..258e014910 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -242,7 +242,7 @@ bool VKShaderModule::Compile(VulkanContext *vulkan, ShaderLanguage language, con #endif VkShaderModule shaderModule = VK_NULL_HANDLE; - if (vulkan->CreateShaderModule(spirv, &shaderModule, vkstage_ == VK_SHADER_STAGE_VERTEX_BIT ? "thin3d_vs" : "thin3d_fs")) { + if (vulkan->CreateShaderModule(spirv, &shaderModule, tag_.c_str())) { module_ = Promise::AlreadyDone(shaderModule); ok_ = true; } else { diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index ec68cb15c4..175d36d0bc 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -2878,11 +2878,7 @@ static void DoRelease(T *&obj) { obj = nullptr; } -void FramebufferManagerCommon::DeviceLost() { - DestroyAllFBOs(); - - presentation_->DeviceLost(); - +void FramebufferManagerCommon::ReleasePipelines() { for (int i = 0; i < ARRAY_SIZE(reinterpretFromTo_); i++) { for (int j = 0; j < ARRAY_SIZE(reinterpretFromTo_); j++) { DoRelease(reinterpretFromTo_[i][j]); @@ -2899,9 +2895,16 @@ void FramebufferManagerCommon::DeviceLost() { DoRelease(draw2DPipelineDepth_); DoRelease(draw2DPipeline565ToDepth_); DoRelease(draw2DPipeline565ToDepthDeswizzle_); +} +void FramebufferManagerCommon::DeviceLost() { + DestroyAllFBOs(); + + presentation_->DeviceLost(); draw2D_.DeviceLost(); + ReleasePipelines(); + draw_ = nullptr; } diff --git a/GPU/Common/FramebufferManagerCommon.h b/GPU/Common/FramebufferManagerCommon.h index 0a22fdb366..27380df454 100644 --- a/GPU/Common/FramebufferManagerCommon.h +++ b/GPU/Common/FramebufferManagerCommon.h @@ -443,6 +443,8 @@ public: int scaleFactor, // usually unused, except for swizzle... Draw2DPipeline *pipeline, const char *tag); + void ReleasePipelines(); + protected: virtual void ReadbackFramebufferSync(VirtualFramebuffer *vfb, int x, int y, int w, int h, RasterChannel channel); // Used for when a shader is required, such as GLES. diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index 76b14bdc9e..7d2cde8b12 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -267,7 +267,7 @@ protected: void DeviceLost() override; void DeviceRestore() override; - void CheckRenderResized(); + virtual void CheckRenderResized(); // Add additional common features dependent on other features, which may be backend-determined. u32 CheckGPUFeaturesLate(u32 features) const; diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index f735f3267f..1606073ee9 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -465,6 +465,14 @@ void GPU_Vulkan::DestroyDeviceObjects() { } } +void GPU_Vulkan::CheckRenderResized() { + if (renderResized_) { + GPUCommon::CheckRenderResized(); + pipelineManager_->InvalidateMSAAPipelines(); + framebufferManager_->ReleasePipelines(); + } +} + void GPU_Vulkan::DeviceLost() { CancelReady(); while (!IsReady()) { diff --git a/GPU/Vulkan/GPU_Vulkan.h b/GPU/Vulkan/GPU_Vulkan.h index 1aa405e1f6..f4b56c27e4 100644 --- a/GPU/Vulkan/GPU_Vulkan.h +++ b/GPU/Vulkan/GPU_Vulkan.h @@ -70,6 +70,7 @@ public: protected: void FinishDeferred() override; + void CheckRenderResized() override; private: void Flush() { diff --git a/GPU/Vulkan/PipelineManagerVulkan.cpp b/GPU/Vulkan/PipelineManagerVulkan.cpp index 6b8941be07..0c081c3f78 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.cpp +++ b/GPU/Vulkan/PipelineManagerVulkan.cpp @@ -49,6 +49,12 @@ void PipelineManagerVulkan::Clear() { pipelines_.Clear(); } +void PipelineManagerVulkan::InvalidateMSAAPipelines() { + pipelines_.Iterate([&](const VulkanPipelineKey &key, VulkanPipeline *value) { + value->pipeline->DestroyVariants(vulkan_, true); + }); +} + void PipelineManagerVulkan::DeviceLost() { Clear(); if (pipelineCache_ != VK_NULL_HANDLE) diff --git a/GPU/Vulkan/PipelineManagerVulkan.h b/GPU/Vulkan/PipelineManagerVulkan.h index 831136c955..dcd13c54c5 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.h +++ b/GPU/Vulkan/PipelineManagerVulkan.h @@ -88,6 +88,8 @@ public: void DeviceLost(); void DeviceRestore(VulkanContext *vulkan); + void InvalidateMSAAPipelines(); + std::string DebugGetObjectString(std::string id, DebugShaderType type, DebugShaderStringType stringType); std::vector DebugGetObjectIDs(DebugShaderType type);