mirror of https://github.com/snes9xgit/snes9x.git
Vulkan: Utilize VK_EXT_swapchain_maintenance1.
This is core in Vulkan 1.1. We can now change vsync state without a new swapchain. A fence is signaled when image is on screen, so we can possibly be a little more precise with timing and avoid a whole device wait.
This commit is contained in:
parent
99990af31e
commit
5949bbab97
|
@ -222,6 +222,7 @@ void S9xVulkanDisplayDriver::update(uint16_t *buffer, int width, int height, int
|
||||||
throttle.wait_for_frame_and_rebase_time();
|
throttle.wait_for_frame_and_rebase_time();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
context->swapchain->set_vsync(gui_config->sync_to_vblank);
|
||||||
context->swapchain->swap();
|
context->swapchain->swap();
|
||||||
|
|
||||||
if (gui_config->reduce_input_lag)
|
if (gui_config->reduce_input_lag)
|
||||||
|
|
|
@ -178,9 +178,6 @@ void EmuCanvasVulkan::draw()
|
||||||
if (!window->isVisible())
|
if (!window->isVisible())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (context->swapchain->set_vsync(config->enable_vsync))
|
|
||||||
context->recreate_swapchain();
|
|
||||||
|
|
||||||
if (S9xImGuiDraw(width() * devicePixelRatioF(), height() * devicePixelRatioF()))
|
if (S9xImGuiDraw(width() * devicePixelRatioF(), height() * devicePixelRatioF()))
|
||||||
{
|
{
|
||||||
auto draw_data = ImGui::GetDrawData();
|
auto draw_data = ImGui::GetDrawData();
|
||||||
|
@ -205,10 +202,11 @@ void EmuCanvasVulkan::draw()
|
||||||
if (retval)
|
if (retval)
|
||||||
{
|
{
|
||||||
throttle();
|
throttle();
|
||||||
|
context->swapchain->set_vsync(config->enable_vsync);
|
||||||
context->swapchain->swap();
|
context->swapchain->swap();
|
||||||
if (config->reduce_input_lag)
|
if (config->reduce_input_lag)
|
||||||
{
|
{
|
||||||
context->wait_idle();
|
context->swapchain->wait_on_frames();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -219,8 +219,9 @@ static bool check_extensions(std::vector<const char *> &required_extensions, vk:
|
||||||
|
|
||||||
bool Context::init_device(int preferred_device)
|
bool Context::init_device(int preferred_device)
|
||||||
{
|
{
|
||||||
std::vector<const char *> required_extensions;
|
std::vector<const char *> required_extensions = {
|
||||||
required_extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
|
||||||
|
};
|
||||||
|
|
||||||
auto device_list = instance->enumeratePhysicalDevices().value;
|
auto device_list = instance->enumeratePhysicalDevices().value;
|
||||||
physical_device = nullptr;
|
physical_device = nullptr;
|
||||||
|
@ -247,15 +248,14 @@ bool Context::init_device(int preferred_device)
|
||||||
auto extension_properties = physical_device.enumerateDeviceExtensionProperties().value;
|
auto extension_properties = physical_device.enumerateDeviceExtensionProperties().value;
|
||||||
physical_device.getProperties(&physical_device_props);
|
physical_device.getProperties(&physical_device_props);
|
||||||
|
|
||||||
if (find_extension(extension_properties, VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME))
|
|
||||||
required_extensions.push_back(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
|
|
||||||
|
|
||||||
graphics_queue_family_index = find_graphics_queue(physical_device);
|
graphics_queue_family_index = find_graphics_queue(physical_device);
|
||||||
if (graphics_queue_family_index == UINT32_MAX)
|
if (graphics_queue_family_index == UINT32_MAX)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
vk::DeviceQueueCreateInfo dqci({}, graphics_queue_family_index, 1);
|
std::vector<float> priorities = { 1.0f };
|
||||||
vk::DeviceCreateInfo dci({}, dqci, {}, required_extensions, {});
|
vk::DeviceQueueCreateInfo dqci({}, graphics_queue_family_index, priorities);
|
||||||
|
vk::DeviceCreateInfo dci({}, dqci, {}, required_extensions);
|
||||||
|
|
||||||
device = physical_device.createDevice(dci).value;
|
device = physical_device.createDevice(dci).value;
|
||||||
queue = device.getQueue(graphics_queue_family_index, 0);
|
queue = device.getQueue(graphics_queue_family_index, 0);
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#include "vulkan_swapchain.hpp"
|
#include "vulkan_swapchain.hpp"
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
namespace Vulkan
|
namespace Vulkan
|
||||||
{
|
{
|
||||||
|
@ -80,7 +79,9 @@ void Swapchain::create_render_pass()
|
||||||
|
|
||||||
bool Swapchain::recreate(int new_width, int new_height)
|
bool Swapchain::recreate(int new_width, int new_height)
|
||||||
{
|
{
|
||||||
device.waitIdle();
|
if (swapchain_object)
|
||||||
|
wait_on_frames();
|
||||||
|
|
||||||
return create(num_swapchain_images, new_width, new_height);
|
return create(num_swapchain_images, new_width, new_height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,24 +165,24 @@ bool Swapchain::create(unsigned int desired_num_swapchain_images, int new_width,
|
||||||
extents.height = surface_capabilities.minImageExtent.height;
|
extents.height = surface_capabilities.minImageExtent.height;
|
||||||
|
|
||||||
auto present_modes = physical_device.getSurfacePresentModesKHR(surface).value;
|
auto present_modes = physical_device.getSurfacePresentModesKHR(surface).value;
|
||||||
bool mailbox_supported =
|
supports_mailbox =
|
||||||
std::find(present_modes.begin(), present_modes.end(),
|
std::find(present_modes.begin(), present_modes.end(),
|
||||||
vk::PresentModeKHR::eMailbox) != present_modes.end();
|
vk::PresentModeKHR::eMailbox) != present_modes.end();
|
||||||
bool immediate_supported =
|
supports_immediate =
|
||||||
std::find(present_modes.begin(), present_modes.end(),
|
std::find(present_modes.begin(), present_modes.end(),
|
||||||
vk::PresentModeKHR::eImmediate) != present_modes.end();
|
vk::PresentModeKHR::eImmediate) != present_modes.end();
|
||||||
|
|
||||||
vk::PresentModeKHR present_mode = vk::PresentModeKHR::eFifo;
|
auto present_mode = vk::PresentModeKHR::eFifo;
|
||||||
if (!vsync)
|
if (!vsync)
|
||||||
{
|
{
|
||||||
if (mailbox_supported)
|
if (supports_mailbox)
|
||||||
present_mode = vk::PresentModeKHR::eMailbox;
|
present_mode = vk::PresentModeKHR::eMailbox;
|
||||||
if (immediate_supported)
|
if (supports_immediate)
|
||||||
present_mode = vk::PresentModeKHR::eImmediate;
|
present_mode = vk::PresentModeKHR::eImmediate;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (present_mode == vk::PresentModeKHR::eMailbox)
|
auto swapchain_maintenance_info = vk::SwapchainPresentModesCreateInfoEXT{}
|
||||||
num_swapchain_images++;
|
.setPresentModes(present_modes);
|
||||||
|
|
||||||
auto swapchain_create_info = vk::SwapchainCreateInfoKHR{}
|
auto swapchain_create_info = vk::SwapchainCreateInfoKHR{}
|
||||||
.setMinImageCount(num_swapchain_images)
|
.setMinImageCount(num_swapchain_images)
|
||||||
|
@ -196,7 +197,8 @@ bool Swapchain::create(unsigned int desired_num_swapchain_images, int new_width,
|
||||||
.setSurface(surface)
|
.setSurface(surface)
|
||||||
.setPreTransform(vk::SurfaceTransformFlagBitsKHR::eIdentity)
|
.setPreTransform(vk::SurfaceTransformFlagBitsKHR::eIdentity)
|
||||||
.setImageArrayLayers(1)
|
.setImageArrayLayers(1)
|
||||||
.setQueueFamilyIndices(graphics_queue_index);
|
.setQueueFamilyIndices(graphics_queue_index)
|
||||||
|
.setPNext(&swapchain_maintenance_info);
|
||||||
|
|
||||||
swapchain_object.reset();
|
swapchain_object.reset();
|
||||||
auto resval = device.createSwapchainKHRUnique(swapchain_create_info);
|
auto resval = device.createSwapchainKHRUnique(swapchain_create_info);
|
||||||
|
@ -207,12 +209,19 @@ bool Swapchain::create(unsigned int desired_num_swapchain_images, int new_width,
|
||||||
}
|
}
|
||||||
swapchain_object = std::move(resval.value);
|
swapchain_object = std::move(resval.value);
|
||||||
|
|
||||||
auto swapchain_images = device.getSwapchainImagesKHR(swapchain_object.get()).value;
|
create_resources();
|
||||||
vk::CommandBufferAllocateInfo command_buffer_allocate_info(command_pool, vk::CommandBufferLevel::ePrimary, swapchain_images.size());
|
|
||||||
auto command_buffers = device.allocateCommandBuffersUnique(command_buffer_allocate_info).value;
|
|
||||||
|
|
||||||
if (imageviewfbs.size() > num_swapchain_images)
|
return true;
|
||||||
num_swapchain_images = imageviewfbs.size();
|
}
|
||||||
|
|
||||||
|
bool Swapchain::create_resources()
|
||||||
|
{
|
||||||
|
auto swapchain_images = device.getSwapchainImagesKHR(swapchain_object.get()).value;
|
||||||
|
if (swapchain_images.size() > num_swapchain_images)
|
||||||
|
num_swapchain_images = swapchain_images.size();
|
||||||
|
|
||||||
|
vk::CommandBufferAllocateInfo command_buffer_allocate_info(command_pool, vk::CommandBufferLevel::ePrimary, num_swapchain_images);
|
||||||
|
auto command_buffers = device.allocateCommandBuffersUnique(command_buffer_allocate_info).value;
|
||||||
|
|
||||||
frames.resize(num_swapchain_images);
|
frames.resize(num_swapchain_images);
|
||||||
imageviewfbs.resize(num_swapchain_images);
|
imageviewfbs.resize(num_swapchain_images);
|
||||||
|
@ -225,10 +234,10 @@ bool Swapchain::create(unsigned int desired_num_swapchain_images, int new_width,
|
||||||
auto &frame = frames[i];
|
auto &frame = frames[i];
|
||||||
frame.command_buffer = std::move(command_buffers[i]);
|
frame.command_buffer = std::move(command_buffers[i]);
|
||||||
frame.fence = device.createFenceUnique(fence_create_info).value;
|
frame.fence = device.createFenceUnique(fence_create_info).value;
|
||||||
|
frame.freeable = device.createFenceUnique(fence_create_info).value;
|
||||||
frame.acquire = device.createSemaphoreUnique({}).value;
|
frame.acquire = device.createSemaphoreUnique({}).value;
|
||||||
frame.complete = device.createSemaphoreUnique({}).value;
|
frame.complete = device.createSemaphoreUnique({}).value;
|
||||||
}
|
}
|
||||||
current_frame = 0;
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < num_swapchain_images; i++)
|
for (unsigned int i = 0; i < num_swapchain_images; i++)
|
||||||
{
|
{
|
||||||
|
@ -252,9 +261,8 @@ bool Swapchain::create(unsigned int desired_num_swapchain_images, int new_width,
|
||||||
image.framebuffer = device.createFramebufferUnique(framebuffer_create_info).value;
|
image.framebuffer = device.createFramebufferUnique(framebuffer_create_info).value;
|
||||||
}
|
}
|
||||||
|
|
||||||
device.waitIdle();
|
|
||||||
|
|
||||||
current_swapchain_image = 0;
|
current_swapchain_image = 0;
|
||||||
|
current_frame = 0;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -269,7 +277,7 @@ bool Swapchain::begin_frame()
|
||||||
|
|
||||||
auto &frame = frames[current_frame];
|
auto &frame = frames[current_frame];
|
||||||
|
|
||||||
auto result = device.waitForFences(frame.fence.get(), true, 33333333);
|
auto result = device.waitForFences({ frame.fence.get(), frame.freeable.get() }, true, 33333333);
|
||||||
if (result != vk::Result::eSuccess)
|
if (result != vk::Result::eSuccess)
|
||||||
{
|
{
|
||||||
printf("Timed out waiting for fence.\n");
|
printf("Timed out waiting for fence.\n");
|
||||||
|
@ -330,8 +338,23 @@ bool Swapchain::swap()
|
||||||
.setSwapchains(swapchain_object.get())
|
.setSwapchains(swapchain_object.get())
|
||||||
.setImageIndices(current_swapchain_image);
|
.setImageIndices(current_swapchain_image);
|
||||||
|
|
||||||
vk::Result result = vk::Result::eSuccess;
|
vk::SwapchainPresentModeInfoEXT present_mode_info;
|
||||||
result = queue.presentKHR(present_info);
|
vk::PresentModeKHR present_mode = vk::PresentModeKHR::eFifo;
|
||||||
|
if (!vsync)
|
||||||
|
{
|
||||||
|
if (supports_mailbox)
|
||||||
|
present_mode = vk::PresentModeKHR::eMailbox;
|
||||||
|
if (supports_immediate)
|
||||||
|
present_mode = vk::PresentModeKHR::eImmediate;
|
||||||
|
}
|
||||||
|
present_mode_info.setPresentModes(present_mode);
|
||||||
|
present_info.setPNext(&present_mode_info);
|
||||||
|
|
||||||
|
device.resetFences(frames[current_frame].freeable.get());
|
||||||
|
vk::SwapchainPresentFenceInfoEXT present_fence_info(frames[current_frame].freeable.get());
|
||||||
|
present_mode_info.setPNext(&present_fence_info);
|
||||||
|
|
||||||
|
vk::Result result = queue.presentKHR(present_info);
|
||||||
if (result == vk::Result::eErrorOutOfDateKHR)
|
if (result == vk::Result::eErrorOutOfDateKHR)
|
||||||
{
|
{
|
||||||
// NVIDIA binary drivers will set OutOfDate between acquire and
|
// NVIDIA binary drivers will set OutOfDate between acquire and
|
||||||
|
@ -389,10 +412,16 @@ void Swapchain::end_render_pass()
|
||||||
|
|
||||||
bool Swapchain::wait_on_frame(int frame_num)
|
bool Swapchain::wait_on_frame(int frame_num)
|
||||||
{
|
{
|
||||||
auto result = device.waitForFences(frames[frame_num].fence.get(), true, 33000000);
|
auto result = device.waitForFences({ frames[frame_num].fence.get(), frames[frame_num].freeable.get() }, true, 133000000);
|
||||||
return (result == vk::Result::eSuccess);
|
return (result == vk::Result::eSuccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Swapchain::wait_on_frames()
|
||||||
|
{
|
||||||
|
for (auto i = 0; i < frames.size(); i++)
|
||||||
|
wait_on_frame(i);
|
||||||
|
}
|
||||||
|
|
||||||
vk::Extent2D Swapchain::get_extents()
|
vk::Extent2D Swapchain::get_extents()
|
||||||
{
|
{
|
||||||
return extents;
|
return extents;
|
||||||
|
|
|
@ -17,6 +17,7 @@ class Swapchain
|
||||||
~Swapchain();
|
~Swapchain();
|
||||||
bool create(unsigned int num_frames, int width = -1, int height = -1);
|
bool create(unsigned int num_frames, int width = -1, int height = -1);
|
||||||
bool recreate(int width = -1, int height = -1);
|
bool recreate(int width = -1, int height = -1);
|
||||||
|
bool create_resources();
|
||||||
bool check_and_resize(int width = -1, int height = -1);
|
bool check_and_resize(int width = -1, int height = -1);
|
||||||
bool begin_frame();
|
bool begin_frame();
|
||||||
void begin_render_pass();
|
void begin_render_pass();
|
||||||
|
@ -25,6 +26,7 @@ class Swapchain
|
||||||
bool end_frame();
|
bool end_frame();
|
||||||
void end_frame_without_swap();
|
void end_frame_without_swap();
|
||||||
bool swap();
|
bool swap();
|
||||||
|
void wait_on_frames();
|
||||||
// Returns true if vsync setting was changed, false if it was the same
|
// Returns true if vsync setting was changed, false if it was the same
|
||||||
bool set_vsync(bool on);
|
bool set_vsync(bool on);
|
||||||
void on_render_pass_end(std::function<void()> function);
|
void on_render_pass_end(std::function<void()> function);
|
||||||
|
@ -43,6 +45,7 @@ class Swapchain
|
||||||
struct Frame
|
struct Frame
|
||||||
{
|
{
|
||||||
vk::UniqueFence fence;
|
vk::UniqueFence fence;
|
||||||
|
vk::UniqueFence freeable;
|
||||||
vk::UniqueSemaphore acquire;
|
vk::UniqueSemaphore acquire;
|
||||||
vk::UniqueSemaphore complete;
|
vk::UniqueSemaphore complete;
|
||||||
vk::UniqueCommandBuffer command_buffer;
|
vk::UniqueCommandBuffer command_buffer;
|
||||||
|
@ -64,6 +67,8 @@ class Swapchain
|
||||||
unsigned int current_swapchain_image = 0;
|
unsigned int current_swapchain_image = 0;
|
||||||
unsigned int num_swapchain_images = 0;
|
unsigned int num_swapchain_images = 0;
|
||||||
bool vsync = true;
|
bool vsync = true;
|
||||||
|
bool supports_immediate = false;
|
||||||
|
bool supports_mailbox = false;
|
||||||
std::vector<Frame> frames;
|
std::vector<Frame> frames;
|
||||||
std::vector<ImageViewFB> imageviewfbs;
|
std::vector<ImageViewFB> imageviewfbs;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue