@@ -60,6 +60,8 @@ static XContext vulkan_swapchain_context;
6060
6161static struct list surface_list = LIST_INIT ( surface_list );
6262
63+ #define NO_IMAGE_INDEX UINT32_MAX
64+
6365struct 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
7882typedef struct VkXlibSurfaceCreateInfoKHR
@@ -108,6 +112,8 @@ static VkResult (*pvkQueuePresentKHR)(VkQueue, const VkPresentInfoKHR *);
108112static VkResult (* pvkWaitForFences )(VkDevice device , uint32_t fenceCount , const VkFence * pFences , VkBool32 waitAll , uint64_t timeout );
109113static VkResult (* pvkCreateFence )(VkDevice device , const VkFenceCreateInfo * pCreateInfo , const VkAllocationCallbacks * pAllocator , VkFence * pFence );
110114static 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
112118static void * X11DRV_get_vk_device_proc_addr (const char * name );
113119static 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
409474static 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