diff --git a/Source/Core/DolphinLibretro/Output.cpp b/Source/Core/DolphinLibretro/Output.cpp index 376be90c42..eb988bb993 100644 --- a/Source/Core/DolphinLibretro/Output.cpp +++ b/Source/Core/DolphinLibretro/Output.cpp @@ -12,7 +12,6 @@ #ifdef HAS_VULKAN #include "VideoBackends/Vulkan/CommandBufferManager.h" #include "VideoBackends/Vulkan/StateTracker.h" -#include "VideoBackends/Vulkan/VulkanContext.h" #endif namespace Libretro @@ -232,15 +231,6 @@ VKOutput::~VKOutput() void VKOutput::DropDirect() { - /* the frontend's frames that read it were submitted before anything - * the core submits next, so it goes once that completes */ - if (m_direct_image.image_view != VK_NULL_HANDLE) - { - if (Vulkan::g_command_buffer_mgr) - Vulkan::g_command_buffer_mgr->DeferImageViewDestruction(m_direct_image.image_view); - else - vkDestroyImageView(Vulkan::g_vulkan_context->GetDevice(), m_direct_image.image_view, nullptr); - } memset(&m_direct_image, 0, sizeof(m_direct_image)); m_direct = nullptr; } @@ -333,9 +323,14 @@ bool VKOutput::PresentTexture(const AbstractTexture* texture, u32 width, u32 hei Vulkan::VKTexture* vk_texture = const_cast(static_cast(texture)); retro_vulkan_image image; - VkImageView view = VK_NULL_HANDLE; + + /* the texture's own 2D view of its one layer: the frontend's shaders + * read a 2D image */ + if (vk_texture->GetView2D() == VK_NULL_HANDLE) + return false; memset(&image, 0, sizeof(image)); + image.image_view = vk_texture->GetView2D(); image.image_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; image.create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; image.create_info.image = vk_texture->GetImage(); @@ -350,15 +345,6 @@ bool VKOutput::PresentTexture(const AbstractTexture* texture, u32 width, u32 hei image.create_info.subresourceRange.levelCount = 1; image.create_info.subresourceRange.baseArrayLayer = 0; image.create_info.subresourceRange.layerCount = 1; - /* a view per picture: an image's handle can come back for another one - * once it is destroyed, so none is kept for the next */ - if (vkCreateImageView(Vulkan::g_vulkan_context->GetDevice(), &image.create_info, nullptr, - &view) != VK_SUCCESS) - { - return false; - } - image.image_view = view; - vk_texture->TransitionToLayout(Vulkan::g_command_buffer_mgr->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); Vulkan::g_command_buffer_mgr->SubmitCommandBuffer(false, false, true); diff --git a/Source/Core/DolphinLibretro/Output.h b/Source/Core/DolphinLibretro/Output.h index 8f6cac875f..b89c97ee71 100644 --- a/Source/Core/DolphinLibretro/Output.h +++ b/Source/Core/DolphinLibretro/Output.h @@ -98,9 +98,9 @@ private: retro_vulkan_image m_images[OUTPUT_MAX_SLOTS]; std::unique_ptr m_textures[OUTPUT_MAX_SLOTS]; std::unique_ptr m_framebuffers[OUTPUT_MAX_SLOTS]; - /* A texture handed on where it is, with a 2D view of its one layer of - * its own, made for it: the frontend reads it until another picture is - * handed on, so it is kept in shader-read layout meanwhile. */ + /* A texture handed on where it is, through its 2D view: the frontend + * reads it until another picture is handed on, so it is kept in + * shader-read layout meanwhile. */ retro_vulkan_image m_direct_image; Vulkan::VKTexture* m_direct; retro_hw_render_interface_vulkan* m_iface; diff --git a/Source/Core/VideoBackends/Vulkan/VKTexture.cpp b/Source/Core/VideoBackends/Vulkan/VKTexture.cpp index ee6a1b77b3..6c7b047b1b 100644 --- a/Source/Core/VideoBackends/Vulkan/VKTexture.cpp +++ b/Source/Core/VideoBackends/Vulkan/VKTexture.cpp @@ -47,6 +47,8 @@ VKTexture::~VKTexture() { StateTracker::GetInstance()->UnbindTexture(m_view); g_command_buffer_mgr->DeferImageViewDestruction(m_view); + if (m_view_2d != VK_NULL_HANDLE) + g_command_buffer_mgr->DeferImageViewDestruction(m_view_2d); // If we don't have device memory allocated, the image is not owned by us (e.g. swapchain) if (m_alloc != VK_NULL_HANDLE) @@ -127,8 +129,14 @@ std::unique_ptr VKTexture::Create(const TextureConfig& tex_config, st PanicAlertFmt("Unhandled texture type."); return nullptr; } - if (!texture->CreateView(image_view_type)) + if (!texture->CreateView(image_view_type, &texture->m_view)) return nullptr; + if (tex_config.type == AbstractTextureType::Texture_2DArray && tex_config.layers == 1 && + tex_config.IsRenderTarget() && + !texture->CreateView(VK_IMAGE_VIEW_TYPE_2D, &texture->m_view_2d)) + { + return nullptr; + } return texture; } @@ -138,13 +146,13 @@ std::unique_ptr VKTexture::CreateAdopted(const TextureConfig& tex_con { std::unique_ptr texture = std::make_unique( tex_config, VmaAllocation(VK_NULL_HANDLE), image, "", layout, ComputeImageLayout::Undefined); - if (!texture->CreateView(view_type)) + if (!texture->CreateView(view_type, &texture->m_view)) return nullptr; return texture; } -bool VKTexture::CreateView(VkImageViewType type) +bool VKTexture::CreateView(VkImageViewType type, VkImageView* view) { VkImageViewCreateInfo view_info = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, @@ -157,7 +165,7 @@ bool VKTexture::CreateView(VkImageViewType type) VK_COMPONENT_SWIZZLE_IDENTITY}, {GetImageViewAspectForFormat(GetFormat()), 0, GetLevels(), 0, GetLayers()}}; - VkResult res = vkCreateImageView(g_vulkan_context->GetDevice(), &view_info, nullptr, &m_view); + VkResult res = vkCreateImageView(g_vulkan_context->GetDevice(), &view_info, nullptr, view); if (res != VK_SUCCESS) { LOG_VULKAN_ERROR(res, "vkCreateImageView failed: "); diff --git a/Source/Core/VideoBackends/Vulkan/VKTexture.h b/Source/Core/VideoBackends/Vulkan/VKTexture.h index 456b4fcd33..65b31460f4 100644 --- a/Source/Core/VideoBackends/Vulkan/VKTexture.h +++ b/Source/Core/VideoBackends/Vulkan/VKTexture.h @@ -52,6 +52,9 @@ public: VkImage GetImage() const { return m_image; } VkImageView GetView() const { return m_view; } + /* A 2D view of a render target's one layer, for whoever reads it as a + * plain 2D image: the frontend, when it is handed on; null otherwise. */ + VkImageView GetView2D() const { return m_view_2d; } VkImageLayout GetLayout() const { return m_layout; } VkFormat GetVkFormat() const { return GetVkFormatForHostTextureFormat(m_config.format); } bool IsAdopted() const { return m_alloc != VmaAllocation(VK_NULL_HANDLE); } @@ -72,11 +75,12 @@ public: void PrepareForRenderPass(VkCommandBuffer command_buffer) const; private: - bool CreateView(VkImageViewType type); + bool CreateView(VkImageViewType type, VkImageView* view); VmaAllocation m_alloc; VkImage m_image; VkImageView m_view = VK_NULL_HANDLE; + VkImageView m_view_2d = VK_NULL_HANDLE; mutable VkImageLayout m_layout = VK_IMAGE_LAYOUT_UNDEFINED; mutable ComputeImageLayout m_compute_layout = ComputeImageLayout::Undefined; mutable bool m_written_since_last_layout_change = false;