@@ -60,6 +60,8 @@ static XContext vulkan_swapchain_context;
60
60
61
61
static struct list surface_list = LIST_INIT ( surface_list );
62
62
63
+ #define NO_IMAGE_INDEX UINT32_MAX
64
+
63
65
struct wine_vk_surface
64
66
{
65
67
LONG ref ;
@@ -73,6 +75,8 @@ struct wine_vk_surface
73
75
HDC hdc ;
74
76
HWND hwnd ;
75
77
DWORD hwnd_thread_id ;
78
+ VkDevice device ;
79
+ uint32_t next_image_index ;
76
80
};
77
81
78
82
typedef struct VkXlibSurfaceCreateInfoKHR
@@ -108,6 +112,8 @@ static VkResult (*pvkQueuePresentKHR)(VkQueue, const VkPresentInfoKHR *);
108
112
static VkResult (* pvkWaitForFences )(VkDevice device , uint32_t fenceCount , const VkFence * pFences , VkBool32 waitAll , uint64_t timeout );
109
113
static VkResult (* pvkCreateFence )(VkDevice device , const VkFenceCreateInfo * pCreateInfo , const VkAllocationCallbacks * pAllocator , VkFence * pFence );
110
114
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 );
111
117
112
118
static void * X11DRV_get_vk_device_proc_addr (const char * name );
113
119
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)
153
159
LOAD_FUNCPTR (vkWaitForFences );
154
160
LOAD_FUNCPTR (vkCreateFence );
155
161
LOAD_FUNCPTR (vkDestroyFence );
162
+ LOAD_FUNCPTR (vkGetDeviceQueue );
163
+ LOAD_FUNCPTR (vkQueueSubmit );
156
164
#undef LOAD_FUNCPTR
157
165
#undef LOAD_OPTIONAL_FUNCPTR
158
166
@@ -403,7 +411,64 @@ static VkResult X11DRV_vkAcquireNextImageKHR(VkDevice device,
403
411
VkSwapchainKHR swapchain , uint64_t timeout , VkSemaphore semaphore ,
404
412
VkFence fence , uint32_t * image_index )
405
413
{
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
+ }
407
472
}
408
473
409
474
static VkResult X11DRV_vkAcquireNextImage2KHR (VkDevice device ,
@@ -428,6 +493,9 @@ static VkResult X11DRV_vkCreateSwapchainKHR(VkDevice device,
428
493
VkSwapchainCreateInfoKHR create_info_host ;
429
494
VkResult result ;
430
495
496
+ x11_surface -> next_image_index = NO_IMAGE_INDEX ;
497
+ x11_surface -> device = device ;
498
+
431
499
TRACE ("%p %p %p %p\n" , device , create_info , allocator , swapchain );
432
500
433
501
if (allocator )
@@ -828,11 +896,40 @@ static VkResult X11DRV_vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *
828
896
struct x11drv_escape_present_drawable escape ;
829
897
struct wine_vk_surface * surface = NULL ;
830
898
VkFence orig_fence ;
899
+ VkFence acquire_fences [10 ]; //TODO allocate surface->swapchain_count
831
900
BOOL wait_fence = FALSE;
832
901
HDC hdc = 0 ;
833
902
834
903
TRACE ("%p, %p\n" , queue , present_info );
835
904
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
+
836
933
res = pvkQueuePresentKHR (queue , present_info );
837
934
838
935
if (TRACE_ON (fps ))
@@ -876,6 +973,14 @@ static VkResult X11DRV_vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *
876
973
escape .drawable = surface -> window ;
877
974
escape .flush = TRUE;
878
975
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
+
879
984
ExtEscape (hdc , X11DRV_ESCAPE , sizeof (escape ), (char * )& escape , 0 , NULL );
880
985
if (surface -> present_mode == VK_PRESENT_MODE_MAILBOX_KHR )
881
986
if (once ++ ) FIXME ("Application requires child window rendering with mailbox present mode, expect possible tearing!\n" );
0 commit comments