This adds D3DKMT sync object monitored fence tests, showing that the fences can be rewound when requested explicitly. Also adds some interop tests between D3D11 / D3D12 / Vulkan.
The vulkan-1 tests show that timeline semaphores are rewindable on Windows even when not shared (at least with NVIDIA GPU), which is forbidden by spec but useful if not required for D3D12 fence interop.
-- v2: vulkan-1/tests: Add timeline semaphore tests. win32u/tests: Add external semaphore / fences tests. win32u/tests: Test NtGdiDdDDI(Signal|WaitFor)SynchronizationObjectFromCpu. win32u: Stub NtGdiDdDDI(Signal|WaitFor)SynchronizationObjectFromCpu. winevulkan: Force copy some missing semaphore / fence structs.
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winevulkan/make_vulkan | 2 + dlls/winevulkan/vulkan_thunks.c | 93 ++++++++++++++++++++++++++++++--- 2 files changed, 88 insertions(+), 7 deletions(-)
diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index 619dd35cd72..dee443fb6b2 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -309,6 +309,8 @@ STRUCT_CHAIN_CONVERSIONS = { "VkBufferCreateInfo": {}, "VkImageCreateInfo": {}, "VkPhysicalDeviceExternalBufferInfo": {}, + "VkPhysicalDeviceExternalFenceInfo": {}, + "VkPhysicalDeviceExternalSemaphoreInfo": {}, "VkPhysicalDeviceImageFormatInfo2": {}, "VkCommandBufferSubmitInfo": {}, "VkSemaphoreCreateInfo": {}, diff --git a/dlls/winevulkan/vulkan_thunks.c b/dlls/winevulkan/vulkan_thunks.c index 7f902f8ad47..c559cef0c28 100644 --- a/dlls/winevulkan/vulkan_thunks.c +++ b/dlls/winevulkan/vulkan_thunks.c @@ -29405,7 +29405,18 @@ static void convert_VkExternalBufferProperties_host_to_win32(const VkExternalBuf out->externalMemoryProperties = in->externalMemoryProperties; }
-static void convert_VkPhysicalDeviceExternalFenceInfo_win32_to_host(const VkPhysicalDeviceExternalFenceInfo32 *in, VkPhysicalDeviceExternalFenceInfo *out) +#ifdef _WIN64 +static void convert_VkPhysicalDeviceExternalFenceInfo_win64_to_host(struct conversion_context *ctx, const VkPhysicalDeviceExternalFenceInfo *in, VkPhysicalDeviceExternalFenceInfo *out) +{ + if (!in) return; + + out->sType = in->sType; + out->pNext = in->pNext; + out->handleType = in->handleType; +} +#endif /* _WIN64 */ + +static void convert_VkPhysicalDeviceExternalFenceInfo_win32_to_host(struct conversion_context *ctx, const VkPhysicalDeviceExternalFenceInfo32 *in, VkPhysicalDeviceExternalFenceInfo *out) { if (!in) return;
@@ -29435,6 +29446,42 @@ static void convert_VkExternalFenceProperties_host_to_win32(const VkExternalFenc out->externalFenceFeatures = in->externalFenceFeatures; }
+#ifdef _WIN64 +static void convert_VkPhysicalDeviceExternalSemaphoreInfo_win64_to_host(struct conversion_context *ctx, const VkPhysicalDeviceExternalSemaphoreInfo *in, VkPhysicalDeviceExternalSemaphoreInfo *out) +{ + const VkBaseInStructure *in_header; + VkBaseOutStructure *out_header = (void *)out; + + if (!in) return; + + out->sType = in->sType; + out->pNext = NULL; + out->handleType = in->handleType; + + for (in_header = (void *)in->pNext; in_header; in_header = (void *)in_header->pNext) + { + switch (in_header->sType) + { + case VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO: + { + VkSemaphoreTypeCreateInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); + const VkSemaphoreTypeCreateInfo *in_ext = (const VkSemaphoreTypeCreateInfo *)in_header; + out_ext->sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO; + out_ext->pNext = NULL; + out_ext->semaphoreType = in_ext->semaphoreType; + out_ext->initialValue = in_ext->initialValue; + out_header->pNext = (void *)out_ext; + out_header = (void *)out_ext; + break; + } + default: + FIXME("Unhandled sType %u.\n", in_header->sType); + break; + } + } +} +#endif /* _WIN64 */ + static void convert_VkPhysicalDeviceExternalSemaphoreInfo_win32_to_host(struct conversion_context *ctx, const VkPhysicalDeviceExternalSemaphoreInfo32 *in, VkPhysicalDeviceExternalSemaphoreInfo *out) { const VkBaseInStructure32 *in_header; @@ -56285,10 +56332,16 @@ static NTSTATUS thunk32_vkGetPhysicalDeviceExternalBufferPropertiesKHR(void *arg static NTSTATUS thunk64_vkGetPhysicalDeviceExternalFenceProperties(void *args) { struct vkGetPhysicalDeviceExternalFenceProperties_params *params = args; + VkPhysicalDeviceExternalFenceInfo pExternalFenceInfo_host; + struct conversion_context local_ctx; + struct conversion_context *ctx = &local_ctx;
TRACE("%p, %p, %p\n", params->physicalDevice, params->pExternalFenceInfo, params->pExternalFenceProperties);
- wine_vkGetPhysicalDeviceExternalFenceProperties(params->physicalDevice, params->pExternalFenceInfo, params->pExternalFenceProperties); + init_conversion_context(ctx); + convert_VkPhysicalDeviceExternalFenceInfo_win64_to_host(ctx, params->pExternalFenceInfo, &pExternalFenceInfo_host); + wine_vkGetPhysicalDeviceExternalFenceProperties(params->physicalDevice, &pExternalFenceInfo_host, params->pExternalFenceProperties); + free_conversion_context(ctx); return STATUS_SUCCESS; } #endif /* _WIN64 */ @@ -56303,13 +56356,17 @@ static NTSTATUS thunk32_vkGetPhysicalDeviceExternalFenceProperties(void *args) } *params = args; VkPhysicalDeviceExternalFenceInfo pExternalFenceInfo_host; VkExternalFenceProperties pExternalFenceProperties_host; + struct conversion_context local_ctx; + struct conversion_context *ctx = &local_ctx;
TRACE("%#x, %#x, %#x\n", params->physicalDevice, params->pExternalFenceInfo, params->pExternalFenceProperties);
- convert_VkPhysicalDeviceExternalFenceInfo_win32_to_host((const VkPhysicalDeviceExternalFenceInfo32 *)UlongToPtr(params->pExternalFenceInfo), &pExternalFenceInfo_host); + init_conversion_context(ctx); + convert_VkPhysicalDeviceExternalFenceInfo_win32_to_host(ctx, (const VkPhysicalDeviceExternalFenceInfo32 *)UlongToPtr(params->pExternalFenceInfo), &pExternalFenceInfo_host); convert_VkExternalFenceProperties_win32_to_host((VkExternalFenceProperties32 *)UlongToPtr(params->pExternalFenceProperties), &pExternalFenceProperties_host); wine_vkGetPhysicalDeviceExternalFenceProperties((VkPhysicalDevice)UlongToPtr(params->physicalDevice), &pExternalFenceInfo_host, &pExternalFenceProperties_host); convert_VkExternalFenceProperties_host_to_win32(&pExternalFenceProperties_host, (VkExternalFenceProperties32 *)UlongToPtr(params->pExternalFenceProperties)); + free_conversion_context(ctx); return STATUS_SUCCESS; }
@@ -56317,10 +56374,16 @@ static NTSTATUS thunk32_vkGetPhysicalDeviceExternalFenceProperties(void *args) static NTSTATUS thunk64_vkGetPhysicalDeviceExternalFencePropertiesKHR(void *args) { struct vkGetPhysicalDeviceExternalFencePropertiesKHR_params *params = args; + VkPhysicalDeviceExternalFenceInfo pExternalFenceInfo_host; + struct conversion_context local_ctx; + struct conversion_context *ctx = &local_ctx;
TRACE("%p, %p, %p\n", params->physicalDevice, params->pExternalFenceInfo, params->pExternalFenceProperties);
- wine_vkGetPhysicalDeviceExternalFencePropertiesKHR(params->physicalDevice, params->pExternalFenceInfo, params->pExternalFenceProperties); + init_conversion_context(ctx); + convert_VkPhysicalDeviceExternalFenceInfo_win64_to_host(ctx, params->pExternalFenceInfo, &pExternalFenceInfo_host); + wine_vkGetPhysicalDeviceExternalFencePropertiesKHR(params->physicalDevice, &pExternalFenceInfo_host, params->pExternalFenceProperties); + free_conversion_context(ctx); return STATUS_SUCCESS; } #endif /* _WIN64 */ @@ -56335,13 +56398,17 @@ static NTSTATUS thunk32_vkGetPhysicalDeviceExternalFencePropertiesKHR(void *args } *params = args; VkPhysicalDeviceExternalFenceInfo pExternalFenceInfo_host; VkExternalFenceProperties pExternalFenceProperties_host; + struct conversion_context local_ctx; + struct conversion_context *ctx = &local_ctx;
TRACE("%#x, %#x, %#x\n", params->physicalDevice, params->pExternalFenceInfo, params->pExternalFenceProperties);
- convert_VkPhysicalDeviceExternalFenceInfo_win32_to_host((const VkPhysicalDeviceExternalFenceInfo32 *)UlongToPtr(params->pExternalFenceInfo), &pExternalFenceInfo_host); + init_conversion_context(ctx); + convert_VkPhysicalDeviceExternalFenceInfo_win32_to_host(ctx, (const VkPhysicalDeviceExternalFenceInfo32 *)UlongToPtr(params->pExternalFenceInfo), &pExternalFenceInfo_host); convert_VkExternalFenceProperties_win32_to_host((VkExternalFenceProperties32 *)UlongToPtr(params->pExternalFenceProperties), &pExternalFenceProperties_host); wine_vkGetPhysicalDeviceExternalFencePropertiesKHR((VkPhysicalDevice)UlongToPtr(params->physicalDevice), &pExternalFenceInfo_host, &pExternalFenceProperties_host); convert_VkExternalFenceProperties_host_to_win32(&pExternalFenceProperties_host, (VkExternalFenceProperties32 *)UlongToPtr(params->pExternalFenceProperties)); + free_conversion_context(ctx); return STATUS_SUCCESS; }
@@ -56349,10 +56416,16 @@ static NTSTATUS thunk32_vkGetPhysicalDeviceExternalFencePropertiesKHR(void *args static NTSTATUS thunk64_vkGetPhysicalDeviceExternalSemaphoreProperties(void *args) { struct vkGetPhysicalDeviceExternalSemaphoreProperties_params *params = args; + VkPhysicalDeviceExternalSemaphoreInfo pExternalSemaphoreInfo_host; + struct conversion_context local_ctx; + struct conversion_context *ctx = &local_ctx;
TRACE("%p, %p, %p\n", params->physicalDevice, params->pExternalSemaphoreInfo, params->pExternalSemaphoreProperties);
- vk_funcs->p_vkGetPhysicalDeviceExternalSemaphoreProperties(params->physicalDevice, params->pExternalSemaphoreInfo, params->pExternalSemaphoreProperties); + init_conversion_context(ctx); + convert_VkPhysicalDeviceExternalSemaphoreInfo_win64_to_host(ctx, params->pExternalSemaphoreInfo, &pExternalSemaphoreInfo_host); + vk_funcs->p_vkGetPhysicalDeviceExternalSemaphoreProperties(params->physicalDevice, &pExternalSemaphoreInfo_host, params->pExternalSemaphoreProperties); + free_conversion_context(ctx); return STATUS_SUCCESS; } #endif /* _WIN64 */ @@ -56385,10 +56458,16 @@ static NTSTATUS thunk32_vkGetPhysicalDeviceExternalSemaphoreProperties(void *arg static NTSTATUS thunk64_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR(void *args) { struct vkGetPhysicalDeviceExternalSemaphorePropertiesKHR_params *params = args; + VkPhysicalDeviceExternalSemaphoreInfo pExternalSemaphoreInfo_host; + struct conversion_context local_ctx; + struct conversion_context *ctx = &local_ctx;
TRACE("%p, %p, %p\n", params->physicalDevice, params->pExternalSemaphoreInfo, params->pExternalSemaphoreProperties);
- vk_funcs->p_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR(params->physicalDevice, params->pExternalSemaphoreInfo, params->pExternalSemaphoreProperties); + init_conversion_context(ctx); + convert_VkPhysicalDeviceExternalSemaphoreInfo_win64_to_host(ctx, params->pExternalSemaphoreInfo, &pExternalSemaphoreInfo_host); + vk_funcs->p_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR(params->physicalDevice, &pExternalSemaphoreInfo_host, params->pExternalSemaphoreProperties); + free_conversion_context(ctx); return STATUS_SUCCESS; } #endif /* _WIN64 */
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/gdi32/gdi32.spec | 2 + dlls/win32u/d3dkmt.c | 18 +++++ dlls/win32u/main.c | 10 +++ dlls/win32u/win32syscalls.h | 10 +-- dlls/win32u/win32u.spec | 4 +- dlls/wow64win/gdi.c | 46 +++++++++++ include/d3dukmdt.h | 136 +++++++++++++++++++++++++++++++++ include/ddk/d3dkmthk.h | 147 ++++++------------------------------ include/ntgdi.h | 2 + 9 files changed, 242 insertions(+), 133 deletions(-)
diff --git a/dlls/gdi32/gdi32.spec b/dlls/gdi32/gdi32.spec index c42172f142f..207549ff826 100644 --- a/dlls/gdi32/gdi32.spec +++ b/dlls/gdi32/gdi32.spec @@ -146,6 +146,8 @@ @ stdcall D3DKMTSetQueuedLimit(ptr) win32u.NtGdiDdDDISetQueuedLimit @ stdcall D3DKMTSetVidPnSourceOwner(ptr) win32u.NtGdiDdDDISetVidPnSourceOwner @ stdcall D3DKMTShareObjects(long ptr ptr long ptr) win32u.NtGdiDdDDIShareObjects +@ stdcall D3DKMTSignalSynchronizationObjectFromCpu(ptr) win32u.NtGdiDdDDISignalSynchronizationObjectFromCpu +@ stdcall D3DKMTWaitForSynchronizationObjectFromCpu(ptr) win32u.NtGdiDdDDIWaitForSynchronizationObjectFromCpu @ stdcall DPtoLP(long ptr long) @ stdcall DeleteColorSpace(long) @ stdcall DeleteDC(long) diff --git a/dlls/win32u/d3dkmt.c b/dlls/win32u/d3dkmt.c index 1e731ded520..98f6b935d6f 100644 --- a/dlls/win32u/d3dkmt.c +++ b/dlls/win32u/d3dkmt.c @@ -1917,6 +1917,24 @@ NTSTATUS WINAPI NtGdiDdDDIDestroySynchronizationObject( const D3DKMT_DESTROYSYNC return d3dkmt_destroy_sync( params->hSyncObject ); }
+/****************************************************************************** + * NtGdiDdDDISignalSynchronizationObjectFromCpu (win32u.@) + */ +NTSTATUS WINAPI NtGdiDdDDISignalSynchronizationObjectFromCpu( const D3DKMT_SIGNALSYNCHRONIZATIONOBJECTFROMCPU *params ) +{ + FIXME( "params %p stub!\n", params ); + return STATUS_NOT_IMPLEMENTED; +} + +/****************************************************************************** + * NtGdiDdDDIWaitForSynchronizationObjectFromCpu (win32u.@) + */ +NTSTATUS WINAPI NtGdiDdDDIWaitForSynchronizationObjectFromCpu( const D3DKMT_WAITFORSYNCHRONIZATIONOBJECTFROMCPU *params ) +{ + FIXME( "params %p stub!\n", params ); + return STATUS_NOT_IMPLEMENTED; +} + static void get_resource_global_keyed_mutex( struct d3dkmt_dxgi_desc *desc, D3DKMT_HANDLE *mutex_global, D3DKMT_HANDLE *sync_global ) { if ((desc->size != sizeof(struct d3dkmt_d3d9_desc) && desc->size != sizeof(struct d3dkmt_d3d11_desc)) || diff --git a/dlls/win32u/main.c b/dlls/win32u/main.c index 428412a2ddb..193c2c048bf 100644 --- a/dlls/win32u/main.c +++ b/dlls/win32u/main.c @@ -441,6 +441,16 @@ NTSTATUS SYSCALL_API NtGdiDdDDIShareObjects( UINT count, const D3DKMT_HANDLE *ha SYSCALL_FUNC( NtGdiDdDDIShareObjects ); }
+NTSTATUS SYSCALL_API NtGdiDdDDISignalSynchronizationObjectFromCpu( const D3DKMT_SIGNALSYNCHRONIZATIONOBJECTFROMCPU *params ) +{ + SYSCALL_FUNC( NtGdiDdDDISignalSynchronizationObjectFromCpu ); +} + +NTSTATUS SYSCALL_API NtGdiDdDDIWaitForSynchronizationObjectFromCpu( const D3DKMT_WAITFORSYNCHRONIZATIONOBJECTFROMCPU *params ) +{ + SYSCALL_FUNC( NtGdiDdDDIWaitForSynchronizationObjectFromCpu ); +} + BOOL SYSCALL_API NtGdiDeleteClientObj( HGDIOBJ handle ) { SYSCALL_FUNC( NtGdiDeleteClientObj ); diff --git a/dlls/win32u/win32syscalls.h b/dlls/win32u/win32syscalls.h index 5321c282397..69982b52833 100644 --- a/dlls/win32u/win32syscalls.h +++ b/dlls/win32u/win32syscalls.h @@ -374,7 +374,7 @@ SYSCALL_ENTRY( 0x1172, NtGdiDdDDISharedPrimaryLockNotification, 0 ) \ SYSCALL_ENTRY( 0x1173, NtGdiDdDDISharedPrimaryUnLockNotification, 0 ) \ SYSCALL_ENTRY( 0x1174, NtGdiDdDDISignalSynchronizationObject, 0 ) \ - SYSCALL_ENTRY( 0x1175, NtGdiDdDDISignalSynchronizationObjectFromCpu, 0 ) \ + SYSCALL_ENTRY( 0x1175, NtGdiDdDDISignalSynchronizationObjectFromCpu, 4 ) \ SYSCALL_ENTRY( 0x1176, NtGdiDdDDISignalSynchronizationObjectFromGpu, 0 ) \ SYSCALL_ENTRY( 0x1177, NtGdiDdDDISignalSynchronizationObjectFromGpu2, 0 ) \ SYSCALL_ENTRY( 0x1178, NtGdiDdDDISubmitCommand, 0 ) \ @@ -390,7 +390,7 @@ SYSCALL_ENTRY( 0x1182, NtGdiDdDDIUpdateOverlay, 0 ) \ SYSCALL_ENTRY( 0x1183, NtGdiDdDDIWaitForIdle, 0 ) \ SYSCALL_ENTRY( 0x1184, NtGdiDdDDIWaitForSynchronizationObject, 0 ) \ - SYSCALL_ENTRY( 0x1185, NtGdiDdDDIWaitForSynchronizationObjectFromCpu, 0 ) \ + SYSCALL_ENTRY( 0x1185, NtGdiDdDDIWaitForSynchronizationObjectFromCpu, 4 ) \ SYSCALL_ENTRY( 0x1186, NtGdiDdDDIWaitForSynchronizationObjectFromGpu, 0 ) \ SYSCALL_ENTRY( 0x1187, NtGdiDdDDIWaitForVerticalBlankEvent, 0 ) \ SYSCALL_ENTRY( 0x1188, NtGdiDdDDIWaitForVerticalBlankEvent2, 0 ) \ @@ -1916,7 +1916,7 @@ SYSCALL_ENTRY( 0x1172, NtGdiDdDDISharedPrimaryLockNotification, 0 ) \ SYSCALL_ENTRY( 0x1173, NtGdiDdDDISharedPrimaryUnLockNotification, 0 ) \ SYSCALL_ENTRY( 0x1174, NtGdiDdDDISignalSynchronizationObject, 0 ) \ - SYSCALL_ENTRY( 0x1175, NtGdiDdDDISignalSynchronizationObjectFromCpu, 0 ) \ + SYSCALL_ENTRY( 0x1175, NtGdiDdDDISignalSynchronizationObjectFromCpu, 8 ) \ SYSCALL_ENTRY( 0x1176, NtGdiDdDDISignalSynchronizationObjectFromGpu, 0 ) \ SYSCALL_ENTRY( 0x1177, NtGdiDdDDISignalSynchronizationObjectFromGpu2, 0 ) \ SYSCALL_ENTRY( 0x1178, NtGdiDdDDISubmitCommand, 0 ) \ @@ -1932,7 +1932,7 @@ SYSCALL_ENTRY( 0x1182, NtGdiDdDDIUpdateOverlay, 0 ) \ SYSCALL_ENTRY( 0x1183, NtGdiDdDDIWaitForIdle, 0 ) \ SYSCALL_ENTRY( 0x1184, NtGdiDdDDIWaitForSynchronizationObject, 0 ) \ - SYSCALL_ENTRY( 0x1185, NtGdiDdDDIWaitForSynchronizationObjectFromCpu, 0 ) \ + SYSCALL_ENTRY( 0x1185, NtGdiDdDDIWaitForSynchronizationObjectFromCpu, 8 ) \ SYSCALL_ENTRY( 0x1186, NtGdiDdDDIWaitForSynchronizationObjectFromGpu, 0 ) \ SYSCALL_ENTRY( 0x1187, NtGdiDdDDIWaitForVerticalBlankEvent, 0 ) \ SYSCALL_ENTRY( 0x1188, NtGdiDdDDIWaitForVerticalBlankEvent2, 0 ) \ @@ -3384,7 +3384,6 @@ SYSCALL_STUB( NtGdiDdDDISharedPrimaryLockNotification ) \ SYSCALL_STUB( NtGdiDdDDISharedPrimaryUnLockNotification ) \ SYSCALL_STUB( NtGdiDdDDISignalSynchronizationObject ) \ - SYSCALL_STUB( NtGdiDdDDISignalSynchronizationObjectFromCpu ) \ SYSCALL_STUB( NtGdiDdDDISignalSynchronizationObjectFromGpu ) \ SYSCALL_STUB( NtGdiDdDDISignalSynchronizationObjectFromGpu2 ) \ SYSCALL_STUB( NtGdiDdDDISubmitCommand ) \ @@ -3400,7 +3399,6 @@ SYSCALL_STUB( NtGdiDdDDIUpdateOverlay ) \ SYSCALL_STUB( NtGdiDdDDIWaitForIdle ) \ SYSCALL_STUB( NtGdiDdDDIWaitForSynchronizationObject ) \ - SYSCALL_STUB( NtGdiDdDDIWaitForSynchronizationObjectFromCpu ) \ SYSCALL_STUB( NtGdiDdDDIWaitForSynchronizationObjectFromGpu ) \ SYSCALL_STUB( NtGdiDdDDIWaitForVerticalBlankEvent ) \ SYSCALL_STUB( NtGdiDdDDIWaitForVerticalBlankEvent2 ) \ diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec index 99c48b12f82..f0ccfba35cb 100644 --- a/dlls/win32u/win32u.spec +++ b/dlls/win32u/win32u.spec @@ -372,7 +372,7 @@ @ stub -syscall NtGdiDdDDISharedPrimaryLockNotification @ stub -syscall NtGdiDdDDISharedPrimaryUnLockNotification @ stub -syscall NtGdiDdDDISignalSynchronizationObject -@ stub -syscall NtGdiDdDDISignalSynchronizationObjectFromCpu +@ stdcall -syscall NtGdiDdDDISignalSynchronizationObjectFromCpu(ptr) @ stub -syscall NtGdiDdDDISignalSynchronizationObjectFromGpu @ stub -syscall NtGdiDdDDISignalSynchronizationObjectFromGpu2 @ stub -syscall NtGdiDdDDISubmitCommand @@ -388,7 +388,7 @@ @ stub -syscall NtGdiDdDDIUpdateOverlay @ stub -syscall NtGdiDdDDIWaitForIdle @ stub -syscall NtGdiDdDDIWaitForSynchronizationObject -@ stub -syscall NtGdiDdDDIWaitForSynchronizationObjectFromCpu +@ stdcall -syscall NtGdiDdDDIWaitForSynchronizationObjectFromCpu(ptr) @ stub -syscall NtGdiDdDDIWaitForSynchronizationObjectFromGpu @ stub -syscall NtGdiDdDDIWaitForVerticalBlankEvent @ stub -syscall NtGdiDdDDIWaitForVerticalBlankEvent2 diff --git a/dlls/wow64win/gdi.c b/dlls/wow64win/gdi.c index 9ba1c3b93de..5a38f1860cf 100644 --- a/dlls/wow64win/gdi.c +++ b/dlls/wow64win/gdi.c @@ -1554,6 +1554,52 @@ NTSTATUS WINAPI wow64_NtGdiDdDDIShareObjects( UINT *args ) return status; }
+NTSTATUS WINAPI wow64_NtGdiDdDDISignalSynchronizationObjectFromCpu( UINT *args ) +{ + const struct + { + D3DKMT_HANDLE hDevice; + UINT ObjectCount; + ULONG ObjectHandleArray; + ULONG FenceValueArray; + D3DDDICB_SIGNALFLAGS Flags; + } *desc32 = get_ptr( &args ); + D3DKMT_SIGNALSYNCHRONIZATIONOBJECTFROMCPU desc; + + if (!desc32) return STATUS_INVALID_PARAMETER; + desc.hDevice = desc32->hDevice; + desc.ObjectCount = desc32->ObjectCount; + desc.ObjectHandleArray = UlongToPtr( desc32->ObjectHandleArray ); + desc.FenceValueArray = UlongToPtr( desc32->FenceValueArray ); + desc.Flags = desc32->Flags; + + return NtGdiDdDDISignalSynchronizationObjectFromCpu( &desc ); +} + +NTSTATUS WINAPI wow64_NtGdiDdDDIWaitForSynchronizationObjectFromCpu( UINT *args ) +{ + const struct + { + D3DKMT_HANDLE hDevice; + UINT ObjectCount; + ULONG ObjectHandleArray; + ULONG FenceValueArray; + ULONG hAsyncEvent; + D3DDDI_WAITFORSYNCHRONIZATIONOBJECTFROMCPU_FLAGS Flags; + } *desc32 = get_ptr( &args ); + D3DKMT_WAITFORSYNCHRONIZATIONOBJECTFROMCPU desc; + + if (!desc32) return STATUS_INVALID_PARAMETER; + desc.hDevice = desc32->hDevice; + desc.ObjectCount = desc32->ObjectCount; + desc.ObjectHandleArray = UlongToPtr( desc32->ObjectHandleArray ); + desc.FenceValueArray = UlongToPtr( desc32->FenceValueArray ); + desc.hAsyncEvent = UlongToHandle( desc32->hAsyncEvent ); + desc.Flags = desc32->Flags; + + return NtGdiDdDDIWaitForSynchronizationObjectFromCpu( &desc ); +} + NTSTATUS WINAPI wow64_NtGdiDeleteClientObj( UINT *args ) { HGDIOBJ obj = get_handle( &args ); diff --git a/include/d3dukmdt.h b/include/d3dukmdt.h index f88771cbce6..99f7a5a8b74 100644 --- a/include/d3dukmdt.h +++ b/include/d3dukmdt.h @@ -26,6 +26,8 @@ #endif /* MAKEFOURCC */
typedef UINT D3DKMT_HANDLE; +typedef ULONGLONG D3DGPU_VIRTUAL_ADDRESS; +typedef UINT D3DDDI_VIDEO_PRESENT_TARGET_ID;
typedef enum _D3DDDIFORMAT { @@ -153,4 +155,138 @@ typedef struct _D3DDDI_ESCAPEFLAGS }; } D3DDDI_ESCAPEFLAGS;
+#ifndef D3DDDI_SYNCHRONIZATIONOBJECT_FLAGS_EXT +#define D3DDDI_SYNCHRONIZATIONOBJECT_FLAGS_EXT +#define D3DDDI_SYNCHRONIZATIONOBJECT_FLAGS_RESERVED0 Reserved0 +#endif + +typedef struct _D3DDDI_SYNCHRONIZATIONOBJECT_FLAGS +{ + union + { + struct + { + UINT Shared : 1; + UINT NtSecuritySharing : 1; + UINT CrossAdapter : 1; + UINT TopOfPipeline : 1; + UINT NoSignal : 1; + UINT NoWait : 1; + UINT NoSignalMaxValueOnTdr : 1; + UINT NoGPUAccess : 1; + UINT Reserved : 23; + UINT D3DDDI_SYNCHRONIZATIONOBJECT_FLAGS_RESERVED0 : 1; + }; + UINT Value; + }; +} D3DDDI_SYNCHRONIZATIONOBJECT_FLAGS; + +typedef enum _D3DDDI_SYNCHRONIZATIONOBJECT_TYPE +{ + D3DDDI_SYNCHRONIZATION_MUTEX = 1, + D3DDDI_SEMAPHORE = 2, + D3DDDI_FENCE = 3, + D3DDDI_CPU_NOTIFICATION = 4, + D3DDDI_MONITORED_FENCE = 5, + D3DDDI_PERIODIC_MONITORED_FENCE = 6, + D3DDDI_SYNCHRONIZATION_TYPE_LIMIT +} D3DDDI_SYNCHRONIZATIONOBJECT_TYPE; + +typedef struct _D3DDDI_SYNCHRONIZATIONOBJECTINFO +{ + D3DDDI_SYNCHRONIZATIONOBJECT_TYPE Type; + union + { + struct + { + BOOL InitialState; + } SynchronizationMutex; + struct + { + UINT MaxCount; + UINT InitialCount; + } Semaphore; + struct + { + UINT Reserved[16]; + } Reserved; + }; +} D3DDDI_SYNCHRONIZATIONOBJECTINFO; + +typedef struct _D3DDDI_SYNCHRONIZATIONOBJECTINFO2 +{ + D3DDDI_SYNCHRONIZATIONOBJECT_TYPE Type; + D3DDDI_SYNCHRONIZATIONOBJECT_FLAGS Flags; + union + { + struct + { + BOOL InitialState; + } SynchronizationMutex; + struct + { + UINT MaxCount; + UINT InitialCount; + } Semaphore; + struct + { + UINT64 FenceValue; + } Fence; + struct + { + HANDLE Event; + } CPUNotification; + struct + { + UINT64 InitialFenceValue; + void *FenceValueCPUVirtualAddress; + D3DGPU_VIRTUAL_ADDRESS FenceValueGPUVirtualAddress; + UINT EngineAffinity; + } MonitoredFence; + struct + { + D3DKMT_HANDLE hAdapter; + D3DDDI_VIDEO_PRESENT_TARGET_ID VidPnTargetId; + UINT64 Time; + void *FenceValueCPUVirtualAddress; + D3DGPU_VIRTUAL_ADDRESS FenceValueGPUVirtualAddress; + UINT EngineAffinity; + } PeriodicMonitoredFence; + struct + { + UINT64 Reserved[8]; + } Reserved; + }; + D3DKMT_HANDLE SharedHandle; +} D3DDDI_SYNCHRONIZATIONOBJECTINFO2; + +typedef struct _D3DDDI_WAITFORSYNCHRONIZATIONOBJECTFROMCPU_FLAGS +{ + union + { + struct + { + UINT WaitAny :1; + UINT Reserved :31; + }; + UINT Value; + }; +} D3DDDI_WAITFORSYNCHRONIZATIONOBJECTFROMCPU_FLAGS; + +typedef struct _D3DDDICB_SIGNALFLAGS +{ + union + { + struct + { + UINT SignalAtSubmission :1; + UINT EnqueueCpuEvent :1; + UINT AllowFenceRewind :1; + UINT Reserved :28; + UINT DXGK_SIGNAL_FLAG_INTERNAL0 :1; + }; + UINT Value; + }; +} D3DDDICB_SIGNALFLAGS; + #endif /* __WINE_D3DUKMDT_H */ diff --git a/include/ddk/d3dkmthk.h b/include/ddk/d3dkmthk.h index b072b16f1fc..9f7e6d55a3d 100644 --- a/include/ddk/d3dkmthk.h +++ b/include/ddk/d3dkmthk.h @@ -812,22 +812,6 @@ typedef struct _D3DKMT_CREATEKEYEDMUTEX D3DKMT_HANDLE hKeyedMutex; } D3DKMT_CREATEKEYEDMUTEX;
-typedef struct _D3DDDICB_SIGNALFLAGS -{ - union - { - struct - { - UINT SignalAtSubmission : 1; - UINT EnqueueCpuEvent : 1; - UINT AllowFenceRewind : 1; - UINT Reserved : 28; - UINT DXGK_SIGNAL_FLAG_INTERNAL0 : 1; - }; - UINT Value; - }; -} D3DDDICB_SIGNALFLAGS; - typedef struct _D3DKMT_CREATEKEYEDMUTEX2_FLAGS { union @@ -919,68 +903,6 @@ typedef struct _D3DKMT_OPENNTHANDLEFROMNAME HANDLE hNtHandle; } D3DKMT_OPENNTHANDLEFROMNAME;
-typedef ULONGLONG D3DGPU_VIRTUAL_ADDRESS; - -#ifndef D3DDDI_SYNCHRONIZATIONOBJECT_FLAGS_EXT -#define D3DDDI_SYNCHRONIZATIONOBJECT_FLAGS_EXT -#define D3DDDI_SYNCHRONIZATIONOBJECT_FLAGS_RESERVED0 Reserved0 -#endif - -typedef struct _D3DDDI_SYNCHRONIZATIONOBJECT_FLAGS -{ - union - { - struct - { - UINT Shared : 1; - UINT NtSecuritySharing : 1; - UINT CrossAdapter : 1; - UINT TopOfPipeline : 1; - UINT NoSignal : 1; - UINT NoWait : 1; - UINT NoSignalMaxValueOnTdr : 1; - UINT NoGPUAccess : 1; - UINT Reserved : 23; - UINT D3DDDI_SYNCHRONIZATIONOBJECT_FLAGS_RESERVED0 : 1; - }; - UINT Value; - }; -} D3DDDI_SYNCHRONIZATIONOBJECT_FLAGS; - -typedef UINT D3DDDI_VIDEO_PRESENT_TARGET_ID; - -typedef enum _D3DDDI_SYNCHRONIZATIONOBJECT_TYPE -{ - D3DDDI_SYNCHRONIZATION_MUTEX = 1, - D3DDDI_SEMAPHORE = 2, - D3DDDI_FENCE = 3, - D3DDDI_CPU_NOTIFICATION = 4, - D3DDDI_MONITORED_FENCE = 5, - D3DDDI_PERIODIC_MONITORED_FENCE = 6, - D3DDDI_SYNCHRONIZATION_TYPE_LIMIT -} D3DDDI_SYNCHRONIZATIONOBJECT_TYPE; - -typedef struct _D3DDDI_SYNCHRONIZATIONOBJECTINFO -{ - D3DDDI_SYNCHRONIZATIONOBJECT_TYPE Type; - union - { - struct - { - BOOL InitialState; - } SynchronizationMutex; - struct - { - UINT MaxCount; - UINT InitialCount; - } Semaphore; - struct - { - UINT Reserved[16]; - } Reserved; - }; -} D3DDDI_SYNCHRONIZATIONOBJECTINFO; - typedef struct _D3DKMT_CREATESYNCHRONIZATIONOBJECT { D3DKMT_HANDLE hDevice; @@ -988,53 +910,6 @@ typedef struct _D3DKMT_CREATESYNCHRONIZATIONOBJECT D3DKMT_HANDLE hSyncObject; } D3DKMT_CREATESYNCHRONIZATIONOBJECT;
-typedef struct _D3DDDI_SYNCHRONIZATIONOBJECTINFO2 -{ - D3DDDI_SYNCHRONIZATIONOBJECT_TYPE Type; - D3DDDI_SYNCHRONIZATIONOBJECT_FLAGS Flags; - union - { - struct - { - BOOL InitialState; - } SynchronizationMutex; - struct - { - UINT MaxCount; - UINT InitialCount; - } Semaphore; - struct - { - UINT64 FenceValue; - } Fence; - struct - { - HANDLE Event; - } CPUNotification; - struct - { - UINT64 InitialFenceValue; - void *FenceValueCPUVirtualAddress; - D3DGPU_VIRTUAL_ADDRESS FenceValueGPUVirtualAddress; - UINT EngineAffinity; - } MonitoredFence; - struct - { - D3DKMT_HANDLE hAdapter; - D3DDDI_VIDEO_PRESENT_TARGET_ID VidPnTargetId; - UINT64 Time; - void *FenceValueCPUVirtualAddress; - D3DGPU_VIRTUAL_ADDRESS FenceValueGPUVirtualAddress; - UINT EngineAffinity; - } PeriodicMonitoredFence; - struct - { - UINT64 Reserved[8]; - } Reserved; - }; - D3DKMT_HANDLE SharedHandle; -} D3DDDI_SYNCHRONIZATIONOBJECTINFO2; - typedef struct _D3DKMT_CREATESYNCHRONIZATIONOBJECT2 { D3DKMT_HANDLE hDevice; @@ -1086,6 +961,25 @@ typedef struct _D3DKMT_DESTROYSYNCHRONIZATIONOBJECT D3DKMT_HANDLE hSyncObject; } D3DKMT_DESTROYSYNCHRONIZATIONOBJECT;
+typedef struct _D3DKMT_SIGNALSYNCHRONIZATIONOBJECTFROMCPU +{ + D3DKMT_HANDLE hDevice; + UINT ObjectCount; + const D3DKMT_HANDLE *ObjectHandleArray; + const UINT64 *FenceValueArray; + D3DDDICB_SIGNALFLAGS Flags; +} D3DKMT_SIGNALSYNCHRONIZATIONOBJECTFROMCPU; + +typedef struct _D3DKMT_WAITFORSYNCHRONIZATIONOBJECTFROMCPU +{ + D3DKMT_HANDLE hDevice; + UINT ObjectCount; + const D3DKMT_HANDLE *ObjectHandleArray; + const UINT64 *FenceValueArray; + HANDLE hAsyncEvent; + D3DDDI_WAITFORSYNCHRONIZATIONOBJECTFROMCPU_FLAGS Flags; +} D3DKMT_WAITFORSYNCHRONIZATIONOBJECTFROMCPU; + typedef struct _D3DKMT_CREATESTANDARDALLOCATIONFLAGS { union @@ -1375,6 +1269,9 @@ NTSTATUS WINAPI D3DKMTReleaseKeyedMutex2( D3DKMT_RELEASEKEYEDMUTEX2 *params ); NTSTATUS WINAPI D3DKMTSetQueuedLimit(D3DKMT_SETQUEUEDLIMIT *desc); NTSTATUS WINAPI D3DKMTSetVidPnSourceOwner(const D3DKMT_SETVIDPNSOURCEOWNER *desc); NTSTATUS WINAPI D3DKMTShareObjects( UINT count, const D3DKMT_HANDLE *handles, OBJECT_ATTRIBUTES *attr, UINT access, HANDLE *handle ); +NTSTATUS WINAPI D3DKMTSignalSynchronizationObjectFromCpu( const D3DKMT_SIGNALSYNCHRONIZATIONOBJECTFROMCPU *params ); +NTSTATUS WINAPI D3DKMTWaitForSynchronizationObjectFromCpu( const D3DKMT_WAITFORSYNCHRONIZATIONOBJECTFROMCPU *params ); +
#ifdef __cplusplus } diff --git a/include/ntgdi.h b/include/ntgdi.h index d8fbfc6c8fd..23053e537d2 100644 --- a/include/ntgdi.h +++ b/include/ntgdi.h @@ -560,6 +560,8 @@ W32KAPI NTSTATUS WINAPI NtGdiDdDDIReleaseKeyedMutex2( D3DKMT_RELEASEKEYEDMUTEX2 W32KAPI NTSTATUS WINAPI NtGdiDdDDISetQueuedLimit( D3DKMT_SETQUEUEDLIMIT *desc ); W32KAPI NTSTATUS WINAPI NtGdiDdDDISetVidPnSourceOwner( const D3DKMT_SETVIDPNSOURCEOWNER *desc ); W32KAPI NTSTATUS WINAPI NtGdiDdDDIShareObjects( UINT count, const D3DKMT_HANDLE *handles, OBJECT_ATTRIBUTES *attr, UINT access, HANDLE *handle ); +W32KAPI NTSTATUS WINAPI NtGdiDdDDISignalSynchronizationObjectFromCpu( const D3DKMT_SIGNALSYNCHRONIZATIONOBJECTFROMCPU *params ); +W32KAPI NTSTATUS WINAPI NtGdiDdDDIWaitForSynchronizationObjectFromCpu( const D3DKMT_WAITFORSYNCHRONIZATIONOBJECTFROMCPU *params );
/* Wine extensions */ W32KAPI const struct vulkan_funcs * __wine_get_vulkan_driver(UINT version);
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/tests/d3dkmt.c | 146 +++++++++++++++++++++++++++++++++++++ 1 file changed, 146 insertions(+)
diff --git a/dlls/win32u/tests/d3dkmt.c b/dlls/win32u/tests/d3dkmt.c index 000f91d31cb..e47d2e2917c 100644 --- a/dlls/win32u/tests/d3dkmt.c +++ b/dlls/win32u/tests/d3dkmt.c @@ -1898,6 +1898,151 @@ static void test_D3DKMTCreateSynchronizationObject( void ) ok_nt( STATUS_SUCCESS, status ); }
+static void test_D3DKMTSignalSynchronizationObject(void) +{ + D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME open_adapter = {0}; + D3DKMT_SIGNALSYNCHRONIZATIONOBJECTFROMCPU signal = {0}; + D3DKMT_WAITFORSYNCHRONIZATIONOBJECTFROMCPU wait = {0}; + D3DKMT_DESTROYSYNCHRONIZATIONOBJECT destroy = {0}; + D3DKMT_CREATESYNCHRONIZATIONOBJECT2 create2 = {0}; + D3DKMT_DESTROYDEVICE destroy_device = {0}; + D3DKMT_CREATEDEVICE create_device = {0}; + D3DKMT_CLOSEADAPTER close_adapter = {0}; + UINT64 wait_value, signal_value; + D3DKMT_HANDLE next_local = 0; + NTSTATUS status; + HANDLE event; + DWORD ret; + + wcscpy( open_adapter.DeviceName, L"\\.\DISPLAY1" ); + status = D3DKMTOpenAdapterFromGdiDisplayName( &open_adapter ); + ok_nt( STATUS_SUCCESS, status ); + check_d3dkmt_local( open_adapter.hAdapter, &next_local ); + create_device.hAdapter = open_adapter.hAdapter; + status = D3DKMTCreateDevice( &create_device ); + ok_nt( STATUS_SUCCESS, status ); + check_d3dkmt_local( create_device.hDevice, &next_local ); + create2.hDevice = create_device.hDevice; + + event = CreateEventW( NULL, FALSE, FALSE, NULL ); + ok_ptr( event, !=, NULL ); + + wait.hDevice = create_device.hDevice; + wait.ObjectCount = 1; + wait.ObjectHandleArray = &create2.hSyncObject; + wait.FenceValueArray = &wait_value; + wait.hAsyncEvent = event; + wait_value = 0; + + signal.hDevice = create_device.hDevice; + signal.ObjectCount = 1; + signal.ObjectHandleArray = &create2.hSyncObject; + signal.FenceValueArray = &signal_value; + signal_value = 0; + + + create2.Info.Type = D3DDDI_SYNCHRONIZATION_MUTEX; + create2.hSyncObject = create2.Info.SharedHandle = 0x1eadbeed; + status = D3DKMTCreateSynchronizationObject2( &create2 ); + ok_nt( STATUS_SUCCESS, status ); + check_d3dkmt_local( create2.hSyncObject, &next_local ); + status = D3DKMTWaitForSynchronizationObjectFromCpu( &wait ); + todo_wine ok_nt( STATUS_INVALID_PARAMETER, status ); + status = D3DKMTSignalSynchronizationObjectFromCpu( &signal ); + todo_wine ok_nt( STATUS_INVALID_PARAMETER, status ); + destroy.hSyncObject = create2.hSyncObject; + status = D3DKMTDestroySynchronizationObject( &destroy ); + ok_nt( STATUS_SUCCESS, status ); + + create2.Info.Type = D3DDDI_SEMAPHORE; + create2.hSyncObject = create2.Info.SharedHandle = 0x1eadbeed; + status = D3DKMTCreateSynchronizationObject2( &create2 ); + ok_nt( STATUS_SUCCESS, status ); + check_d3dkmt_local( create2.hSyncObject, &next_local ); + status = D3DKMTWaitForSynchronizationObjectFromCpu( &wait ); + todo_wine ok_nt( STATUS_INVALID_PARAMETER, status ); + status = D3DKMTSignalSynchronizationObjectFromCpu( &signal ); + todo_wine ok_nt( STATUS_INVALID_PARAMETER, status ); + destroy.hSyncObject = create2.hSyncObject; + status = D3DKMTDestroySynchronizationObject( &destroy ); + ok_nt( STATUS_SUCCESS, status ); + + create2.Info.Type = D3DDDI_FENCE; + create2.hSyncObject = create2.Info.SharedHandle = 0x1eadbeed; + status = D3DKMTCreateSynchronizationObject2( &create2 ); + ok_nt( STATUS_SUCCESS, status ); + check_d3dkmt_local( create2.hSyncObject, &next_local ); + status = D3DKMTWaitForSynchronizationObjectFromCpu( &wait ); + todo_wine ok_nt( STATUS_INVALID_PARAMETER, status ); + status = D3DKMTSignalSynchronizationObjectFromCpu( &signal ); + todo_wine ok_nt( STATUS_INVALID_PARAMETER, status ); + destroy.hSyncObject = create2.hSyncObject; + status = D3DKMTDestroySynchronizationObject( &destroy ); + ok_nt( STATUS_SUCCESS, status ); + + + create2.Info.Type = D3DDDI_MONITORED_FENCE; + create2.Info.Fence.FenceValue = 1; + create2.hSyncObject = create2.Info.SharedHandle = 0x1eadbeed; + status = D3DKMTCreateSynchronizationObject2( &create2 ); + ok_nt( STATUS_SUCCESS, status ); + check_d3dkmt_local( create2.hSyncObject, &next_local ); + + status = D3DKMTWaitForSynchronizationObjectFromCpu( &wait ); + todo_wine ok_nt( STATUS_SUCCESS, status ); + ret = WaitForSingleObject( event, 100 ); + todo_wine ok_ret( 0, ret ); + wait_value = 1; + status = D3DKMTWaitForSynchronizationObjectFromCpu( &wait ); + todo_wine ok_nt( STATUS_SUCCESS, status ); + ret = WaitForSingleObject( event, 100 ); + todo_wine ok_ret( 0, ret ); + wait_value = 2; + status = D3DKMTWaitForSynchronizationObjectFromCpu( &wait ); + todo_wine ok_nt( STATUS_SUCCESS, status ); + ret = WaitForSingleObject( event, 100 ); + ok_ret( WAIT_TIMEOUT, ret ); + + signal_value = 2; + status = D3DKMTSignalSynchronizationObjectFromCpu( &signal ); + todo_wine ok_nt( STATUS_SUCCESS, status ); + ret = WaitForSingleObject( event, 100 ); + todo_wine ok_ret( 0, ret ); + + signal_value = 1; + status = D3DKMTSignalSynchronizationObjectFromCpu( &signal ); + todo_wine ok_nt( STATUS_INVALID_PARAMETER, status ); + signal.Flags.AllowFenceRewind = 1; + status = D3DKMTSignalSynchronizationObjectFromCpu( &signal ); + todo_wine ok_nt( STATUS_SUCCESS, status ); + signal.Flags.AllowFenceRewind = 0; + + status = D3DKMTWaitForSynchronizationObjectFromCpu( &wait ); + todo_wine ok_nt( STATUS_SUCCESS, status ); + ret = WaitForSingleObject( event, 100 ); + ok_ret( WAIT_TIMEOUT, ret ); + + signal_value = 2; + status = D3DKMTSignalSynchronizationObjectFromCpu( &signal ); + todo_wine ok_nt( STATUS_SUCCESS, status ); + ret = WaitForSingleObject( event, 100 ); + todo_wine ok_ret( 0, ret ); + + destroy.hSyncObject = create2.hSyncObject; + status = D3DKMTDestroySynchronizationObject( &destroy ); + ok_nt( STATUS_SUCCESS, status ); + + + CloseHandle( event ); + + destroy_device.hDevice = create_device.hDevice; + status = D3DKMTDestroyDevice( &destroy_device ); + ok_nt( STATUS_SUCCESS, status ); + close_adapter.hAdapter = open_adapter.hAdapter; + status = D3DKMTCloseAdapter( &close_adapter ); + ok_nt( STATUS_SUCCESS, status ); +} + static void test_D3DKMTCreateKeyedMutex( void ) { D3DKMT_DESTROYKEYEDMUTEX destroy = {0}; @@ -5442,6 +5587,7 @@ START_TEST( d3dkmt ) test_D3DKMTQueryVideoMemoryInfo(); test_gpu_device_properties(); test_D3DKMTCreateSynchronizationObject(); + test_D3DKMTSignalSynchronizationObject(); test_D3DKMTCreateKeyedMutex(); test_D3DKMTAcquireKeyedMutex(); test_D3DKMTCreateAllocation();
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/tests/d3dkmt.c | 1093 +++++++++++++++++++++++++++++++++--- 1 file changed, 1028 insertions(+), 65 deletions(-)
diff --git a/dlls/win32u/tests/d3dkmt.c b/dlls/win32u/tests/d3dkmt.c index e47d2e2917c..c932b0cc65f 100644 --- a/dlls/win32u/tests/d3dkmt.c +++ b/dlls/win32u/tests/d3dkmt.c @@ -38,7 +38,7 @@
#include "d3d9.h" #include "dxgi1_3.h" -#include "d3d11_1.h" +#include "d3d11_4.h" #include "d3d12.h"
#include "wine/vulkan.h" @@ -3411,22 +3411,22 @@ static IDXGIAdapter *create_dxgi_adapter( IDXGIFactory3 *dxgi, LUID *luid ) return adapter; }
-static ID3D11Device1 *create_d3d11_device( IDXGIAdapter *adapter ) +static void *create_d3d11_device( IDXGIAdapter *adapter, const GUID *iid ) { D3D_FEATURE_LEVEL feature_level = D3D_FEATURE_LEVEL_11_0; - ID3D11Device1 *device1; ID3D11Device *device; HRESULT hr; + void *ret;
hr = D3D11CreateDevice( adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, 0, &feature_level, 1, D3D11_SDK_VERSION, &device, NULL, NULL ); ok_hr( S_OK, hr );
- hr = ID3D11Device_QueryInterface( device, &IID_ID3D11Device1, (void **)&device1 ); + hr = ID3D11Device_QueryInterface( device, iid, &ret ); ok_hr( S_OK, hr ); ID3D11Device_Release( device );
- return device1; + return ret; }
struct vulkan_device @@ -3471,15 +3471,15 @@ static VkResult create_vulkan_instance( uint32_t extension_count, const char *co
static void get_vulkan_physical_device_luid( VkInstance instance, VkPhysicalDevice physical_device, LUID *luid ) { - PFN_vkGetPhysicalDeviceProperties2 p_vkGetPhysicalDeviceProperties2; + PFN_vkGetPhysicalDeviceProperties2 p_vkGetPhysicalDeviceProperties2KHR;
VkPhysicalDeviceIDProperties id_props = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES}; VkPhysicalDeviceVulkan11Properties vk11_props = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES, .pNext = &id_props}; VkPhysicalDeviceProperties2 props = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, .pNext = &vk11_props};
- if (!(p_vkGetPhysicalDeviceProperties2 = (void *)p_vkGetInstanceProcAddr( instance, "vkGetPhysicalDeviceProperties2" ))) return; + if (!(p_vkGetPhysicalDeviceProperties2KHR = (void *)p_vkGetInstanceProcAddr( instance, "vkGetPhysicalDeviceProperties2KHR" ))) return;
- p_vkGetPhysicalDeviceProperties2( physical_device, &props ); + p_vkGetPhysicalDeviceProperties2KHR( physical_device, &props ); ok_u4( props.properties.apiVersion, !=, 0 ); ok_u4( props.properties.driverVersion, !=, 0 ); ok_u4( props.properties.vendorID, !=, 0 ); @@ -3553,6 +3553,126 @@ static VkExternalMemoryHandleTypeFlags get_vulkan_external_image_types( VkInstan return handle_types; }
+static void check_external_image_types( struct vulkan_device *dev ) +{ + PFN_vkEnumeratePhysicalDevices p_vkEnumeratePhysicalDevices; + VkPhysicalDevice *physical_devices; + uint32_t count; + VkResult vr; + + p_vkEnumeratePhysicalDevices = (void *)p_vkGetInstanceProcAddr( dev->instance, "vkEnumeratePhysicalDevices" ); + vr = p_vkEnumeratePhysicalDevices( dev->instance, &count, NULL ); + ok_vk( VK_SUCCESS, vr ); + + physical_devices = calloc( count, sizeof(*physical_devices) ); + ok_ptr( physical_devices, !=, NULL ); + vr = p_vkEnumeratePhysicalDevices( dev->instance, &count, physical_devices ); + ok_vk( VK_SUCCESS, vr ); + + for (uint32_t i = 0; i < count; ++i) + { + static const VkExternalMemoryHandleTypeFlags expect_export_types = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT | + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT; + static const VkExternalMemoryHandleTypeFlags expect_import_types = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT | + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT | + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT | + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT | + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT | + VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT; + VkExternalMemoryHandleTypeFlags types; + + winetest_push_context( "export" ); + types = get_vulkan_external_image_types( dev->instance, physical_devices[i], VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHR ); + ok( !(~types & expect_export_types), "got types %#x\n", types ); + winetest_pop_context(); + + winetest_push_context( "import" ); + types = get_vulkan_external_image_types( dev->instance, physical_devices[i], VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR ); + ok( !(~types & expect_import_types), "got types %#x\n", types ); + winetest_pop_context(); + } + + free( physical_devices ); +} + +static VkExternalSemaphoreHandleTypeFlags get_vulkan_external_semaphore_types( VkInstance instance, VkPhysicalDevice physical_device, + VkExternalSemaphoreFeatureFlags feature_flags ) +{ + static const VkExternalSemaphoreHandleTypeFlagBits bits[] = + { + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT, + }; + + VkPhysicalDeviceExternalSemaphoreInfo external_info = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO}; + + PFN_vkGetPhysicalDeviceExternalSemaphoreProperties p_vkGetPhysicalDeviceExternalSemaphoreProperties; + VkExternalSemaphoreHandleTypeFlags handle_types = 0; + + if (!(p_vkGetPhysicalDeviceExternalSemaphoreProperties = (void *)p_vkGetInstanceProcAddr( instance, "vkGetPhysicalDeviceExternalSemaphoreProperties" ))) return 0; + + for (const VkExternalSemaphoreHandleTypeFlagBits *bit = bits; bit < bits + ARRAY_SIZE(bits); bit++) + { + VkExternalSemaphoreProperties external_props = {.sType = VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES}; + + winetest_push_context( "%#x", *bit ); + + external_info.handleType = *bit; + p_vkGetPhysicalDeviceExternalSemaphoreProperties( physical_device, &external_info, &external_props ); + if (!(~external_props.externalSemaphoreFeatures & feature_flags)) + { + ok_u4( external_props.compatibleHandleTypes, ==, external_info.handleType ); + handle_types |= external_info.handleType; + } + + winetest_pop_context(); + } + + return handle_types; +} + +static void check_external_semaphore_types( struct vulkan_device *dev ) +{ + PFN_vkEnumeratePhysicalDevices p_vkEnumeratePhysicalDevices; + VkPhysicalDevice *physical_devices; + uint32_t count; + VkResult vr; + + p_vkEnumeratePhysicalDevices = (void *)p_vkGetInstanceProcAddr( dev->instance, "vkEnumeratePhysicalDevices" ); + vr = p_vkEnumeratePhysicalDevices( dev->instance, &count, NULL ); + ok_vk( VK_SUCCESS, vr ); + + physical_devices = calloc( count, sizeof(*physical_devices) ); + ok_ptr( physical_devices, !=, NULL ); + vr = p_vkEnumeratePhysicalDevices( dev->instance, &count, physical_devices ); + ok_vk( VK_SUCCESS, vr ); + + for (uint32_t i = 0; i < count; ++i) + { + static const VkExternalSemaphoreHandleTypeFlags expect_export_types = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT | + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT; + static const VkExternalSemaphoreHandleTypeFlags expect_import_types = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT | + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT | + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT; + VkExternalMemoryHandleTypeFlags types; + + winetest_push_context( "export" ); + types = get_vulkan_external_semaphore_types( dev->instance, physical_devices[i], VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT_KHR ); + ok( !(~types & expect_export_types), "got types %#x\n", types ); + winetest_pop_context(); + + winetest_push_context( "import" ); + types = get_vulkan_external_semaphore_types( dev->instance, physical_devices[i], VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT_KHR ); + ok( !(~types & expect_import_types), "got types %#x\n", types ); + winetest_pop_context(); + } + + free( physical_devices ); +} + static void destroy_vulkan_device( struct vulkan_device *dev ) { if (dev->instance) @@ -3589,21 +3709,14 @@ static uint32_t get_vulkan_queue_family( VkInstance instance, VkPhysicalDevice p return i; }
-static struct vulkan_device *create_vulkan_device( LUID *luid ) +static VkResult create_vulkan_device( LUID *luid, const char **device_extensions, UINT device_extensions_count, struct vulkan_device **device ) { static const char *instance_extensions[] = { "VK_KHR_external_memory_capabilities", + "VK_KHR_external_semaphore_capabilities", "VK_KHR_get_physical_device_properties2", }; - static const char *device_extensions[] = - { - "VK_KHR_get_memory_requirements2", - "VK_KHR_dedicated_allocation", - "VK_KHR_external_memory", - "VK_KHR_external_memory_win32", - "VK_KHR_win32_keyed_mutex", - };
VkDeviceQueueCreateInfo queue_info = {.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO}; VkDeviceCreateInfo create_info = {.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO}; @@ -3615,14 +3728,14 @@ static struct vulkan_device *create_vulkan_device( LUID *luid ) struct vulkan_device *dev; float priority = 0.0f; uint32_t count; - BOOL is_wow64; VkResult vr;
+ *device = NULL; dev = calloc( 1, sizeof(*dev) ); ok_ptr( dev, !=, NULL );
vr = create_vulkan_instance( ARRAY_SIZE(instance_extensions), instance_extensions, &dev->instance ); - if (vr != VK_SUCCESS) return NULL; + if (vr != VK_SUCCESS) return vr;
p_vkEnumeratePhysicalDevices = (void *)p_vkGetInstanceProcAddr( dev->instance, "vkEnumeratePhysicalDevices" ); vr = p_vkEnumeratePhysicalDevices( dev->instance, &count, NULL ); @@ -3633,29 +3746,6 @@ static struct vulkan_device *create_vulkan_device( LUID *luid ) vr = p_vkEnumeratePhysicalDevices( dev->instance, &count, physical_devices ); ok_vk( VK_SUCCESS, vr );
- for (uint32_t i = 0; i < count; ++i) - { - static const VkExternalMemoryHandleTypeFlags expect_export_types = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT | - VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT; - static const VkExternalMemoryHandleTypeFlags expect_import_types = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT | - VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT | - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT | - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT | - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT | - VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT; - VkExternalMemoryHandleTypeFlags types; - - winetest_push_context( "export" ); - types = get_vulkan_external_image_types( dev->instance, physical_devices[i], VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHR ); - ok( !(~types & expect_export_types), "got types %#x\n", types ); - winetest_pop_context(); - - winetest_push_context( "import" ); - types = get_vulkan_external_image_types( dev->instance, physical_devices[i], VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR ); - ok( !(~types & expect_import_types), "got types %#x\n", types ); - winetest_pop_context(); - } - for (uint32_t i = 0; i < count; ++i) { LUID device_luid; @@ -3674,27 +3764,24 @@ static struct vulkan_device *create_vulkan_device( LUID *luid ) queue_info.queueCount = 1; queue_info.pQueuePriorities = &priority;
- create_info.enabledExtensionCount = ARRAY_SIZE(device_extensions); + create_info.enabledExtensionCount = device_extensions_count; create_info.ppEnabledExtensionNames = device_extensions; create_info.queueCreateInfoCount = 1; create_info.pQueueCreateInfos = &queue_info;
p_vkCreateDevice = (void *)p_vkGetInstanceProcAddr( dev->instance, "vkCreateDevice" ); vr = p_vkCreateDevice( dev->physical_device, &create_info, NULL, &dev->device ); - /* currently fails on llvmpipe on WOW64 without placed memory */ - todo_wine_if(IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64 && vr == VK_ERROR_EXTENSION_NOT_PRESENT) - ok_vk( VK_SUCCESS, vr ); if (vr != VK_SUCCESS) { PFN_vkDestroyInstance p_vkDestroyInstance; p_vkDestroyInstance = (void *)p_vkGetInstanceProcAddr( dev->instance, "vkDestroyInstance" ); p_vkDestroyInstance( dev->instance, NULL ); free( dev ); - return NULL; + dev = NULL; } - ok_ptr( dev->device, !=, VK_NULL_HANDLE );
- return dev; + *device = dev; + return vr; }
static uint32_t find_vulkan_memory_type( VkInstance instance, VkPhysicalDevice physical_device, VkMemoryPropertyFlagBits flags, uint32_t mask ) @@ -3999,6 +4086,74 @@ static VkResult import_vulkan_image( struct vulkan_device *dev, UINT width, UINT return VK_SUCCESS; }
+static void destroy_vulkan_semaphore( struct vulkan_device *dev, VkSemaphore semaphore ) +{ + PFN_vkDestroySemaphore p_vkDestroySemaphore; + p_vkDestroySemaphore = (void *)p_vkGetDeviceProcAddr( dev->device, "vkDestroySemaphore" ); + p_vkDestroySemaphore( dev->device, semaphore, NULL ); +} + +static VkSemaphore export_vulkan_semaphore( struct vulkan_device *dev, uint64_t value, VkSemaphoreType type, + UINT handle_type, HANDLE *handle ) +{ + VkExportSemaphoreCreateInfo export_info = {.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO}; + VkSemaphoreTypeCreateInfo type_info = {.sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO, .pNext = &export_info}; + VkSemaphoreCreateInfo create_info = {.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, .pNext = &type_info}; + + VkSemaphoreGetWin32HandleInfoKHR get_handle_info = {.sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_WIN32_HANDLE_INFO_KHR}; + + PFN_vkGetSemaphoreWin32HandleKHR p_vkGetSemaphoreWin32HandleKHR; + PFN_vkCreateSemaphore p_vkCreateSemaphore; + VkSemaphore semaphore; + VkResult vr; + + p_vkCreateSemaphore = (void *)p_vkGetDeviceProcAddr( dev->device, "vkCreateSemaphore" ); + p_vkGetSemaphoreWin32HandleKHR = (void *)p_vkGetDeviceProcAddr( dev->device, "vkGetSemaphoreWin32HandleKHR" ); + + export_info.handleTypes = handle_type; + type_info.semaphoreType = type; + type_info.initialValue = value; + vr = p_vkCreateSemaphore( dev->device, &create_info, NULL, &semaphore ); + ok_vk( VK_SUCCESS, vr ); + + get_handle_info.semaphore = semaphore; + get_handle_info.handleType = handle_type; + vr = p_vkGetSemaphoreWin32HandleKHR( dev->device, &get_handle_info, handle ); + ok_vk( VK_SUCCESS, vr ); + + return semaphore; +} + +static VkResult import_vulkan_semaphore( struct vulkan_device *dev, VkSemaphoreType type, const WCHAR *name, + HANDLE handle, UINT handle_type, VkSemaphore *out ) +{ + VkSemaphoreTypeCreateInfo type_info = {.sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO}; + VkSemaphoreCreateInfo create_info = {.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, .pNext = &type_info}; + VkImportSemaphoreWin32HandleInfoKHR import_info = {.sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR}; + + PFN_vkCreateSemaphore p_vkCreateSemaphore; + PFN_vkImportSemaphoreWin32HandleKHR p_vkImportSemaphoreWin32HandleKHR; + VkSemaphore semaphore; + + VkResult vr; + + p_vkCreateSemaphore = (void *)p_vkGetDeviceProcAddr( dev->device, "vkCreateSemaphore" ); + p_vkImportSemaphoreWin32HandleKHR = (void *)p_vkGetDeviceProcAddr( dev->device, "vkImportSemaphoreWin32HandleKHR" ); + + type_info.semaphoreType = type; + create_info.flags = 0; + vr = p_vkCreateSemaphore( dev->device, &create_info, NULL, &semaphore ); + ok_vk( VK_SUCCESS, vr ); + + import_info.semaphore = semaphore; + import_info.handleType = handle_type; + import_info.handle = name ? NULL : handle; + import_info.name = name; + vr = p_vkImportSemaphoreWin32HandleKHR( dev->device, &import_info ); + *out = semaphore; + return vr; +} + C_ASSERT( sizeof(GUID) == GL_UUID_SIZE_EXT ); C_ASSERT( sizeof(LUID) == GL_LUID_SIZE_EXT );
@@ -4205,6 +4360,19 @@ static HRESULT get_d3d12_shared_handle( ID3D12Device *d3d12, IUnknown *obj, cons return hr; }
+static HRESULT open_d3d12_named_shared_handle( ID3D12Device *d3d12, const WCHAR *name, const GUID *iid, void **obj ) +{ + HANDLE handle; + HRESULT hr; + + hr = ID3D12Device_OpenSharedHandleByName( d3d12, name, GENERIC_ALL, &handle ); + ok_hr( S_OK, hr ); + hr = ID3D12Device_OpenSharedHandle( d3d12, handle, iid, obj ); + CloseHandle( handle ); + + return hr; +} + static void test_shared_keyed_mutex( LUID luid, struct vulkan_device *vulkan_imp, struct vulkan_image *img, HANDLE handle, BOOL shared ) { uint64_t release_key = 0, acquire_key = 0; @@ -4391,16 +4559,26 @@ static void test_shared_keyed_mutex( LUID luid, struct vulkan_device *vulkan_imp
static void test_shared_resources(void) { + static const char *device_extensions[] = + { + "VK_KHR_get_memory_requirements2", + "VK_KHR_dedicated_allocation", + "VK_KHR_external_memory", + "VK_KHR_external_memory_win32", + "VK_KHR_win32_keyed_mutex", + }; + struct vulkan_device *vulkan_imp = NULL, *vulkan_exp = NULL; struct opengl_device *opengl_imp = NULL; IDirect3DDevice9Ex *d3d9_exp = NULL, *d3d9_imp = NULL; ID3D11Device1 *d3d11_exp = NULL, *d3d11_imp = NULL; ID3D10Device *d3d10_exp = NULL, *d3d10_imp = NULL; ID3D12Device *d3d12_exp = NULL, *d3d12_imp = NULL; + BOOL stencil_broken, is_wow64 = FALSE; IDXGIFactory3 *dxgi = NULL; IDXGIAdapter *adapter; - BOOL stencil_broken; LUID luid = {0}; + VkResult vr; HRESULT hr; HWND hwnd; MSG msg; @@ -4416,10 +4594,16 @@ static void test_shared_resources(void) return; }
- trace( "adapter luid %s\n", debugstr_luid( &luid ) ); + vr = create_vulkan_device( &luid, device_extensions, ARRAY_SIZE(device_extensions), &vulkan_exp ); + /* currently fails on llvmpipe on WOW64 without placed memory */ + todo_wine_if(IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64 && vr == VK_ERROR_EXTENSION_NOT_PRESENT) + ok_vk( VK_SUCCESS, vr ); + + vr = create_vulkan_device( &luid, device_extensions, ARRAY_SIZE(device_extensions), &vulkan_imp ); + if (vulkan_exp) ok_vk( VK_SUCCESS, vr ); + else ok_vk( VK_ERROR_EXTENSION_NOT_PRESENT, vr );
- vulkan_exp = create_vulkan_device( &luid ); - vulkan_imp = create_vulkan_device( &luid ); + if (vulkan_exp) check_external_image_types( vulkan_exp );
d3d9_exp = create_d3d9ex_device( hwnd, &luid, &stencil_broken ); ok_ptr( d3d9_exp, !=, NULL ); @@ -4439,9 +4623,9 @@ static void test_shared_resources(void) D3D10_SDK_VERSION, &d3d10_exp ); ok_hr( S_OK, hr );
- d3d11_imp = create_d3d11_device( adapter ); + d3d11_imp = create_d3d11_device( adapter, &IID_ID3D11Device1 ); ok_ptr( d3d11_imp, !=, NULL ); - d3d11_exp = create_d3d11_device( adapter ); + d3d11_exp = create_d3d11_device( adapter, &IID_ID3D11Device1 ); ok_ptr( d3d11_exp, !=, NULL );
hr = D3D12CreateDevice( (IUnknown *)adapter, D3D_FEATURE_LEVEL_12_0, @@ -4453,6 +4637,8 @@ static void test_shared_resources(void)
IDXGIAdapter_Release( adapter );
+ trace( "adapter luid %s\n", debugstr_luid( &luid ) ); + #define MAKETEST(api, dim, idx) (((api & 7) << 7) | ((dim & 7) << 4) | (idx & 15)) #define GET_API(test) ((test >> 7) & 7) #define GET_DIM(test) ((test >> 4) & 7) @@ -5323,20 +5509,13 @@ static void test_shared_resources(void) { hr = ID3D12Device_OpenSharedHandle( d3d12_imp, handle, &IID_ID3D12Resource, (void **)&import ); ok_hr( S_OK, hr ); - ok_ptr( import, !=, NULL ); - if (import) ok_ref( 0, IUnknown_Release( import ) ); + if (hr == S_OK) ok_ref( 0, IUnknown_Release( import ) );
if (name) { - HANDLE other = 0; - - hr = ID3D12Device_OpenSharedHandleByName( d3d12_imp, name, GENERIC_ALL, &other ); + hr = open_d3d12_named_shared_handle( d3d12_imp, name, &IID_ID3D12Resource, (void **)&import ); ok_hr( S_OK, hr ); - hr = ID3D12Device_OpenSharedHandle( d3d12_imp, other, &IID_ID3D12Resource, (void **)&import ); - ok_hr( S_OK, hr ); - if (other) CloseHandle( other ); - - if (import) ok_ref( 0, IUnknown_Release( import ) ); + if (hr == S_OK) ok_ref( 0, IUnknown_Release( import ) ); } }
@@ -5561,6 +5740,789 @@ skip_tests: DestroyWindow( hwnd ); }
+static BOOL has_timeline_semaphore( struct vulkan_device *dev ) +{ + VkPhysicalDeviceTimelineSemaphoreFeaturesKHR timeline_features = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES_KHR}; + VkPhysicalDeviceFeatures2KHR features = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR, .pNext = &timeline_features}; + PFN_vkGetPhysicalDeviceFeatures2KHR p_vkGetPhysicalDeviceFeatures2KHR; + + p_vkGetPhysicalDeviceFeatures2KHR = (void *)p_vkGetInstanceProcAddr( dev->instance, "vkGetPhysicalDeviceFeatures2KHR" ); + p_vkGetPhysicalDeviceFeatures2KHR( dev->physical_device, &features ); + + return timeline_features.timelineSemaphore; +} + +static UINT64 get_timeline_semaphore_limit( struct vulkan_device *dev ) +{ + VkPhysicalDeviceTimelineSemaphorePropertiesKHR timeline_props = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES_KHR}; + VkPhysicalDeviceProperties2KHR props = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR, .pNext = &timeline_props}; + PFN_vkGetPhysicalDeviceProperties2KHR p_vkGetPhysicalDeviceProperties2KHR; + + p_vkGetPhysicalDeviceProperties2KHR = (void *)p_vkGetInstanceProcAddr( dev->instance, "vkGetPhysicalDeviceProperties2KHR" ); + p_vkGetPhysicalDeviceProperties2KHR( dev->physical_device, &props ); + + return timeline_props.maxTimelineSemaphoreValueDifference; +} + +static void test_vulkan_semaphore_from_d3d12_fence( struct vulkan_device *dev, ID3D12Fence *fence, HANDLE handle ) +{ + VkFenceCreateInfo fence_info = {.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO}; + uint32_t index, stage_mask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; + VkTimelineSemaphoreSubmitInfo timeline_info; + PFN_vkGetDeviceQueue p_vkGetDeviceQueue; + PFN_vkWaitForFences p_vkWaitForFences; + VkD3D12FenceSubmitInfoKHR d3d12_info; + PFN_vkDestroyFence p_vkDestroyFence; + PFN_vkCreateFence p_vkCreateFence; + PFN_vkQueueSubmit p_vkQueueSubmit; + uint64_t wait_values, signal_values; + VkSubmitInfo submit; + VkFence vk_fence; + VkQueue vk_queue; + VkSemaphore sem; + UINT64 value; + VkResult vr; + HRESULT hr; + + p_vkGetDeviceQueue = (void *)p_vkGetDeviceProcAddr( dev->device, "vkGetDeviceQueue" ); + p_vkWaitForFences = (void *)p_vkGetDeviceProcAddr( dev->device, "vkWaitForFences" ); + p_vkDestroyFence = (void *)p_vkGetDeviceProcAddr( dev->device, "vkDestroyFence" ); + p_vkCreateFence = (void *)p_vkGetDeviceProcAddr( dev->device, "vkCreateFence" ); + p_vkQueueSubmit = (void *)p_vkGetDeviceProcAddr( dev->device, "vkQueueSubmit" ); + + index = get_vulkan_queue_family( dev->instance, dev->physical_device ); + p_vkGetDeviceQueue( dev->device, index, 0, &vk_queue ); + + + /* test importing as binary semaphore with d3d12 fence submits */ + value = ID3D12Fence_GetCompletedValue( fence ); + ok_x8( value, ==, 0 ); + vr = import_vulkan_semaphore( dev, VK_SEMAPHORE_TYPE_BINARY, NULL, handle, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT, &sem ); + ok_vk( VK_SUCCESS, vr ); + + memset( &submit, 0, sizeof(submit) ); + submit.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit.pWaitSemaphores = &sem; + submit.pWaitDstStageMask = &stage_mask; + submit.waitSemaphoreCount = 1; + submit.pNext = &d3d12_info; + memset( &d3d12_info, 0, sizeof(d3d12_info) ); + d3d12_info.sType = VK_STRUCTURE_TYPE_D3D12_FENCE_SUBMIT_INFO_KHR; + d3d12_info.pWaitSemaphoreValues = &wait_values; + d3d12_info.waitSemaphoreValuesCount = 1; + wait_values = 1; + vr = p_vkCreateFence( dev->device, &fence_info, NULL, &vk_fence ); + ok_vk( VK_SUCCESS, vr ); + vr = p_vkQueueSubmit( vk_queue, 1, &submit, vk_fence ); + ok_vk( VK_SUCCESS, vr ); + vr = p_vkWaitForFences( dev->device, 1, &vk_fence, VK_FALSE, 100 * 1000000 ); + ok_vk( VK_TIMEOUT, vr ); + + hr = ID3D12Fence_Signal( fence, 1 ); + ok_hr( S_OK, hr ); + value = ID3D12Fence_GetCompletedValue( fence ); + ok_x8( value, ==, 1 ); + vr = p_vkWaitForFences( dev->device, 1, &vk_fence, VK_FALSE, 1000 * 1000000 ); + ok_vk( VK_SUCCESS, vr ); + p_vkDestroyFence( dev->device, vk_fence, NULL ); + + memset( &submit, 0, sizeof(submit) ); + submit.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit.pSignalSemaphores = &sem; + submit.signalSemaphoreCount = 1; + submit.pNext = &d3d12_info; + memset( &d3d12_info, 0, sizeof(d3d12_info) ); + d3d12_info.sType = VK_STRUCTURE_TYPE_D3D12_FENCE_SUBMIT_INFO_KHR; + d3d12_info.pSignalSemaphoreValues = &signal_values; + d3d12_info.signalSemaphoreValuesCount = 1; + signal_values = 2; + vr = p_vkCreateFence( dev->device, &fence_info, NULL, &vk_fence ); + ok_vk( VK_SUCCESS, vr ); + vr = p_vkQueueSubmit( vk_queue, 1, &submit, vk_fence ); + ok_vk( VK_SUCCESS, vr ); + vr = p_vkWaitForFences( dev->device, 1, &vk_fence, VK_FALSE, 1000 * 1000000 ); + ok_vk( VK_SUCCESS, vr ); + p_vkDestroyFence( dev->device, vk_fence, NULL ); + value = ID3D12Fence_GetCompletedValue( fence ); + ok_x8( value, ==, 2 ); + + signal_values = 1; + vr = p_vkCreateFence( dev->device, &fence_info, NULL, &vk_fence ); + ok_vk( VK_SUCCESS, vr ); + vr = p_vkQueueSubmit( vk_queue, 1, &submit, vk_fence ); + ok( vr == VK_SUCCESS || broken(vr == VK_ERROR_UNKNOWN) /* AMD */, "got vr %d\n", vr ); + vr = p_vkWaitForFences( dev->device, 1, &vk_fence, VK_FALSE, 1000 * 1000000 ); + ok_vk( VK_SUCCESS, vr ); + p_vkDestroyFence( dev->device, vk_fence, NULL ); + value = ID3D12Fence_GetCompletedValue( fence ); + ok( value == 1 || broken(value == 2) /* AMD */, "got value %#I64x\n", value ); + + destroy_vulkan_semaphore( dev, sem ); + hr = ID3D12Fence_Signal( fence, 0 ); + ok_hr( S_OK, hr ); + + + /* test importing as timeline semaphore with d3d12 fence submits */ + + value = ID3D12Fence_GetCompletedValue( fence ); + ok_x8( value, ==, 0 ); + vr = import_vulkan_semaphore( dev, VK_SEMAPHORE_TYPE_TIMELINE, NULL, handle, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT, &sem ); + ok_vk( VK_SUCCESS, vr ); + + memset( &submit, 0, sizeof(submit) ); + submit.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit.pWaitSemaphores = &sem; + submit.pWaitDstStageMask = &stage_mask; + submit.waitSemaphoreCount = 1; + submit.pNext = &d3d12_info; + memset( &d3d12_info, 0, sizeof(d3d12_info) ); + d3d12_info.sType = VK_STRUCTURE_TYPE_D3D12_FENCE_SUBMIT_INFO_KHR; + d3d12_info.pWaitSemaphoreValues = &wait_values; + d3d12_info.waitSemaphoreValuesCount = 1; + wait_values = 1; + vr = p_vkCreateFence( dev->device, &fence_info, NULL, &vk_fence ); + ok_vk( VK_SUCCESS, vr ); + vr = p_vkQueueSubmit( vk_queue, 1, &submit, vk_fence ); + ok_vk( VK_SUCCESS, vr ); + vr = p_vkWaitForFences( dev->device, 1, &vk_fence, VK_FALSE, 100 * 1000000 ); + ok_vk( VK_TIMEOUT, vr ); + + hr = ID3D12Fence_Signal( fence, 1 ); + ok_hr( S_OK, hr ); + value = ID3D12Fence_GetCompletedValue( fence ); + ok_x8( value, ==, 1 ); + vr = p_vkWaitForFences( dev->device, 1, &vk_fence, VK_FALSE, 1000 * 1000000 ); + ok_vk( VK_SUCCESS, vr ); + p_vkDestroyFence( dev->device, vk_fence, NULL ); + + memset( &submit, 0, sizeof(submit) ); + submit.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit.pSignalSemaphores = &sem; + submit.signalSemaphoreCount = 1; + submit.pNext = &d3d12_info; + memset( &d3d12_info, 0, sizeof(d3d12_info) ); + d3d12_info.sType = VK_STRUCTURE_TYPE_D3D12_FENCE_SUBMIT_INFO_KHR; + d3d12_info.pSignalSemaphoreValues = &signal_values; + d3d12_info.signalSemaphoreValuesCount = 1; + signal_values = 2; + vr = p_vkCreateFence( dev->device, &fence_info, NULL, &vk_fence ); + ok_vk( VK_SUCCESS, vr ); + vr = p_vkQueueSubmit( vk_queue, 1, &submit, vk_fence ); + ok_vk( VK_SUCCESS, vr ); + vr = p_vkWaitForFences( dev->device, 1, &vk_fence, VK_FALSE, 1000 * 1000000 ); + ok_vk( VK_SUCCESS, vr ); + p_vkDestroyFence( dev->device, vk_fence, NULL ); + value = ID3D12Fence_GetCompletedValue( fence ); + ok_x8( value, ==, 2 ); + + signal_values = 1; + vr = p_vkCreateFence( dev->device, &fence_info, NULL, &vk_fence ); + ok_vk( VK_SUCCESS, vr ); + vr = p_vkQueueSubmit( vk_queue, 1, &submit, vk_fence ); + ok( vr == VK_SUCCESS || broken(vr == VK_ERROR_UNKNOWN) /* AMD */, "got vr %d\n", vr ); + vr = p_vkWaitForFences( dev->device, 1, &vk_fence, VK_FALSE, 1000 * 1000000 ); + ok_vk( VK_SUCCESS, vr ); + p_vkDestroyFence( dev->device, vk_fence, NULL ); + value = ID3D12Fence_GetCompletedValue( fence ); + ok( value == 1 || broken(value == 2) /* AMD */, "got value %#I64x\n", value ); + + destroy_vulkan_semaphore( dev, sem ); + hr = ID3D12Fence_Signal( fence, 0 ); + ok_hr( S_OK, hr ); + + + /* test importing as timeline semaphore with timeline submits */ + + value = ID3D12Fence_GetCompletedValue( fence ); + ok_x8( value, ==, 0 ); + vr = import_vulkan_semaphore( dev, VK_SEMAPHORE_TYPE_TIMELINE, NULL, handle, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT, &sem ); + ok_vk( VK_SUCCESS, vr ); + + memset( &submit, 0, sizeof(submit) ); + submit.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit.pWaitSemaphores = &sem; + submit.pWaitDstStageMask = &stage_mask; + submit.waitSemaphoreCount = 1; + submit.pNext = &timeline_info; + memset( &timeline_info, 0, sizeof(timeline_info) ); + timeline_info.sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO; + timeline_info.pWaitSemaphoreValues = &wait_values; + timeline_info.waitSemaphoreValueCount = 1; + wait_values = 1; + vr = p_vkCreateFence( dev->device, &fence_info, NULL, &vk_fence ); + ok_vk( VK_SUCCESS, vr ); + vr = p_vkQueueSubmit( vk_queue, 1, &submit, vk_fence ); + ok_vk( VK_SUCCESS, vr ); + vr = p_vkWaitForFences( dev->device, 1, &vk_fence, VK_FALSE, 100 * 1000000 ); + ok_vk( VK_TIMEOUT, vr ); + + hr = ID3D12Fence_Signal( fence, 1 ); + ok_hr( S_OK, hr ); + value = ID3D12Fence_GetCompletedValue( fence ); + ok_x8( value, ==, 1 ); + vr = p_vkWaitForFences( dev->device, 1, &vk_fence, VK_FALSE, 1000 * 1000000 ); + ok_vk( VK_SUCCESS, vr ); + p_vkDestroyFence( dev->device, vk_fence, NULL ); + + memset( &submit, 0, sizeof(submit) ); + submit.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit.pSignalSemaphores = &sem; + submit.signalSemaphoreCount = 1; + submit.pNext = &timeline_info; + memset( &timeline_info, 0, sizeof(timeline_info) ); + timeline_info.sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO; + timeline_info.pSignalSemaphoreValues = &signal_values; + timeline_info.signalSemaphoreValueCount = 1; + signal_values = 2; + vr = p_vkCreateFence( dev->device, &fence_info, NULL, &vk_fence ); + ok_vk( VK_SUCCESS, vr ); + vr = p_vkQueueSubmit( vk_queue, 1, &submit, vk_fence ); + ok_vk( VK_SUCCESS, vr ); + vr = p_vkWaitForFences( dev->device, 1, &vk_fence, VK_FALSE, 1000 * 1000000 ); + ok_vk( VK_SUCCESS, vr ); + p_vkDestroyFence( dev->device, vk_fence, NULL ); + value = ID3D12Fence_GetCompletedValue( fence ); + ok_x8( value, ==, 2 ); + + signal_values = 1; + vr = p_vkCreateFence( dev->device, &fence_info, NULL, &vk_fence ); + ok_vk( VK_SUCCESS, vr ); + vr = p_vkQueueSubmit( vk_queue, 1, &submit, vk_fence ); + ok( vr == VK_SUCCESS || broken(vr == VK_ERROR_UNKNOWN) /* AMD */, "got vr %d\n", vr ); + vr = p_vkWaitForFences( dev->device, 1, &vk_fence, VK_FALSE, 1000 * 1000000 ); + ok_vk( VK_SUCCESS, vr ); + p_vkDestroyFence( dev->device, vk_fence, NULL ); + value = ID3D12Fence_GetCompletedValue( fence ); + ok( value == 1 || broken(value == 2) /* AMD */, "got value %#I64x\n", value ); + + destroy_vulkan_semaphore( dev, sem ); + hr = ID3D12Fence_Signal( fence, 0 ); + ok_hr( S_OK, hr ); + + + /* test larger than maxTimelineSemaphoreValueDifference values */ + + value = ID3D12Fence_GetCompletedValue( fence ); + ok_x8( value, ==, 0 ); + vr = import_vulkan_semaphore( dev, VK_SEMAPHORE_TYPE_TIMELINE, NULL, handle, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT, &sem ); + ok_vk( VK_SUCCESS, vr ); + + memset( &submit, 0, sizeof(submit) ); + submit.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit.pWaitSemaphores = &sem; + submit.pWaitDstStageMask = &stage_mask; + submit.waitSemaphoreCount = 1; + submit.pNext = &timeline_info; + memset( &timeline_info, 0, sizeof(timeline_info) ); + timeline_info.sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO; + timeline_info.pWaitSemaphoreValues = &wait_values; + timeline_info.waitSemaphoreValueCount = 1; + wait_values = 0x7fffffffffffffffull; + vr = p_vkCreateFence( dev->device, &fence_info, NULL, &vk_fence ); + ok_vk( VK_SUCCESS, vr ); + vr = p_vkQueueSubmit( vk_queue, 1, &submit, vk_fence ); + ok_vk( VK_SUCCESS, vr ); + vr = p_vkWaitForFences( dev->device, 1, &vk_fence, VK_FALSE, 100 * 1000000 ); + ok_vk( VK_TIMEOUT, vr ); + + hr = ID3D12Fence_Signal( fence, 0x7fffffffffffffffull ); + ok_hr( S_OK, hr ); + value = ID3D12Fence_GetCompletedValue( fence ); + ok_x8( value, ==, 0x7fffffffffffffffull ); + vr = p_vkWaitForFences( dev->device, 1, &vk_fence, VK_FALSE, 1000 * 1000000 ); + ok_vk( VK_SUCCESS, vr ); + p_vkDestroyFence( dev->device, vk_fence, NULL ); + + memset( &submit, 0, sizeof(submit) ); + submit.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit.pSignalSemaphores = &sem; + submit.signalSemaphoreCount = 1; + submit.pNext = &timeline_info; + memset( &timeline_info, 0, sizeof(timeline_info) ); + timeline_info.sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO; + timeline_info.pSignalSemaphoreValues = &signal_values; + timeline_info.signalSemaphoreValueCount = 1; + signal_values = 0xffffffffffffffffull; + vr = p_vkCreateFence( dev->device, &fence_info, NULL, &vk_fence ); + ok_vk( VK_SUCCESS, vr ); + vr = p_vkQueueSubmit( vk_queue, 1, &submit, vk_fence ); + ok_vk( VK_SUCCESS, vr ); + vr = p_vkWaitForFences( dev->device, 1, &vk_fence, VK_FALSE, 1000 * 1000000 ); + ok_vk( VK_SUCCESS, vr ); + p_vkDestroyFence( dev->device, vk_fence, NULL ); + value = ID3D12Fence_GetCompletedValue( fence ); + ok_x8( value, ==, 0xffffffffffffffffull ); + + signal_values = 1; + vr = p_vkCreateFence( dev->device, &fence_info, NULL, &vk_fence ); + ok_vk( VK_SUCCESS, vr ); + vr = p_vkQueueSubmit( vk_queue, 1, &submit, vk_fence ); + ok( vr == VK_SUCCESS || broken(vr == VK_ERROR_UNKNOWN) /* AMD */, "got vr %d\n", vr ); + vr = p_vkWaitForFences( dev->device, 1, &vk_fence, VK_FALSE, 1000 * 1000000 ); + ok_vk( VK_SUCCESS, vr ); + p_vkDestroyFence( dev->device, vk_fence, NULL ); + value = ID3D12Fence_GetCompletedValue( fence ); + ok( value == 1 || broken(value == 0xffffffffffffffffull) /* AMD */, "got value %#I64x\n", value ); + + destroy_vulkan_semaphore( dev, sem ); + hr = ID3D12Fence_Signal( fence, 0 ); + ok_hr( S_OK, hr ); +} + +static void test_d3d12_fence_from_vulkan_timeline( ID3D12Device *device, struct vulkan_device *dev, VkSemaphore sem, HANDLE handle ) +{ + VkSemaphoreSignalInfo signal_info = {.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO}; + VkSemaphoreWaitInfo wait_info = {.sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO}; + PFN_vkGetSemaphoreCounterValue p_vkGetSemaphoreCounterValue; + PFN_vkSignalSemaphore p_vkSignalSemaphore; + PFN_vkWaitSemaphores p_vkWaitSemaphores; + uint64_t wait_values; + ID3D12Fence *fence; + UINT64 value; + HANDLE event; + VkResult vr; + HRESULT hr; + DWORD ret; + + p_vkGetSemaphoreCounterValue = (void *)p_vkGetDeviceProcAddr( dev->device, "vkGetSemaphoreCounterValue" ); + p_vkSignalSemaphore = (void *)p_vkGetDeviceProcAddr( dev->device, "vkSignalSemaphore" ); + p_vkWaitSemaphores = (void *)p_vkGetDeviceProcAddr( dev->device, "vkWaitSemaphores" ); + + hr = ID3D12Device_OpenSharedHandle( device, handle, &IID_ID3D12Fence, (void **)&fence ); + if (FAILED(hr)) + { + skip( "Failed to import vulkan semaphore as D3D12 fence, skipping tests\n" ); + return; + } + ok_hr( S_OK, hr ); + + event = CreateEventW( NULL, FALSE, FALSE, NULL ); + ok_ptr( event, !=, NULL ); + + value = ID3D12Fence_GetCompletedValue( fence ); + ok_x8( value, ==, 0 ); + + hr = ID3D12Fence_SetEventOnCompletion( fence, 1, event ); + ok_hr( S_OK, hr ); + ret = WaitForSingleObject( event, 100 ); + ok_ret( WAIT_TIMEOUT, ret ); + + signal_info.semaphore = sem; + signal_info.value = 2; + vr = p_vkSignalSemaphore( dev->device, &signal_info ); + ok_vk( VK_SUCCESS, vr ); + vr = p_vkGetSemaphoreCounterValue( dev->device, sem, &value ); + ok_x8( value, ==, 2 ); + ret = WaitForSingleObject( event, 100 ); + ok_ret( 0, ret ); + value = ID3D12Fence_GetCompletedValue( fence ); + ok_x8( value, ==, 2 ); + hr = ID3D12Fence_SetEventOnCompletion( fence, 1, event ); + ok_hr( S_OK, hr ); + ret = WaitForSingleObject( event, 100 ); + ok_ret( 0, ret ); + value = ID3D12Fence_GetCompletedValue( fence ); + ok_x8( value, ==, 2 ); + + /* rewinding timeline semaphore works */ + signal_info.semaphore = sem; + signal_info.value = 1; + vr = p_vkSignalSemaphore( dev->device, &signal_info ); + ok_vk( VK_SUCCESS, vr ); + vr = p_vkGetSemaphoreCounterValue( dev->device, sem, &value ); + ok_x8( value, ==, 1 ); + hr = ID3D12Fence_SetEventOnCompletion( fence, 2, event ); + ok_hr( S_OK, hr ); + ret = WaitForSingleObject( event, 100 ); + ok_ret( WAIT_TIMEOUT, ret ); + value = ID3D12Fence_GetCompletedValue( fence ); + ok_x8( value, ==, 1 ); + signal_info.semaphore = sem; + signal_info.value = 2; + vr = p_vkSignalSemaphore( dev->device, &signal_info ); + ok_vk( VK_SUCCESS, vr ); + vr = p_vkGetSemaphoreCounterValue( dev->device, sem, &value ); + ok_x8( value, ==, 2 ); + ret = WaitForSingleObject( event, 100 ); + ok_ret( 0, ret ); + value = ID3D12Fence_GetCompletedValue( fence ); + ok_x8( value, ==, 2 ); + + hr = ID3D12Fence_Signal( fence, 4 ); + ok_hr( S_OK, hr ); + vr = p_vkGetSemaphoreCounterValue( dev->device, sem, &value ); + ok_x8( value, ==, 4 ); + hr = ID3D12Fence_Signal( fence, 3 ); + ok_hr( S_OK, hr ); + vr = p_vkGetSemaphoreCounterValue( dev->device, sem, &value ); + ok_x8( value, ==, 3 ); + wait_info.semaphoreCount = 1; + wait_info.pSemaphores = &sem; + wait_info.pValues = &wait_values; + wait_values = 4; + vr = p_vkWaitSemaphores( dev->device, &wait_info, 100 * 1000000 ); + ok_vk( VK_TIMEOUT, vr ); + + hr = ID3D12Fence_Signal( fence, 5 ); + ok_hr( S_OK, hr ); + vr = p_vkWaitSemaphores( dev->device, &wait_info, 100 * 1000000 ); + ok_vk( VK_SUCCESS, vr ); + vr = p_vkGetSemaphoreCounterValue( dev->device, sem, &value ); + ok_x8( value, ==, 5 ); + + CloseHandle( event ); + ID3D12Fence_Release( fence ); +} + +static void test_d3d12_fence_from_vulkan_binary( ID3D12Device *device, struct vulkan_device *dev, VkSemaphore sem, HANDLE handle ) +{ + VkFenceCreateInfo fence_info = {.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO}; + uint32_t index, stage_mask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; + PFN_vkGetDeviceQueue p_vkGetDeviceQueue; + PFN_vkWaitForFences p_vkWaitForFences; + PFN_vkDestroyFence p_vkDestroyFence; + PFN_vkCreateFence p_vkCreateFence; + PFN_vkQueueSubmit p_vkQueueSubmit; + VkSubmitInfo submit; + ID3D12Fence *fence; + VkFence vk_fence; + VkQueue vk_queue; + HANDLE event; + UINT64 value; + VkResult vr; + HRESULT hr; + DWORD ret; + + p_vkGetDeviceQueue = (void *)p_vkGetDeviceProcAddr( dev->device, "vkGetDeviceQueue" ); + p_vkWaitForFences = (void *)p_vkGetDeviceProcAddr( dev->device, "vkWaitForFences" ); + p_vkDestroyFence = (void *)p_vkGetDeviceProcAddr( dev->device, "vkDestroyFence" ); + p_vkCreateFence = (void *)p_vkGetDeviceProcAddr( dev->device, "vkCreateFence" ); + p_vkQueueSubmit = (void *)p_vkGetDeviceProcAddr( dev->device, "vkQueueSubmit" ); + + index = get_vulkan_queue_family( dev->instance, dev->physical_device ); + p_vkGetDeviceQueue( dev->device, index, 0, &vk_queue ); + + event = CreateEventW( NULL, FALSE, FALSE, NULL ); + ok_ptr( event, !=, NULL ); + + hr = ID3D12Device_OpenSharedHandle( device, handle, &IID_ID3D12Fence, (void **)&fence ); + ok_hr( S_OK, hr ); + value = ID3D12Fence_GetCompletedValue( fence ); + ok_x8( value, ==, 0 ); + + hr = ID3D12Fence_SetEventOnCompletion( fence, 1, event ); + ok_hr( S_OK, hr ); + ret = WaitForSingleObject( event, 100 ); + ok_ret( WAIT_TIMEOUT, ret ); + + + memset( &submit, 0, sizeof(submit) ); + submit.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit.pSignalSemaphores = &sem; + submit.signalSemaphoreCount = 1; + vr = p_vkCreateFence( dev->device, &fence_info, NULL, &vk_fence ); + ok_vk( VK_SUCCESS, vr ); + vr = p_vkQueueSubmit( vk_queue, 1, &submit, vk_fence ); + ok_vk( VK_SUCCESS, vr ); + vr = p_vkWaitForFences( dev->device, 1, &vk_fence, VK_FALSE, 100 * 1000000 ); + ok_vk( VK_SUCCESS, vr ); + p_vkDestroyFence( dev->device, vk_fence, NULL ); + + value = ID3D12Fence_GetCompletedValue( fence ); + ok_x8( value, ==, 1 ); + ret = WaitForSingleObject( event, 100 ); + ok_ret( 0, ret ); + + + hr = ID3D12Fence_Signal( fence, 0 ); + ok_hr( S_OK, hr ); + value = ID3D12Fence_GetCompletedValue( fence ); + ok_x8( value, ==, 0 ); + hr = ID3D12Fence_SetEventOnCompletion( fence, 1, event ); + ok_hr( S_OK, hr ); + ret = WaitForSingleObject( event, 100 ); + ok_ret( WAIT_TIMEOUT, ret ); + + memset( &submit, 0, sizeof(submit) ); + submit.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit.pWaitSemaphores = &sem; + submit.pWaitDstStageMask = &stage_mask; + submit.waitSemaphoreCount = 1; + vr = p_vkCreateFence( dev->device, &fence_info, NULL, &vk_fence ); + ok_vk( VK_SUCCESS, vr ); + vr = p_vkQueueSubmit( vk_queue, 1, &submit, vk_fence ); + ok_vk( VK_SUCCESS, vr ); + vr = p_vkWaitForFences( dev->device, 1, &vk_fence, VK_FALSE, 100 * 1000000 ); + ok_vk( VK_SUCCESS, vr ); + + hr = ID3D12Fence_Signal( fence, 2 ); + ok_hr( S_OK, hr ); + ret = WaitForSingleObject( event, 100 ); + ok_ret( 0, ret ); + value = ID3D12Fence_GetCompletedValue( fence ); + ok_x8( value, ==, 2 ); + + p_vkDestroyFence( dev->device, vk_fence, NULL ); + + + CloseHandle( event ); + ID3D12Fence_Release( fence ); +} + +static void test_shared_fences(void) +{ + static const char *device_extensions[] = + { + "VK_KHR_timeline_semaphore", + "VK_KHR_external_semaphore", + "VK_KHR_external_semaphore_win32", + }; + + struct vulkan_device *vulkan_imp = NULL, *vulkan_exp = NULL; + ID3D11Device5 *d3d11_exp = NULL, *d3d11_imp = NULL; + ID3D12Device *d3d12_exp = NULL, *d3d12_imp = NULL; + BOOL has_timeline = FALSE, vk_export_broken; + DXGI_ADAPTER_DESC adapter_desc; + IDXGIFactory3 *dxgi = NULL; + UINT64 max_timeline = -1; + IDXGIAdapter *adapter; + LUID luid = {0}; + VkResult vr; + HRESULT hr; + + vr = create_vulkan_device( &luid, device_extensions, ARRAY_SIZE(device_extensions), &vulkan_exp ); + todo_wine ok( vr == VK_SUCCESS || broken(vr == VK_ERROR_INITIALIZATION_FAILED || vr == VK_ERROR_INCOMPATIBLE_DRIVER) /* no GPU */, "got vr %d\n", vr ); + if (vr == VK_SUCCESS) + { + has_timeline = has_timeline_semaphore( vulkan_exp ); + ok( has_timeline, "got has_timeline %u\n", has_timeline ); + max_timeline = get_timeline_semaphore_limit( vulkan_exp ); + ok( max_timeline <= 0xffffffff, "got max_timeline %I64d\n", max_timeline ); + check_external_semaphore_types( vulkan_exp ); + } + vr = create_vulkan_device( &luid, device_extensions, ARRAY_SIZE(device_extensions), &vulkan_imp ); + if (vulkan_exp) todo_wine ok_vk( VK_SUCCESS, vr ); + + hr = CreateDXGIFactory1( &IID_IDXGIFactory3, (void **)&dxgi ); + ok_hr( S_OK, hr ); + adapter = create_dxgi_adapter( dxgi, &luid ); + ok_ptr( adapter, !=, NULL ); + IDXGIFactory3_Release( dxgi ); + + d3d11_imp = create_d3d11_device( adapter, &IID_ID3D11Device5 ); + ok_ptr( d3d11_imp, !=, NULL ); + d3d11_exp = create_d3d11_device( adapter, &IID_ID3D11Device5 ); + ok_ptr( d3d11_exp, !=, NULL ); + + hr = D3D12CreateDevice( (IUnknown *)adapter, D3D_FEATURE_LEVEL_12_0, + &IID_ID3D12Device, (void **)&d3d12_imp ); + todo_wine ok_hr( S_OK, hr ); + hr = D3D12CreateDevice( (IUnknown *)adapter, D3D_FEATURE_LEVEL_12_0, + &IID_ID3D12Device, (void **)&d3d12_exp ); + todo_wine ok_hr( S_OK, hr ); + + hr = IDXGIAdapter_GetDesc( adapter, &adapter_desc ); + ok_hr( S_OK, hr ); + vk_export_broken = !winetest_platform_is_wine && adapter_desc.VendorId == 0x1002; + + IDXGIAdapter_Release( adapter ); + + trace( "adapter luid %s\n", debugstr_luid( &luid ) ); + +#define MAKETEST(api, idx) (((api & 7) << 4) | (idx & 15)) +#define GET_API(test) ((test >> 4) & 7) + + for (UINT test = 0; test <= MAKETEST(7,0xf); test++) + { + IUnknown *export = NULL, *import = NULL; + const WCHAR *name = NULL; + HANDLE handle = NULL; + WCHAR path[MAX_PATH]; + VkSemaphore sem = 0; + + winetest_push_context( "%u:%u", GET_API(test), test & 15 ); + + switch (test) + { + case MAKETEST(0, 0): + hr = ID3D11Device5_CreateFence( d3d11_exp, 0, D3D11_FENCE_FLAG_SHARED, &IID_ID3D11Fence, (void **)&export ); + todo_wine ok_hr( S_OK, hr ); + if (!export) break; + hr = ID3D11Fence_CreateSharedHandle( (ID3D11Fence *)export, NULL, GENERIC_ALL, NULL, &handle ); + ok_hr( S_OK, hr ); + break; + case MAKETEST(0, 1): + hr = ID3D11Device5_CreateFence( d3d11_exp, 0, D3D11_FENCE_FLAG_SHARED, &IID_ID3D11Fence, (void **)&export ); + todo_wine ok_hr( S_OK, hr ); + if (!export) break; + name = L"__winetest_d3d11_fence"; + hr = ID3D11Fence_CreateSharedHandle( (ID3D11Fence *)export, NULL, GENERIC_ALL, name, &handle ); + ok_hr( S_OK, hr ); + break; + + case MAKETEST(1, 0): + if (!d3d12_exp) break; + hr = ID3D12Device_CreateFence( d3d12_exp, 0, D3D12_FENCE_FLAG_SHARED, &IID_ID3D12Fence, (void **)&export ); + ok_hr( S_OK, hr ); + if (!export) break; + hr = get_d3d12_shared_handle( d3d12_exp, export, NULL, &handle ); + ok_hr( S_OK, hr ); + if (vulkan_imp) test_vulkan_semaphore_from_d3d12_fence( vulkan_imp, (ID3D12Fence *)export, handle ); + break; + case MAKETEST(1, 1): + if (!d3d12_exp) break; + hr = ID3D12Device_CreateFence( d3d12_exp, 0, D3D12_FENCE_FLAG_SHARED, &IID_ID3D12Fence, (void **)&export ); + ok_hr( S_OK, hr ); + if (!export) break; + name = L"__winetest_d3d12_fence"; + hr = get_d3d12_shared_handle( d3d12_exp, export, name, &handle ); + ok_hr( S_OK, hr ); + break; + + /* VK_SEMAPHORE_TYPE_TIMELINE + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT crashes on windows */ + case MAKETEST(2, 0): + if (!vulkan_exp || vk_export_broken /* AMD crashes on export */) break; + sem = export_vulkan_semaphore( vulkan_exp, 0, VK_SEMAPHORE_TYPE_TIMELINE, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT, &handle ); + if (sem && d3d12_imp) test_d3d12_fence_from_vulkan_timeline( d3d12_imp, vulkan_exp, sem, handle ); + break; + case MAKETEST(2, 1): + if (!vulkan_exp || vk_export_broken /* AMD crashes on export */) break; + sem = export_vulkan_semaphore( vulkan_exp, 0, VK_SEMAPHORE_TYPE_TIMELINE, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D11_FENCE_BIT, &handle ); + if (sem && d3d12_imp) test_d3d12_fence_from_vulkan_timeline( d3d12_imp, vulkan_exp, sem, handle ); + break; + case MAKETEST(2, 2): + if (!vulkan_exp || vk_export_broken /* AMD crashes on export */) break; + sem = export_vulkan_semaphore( vulkan_exp, 0, VK_SEMAPHORE_TYPE_TIMELINE, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT, &handle ); + if (sem && d3d12_imp) test_d3d12_fence_from_vulkan_timeline( d3d12_imp, vulkan_exp, sem, handle ); + break; + + case MAKETEST(2, 3): + if (!vulkan_exp) break; + sem = export_vulkan_semaphore( vulkan_exp, 0, VK_SEMAPHORE_TYPE_BINARY, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT, &handle ); + break; + case MAKETEST(2, 4): + if (!vulkan_exp) break; + sem = export_vulkan_semaphore( vulkan_exp, 0, VK_SEMAPHORE_TYPE_BINARY, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT, &handle ); + if (sem && d3d12_imp) /* D3D12 fence doesn't work when exporting as OPAQUE_WIN32_BIT */ + { + ID3D12Fence *fence; + UINT64 value; + + hr = ID3D12Device_OpenSharedHandle( d3d12_imp, handle, &IID_ID3D12Fence, (void **)&fence ); + ok_hr( S_OK, hr ); + value = ID3D12Fence_GetCompletedValue( fence ); + ok_x8( value, ==, -1 ); + ID3D12Fence_Release( fence ); + } + break; + case MAKETEST(2, 5): + if (!vulkan_exp || vk_export_broken /* AMD crashes */) break; + sem = export_vulkan_semaphore( vulkan_exp, 0, VK_SEMAPHORE_TYPE_BINARY, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D11_FENCE_BIT, &handle ); + if (sem && d3d12_imp) test_d3d12_fence_from_vulkan_binary( d3d12_imp, vulkan_exp, sem, handle ); + break; + case MAKETEST(2, 6): + if (!vulkan_exp || vk_export_broken /* AMD crashes */) break; + sem = export_vulkan_semaphore( vulkan_exp, 0, VK_SEMAPHORE_TYPE_BINARY, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT, &handle ); + if (sem && d3d12_imp) test_d3d12_fence_from_vulkan_binary( d3d12_imp, vulkan_exp, sem, handle ); + break; + } + if (!handle) goto skip_tests; + + if (name) + { + swprintf( path, ARRAY_SIZE(path), L"\Sessions\1\BaseNamedObjects\%s", name ); + check_object_name( handle, path ); + } + + if (d3d11_imp) + { + hr = ID3D11Device5_OpenSharedFence( d3d11_imp, handle, &IID_ID3D11Fence, (void **)&import ); + if (is_d3dkmt_handle( handle )) todo_wine ok_hr( E_INVALIDARG, hr ); + else todo_wine ok_hr( S_OK, hr ); + if (hr == S_OK) ok_ref( 0, IUnknown_Release( import ) ); + } + + if (d3d12_imp) + { + hr = ID3D12Device_OpenSharedHandle( d3d12_imp, handle, &IID_ID3D12Fence, (void **)&import ); + if (is_d3dkmt_handle( handle )) ok_hr( E_HANDLE, hr ); + else ok_hr( S_OK, hr ); + if (hr == S_OK) ok_ref( 0, IUnknown_Release( import ) ); + + if (name) + { + hr = open_d3d12_named_shared_handle( d3d12_imp, name, &IID_ID3D12Fence, (void **)&import ); + ok_hr( S_OK, hr ); + ok_ref( 0, IUnknown_Release( import ) ); + } + } + + if (vulkan_imp) + { + VkSemaphore sem_imp; + VkResult vr; + + if (is_d3dkmt_handle( handle )) + { + vr = import_vulkan_semaphore( vulkan_imp, VK_SEMAPHORE_TYPE_BINARY, name, handle, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT, &sem_imp ); + ok_vk( VK_SUCCESS, vr ); + destroy_vulkan_semaphore( vulkan_imp, sem_imp ); + + vr = import_vulkan_semaphore( vulkan_imp, VK_SEMAPHORE_TYPE_TIMELINE, name, handle, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT, &sem_imp ); + ok_vk( VK_SUCCESS, vr ); + destroy_vulkan_semaphore( vulkan_imp, sem_imp ); + } + else + { + vr = import_vulkan_semaphore( vulkan_imp, VK_SEMAPHORE_TYPE_BINARY, name, handle, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT, &sem_imp ); + if (test == MAKETEST(2, 4)) ok_vk( VK_SUCCESS, vr ); + else ok( vr == VK_SUCCESS || broken(vr == VK_ERROR_INITIALIZATION_FAILED) /* NVIDIA */, "got %d\n", vr ); + if (vr == VK_SUCCESS) destroy_vulkan_semaphore( vulkan_imp, sem_imp ); + + vr = import_vulkan_semaphore( vulkan_imp, VK_SEMAPHORE_TYPE_BINARY, name, handle, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D11_FENCE_BIT, &sem_imp ); + if (test != MAKETEST(2, 4)) ok_vk( VK_SUCCESS, vr ); + else ok( vr == VK_SUCCESS || broken(vr == VK_ERROR_INITIALIZATION_FAILED) /* NVIDIA */, "got %d\n", vr ); + if (vr == VK_SUCCESS) destroy_vulkan_semaphore( vulkan_imp, sem_imp ); + + vr = import_vulkan_semaphore( vulkan_imp, VK_SEMAPHORE_TYPE_BINARY, name, handle, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT, &sem_imp ); + if (test != MAKETEST(2, 4)) ok_vk( VK_SUCCESS, vr ); + else ok( vr == VK_SUCCESS || broken(vr == VK_ERROR_INITIALIZATION_FAILED) /* NVIDIA */, "got %d\n", vr ); + if (vr == VK_SUCCESS) destroy_vulkan_semaphore( vulkan_imp, sem_imp ); + + + vr = import_vulkan_semaphore( vulkan_imp, VK_SEMAPHORE_TYPE_TIMELINE, name, handle, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT, &sem_imp ); + if (test != MAKETEST(2, 4)) ok_vk( VK_SUCCESS, vr ); + else ok( vr == VK_SUCCESS || broken(vr == VK_ERROR_INITIALIZATION_FAILED) /* NVIDIA */, "got %d\n", vr ); + if (vr == VK_SUCCESS) destroy_vulkan_semaphore( vulkan_imp, sem_imp ); + + vr = import_vulkan_semaphore( vulkan_imp, VK_SEMAPHORE_TYPE_TIMELINE, name, handle, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D11_FENCE_BIT, &sem_imp ); + if (test != MAKETEST(2, 4)) ok_vk( VK_SUCCESS, vr ); + else ok( vr == VK_SUCCESS || broken(vr == VK_ERROR_INITIALIZATION_FAILED) /* NVIDIA */, "got %d\n", vr ); + if (vr == VK_SUCCESS) destroy_vulkan_semaphore( vulkan_imp, sem_imp ); + + vr = import_vulkan_semaphore( vulkan_imp, VK_SEMAPHORE_TYPE_TIMELINE, name, handle, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT, &sem_imp ); + if (test != MAKETEST(2, 4)) ok_vk( VK_SUCCESS, vr ); + else ok( vr == VK_SUCCESS || broken(vr == VK_ERROR_INITIALIZATION_FAILED) /* NVIDIA */, "got %d\n", vr ); + if (vr == VK_SUCCESS) destroy_vulkan_semaphore( vulkan_imp, sem_imp ); + } + } + +skip_tests: + if (handle && !is_d3dkmt_handle( handle )) CloseHandle( handle ); + if (export) ok_ref( 0, IUnknown_Release( export ) ); + if (sem) destroy_vulkan_semaphore( vulkan_exp, sem ); + winetest_pop_context(); + } + +#undef GET_API +#undef MAKETEST + + if (d3d12_imp) ID3D12Device_Release( d3d12_imp ); + if (d3d12_exp) ok_ref( 0, ID3D12Device_Release( d3d12_exp ) ); + if (vulkan_imp) destroy_vulkan_device( vulkan_imp ); + if (vulkan_exp) destroy_vulkan_device( vulkan_exp ); +} + START_TEST( d3dkmt ) { char **argv; @@ -5593,4 +6555,5 @@ START_TEST( d3dkmt ) test_D3DKMTCreateAllocation(); test_D3DKMTShareObjects(); test_shared_resources(); + test_shared_fences(); }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/vulkan-1/tests/vulkan.c | 279 +++++++++++++++++++++++++++++++++++ 1 file changed, 279 insertions(+)
diff --git a/dlls/vulkan-1/tests/vulkan.c b/dlls/vulkan-1/tests/vulkan.c index 8f9678aec03..d4d5cc86ab0 100644 --- a/dlls/vulkan-1/tests/vulkan.c +++ b/dlls/vulkan-1/tests/vulkan.c @@ -1414,6 +1414,284 @@ static void test_external_memory(VkInstance vk_instance, VkPhysicalDevice vk_phy vkDestroyDevice(vk_device, NULL); }
+static const char *test_timeline_semaphore_extensions[] = +{ + "VK_KHR_get_physical_device_properties2", + "VK_KHR_external_semaphore_capabilities", +}; + +static void test_timeline_semaphore(VkInstance vk_instance, VkPhysicalDevice vk_physical_device) +{ + VkSemaphoreTypeCreateInfo type_info = {.sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO}; + VkSemaphoreCreateInfo create_info = {.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, .pNext = &type_info}; + VkSemaphoreWaitInfo wait_info = {.sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO}; + VkTimelineSemaphoreSubmitInfo timeline_info = {.sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO}; + VkSubmitInfo submit = {.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, .pNext = &timeline_info}; + VkSemaphoreSignalInfo signal_info = {.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO}; + VkFenceCreateInfo fence_info = {.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO}; + PFN_vkGetSemaphoreCounterValueKHR p_vkGetSemaphoreCounterValueKHR; + uint32_t index, stage_mask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; + PFN_vkSignalSemaphoreKHR p_vkSignalSemaphoreKHR; + PFN_vkWaitSemaphoresKHR p_vkWaitSemaphoresKHR; + uint64_t value, wait_value, signal_value; + VkSemaphore vk_semaphore, vk_semaphore2; + VkDevice vk_device; + VkFence vk_fence; + VkQueue vk_queue; + VkResult vr; + + static const char *extensions[] = + { + "VK_KHR_timeline_semaphore", + "VK_KHR_external_semaphore", + "VK_KHR_external_semaphore_win32", + }; + + if ((vr = create_device(vk_physical_device, ARRAY_SIZE(extensions), extensions, NULL, &vk_device))) + { + skip("Failed to create device with external memory extensions, VkResult %d.\n", vr); + return; + } + + p_vkGetSemaphoreCounterValueKHR = (void *)vkGetDeviceProcAddr(vk_device, "vkGetSemaphoreCounterValueKHR"); + p_vkSignalSemaphoreKHR = (void *)vkGetDeviceProcAddr(vk_device, "vkSignalSemaphoreKHR"); + p_vkWaitSemaphoresKHR = (void *)vkGetDeviceProcAddr(vk_device, "vkWaitSemaphoresKHR"); + + type_info.semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE; + + vr = vkCreateSemaphore(vk_device, &create_info, NULL, &vk_semaphore); + ok(vr == VK_SUCCESS, "got %d\n", vr); + vr = vkCreateSemaphore(vk_device, &create_info, NULL, &vk_semaphore2); + ok(vr == VK_SUCCESS, "got %d\n", vr); + + + find_queue_family(vk_physical_device, VK_QUEUE_GRAPHICS_BIT, &index); + vkGetDeviceQueue(vk_device, index, 0, &vk_queue); + + vr = p_vkGetSemaphoreCounterValueKHR(vk_device, vk_semaphore, &value); + ok(vr == VK_SUCCESS, "got %d\n", vr); + ok(value == 0, "got %#I64x\n", value); + vr = p_vkGetSemaphoreCounterValueKHR(vk_device, vk_semaphore2, &value); + ok(vr == VK_SUCCESS, "got %d\n", vr); + ok(value == 0, "got %#I64x\n", value); + + memset(&submit, 0, sizeof(submit)); + submit.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit.pSignalSemaphores = &vk_semaphore; + submit.signalSemaphoreCount = 1; + submit.pNext = &timeline_info; + memset(&timeline_info, 0, sizeof(timeline_info)); + timeline_info.sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO; + timeline_info.pSignalSemaphoreValues = &signal_value; + timeline_info.signalSemaphoreValueCount = 1; + signal_value = 1; + vr = vkQueueSubmit(vk_queue, 1, &submit, VK_NULL_HANDLE); + ok(vr == VK_SUCCESS, "got %d\n", vr); + + wait_info.pSemaphores = &vk_semaphore; + wait_info.semaphoreCount = 1; + wait_info.pValues = &wait_value; + wait_value = 1; + vr = p_vkWaitSemaphoresKHR(vk_device, &wait_info, 1000 * 1000000); + ok(vr == VK_SUCCESS, "got %d\n", vr); + vr = p_vkGetSemaphoreCounterValueKHR(vk_device, vk_semaphore, &value); + ok(vr == VK_SUCCESS, "got %d\n", vr); + ok(value == 1, "got %#I64x\n", value); + + memset(&submit, 0, sizeof(submit)); + submit.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit.pSignalSemaphores = &vk_semaphore; + submit.signalSemaphoreCount = 1; + submit.pNext = &timeline_info; + memset(&timeline_info, 0, sizeof(timeline_info)); + timeline_info.sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO; + timeline_info.pSignalSemaphoreValues = &signal_value; + timeline_info.signalSemaphoreValueCount = 1; + signal_value = 2; + vr = vkQueueSubmit(vk_queue, 1, &submit, VK_NULL_HANDLE); + ok(vr == VK_SUCCESS, "got %d\n", vr); + + memset(&submit, 0, sizeof(submit)); + submit.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit.pWaitSemaphores = &vk_semaphore; + submit.pWaitDstStageMask = &stage_mask; + submit.waitSemaphoreCount = 1; + submit.pSignalSemaphores = &vk_semaphore2; + submit.signalSemaphoreCount = 1; + submit.pNext = &timeline_info; + memset(&timeline_info, 0, sizeof(timeline_info)); + timeline_info.sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO; + timeline_info.waitSemaphoreValueCount = 1; + timeline_info.pWaitSemaphoreValues = &wait_value; + timeline_info.pSignalSemaphoreValues = &signal_value; + timeline_info.signalSemaphoreValueCount = 1; + signal_value = 1; + wait_value = 3; + vr = vkQueueSubmit(vk_queue, 1, &submit, VK_NULL_HANDLE); + ok(vr == VK_SUCCESS, "got %d\n", vr); + + wait_info.pSemaphores = &vk_semaphore; + wait_info.semaphoreCount = 1; + wait_info.pValues = &wait_value; + wait_value = 2; + vr = p_vkWaitSemaphoresKHR(vk_device, &wait_info, 1000 * 1000000); + ok(vr == VK_SUCCESS, "got %d\n", vr); + vr = p_vkGetSemaphoreCounterValueKHR(vk_device, vk_semaphore, &value); + ok(vr == VK_SUCCESS, "got %d\n", vr); + ok(value == 2, "got %#I64x\n", value); + + wait_info.pSemaphores = &vk_semaphore2; + wait_info.semaphoreCount = 1; + wait_info.pValues = &wait_value; + wait_value = 1; + vr = p_vkWaitSemaphoresKHR(vk_device, &wait_info, 100 * 1000000); + ok(vr == VK_TIMEOUT, "got %d\n", vr); + + signal_info.semaphore = vk_semaphore; + signal_info.value = 3; + vr = p_vkSignalSemaphoreKHR(vk_device, &signal_info); + ok(vr == VK_SUCCESS, "got %d\n", vr); + + wait_info.pSemaphores = &vk_semaphore; + wait_info.semaphoreCount = 1; + wait_info.pValues = &wait_value; + wait_value = 3; + vr = p_vkWaitSemaphoresKHR(vk_device, &wait_info, 1000 * 1000000); + ok(vr == VK_SUCCESS, "got %d\n", vr); + vr = p_vkGetSemaphoreCounterValueKHR(vk_device, vk_semaphore, &value); + ok(vr == VK_SUCCESS, "got %d\n", vr); + ok(value == 3, "got %#I64x\n", value); + + wait_info.pSemaphores = &vk_semaphore2; + wait_info.semaphoreCount = 1; + wait_info.pValues = &wait_value; + wait_value = 1; + vr = p_vkWaitSemaphoresKHR(vk_device, &wait_info, 1000 * 1000000); + ok(vr == VK_SUCCESS, "got %d\n", vr); + vr = p_vkGetSemaphoreCounterValueKHR(vk_device, vk_semaphore2, &value); + ok(vr == VK_SUCCESS, "got %d\n", vr); + ok(value == 1, "got %#I64x\n", value); + + + /* following tests are confusing the vulkan driver on Linux */ + if (winetest_platform_is_wine) goto done; + + + /* large value jumps are allowed */ + + signal_info.semaphore = vk_semaphore; + wait_info.pSemaphores = &vk_semaphore; + wait_info.semaphoreCount = 1; + wait_info.pValues = &wait_value; + + signal_info.value = 4; + vr = p_vkSignalSemaphoreKHR(vk_device, &signal_info); + ok(vr == VK_SUCCESS, "got %d\n", vr); + wait_value = 0x7fffffffffffffffull; + vr = p_vkWaitSemaphoresKHR(vk_device, &wait_info, 100 * 1000000); + ok(vr == VK_TIMEOUT, "got %d\n", vr); + signal_info.value = 0x7fffffffffffffffull; + vr = p_vkSignalSemaphoreKHR(vk_device, &signal_info); + ok(vr == VK_SUCCESS, "got %d\n", vr); + vr = p_vkWaitSemaphoresKHR(vk_device, &wait_info, 100 * 1000000); + ok(vr == VK_SUCCESS, "got %d\n", vr); + vr = p_vkGetSemaphoreCounterValueKHR(vk_device, vk_semaphore, &value); + ok(vr == VK_SUCCESS, "got %d\n", vr); + ok(value == 0x7fffffffffffffffull, "got %#I64x\n", value); + + + /* rewinding on the CPU is allowed */ + + signal_info.semaphore = vk_semaphore; + wait_info.pSemaphores = &vk_semaphore; + wait_info.semaphoreCount = 1; + wait_info.pValues = &wait_value; + + signal_info.value = 1; + vr = p_vkSignalSemaphoreKHR(vk_device, &signal_info); + ok(vr == VK_SUCCESS, "got %d\n", vr); + wait_value = 2; + vr = p_vkWaitSemaphoresKHR(vk_device, &wait_info, 100 * 1000000); + ok(vr == VK_TIMEOUT, "got %d\n", vr); + signal_info.value = 2; + vr = p_vkSignalSemaphoreKHR(vk_device, &signal_info); + ok(vr == VK_SUCCESS, "got %d\n", vr); + vr = p_vkWaitSemaphoresKHR(vk_device, &wait_info, 100 * 1000000); + ok(vr == VK_SUCCESS, "got %d\n", vr); + vr = p_vkGetSemaphoreCounterValueKHR(vk_device, vk_semaphore, &value); + ok(vr == VK_SUCCESS, "got %d\n", vr); + ok(value == 2, "got %#I64x\n", value); + + + /* rewinding on the GPU is allowed */ + + memset(&submit, 0, sizeof(submit)); + submit.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit.pSignalSemaphores = &vk_semaphore; + submit.signalSemaphoreCount = 1; + submit.pNext = &timeline_info; + memset(&timeline_info, 0, sizeof(timeline_info)); + timeline_info.sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO; + timeline_info.pSignalSemaphoreValues = &signal_value; + timeline_info.signalSemaphoreValueCount = 1; + signal_value = 1; + vr = vkCreateFence(vk_device, &fence_info, NULL, &vk_fence); + ok(vr == VK_SUCCESS, "got %d\n", vr); + vr = vkQueueSubmit(vk_queue, 1, &submit, vk_fence); + ok(vr == VK_SUCCESS || broken(vr == VK_ERROR_UNKNOWN) /* AMD */, "got %d\n", vr); + vr = vkWaitForFences(vk_device, 1, &vk_fence, VK_FALSE, 100 * 1000000); + ok(vr == VK_SUCCESS, "got %d\n", vr); + vkDestroyFence(vk_device, vk_fence, NULL); + + memset(&submit, 0, sizeof(submit)); + submit.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit.pWaitSemaphores = &vk_semaphore2; + submit.pWaitDstStageMask = &stage_mask; + submit.waitSemaphoreCount = 1; + submit.pSignalSemaphores = &vk_semaphore; + submit.signalSemaphoreCount = 1; + submit.pNext = &timeline_info; + memset(&timeline_info, 0, sizeof(timeline_info)); + timeline_info.sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO; + timeline_info.pWaitSemaphoreValues = &wait_value; + timeline_info.waitSemaphoreValueCount = 1; + timeline_info.pSignalSemaphoreValues = &signal_value; + timeline_info.signalSemaphoreValueCount = 1; + signal_value = 3; + wait_value = 2; + vr = vkQueueSubmit(vk_queue, 1, &submit, VK_NULL_HANDLE); + ok(vr == VK_SUCCESS, "got %d\n", vr); + + wait_info.pSemaphores = &vk_semaphore; + wait_info.semaphoreCount = 1; + wait_info.pValues = &wait_value; + wait_value = 2; + vr = p_vkWaitSemaphoresKHR(vk_device, &wait_info, 100 * 1000000); + ok(vr == VK_TIMEOUT || broken(vr == VK_SUCCESS) /* AMD */, "got %d\n", vr); + wait_value = 1; + vr = p_vkWaitSemaphoresKHR(vk_device, &wait_info, 100 * 1000000); + ok(vr == VK_SUCCESS, "got %d\n", vr); + vr = p_vkGetSemaphoreCounterValueKHR(vk_device, vk_semaphore, &value); + ok(vr == VK_SUCCESS, "got %d\n", vr); + ok(value == 1 || broken(value == 2) /* AMD */, "got %#I64x\n", value); + signal_info.semaphore = vk_semaphore2; + signal_info.value = 2; + vr = p_vkSignalSemaphoreKHR(vk_device, &signal_info); + ok(vr == VK_SUCCESS, "got %d\n", vr); + wait_value = 3; + vr = p_vkWaitSemaphoresKHR(vk_device, &wait_info, 1000 * 1000000); + ok(vr == VK_SUCCESS, "got %d\n", vr); + vr = p_vkGetSemaphoreCounterValueKHR(vk_device, vk_semaphore, &value); + ok(vr == VK_SUCCESS, "got %d\n", vr); + ok(value == 3, "got %#I64x\n", value); + + +done: + vkDestroySemaphore(vk_device, vk_semaphore, NULL); + vkDestroySemaphore(vk_device, vk_semaphore2, NULL); + vkDestroyDevice(vk_device, NULL); +} + static void for_each_device_instance(uint32_t extension_count, const char * const *enabled_extensions, void (*test_func_instance)(VkInstance, VkPhysicalDevice), void (*test_func)(VkPhysicalDevice)) { @@ -1483,4 +1761,5 @@ START_TEST(vulkan) for_each_device(test_private_data); for_each_device_instance(ARRAY_SIZE(test_win32_surface_extensions), test_win32_surface_extensions, test_win32_surface, NULL); for_each_device_instance(ARRAY_SIZE(test_external_memory_extensions), test_external_memory_extensions, test_external_memory, NULL); + for_each_device_instance(ARRAY_SIZE(test_timeline_semaphore_extensions), test_timeline_semaphore_extensions, test_timeline_semaphore, NULL); }
v2: Tweak expected test failures when no Vulkan driver/GPU is available.
This merge request was approved by Huw Davies.