 
            -- v2: win32u: Import vulkan memory from the D3DKMT object fd. win32u: Send D3DKMT object fd to wineserver on creation. win32u: Export host memory unix file descriptor. ntdll: Export wine_server_send_fd to other unix libs. winevulkan: Handle WOW64 conversion of SECURITY_ATTRIBUTES. winevulkan: Require VK_EXT_map_memory_placed for WOW64 memory export. winevulkan: Move physical device extension checks around.
 
            From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winevulkan/vulkan.c | 50 ++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 25 deletions(-)
diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index 04b2085ac9b..b69b6618243 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -398,31 +398,6 @@ static VkResult vulkan_physical_device_init(struct vulkan_physical_device *physi goto err; }
- for (i = 0, j = 0; i < num_host_properties; i++) - { - if (!strcmp(host_properties[i].extensionName, vk_funcs->p_get_host_extension("VK_KHR_external_memory_win32"))) - { - strcpy(physical_device->extensions[j].extensionName, "VK_KHR_external_memory_win32"); - physical_device->extensions[j++].specVersion = VK_KHR_EXTERNAL_MEMORY_WIN32_SPEC_VERSION; - } - else if (!strcmp(host_properties[i].extensionName, vk_funcs->p_get_host_extension("VK_KHR_external_semaphore_win32"))) - { - 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]; - j++; - } - } - physical_device->extension_count = num_properties; - if (zero_bits && have_memory_placed && have_map_memory2) { VkPhysicalDeviceMapMemoryPlacedFeaturesEXT map_placed_feature = @@ -472,6 +447,31 @@ static VkResult vulkan_physical_device_init(struct vulkan_physical_device *physi physical_device->external_memory_align); }
+ for (i = 0, j = 0; i < num_host_properties; i++) + { + if (!strcmp(host_properties[i].extensionName, vk_funcs->p_get_host_extension("VK_KHR_external_memory_win32"))) + { + strcpy(physical_device->extensions[j].extensionName, "VK_KHR_external_memory_win32"); + physical_device->extensions[j++].specVersion = VK_KHR_EXTERNAL_MEMORY_WIN32_SPEC_VERSION; + } + else if (!strcmp(host_properties[i].extensionName, vk_funcs->p_get_host_extension("VK_KHR_external_semaphore_win32"))) + { + 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]; + j++; + } + } + physical_device->extension_count = num_properties; + free(host_properties); return VK_SUCCESS;
 
            From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/tests/d3dkmt.c | 17 +++++++++++++++++ dlls/winevulkan/vulkan.c | 12 +++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-)
diff --git a/dlls/win32u/tests/d3dkmt.c b/dlls/win32u/tests/d3dkmt.c index ba25286642e..2d54a3b57bb 100644 --- a/dlls/win32u/tests/d3dkmt.c +++ b/dlls/win32u/tests/d3dkmt.c @@ -3330,6 +3330,7 @@ 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;
dev = calloc( 1, sizeof(*dev) ); @@ -3395,7 +3396,17 @@ static struct vulkan_device *create_vulkan_device( LUID *luid )
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; + } ok_ptr( dev->device, !=, VK_NULL_HANDLE );
return dev; @@ -4637,36 +4648,42 @@ static void test_shared_resources(void)
case MAKETEST(4, 0, 0): { + if (!vulkan_exp) break; buf = export_vulkan_buffer( vulkan_exp, resource_size, NULL, VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT, &handle ); get_d3dkmt_resource_desc( luid, handle, FALSE, 0, runtime_desc ); break; } case MAKETEST(4, 0, 1): { + if (!vulkan_exp) break; buf = export_vulkan_buffer( vulkan_exp, resource_size, NULL, VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT, &handle ); get_d3dkmt_resource_desc( luid, handle, TRUE, 0, runtime_desc ); break; } case MAKETEST(4, 1, 0): { + if (!vulkan_exp) break; img = export_vulkan_image( vulkan_exp, width_1d, 1, array_1d, NULL, VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT, &handle ); get_d3dkmt_resource_desc( luid, handle, FALSE, 0, runtime_desc ); break; } case MAKETEST(4, 2, 0): { + if (!vulkan_exp) break; img = export_vulkan_image( vulkan_exp, width_2d, height_2d, 1, NULL, VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT, &handle ); get_d3dkmt_resource_desc( luid, handle, FALSE, 0, runtime_desc ); break; } case MAKETEST(4, 2, 1): { + if (!vulkan_exp) break; img = export_vulkan_image( vulkan_exp, width_2d, height_2d, 1, NULL, VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT, &handle ); get_d3dkmt_resource_desc( luid, handle, TRUE, 0, runtime_desc ); break; } case MAKETEST(4, 3, 0): { + if (!vulkan_exp) break; img = export_vulkan_image( vulkan_exp, width_3d, height_3d, depth_3d, NULL, VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT, &handle ); get_d3dkmt_resource_desc( luid, handle, FALSE, 0, runtime_desc ); break; diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index b69b6618243..3ff313e5b83 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -451,6 +451,11 @@ 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"))) { + if (zero_bits && !physical_device->map_placed_align) + { + WARN("Cannot export WOW64 memory without VK_EXT_map_memory_placed\n"); + continue; + } strcpy(physical_device->extensions[j].extensionName, "VK_KHR_external_memory_win32"); physical_device->extensions[j++].specVersion = VK_KHR_EXTERNAL_MEMORY_WIN32_SPEC_VERSION; } @@ -470,7 +475,7 @@ static VkResult vulkan_physical_device_init(struct vulkan_physical_device *physi j++; } } - physical_device->extension_count = num_properties; + physical_device->extension_count = j;
free(host_properties); return VK_SUCCESS; @@ -590,6 +595,11 @@ static VkResult wine_vk_device_convert_create_info(struct vulkan_physical_device if (!strcmp(*extension, "VK_KHR_swapchain")) has_swapchain = true; if (!strcmp(*extension, "VK_KHR_external_memory_win32")) { + if (zero_bits && !physical_device->map_placed_align) + { + FIXME("Cannot export WOW64 memory without VK_EXT_map_memory_placed\n"); + return VK_ERROR_EXTENSION_NOT_PRESENT; + } device->has_external_memory_win32 = true; *extension = vk_funcs->p_get_host_extension("VK_KHR_external_memory_win32"); if (!strcmp(*extension, "VK_EXT_external_memory_dma_buf")) extensions[count++] = "VK_KHR_external_memory_fd";
 
            From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winevulkan/make_vulkan | 3 ++- dlls/winevulkan/vulkan_thunks.c | 38 ++++++++++++++++++++++++++++++--- dlls/winevulkan/winevk.xml | 11 ++++++++++ 3 files changed, 48 insertions(+), 4 deletions(-) create mode 100644 dlls/winevulkan/winevk.xml
diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index 22cca40f15b..48a0134a092 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -2989,7 +2989,7 @@ class VkGenerator(object): # Note: unions are stored in structs for dependency reasons, # see comment in parsing section. for struct in self.registry.structs: - if struct.required: + if struct.required and struct.name != "SECURITY_ATTRIBUTES": LOGGER.debug("Generating struct: {0}".format(struct.name)) f.write(struct.definition(align=True)) f.write("\n") @@ -3128,6 +3128,7 @@ class VkRegistry(object): self.video_copyright = video_root.find('./comment').text
root.extend(video_root) + root.extend(ET.parse("winevk.xml").getroot())
self._parse_enums(root) self._parse_types(root) diff --git a/dlls/winevulkan/vulkan_thunks.c b/dlls/winevulkan/vulkan_thunks.c index f2ceb7b7fed..ba79adb23db 100644 --- a/dlls/winevulkan/vulkan_thunks.c +++ b/dlls/winevulkan/vulkan_thunks.c @@ -578,6 +578,13 @@ typedef struct VkVideoPictureResourceInfoKHR32 VkImageView DECLSPEC_ALIGN(8) imageViewBinding; } VkVideoPictureResourceInfoKHR32;
+typedef struct SECURITY_ATTRIBUTES32 +{ + DWORD nLength; + PTR32 lpSecurityDescriptor; + BOOL bInheritHandle; +} SECURITY_ATTRIBUTES32; + typedef struct StdVideoAV1SequenceHeader32 { StdVideoAV1SequenceHeaderFlags flags; @@ -9958,6 +9965,31 @@ static void convert_VkMemoryAllocateInfo_win64_to_host(struct conversion_context } #endif /* _WIN64 */
+static void convert_SECURITY_ATTRIBUTES_win32_to_host(const SECURITY_ATTRIBUTES32 *in, SECURITY_ATTRIBUTES *out) +{ + if (!in) return; + + out->nLength = in->nLength; + out->lpSecurityDescriptor = UlongToPtr(in->lpSecurityDescriptor); + out->bInheritHandle = in->bInheritHandle; +} + +static const SECURITY_ATTRIBUTES *convert_SECURITY_ATTRIBUTES_array_win32_to_host(struct conversion_context *ctx, const SECURITY_ATTRIBUTES32 *in, uint32_t count) +{ + SECURITY_ATTRIBUTES *out; + unsigned int i; + + if (!in || !count) return NULL; + + out = conversion_context_alloc(ctx, count * sizeof(*out)); + for (i = 0; i < count; i++) + { + convert_SECURITY_ATTRIBUTES_win32_to_host(&in[i], &out[i]); + } + + return out; +} + static void convert_VkMemoryAllocateInfo_win32_to_host(struct conversion_context *ctx, const VkMemoryAllocateInfo32 *in, VkMemoryAllocateInfo *out) { const VkBaseInStructure32 *in_header; @@ -10003,7 +10035,7 @@ static void convert_VkMemoryAllocateInfo_win32_to_host(struct conversion_context const VkExportMemoryWin32HandleInfoKHR32 *in_ext = (const VkExportMemoryWin32HandleInfoKHR32 *)in_header; out_ext->sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR; out_ext->pNext = NULL; - out_ext->pAttributes = UlongToPtr(in_ext->pAttributes); + out_ext->pAttributes = convert_SECURITY_ATTRIBUTES_array_win32_to_host(ctx, (const SECURITY_ATTRIBUTES32 *)UlongToPtr(in_ext->pAttributes), 1); out_ext->dwAccess = in_ext->dwAccess; out_ext->name = (LPCWSTR)UlongToPtr(in_ext->name); out_header->pNext = (void *)out_ext; @@ -22499,7 +22531,7 @@ static void convert_VkFenceCreateInfo_win32_to_host(struct conversion_context *c const VkExportFenceWin32HandleInfoKHR32 *in_ext = (const VkExportFenceWin32HandleInfoKHR32 *)in_header; out_ext->sType = VK_STRUCTURE_TYPE_EXPORT_FENCE_WIN32_HANDLE_INFO_KHR; out_ext->pNext = NULL; - out_ext->pAttributes = UlongToPtr(in_ext->pAttributes); + out_ext->pAttributes = convert_SECURITY_ATTRIBUTES_array_win32_to_host(ctx, (const SECURITY_ATTRIBUTES32 *)UlongToPtr(in_ext->pAttributes), 1); out_ext->dwAccess = in_ext->dwAccess; out_ext->name = (LPCWSTR)UlongToPtr(in_ext->name); out_header->pNext = (void *)out_ext; @@ -26390,7 +26422,7 @@ static void convert_VkSemaphoreCreateInfo_win32_to_host(struct conversion_contex const VkExportSemaphoreWin32HandleInfoKHR32 *in_ext = (const VkExportSemaphoreWin32HandleInfoKHR32 *)in_header; out_ext->sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR; out_ext->pNext = NULL; - out_ext->pAttributes = UlongToPtr(in_ext->pAttributes); + out_ext->pAttributes = convert_SECURITY_ATTRIBUTES_array_win32_to_host(ctx, (const SECURITY_ATTRIBUTES32 *)UlongToPtr(in_ext->pAttributes), 1); out_ext->dwAccess = in_ext->dwAccess; out_ext->name = (LPCWSTR)UlongToPtr(in_ext->name); out_header->pNext = (void *)out_ext; diff --git a/dlls/winevulkan/winevk.xml b/dlls/winevulkan/winevk.xml new file mode 100644 index 00000000000..58421b063e0 --- /dev/null +++ b/dlls/winevulkan/winevk.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="UTF-8"?> +<registry> + <types> + <type requires="windows.h" name="BOOL"/> + <type category="struct" name="SECURITY_ATTRIBUTES"> + <member><type>DWORD</type> <name>nLength</name></member> + <member><type>void</type>* <name>lpSecurityDescriptor</name></member> + <member><type>BOOL</type> <name>bInheritHandle</name></member> + </type> + </types> +</registry>
 
            From: Rémi Bernon rbernon@codeweavers.com
--- dlls/ntdll/unix/server.c | 2 +- dlls/ntdll/unix/unix_private.h | 1 - include/wine/server.h | 1 + 3 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c index ee34c5e9cd8..258a959de72 100644 --- a/dlls/ntdll/unix/server.c +++ b/dlls/ntdll/unix/server.c @@ -939,7 +939,7 @@ unsigned int server_queue_process_apc( HANDLE process, const union apc_call *cal * * Send a file descriptor to the server. */ -void wine_server_send_fd( int fd ) +void CDECL wine_server_send_fd( int fd ) { struct send_fd data; struct msghdr msghdr; diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index 4e7af70bf25..5d374017101 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -233,7 +233,6 @@ extern unsigned int server_queue_process_apc( HANDLE process, const union apc_ca union apc_result *result ); extern int server_get_unix_fd( HANDLE handle, unsigned int wanted_access, int *unix_fd, int *needs_close, enum server_fd_type *type, unsigned int *options ); -extern void wine_server_send_fd( int fd ); extern int wine_server_receive_fd( obj_handle_t *handle ); extern void process_exit_wrapper( int status ) DECLSPEC_NORETURN; extern size_t server_init_process(void); diff --git a/include/wine/server.h b/include/wine/server.h index 458c33c27b5..d982675d603 100644 --- a/include/wine/server.h +++ b/include/wine/server.h @@ -49,6 +49,7 @@ struct __server_request_info struct __server_iovec data[__SERVER_MAX_DATA]; /* request variable size data */ };
+NTSYSAPI void CDECL wine_server_send_fd( int fd ); NTSYSAPI unsigned int CDECL wine_server_call( void *req_ptr ); NTSYSAPI NTSTATUS CDECL wine_server_fd_to_handle( int fd, unsigned int access, unsigned int attributes, HANDLE *handle ); NTSYSAPI NTSTATUS CDECL wine_server_handle_to_fd( HANDLE handle, unsigned int access, int *unix_fd, unsigned int *options );
 
            From: Rémi Bernon rbernon@codeweavers.com
And pass it to D3DKMT creation functions. --- dlls/win32u/d3dkmt.c | 18 +++++++++--------- dlls/win32u/vulkan.c | 24 ++++++++++++++++++++++-- dlls/win32u/win32u_private.h | 2 +- 3 files changed, 32 insertions(+), 12 deletions(-)
diff --git a/dlls/win32u/d3dkmt.c b/dlls/win32u/d3dkmt.c index 23640cb39be..5d6ada3e11d 100644 --- a/dlls/win32u/d3dkmt.c +++ b/dlls/win32u/d3dkmt.c @@ -180,7 +180,7 @@ static NTSTATUS d3dkmt_object_alloc( UINT size, enum d3dkmt_type type, void **ob }
/* create a global D3DKMT object, either with a global handle or later shareable */ -static NTSTATUS d3dkmt_object_create( struct d3dkmt_object *object, BOOL shared, const void *runtime, UINT runtime_size ) +static NTSTATUS d3dkmt_object_create( struct d3dkmt_object *object, int fd, BOOL shared, const void *runtime, UINT runtime_size ) { NTSTATUS status;
@@ -1053,7 +1053,7 @@ NTSTATUS WINAPI NtGdiDdDDICreateAllocation2( D3DKMT_CREATEALLOCATION *params ) if ((status = d3dkmt_object_alloc( sizeof(*allocation), D3DKMT_ALLOCATION, (void **)&allocation ))) goto failed;
if (!params->Flags.CreateShared) status = alloc_object_handle( &resource->obj ); - else status = d3dkmt_object_create( &resource->obj, params->Flags.NtSecuritySharing, + else status = d3dkmt_object_create( &resource->obj, -1, params->Flags.NtSecuritySharing, params->pPrivateRuntimeData, params->PrivateRuntimeDataSize ); if (status) goto failed;
@@ -1372,7 +1372,7 @@ NTSTATUS WINAPI NtGdiDdDDICreateKeyedMutex2( D3DKMT_CREATEKEYEDMUTEX2 *params ) if (!params) return STATUS_INVALID_PARAMETER;
if ((status = d3dkmt_object_alloc( sizeof(*mutex), D3DKMT_MUTEX, (void **)&mutex ))) return status; - if ((status = d3dkmt_object_create( mutex, params->Flags.NtSecuritySharing, + if ((status = d3dkmt_object_create( mutex, -1, params->Flags.NtSecuritySharing, params->pPrivateRuntimeData, params->PrivateRuntimeDataSize ))) goto failed;
@@ -1511,7 +1511,7 @@ NTSTATUS WINAPI NtGdiDdDDICreateSynchronizationObject2( D3DKMT_CREATESYNCHRONIZA
if ((status = d3dkmt_object_alloc( sizeof(*sync), D3DKMT_SYNC, (void **)&sync ))) return status; if (!params->Info.Flags.Shared) status = alloc_object_handle( sync ); - else status = d3dkmt_object_create( sync, params->Info.Flags.NtSecuritySharing, NULL, 0 ); + else status = d3dkmt_object_create( sync, -1, params->Info.Flags.NtSecuritySharing, NULL, 0 ); if (status) goto failed;
if (params->Info.Flags.Shared) params->Info.SharedHandle = sync->shared ? 0 : sync->global; @@ -1668,18 +1668,18 @@ NTSTATUS WINAPI NtGdiDdDDIDestroySynchronizationObject( const D3DKMT_DESTROYSYNC return STATUS_SUCCESS; }
-/* create a D3DKMT global or shared resource */ -D3DKMT_HANDLE d3dkmt_create_resource( D3DKMT_HANDLE *global ) +/* create a D3DKMT global or shared resource from a host-specific fd */ +D3DKMT_HANDLE d3dkmt_create_resource( int fd, D3DKMT_HANDLE *global ) { struct d3dkmt_resource *resource = NULL; struct d3dkmt_object *allocation = NULL; NTSTATUS status;
- TRACE( "global %p\n", global ); + TRACE( "fd %d, global %p\n", fd, global );
if ((status = d3dkmt_object_alloc( sizeof(*resource), D3DKMT_RESOURCE, (void **)&resource ))) goto failed; if ((status = d3dkmt_object_alloc( sizeof(*allocation), D3DKMT_ALLOCATION, (void **)&allocation ))) goto failed; - if ((status = d3dkmt_object_create( &resource->obj, !global, NULL, 0 ))) goto failed; + if ((status = d3dkmt_object_create( &resource->obj, fd, !global, NULL, 0 ))) goto failed;
if ((status = alloc_object_handle( allocation ))) goto failed; resource->allocation = allocation->local; @@ -1744,7 +1744,7 @@ D3DKMT_HANDLE d3dkmt_create_sync( D3DKMT_HANDLE *global ) TRACE( "global %p\n", global );
if ((status = d3dkmt_object_alloc( sizeof(*sync), D3DKMT_SYNC, (void **)&sync ))) goto failed; - if ((status = d3dkmt_object_create( sync, !global, NULL, 0 ))) goto failed; + if ((status = d3dkmt_object_create( sync, -1, !global, NULL, 0 ))) goto failed; if (global) *global = sync->global; return sync->local;
diff --git a/dlls/win32u/vulkan.c b/dlls/win32u/vulkan.c index cb6684fc7f6..7c253af5bff 100644 --- a/dlls/win32u/vulkan.c +++ b/dlls/win32u/vulkan.c @@ -26,6 +26,7 @@
#include <dlfcn.h> #include <pthread.h> +#include <unistd.h>
#include "ntstatus.h" #define WIN32_NO_STATUS @@ -372,9 +373,27 @@ static VkResult win32u_vkAllocateMemory( VkDevice client_device, const VkMemoryA
if (export_info) { - FIXME( "Exporting memory handle not yet implemented!\n" ); + if (!memory->local) + { + VkMemoryGetFdInfoKHR get_fd_info = {.sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR, .memory = host_device_memory}; + int fd = -1;
- if (!memory->local && !(memory->local = d3dkmt_create_resource( nt_shared ? NULL : &memory->global ))) goto failed; + switch ((get_fd_info.handleType = get_host_external_memory_type())) + { + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT: + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT: + if ((res = device->p_vkGetMemoryFdKHR( device->host.device, &get_fd_info, &fd ))) goto failed; + break; + default: + FIXME( "Unsupported handle type %#x\n", get_fd_info.handleType ); + break; + } + + memory->local = d3dkmt_create_resource( fd, nt_shared ? NULL : &memory->global ); + close( fd ); + + if (!memory->local) goto failed; + } if (nt_shared && !(memory->shared = create_shared_resource_handle( memory->local, &export_win32 ))) goto failed; }
@@ -387,6 +406,7 @@ static VkResult win32u_vkAllocateMemory( VkDevice client_device, const VkMemoryA return VK_SUCCESS;
failed: + WARN( "Failed to allocate memory, res %d\n", res ); device->p_vkFreeMemory( device->host.device, host_device_memory, NULL ); if (memory->local) d3dkmt_destroy_resource( memory->local ); free( memory ); diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 6eaa7270b01..8257881ba69 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -205,7 +205,7 @@ extern BOOL get_vulkan_gpus( struct list *gpus ); extern void free_vulkan_gpu( struct vulkan_gpu *gpu ); extern BOOL get_vulkan_uuid_from_luid( const LUID *luid, GUID *uuid );
-extern D3DKMT_HANDLE d3dkmt_create_resource( D3DKMT_HANDLE *global ); +extern D3DKMT_HANDLE d3dkmt_create_resource( int fd, D3DKMT_HANDLE *global ); extern D3DKMT_HANDLE d3dkmt_open_resource( D3DKMT_HANDLE global, HANDLE shared ); extern NTSTATUS d3dkmt_destroy_resource( D3DKMT_HANDLE local );
 
            From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/d3dkmt.c | 3 +++ server/d3dkmt.c | 57 ++++++++++++++++++++++++++++++++++++++++++-- server/protocol.def | 1 + 3 files changed, 59 insertions(+), 2 deletions(-)
diff --git a/dlls/win32u/d3dkmt.c b/dlls/win32u/d3dkmt.c index 5d6ada3e11d..fd9e49b77a0 100644 --- a/dlls/win32u/d3dkmt.c +++ b/dlls/win32u/d3dkmt.c @@ -184,9 +184,12 @@ static NTSTATUS d3dkmt_object_create( struct d3dkmt_object *object, int fd, BOOL { NTSTATUS status;
+ if (fd >= 0) wine_server_send_fd( fd ); + SERVER_START_REQ( d3dkmt_object_create ) { req->type = object->type; + req->fd = fd; if (runtime_size) wine_server_add_data( req, runtime, runtime_size ); status = wine_server_call( req ); object->handle = wine_server_ptr_handle( reply->handle ); diff --git a/server/d3dkmt.c b/server/d3dkmt.c index c253740a7bb..672ff2ce9c1 100644 --- a/server/d3dkmt.c +++ b/server/d3dkmt.c @@ -42,9 +42,11 @@ struct d3dkmt_object d3dkmt_handle_t global; /* object global handle */ void *runtime; /* client runtime data */ data_size_t runtime_size; /* size of client runtime data */ + struct fd *fd; /* fd object for unix fds */ };
static void d3dkmt_object_dump( struct object *obj, int verbose ); +static struct fd *d3dkmt_object_get_fd( struct object *obj ); static void d3dkmt_object_destroy( struct object *obj );
static const struct object_ops d3dkmt_object_ops = @@ -57,7 +59,7 @@ static const struct object_ops d3dkmt_object_ops = NULL, /* signaled */ NULL, /* satisfied */ no_signal, /* signal */ - no_get_fd, /* get_fd */ + d3dkmt_object_get_fd, /* get_fd */ default_get_sync, /* get_sync */ default_map_access, /* map_access */ default_get_sd, /* get_sd */ @@ -72,6 +74,27 @@ static const struct object_ops d3dkmt_object_ops = d3dkmt_object_destroy, /* destroy */ };
+static enum server_fd_type d3dkmt_get_fd_type( struct fd *fd ) +{ + return FD_TYPE_INVALID; +} + +static const struct fd_ops d3dkmt_fd_ops = +{ + default_fd_get_poll_events, /* get_poll_events */ + default_poll_event, /* poll_event */ + d3dkmt_get_fd_type, /* get_fd_type */ + no_fd_read, /* read */ + no_fd_write, /* write */ + no_fd_flush, /* flush */ + no_fd_get_file_info, /* get_file_info */ + no_fd_get_volume_info, /* get_volume_info */ + no_fd_ioctl, /* ioctl */ + default_fd_cancel_async, /* cancel_async */ + no_fd_queue_async, /* queue_async */ + default_fd_reselect_async /* reselect_async */ +}; + #define DXGK_SHARED_SYNC_QUERY_STATE 0x0001 #define DXGK_SHARED_SYNC_MODIFY_STATE 0x0002 #define DXGK_SHARED_SYNC_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3) @@ -306,12 +329,24 @@ static void d3dkmt_object_dump( struct object *obj, int verbose ) fprintf( stderr, "type=%#x global=%#x\n", object->type, object->global ); }
+static struct fd *d3dkmt_object_get_fd( struct object *obj ) +{ + struct d3dkmt_object *object = (struct d3dkmt_object *)obj; + assert( obj->ops == &d3dkmt_object_ops ); + + if (object->fd) return (struct fd *)grab_object( object->fd ); + + set_error( STATUS_NO_SUCH_FILE ); + return NULL; +} + static void d3dkmt_object_destroy( struct object *obj ) { struct d3dkmt_object *object = (struct d3dkmt_object *)obj; assert( obj->ops == &d3dkmt_object_ops );
if (object->global) free_object_handle( object->global ); + if (object->fd) release_object( object->fd ); free( object->runtime ); }
@@ -323,6 +358,7 @@ static struct d3dkmt_object *d3dkmt_object_create( enum d3dkmt_type type, data_s object->type = type; object->global = 0; object->runtime_size = runtime_size; + object->fd = NULL;
if (!(object->runtime = memdup( runtime, runtime_size )) || !(object->global = alloc_object_handle( object ))) @@ -381,11 +417,28 @@ static struct d3dkmt_object *d3dkmt_object_open_shared( obj_handle_t handle, enu DECL_HANDLER(d3dkmt_object_create) { struct d3dkmt_object *object; + struct fd *fd = NULL; + + if (req->fd >= 0) + { + int unix_fd; + if ((unix_fd = thread_get_inflight_fd( current, req->fd )) < 0) return; + if (!(fd = create_anonymous_fd( NULL, unix_fd, NULL, 0 ))) return; + } + + if (!(object = d3dkmt_object_create( req->type, get_req_data_size(), get_req_data() ))) goto done; + if (fd) + { + set_fd_user( fd, &d3dkmt_fd_ops, &object->obj ); + object->fd = (struct fd *)grab_object( fd ); + }
- if (!(object = d3dkmt_object_create( req->type, get_req_data_size(), get_req_data() ))) return; reply->handle = alloc_handle( current->process, object, STANDARD_RIGHTS_ALL, OBJ_INHERIT ); reply->global = object->global; release_object( object ); + +done: + if (fd) release_object( fd ); }
/* update a global d3dkmt object */ diff --git a/server/protocol.def b/server/protocol.def index 87b8730f92a..45fa52858e7 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -4177,6 +4177,7 @@ enum inproc_sync_type /* Create a global d3dkmt object */ @REQ(d3dkmt_object_create) unsigned int type; /* d3dkmt object type */ + int fd; /* host specific fd */ VARARG(runtime,bytes); /* client runtime data */ @REPLY d3dkmt_handle_t global; /* global d3dkmt handle */
 
            From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/d3dkmt.c | 19 +++++++++++++++++++ dlls/win32u/vulkan.c | 7 +++++-- dlls/win32u/win32u_private.h | 2 ++ 3 files changed, 26 insertions(+), 2 deletions(-)
diff --git a/dlls/win32u/d3dkmt.c b/dlls/win32u/d3dkmt.c index fd9e49b77a0..ade74cd1eed 100644 --- a/dlls/win32u/d3dkmt.c +++ b/dlls/win32u/d3dkmt.c @@ -1671,6 +1671,25 @@ NTSTATUS WINAPI NtGdiDdDDIDestroySynchronizationObject( const D3DKMT_DESTROYSYNC return STATUS_SUCCESS; }
+/* get a locally opened D3DKMT object host-specific fd */ +int d3dkmt_object_get_fd( D3DKMT_HANDLE local ) +{ + struct d3dkmt_object *object; + NTSTATUS status; + int fd; + + TRACE( "local %#x\n", local ); + + if (!(object = get_d3dkmt_object( local, -1 ))) return -1; + if ((status = wine_server_handle_to_fd( object->handle, GENERIC_ALL, &fd, NULL ))) + { + WARN( "Failed to receive object %p/%#x fd, status %#x\n", object, local, status ); + return -1; + } + + return fd; +} + /* create a D3DKMT global or shared resource from a host-specific fd */ D3DKMT_HANDLE d3dkmt_create_resource( int fd, D3DKMT_HANDLE *global ) { diff --git a/dlls/win32u/vulkan.c b/dlls/win32u/vulkan.c index 7c253af5bff..fe89ca36707 100644 --- a/dlls/win32u/vulkan.c +++ b/dlls/win32u/vulkan.c @@ -270,6 +270,7 @@ static HANDLE open_shared_resource_from_name( const WCHAR *name ) static VkResult win32u_vkAllocateMemory( VkDevice client_device, const VkMemoryAllocateInfo *client_alloc_info, const VkAllocationCallbacks *allocator, VkDeviceMemory *ret ) { + VkImportMemoryFdInfoKHR fd_info = {.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR}; VkMemoryAllocateInfo *alloc_info = (VkMemoryAllocateInfo *)client_alloc_info; /* cast away const, chain has been copied in the thunks */ VkBaseOutStructure **next, *prev = (VkBaseOutStructure *)alloc_info; struct vulkan_device *device = vulkan_device_from_handle( client_device ); @@ -355,13 +356,15 @@ static VkResult win32u_vkAllocateMemory( VkDevice client_device, const VkMemoryA break; }
- if (!memory->local) + if ((fd_info.fd = d3dkmt_object_get_fd( memory->local )) < 0) { free( memory ); return VK_ERROR_INVALID_EXTERNAL_HANDLE; }
- FIXME( "Importing memory handle not yet implemented!\n" ); + fd_info.handleType = get_host_external_memory_type(); + fd_info.pNext = alloc_info->pNext; + alloc_info->pNext = &fd_info; }
if ((res = device->p_vkAllocateMemory( device->host.device, alloc_info, NULL, &host_device_memory ))) diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 8257881ba69..fff97511292 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -205,6 +205,8 @@ extern BOOL get_vulkan_gpus( struct list *gpus ); extern void free_vulkan_gpu( struct vulkan_gpu *gpu ); extern BOOL get_vulkan_uuid_from_luid( const LUID *luid, GUID *uuid );
+extern int d3dkmt_object_get_fd( D3DKMT_HANDLE local ); + extern D3DKMT_HANDLE d3dkmt_create_resource( int fd, D3DKMT_HANDLE *global ); extern D3DKMT_HANDLE d3dkmt_open_resource( D3DKMT_HANDLE global, HANDLE shared ); extern NTSTATUS d3dkmt_destroy_resource( D3DKMT_HANDLE local );
 
            On Mon Oct 13 19:40:33 2025 +0000, Rémi Bernon wrote:
changed this line in [version 2 of the diff](/wine/wine/-/merge_requests/9166/diffs?diff_id=216237&start_sha=8c2b5157cacaa70f679de58e4d267683208e9b05#088bf0bfc689b10bf8f4d5be0a2a598b65cb6e95_250_246)
Right, I got confused by `wine_server_handle_to_fd` getting stuck if the object had no fd, but it's just a matter of setting an error status. I've changed it to only keep the fd on the server side. Note that in theory D3DKMT object could also be local only, but we don't really need that.
 
            On Mon Oct 13 17:33:41 2025 +0000, Rémi Bernon wrote:
Actually I see now that it fails on WOW64 with llvmpipe and some local changes, we fail to export fd if memory was allocated from host memory... Hmm
I've disabled the extension on WOW64 without placed memory, as it fails otherwise in local tests with the new version of the code.
I think there's perhaps some way to make it work by using shared mappings and importing host pointers instead of fds, but that's perhaps unnecessary if we plan to use placed memory mapping instead. Hopefully just a matter of time until it lands in llvmpipe.
 
            This merge request was approved by Jacek Caban.
 
            On Mon Oct 13 19:44:09 2025 +0000, Rémi Bernon wrote:
I've disabled the extension on WOW64 without placed memory, as it fails otherwise in local tests with the new version of the code (we were previously generally ignoring fd sharing errors). I think there's perhaps some way to make it work by using shared mappings and importing host pointers instead of fds, but that's perhaps unnecessary if we plan to use placed memory mapping instead. Hopefully just a matter of time until it lands in llvmpipe.
Right, llvmpipe doesn’t support placed memory yet, that’s unfortunate. And yeah, we could try harder to emulate that if we had to, but it probably wouldn’t be pleasant.


