Skip to content

Commit 473bcb5

Browse files
committed
Wait fence in vkQueuePresentKHR
1 parent 508f79e commit 473bcb5

File tree

1 file changed

+63
-20
lines changed

1 file changed

+63
-20
lines changed

dlls/winex11.drv/vulkan.c

Lines changed: 63 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ static XContext vulkan_swapchain_context;
6060

6161
static struct list surface_list = LIST_INIT( surface_list );
6262

63+
#define NO_IMAGE_INDEX UINT32_MAX
64+
6365
struct wine_vk_surface
6466
{
6567
LONG ref;
@@ -73,6 +75,8 @@ struct wine_vk_surface
7375
HDC hdc;
7476
HWND hwnd;
7577
DWORD hwnd_thread_id;
78+
VkDevice device;
79+
uint32_t next_image_index;
7680
};
7781

7882
typedef struct VkXlibSurfaceCreateInfoKHR
@@ -108,6 +112,8 @@ static VkResult (*pvkQueuePresentKHR)(VkQueue, const VkPresentInfoKHR *);
108112
static VkResult (*pvkWaitForFences)(VkDevice device, uint32_t fenceCount, const VkFence *pFences, VkBool32 waitAll, uint64_t timeout);
109113
static VkResult (*pvkCreateFence)(VkDevice device, const VkFenceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkFence *pFence);
110114
static void (*pvkDestroyFence)(VkDevice device, VkFence fence, const VkAllocationCallbacks *pAllocator);
115+
static void (*pvkGetDeviceQueue)(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue* pQueue);
116+
static VkResult (*pvkQueueSubmit)(VkQueue queue, uint32_t submitCount, const VkSubmitInfo* pSubmits, VkFence fence);
111117

112118
static void *X11DRV_get_vk_device_proc_addr(const char *name);
113119
static void *X11DRV_get_vk_instance_proc_addr(VkInstance instance, const char *name);
@@ -153,6 +159,8 @@ static BOOL WINAPI wine_vk_init(INIT_ONCE *once, void *param, void **context)
153159
LOAD_FUNCPTR(vkWaitForFences);
154160
LOAD_FUNCPTR(vkCreateFence);
155161
LOAD_FUNCPTR(vkDestroyFence);
162+
LOAD_FUNCPTR(vkGetDeviceQueue);
163+
LOAD_FUNCPTR(vkQueueSubmit);
156164
#undef LOAD_FUNCPTR
157165
#undef LOAD_OPTIONAL_FUNCPTR
158166

@@ -405,15 +413,12 @@ static VkResult X11DRV_vkAcquireNextImageKHR(VkDevice device,
405413
{
406414
struct wine_vk_surface *surface = NULL;
407415
VkResult result;
408-
VkFence orig_fence;
409416
BOOL wait_fence = FALSE;
410-
HDC hdc = 0;
411417

412418
EnterCriticalSection(&context_section);
413419
if (!XFindContext(gdi_display, (XID)swapchain, vulkan_swapchain_context, (char **)&surface))
414420
{
415421
wine_vk_surface_grab(surface);
416-
hdc = surface->hdc;
417422
}
418423
LeaveCriticalSection(&context_section);
419424

@@ -423,25 +428,44 @@ static VkResult X11DRV_vkAcquireNextImageKHR(VkDevice device,
423428
surface->present_mode == VK_PRESENT_MODE_FIFO_KHR)
424429
wait_fence = TRUE;
425430

426-
orig_fence = fence;
427-
if (wait_fence && !fence)
431+
if(wait_fence && surface->next_image_index != NO_IMAGE_INDEX)
428432
{
429-
VkFenceCreateInfo create_info;
430-
create_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
431-
create_info.pNext = NULL;
432-
create_info.flags = 0;
433-
pvkCreateFence(device, &create_info, NULL, &fence);
434-
}
433+
//the app expets the fence and the semaphore to be signaled
434+
VkSubmitInfo submit_info;
435+
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
436+
submit_info.pNext = NULL;
437+
submit_info.waitSemaphoreCount = 0;
438+
submit_info.pWaitSemaphores = NULL;
439+
submit_info.pWaitDstStageMask = NULL;
440+
submit_info.commandBufferCount = 0;
441+
submit_info.pCommandBuffers = NULL;
442+
submit_info.signalSemaphoreCount = semaphore != VK_NULL_HANDLE;
443+
submit_info.pSignalSemaphores = &semaphore;
444+
445+
VkQueue queue = NULL;
446+
pvkGetDeviceQueue(device, 0, 0, &queue);
447+
if(!queue)
448+
{
449+
return VK_NOT_READY; //random error
450+
}
451+
452+
VkResult submit_result = pvkQueueSubmit(queue, 1, &submit_info, fence);
453+
if(submit_result != VK_SUCCESS)
454+
{
455+
return submit_result;
456+
}
457+
458+
*image_index = surface->next_image_index;
435459

436-
result = pvkAcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, image_index);
437-
if ((result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR) && hdc && surface && surface->offscreen)
460+
461+
if (surface) wine_vk_surface_release(surface);
462+
463+
return VK_SUCCESS;
464+
}
465+
else
438466
{
439-
if (wait_fence) pvkWaitForFences(device, 1, &fence, 0, timeout);
467+
return pvkAcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, image_index);
440468
}
441-
442-
if (fence != orig_fence) pvkDestroyFence(device, fence, NULL);
443-
if (surface) wine_vk_surface_release(surface);
444-
return result;
445469
}
446470

447471
static VkResult X11DRV_vkAcquireNextImage2KHR(VkDevice device,
@@ -466,6 +490,9 @@ static VkResult X11DRV_vkCreateSwapchainKHR(VkDevice device,
466490
VkSwapchainCreateInfoKHR create_info_host;
467491
VkResult result;
468492

493+
x11_surface->next_image_index = NO_IMAGE_INDEX;
494+
x11_surface->device = device;
495+
469496
TRACE("%p %p %p %p\n", device, create_info, allocator, swapchain);
470497

471498
if (allocator)
@@ -865,7 +892,7 @@ static VkResult X11DRV_vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *
865892
static int once;
866893
struct x11drv_escape_present_drawable escape;
867894
struct wine_vk_surface *surface = NULL;
868-
VkFence orig_fence;
895+
VkFence acquire_fence;
869896
BOOL wait_fence = FALSE;
870897
HDC hdc = 0;
871898

@@ -908,12 +935,28 @@ static VkResult X11DRV_vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *
908935
}
909936
LeaveCriticalSection(&context_section);
910937

938+
BOOL needs_sync = surface->present_mode == VK_PRESENT_MODE_MAILBOX_KHR ||
939+
surface->present_mode == VK_PRESENT_MODE_FIFO_KHR;
940+
941+
//if needed wait fence to avoid tearing
942+
if (hdc && surface && surface->offscreen && needs_sync)
943+
{
944+
VkFenceCreateInfo create_info;
945+
create_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
946+
create_info.pNext = NULL;
947+
create_info.flags = 0;
948+
pvkCreateFence(surface->device, &create_info, NULL, &acquire_fence);
949+
950+
pvkAcquireNextImageKHR(surface->device, swapchain, UINT64_MAX, VK_NULL_HANDLE, acquire_fence, &surface->next_image_index);
951+
952+
pvkWaitForFences(surface->device, 1, &acquire_fence, 0, UINT64_MAX);
953+
}
954+
911955
if (hdc && surface && surface->offscreen)
912956
{
913957
escape.code = X11DRV_PRESENT_DRAWABLE;
914958
escape.drawable = surface->window;
915959
escape.flush = TRUE;
916-
917960
ExtEscape(hdc, X11DRV_ESCAPE, sizeof(escape), (char *)&escape, 0, NULL);
918961
if (surface->present_mode == VK_PRESENT_MODE_MAILBOX_KHR)
919962
if (once++) FIXME("Application requires child window rendering with mailbox present mode, expect possible tearing!\n");

0 commit comments

Comments
 (0)