[PATCH 0/2] MR11175: win32u: A couple of d3d12 shared fences improvements.
From: Paul Gofman <pgofman@codeweavers.com> --- dlls/win32u/vulkan.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/dlls/win32u/vulkan.c b/dlls/win32u/vulkan.c index 00f85243a3f..154766c53c0 100644 --- a/dlls/win32u/vulkan.c +++ b/dlls/win32u/vulkan.c @@ -2196,9 +2196,21 @@ static VkResult win32u_vkQueueSubmit( VkQueue client_queue, uint32_t count, cons switch ((*next)->sType) { case VK_STRUCTURE_TYPE_D3D12_FENCE_SUBMIT_INFO_KHR: - FIXME( "VK_STRUCTURE_TYPE_D3D12_FENCE_SUBMIT_INFO_KHR not implemented!\n" ); + { + VkD3D12FenceSubmitInfoKHR *info = (VkD3D12FenceSubmitInfoKHR *)*next; + + if (timeline->sType == VK_STRUCTURE_TYPE_D3D12_FENCE_SUBMIT_INFO_KHR) + ERR( "Duplicated d3d12 fence submit info.\n" ); + else if (timeline->sType) + FIXME( "Both d3d12 fence and timeline submit info.\n" ); + timeline->sType = info->sType; + timeline->waitSemaphoreValueCount = info->waitSemaphoreValuesCount; + timeline->pWaitSemaphoreValues = info->pWaitSemaphoreValues; + timeline->signalSemaphoreValueCount = info->signalSemaphoreValuesCount; + timeline->pSignalSemaphoreValues = info->pSignalSemaphoreValues; *next = (*next)->pNext; next = &prev; break; + } case VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO: device_group = (VkDeviceGroupSubmitInfo *)*next; break; @@ -2208,7 +2220,11 @@ static VkResult win32u_vkQueueSubmit( VkQueue client_queue, uint32_t count, cons case VK_STRUCTURE_TYPE_PERFORMANCE_QUERY_SUBMIT_INFO_KHR: break; case VK_STRUCTURE_TYPE_PROTECTED_SUBMIT_INFO: break; case VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO: - if (timeline->sType) ERR( "Duplicated timeline semaphore submit info!\n" ); + if (timeline->sType == VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO) + ERR( "Duplicated timeline semaphore submit info.\n" ); + else if (timeline->sType) + FIXME( "Both d3d12 fence and timeline submit info.\n" ); + *timeline = *(VkTimelineSemaphoreSubmitInfo *)*next; *next = (*next)->pNext; next = &prev; /* remove it from the chain, we'll add it back below */ break; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11175
From: Paul Gofman <pgofman@codeweavers.com> --- dlls/win32u/vulkan.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/dlls/win32u/vulkan.c b/dlls/win32u/vulkan.c index 154766c53c0..29b656e7049 100644 --- a/dlls/win32u/vulkan.c +++ b/dlls/win32u/vulkan.c @@ -2566,6 +2566,7 @@ static VkResult win32u_vkImportSemaphoreWin32HandleKHR( VkDevice client_device, VkImportSemaphoreFdInfoKHR fd_info = {.sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR}; struct vulkan_device *device = vulkan_device_from_handle( client_device ); struct semaphore *semaphore = semaphore_from_handle( handle_info->semaphore ); + struct vulkan_instance *instance = device->physical_device->instance; D3DKMT_HANDLE local, global = 0; VkResult res = VK_SUCCESS; HANDLE shared = NULL; @@ -2598,7 +2599,35 @@ static VkResult win32u_vkImportSemaphoreWin32HandleKHR( VkDevice client_device, } if ((fd_info.fd = d3dkmt_object_get_fd( local )) < 0) res = VK_ERROR_INVALID_EXTERNAL_HANDLE; - else + if (!res && handle_info->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) + { + /* Recreate semaphore to make sure it has timeline type. */ + VkSemaphoreTypeCreateInfo type_info = + { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO, + .semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE, + }; + VkSemaphoreCreateInfo create_info = + { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, + .pNext = &type_info, + }; + VkSemaphore new_semaphore; + + if ((res = device->p_vkCreateSemaphore( device->host.device, &create_info, NULL, &new_semaphore ))) + { + ERR( "Failed to create timeline semaphore, vr %d.\n", res ); + } + else + { + instance->p_remove_object( instance, &semaphore->obj.obj ); + device->p_vkDestroySemaphore( device->host.device, semaphore->obj.host.semaphore, NULL ); + semaphore->obj.host.semaphore = new_semaphore; + instance->p_insert_object( instance, &semaphore->obj.obj ); + } + } + + if (!res) { fd_info.handleType = get_host_external_semaphore_type(); fd_info.semaphore = semaphore->obj.host.semaphore; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11175
That fixes Crysis 2 Remastered hanging going in game when ray tracing is enabled (with dxvk, wined3d is currently missing d3d11 fence creation / export for the related parts to work). That is d3d11 game which does raytracing on Vulkan and synchronizes resource access using d3d12 fence created through d3d11 and imported to Vulkan. vkQueueSubmit part looks obvious, D3D12_FENCE_SUBMIT_INFO is the counterpart for TIMELINE_SEMAPHORE_SUBMIT_INFO as soon as shared fences are concerned. In theory those may appear together, with timeline values from each used for their corresponding semaphore type, but I am leaving this theoretical case as fixme. Then, the game creates the semaphore (to be immediately used with vkImportSemaphoreWin32HandleKHR) without specifying SEMAPHORE_TYPE_CREATE_INFO, meaning that results in binary semaphore. When that binary semaphore gets timeline semaphore (from d3d12 fence implementation) imported that doesn't work very well for d3d12 fence semantics. It doesn't look specified what should happen in this case WRT d3d12 fence, but d3d12 fences imported this way work this way on Windows and, while Vulkan timeline semaphore also does not match d3d12 fence semantics exactly, it looks reasonable that compatible implementation would just ignore original semaphore type (while it probably should not be ignored / recreated when importing external vulkan semaphore). -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11175#note_143369
I'm not completely sure about this, it might be enough for the game to work but it also actually introduces strong expectations on how D3D12 shared fences would be implemented, while we still don't have functional d3d12 shared fences in Wine. And as we've discussed it will likely never be the case, unless there is host Vulkan driver support for timeline semaphore rewinding, if we want them to be correct wrt. native behavior. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11175#note_143472
Not sure how that imposes any expectations on futher development of this? This is purely Vulkan change. These d3d12 fences are de-facto somewhat supported now, can be created / imported / exported. These simple changes make it somewhat functional for limited set of use cases. When we change the way of implementation how these lines of code would stand on the way of that? -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11175#note_143496
Then, while fully correct behaviour might be not achievable, we can later maybe further improve those if take some practical compromise what we support and what we do not. E. g., if we say we don't support cross process usage of d3d12 fences we can solve the issues with d3d12 more flexible timeline management relatively easy. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11175#note_143497
Rémi Bernon (@rbernon) commented about dlls/win32u/vulkan.c:
case VK_STRUCTURE_TYPE_PERFORMANCE_QUERY_SUBMIT_INFO_KHR: break; case VK_STRUCTURE_TYPE_PROTECTED_SUBMIT_INFO: break; case VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO: - if (timeline->sType) ERR( "Duplicated timeline semaphore submit info!\n" ); + if (timeline->sType == VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO) + ERR( "Duplicated timeline semaphore submit info.\n" ); + else if (timeline->sType) + FIXME( "Both d3d12 fence and timeline submit info.\n" ); +
Can both even be added at the same time, what is it supposed to do? I think we can just keep the error message and use the same check in VK_STRUCTURE_TYPE_D3D12_FENCE_SUBMIT_INFO_KHR. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11175#note_143582
Rémi Bernon (@rbernon) commented about dlls/win32u/vulkan.c:
+ VkSemaphoreCreateInfo create_info = + { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, + .pNext = &type_info, + }; + VkSemaphore new_semaphore; + + if ((res = device->p_vkCreateSemaphore( device->host.device, &create_info, NULL, &new_semaphore ))) + { + ERR( "Failed to create timeline semaphore, vr %d.\n", res ); + } else + { + instance->p_remove_object( instance, &semaphore->obj.obj ); + device->p_vkDestroySemaphore( device->host.device, semaphore->obj.host.semaphore, NULL ); + semaphore->obj.host.semaphore = new_semaphore;
vulkan_object_init( &semaphore->obj.obj, new_semaphore );
Lets keep this more similar to other object creation code patterns. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11175#note_143583
On Fri Jun 19 07:52:18 2026 +0000, Rémi Bernon wrote:
Can both even be added at the same time, what is it supposed to do? I think we can just keep the error message and use the same check in VK_STRUCTURE_TYPE_D3D12_FENCE_SUBMIT_INFO_KHR. From the spec: "If the semaphore in VkSubmitInfo::pWaitSemaphores or VkSubmitInfo::pSignalSemaphores corresponding to an entry in pWaitSemaphoreValues or pSignalSemaphoreValues respectively does not currently have a payload referring to a Direct3D 12 fence, the implementation must ignore the value in the pWaitSemaphoreValues or pSignalSemaphoreValues entry." (https://docs.vulkan.org/refpages/latest/refpages/source/VkD3D12FenceSubmitIn...).
So my understanding is that if you want to mix timelines sems with d3d12 fences in the same submit wait or signal array you should provide both fence and timeline submit info and for each semaphore implementation should use the value from the corresponding structure type. Not sure why, maybe that is because those are different extensions. Besides, structures have important difference: waitSemaphoreValuesCount in d3d12 vs waitSemaphoreValueCount in timeline submit info. That said, this dance with ERR vs FIXMES looks clumsy, indeed looks better probably to just have the same ERR there, the needed log hint is apparent anyway, I will change that. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11175#note_143633
participants (3)
-
Paul Gofman -
Paul Gofman (@gofman) -
Rémi Bernon (@rbernon)