Vulkan: Emulate mailbox on Windows.

This commit is contained in:
Themaister 2018-09-02 17:52:06 +02:00
parent af534f0fa8
commit 9ebac87638
3 changed files with 58 additions and 8 deletions

View File

@ -38,6 +38,12 @@
#include "../../libretro-common/include/retro_math.h"
#include "../../libretro-common/include/string/stdstring.h"
// Windows is not particularly good at recreating swapchains.
// Emulate vsync toggling by using vkAcquireNextImageKHR timeouts.
#if defined(_WIN32)
#define VULKAN_EMULATE_MAILBOX
#endif
static dylib_t vulkan_library;
static VkInstance cached_instance_vk;
static VkDevice cached_device_vk;
@ -1494,6 +1500,10 @@ static bool vulkan_context_init_device(gfx_ctx_vulkan_data_t *vk)
"VK_KHR_sampler_mirror_clamp_to_edge",
};
#ifdef VULKAN_EMULATE_MAILBOX
vk->emulate_mailbox = true;
#endif
#ifdef VULKAN_DEBUG
static const char *device_layers[] = { "VK_LAYER_LUNARG_standard_validation" };
#endif
@ -2333,6 +2343,7 @@ static void vulkan_destroy_swapchain(gfx_ctx_vulkan_data_t *vk)
vkDestroySwapchainKHR(vk->context.device, vk->swapchain, NULL);
memset(vk->context.swapchain_images, 0, sizeof(vk->context.swapchain_images));
vk->swapchain = VK_NULL_HANDLE;
vk->context.has_acquired_swapchain = false;
}
for (i = 0; i < VULKAN_MAX_SWAPCHAIN_IMAGES; i++)
@ -2351,9 +2362,13 @@ static void vulkan_destroy_swapchain(gfx_ctx_vulkan_data_t *vk)
void vulkan_present(gfx_ctx_vulkan_data_t *vk, unsigned index)
{
VkPresentInfoKHR present = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR };
VkResult result = VK_SUCCESS;
VkResult err = VK_SUCCESS;
VkPresentInfoKHR present = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR };
VkResult result = VK_SUCCESS;
VkResult err = VK_SUCCESS;
if (!vk->context.has_acquired_swapchain)
return;
vk->context.has_acquired_swapchain = false;
/* We're still waiting for a proper swapchain, so just fake it. */
if (vk->swapchain == VK_NULL_HANDLE)
@ -2525,12 +2540,29 @@ retry:
vkCreateFence(vk->context.device, &fence_info, NULL, &fence);
err = vkAcquireNextImageKHR(vk->context.device,
vk->swapchain, UINT64_MAX,
VK_NULL_HANDLE, fence, &vk->context.current_swapchain_index);
if (vk->emulating_mailbox)
{
/* Non-blocking acquire. If we don't get a swapchain frame right away,
* just skip rendering to the swapchain this frame, similar to what
* MAILBOX would do. */
err = vkAcquireNextImageKHR(vk->context.device,
vk->swapchain, 0,
VK_NULL_HANDLE, fence, &vk->context.current_swapchain_index);
}
else
{
err = vkAcquireNextImageKHR(vk->context.device,
vk->swapchain, UINT64_MAX,
VK_NULL_HANDLE, fence, &vk->context.current_swapchain_index);
}
if (err == VK_SUCCESS)
{
vkWaitForFences(vk->context.device, 1, &fence, true, UINT64_MAX);
vk->context.has_acquired_swapchain = true;
}
else
vk->context.has_acquired_swapchain = false;
#ifdef WSI_HARDENING_TEST
trigger_spurious_error_vkresult(&err);
@ -2538,7 +2570,13 @@ retry:
vkDestroyFence(vk->context.device, fence, NULL);
if (err == VK_ERROR_OUT_OF_DATE_KHR)
if (err == VK_NOT_READY || err == VK_TIMEOUT)
{
/* Just pretend we have a swapchain index, round-robin style. */
vk->context.current_swapchain_index =
(vk->context.current_swapchain_index + 1) % vk->context.num_swapchain_images;
}
else if (err == VK_ERROR_OUT_OF_DATE_KHR)
{
/* Throw away the old swapchain and try again. */
vulkan_destroy_swapchain(vk);
@ -2601,6 +2639,14 @@ bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk,
vkDeviceWaitIdle(vk->context.device);
vulkan_acquire_clear_fences(vk);
if (swap_interval == 0 && vk->emulate_mailbox)
{
swap_interval = 1;
vk->emulating_mailbox = true;
}
else
vk->emulating_mailbox = false;
vk->created_new_swapchain = true;
if (vk->swapchain != VK_NULL_HANDLE &&
!vk->context.invalid_swapchain &&

View File

@ -96,6 +96,7 @@ typedef struct vulkan_context
/* Used by screenshot to get blits with correct colorspace. */
bool swapchain_is_srgb;
bool swap_interval_emulation_lock;
bool has_acquired_swapchain;
unsigned swapchain_width;
unsigned swapchain_height;
@ -131,6 +132,8 @@ typedef struct gfx_ctx_vulkan_data
{
bool need_new_swapchain;
bool created_new_swapchain;
bool emulate_mailbox;
bool emulating_mailbox;
vulkan_context_t context;
VkSurfaceKHR vk_surface;
VkSwapchainKHR swapchain;

View File

@ -1778,7 +1778,7 @@ static bool vulkan_frame(void *data, const void *frame,
(vulkan_filter_chain_t*)vk->filter_chain,
vk->cmd, &vk->vk_vp);
/* Render to backbuffer. */
if (chain->backbuffer.image != VK_NULL_HANDLE)
if (chain->backbuffer.image != VK_NULL_HANDLE && vk->context->has_acquired_swapchain)
{
rp_info.renderPass = vk->render_pass;
rp_info.framebuffer = chain->backbuffer.framebuffer;
@ -1874,6 +1874,7 @@ static bool vulkan_frame(void *data, const void *frame,
vulkan_filter_chain_end_frame((vulkan_filter_chain_t*)vk->filter_chain, vk->cmd);
if (chain->backbuffer.image != VK_NULL_HANDLE &&
vk->context->has_acquired_swapchain &&
(vk->readback.pending || vk->readback.streamed))
{
/* We cannot safely read back from an image which