Skip to content

Commit 3a8676b

Browse files
committed
Wait fence in vkQueuePresentKHR
1 parent 919bcbb commit 3a8676b

File tree

1 file changed

+106
-1
lines changed

1 file changed

+106
-1
lines changed

dlls/winex11.drv/vulkan.c

+106-1
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

@@ -403,7 +411,64 @@ static VkResult X11DRV_vkAcquireNextImageKHR(VkDevice device,
403411
VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore,
404412
VkFence fence, uint32_t *image_index)
405413
{
406-
return pvkAcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, image_index);
414+
struct wine_vk_surface *surface = NULL;
415+
VkResult result;
416+
VkFence orig_fence;
417+
BOOL wait_fence = FALSE;
418+
HDC hdc = 0;
419+
420+
EnterCriticalSection(&context_section);
421+
if (!XFindContext(gdi_display, (XID)swapchain, vulkan_swapchain_context, (char **)&surface))
422+
{
423+
wine_vk_surface_grab(surface);
424+
hdc = surface->hdc;
425+
}
426+
LeaveCriticalSection(&context_section);
427+
428+
if (!surface || !surface->offscreen)
429+
wait_fence = FALSE;
430+
else if (surface->present_mode == VK_PRESENT_MODE_MAILBOX_KHR ||
431+
surface->present_mode == VK_PRESENT_MODE_FIFO_KHR)
432+
wait_fence = TRUE;
433+
434+
if(wait_fence && surface->next_image_index != NO_IMAGE_INDEX)
435+
{
436+
//prevent deadlock
437+
VkSubmitInfo submit_info;
438+
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
439+
submit_info.pNext = NULL;
440+
submit_info.waitSemaphoreCount = 0;
441+
submit_info.pWaitSemaphores = NULL;
442+
submit_info.pWaitDstStageMask = NULL;
443+
submit_info.commandBufferCount = 0;
444+
submit_info.pCommandBuffers = NULL;
445+
submit_info.signalSemaphoreCount = semaphore != VK_NULL_HANDLE;
446+
submit_info.pSignalSemaphores = &semaphore;
447+
448+
VkQueue queue = NULL;
449+
pvkGetDeviceQueue(device, 0, 0, &queue);
450+
if(!queue)
451+
{
452+
return VK_NOT_READY; //random error
453+
}
454+
455+
VkResult submit_result = pvkQueueSubmit(queue, 1, &submit_info, fence);
456+
if(submit_result != VK_SUCCESS)
457+
{
458+
return submit_result;
459+
}
460+
461+
*image_index = surface->next_image_index;
462+
463+
464+
if (surface) wine_vk_surface_release(surface);
465+
466+
return VK_SUCCESS;
467+
}
468+
else
469+
{
470+
return pvkAcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, image_index);
471+
}
407472
}
408473

409474
static VkResult X11DRV_vkAcquireNextImage2KHR(VkDevice device,
@@ -428,6 +493,9 @@ static VkResult X11DRV_vkCreateSwapchainKHR(VkDevice device,
428493
VkSwapchainCreateInfoKHR create_info_host;
429494
VkResult result;
430495

496+
x11_surface->next_image_index = NO_IMAGE_INDEX;
497+
x11_surface->device = device;
498+
431499
TRACE("%p %p %p %p\n", device, create_info, allocator, swapchain);
432500

433501
if (allocator)
@@ -828,11 +896,40 @@ static VkResult X11DRV_vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *
828896
struct x11drv_escape_present_drawable escape;
829897
struct wine_vk_surface *surface = NULL;
830898
VkFence orig_fence;
899+
VkFence acquire_fences[10]; //TODO allocate surface->swapchain_count
831900
BOOL wait_fence = FALSE;
832901
HDC hdc = 0;
833902

834903
TRACE("%p, %p\n", queue, present_info);
835904

905+
//wait fence to avoid tearing
906+
for(uint32_t i = 0; i < present_info->swapchainCount; i++)
907+
{
908+
swapchain = present_info->pSwapchains[i];
909+
910+
EnterCriticalSection(&context_section);
911+
if (!XFindContext(gdi_display, (XID)swapchain, vulkan_swapchain_context, (char **)&surface))
912+
{
913+
wine_vk_surface_grab(surface);
914+
hdc = surface->hdc;
915+
}
916+
LeaveCriticalSection(&context_section);
917+
918+
BOOL needs_sync = surface->present_mode == VK_PRESENT_MODE_MAILBOX_KHR ||
919+
surface->present_mode == VK_PRESENT_MODE_FIFO_KHR;
920+
921+
if (hdc && surface && surface->offscreen && needs_sync)
922+
{
923+
VkFenceCreateInfo create_info;
924+
create_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
925+
create_info.pNext = NULL;
926+
create_info.flags = 0;
927+
pvkCreateFence(surface->device, &create_info, NULL, &acquire_fences[i]);
928+
929+
pvkAcquireNextImageKHR(surface->device, swapchain, UINT64_MAX, VK_NULL_HANDLE, acquire_fences[i], &surface->next_image_index);
930+
}
931+
}
932+
836933
res = pvkQueuePresentKHR(queue, present_info);
837934

838935
if (TRACE_ON(fps))
@@ -876,6 +973,14 @@ static VkResult X11DRV_vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *
876973
escape.drawable = surface->window;
877974
escape.flush = TRUE;
878975

976+
977+
BOOL needs_sync = surface->present_mode == VK_PRESENT_MODE_MAILBOX_KHR ||
978+
surface->present_mode == VK_PRESENT_MODE_FIFO_KHR;
979+
if(needs_sync)
980+
{
981+
pvkWaitForFences(surface->device, 1, &acquire_fences[i], 0, UINT64_MAX);
982+
}
983+
879984
ExtEscape(hdc, X11DRV_ESCAPE, sizeof(escape), (char *)&escape, 0, NULL);
880985
if (surface->present_mode == VK_PRESENT_MODE_MAILBOX_KHR)
881986
if (once++) FIXME("Application requires child window rendering with mailbox present mode, expect possible tearing!\n");

0 commit comments

Comments
 (0)