mirror of
https://github.com/libretro/RetroArch
synced 2025-04-01 04:20:27 +00:00
Support pending swapchain creation.
This commit is contained in:
parent
ac42b87400
commit
75b84b4f94
@ -28,6 +28,7 @@
|
||||
#endif
|
||||
|
||||
#include "vulkan_common.h"
|
||||
#include "../../libretro-common/include/retro_timers.h"
|
||||
#include "../../configuration.h"
|
||||
|
||||
static dylib_t vulkan_library;
|
||||
@ -2162,6 +2163,7 @@ bool vulkan_surface_create(gfx_ctx_vulkan_data_t *vk,
|
||||
vk, width, height, swap_interval))
|
||||
return false;
|
||||
|
||||
vulkan_acquire_next_image(vk);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2171,6 +2173,13 @@ void vulkan_present(gfx_ctx_vulkan_data_t *vk, unsigned index)
|
||||
VkResult result = VK_SUCCESS;
|
||||
VkResult err = VK_SUCCESS;
|
||||
|
||||
/* We're still waiting for a proper swapchain, so just fake it. */
|
||||
if (vk->swapchain == VK_NULL_HANDLE)
|
||||
{
|
||||
retro_sleep(10);
|
||||
return;
|
||||
}
|
||||
|
||||
present.swapchainCount = 1;
|
||||
present.pSwapchains = &vk->swapchain;
|
||||
present.pImageIndices = &index;
|
||||
@ -2253,18 +2262,71 @@ void vulkan_context_destroy(gfx_ctx_vulkan_data_t *vk,
|
||||
}
|
||||
}
|
||||
|
||||
static void vulkan_acquire_clear_fences(gfx_ctx_vulkan_data_t *vk)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < vk->context.num_swapchain_images; i++)
|
||||
{
|
||||
if (vk->context.swapchain_fences[i])
|
||||
{
|
||||
vkDestroyFence(vk->context.device,
|
||||
vk->context.swapchain_fences[i], NULL);
|
||||
vk->context.swapchain_fences[i] = VK_NULL_HANDLE;
|
||||
vk->context.swapchain_fences_signalled[i] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void vulkan_acquire_wait_fences(gfx_ctx_vulkan_data_t *vk)
|
||||
{
|
||||
VkFenceCreateInfo fence_info =
|
||||
{ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO };
|
||||
|
||||
unsigned index = vk->context.current_swapchain_index;
|
||||
VkFence *next_fence = &vk->context.swapchain_fences[index];
|
||||
|
||||
if (*next_fence != VK_NULL_HANDLE)
|
||||
{
|
||||
if (vk->context.swapchain_fences_signalled[index])
|
||||
vkWaitForFences(vk->context.device, 1, next_fence, true, UINT64_MAX);
|
||||
vkResetFences(vk->context.device, 1, next_fence);
|
||||
vk->context.swapchain_fences_signalled[index] = false;
|
||||
}
|
||||
else
|
||||
vkCreateFence(vk->context.device, &fence_info, NULL, next_fence);
|
||||
}
|
||||
|
||||
void vulkan_acquire_next_image(gfx_ctx_vulkan_data_t *vk)
|
||||
{
|
||||
unsigned index;
|
||||
VkResult err;
|
||||
VkFence fence;
|
||||
VkSemaphoreCreateInfo sem_info =
|
||||
{ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO };
|
||||
VkFenceCreateInfo fence_info =
|
||||
{ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO };
|
||||
VkFence *next_fence = NULL;
|
||||
VkSemaphoreCreateInfo sem_info =
|
||||
{ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO };
|
||||
bool is_retrying = false;
|
||||
|
||||
if (vk->swapchain == VK_NULL_HANDLE)
|
||||
{
|
||||
/* We don't have a swapchain, try to create one now. */
|
||||
if (!vulkan_create_swapchain(vk, vk->context.swapchain_width,
|
||||
vk->context.swapchain_height, vk->context.swap_interval))
|
||||
{
|
||||
RARCH_ERR("[Vulkan]: Failed to create new swapchain.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (vk->swapchain == VK_NULL_HANDLE)
|
||||
{
|
||||
/* We still don't have a swapchain, so just fake it ... */
|
||||
vk->context.current_swapchain_index = 0;
|
||||
vulkan_acquire_clear_fences(vk);
|
||||
vulkan_acquire_wait_fences(vk);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
retry:
|
||||
vkCreateFence(vk->context.device, &fence_info, NULL, &fence);
|
||||
|
||||
@ -2281,17 +2343,7 @@ retry:
|
||||
vkWaitForFences(vk->context.device, 1, &fence, true, UINT64_MAX);
|
||||
vkDestroyFence(vk->context.device, fence, NULL);
|
||||
|
||||
next_fence = &vk->context.swapchain_fences[index];
|
||||
|
||||
if (*next_fence != VK_NULL_HANDLE)
|
||||
{
|
||||
if (vk->context.swapchain_fences_signalled[index])
|
||||
vkWaitForFences(vk->context.device, 1, next_fence, true, UINT64_MAX);
|
||||
vkResetFences(vk->context.device, 1, next_fence);
|
||||
vk->context.swapchain_fences_signalled[index] = false;
|
||||
}
|
||||
else
|
||||
vkCreateFence(vk->context.device, &fence_info, NULL, next_fence);
|
||||
vulkan_acquire_wait_fences(vk);
|
||||
|
||||
if (err != VK_SUCCESS)
|
||||
{
|
||||
@ -2430,6 +2482,43 @@ bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk,
|
||||
else
|
||||
swapchain_size = surface_properties.currentExtent;
|
||||
|
||||
#if 0
|
||||
/* Tests for deferred creation. */
|
||||
static unsigned retry_count = 0;
|
||||
if (++retry_count < 50)
|
||||
{
|
||||
surface_properties.maxImageExtent.width = 0;
|
||||
surface_properties.maxImageExtent.height = 0;
|
||||
surface_properties.minImageExtent.width = 0;
|
||||
surface_properties.minImageExtent.height = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Clamp swapchain size to boundaries. */
|
||||
if (swapchain_size.width > surface_properties.maxImageExtent.width)
|
||||
swapchain_size.width = surface_properties.maxImageExtent.width;
|
||||
if (swapchain_size.width < surface_properties.minImageExtent.width)
|
||||
swapchain_size.width = surface_properties.minImageExtent.width;
|
||||
if (swapchain_size.height > surface_properties.maxImageExtent.height)
|
||||
swapchain_size.height = surface_properties.maxImageExtent.height;
|
||||
if (swapchain_size.height < surface_properties.minImageExtent.height)
|
||||
swapchain_size.height = surface_properties.minImageExtent.height;
|
||||
|
||||
if (swapchain_size.width == 0 && swapchain_size.height == 0)
|
||||
{
|
||||
/* Cannot create swapchain yet, try again later. */
|
||||
if (vk->swapchain != VK_NULL_HANDLE)
|
||||
vkDestroySwapchainKHR(vk->context.device, vk->swapchain, NULL);
|
||||
vk->swapchain = VK_NULL_HANDLE;
|
||||
vk->context.swapchain_width = width;
|
||||
vk->context.swapchain_height = height;
|
||||
vk->context.num_swapchain_images = 1;
|
||||
|
||||
memset(vk->context.swapchain_images, 0, sizeof(vk->context.swapchain_images));
|
||||
RARCH_LOG("[Vulkan]: Cannot create a swapchain yet. Will try again later ...\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
RARCH_LOG("[Vulkan]: Using swapchain size %u x %u.\n",
|
||||
swapchain_size.width, swapchain_size.height);
|
||||
|
||||
@ -2531,18 +2620,8 @@ bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk,
|
||||
RARCH_LOG("[Vulkan]: Got %u swapchain images.\n",
|
||||
vk->context.num_swapchain_images);
|
||||
|
||||
for (i = 0; i < vk->context.num_swapchain_images; i++)
|
||||
{
|
||||
if (vk->context.swapchain_fences[i])
|
||||
{
|
||||
vkDestroyFence(vk->context.device,
|
||||
vk->context.swapchain_fences[i], NULL);
|
||||
vk->context.swapchain_fences[i] = VK_NULL_HANDLE;
|
||||
vk->context.swapchain_fences_signalled[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
vulkan_acquire_next_image(vk);
|
||||
vulkan_acquire_clear_fences(vk);
|
||||
vk->context.invalid_swapchain = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -128,7 +128,14 @@ static void vulkan_init_framebuffers(
|
||||
VkFramebufferCreateInfo info =
|
||||
{ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO };
|
||||
|
||||
vk->swapchain[i].backbuffer.image = vk->context->swapchain_images[i];
|
||||
vk->swapchain[i].backbuffer.image = vk->context->swapchain_images[i];
|
||||
|
||||
if (vk->context->swapchain_images[i] == VK_NULL_HANDLE)
|
||||
{
|
||||
vk->swapchain[i].backbuffer.view = VK_NULL_HANDLE;
|
||||
vk->swapchain[i].backbuffer.framebuffer = VK_NULL_HANDLE;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Create an image view which we can render into. */
|
||||
view.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
@ -716,10 +723,17 @@ static void vulkan_deinit_framebuffers(vk_t *vk)
|
||||
unsigned i;
|
||||
for (i = 0; i < vk->num_swapchain_images; i++)
|
||||
{
|
||||
vkDestroyFramebuffer(vk->context->device,
|
||||
vk->swapchain[i].backbuffer.framebuffer, NULL);
|
||||
vkDestroyImageView(vk->context->device,
|
||||
vk->swapchain[i].backbuffer.view, NULL);
|
||||
if (vk->swapchain[i].backbuffer.framebuffer)
|
||||
{
|
||||
vkDestroyFramebuffer(vk->context->device,
|
||||
vk->swapchain[i].backbuffer.framebuffer, NULL);
|
||||
}
|
||||
|
||||
if (vk->swapchain[i].backbuffer.view)
|
||||
{
|
||||
vkDestroyImageView(vk->context->device,
|
||||
vk->swapchain[i].backbuffer.view, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
vkDestroyRenderPass(vk->context->device, vk->render_pass, NULL);
|
||||
@ -1748,88 +1762,92 @@ static bool vulkan_frame(void *data, const void *frame,
|
||||
(vulkan_filter_chain_t*)vk->filter_chain,
|
||||
vk->cmd, &vk->vk_vp);
|
||||
/* Render to backbuffer. */
|
||||
rp_info.renderPass = vk->render_pass;
|
||||
rp_info.framebuffer = chain->backbuffer.framebuffer;
|
||||
rp_info.renderArea.extent.width = vk->context->swapchain_width;
|
||||
rp_info.renderArea.extent.height = vk->context->swapchain_height;
|
||||
rp_info.clearValueCount = 1;
|
||||
rp_info.pClearValues = &clear_color;
|
||||
if (chain->backbuffer.image != VK_NULL_HANDLE)
|
||||
{
|
||||
rp_info.renderPass = vk->render_pass;
|
||||
rp_info.framebuffer = chain->backbuffer.framebuffer;
|
||||
rp_info.renderArea.extent.width = vk->context->swapchain_width;
|
||||
rp_info.renderArea.extent.height = vk->context->swapchain_height;
|
||||
rp_info.clearValueCount = 1;
|
||||
rp_info.pClearValues = &clear_color;
|
||||
|
||||
clear_color.color.float32[0] = 0.0f;
|
||||
clear_color.color.float32[1] = 0.0f;
|
||||
clear_color.color.float32[2] = 0.0f;
|
||||
clear_color.color.float32[3] = 0.0f;
|
||||
clear_color.color.float32[0] = 0.0f;
|
||||
clear_color.color.float32[1] = 0.0f;
|
||||
clear_color.color.float32[2] = 0.0f;
|
||||
clear_color.color.float32[3] = 0.0f;
|
||||
|
||||
/* Prepare backbuffer for rendering. We don't use WSI semaphores here. */
|
||||
vulkan_image_layout_transition(vk, vk->cmd, chain->backbuffer.image,
|
||||
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||
0, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT,
|
||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
|
||||
/* Prepare backbuffer for rendering. We don't use WSI semaphores here. */
|
||||
vulkan_image_layout_transition(vk, vk->cmd, chain->backbuffer.image,
|
||||
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||
0, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT,
|
||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
|
||||
|
||||
/* Begin render pass and set up viewport */
|
||||
vkCmdBeginRenderPass(vk->cmd, &rp_info, VK_SUBPASS_CONTENTS_INLINE);
|
||||
/* Begin render pass and set up viewport */
|
||||
vkCmdBeginRenderPass(vk->cmd, &rp_info, VK_SUBPASS_CONTENTS_INLINE);
|
||||
|
||||
vulkan_filter_chain_build_viewport_pass(
|
||||
(vulkan_filter_chain_t*)vk->filter_chain, vk->cmd,
|
||||
&vk->vk_vp, vk->mvp.data);
|
||||
vulkan_filter_chain_build_viewport_pass(
|
||||
(vulkan_filter_chain_t*)vk->filter_chain, vk->cmd,
|
||||
&vk->vk_vp, vk->mvp.data);
|
||||
|
||||
#if defined(HAVE_MENU)
|
||||
if (vk->menu.enable)
|
||||
{
|
||||
menu_driver_frame(video_info);
|
||||
|
||||
if (vk->menu.textures[vk->menu.last_index].image != VK_NULL_HANDLE)
|
||||
if (vk->menu.enable)
|
||||
{
|
||||
struct vk_draw_quad quad;
|
||||
struct vk_texture *optimal = &vk->menu.textures_optimal[vk->menu.last_index];
|
||||
vulkan_set_viewport(vk, width, height, vk->menu.full_screen, false);
|
||||
menu_driver_frame(video_info);
|
||||
|
||||
quad.pipeline = vk->pipelines.alpha_blend;
|
||||
quad.texture = &vk->menu.textures[vk->menu.last_index];
|
||||
|
||||
if (optimal->memory != VK_NULL_HANDLE)
|
||||
if (vk->menu.textures[vk->menu.last_index].image != VK_NULL_HANDLE)
|
||||
{
|
||||
if (vk->menu.dirty[vk->menu.last_index])
|
||||
struct vk_draw_quad quad;
|
||||
struct vk_texture *optimal = &vk->menu.textures_optimal[vk->menu.last_index];
|
||||
vulkan_set_viewport(vk, width, height, vk->menu.full_screen, false);
|
||||
|
||||
quad.pipeline = vk->pipelines.alpha_blend;
|
||||
quad.texture = &vk->menu.textures[vk->menu.last_index];
|
||||
|
||||
if (optimal->memory != VK_NULL_HANDLE)
|
||||
{
|
||||
vulkan_copy_staging_to_dynamic(vk, vk->cmd,
|
||||
optimal,
|
||||
quad.texture);
|
||||
vk->menu.dirty[vk->menu.last_index] = false;
|
||||
if (vk->menu.dirty[vk->menu.last_index])
|
||||
{
|
||||
vulkan_copy_staging_to_dynamic(vk, vk->cmd,
|
||||
optimal,
|
||||
quad.texture);
|
||||
vk->menu.dirty[vk->menu.last_index] = false;
|
||||
}
|
||||
quad.texture = optimal;
|
||||
}
|
||||
quad.texture = optimal;
|
||||
|
||||
quad.sampler = optimal->mipmap ?
|
||||
vk->samplers.mipmap_linear : vk->samplers.linear;
|
||||
|
||||
quad.mvp = &vk->mvp_no_rot;
|
||||
quad.color.r = 1.0f;
|
||||
quad.color.g = 1.0f;
|
||||
quad.color.b = 1.0f;
|
||||
quad.color.a = vk->menu.alpha;
|
||||
vulkan_draw_quad(vk, &quad);
|
||||
}
|
||||
|
||||
quad.sampler = optimal->mipmap ?
|
||||
vk->samplers.mipmap_linear : vk->samplers.linear;
|
||||
|
||||
quad.mvp = &vk->mvp_no_rot;
|
||||
quad.color.r = 1.0f;
|
||||
quad.color.g = 1.0f;
|
||||
quad.color.b = 1.0f;
|
||||
quad.color.a = vk->menu.alpha;
|
||||
vulkan_draw_quad(vk, &quad);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (msg)
|
||||
font_driver_render_msg(video_info, NULL, msg, NULL);
|
||||
if (msg)
|
||||
font_driver_render_msg(video_info, NULL, msg, NULL);
|
||||
|
||||
#ifdef HAVE_OVERLAY
|
||||
if (vk->overlay.enable)
|
||||
vulkan_render_overlay(vk, video_info);
|
||||
if (vk->overlay.enable)
|
||||
vulkan_render_overlay(vk, video_info);
|
||||
#endif
|
||||
|
||||
/* End the render pass. We're done rendering to backbuffer now. */
|
||||
vkCmdEndRenderPass(vk->cmd);
|
||||
/* End the render pass. We're done rendering to backbuffer now. */
|
||||
vkCmdEndRenderPass(vk->cmd);
|
||||
}
|
||||
|
||||
/* End the filter chain frame.
|
||||
* This must happen outside a render pass.
|
||||
*/
|
||||
vulkan_filter_chain_end_frame((vulkan_filter_chain_t*)vk->filter_chain, vk->cmd);
|
||||
|
||||
if (vk->readback.pending || vk->readback.streamed)
|
||||
if (chain->backbuffer.image != VK_NULL_HANDLE &&
|
||||
(vk->readback.pending || vk->readback.streamed))
|
||||
{
|
||||
/* We cannot safely read back from an image which
|
||||
* has already been presented as we need to
|
||||
@ -1860,7 +1878,7 @@ static bool vulkan_frame(void *data, const void *frame,
|
||||
|
||||
vk->readback.pending = false;
|
||||
}
|
||||
else
|
||||
else if (chain->backbuffer.image != VK_NULL_HANDLE)
|
||||
{
|
||||
/* Prepare backbuffer for presentation. */
|
||||
vulkan_image_layout_transition(vk, vk->cmd,
|
||||
@ -1930,7 +1948,6 @@ static bool vulkan_frame(void *data, const void *frame,
|
||||
}
|
||||
submit_info.pSignalSemaphores = submit_info.signalSemaphoreCount ? signal_semaphores : NULL;
|
||||
|
||||
|
||||
#ifdef HAVE_THREADS
|
||||
slock_lock(vk->context->queue_lock);
|
||||
#endif
|
||||
|
@ -281,6 +281,7 @@ static bool android_gfx_ctx_set_resize(void *data,
|
||||
return false;
|
||||
}
|
||||
|
||||
vulkan_acquire_next_image(&and->vk);
|
||||
and->vk.context.invalid_swapchain = true;
|
||||
and->vk.need_new_swapchain = false;
|
||||
#endif
|
||||
|
@ -103,6 +103,8 @@ static bool gfx_ctx_khr_display_set_resize(void *data,
|
||||
return false;
|
||||
}
|
||||
|
||||
vulkan_acquire_next_image(&khr->vk);
|
||||
|
||||
khr->vk.context.invalid_swapchain = true;
|
||||
khr->vk.need_new_swapchain = false;
|
||||
return false;
|
||||
|
@ -684,7 +684,10 @@ static bool gfx_ctx_wl_set_resize(void *data, unsigned width, unsigned height)
|
||||
wl->height = height;
|
||||
|
||||
if (vulkan_create_swapchain(&wl->vk, width, height, wl->swap_interval))
|
||||
{
|
||||
wl->vk.context.invalid_swapchain = true;
|
||||
vulkan_acquire_next_image(&wl->vk);
|
||||
}
|
||||
else
|
||||
{
|
||||
RARCH_ERR("[Wayland/Vulkan]: Failed to update swapchain.\n");
|
||||
|
@ -395,6 +395,7 @@ static bool gfx_ctx_wgl_set_resize(void *data,
|
||||
return false;
|
||||
}
|
||||
|
||||
vulkan_acquire_next_image(&win32_vk);
|
||||
win32_vk.context.invalid_swapchain = true;
|
||||
win32_vk.need_new_swapchain = false;
|
||||
#endif
|
||||
|
@ -448,6 +448,7 @@ static bool gfx_ctx_x_set_resize(void *data,
|
||||
return false;
|
||||
}
|
||||
|
||||
vulkan_acquire_next_image(&x->vk);
|
||||
x->vk.context.invalid_swapchain = true;
|
||||
x->vk.need_new_swapchain = false;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user