From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/vulkan.c | 1 + dlls/winevulkan/vulkan.c | 16 ++++++++++++++++ dlls/winevulkan/vulkan_private.h | 1 + dlls/winewayland.drv/vulkan.c | 1 + dlls/winex11.drv/vulkan.c | 1 + 5 files changed, 20 insertions(+)
diff --git a/dlls/win32u/vulkan.c b/dlls/win32u/vulkan.c index 877091cd590..8f168fd2e07 100644 --- a/dlls/win32u/vulkan.c +++ b/dlls/win32u/vulkan.c @@ -1745,6 +1745,7 @@ static const char *nulldrv_get_host_extension( const char *name ) if (!strcmp( name, "VK_KHR_win32_surface" )) return "VK_EXT_headless_surface"; if (!strcmp( name, "VK_KHR_external_memory_win32" )) return "VK_KHR_external_memory_fd"; if (!strcmp( name, "VK_KHR_external_semaphore_win32" )) return "VK_KHR_external_semaphore_fd"; + if (!strcmp( name, "VK_KHR_external_fence_win32" )) return "VK_KHR_external_fence_fd"; return name; }
diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index 71785d97ca5..04b2085ac9b 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -368,6 +368,7 @@ static VkResult vulkan_physical_device_init(struct vulkan_physical_device *physi { if (!strcmp(host_properties[i].extensionName, vk_funcs->p_get_host_extension("VK_KHR_external_memory_win32")) || !strcmp(host_properties[i].extensionName, vk_funcs->p_get_host_extension("VK_KHR_external_semaphore_win32")) + || !strcmp(host_properties[i].extensionName, vk_funcs->p_get_host_extension("VK_KHR_external_fence_win32")) || wine_vk_device_extension_supported(host_properties[i].extensionName)) { TRACE("Enabling extension '%s' for physical device %p\n", host_properties[i].extensionName, physical_device); @@ -409,6 +410,11 @@ static VkResult vulkan_physical_device_init(struct vulkan_physical_device *physi strcpy(physical_device->extensions[j].extensionName, "VK_KHR_external_semaphore_win32"); physical_device->extensions[j++].specVersion = VK_KHR_EXTERNAL_SEMAPHORE_WIN32_SPEC_VERSION; } + else if (!strcmp(host_properties[i].extensionName, vk_funcs->p_get_host_extension("VK_KHR_external_fence_win32"))) + { + strcpy(physical_device->extensions[j].extensionName, "VK_KHR_external_fence_win32"); + physical_device->extensions[j++].specVersion = VK_KHR_EXTERNAL_FENCE_WIN32_SPEC_VERSION; + } else if (wine_vk_device_extension_supported(host_properties[i].extensionName)) { physical_device->extensions[j] = host_properties[i]; @@ -593,6 +599,11 @@ static VkResult wine_vk_device_convert_create_info(struct vulkan_physical_device device->has_external_semaphore_win32 = true; *extension = vk_funcs->p_get_host_extension("VK_KHR_external_semaphore_win32"); } + if (!strcmp(*extension, "VK_KHR_external_fence_win32")) + { + device->has_external_fence_win32 = true; + *extension = vk_funcs->p_get_host_extension("VK_KHR_external_fence_win32"); + } }
if (physical_device->map_placed_align) @@ -1798,6 +1809,11 @@ static NTSTATUS is_available_device_function(VkDevice handle, const char *name) if (!strcmp(name, "vkImportSemaphoreWin32HandleKHR")) return device->has_external_semaphore_win32;
+ if (!strcmp(name, "vkGetFenceWin32HandleKHR")) + return device->has_external_fence_win32; + if (!strcmp(name, "vkImportFenceWin32HandleKHR")) + return device->has_external_fence_win32; + return !!vk_funcs->p_vkGetDeviceProcAddr(device->obj.host.device, name); }
diff --git a/dlls/winevulkan/vulkan_private.h b/dlls/winevulkan/vulkan_private.h index 37aae0ca004..2324e6f8639 100644 --- a/dlls/winevulkan/vulkan_private.h +++ b/dlls/winevulkan/vulkan_private.h @@ -43,6 +43,7 @@ struct wine_device struct vulkan_device obj; bool has_external_memory_win32; bool has_external_semaphore_win32; + bool has_external_fence_win32; uint64_t queue_count; struct wine_queue queues[]; }; diff --git a/dlls/winewayland.drv/vulkan.c b/dlls/winewayland.drv/vulkan.c index b70d2636df3..9a70c90447d 100644 --- a/dlls/winewayland.drv/vulkan.c +++ b/dlls/winewayland.drv/vulkan.c @@ -86,6 +86,7 @@ static const char *wayland_get_host_extension(const char *name) if (!strcmp( name, "VK_KHR_win32_surface" )) return "VK_KHR_wayland_surface"; if (!strcmp( name, "VK_KHR_external_memory_win32" )) return "VK_KHR_external_memory_fd"; if (!strcmp( name, "VK_KHR_external_semaphore_win32" )) return "VK_KHR_external_semaphore_fd"; + if (!strcmp( name, "VK_KHR_external_fence_win32" )) return "VK_KHR_external_fence_fd"; return name; }
diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c index a3277bb999b..bb4f5c45eec 100644 --- a/dlls/winex11.drv/vulkan.c +++ b/dlls/winex11.drv/vulkan.c @@ -83,6 +83,7 @@ static const char *X11DRV_get_host_extension( const char *name ) if (!strcmp( name, "VK_KHR_win32_surface" )) return "VK_KHR_xlib_surface"; if (!strcmp( name, "VK_KHR_external_memory_win32" )) return "VK_KHR_external_memory_fd"; if (!strcmp( name, "VK_KHR_external_semaphore_win32" )) return "VK_KHR_external_semaphore_fd"; + if (!strcmp( name, "VK_KHR_external_fence_win32" )) return "VK_KHR_external_fence_fd"; return name; }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/vulkan.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-)
diff --git a/dlls/win32u/vulkan.c b/dlls/win32u/vulkan.c index 8f168fd2e07..9ce21a4c820 100644 --- a/dlls/win32u/vulkan.c +++ b/dlls/win32u/vulkan.c @@ -55,6 +55,8 @@ static const UINT EXTERNAL_MEMORY_WIN32_BITS = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OP static const UINT EXTERNAL_SEMAPHORE_WIN32_BITS = 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; +static const UINT EXTERNAL_FENCE_WIN32_BITS = VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT | + VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT;
struct device_memory { @@ -203,6 +205,14 @@ static VkExternalSemaphoreHandleTypeFlagBits get_host_external_semaphore_type(vo return 0; }
+static VkExternalFenceHandleTypeFlagBits get_host_external_fence_type(void) +{ + const char *host_extension = driver_funcs->p_get_host_extension( "VK_KHR_external_fence_win32" ); + if (!strcmp( host_extension, "VK_KHR_external_fence_fd" )) return VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT; + if (!strcmp( host_extension, "VK_KHR_external_fence_capabilities" )) return VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT; + return 0; +} + static void init_shared_resource_path( const WCHAR *name, UNICODE_STRING *str ) { UINT len = wcslen( name ); @@ -1653,15 +1663,22 @@ static VkResult win32u_vkImportFenceWin32HandleKHR( VkDevice client_device, cons return VK_ERROR_INCOMPATIBLE_DRIVER; }
-static void win32u_vkGetPhysicalDeviceExternalFenceProperties( VkPhysicalDevice client_physical_device, const VkPhysicalDeviceExternalFenceInfo *fence_info, +static void win32u_vkGetPhysicalDeviceExternalFenceProperties( VkPhysicalDevice client_physical_device, const VkPhysicalDeviceExternalFenceInfo *client_fence_info, VkExternalFenceProperties *fence_properties ) { + VkPhysicalDeviceExternalFenceInfo *fence_info = (VkPhysicalDeviceExternalFenceInfo *)client_fence_info; /* cast away const, it has been copied in the thunks */ struct vulkan_physical_device *physical_device = vulkan_physical_device_from_handle( client_physical_device ); struct vulkan_instance *instance = physical_device->instance; + VkExternalFenceHandleTypeFlagBits handle_type;
TRACE( "physical_device %p, fence_info %p, fence_properties %p\n", physical_device, fence_info, fence_properties );
+ handle_type = fence_info->handleType; + if (fence_info->handleType & EXTERNAL_FENCE_WIN32_BITS) fence_info->handleType = get_host_external_fence_type(); + instance->p_vkGetPhysicalDeviceExternalFenceProperties( physical_device->host.physical_device, fence_info, fence_properties ); + fence_properties->compatibleHandleTypes = handle_type; + fence_properties->exportFromImportedHandleTypes = handle_type; }
static const char *win32u_get_host_extension( const char *name )
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/vulkan.c | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-)
diff --git a/dlls/win32u/vulkan.c b/dlls/win32u/vulkan.c index 9ce21a4c820..179ebd84be8 100644 --- a/dlls/win32u/vulkan.c +++ b/dlls/win32u/vulkan.c @@ -118,6 +118,8 @@ static struct semaphore *semaphore_from_handle( VkSemaphore handle ) struct fence { struct vulkan_fence obj; + D3DKMT_HANDLE local; + D3DKMT_HANDLE global; };
static struct fence *fence_from_handle( VkFence handle ) @@ -1592,6 +1594,7 @@ static VkResult win32u_vkCreateFence( VkDevice client_device, const VkFenceCreat struct vulkan_device *device = vulkan_device_from_handle( client_device ); VkBaseOutStructure **next, *prev = (VkBaseOutStructure *)create_info; struct vulkan_instance *instance = device->physical_device->instance; + VkExportFenceCreateInfoKHR *export_info = NULL; struct fence *fence; VkFence host_fence; VkResult res; @@ -1603,7 +1606,11 @@ static VkResult win32u_vkCreateFence( VkDevice client_device, const VkFenceCreat switch ((*next)->sType) { case VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO: - FIXME( "VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO not implemented.\n" ); + export_info = (VkExportFenceCreateInfoKHR *)*next; + if (!(export_info->handleTypes & EXTERNAL_FENCE_WIN32_BITS)) + FIXME( "Unsupported handle types %#x\n", export_info->handleTypes ); + else + export_info->handleTypes = get_host_external_fence_type(); *next = (*next)->pNext; next = &prev; break; case VK_STRUCTURE_TYPE_EXPORT_FENCE_WIN32_HANDLE_INFO_KHR: @@ -1622,11 +1629,24 @@ static VkResult win32u_vkCreateFence( VkDevice client_device, const VkFenceCreat return res; }
+ if (export_info) + { + FIXME( "Exporting fence handle not yet implemented!\n" ); + + if (!(fence->local = d3dkmt_create_sync( &fence->global ))) goto failed; + } + vulkan_object_init( &fence->obj.obj, host_fence ); instance->p_insert_object( instance, &fence->obj.obj );
*ret = fence->obj.client.fence; return res; + +failed: + device->p_vkDestroyFence( device->host.device, host_fence, NULL ); + if (fence->local) d3dkmt_destroy_sync( fence->local ); + free( fence ); + return VK_ERROR_OUT_OF_HOST_MEMORY; }
static void win32u_vkDestroyFence( VkDevice client_device, VkFence client_fence, const VkAllocationCallbacks *allocator ) @@ -1642,16 +1662,28 @@ static void win32u_vkDestroyFence( VkDevice client_device, VkFence client_fence, device->p_vkDestroyFence( device->host.device, fence->obj.host.fence, NULL /* allocator */ ); instance->p_remove_object( instance, &fence->obj.obj );
+ if (fence->local) d3dkmt_destroy_sync( fence->local ); free( fence ); }
static VkResult win32u_vkGetFenceWin32HandleKHR( VkDevice client_device, const VkFenceGetWin32HandleInfoKHR *handle_info, HANDLE *handle ) { struct vulkan_device *device = vulkan_device_from_handle( client_device ); + struct fence *fence = fence_from_handle( handle_info->fence );
- FIXME( "device %p, handle_info %p, handle %p stub!\n", device, handle_info, handle ); + TRACE( "device %p, handle_info %p, handle %p\n", device, handle_info, handle );
- return VK_ERROR_INCOMPATIBLE_DRIVER; + switch (handle_info->handleType) + { + case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT: + TRACE( "Returning global D3DKMT handle %#x\n", fence->global ); + *handle = UlongToPtr( fence->global ); + return VK_SUCCESS; + + default: + FIXME( "Unsupported handle type %#x\n", handle_info->handleType ); + return VK_ERROR_INCOMPATIBLE_DRIVER; + } }
static VkResult win32u_vkImportFenceWin32HandleKHR( VkDevice client_device, const VkImportFenceWin32HandleInfoKHR *handle_info )
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/vulkan.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-)
diff --git a/dlls/win32u/vulkan.c b/dlls/win32u/vulkan.c index 179ebd84be8..07d9b9a1b78 100644 --- a/dlls/win32u/vulkan.c +++ b/dlls/win32u/vulkan.c @@ -1689,10 +1689,36 @@ static VkResult win32u_vkGetFenceWin32HandleKHR( VkDevice client_device, const V static VkResult win32u_vkImportFenceWin32HandleKHR( VkDevice client_device, const VkImportFenceWin32HandleInfoKHR *handle_info ) { struct vulkan_device *device = vulkan_device_from_handle( client_device ); + struct fence *fence = fence_from_handle( handle_info->fence ); + D3DKMT_HANDLE local, global = 0;
- FIXME( "device %p, handle_info %p stub!\n", device, handle_info ); + TRACE( "device %p, handle_info %p\n", device, handle_info );
- return VK_ERROR_INCOMPATIBLE_DRIVER; + switch (handle_info->handleType) + { + case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT: + global = PtrToUlong( handle_info->handle ); + if (!(local = d3dkmt_open_sync( global, NULL ))) return VK_ERROR_INVALID_EXTERNAL_HANDLE; + break; + default: + FIXME( "Unsupported handle type %#x\n", handle_info->handleType ); + return VK_ERROR_INVALID_EXTERNAL_HANDLE; + } + + FIXME( "Importing memory handle not yet implemented!\n" ); + + if (handle_info->flags & VK_FENCE_IMPORT_TEMPORARY_BIT) + { + /* FIXME: Should we still keep the temporary handles for vkGetFenceWin32HandleKHR? */ + d3dkmt_destroy_sync( local ); + } + else + { + if (fence->local) d3dkmt_destroy_sync( fence->local ); + fence->global = global; + fence->local = local; + } + return VK_SUCCESS; }
static void win32u_vkGetPhysicalDeviceExternalFenceProperties( VkPhysicalDevice client_physical_device, const VkPhysicalDeviceExternalFenceInfo *client_fence_info,
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/vulkan.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-)
diff --git a/dlls/win32u/vulkan.c b/dlls/win32u/vulkan.c index 07d9b9a1b78..cd811405c1f 100644 --- a/dlls/win32u/vulkan.c +++ b/dlls/win32u/vulkan.c @@ -120,6 +120,7 @@ struct fence struct vulkan_fence obj; D3DKMT_HANDLE local; D3DKMT_HANDLE global; + HANDLE shared; };
static struct fence *fence_from_handle( VkFence handle ) @@ -1592,9 +1593,11 @@ static VkResult win32u_vkCreateFence( VkDevice client_device, const VkFenceCreat { VkFenceCreateInfo *create_info = (VkFenceCreateInfo *)client_create_info; /* cast away const, chain has been copied in the thunks */ struct vulkan_device *device = vulkan_device_from_handle( client_device ); + VkExportSemaphoreWin32HandleInfoKHR export_win32 = {.dwAccess = GENERIC_ALL}; VkBaseOutStructure **next, *prev = (VkBaseOutStructure *)create_info; struct vulkan_instance *instance = device->physical_device->instance; VkExportFenceCreateInfoKHR *export_info = NULL; + BOOL nt_shared = FALSE; struct fence *fence; VkFence host_fence; VkResult res; @@ -1610,13 +1613,21 @@ static VkResult win32u_vkCreateFence( VkDevice client_device, const VkFenceCreat if (!(export_info->handleTypes & EXTERNAL_FENCE_WIN32_BITS)) FIXME( "Unsupported handle types %#x\n", export_info->handleTypes ); else + { + nt_shared = !(export_info->handleTypes & VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT); export_info->handleTypes = get_host_external_fence_type(); + } *next = (*next)->pNext; next = &prev; break; case VK_STRUCTURE_TYPE_EXPORT_FENCE_WIN32_HANDLE_INFO_KHR: - FIXME( "VK_STRUCTURE_TYPE_EXPORT_FENCE_WIN32_HANDLE_INFO_KHR not implemented.\n" ); + { + VkExportFenceWin32HandleInfoKHR *fence_win32 = (VkExportFenceWin32HandleInfoKHR *)*next; + export_win32.pAttributes = fence_win32->pAttributes; + export_win32.dwAccess = fence_win32->dwAccess; + export_win32.name = fence_win32->name; *next = (*next)->pNext; next = &prev; break; + } default: FIXME( "Unhandled sType %u.\n", (*next)->sType ); break; } } @@ -1633,7 +1644,8 @@ static VkResult win32u_vkCreateFence( VkDevice client_device, const VkFenceCreat { FIXME( "Exporting fence handle not yet implemented!\n" );
- if (!(fence->local = d3dkmt_create_sync( &fence->global ))) goto failed; + if (!(fence->local = d3dkmt_create_sync( nt_shared ? NULL : &fence->global ))) goto failed; + if (nt_shared && !(fence->shared = create_shared_semaphore_handle( fence->local, &export_win32 ))) goto failed; }
vulkan_object_init( &fence->obj.obj, host_fence ); @@ -1662,6 +1674,7 @@ static void win32u_vkDestroyFence( VkDevice client_device, VkFence client_fence, device->p_vkDestroyFence( device->host.device, fence->obj.host.fence, NULL /* allocator */ ); instance->p_remove_object( instance, &fence->obj.obj );
+ if (fence->shared) NtClose( fence->shared ); if (fence->local) d3dkmt_destroy_sync( fence->local ); free( fence ); } @@ -1680,6 +1693,11 @@ static VkResult win32u_vkGetFenceWin32HandleKHR( VkDevice client_device, const V *handle = UlongToPtr( fence->global ); return VK_SUCCESS;
+ case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT: + NtDuplicateObject( NtCurrentProcess(), fence->shared, NtCurrentProcess(), handle, 0, 0, DUPLICATE_SAME_ATTRIBUTES | DUPLICATE_SAME_ACCESS ); + TRACE( "Returning NT shared handle %p -> %p\n", fence->shared, *handle ); + return VK_SUCCESS; + default: FIXME( "Unsupported handle type %#x\n", handle_info->handleType ); return VK_ERROR_INCOMPATIBLE_DRIVER;
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/vulkan.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
diff --git a/dlls/win32u/vulkan.c b/dlls/win32u/vulkan.c index cd811405c1f..47f8a679db7 100644 --- a/dlls/win32u/vulkan.c +++ b/dlls/win32u/vulkan.c @@ -1709,6 +1709,7 @@ static VkResult win32u_vkImportFenceWin32HandleKHR( VkDevice client_device, cons struct vulkan_device *device = vulkan_device_from_handle( client_device ); struct fence *fence = fence_from_handle( handle_info->fence ); D3DKMT_HANDLE local, global = 0; + HANDLE shared = NULL;
TRACE( "device %p, handle_info %p\n", device, handle_info );
@@ -1718,6 +1719,17 @@ static VkResult win32u_vkImportFenceWin32HandleKHR( VkDevice client_device, cons global = PtrToUlong( handle_info->handle ); if (!(local = d3dkmt_open_sync( global, NULL ))) return VK_ERROR_INVALID_EXTERNAL_HANDLE; break; + case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT: + if (!(shared = handle_info->handle) || NtDuplicateObject( NtCurrentProcess(), shared, NtCurrentProcess(), &shared, + 0, 0, DUPLICATE_SAME_ATTRIBUTES | DUPLICATE_SAME_ACCESS )) + return VK_ERROR_INVALID_EXTERNAL_HANDLE; + + if (!(local = d3dkmt_open_sync( 0, shared ))) + { + NtClose( shared ); + return VK_ERROR_INVALID_EXTERNAL_HANDLE; + } + break; default: FIXME( "Unsupported handle type %#x\n", handle_info->handleType ); return VK_ERROR_INVALID_EXTERNAL_HANDLE; @@ -1728,11 +1740,14 @@ static VkResult win32u_vkImportFenceWin32HandleKHR( VkDevice client_device, cons if (handle_info->flags & VK_FENCE_IMPORT_TEMPORARY_BIT) { /* FIXME: Should we still keep the temporary handles for vkGetFenceWin32HandleKHR? */ + if (shared) NtClose( shared ); d3dkmt_destroy_sync( local ); } else { + if (fence->shared) NtClose( fence->shared ); if (fence->local) d3dkmt_destroy_sync( fence->local ); + fence->shared = shared; fence->global = global; fence->local = local; }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/vulkan.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/dlls/win32u/vulkan.c b/dlls/win32u/vulkan.c index 47f8a679db7..b8637d93757 100644 --- a/dlls/win32u/vulkan.c +++ b/dlls/win32u/vulkan.c @@ -1720,8 +1720,10 @@ static VkResult win32u_vkImportFenceWin32HandleKHR( VkDevice client_device, cons if (!(local = d3dkmt_open_sync( global, NULL ))) return VK_ERROR_INVALID_EXTERNAL_HANDLE; break; case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT: - if (!(shared = handle_info->handle) || NtDuplicateObject( NtCurrentProcess(), shared, NtCurrentProcess(), &shared, - 0, 0, DUPLICATE_SAME_ATTRIBUTES | DUPLICATE_SAME_ACCESS )) + if (handle_info->name && !(shared = open_shared_semaphore_from_name( handle_info->name ))) + return VK_ERROR_INVALID_EXTERNAL_HANDLE; + else if (!(shared = handle_info->handle) || NtDuplicateObject( NtCurrentProcess(), shared, NtCurrentProcess(), &shared, + 0, 0, DUPLICATE_SAME_ATTRIBUTES | DUPLICATE_SAME_ACCESS )) return VK_ERROR_INVALID_EXTERNAL_HANDLE;
if (!(local = d3dkmt_open_sync( 0, shared )))