diff --git a/common/video/vulkan/vulkan_context.cpp b/common/video/vulkan/vulkan_context.cpp index bb0e6755..9fa820a6 100644 --- a/common/video/vulkan/vulkan_context.cpp +++ b/common/video/vulkan/vulkan_context.cpp @@ -235,6 +235,12 @@ bool Context::init_device() VK_KHR_SWAPCHAIN_EXTENSION_NAME, }; + std::vector present_wait_extensions = + { + VK_KHR_PRESENT_ID_EXTENSION_NAME, + VK_KHR_PRESENT_WAIT_EXTENSION_NAME + }; + auto device_list = instance->enumeratePhysicalDevices().value; bool device_chosen = false; physical_device = vk::PhysicalDevice(); @@ -263,6 +269,17 @@ bool Context::init_device() if (!device_chosen) return false; + if (check_extensions(present_wait_extensions, physical_device)) + { + for (auto &ext : present_wait_extensions) + required_extensions.push_back(ext); + have_present_wait = true; + } + else + { + have_present_wait = false; + } + if (auto index = find_graphics_queue(physical_device)) graphics_queue_family_index = *index; else @@ -272,6 +289,14 @@ bool Context::init_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_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); diff --git a/common/video/vulkan/vulkan_context.hpp b/common/video/vulkan/vulkan_context.hpp index abeb5bdb..f46736cd 100644 --- a/common/video/vulkan/vulkan_context.hpp +++ b/common/video/vulkan/vulkan_context.hpp @@ -56,6 +56,7 @@ class Context vk::PhysicalDeviceProperties physical_device_props; vk::UniqueSurfaceKHR surface; std::string platform_name; + bool have_present_wait; private: bool init_vma(); diff --git a/common/video/vulkan/vulkan_swapchain.cpp b/common/video/vulkan/vulkan_swapchain.cpp index 3cb113d5..3b7f1240 100644 --- a/common/video/vulkan/vulkan_swapchain.cpp +++ b/common/video/vulkan/vulkan_swapchain.cpp @@ -364,6 +364,14 @@ bool Swapchain::swap() .setSwapchains(swapchain_object.get()) .setImageIndices(current_swapchain_image); + vk::PresentIdKHR present_id; + if (context.have_present_wait) + { + presentation_id++; + present_id.setPresentIds(presentation_id); + present_info.setPNext(&present_id); + } + vk::Result result = queue.presentKHR(present_info); if (result == vk::Result::eErrorOutOfDateKHR) { @@ -430,4 +438,12 @@ vk::RenderPass &Swapchain::get_render_pass() return render_pass.get(); } +void Swapchain::present_wait() +{ + if (context.have_present_wait && context.platform_name != "wayland") + { + device.waitForPresentKHR(swapchain_object.get(), presentation_id, 16666666); + } +} + } // namespace Vulkan diff --git a/common/video/vulkan/vulkan_swapchain.hpp b/common/video/vulkan/vulkan_swapchain.hpp index a304b98e..7e0796bf 100644 --- a/common/video/vulkan/vulkan_swapchain.hpp +++ b/common/video/vulkan/vulkan_swapchain.hpp @@ -29,6 +29,7 @@ class Swapchain bool end_frame(); void end_frame_without_swap(); bool swap(); + void present_wait(); void set_vsync(bool on); void on_render_pass_end(std::function function); int get_num_frames() { return num_swapchain_images; } diff --git a/gtk/src/gtk_display_driver_vulkan.cpp b/gtk/src/gtk_display_driver_vulkan.cpp index 3d7fcfbd..a120180c 100644 --- a/gtk/src/gtk_display_driver_vulkan.cpp +++ b/gtk/src/gtk_display_driver_vulkan.cpp @@ -238,7 +238,10 @@ void S9xVulkanDisplayDriver::update(uint16_t *buffer, int width, int height, int context->swapchain->swap(); if (gui_config->reduce_input_lag) + { context->wait_idle(); + context->swapchain->present_wait(); + } } } diff --git a/qt/src/EmuCanvasVulkan.cpp b/qt/src/EmuCanvasVulkan.cpp index 1eef16a4..670aabd7 100644 --- a/qt/src/EmuCanvasVulkan.cpp +++ b/qt/src/EmuCanvasVulkan.cpp @@ -226,6 +226,7 @@ void EmuCanvasVulkan::draw() if (config->reduce_input_lag) { context->wait_idle(); + context->swapchain->present_wait(); } } }