diff --git a/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp b/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp index 94f773fb94..9c2c712837 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() @@ -256,7 +164,7 @@ bool FramebufferManager::CreateEFBFramebuffer() INFO_LOG(VIDEO, "EFB size: %ux%ux%u", efb_width, efb_height, efb_layers); // Update the static variable in the base class. Why does this even exist? - FramebufferManagerBase::m_EFBLayers = g_ActiveConfig.iMultisamples; + FramebufferManagerBase::m_EFBLayers = efb_layers; // Allocate EFB render targets m_efb_color_texture = @@ -410,21 +318,17 @@ void FramebufferManager::DestroyEFBFramebuffer() m_efb_resolve_depth_texture.reset(); } -void FramebufferManager::ResizeEFBTextures() +void FramebufferManager::RecreateEFBFramebuffer() { DestroyEFBFramebuffer(); + + if (!CreateEFBRenderPasses()) + PanicAlert("Failed to create EFB render pass"); + if (!CreateEFBFramebuffer()) PanicAlert("Failed to create EFB textures"); } -void FramebufferManager::RecreateRenderPass() -{ - DestroyEFBRenderPass(); - - if (!CreateEFBRenderPass()) - PanicAlert("Failed to create EFB render pass"); -} - void FramebufferManager::RecompileShaders() { DestroyConversionShaders(); @@ -529,6 +433,8 @@ Texture2D* FramebufferManager::ResolveEFBDepthTexture(const VkRect2D& region) m_efb_depth_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + m_efb_resolve_depth_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); // Draw using resolve shader to write the minimum depth of all samples to the resolve texture. UtilityShaderDraw draw(g_command_buffer_mgr->GetCurrentCommandBuffer(), @@ -546,8 +452,6 @@ Texture2D* FramebufferManager::ResolveEFBDepthTexture(const VkRect2D& region) m_efb_depth_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); - // Render pass transitions to shader resource. - m_efb_resolve_depth_texture->OverrideImageLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); return m_efb_resolve_depth_texture.get(); } @@ -715,6 +619,9 @@ bool FramebufferManager::PopulateColorReadbackTexture() if (GetEFBWidth() != EFB_WIDTH || GetEFBHeight() != EFB_HEIGHT) { + // Transition EFB to shader read before drawing. + src_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); m_color_copy_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); @@ -725,10 +632,6 @@ bool FramebufferManager::PopulateColorReadbackTexture() VkRect2D rect = {{0, 0}, {EFB_WIDTH, EFB_HEIGHT}}; draw.BeginRenderPass(m_color_copy_framebuffer, rect); - - // Transition EFB to shader read before drawing. - src_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); draw.SetPSSampler(0, src_texture->GetView(), g_object_cache->GetPointSampler()); draw.SetViewportAndScissor(0, 0, EFB_WIDTH, EFB_HEIGHT); draw.DrawWithoutVertexBuffer(4); @@ -791,6 +694,9 @@ bool FramebufferManager::PopulateDepthReadbackTexture() } if (GetEFBWidth() != EFB_WIDTH || GetEFBHeight() != EFB_HEIGHT) { + // Transition EFB to shader read before drawing. + src_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); m_depth_copy_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); @@ -801,10 +707,6 @@ bool FramebufferManager::PopulateDepthReadbackTexture() VkRect2D rect = {{0, 0}, {EFB_WIDTH, EFB_HEIGHT}}; draw.BeginRenderPass(m_depth_copy_framebuffer, rect); - - // Transition EFB to shader read before drawing. - src_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); draw.SetPSSampler(0, src_texture->GetView(), g_object_cache->GetPointSampler()); draw.SetViewportAndScissor(0, 0, EFB_WIDTH, EFB_HEIGHT); draw.DrawWithoutVertexBuffer(4); @@ -849,62 +751,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 +777,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..f037564e1c 100644 --- a/Source/Core/VideoBackends/Vulkan/FramebufferManager.h +++ b/Source/Core/VideoBackends/Vulkan/FramebufferManager.h @@ -45,10 +45,9 @@ public: VkSampleCountFlagBits GetEFBSamples() const; MultisamplingState GetEFBMultisamplingState() const; - void ResizeEFBTextures(); + void RecreateEFBFramebuffer(); // Recompile shaders, use when MSAA mode changes. - void RecreateRenderPass(); void RecompileShaders(); // Reinterpret pixel format of EFB color texture. @@ -82,8 +81,7 @@ private: u32 color; }; - bool CreateEFBRenderPass(); - void DestroyEFBRenderPass(); + bool CreateEFBRenderPasses(); bool CreateEFBFramebuffer(); void DestroyEFBFramebuffer(); @@ -91,7 +89,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/Renderer.cpp b/Source/Core/VideoBackends/Vulkan/Renderer.cpp index 742a525b98..a146351007 100644 --- a/Source/Core/VideoBackends/Vulkan/Renderer.cpp +++ b/Source/Core/VideoBackends/Vulkan/Renderer.cpp @@ -545,9 +545,6 @@ void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region // Handle host window resizes. CheckForSurfaceChange(); - if (CalculateTargetSize()) - ResizeEFBTextures(); - // Update the window size based on the frame that was just rendered. // Due to depending on guest state, we need to call this every frame. SetWindowSize(xfb_texture->GetConfig().width, xfb_texture->GetConfig().height); @@ -724,9 +721,8 @@ void Renderer::CheckForSurfaceChange() void Renderer::CheckForConfigChanges() { // Save the video config so we can compare against to determine which settings have changed. + const u32 old_multisamples = g_ActiveConfig.iMultisamples; const int old_anisotropy = g_ActiveConfig.iMaxAnisotropy; - const AspectMode old_aspect_mode = g_ActiveConfig.aspect_mode; - const int old_efb_scale = g_ActiveConfig.iEFBScale; const bool old_force_filtering = g_ActiveConfig.bForceFiltering; // Copy g_Config to g_ActiveConfig. @@ -735,21 +731,17 @@ void Renderer::CheckForConfigChanges() UpdateActiveConfig(); // Determine which (if any) settings have changed. + const bool multisamples_changed = old_multisamples != g_ActiveConfig.iMultisamples; const bool anisotropy_changed = old_anisotropy != g_ActiveConfig.iMaxAnisotropy; const bool force_texture_filtering_changed = old_force_filtering != g_ActiveConfig.bForceFiltering; - const bool efb_scale_changed = old_efb_scale != g_ActiveConfig.iEFBScale; - const bool aspect_changed = old_aspect_mode != g_ActiveConfig.aspect_mode; // Update texture cache settings with any changed options. TextureCache::GetInstance()->OnConfigChanged(g_ActiveConfig); - // Handle settings that can cause the target rectangle to change. - if (efb_scale_changed || aspect_changed) - { - if (CalculateTargetSize()) - ResizeEFBTextures(); - } + // Handle settings that can cause the EFB framebuffer to change. + if (CalculateTargetSize() || multisamples_changed) + RecreateEFBFramebuffer(); // MSAA samples changed, we need to recreate the EFB render pass. // If the stereoscopy mode changed, we need to recreate the buffers as well. @@ -757,10 +749,7 @@ void Renderer::CheckForConfigChanges() // Changing stereoscopy from off<->on also requires shaders to be recompiled. if (CheckForHostConfigChanges()) { - g_command_buffer_mgr->WaitForGPUIdle(); - FramebufferManager::GetInstance()->RecreateRenderPass(); - FramebufferManager::GetInstance()->ResizeEFBTextures(); - BindEFBToStateTracker(); + RecreateEFBFramebuffer(); RecompileShaders(); FramebufferManager::GetInstance()->RecompileShaders(); g_shader_cache->ReloadShaderAndPipelineCaches(); @@ -798,7 +787,7 @@ void Renderer::OnSwapChainResized() m_backbuffer_height = m_swap_chain->GetHeight(); UpdateDrawRectangle(); if (CalculateTargetSize()) - ResizeEFBTextures(); + RecreateEFBFramebuffer(); } void Renderer::BindEFBToStateTracker() @@ -816,11 +805,11 @@ void Renderer::BindEFBToStateTracker() FramebufferManager::GetInstance()->GetEFBMultisamplingState()); } -void Renderer::ResizeEFBTextures() +void Renderer::RecreateEFBFramebuffer() { // Ensure the GPU is finished with the current EFB textures. g_command_buffer_mgr->WaitForGPUIdle(); - FramebufferManager::GetInstance()->ResizeEFBTextures(); + FramebufferManager::GetInstance()->RecreateEFBFramebuffer(); BindEFBToStateTracker(); // Viewport and scissor rect have to be reset since they will be scaled differently. diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.h b/Source/Core/VideoBackends/Vulkan/Renderer.h index b3f8168347..5a994bf597 100644 --- a/Source/Core/VideoBackends/Vulkan/Renderer.h +++ b/Source/Core/VideoBackends/Vulkan/Renderer.h @@ -82,7 +82,7 @@ private: void OnSwapChainResized(); void BindEFBToStateTracker(); - void ResizeEFBTextures(); + void RecreateEFBFramebuffer(); void RecompileShaders(); bool CompileShaders(); 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();