diff --git a/common/video/vulkan/vulkan_context.cpp b/common/video/vulkan/vulkan_context.cpp index 3fee38a2..24448974 100644 --- a/common/video/vulkan/vulkan_context.cpp +++ b/common/video/vulkan/vulkan_context.cpp @@ -245,6 +245,23 @@ bool Context::init_device(int preferred_device) } } + std::vector present_wait_extensions = + { + VK_KHR_PRESENT_ID_EXTENSION_NAME, + VK_KHR_PRESENT_WAIT_EXTENSION_NAME + }; + + if (check_extensions(present_wait_extensions, physical_device)) + { + for (auto &ext : present_wait_extensions) + required_extensions.push_back(ext); + have_VK_KHR_present_wait = true; + } + else + { + have_VK_KHR_present_wait = false; + } + auto extension_properties = physical_device.enumerateDeviceExtensionProperties().value; physical_device.getProperties(&physical_device_props); @@ -256,6 +273,14 @@ bool Context::init_device(int preferred_device) vk::DeviceQueueCreateInfo dqci({}, graphics_queue_family_index, priorities); vk::DeviceCreateInfo dci({}, dqci, {}, required_extensions); + vk::PhysicalDevicePresentWaitFeaturesKHR physical_device_present_wait_feature(true); + vk::PhysicalDevicePresentIdFeaturesKHR physical_device_present_id_feature(true); + if (have_VK_KHR_present_wait) + { + dci.setPNext(&physical_device_present_wait_feature); + physical_device_present_wait_feature.setPNext(&physical_device_present_id_feature); + } + device = physical_device.createDevice(dci).value; queue = device.getQueue(graphics_queue_family_index, 0); @@ -289,7 +314,7 @@ bool Context::init_vma() bool Context::create_swapchain(int width, int height) { wait_idle(); - swapchain = std::make_unique(device, physical_device, queue, surface.get(), command_pool.get()); + swapchain = std::make_unique(*this); return swapchain->create(2, width, height); } diff --git a/common/video/vulkan/vulkan_context.hpp b/common/video/vulkan/vulkan_context.hpp index c15df4f8..5cc700f9 100644 --- a/common/video/vulkan/vulkan_context.hpp +++ b/common/video/vulkan/vulkan_context.hpp @@ -51,6 +51,8 @@ class Context vk::PhysicalDeviceProperties physical_device_props; vk::UniqueSurfaceKHR surface; + bool have_VK_KHR_present_wait = false; + private: bool init_vma(); bool init_device(int preferred_device = 0); diff --git a/common/video/vulkan/vulkan_swapchain.cpp b/common/video/vulkan/vulkan_swapchain.cpp index b4d2734c..a9cd5131 100644 --- a/common/video/vulkan/vulkan_swapchain.cpp +++ b/common/video/vulkan/vulkan_swapchain.cpp @@ -1,15 +1,17 @@ #include "vulkan_swapchain.hpp" +#include "vulkan_context.hpp" namespace Vulkan { -Swapchain::Swapchain(vk::Device device_, vk::PhysicalDevice physical_device_, vk::Queue queue_, vk::SurfaceKHR surface_, vk::CommandPool command_pool_) - : surface(surface_), - command_pool(command_pool_), - physical_device(physical_device_), - queue(queue_) +Swapchain::Swapchain(Context &context_) + : context(context_) { - device = device_; + device = context.device; + queue = context.queue; + surface = context.surface.get(); + physical_device = context.physical_device; + command_pool = context.command_pool.get(); create_render_pass(); end_render_pass_function = nullptr; } @@ -351,13 +353,22 @@ bool Swapchain::swap() vk::SwapchainPresentModeInfoEXT present_mode_info; auto present_mode = get_present_mode(); present_mode_info.setPresentModes(present_mode); - present_info.setPNext(&present_mode_info); auto &present_fence = image_data[current_swapchain_image].fence.get(); device.resetFences(present_fence); vk::SwapchainPresentFenceInfoEXT present_fence_info(present_fence); + + present_info.setPNext(&present_mode_info); present_mode_info.setPNext(&present_fence_info); + vk::PresentIdKHR present_id; + if (context.have_VK_KHR_present_wait) + { + presentation_id++; + present_id.setPresentIds(presentation_id); + present_fence_info.setPNext(&present_id); + } + vk::Result result = queue.presentKHR(present_info); if (result == vk::Result::eErrorOutOfDateKHR) { @@ -424,6 +435,15 @@ void Swapchain::wait_on_frames() { for (auto i = 0; i < image_data.size(); i++) wait_on_frame(i); + + if (context.have_VK_KHR_present_wait) + { + auto result = device.waitForPresentKHR(swapchain_object.get(), presentation_id, 16666666); + if (result != vk::Result::eSuccess) + { + printf("Error waiting on present: %s\n", vk::to_string(result).c_str()); + } + } } vk::Extent2D Swapchain::get_extents() diff --git a/common/video/vulkan/vulkan_swapchain.hpp b/common/video/vulkan/vulkan_swapchain.hpp index 41028027..8835e186 100644 --- a/common/video/vulkan/vulkan_swapchain.hpp +++ b/common/video/vulkan/vulkan_swapchain.hpp @@ -6,14 +6,12 @@ namespace Vulkan { +class Context; + class Swapchain { public: - Swapchain(vk::Device device, - vk::PhysicalDevice physical_device, - vk::Queue queue, - vk::SurfaceKHR surface, - vk::CommandPool command_pool); + Swapchain(Context &); ~Swapchain(); bool create(unsigned int num_frames, int width = -1, int height = -1); bool recreate(int width = -1, int height = -1); @@ -66,6 +64,7 @@ class Swapchain unsigned int current_frame = 0; unsigned int current_swapchain_image = 0; unsigned int num_swapchain_images = 0; + uint64_t presentation_id = 0; bool vsync = true; bool supports_immediate = false; bool supports_mailbox = false; @@ -73,6 +72,7 @@ class Swapchain std::vector frames; std::vector image_data; + Vulkan::Context &context; vk::Device device; vk::SurfaceKHR surface; vk::CommandPool command_pool;