diff --git a/Source/Core/VideoBackends/Vulkan/CommandBufferManager.cpp b/Source/Core/VideoBackends/Vulkan/CommandBufferManager.cpp index 19ebbf3cb7..350757194e 100644 --- a/Source/Core/VideoBackends/Vulkan/CommandBufferManager.cpp +++ b/Source/Core/VideoBackends/Vulkan/CommandBufferManager.cpp @@ -352,7 +352,7 @@ void CommandBufferManager::SubmitCommandBuffer(size_t index, VkSemaphore wait_se &present_image_index, nullptr}; - res = vkQueuePresentKHR(g_vulkan_context->GetGraphicsQueue(), &present_info); + res = vkQueuePresentKHR(g_vulkan_context->GetPresentQueue(), &present_info); if (res != VK_SUCCESS && res != VK_ERROR_OUT_OF_DATE_KHR && res != VK_SUBOPTIMAL_KHR) LOG_VULKAN_ERROR(res, "vkQueuePresentKHR failed: "); } diff --git a/Source/Core/VideoBackends/Vulkan/SwapChain.cpp b/Source/Core/VideoBackends/Vulkan/SwapChain.cpp index 21009510bb..c5b3791637 100644 --- a/Source/Core/VideoBackends/Vulkan/SwapChain.cpp +++ b/Source/Core/VideoBackends/Vulkan/SwapChain.cpp @@ -327,7 +327,6 @@ bool SwapChain::CreateSwapChain() VkSwapchainKHR old_swap_chain = m_swap_chain; // Now we can actually create the swap chain - // TODO: Handle case where the present queue is not the graphics queue. VkSwapchainCreateInfoKHR swap_chain_info = {VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, nullptr, 0, @@ -346,6 +345,17 @@ bool SwapChain::CreateSwapChain() m_present_mode, VK_TRUE, old_swap_chain}; + std::array indices = {{ + g_vulkan_context->GetGraphicsQueueFamilyIndex(), + g_vulkan_context->GetPresentQueueFamilyIndex(), + }}; + if (g_vulkan_context->GetGraphicsQueueFamilyIndex() != + g_vulkan_context->GetPresentQueueFamilyIndex()) + { + swap_chain_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT; + swap_chain_info.queueFamilyIndexCount = 2; + swap_chain_info.pQueueFamilyIndices = indices.data(); + } res = vkCreateSwapchainKHR(g_vulkan_context->GetDevice(), &swap_chain_info, nullptr, &m_swap_chain); diff --git a/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp b/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp index 8bb7a5088e..9258a28f6f 100644 --- a/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp +++ b/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp @@ -494,36 +494,41 @@ bool VulkanContext::CreateDevice(VkSurfaceKHR surface, bool enable_validation_la queue_family_properties.data()); INFO_LOG(VIDEO, "%u vulkan queue families", queue_family_count); - // Find a graphics queue - // Currently we only use a single queue for both graphics and presenting. - // TODO: In the future we could do post-processing and presenting on a different queue. + // Find graphics and present queues. m_graphics_queue_family_index = queue_family_count; + m_present_queue_family_index = queue_family_count; for (uint32_t i = 0; i < queue_family_count; i++) { - if (queue_family_properties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) + VkBool32 graphics_supported = queue_family_properties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT; + if (graphics_supported) { - // Check that it can present to our surface from this queue - if (surface) + m_graphics_queue_family_index = i; + // Quit now, no need for a present queue. + if (!surface) { - VkBool32 present_supported; - VkResult res = - vkGetPhysicalDeviceSurfaceSupportKHR(m_physical_device, i, surface, &present_supported); - if (res != VK_SUCCESS) - { - LOG_VULKAN_ERROR(res, "vkGetPhysicalDeviceSurfaceSupportKHR failed: "); - return false; - } - - if (present_supported) - { - m_graphics_queue_family_index = i; - break; - } + break; } - else + } + + if (surface) + { + VkBool32 present_supported; + VkResult res = + vkGetPhysicalDeviceSurfaceSupportKHR(m_physical_device, i, surface, &present_supported); + if (res != VK_SUCCESS) + { + LOG_VULKAN_ERROR(res, "vkGetPhysicalDeviceSurfaceSupportKHR failed: "); + return false; + } + + if (present_supported) + { + m_present_queue_family_index = i; + } + + // Prefer one queue family index that does both graphics and present. + if (graphics_supported && present_supported) { - // We don't need present, so any graphics queue will do. - m_graphics_queue_family_index = i; break; } } @@ -533,6 +538,11 @@ bool VulkanContext::CreateDevice(VkSurfaceKHR surface, bool enable_validation_la ERROR_LOG(VIDEO, "Vulkan: Failed to find an acceptable graphics queue."); return false; } + if (surface && m_present_queue_family_index == queue_family_count) + { + ERROR_LOG(VIDEO, "Vulkan: Failed to find an acceptable present queue."); + return false; + } VkDeviceCreateInfo device_info = {}; device_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; @@ -540,15 +550,32 @@ bool VulkanContext::CreateDevice(VkSurfaceKHR surface, bool enable_validation_la device_info.flags = 0; static constexpr float queue_priorities[] = {1.0f}; - VkDeviceQueueCreateInfo queue_info = {}; - queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - queue_info.pNext = nullptr; - queue_info.flags = 0; - queue_info.queueFamilyIndex = m_graphics_queue_family_index; - queue_info.queueCount = 1; - queue_info.pQueuePriorities = queue_priorities; + VkDeviceQueueCreateInfo graphics_queue_info = {}; + graphics_queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + graphics_queue_info.pNext = nullptr; + graphics_queue_info.flags = 0; + graphics_queue_info.queueFamilyIndex = m_graphics_queue_family_index; + graphics_queue_info.queueCount = 1; + graphics_queue_info.pQueuePriorities = queue_priorities; + + VkDeviceQueueCreateInfo present_queue_info = {}; + present_queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + present_queue_info.pNext = nullptr; + present_queue_info.flags = 0; + present_queue_info.queueFamilyIndex = m_present_queue_family_index; + present_queue_info.queueCount = 1; + present_queue_info.pQueuePriorities = queue_priorities; + + std::array queue_infos = {{ + graphics_queue_info, present_queue_info, + }}; + device_info.queueCreateInfoCount = 1; - device_info.pQueueCreateInfos = &queue_info; + if (m_graphics_queue_family_index != m_present_queue_family_index) + { + device_info.queueCreateInfoCount = 2; + } + device_info.pQueueCreateInfos = queue_infos.data(); ExtensionList enabled_extensions; if (!SelectDeviceExtensions(&enabled_extensions, surface != VK_NULL_HANDLE)) @@ -584,8 +611,12 @@ bool VulkanContext::CreateDevice(VkSurfaceKHR surface, bool enable_validation_la if (!LoadVulkanDeviceFunctions(m_device)) return false; - // Grab the graphics queue (only one we're using at this point). + // Grab the graphics and present queues. vkGetDeviceQueue(m_device, m_graphics_queue_family_index, 0, &m_graphics_queue); + if (surface) + { + vkGetDeviceQueue(m_device, m_present_queue_family_index, 0, &m_present_queue); + } return true; } diff --git a/Source/Core/VideoBackends/Vulkan/VulkanContext.h b/Source/Core/VideoBackends/Vulkan/VulkanContext.h index 17a4a25d2c..fd504560b8 100644 --- a/Source/Core/VideoBackends/Vulkan/VulkanContext.h +++ b/Source/Core/VideoBackends/Vulkan/VulkanContext.h @@ -57,6 +57,8 @@ public: VkDevice GetDevice() const { return m_device; } VkQueue GetGraphicsQueue() const { return m_graphics_queue; } u32 GetGraphicsQueueFamilyIndex() const { return m_graphics_queue_family_index; } + VkQueue GetPresentQueue() const { return m_present_queue; } + u32 GetPresentQueueFamilyIndex() const { return m_present_queue_family_index; } const VkQueueFamilyProperties& GetGraphicsQueueProperties() const { return m_graphics_queue_properties; @@ -119,6 +121,8 @@ private: VkQueue m_graphics_queue = VK_NULL_HANDLE; u32 m_graphics_queue_family_index = 0; + VkQueue m_present_queue = VK_NULL_HANDLE; + u32 m_present_queue_family_index = 0; VkQueueFamilyProperties m_graphics_queue_properties = {}; VkDebugReportCallbackEXT m_debug_report_callback = VK_NULL_HANDLE;