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
--- 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/win32u/d3dkmt.c | 13 ++++++++++--- dlls/win32u/vulkan.c | 21 +++++++++++++++++++-- dlls/win32u/win32u_private.h | 2 +- 3 files changed, 30 insertions(+), 6 deletions(-)
diff --git a/dlls/win32u/d3dkmt.c b/dlls/win32u/d3dkmt.c index 23640cb39be..d7f1cfd34c5 100644 --- a/dlls/win32u/d3dkmt.c +++ b/dlls/win32u/d3dkmt.c @@ -24,6 +24,7 @@
#include <assert.h> #include <pthread.h> +#include <unistd.h>
#include "ntstatus.h" #define WIN32_NO_STATUS @@ -40,6 +41,7 @@ struct d3dkmt_object D3DKMT_HANDLE global; /* object global handle */ BOOL shared; /* object is shared using nt handles */ HANDLE handle; /* internal handle of the server object */ + int fd; /* host specific object unix fd */ };
struct d3dkmt_resource @@ -174,6 +176,7 @@ static NTSTATUS d3dkmt_object_alloc( UINT size, enum d3dkmt_type type, void **ob
if (!(object = calloc( 1, size ))) return STATUS_NO_MEMORY; object->type = type; + object->fd = -1;
*obj = object; return STATUS_SUCCESS; @@ -272,6 +275,7 @@ static void d3dkmt_object_free( struct d3dkmt_object *object ) TRACE( "object %p/%#x, global %#x\n", object, object->local, object->global ); if (object->local) free_object_handle( object ); if (object->handle) NtClose( object->handle ); + close( object->fd ); free( object ); }
@@ -1668,16 +1672,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, takes ownership of the 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; + resource->obj.fd = fd; + 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;
@@ -1691,6 +1697,7 @@ failed: WARN( "Failed to create resource, status %#x\n", status ); if (allocation) d3dkmt_object_free( allocation ); if (resource) d3dkmt_object_free( &resource->obj ); + else close( fd ); return 0; }
diff --git a/dlls/win32u/vulkan.c b/dlls/win32u/vulkan.c index cb6684fc7f6..508597ae8e9 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,24 @@ 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; + + 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; + }
- if (!memory->local && !(memory->local = d3dkmt_create_resource( nt_shared ? NULL : &memory->global ))) goto failed; + if (!(memory->local = d3dkmt_create_resource( fd, nt_shared ? NULL : &memory->global ))) goto failed; + } if (nt_shared && !(memory->shared = create_shared_resource_handle( memory->local, &export_win32 ))) goto failed; }
@@ -387,6 +403,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 | 44 +++++++++++++++++++++++++++++++++++++++++++- server/protocol.def | 1 + 3 files changed, 47 insertions(+), 1 deletion(-)
diff --git a/dlls/win32u/d3dkmt.c b/dlls/win32u/d3dkmt.c index d7f1cfd34c5..07f135671b2 100644 --- a/dlls/win32u/d3dkmt.c +++ b/dlls/win32u/d3dkmt.c @@ -187,9 +187,12 @@ static NTSTATUS d3dkmt_object_create( struct d3dkmt_object *object, BOOL shared, { NTSTATUS status;
+ if (object->fd >= 0) wine_server_send_fd( object->fd ); + SERVER_START_REQ( d3dkmt_object_create ) { req->type = object->type; + req->fd = object->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..d8899346c70 100644 --- a/server/d3dkmt.c +++ b/server/d3dkmt.c @@ -23,6 +23,7 @@ #include <assert.h> #include <stdbool.h> #include <stdio.h> +#include <unistd.h>
#include "ntstatus.h" #define WIN32_NO_STATUS @@ -42,6 +43,7 @@ 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 ); @@ -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) @@ -312,6 +335,7 @@ static void d3dkmt_object_destroy( struct 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 +347,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 +406,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 | 2 ++ server/d3dkmt.c | 12 +++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/dlls/win32u/d3dkmt.c b/dlls/win32u/d3dkmt.c index 07f135671b2..1113eca9f8e 100644 --- a/dlls/win32u/d3dkmt.c +++ b/dlls/win32u/d3dkmt.c @@ -246,6 +246,8 @@ static NTSTATUS d3dkmt_object_open( struct d3dkmt_object *obj, D3DKMT_HANDLE glo *runtime_size = reply->runtime_size; } SERVER_END_REQ; + + if (status == STATUS_PENDING) status = wine_server_handle_to_fd( obj->handle, GENERIC_ALL, &obj->fd, NULL ); if (!status) status = alloc_object_handle( obj );
if (status) WARN( "Failed to open global object %#x/%p, status %#x\n", global, handle, status ); diff --git a/server/d3dkmt.c b/server/d3dkmt.c index d8899346c70..62c7d7dc380 100644 --- a/server/d3dkmt.c +++ b/server/d3dkmt.c @@ -47,6 +47,7 @@ struct d3dkmt_object };
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 = @@ -59,7 +60,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 */ @@ -329,6 +330,14 @@ 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 ); + + return object->fd ? (struct fd *)grab_object( object->fd ) : NULL; +} + static void d3dkmt_object_destroy( struct object *obj ) { struct d3dkmt_object *object = (struct d3dkmt_object *)obj; @@ -488,6 +497,7 @@ DECL_HANDLER(d3dkmt_object_open) reply->global = object->global; reply->runtime_size = object->runtime_size; if (runtime_size) set_reply_data( object->runtime, object->runtime_size ); + if (object->fd) set_error( STATUS_PENDING ); }
release_object( object );
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/d3dkmt.c | 12 ++++++++++++ dlls/win32u/vulkan.c | 9 +++++++-- dlls/win32u/win32u_private.h | 2 ++ 3 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/dlls/win32u/d3dkmt.c b/dlls/win32u/d3dkmt.c index 1113eca9f8e..6a78f774575 100644 --- a/dlls/win32u/d3dkmt.c +++ b/dlls/win32u/d3dkmt.c @@ -1677,6 +1677,18 @@ 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; + + TRACE( "local %#x\n", local ); + + if (!(object = get_d3dkmt_object( local, -1 ))) return -1; + if (object->fd < 0) return -1; + return dup( object->fd ); +} + /* create a D3DKMT global or shared resource from a host-specific fd, takes ownership of the fd */ D3DKMT_HANDLE d3dkmt_create_resource( int fd, D3DKMT_HANDLE *global ) { diff --git a/dlls/win32u/vulkan.c b/dlls/win32u/vulkan.c index 508597ae8e9..e1b368d0202 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 ); @@ -360,8 +361,12 @@ static VkResult win32u_vkAllocateMemory( VkDevice client_device, const VkMemoryA free( memory ); return VK_ERROR_INVALID_EXTERNAL_HANDLE; } - - FIXME( "Importing memory handle not yet implemented!\n" ); + if ((fd_info.fd = d3dkmt_object_get_fd( memory->local )) >= 0) + { + 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 );
Jacek Caban (@jacek) commented about dlls/win32u/d3dkmt.c:
*runtime_size = reply->runtime_size; } SERVER_END_REQ;
- if (status == STATUS_PENDING) status = wine_server_handle_to_fd( obj->handle, GENERIC_ALL, &obj->fd, NULL );
`STATUS_PENDING` seems weird here. More importantly, do we need to store fd on client side anyway? Could we just call retrieve fd from server in `d3dkmt_object_get_fd` instead?
It's not strictly related and we can take care of it separately, but when external host memory is used for wow64 mapping, the import will not work as intended. I guess we shouldn't advertise the extension in this case. Placed alloc should work fine, so it's not too bad in practice.
On Mon Oct 13 15:57:30 2025 +0000, Jacek Caban wrote:
It's not strictly related and we can take care of it separately, but when external host memory is used for wow64 mapping, the import will not work as intended. I guess we shouldn't advertise the extension in this case. Placed alloc should work fine, so it's not too bad in practice.
I'm not sure to understand, why would importing the fd not work?
On Mon Oct 13 15:57:30 2025 +0000, Rémi Bernon wrote:
I'm not sure to understand, why would importing the fd not work?
Fwiw this sounds like a serious issue, many games require D3D shared resources in video playback, and I think that includes older 32bit games.
On Mon Oct 13 16:20:59 2025 +0000, Rémi Bernon wrote:
Fwiw this sounds like a serious issue, many games require D3D shared resources in video playback, and I think that includes older 32bit games.
I'm not sure what importing from memory and fd at the same time would mean. Also, `allocate_external_host_memory` may change the memory type to something that doesn't support importing/exporting the same way the original one does.
Note that when `VK_EXT_map_memory_placed` is available (which is the case for all recent drivers), this code path is not used and I'd expect your approach to be fine.
On Mon Oct 13 16:37:10 2025 +0000, Jacek Caban wrote:
I'm not sure what importing from memory and fd at the same time would mean. Also, `allocate_external_host_memory` may change the memory type to something that doesn't support importing/exporting the same way the original one does. Note that when `VK_EXT_map_memory_placed` is available (which is the case for all recent drivers), this code path is not used and I'd expect your approach to be fine.
I see, if it's only an issue for some older driver versions then it's probably fine.
(Fwiw I was starting to consider whether D3DKMT resources could manage CPU memory too, through wineserver allocated shared mappings that would be imported as host pointers and mmapped to the 32bit address space)
On Mon Oct 13 16:41:43 2025 +0000, Rémi Bernon wrote:
I see, if it's only an issue for some older driver versions then it's probably fine. (Fwiw I was starting to consider whether D3DKMT resources could manage CPU memory too, through wineserver allocated shared mappings that would be imported as host pointers and mmapped to the 32bit address space)
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