From 173a33886c72304aea923382ec114679dcad6ba4 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sat, 9 Sep 2017 14:04:26 +1000 Subject: [PATCH] Vulkan: Move render pass management to ObjectCache --- .../Vulkan/FramebufferManager.cpp | 194 ++---------------- .../VideoBackends/Vulkan/FramebufferManager.h | 4 +- .../Core/VideoBackends/Vulkan/ObjectCache.cpp | 87 ++++++++ .../Core/VideoBackends/Vulkan/ObjectCache.h | 10 + .../Core/VideoBackends/Vulkan/SwapChain.cpp | 47 +---- Source/Core/VideoBackends/Vulkan/SwapChain.h | 1 - .../VideoBackends/Vulkan/TextureCache.cpp | 65 +----- .../Core/VideoBackends/Vulkan/TextureCache.h | 5 - .../VideoBackends/Vulkan/TextureConverter.cpp | 75 ++----- .../VideoBackends/Vulkan/TextureConverter.h | 6 +- .../Core/VideoBackends/Vulkan/VKTexture.cpp | 9 +- Source/Core/VideoBackends/Vulkan/main.cpp | 51 +++-- 12 files changed, 178 insertions(+), 376 deletions(-) diff --git a/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp b/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp index 84127f37db..8befba821a 100644 --- a/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp +++ b/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp @@ -40,14 +40,12 @@ FramebufferManager::FramebufferManager() FramebufferManager::~FramebufferManager() { DestroyEFBFramebuffer(); - DestroyEFBRenderPass(); DestroyConversionShaders(); DestroyReadbackFramebuffer(); DestroyReadbackTextures(); DestroyReadbackShaders(); - DestroyReadbackRenderPasses(); DestroyPokeVertexBuffer(); DestroyPokeShaders(); @@ -88,7 +86,7 @@ MultisamplingState FramebufferManager::GetEFBMultisamplingState() const bool FramebufferManager::Initialize() { - if (!CreateEFBRenderPass()) + if (!CreateEFBRenderPasses()) { PanicAlert("Failed to create EFB render pass"); return false; @@ -142,108 +140,18 @@ bool FramebufferManager::Initialize() return true; } -bool FramebufferManager::CreateEFBRenderPass() +bool FramebufferManager::CreateEFBRenderPasses() { - VkSampleCountFlagBits samples = static_cast(g_ActiveConfig.iMultisamples); - - // render pass for rendering to the efb - VkAttachmentDescription attachments[] = { - {0, EFB_COLOR_TEXTURE_FORMAT, samples, VK_ATTACHMENT_LOAD_OP_LOAD, - VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE, - VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}, - {0, EFB_DEPTH_TEXTURE_FORMAT, samples, VK_ATTACHMENT_LOAD_OP_LOAD, - VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE, - VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL}}; - - VkAttachmentReference color_attachment_references[] = { - {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}}; - - VkAttachmentReference depth_attachment_reference = { - 1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL}; - - VkSubpassDescription subpass_description = { - 0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 1, color_attachment_references, - nullptr, &depth_attachment_reference, 0, nullptr}; - - VkRenderPassCreateInfo pass_info = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, - nullptr, - 0, - static_cast(ArraySize(attachments)), - attachments, - 1, - &subpass_description, - 0, - nullptr}; - - VkResult res = vkCreateRenderPass(g_vulkan_context->GetDevice(), &pass_info, nullptr, - &m_efb_load_render_pass); - if (res != VK_SUCCESS) - { - LOG_VULKAN_ERROR(res, "vkCreateRenderPass (EFB) failed: "); - return false; - } - - // render pass for clearing color/depth on load, as opposed to loading it - attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - res = vkCreateRenderPass(g_vulkan_context->GetDevice(), &pass_info, nullptr, - &m_efb_clear_render_pass); - if (res != VK_SUCCESS) - { - LOG_VULKAN_ERROR(res, "vkCreateRenderPass (EFB) failed: "); - return false; - } - - // render pass for resolving depth, since we can't do it with vkCmdResolveImage - if (g_ActiveConfig.MultisamplingEnabled()) - { - VkAttachmentDescription resolve_attachment = {0, - EFB_DEPTH_AS_COLOR_TEXTURE_FORMAT, - VK_SAMPLE_COUNT_1_BIT, - VK_ATTACHMENT_LOAD_OP_DONT_CARE, - VK_ATTACHMENT_STORE_OP_STORE, - VK_ATTACHMENT_LOAD_OP_DONT_CARE, - VK_ATTACHMENT_STORE_OP_DONT_CARE, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; - - subpass_description.pDepthStencilAttachment = nullptr; - pass_info.pAttachments = &resolve_attachment; - pass_info.attachmentCount = 1; - res = vkCreateRenderPass(g_vulkan_context->GetDevice(), &pass_info, nullptr, - &m_depth_resolve_render_pass); - - if (res != VK_SUCCESS) - { - LOG_VULKAN_ERROR(res, "vkCreateRenderPass (EFB depth resolve) failed: "); - return false; - } - } - - return true; -} - -void FramebufferManager::DestroyEFBRenderPass() -{ - if (m_efb_load_render_pass != VK_NULL_HANDLE) - { - vkDestroyRenderPass(g_vulkan_context->GetDevice(), m_efb_load_render_pass, nullptr); - m_efb_load_render_pass = VK_NULL_HANDLE; - } - - if (m_efb_clear_render_pass != VK_NULL_HANDLE) - { - vkDestroyRenderPass(g_vulkan_context->GetDevice(), m_efb_clear_render_pass, nullptr); - m_efb_clear_render_pass = VK_NULL_HANDLE; - } - - if (m_depth_resolve_render_pass != VK_NULL_HANDLE) - { - vkDestroyRenderPass(g_vulkan_context->GetDevice(), m_depth_resolve_render_pass, nullptr); - m_depth_resolve_render_pass = VK_NULL_HANDLE; - } + m_efb_load_render_pass = + g_object_cache->GetRenderPass(EFB_COLOR_TEXTURE_FORMAT, EFB_DEPTH_TEXTURE_FORMAT, + g_ActiveConfig.iMultisamples, VK_ATTACHMENT_LOAD_OP_LOAD); + m_efb_clear_render_pass = + g_object_cache->GetRenderPass(EFB_COLOR_TEXTURE_FORMAT, EFB_DEPTH_TEXTURE_FORMAT, + g_ActiveConfig.iMultisamples, VK_ATTACHMENT_LOAD_OP_CLEAR); + m_depth_resolve_render_pass = g_object_cache->GetRenderPass( + EFB_DEPTH_AS_COLOR_TEXTURE_FORMAT, VK_FORMAT_UNDEFINED, 1, VK_ATTACHMENT_LOAD_OP_DONT_CARE); + return m_efb_load_render_pass != VK_NULL_HANDLE && m_efb_clear_render_pass != VK_NULL_HANDLE && + m_depth_resolve_render_pass != VK_NULL_HANDLE; } bool FramebufferManager::CreateEFBFramebuffer() @@ -419,9 +327,7 @@ void FramebufferManager::ResizeEFBTextures() void FramebufferManager::RecreateRenderPass() { - DestroyEFBRenderPass(); - - if (!CreateEFBRenderPass()) + if (!CreateEFBRenderPasses()) PanicAlert("Failed to create EFB render pass"); } @@ -849,62 +755,12 @@ void FramebufferManager::InvalidatePeekCache() bool FramebufferManager::CreateReadbackRenderPasses() { - VkAttachmentDescription copy_attachment = { - 0, // VkAttachmentDescriptionFlags flags - EFB_COLOR_TEXTURE_FORMAT, // VkFormat format - VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples - VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp loadOp - VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp - VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp - VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout initialLayout - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout finalLayout - }; - VkAttachmentReference copy_attachment_ref = { - 0, // uint32_t attachment - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout - }; - VkSubpassDescription copy_subpass = { - 0, // VkSubpassDescriptionFlags flags - VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint - 0, // uint32_t inputAttachmentCount - nullptr, // const VkAttachmentReference* pInputAttachments - 1, // uint32_t colorAttachmentCount - ©_attachment_ref, // const VkAttachmentReference* pColorAttachments - nullptr, // const VkAttachmentReference* pResolveAttachments - nullptr, // const VkAttachmentReference* pDepthStencilAttachment - 0, // uint32_t preserveAttachmentCount - nullptr // const uint32_t* pPreserveAttachments - }; - VkRenderPassCreateInfo copy_pass = { - VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType - nullptr, // const void* pNext - 0, // VkRenderPassCreateFlags flags - 1, // uint32_t attachmentCount - ©_attachment, // const VkAttachmentDescription* pAttachments - 1, // uint32_t subpassCount - ©_subpass, // const VkSubpassDescription* pSubpasses - 0, // uint32_t dependencyCount - nullptr // const VkSubpassDependency* pDependencies - }; - - VkResult res = vkCreateRenderPass(g_vulkan_context->GetDevice(), ©_pass, nullptr, - &m_copy_color_render_pass); - if (res != VK_SUCCESS) - { - LOG_VULKAN_ERROR(res, "vkCreateRenderPass failed: "); + m_copy_color_render_pass = g_object_cache->GetRenderPass( + EFB_COLOR_TEXTURE_FORMAT, VK_FORMAT_UNDEFINED, 1, VK_ATTACHMENT_LOAD_OP_DONT_CARE); + m_copy_depth_render_pass = g_object_cache->GetRenderPass( + EFB_DEPTH_AS_COLOR_TEXTURE_FORMAT, VK_FORMAT_UNDEFINED, 1, VK_ATTACHMENT_LOAD_OP_DONT_CARE); + if (m_copy_color_render_pass == VK_NULL_HANDLE || m_copy_depth_render_pass == VK_NULL_HANDLE) return false; - } - - // Depth is similar to copy, just a different format. - copy_attachment.format = EFB_DEPTH_AS_COLOR_TEXTURE_FORMAT; - res = vkCreateRenderPass(g_vulkan_context->GetDevice(), ©_pass, nullptr, - &m_copy_depth_render_pass); - if (res != VK_SUCCESS) - { - LOG_VULKAN_ERROR(res, "vkCreateRenderPass failed: "); - return false; - } // Some devices don't support point sizes >1 (e.g. Adreno). // If we can't use a point size above our maximum IR, use triangles instead. @@ -925,20 +781,6 @@ bool FramebufferManager::CreateReadbackRenderPasses() return true; } -void FramebufferManager::DestroyReadbackRenderPasses() -{ - if (m_copy_color_render_pass != VK_NULL_HANDLE) - { - vkDestroyRenderPass(g_vulkan_context->GetDevice(), m_copy_color_render_pass, nullptr); - m_copy_color_render_pass = VK_NULL_HANDLE; - } - if (m_copy_depth_render_pass != VK_NULL_HANDLE) - { - vkDestroyRenderPass(g_vulkan_context->GetDevice(), m_copy_depth_render_pass, nullptr); - m_copy_depth_render_pass = VK_NULL_HANDLE; - } -} - bool FramebufferManager::CompileReadbackShaders() { std::string source; diff --git a/Source/Core/VideoBackends/Vulkan/FramebufferManager.h b/Source/Core/VideoBackends/Vulkan/FramebufferManager.h index e765abc907..0a731881db 100644 --- a/Source/Core/VideoBackends/Vulkan/FramebufferManager.h +++ b/Source/Core/VideoBackends/Vulkan/FramebufferManager.h @@ -82,8 +82,7 @@ private: u32 color; }; - bool CreateEFBRenderPass(); - void DestroyEFBRenderPass(); + bool CreateEFBRenderPasses(); bool CreateEFBFramebuffer(); void DestroyEFBFramebuffer(); @@ -91,7 +90,6 @@ private: void DestroyConversionShaders(); bool CreateReadbackRenderPasses(); - void DestroyReadbackRenderPasses(); bool CompileReadbackShaders(); void DestroyReadbackShaders(); bool CreateReadbackTextures(); diff --git a/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp b/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp index 1a5cfbf34e..7f72efb93b 100644 --- a/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp +++ b/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp @@ -37,6 +37,7 @@ ObjectCache::~ObjectCache() DestroySamplers(); DestroyPipelineLayouts(); DestroyDescriptorSetLayouts(); + DestroyRenderPassCache(); } bool ObjectCache::Initialize() @@ -358,4 +359,90 @@ VkSampler ObjectCache::GetSampler(const SamplerState& info) m_sampler_cache.emplace(info, sampler); return sampler; } + +VkRenderPass ObjectCache::GetRenderPass(VkFormat color_format, VkFormat depth_format, + u32 multisamples, VkAttachmentLoadOp load_op) +{ + auto key = std::tie(color_format, depth_format, multisamples, load_op); + auto it = m_render_pass_cache.find(key); + if (it != m_render_pass_cache.end()) + return it->second; + + VkAttachmentReference color_reference; + VkAttachmentReference* color_reference_ptr = nullptr; + VkAttachmentReference depth_reference; + VkAttachmentReference* depth_reference_ptr = nullptr; + std::array attachments; + u32 num_attachments = 0; + if (color_format != VK_FORMAT_UNDEFINED) + { + attachments[num_attachments] = {0, + color_format, + static_cast(multisamples), + load_op, + VK_ATTACHMENT_STORE_OP_STORE, + VK_ATTACHMENT_LOAD_OP_DONT_CARE, + VK_ATTACHMENT_STORE_OP_DONT_CARE, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; + color_reference.attachment = num_attachments; + color_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + color_reference_ptr = &color_reference; + num_attachments++; + } + if (depth_format != VK_FORMAT_UNDEFINED) + { + attachments[num_attachments] = {0, + depth_format, + static_cast(multisamples), + load_op, + VK_ATTACHMENT_STORE_OP_STORE, + VK_ATTACHMENT_LOAD_OP_DONT_CARE, + VK_ATTACHMENT_STORE_OP_DONT_CARE, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL}; + depth_reference.attachment = num_attachments; + depth_reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + depth_reference_ptr = &depth_reference; + num_attachments++; + } + + VkSubpassDescription subpass = {0, + VK_PIPELINE_BIND_POINT_GRAPHICS, + 0, + nullptr, + color_reference_ptr ? 1u : 0u, + color_reference_ptr ? color_reference_ptr : nullptr, + nullptr, + depth_reference_ptr, + 0, + nullptr}; + VkRenderPassCreateInfo pass_info = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, + nullptr, + 0, + num_attachments, + attachments.data(), + 1, + &subpass, + 0, + nullptr}; + + VkRenderPass pass; + VkResult res = vkCreateRenderPass(g_vulkan_context->GetDevice(), &pass_info, nullptr, &pass); + if (res != VK_SUCCESS) + { + LOG_VULKAN_ERROR(res, "vkCreateRenderPass failed: "); + return VK_NULL_HANDLE; + } + + m_render_pass_cache.emplace(key, pass); + return pass; +} + +void ObjectCache::DestroyRenderPassCache() +{ + for (auto& it : m_render_pass_cache) + vkDestroyRenderPass(g_vulkan_context->GetDevice(), it.second, nullptr); + m_render_pass_cache.clear(); +} } diff --git a/Source/Core/VideoBackends/Vulkan/ObjectCache.h b/Source/Core/VideoBackends/Vulkan/ObjectCache.h index bfcec09166..5b7939f95b 100644 --- a/Source/Core/VideoBackends/Vulkan/ObjectCache.h +++ b/Source/Core/VideoBackends/Vulkan/ObjectCache.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include "Common/CommonTypes.h" @@ -66,6 +67,10 @@ public: // Dummy image for samplers that are unbound Texture2D* GetDummyImage() const { return m_dummy_texture.get(); } VkImageView GetDummyImageView() const { return m_dummy_texture->GetView(); } + // Render pass cache. + VkRenderPass GetRenderPass(VkFormat color_format, VkFormat depth_format, u32 multisamples, + VkAttachmentLoadOp load_op); + // Perform at startup, create descriptor layouts, compiles all static shaders. bool Initialize(); @@ -81,6 +86,7 @@ private: bool CreateUtilityShaderVertexFormat(); bool CreateStaticSamplers(); void DestroySamplers(); + void DestroyRenderPassCache(); std::array m_descriptor_set_layouts = {}; std::array m_pipeline_layouts = {}; @@ -96,6 +102,10 @@ private: // Dummy image for samplers that are unbound std::unique_ptr m_dummy_texture; + + // Render pass cache + using RenderPassCacheKey = std::tuple; + std::map m_render_pass_cache; }; extern std::unique_ptr g_object_cache; diff --git a/Source/Core/VideoBackends/Vulkan/SwapChain.cpp b/Source/Core/VideoBackends/Vulkan/SwapChain.cpp index 58785130b0..672affeaea 100644 --- a/Source/Core/VideoBackends/Vulkan/SwapChain.cpp +++ b/Source/Core/VideoBackends/Vulkan/SwapChain.cpp @@ -33,7 +33,6 @@ SwapChain::~SwapChain() { DestroySwapChainImages(); DestroySwapChain(); - DestroyRenderPass(); DestroySurface(); } @@ -229,48 +228,9 @@ bool SwapChain::SelectPresentMode() bool SwapChain::CreateRenderPass() { // render pass for rendering to the swap chain - VkAttachmentDescription present_render_pass_attachments[] = { - {0, m_surface_format.format, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_CLEAR, - VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE, - VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}}; - - VkAttachmentReference present_render_pass_color_attachment_references[] = { - {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}}; - - VkSubpassDescription present_render_pass_subpass_descriptions[] = { - {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 1, - present_render_pass_color_attachment_references, nullptr, nullptr, 0, nullptr}}; - - VkRenderPassCreateInfo present_render_pass_info = { - VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, - nullptr, - 0, - static_cast(ArraySize(present_render_pass_attachments)), - present_render_pass_attachments, - static_cast(ArraySize(present_render_pass_subpass_descriptions)), - present_render_pass_subpass_descriptions, - 0, - nullptr}; - - VkResult res = vkCreateRenderPass(g_vulkan_context->GetDevice(), &present_render_pass_info, - nullptr, &m_render_pass); - if (res != VK_SUCCESS) - { - LOG_VULKAN_ERROR(res, "vkCreateRenderPass (present) failed: "); - return false; - } - - return true; -} - -void SwapChain::DestroyRenderPass() -{ - if (!m_render_pass) - return; - - vkDestroyRenderPass(g_vulkan_context->GetDevice(), m_render_pass, nullptr); - m_render_pass = VK_NULL_HANDLE; + m_render_pass = g_object_cache->GetRenderPass(m_surface_format.format, VK_FORMAT_UNDEFINED, 1, + VK_ATTACHMENT_LOAD_OP_CLEAR); + return m_render_pass != VK_NULL_HANDLE; } bool SwapChain::CreateSwapChain() @@ -498,7 +458,6 @@ bool SwapChain::SetVSync(bool enabled) bool SwapChain::RecreateSurface(void* native_handle) { // Destroy the old swap chain, images, and surface. - DestroyRenderPass(); DestroySwapChainImages(); DestroySwapChain(); DestroySurface(); diff --git a/Source/Core/VideoBackends/Vulkan/SwapChain.h b/Source/Core/VideoBackends/Vulkan/SwapChain.h index 69ccb6dff1..1561103cb8 100644 --- a/Source/Core/VideoBackends/Vulkan/SwapChain.h +++ b/Source/Core/VideoBackends/Vulkan/SwapChain.h @@ -68,7 +68,6 @@ private: void DestroySwapChain(); bool CreateRenderPass(); - void DestroyRenderPass(); bool SetupSwapChainImages(); void DestroySwapChainImages(); diff --git a/Source/Core/VideoBackends/Vulkan/TextureCache.cpp b/Source/Core/VideoBackends/Vulkan/TextureCache.cpp index dba11219e7..af9b39fa73 100644 --- a/Source/Core/VideoBackends/Vulkan/TextureCache.cpp +++ b/Source/Core/VideoBackends/Vulkan/TextureCache.cpp @@ -37,8 +37,6 @@ TextureCache::TextureCache() TextureCache::~TextureCache() { - if (m_render_pass != VK_NULL_HANDLE) - vkDestroyRenderPass(g_vulkan_context->GetDevice(), m_render_pass, nullptr); TextureCache::DeleteShaders(); } @@ -47,11 +45,6 @@ VkShaderModule TextureCache::GetCopyShader() const return m_copy_shader; } -VkRenderPass TextureCache::GetTextureCopyRenderPass() const -{ - return m_render_pass; -} - StreamBuffer* TextureCache::GetTextureUploadBuffer() const { return m_texture_upload_buffer.get(); @@ -73,12 +66,6 @@ bool TextureCache::Initialize() return false; } - if (!CreateRenderPasses()) - { - PanicAlert("Failed to create copy render pass"); - return false; - } - m_texture_converter = std::make_unique(); if (!m_texture_converter->Initialize()) { @@ -98,7 +85,7 @@ bool TextureCache::Initialize() void TextureCache::ConvertTexture(TCacheEntry* destination, TCacheEntry* source, const void* palette, TLUTFormat format) { - m_texture_converter->ConvertTexture(destination, source, m_render_pass, palette, format); + m_texture_converter->ConvertTexture(destination, source, palette, format); // Ensure both textures remain in the SHADER_READ_ONLY layout so they can be bound. static_cast(source->texture.get()) @@ -178,50 +165,6 @@ void TextureCache::DecodeTextureOnGPU(TCacheEntry* entry, u32 dst_level, const u } } -bool TextureCache::CreateRenderPasses() -{ - static constexpr VkAttachmentDescription update_attachment = { - 0, - TEXTURECACHE_TEXTURE_FORMAT, - VK_SAMPLE_COUNT_1_BIT, - VK_ATTACHMENT_LOAD_OP_DONT_CARE, - VK_ATTACHMENT_STORE_OP_STORE, - VK_ATTACHMENT_LOAD_OP_DONT_CARE, - VK_ATTACHMENT_STORE_OP_DONT_CARE, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; - - static constexpr VkAttachmentReference color_attachment_reference = { - 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; - - static constexpr VkSubpassDescription subpass_description = { - 0, VK_PIPELINE_BIND_POINT_GRAPHICS, - 0, nullptr, - 1, &color_attachment_reference, - nullptr, nullptr, - 0, nullptr}; - - VkRenderPassCreateInfo update_info = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, - nullptr, - 0, - 1, - &update_attachment, - 1, - &subpass_description, - 0, - nullptr}; - - VkResult res = - vkCreateRenderPass(g_vulkan_context->GetDevice(), &update_info, nullptr, &m_render_pass); - if (res != VK_SUCCESS) - { - LOG_VULKAN_ERROR(res, "vkCreateRenderPass failed: "); - return false; - } - - return true; -} - bool TextureCache::CompileShaders() { static const char COPY_SHADER_SOURCE[] = R"( @@ -322,8 +265,12 @@ void TextureCache::CopyEFBToCacheEntry(TCacheEntry* entry, bool is_depth_copy, shader = Util::CompileAndCreateFragmentShader(source); } + VkRenderPass render_pass = g_object_cache->GetRenderPass( + texture->GetRawTexIdentifier()->GetFormat(), VK_FORMAT_UNDEFINED, + texture->GetRawTexIdentifier()->GetSamples(), VK_ATTACHMENT_LOAD_OP_DONT_CARE); + UtilityShaderDraw draw(command_buffer, - g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_STANDARD), m_render_pass, + g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_STANDARD), render_pass, g_shader_cache->GetPassthroughVertexShader(), g_shader_cache->GetPassthroughGeometryShader(), shader); diff --git a/Source/Core/VideoBackends/Vulkan/TextureCache.h b/Source/Core/VideoBackends/Vulkan/TextureCache.h index dd2e993621..b27f9ad0e7 100644 --- a/Source/Core/VideoBackends/Vulkan/TextureCache.h +++ b/Source/Core/VideoBackends/Vulkan/TextureCache.h @@ -48,18 +48,13 @@ public: TLUTFormat palette_format) override; VkShaderModule GetCopyShader() const; - VkRenderPass GetTextureCopyRenderPass() const; StreamBuffer* GetTextureUploadBuffer() const; private: - bool CreateRenderPasses(); - void CopyEFBToCacheEntry(TCacheEntry* entry, bool is_depth_copy, const EFBRectangle& src_rect, bool scale_by_half, EFBCopyFormat dst_format, bool is_intensity) override; - VkRenderPass m_render_pass = VK_NULL_HANDLE; - std::unique_ptr m_texture_upload_buffer; std::unique_ptr m_texture_converter; diff --git a/Source/Core/VideoBackends/Vulkan/TextureConverter.cpp b/Source/Core/VideoBackends/Vulkan/TextureConverter.cpp index f594f7785b..084dc2f9e8 100644 --- a/Source/Core/VideoBackends/Vulkan/TextureConverter.cpp +++ b/Source/Core/VideoBackends/Vulkan/TextureConverter.cpp @@ -63,9 +63,6 @@ TextureConverter::~TextureConverter() if (m_texel_buffer_view_rgba8_uint != VK_NULL_HANDLE) vkDestroyBufferView(g_vulkan_context->GetDevice(), m_texel_buffer_view_rgba8_uint, nullptr); - if (m_encoding_render_pass != VK_NULL_HANDLE) - vkDestroyRenderPass(g_vulkan_context->GetDevice(), m_encoding_render_pass, nullptr); - for (auto& it : m_encoding_shaders) vkDestroyShaderModule(g_vulkan_context->GetDevice(), it.second, nullptr); @@ -95,12 +92,6 @@ bool TextureConverter::Initialize() return false; } - if (!CreateEncodingRenderPass()) - { - PanicAlert("Failed to create encode render pass"); - return false; - } - if (!CreateEncodingTexture()) { PanicAlert("Failed to create encoding texture"); @@ -165,8 +156,7 @@ TextureConverter::GetCommandBufferForTextureConversion(const TextureCache::TCach } void TextureConverter::ConvertTexture(TextureCacheBase::TCacheEntry* dst_entry, - TextureCacheBase::TCacheEntry* src_entry, - VkRenderPass render_pass, const void* palette, + TextureCacheBase::TCacheEntry* src_entry, const void* palette, TLUTFormat palette_format) { struct PSUniformBlock @@ -199,6 +189,9 @@ void TextureConverter::ConvertTexture(TextureCacheBase::TCacheEntry* dst_entry, command_buffer, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); // Bind and draw to the destination. + VkRenderPass render_pass = g_object_cache->GetRenderPass( + destination_texture->GetRawTexIdentifier()->GetFormat(), VK_FORMAT_UNDEFINED, + destination_texture->GetRawTexIdentifier()->GetSamples(), VK_ATTACHMENT_LOAD_OP_DONT_CARE); UtilityShaderDraw draw(command_buffer, g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_TEXTURE_CONVERSION), render_pass, g_shader_cache->GetScreenQuadVertexShader(), VK_NULL_HANDLE, @@ -240,10 +233,13 @@ void TextureConverter::EncodeTextureToMemory(VkImageView src_texture, u8* dest_p ->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + VkRenderPass render_pass = g_object_cache->GetRenderPass( + Util::GetVkFormatForHostTextureFormat(m_encoding_render_texture->GetConfig().format), + VK_FORMAT_UNDEFINED, 1, VK_ATTACHMENT_LOAD_OP_DONT_CARE); UtilityShaderDraw draw(g_command_buffer_mgr->GetCurrentCommandBuffer(), g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_PUSH_CONSTANT), - m_encoding_render_pass, g_shader_cache->GetScreenQuadVertexShader(), - VK_NULL_HANDLE, shader); + render_pass, g_shader_cache->GetScreenQuadVertexShader(), VK_NULL_HANDLE, + shader); // Uniform - int4 of left,top,native_width,scale EFBEncodeParams encoder_params; @@ -297,10 +293,12 @@ void TextureConverter::EncodeTextureToMemoryYUYV(void* dst_ptr, u32 dst_width, u // the order the guest is expecting and we don't have to swap it at readback time. The width // is halved because we're using an RGBA8 texture, but the YUYV data is two bytes per pixel. u32 output_width = dst_width / 2; - UtilityShaderDraw draw(command_buffer, - g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_STANDARD), - m_encoding_render_pass, g_shader_cache->GetPassthroughVertexShader(), - VK_NULL_HANDLE, m_rgb_to_yuyv_shader); + VkRenderPass render_pass = g_object_cache->GetRenderPass( + Util::GetVkFormatForHostTextureFormat(m_encoding_render_texture->GetConfig().format), + VK_FORMAT_UNDEFINED, 1, VK_ATTACHMENT_LOAD_OP_DONT_CARE); + UtilityShaderDraw draw( + command_buffer, g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_STANDARD), render_pass, + g_shader_cache->GetPassthroughVertexShader(), VK_NULL_HANDLE, m_rgb_to_yuyv_shader); VkRect2D region = {{0, 0}, {output_width, dst_height}}; draw.BeginRenderPass(static_cast(m_encoding_render_texture.get())->GetFramebuffer(), region); @@ -368,10 +366,13 @@ void TextureConverter::DecodeYUYVTextureFromMemory(VKTexture* dst_texture, const static_cast(src_width / 2)}; // Convert from the YUYV data now in the intermediate texture to RGBA in the destination. + VkRenderPass render_pass = g_object_cache->GetRenderPass( + dst_texture->GetRawTexIdentifier()->GetFormat(), VK_FORMAT_UNDEFINED, + dst_texture->GetRawTexIdentifier()->GetSamples(), VK_ATTACHMENT_LOAD_OP_DONT_CARE); UtilityShaderDraw draw(g_command_buffer_mgr->GetCurrentCommandBuffer(), g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_TEXTURE_CONVERSION), - m_encoding_render_pass, g_shader_cache->GetScreenQuadVertexShader(), - VK_NULL_HANDLE, m_yuyv_to_rgb_shader); + render_pass, g_shader_cache->GetScreenQuadVertexShader(), VK_NULL_HANDLE, + m_yuyv_to_rgb_shader); VkRect2D region = {{0, 0}, {src_width, src_height}}; draw.BeginRenderPass(dst_texture->GetFramebuffer(), region); draw.SetViewportAndScissor(0, 0, static_cast(src_width), static_cast(src_height)); @@ -711,42 +712,6 @@ VkShaderModule TextureConverter::GetEncodingShader(const EFBCopyParams& params) return shader; } -bool TextureConverter::CreateEncodingRenderPass() -{ - VkAttachmentDescription attachments[] = { - {0, Util::GetVkFormatForHostTextureFormat(ENCODING_TEXTURE_FORMAT), VK_SAMPLE_COUNT_1_BIT, - VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_STORE, - VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}}; - - VkAttachmentReference color_attachment_references[] = { - {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}}; - - VkSubpassDescription subpass_descriptions[] = {{0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 1, - color_attachment_references, nullptr, nullptr, 0, - nullptr}}; - - VkRenderPassCreateInfo pass_info = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, - nullptr, - 0, - static_cast(ArraySize(attachments)), - attachments, - static_cast(ArraySize(subpass_descriptions)), - subpass_descriptions, - 0, - nullptr}; - - VkResult res = vkCreateRenderPass(g_vulkan_context->GetDevice(), &pass_info, nullptr, - &m_encoding_render_pass); - if (res != VK_SUCCESS) - { - LOG_VULKAN_ERROR(res, "vkCreateRenderPass (Encode) failed: "); - return false; - } - - return true; -} - bool TextureConverter::CreateEncodingTexture() { TextureConfig config(ENCODING_TEXTURE_WIDTH, ENCODING_TEXTURE_HEIGHT, 1, 1, diff --git a/Source/Core/VideoBackends/Vulkan/TextureConverter.h b/Source/Core/VideoBackends/Vulkan/TextureConverter.h index b282e1d4ca..4e86332e92 100644 --- a/Source/Core/VideoBackends/Vulkan/TextureConverter.h +++ b/Source/Core/VideoBackends/Vulkan/TextureConverter.h @@ -35,8 +35,8 @@ public: // Applies palette to dst_entry, using indices from src_entry. void ConvertTexture(TextureCacheBase::TCacheEntry* dst_entry, - TextureCache::TCacheEntry* src_entry, VkRenderPass render_pass, - const void* palette, TLUTFormat palette_format); + TextureCache::TCacheEntry* src_entry, const void* palette, + TLUTFormat palette_format); // Uses an encoding shader to copy src_texture to dest_ptr. // NOTE: Executes the current command buffer. @@ -76,7 +76,6 @@ private: VkShaderModule CompileEncodingShader(const EFBCopyParams& params); VkShaderModule GetEncodingShader(const EFBCopyParams& params); - bool CreateEncodingRenderPass(); bool CreateEncodingTexture(); bool CreateDecodingTexture(); @@ -109,7 +108,6 @@ private: std::map m_encoding_shaders; std::unique_ptr m_encoding_render_texture; std::unique_ptr m_encoding_readback_texture; - VkRenderPass m_encoding_render_pass = VK_NULL_HANDLE; // Texture decoding - GX format in memory->RGBA8 struct TextureDecodingPipeline diff --git a/Source/Core/VideoBackends/Vulkan/VKTexture.cpp b/Source/Core/VideoBackends/Vulkan/VKTexture.cpp index 59be6a0eba..16aa9fecdb 100644 --- a/Source/Core/VideoBackends/Vulkan/VKTexture.cpp +++ b/Source/Core/VideoBackends/Vulkan/VKTexture.cpp @@ -56,11 +56,13 @@ std::unique_ptr VKTexture::Create(const TextureConfig& tex_config) if (tex_config.rendertarget) { VkImageView framebuffer_attachments[] = {texture->GetView()}; + VkRenderPass render_pass = g_object_cache->GetRenderPass( + texture->GetFormat(), VK_FORMAT_UNDEFINED, 1, VK_ATTACHMENT_LOAD_OP_DONT_CARE); VkFramebufferCreateInfo framebuffer_info = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, nullptr, 0, - TextureCache::GetInstance()->GetTextureCopyRenderPass(), + render_pass, static_cast(ArraySize(framebuffer_attachments)), framebuffer_attachments, texture->GetWidth(), @@ -175,9 +177,10 @@ void VKTexture::ScaleRectangleFromTexture(const AbstractTexture* source, m_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + VkRenderPass render_pass = g_object_cache->GetRenderPass( + m_texture->GetFormat(), VK_FORMAT_UNDEFINED, 1, VK_ATTACHMENT_LOAD_OP_DONT_CARE); UtilityShaderDraw draw(g_command_buffer_mgr->GetCurrentCommandBuffer(), - g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_STANDARD), - TextureCache::GetInstance()->GetTextureCopyRenderPass(), + g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_STANDARD), render_pass, g_shader_cache->GetPassthroughVertexShader(), g_shader_cache->GetPassthroughGeometryShader(), TextureCache::GetInstance()->GetCopyShader()); diff --git a/Source/Core/VideoBackends/Vulkan/main.cpp b/Source/Core/VideoBackends/Vulkan/main.cpp index 90621d23ec..63b7921442 100644 --- a/Source/Core/VideoBackends/Vulkan/main.cpp +++ b/Source/Core/VideoBackends/Vulkan/main.cpp @@ -186,6 +186,25 @@ bool VideoBackend::Initialize(void* window_handle) // With the backend information populated, we can now initialize videocommon. InitializeShared(); + // Create command buffers. We do this separately because the other classes depend on it. + g_command_buffer_mgr = std::make_unique(g_Config.bBackendMultithreading); + if (!g_command_buffer_mgr->Initialize()) + { + PanicAlert("Failed to create Vulkan command buffers"); + Shutdown(); + return false; + } + + // Remaining classes are also dependent on object/shader cache. + g_object_cache = std::make_unique(); + g_shader_cache = std::make_unique(); + if (!g_object_cache->Initialize() || !g_shader_cache->Initialize()) + { + PanicAlert("Failed to initialize Vulkan object cache."); + Shutdown(); + return false; + } + // Create swap chain. This has to be done early so that the target size is correct for auto-scale. std::unique_ptr swap_chain; if (surface != VK_NULL_HANDLE) @@ -199,39 +218,19 @@ bool VideoBackend::Initialize(void* window_handle) } } - // Create command buffers. We do this separately because the other classes depend on it. - g_command_buffer_mgr = std::make_unique(g_Config.bBackendMultithreading); - if (!g_command_buffer_mgr->Initialize()) - { - PanicAlert("Failed to create Vulkan command buffers"); - Shutdown(); - return false; - } - // Create main wrapper instances. - g_object_cache = std::make_unique(); - g_shader_cache = std::make_unique(); g_framebuffer_manager = std::make_unique(); g_renderer = std::make_unique(std::move(swap_chain)); + g_vertex_manager = std::make_unique(); + g_texture_cache = std::make_unique(); + g_perf_query = std::make_unique(); // Invoke init methods on main wrapper classes. // These have to be done before the others because the destructors // for the remaining classes may call methods on these. - if (!g_object_cache->Initialize() || !g_shader_cache->Initialize() || - !StateTracker::CreateInstance() || !FramebufferManager::GetInstance()->Initialize() || - !Renderer::GetInstance()->Initialize()) - { - PanicAlert("Failed to initialize Vulkan classes."); - Shutdown(); - return false; - } - - // Create remaining wrapper instances. - g_vertex_manager = std::make_unique(); - g_texture_cache = std::make_unique(); - g_perf_query = std::make_unique(); - if (!VertexManager::GetInstance()->Initialize() || !TextureCache::GetInstance()->Initialize() || - !PerfQuery::GetInstance()->Initialize()) + if (!StateTracker::CreateInstance() || !FramebufferManager::GetInstance()->Initialize() || + !Renderer::GetInstance()->Initialize() || !VertexManager::GetInstance()->Initialize() || + !TextureCache::GetInstance()->Initialize() || !PerfQuery::GetInstance()->Initialize()) { PanicAlert("Failed to initialize Vulkan classes."); Shutdown();