This patchset adds support for Vulkan shared memory in wine, which can in turn be used by API layers like DXVK or D9VK to support D3D shared resources. The final commit in the patchset adds a wine extension allowing layers to associate a custom struct describing a resource, so that they can recreate it with no outside information. In the case of DXVK and D3D11 shared resources, this is a D3D11_COMMON_TEXTURE_DESC.
While this is the simplest solution, it may be a better idea to define a standard structure/s, so that interop between i.e. DXVK and vkd3d would be possible.
Keep in mind that this functionality may also be used for resources other than textures/surfaces, like synchronization primtives.
Derek Lesho (4): server: Implement GPU Resource object type. ntdll: Add custom helpers for interfacing with GPU Resource objects. winevulkan: Add support for VK_KHR_external_memory_fd. server,ntdll: Allow storage of API data inside of GPU Resource objects.
dlls/ntdll/Makefile.in | 1 + dlls/ntdll/gpu_resource.c | 128 ++++++++++++ dlls/ntdll/ntdll.spec | 6 + dlls/winevulkan/make_vulkan | 11 +- dlls/winevulkan/vulkan.c | 336 +++++++++++++++++++++++++++++- dlls/winevulkan/vulkan_private.h | 26 +++ server/Makefile.in | 1 + server/gpu_resource.c | 339 +++++++++++++++++++++++++++++++ server/protocol.def | 41 ++++ 9 files changed, 878 insertions(+), 11 deletions(-) create mode 100644 dlls/ntdll/gpu_resource.c create mode 100644 server/gpu_resource.c
Signed-off-by: Derek Lesho dlesho@codeweavers.com --- server/Makefile.in | 1 + server/gpu_resource.c | 298 ++++++++++++++++++++++++++++++++++++++++++ server/protocol.def | 34 +++++ 3 files changed, 333 insertions(+) create mode 100644 server/gpu_resource.c
diff --git a/server/Makefile.in b/server/Makefile.in index b39bd30305..bc11d5483e 100644 --- a/server/Makefile.in +++ b/server/Makefile.in @@ -14,6 +14,7 @@ C_SRCS = \ event.c \ fd.c \ file.c \ + gpu_resource.c \ handle.c \ hook.c \ mach.c \ diff --git a/server/gpu_resource.c b/server/gpu_resource.c new file mode 100644 index 0000000000..bc083a2f42 --- /dev/null +++ b/server/gpu_resource.c @@ -0,0 +1,298 @@ +#include "config.h" +#include "wine/port.h" + +#include <assert.h> +#include <stdio.h> + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "wine/unicode.h" +#include "windef.h" +#include "winternl.h" +#include "dxgi1_2.h" + +#include "object.h" +#include "file.h" +#include "handle.h" +#include "request.h" + +struct gpu_resource +{ + struct object obj; + struct list kernel_object; + struct fd *fd; + obj_handle_t kmt_handle; /* more like an ID */ +}; + +/* gpu_resource functions */ +static void gpu_resource_dump( struct object*, int verbose ); +static struct object_type *gpu_resource_get_type( struct object *obj ); +static struct fd *gpu_resource_get_fd( struct object *obj ); +static unsigned int gpu_resource_map_access( struct object *obj, unsigned int access ); +static void gpu_resource_destroy( struct object *obj); +static enum server_fd_type gpu_resource_get_fd_type( struct fd *fd ); + +static const struct object_ops gpu_resource_ops = +{ + sizeof(struct gpu_resource), /* size */ + gpu_resource_dump, /* dump */ + gpu_resource_get_type, /* get_type */ + no_add_queue, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ + NULL, /* satisfied */ + no_signal, /* signal */ + gpu_resource_get_fd, /* get_fd */ + gpu_resource_map_access, /* map_access */ + default_get_sd, /* get_sd */ + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + directory_link_name, /* link_name */ + default_unlink_name, /* unlink_name */ + no_open_file, /* no_open_file */ + no_kernel_obj_list, /* no_kernel_obj_list */ + fd_close_handle, /* close_handle */ + gpu_resource_destroy /* destroy */ +}; + +static const struct fd_ops gpu_resource_fd_ops = +{ + NULL, /* get_poll_events */ + NULL, /* poll_event */ + gpu_resource_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 */ + no_fd_queue_async, /* queue_async */ + NULL /* reselect_async */ +}; + +static void gpu_resource_destroy( struct object *obj ) +{ + struct gpu_resource *resource = (struct gpu_resource *) obj; + assert( obj->ops == &gpu_resource_ops ); + + assert( resource->fd ); + + release_object( resource->fd ); +} + +static void gpu_resource_dump( struct object *obj, int verbose ) +{ + struct gpu_resource *resource = (struct gpu_resource *) obj; + assert( obj->ops == &gpu_resource_ops ); + fprintf( stderr, "GPU-Resource fd=%p", resource->fd ); +} + +static struct object_type *gpu_resource_get_type( struct object *obj ) +{ + static const WCHAR name[] = {'D','x','g','k','S','h','a','r','e','d','R','e','s','o','u','r','c','e'}; + static const struct unicode_str str = {name, sizeof(name) }; + return get_object_type( &str ); +} + +static struct fd *gpu_resource_get_fd( struct object *obj ) +{ + struct gpu_resource *resource = (struct gpu_resource *) obj; + assert( obj->ops == &gpu_resource_ops ); + return (struct fd *)grab_object( resource->fd ); +} + +static unsigned int gpu_resource_map_access( struct object *obj, unsigned int access ) +{ + if (access & GENERIC_READ) access |= DXGI_SHARED_RESOURCE_READ; + if (access & GENERIC_WRITE) access |= DXGI_SHARED_RESOURCE_WRITE; + if (access & GENERIC_ALL) access |= (DXGI_SHARED_RESOURCE_READ|DXGI_SHARED_RESOURCE_WRITE); + return access & (DXGI_SHARED_RESOURCE_READ|DXGI_SHARED_RESOURCE_WRITE); +} + +static enum server_fd_type gpu_resource_get_fd_type( struct fd *fd ) +{ + return FD_TYPE_RESOURCE; +} + +/* mostly a copy of PTID code */ +struct kmt_entry +{ + void *ptr; + unsigned int next; +}; + +static struct kmt_entry *kmt_entries; /* array of kmt entries */ +static unsigned int used_kmt_entries; /* number of entries in use */ +static unsigned int alloc_kmt_entries; /* number of allocated entries */ +static unsigned int next_free_kmt_entry; /* next free entry */ +static unsigned int last_free_kmt_entry; /* last free entry */ +static unsigned int num_free_kmt_entries; /* number of free entries */ + +inline obj_handle_t kmt_entry_to_handle( unsigned int entry ) +{ + return (obj_handle_t) (entry + 1) * 4; +} + +inline unsigned int kmt_handle_to_entry( obj_handle_t handle ) +{ + return (unsigned int) (handle / 4) - 1; +} + +/* allocate a new kmt handle */ +obj_handle_t alloc_kmt_handle( void *ptr ) +{ + struct kmt_entry *entry; + obj_handle_t kmt_handle; + + if (used_kmt_entries < alloc_kmt_entries) + { + kmt_handle = kmt_entry_to_handle(used_kmt_entries); + entry = &kmt_entries[used_kmt_entries++]; + } + else if (next_free_kmt_entry && num_free_kmt_entries >= 256) + { + kmt_handle = kmt_entry_to_handle(next_free_kmt_entry * 4); + entry = &kmt_entries[next_free_kmt_entry]; + if (!(next_free_kmt_entry = entry->next)) last_free_kmt_entry = 0; + num_free_kmt_entries--; + } + else /* need to grow the array */ + { + unsigned int count = alloc_kmt_entries + (alloc_kmt_entries / 2); + if (!count) count = 512; + if (!(entry = realloc( kmt_entries, count * sizeof(*entry) ))) + { + set_error( STATUS_NO_MEMORY ); + return 0; + } + kmt_entries = entry; + alloc_kmt_entries = count; + kmt_handle = kmt_entry_to_handle(used_kmt_entries); + entry = &kmt_entries[used_kmt_entries++]; + } + + entry->ptr = ptr; + return kmt_handle; +} + +/* free a kmt handle */ +void free_kmt_handle( obj_handle_t kmt_handle ) +{ + unsigned int entry_id = kmt_handle_to_entry(kmt_handle); + struct kmt_entry *entry = &kmt_entries[entry_id]; + + entry->ptr = NULL; + entry->next = 0; + + /* append to end of free list so that we don't reuse it too early */ + if (last_free_kmt_entry) kmt_entries[last_free_kmt_entry].next = entry_id; + else next_free_kmt_entry = entry_id; + last_free_kmt_entry = entry_id; + num_free_kmt_entries++; +} + +/* retrieve the resource corresponding to a kmt handle */ +void *get_kmt_entry( obj_handle_t kmt_handle ) +{ + if (kmt_handle < 4 || kmt_handle % 4) return NULL; + if (kmt_handle_to_entry(kmt_handle) >= used_kmt_entries) return NULL; + return kmt_entries[kmt_handle_to_entry(kmt_handle)].ptr; +} + +struct gpu_resource *create_gpu_resource(struct object *root, const struct unicode_str *name, + unsigned int attr, int fd, + const struct security_descriptor *sd ) +{ + struct gpu_resource *resource; + + if ((resource = create_named_object( root, &gpu_resource_ops, name, attr, sd))) + { + if (get_error() != STATUS_OBJECT_NAME_EXISTS) + { + list_init( &resource->kernel_object ); + if (!(resource->fd = create_anonymous_fd( &gpu_resource_fd_ops, fd, &resource->obj, 0))) + { + release_object( resource ); + return NULL; + } + resource->kmt_handle = alloc_kmt_handle( resource ); + allow_fd_caching( resource->fd ); + } + } + return resource; +} + +/* Create a GPU resource object */ +DECL_HANDLER(create_gpu_resource) +{ + struct gpu_resource *resource; + int fd; + struct unicode_str name; + struct object *root; + const struct security_descriptor *sd; + const struct object_attributes *objattr = get_req_object_attributes( &sd, &name, &root ); + + reply->handle = 0; + + if (!objattr) return; + + if ((fd = thread_get_inflight_fd( current, req->fd )) == -1) + { + set_error( STATUS_INVALID_HANDLE ); + return; + } + + if ((resource = create_gpu_resource( root, &name, objattr->attributes, fd, sd))) + { + if (get_error() == STATUS_OBJECT_NAME_EXISTS) + reply->handle = alloc_handle( current->process, resource, req->access, objattr->attributes ); + else + reply->handle = alloc_handle_no_access_check( current->process, resource, + req->access, objattr->attributes ); + reply->kmt_handle = resource->kmt_handle; + release_object( resource ); + } + + if (root) release_object( root ); +} + +/* Open a GPU Resource */ +DECL_HANDLER(open_gpu_resource) +{ + if (req->kmt_handle) + { + struct object *obj = (struct object *) get_kmt_entry(req->kmt_handle); + if (!obj) + { + set_error(STATUS_INVALID_HANDLE); + return; + } + if (obj->ops != &gpu_resource_ops) + { + set_error(STATUS_OBJECT_TYPE_MISMATCH); + return; + } + grab_object(obj); + reply->handle = alloc_handle_no_access_check( current->process, obj, req->access, 0 ); + release_object(obj); + } else { + struct unicode_str name = get_req_unicode_str(); + + reply->handle = open_object( current->process, req->rootdir, req->access, &gpu_resource_ops, &name, req->attributes ); + } +} + +struct gpu_resource *get_resource_obj( struct process *process, obj_handle_t handle, unsigned int access ) +{ + return (struct gpu_resource *)get_handle_obj( process, handle, access, &gpu_resource_ops ); +} + +/* Query KMT handle of GPU Resource */ +DECL_HANDLER(query_gpu_resource) +{ + struct gpu_resource *resource; + + if (!(resource = get_resource_obj( current->process, req->handle, 0 ))) return; + reply->kmt_handle = resource->kmt_handle; + release_object(resource); +} diff --git a/server/protocol.def b/server/protocol.def index 6af0ae0cff..a4bc550544 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1302,6 +1302,7 @@ enum server_fd_type FD_TYPE_MAILSLOT, /* mailslot */ FD_TYPE_CHAR, /* unspecified char device */ FD_TYPE_DEVICE, /* Windows device file */ + FD_TYPE_RESOURCE, /* DXGI GPU resource */ FD_TYPE_NB_TYPES };
@@ -3934,6 +3935,39 @@ struct handle_info @END
+/* Create a GPU resource object */ +@REQ(create_gpu_resource) + unsigned int access; + int fd; + VARARG(objattr,object_attributes); /* object attributes */ +@REPLY + obj_handle_t handle; + obj_handle_t kmt_handle; +@END + + +/* Open a GPU Resource */ +@REQ(open_gpu_resource) + unsigned int access; /* wanted access rights */ + + obj_handle_t kmt_handle; + /* OR */ + unsigned int attributes; /* object attributes */ + obj_handle_t rootdir; /* root directory */ + VARARG(name,unicode_str); /* object name */ +@REPLY + obj_handle_t handle; +@END + + +/* Query KMT Handle of GPU Resource */ +@REQ(query_gpu_resource) + obj_handle_t handle; +@REPLY + obj_handle_t kmt_handle; +@END + + /* Suspend a process */ @REQ(suspend_process) obj_handle_t handle; /* process handle */
Signed-off-by: Derek Lesho dlesho@codeweavers.com --- dlls/ntdll/Makefile.in | 1 + dlls/ntdll/gpu_resource.c | 104 ++++++++++++++++++++++++++++++++++++++ dlls/ntdll/ntdll.spec | 5 ++ 3 files changed, 110 insertions(+) create mode 100644 dlls/ntdll/gpu_resource.c
diff --git a/dlls/ntdll/Makefile.in b/dlls/ntdll/Makefile.in index 9b4d70f6e8..ba4c7b8149 100644 --- a/dlls/ntdll/Makefile.in +++ b/dlls/ntdll/Makefile.in @@ -19,6 +19,7 @@ C_SRCS = \ error.c \ exception.c \ file.c \ + gpu_resource.c \ handletable.c \ heap.c \ large_int.c \ diff --git a/dlls/ntdll/gpu_resource.c b/dlls/ntdll/gpu_resource.c new file mode 100644 index 0000000000..63488016b1 --- /dev/null +++ b/dlls/ntdll/gpu_resource.c @@ -0,0 +1,104 @@ +#include "config.h" + +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "ntdll_misc.h" +#include "dxgi1_2.h" + +/* Closes Staging FD afterwards if successful */ +NTSTATUS CDECL __wine_create_gpu_resource(PHANDLE handle, PHANDLE kmt_handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, int fd ) +{ + NTSTATUS ret; + data_size_t len; + struct object_attributes *objattr; + + if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret; + + wine_server_send_fd( fd ); + + SERVER_START_REQ( create_gpu_resource ) + { + req->access = access; + req->fd = fd; + wine_server_add_data( req, objattr, len ); + ret = wine_server_call( req ); + if(handle) *handle = wine_server_ptr_handle( reply->handle ); + if(kmt_handle) *kmt_handle = wine_server_ptr_handle( reply->kmt_handle ); + } + SERVER_END_REQ; + + RtlFreeHeap( GetProcessHeap(), 0, objattr ); + if (!ret) + close(fd); + + return ret; +} + +/* Opens a GPU-resource handle from a KMT handle or name */ +NTSTATUS CDECL __wine_open_gpu_resource(HANDLE kmt_handle, OBJECT_ATTRIBUTES *attr, DWORD access, PHANDLE handle ) +{ + NTSTATUS ret; + + if ((kmt_handle && attr) || !handle) + return STATUS_INVALID_PARAMETER; + + SERVER_START_REQ( open_gpu_resource ) + { + req->access = access; + req->kmt_handle = wine_server_obj_handle( kmt_handle ); + if (attr) + { + req->attributes = attr->Attributes; + req->rootdir = wine_server_obj_handle( attr->RootDirectory ); + if (attr->ObjectName) + wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length ); + } + if (!(ret = wine_server_call( req ))) + *handle = wine_server_ptr_handle( reply->handle ); + else + *handle = INVALID_HANDLE_VALUE; + } + SERVER_END_REQ; + + return ret; +} + + +/* Gets an FD from GPU resource handle */ +NTSTATUS CDECL __wine_get_gpu_resource_fd(HANDLE handle, int *fd, int *needs_close) +{ + NTSTATUS ret; + enum server_fd_type type; + + ret = server_get_unix_fd( handle, DXGI_SHARED_RESOURCE_READ|DXGI_SHARED_RESOURCE_WRITE, fd, needs_close, &type, NULL ); + + if (type != FD_TYPE_RESOURCE) + { + if (*needs_close) + close(*fd); + *fd = -1; + return STATUS_INVALID_HANDLE; + } + + return ret; +} + +/* gets KMT handle */ +NTSTATUS CDECL __wine_get_gpu_resource_info(HANDLE handle, HANDLE *kmt_handle) +{ + NTSTATUS ret; + + SERVER_START_REQ(query_gpu_resource) + { + req->handle = wine_server_obj_handle( handle ); + if (!(ret = wine_server_call(req))) + *kmt_handle = wine_server_ptr_handle( reply->kmt_handle ); + } + SERVER_END_REQ; + + return ret; +} \ No newline at end of file diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index 06811edf01..4cc03469f9 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -1570,3 +1570,8 @@ # Filesystem @ cdecl wine_nt_to_unix_file_name(ptr ptr long long) @ cdecl wine_unix_to_nt_file_name(ptr ptr) + +@ cdecl __wine_create_gpu_resource(ptr ptr long ptr long) +@ cdecl __wine_open_gpu_resource(ptr ptr long ptr) +@ cdecl __wine_get_gpu_resource_fd(ptr ptr ptr) +@ cdecl __wine_get_gpu_resource_info(ptr ptr) \ No newline at end of file
Signed-off-by: Derek Lesho dlesho@codeweavers.com --- dlls/winevulkan/make_vulkan | 11 +- dlls/winevulkan/vulkan.c | 336 ++++++++++++++++++++++++++++++- dlls/winevulkan/vulkan_private.h | 26 +++ 3 files changed, 362 insertions(+), 11 deletions(-)
diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index 4f1c03cc7c..e0a988e7aa 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -107,7 +107,6 @@ BLACKLISTED_EXTENSIONS = [ "VK_EXT_pipeline_creation_feedback", "VK_GOOGLE_display_timing", "VK_KHR_external_fence_win32", - "VK_KHR_external_memory_win32", "VK_KHR_external_semaphore_win32", # Relates to external_semaphore and needs type conversions in bitflags. "VK_KHR_shared_presentable_image", # Needs WSI work. @@ -117,7 +116,6 @@ BLACKLISTED_EXTENSIONS = [ "VK_EXT_external_memory_dma_buf", "VK_EXT_image_drm_format_modifier", "VK_KHR_external_fence_fd", - "VK_KHR_external_memory_fd", "VK_KHR_external_semaphore_fd",
# Deprecated extensions @@ -168,11 +166,13 @@ FUNCTION_OVERRIDES = {
# Device functions "vkAllocateCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : False}, + "vkAllocateMemory" : {"dispatch" : True, "driver" : False, "thunk" : False}, "vkCmdExecuteCommands" : {"dispatch" : True, "driver" : False, "thunk" : False}, "vkCreateCommandPool" : {"dispatch": True, "driver" : False, "thunk" : False}, "vkDestroyCommandPool" : {"dispatch": True, "driver" : False, "thunk" : False}, "vkDestroyDevice" : {"dispatch" : True, "driver" : False, "thunk" : False}, "vkFreeCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : False}, + "vkFreeMemory" : {"dispatch" : True, "driver" : False, "thunk" : False}, "vkGetDeviceProcAddr" : {"dispatch" : False, "driver" : True, "thunk" : False}, "vkGetDeviceQueue" : {"dispatch": True, "driver" : False, "thunk" : False}, "vkGetDeviceQueue2" : {"dispatch": True, "driver" : False, "thunk" : False}, @@ -211,6 +211,10 @@ FUNCTION_OVERRIDES = { # VK_KHR_device_group "vkGetDeviceGroupSurfacePresentModesKHR" : {"dispatch" : True, "driver" : True, "thunk" : True}, "vkGetPhysicalDevicePresentRectanglesKHR" : {"dispatch" : True, "driver" : True, "thunk" : True}, + + # VK_KHR_external_memory_win32 + "vkGetMemoryWin32HandleKHR" : {"dispatch" : False, "driver" : False, "thunk" : False}, + "vkGetMemoryWin32HandlePropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : False}, }
STRUCT_CHAIN_CONVERSIONS = [ @@ -887,6 +891,9 @@ class VkHandle(object): if self.name == "VkCommandPool": return "wine_cmd_pool_from_handle({0})->command_pool".format(name)
+ if self.name == "VkDeviceMemory": + return "wine_dev_mem_from_handle({0})->dev_mem".format(name) + native_handle_name = None
if self.name == "VkCommandBuffer": diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index 725bdf019e..01cab11e21 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -17,11 +17,22 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
+#include "config.h" + #include <stdarg.h> +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif
+#include "ntstatus.h" +#define WIN32_NO_STATUS #include "windef.h" +#include "winternl.h" #include "winbase.h" #include "winuser.h" +#include "wine/unicode.h" + +#include "dxgi1_2.h"
#include "vulkan_private.h"
@@ -111,6 +122,14 @@ static struct VkPhysicalDevice_T *wine_vk_physical_device_alloc(struct VkInstanc { if (wine_vk_device_extension_supported(host_properties[i].extensionName)) { + if (!strcmp(host_properties[i].extensionName, "VK_KHR_external_memory_fd")) + { + TRACE("Substituting VK_KHR_external_memory_fd for VK_KHR_external_memory_win32\n"); + + snprintf(host_properties[i].extensionName, sizeof(host_properties[i].extensionName), + VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME); + host_properties[i].specVersion = VK_KHR_EXTERNAL_MEMORY_WIN32_SPEC_VERSION; + } TRACE("Enabling extension '%s' for physical device %p\n", host_properties[i].extensionName, object); num_properties++; } @@ -224,9 +243,15 @@ static VkResult wine_vk_device_convert_create_info(const VkDeviceCreateInfo *src { VkDeviceGroupDeviceCreateInfo *group_info; unsigned int i; + const char **enabled_extensions = NULL; VkResult res;
- *dst = *src; + dst->sType = src->sType; + dst->flags = src->flags; + dst->pNext = src->pNext; + dst->queueCreateInfoCount = src->queueCreateInfoCount; + dst->pQueueCreateInfos = src->pQueueCreateInfos; + dst->pEnabledFeatures = src->pEnabledFeatures;
if ((res = convert_VkDeviceCreateInfo_struct_chain(src->pNext, dst)) < 0) { @@ -254,18 +279,31 @@ static VkResult wine_vk_device_convert_create_info(const VkDeviceCreateInfo *src /* Should be filtered out by loader as ICDs don't support layers. */ dst->enabledLayerCount = 0; dst->ppEnabledLayerNames = NULL; + dst->enabledExtensionCount = 0; + dst->ppEnabledExtensionNames = NULL;
- TRACE("Enabled %u extensions.\n", dst->enabledExtensionCount); - for (i = 0; i < dst->enabledExtensionCount; i++) + if (src->enabledExtensionCount > 0) { - const char *extension_name = dst->ppEnabledExtensionNames[i]; - TRACE("Extension %u: %s.\n", i, debugstr_a(extension_name)); - if (!wine_vk_device_extension_supported(extension_name)) + enabled_extensions = heap_calloc(src->enabledExtensionCount, sizeof(*src->ppEnabledExtensionNames)); + if (!enabled_extensions) { - WARN("Extension %s is not supported.\n", debugstr_a(extension_name)); - wine_vk_device_free_create_info(dst); - return VK_ERROR_EXTENSION_NOT_PRESENT; + ERR("Failed to allocate memory for enabled extensions\n"); + return VK_ERROR_OUT_OF_HOST_MEMORY; } + + for (i = 0; i < src->enabledExtensionCount; i++) + { + if (!strcmp(src->ppEnabledExtensionNames[i], "VK_KHR_external_memory_win32")) + { + enabled_extensions[i] = "VK_KHR_external_memory_fd"; + } + else + { + enabled_extensions[i] = src->ppEnabledExtensionNames[i]; + } + } + dst->ppEnabledExtensionNames = enabled_extensions; + dst->enabledExtensionCount = src->enabledExtensionCount; }
return VK_SUCCESS; @@ -1128,6 +1166,241 @@ void WINAPI wine_vkDestroyCommandPool(VkDevice device, VkCommandPool handle, heap_free(pool); }
+extern NTSTATUS CDECL __wine_create_gpu_resource(PHANDLE handle, PHANDLE kmt_handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, int fd ); +extern NTSTATUS CDECL __wine_open_gpu_resource(HANDLE kmt_handle, OBJECT_ATTRIBUTES *attr, DWORD access, PHANDLE handle ); +extern NTSTATUS CDECL __wine_get_gpu_resource_fd(HANDLE handle, int *fd, int *needs_close); +extern NTSTATUS CDECL __wine_get_gpu_resource_info(HANDLE handle, HANDLE *kmt_handle); + +static NTSTATUS server_create_dxgi_resource( PHANDLE handle, PHANDLE kmt_handle, int fd, DWORD access, SECURITY_ATTRIBUTES *sa, LPCWSTR name ) +{ + OBJECT_ATTRIBUTES attr; + + attr.Length = sizeof(attr); + attr.RootDirectory = 0; + attr.ObjectName = NULL; + attr.Attributes = OBJ_OPENIF | ((sa && sa->bInheritHandle) ? OBJ_INHERIT : 0); + attr.SecurityDescriptor = sa ? sa->lpSecurityDescriptor : NULL; + attr.SecurityQualityOfService = NULL; + if (name) + { + RtlInitUnicodeString( attr.ObjectName, name ); + attr.RootDirectory = /*TODO*/0/*TODO*/; + } + + return __wine_create_gpu_resource(handle, kmt_handle, access, &attr, fd); +} + +static NTSTATUS server_open_dxgi_resource( PHANDLE handle, LPCWSTR name, DWORD access) +{ + OBJECT_ATTRIBUTES attr; + + attr.Length = sizeof(attr); + attr.RootDirectory = 0; + attr.ObjectName = NULL; + attr.Attributes = 0; + attr.SecurityDescriptor = 0; + attr.SecurityQualityOfService = NULL; + if (name) + { + RtlInitUnicodeString( attr.ObjectName, name ); + attr.RootDirectory = /*TODO*/0/*TODO*/; + } + + return __wine_open_gpu_resource(NULL, &attr, access, handle); +} + +VkResult WINAPI wine_vkAllocateMemory(VkDevice device, const VkMemoryAllocateInfo *allocate_info, const VkAllocationCallbacks *allocator, VkDeviceMemory *memory_out) +{ + struct wine_dev_mem *object; + VkMemoryAllocateInfo allocate_info_host = *allocate_info; + VkBaseOutStructure *header; + VkExternalMemoryHandleTypeFlags handle_types = 0; + VkExportMemoryAllocateInfo *export_info = NULL; + VkExportMemoryWin32HandleInfoKHR *handle_export_info = NULL; + VkImportMemoryFdInfoKHR fd_import_info; + int needs_close = TRUE; + VkResult res; + + TRACE("%p %p %p %p\n", device, allocate_info, allocator, memory_out); + + if (allocator) + FIXME("Support for allocation callbacks not implemented yet\n"); + + if (!(object = heap_alloc_zero(sizeof(*object)))) + return VK_ERROR_OUT_OF_HOST_MEMORY; + + object->dev_mem = VK_NULL_HANDLE; + object->handle = INVALID_HANDLE_VALUE; + object->kmt_handle = INVALID_HANDLE_VALUE; + fd_import_info.fd = -1; + + /* find and process handle import/export info and grab it */ + for (header = (void *)allocate_info->pNext; header; header = header->pNext) + { + switch (header->sType) + { + case VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO: + { + export_info = (VkExportMemoryAllocateInfo *)header; + + handle_types = export_info->handleTypes; + if (handle_types & (VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT|VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT)) + export_info->handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; + }break; + case VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR: + { + handle_export_info = (VkExportMemoryWin32HandleInfoKHR *)header; + }break; + case VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR: + { + VkImportMemoryWin32HandleInfoKHR *win32_import_info = (VkImportMemoryWin32HandleInfoKHR *)header; + + fd_import_info.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR; + fd_import_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; + + /* get the fd from the handle */ + switch (win32_import_info->handleType) + { + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT: + if (win32_import_info->handle) + DuplicateHandle( GetCurrentProcess(), win32_import_info->handle, GetCurrentProcess(), &object->handle, 0, FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); + else if (win32_import_info->name) + server_open_dxgi_resource( &object->handle, win32_import_info->name, DXGI_SHARED_RESOURCE_READ|DXGI_SHARED_RESOURCE_WRITE ); + break; + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT: + __wine_open_gpu_resource( win32_import_info->handle, NULL, DXGI_SHARED_RESOURCE_READ|DXGI_SHARED_RESOURCE_WRITE, &object->handle ); + object->kmt_handle = win32_import_info->handle; + break; + default: + TRACE("Invalid handle type %08x passed in.\n", win32_import_info->handleType); + res = VK_ERROR_INVALID_EXTERNAL_HANDLE; + goto done; + } + + if (object->handle != INVALID_HANDLE_VALUE) + __wine_get_gpu_resource_fd(object->handle, &fd_import_info.fd, &needs_close); + + if (fd_import_info.fd != -1) + { + fd_import_info.pNext = allocate_info_host.pNext; + /* we ignore the const because we'll restore it */ + allocate_info_host.pNext = &fd_import_info; + + /* if the fd needs closing, we can just pass it to vulkan where it can be consumed, + otherwise we need to duplicate it so the cached fd isn't consumed by vulkan */ + if (!needs_close) + fd_import_info.fd = dup(fd_import_info.fd); + } + else + { + TRACE("Couldn't access resource handle or name. type=%08x handle=%p name=%s\n", win32_import_info->handleType, win32_import_info->handle, + win32_import_info->name ? debugstr_w(win32_import_info->name) : ""); + res = VK_ERROR_INVALID_EXTERNAL_HANDLE; + goto done; + } + }break; + default: + { + TRACE("Unhandled stype = %08x\n", header->sType); + } + } + } + + res = device->funcs.p_vkAllocateMemory(device->device, &allocate_info_host, NULL, &object->dev_mem); + + if (res == VK_SUCCESS) + { + VkDeviceMemory memory = object->dev_mem; + + if (export_info && export_info->handleTypes) + { + if (object->handle != INVALID_HANDLE_VALUE) + { + /* occurs if the caller imports *and* exports the memory */ + if (handle_types & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT && object->kmt_handle == INVALID_HANDLE_VALUE) + __wine_get_gpu_resource_info(object->handle, &object->kmt_handle); + } else { + int fd; + VkMemoryGetFdInfoKHR host_fd_info; + + /* get an fd to represent it */ + + host_fd_info.sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR; + host_fd_info.pNext = NULL; + host_fd_info.memory = memory; + host_fd_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; + + if (device->funcs.p_vkGetMemoryFdKHR(device->device, &host_fd_info, &fd) == VK_SUCCESS) + { + LPCWSTR name = handle_export_info ? handle_export_info->name : NULL; + SECURITY_ATTRIBUTES sa = handle_export_info ? (handle_export_info->pAttributes ? *handle_export_info->pAttributes : (SECURITY_ATTRIBUTES){0}) : (SECURITY_ATTRIBUTES){0}; + if (sa.bInheritHandle){ + sa.bInheritHandle = FALSE; + } + if (!(server_create_dxgi_resource(&object->handle, &object->kmt_handle, fd, object->access, sa.nLength ? &sa : NULL, name))) + { + object->handle_types = handle_types & + (VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT|VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT); + TRACE("Device Memory %p set-up to export handle types: %08x\n", object, object->handle_types); + } else { + TRACE("Failed to create server-side dxgi-resource.\n"); + close(fd); + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto done; + } + } else { + TRACE("Failed to retrieve FD from native vulkan driver.\n"); + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto done; + } + } + object->access = handle_export_info ? handle_export_info->dwAccess : DXGI_SHARED_RESOURCE_READ|DXGI_SHARED_RESOURCE_WRITE; + object->inherit = handle_export_info ? (handle_export_info->pAttributes ? handle_export_info->pAttributes->bInheritHandle : FALSE) : FALSE; + } + + *memory_out = wine_dev_mem_to_handle(object); + } + else + { + TRACE("vkAllocateMemory failed with %u\n", res); + goto done; + } + + done: + if (res != VK_SUCCESS) + { + if (object->dev_mem != VK_NULL_HANDLE) + device->funcs.p_vkFreeMemory(device->device, object->dev_mem, NULL); + if (fd_import_info.fd != -1 && needs_close) + close(fd_import_info.fd); + if (object->handle != INVALID_HANDLE_VALUE) + CloseHandle(object->handle); + heap_free(object); + } + if (export_info) + export_info->handleTypes = handle_types; + return res; +} + +void WINAPI wine_vkFreeMemory(VkDevice device, VkDeviceMemory handle, + const VkAllocationCallbacks* allocator) +{ + struct wine_dev_mem *dev_mem = wine_dev_mem_from_handle(handle); + + TRACE("%p 0x%s, %p\n", device, wine_dbgstr_longlong(handle), allocator); + + if (!handle) + return; + + if (allocator) + FIXME("Support for allocation callbacks not implemented yet\n"); + + device->funcs.p_vkFreeMemory(device->device, dev_mem->dev_mem, NULL); + if (dev_mem->handle != INVALID_HANDLE_VALUE) + CloseHandle(dev_mem->handle); + heap_free(dev_mem); +} + static VkResult wine_vk_enumerate_physical_device_groups(struct VkInstance_T *instance, VkResult (*p_vkEnumeratePhysicalDeviceGroups)(VkInstance, uint32_t *, VkPhysicalDeviceGroupProperties *), uint32_t *count, VkPhysicalDeviceGroupProperties *properties) @@ -1261,6 +1534,51 @@ void WINAPI wine_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR(VkPhysicalDev properties->externalSemaphoreFeatures = 0; }
+VkResult WINAPI wine_vkGetMemoryWin32HandleKHR(VkDevice device, + const VkMemoryGetWin32HandleInfoKHR *handle_info, HANDLE *handle) +{ + struct wine_dev_mem *dev_mem; + + TRACE("%p, %p %p\n", device, handle_info, handle); + + dev_mem = wine_dev_mem_from_handle(handle_info->memory); + + switch(handle_info->handleType) + { + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT: + if (!(dev_mem->handle_types & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT)) + { + *handle = INVALID_HANDLE_VALUE; + TRACE("VkDeviceMemory wasn't set-up to export native win32 handles.\n"); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + if (!(DuplicateHandle( GetCurrentProcess(), dev_mem->handle, GetCurrentProcess(), handle, dev_mem->access, dev_mem->inherit, 0 ))) + return VK_ERROR_OUT_OF_HOST_MEMORY; + break; + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT: + if (!(dev_mem->handle_types & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT)) + { + *handle = INVALID_HANDLE_VALUE; + TRACE("VkDeviceMemory wasn't set-up to export KMT handles.\n"); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + *handle = dev_mem->kmt_handle; + break; + default: + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + + return VK_SUCCESS; +} + +VkResult WINAPI wine_vkGetMemoryWin32HandlePropertiesKHR(VkDevice device, + VkExternalMemoryHandleTypeFlagBits type, HANDLE handle, VkMemoryWin32HandlePropertiesKHR *properties) +{ + TRACE("%p %u %p %p\n", device, type, handle, properties); + + return VK_ERROR_INCOMPATIBLE_DRIVER; +} + BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, void *reserved) { TRACE("%p, %u, %p\n", hinst, reason, reserved); diff --git a/dlls/winevulkan/vulkan_private.h b/dlls/winevulkan/vulkan_private.h index 17072d2341..f0b3b10dd3 100644 --- a/dlls/winevulkan/vulkan_private.h +++ b/dlls/winevulkan/vulkan_private.h @@ -120,16 +120,42 @@ struct wine_cmd_pool struct list command_buffers; };
+struct wine_dev_mem +{ + VkDeviceMemory dev_mem; + + VkExternalMemoryHandleTypeFlags handle_types; + + BOOL inherit; + DWORD access; + + /* Internal handle that lasts as long as the object */ + HANDLE handle; + + /* KMT "handle" */ + HANDLE kmt_handle; +}; + static inline struct wine_cmd_pool *wine_cmd_pool_from_handle(VkCommandPool handle) { return (struct wine_cmd_pool *)(uintptr_t)handle; }
+static inline struct wine_dev_mem *wine_dev_mem_from_handle(VkDeviceMemory handle) +{ + return (struct wine_dev_mem *)(uintptr_t)handle; +} + static inline VkCommandPool wine_cmd_pool_to_handle(struct wine_cmd_pool *cmd_pool) { return (VkCommandPool)(uintptr_t)cmd_pool; }
+static inline VkDeviceMemory wine_dev_mem_to_handle(struct wine_dev_mem *dev_mem) +{ + return (VkDeviceMemory)(uintptr_t)dev_mem; +} + void *wine_vk_get_device_proc_addr(const char *name) DECLSPEC_HIDDEN; void *wine_vk_get_instance_proc_addr(const char *name) DECLSPEC_HIDDEN;
This is necessary when Graphics API Layers are emulating APIs that support sharing resources with more details than just the underlying memory.
Signed-off-by: Derek Lesho dlesho@codeweavers.com --- dlls/ntdll/gpu_resource.c | 30 +++++++++++++++++++++--- dlls/ntdll/ntdll.spec | 3 ++- dlls/winevulkan/vulkan.c | 4 ++-- server/gpu_resource.c | 49 +++++++++++++++++++++++++++++++++++---- server/protocol.def | 9 ++++++- 5 files changed, 84 insertions(+), 11 deletions(-)
diff --git a/dlls/ntdll/gpu_resource.c b/dlls/ntdll/gpu_resource.c index 63488016b1..00d07cd4fd 100644 --- a/dlls/ntdll/gpu_resource.c +++ b/dlls/ntdll/gpu_resource.c @@ -87,16 +87,40 @@ NTSTATUS CDECL __wine_get_gpu_resource_fd(HANDLE handle, int *fd, int *needs_clo return ret; }
-/* gets KMT handle */ -NTSTATUS CDECL __wine_get_gpu_resource_info(HANDLE handle, HANDLE *kmt_handle) +/* gets KMT handle and userdata */ +NTSTATUS CDECL __wine_get_gpu_resource_info(HANDLE handle, HANDLE *kmt_handle, void *user_data_buf, unsigned int *user_data_len) { NTSTATUS ret; + BOOL get_user_data = user_data_buf && user_data_len;
SERVER_START_REQ(query_gpu_resource) { req->handle = wine_server_obj_handle( handle ); + if (get_user_data) + wine_server_set_reply(req, user_data_buf, *user_data_len); if (!(ret = wine_server_call(req))) - *kmt_handle = wine_server_ptr_handle( reply->kmt_handle ); + { + if (kmt_handle) + *kmt_handle = wine_server_ptr_handle( reply->kmt_handle ); + if (user_data_len) + *user_data_len = wine_server_reply_size(reply); + } + } + SERVER_END_REQ; + + return ret; +} + +/* Updates the userdata of the GPU resource */ +NTSTATUS CDECL __wine_set_gpu_resource_userdata(HANDLE handle, void *user_data, unsigned int user_data_len) +{ + NTSTATUS ret; + + SERVER_START_REQ(set_userdata_gpu_resource) + { + req->handle = wine_server_obj_handle(handle); + wine_server_add_data(req, user_data, user_data_len); + ret = wine_server_call( req ); } SERVER_END_REQ;
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index 4cc03469f9..e80b28f14f 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -1574,4 +1574,5 @@ @ cdecl __wine_create_gpu_resource(ptr ptr long ptr long) @ cdecl __wine_open_gpu_resource(ptr ptr long ptr) @ cdecl __wine_get_gpu_resource_fd(ptr ptr ptr) -@ cdecl __wine_get_gpu_resource_info(ptr ptr) \ No newline at end of file +@ cdecl __wine_get_gpu_resource_info(ptr ptr ptr ptr) +@ cdecl __wine_set_gpu_resource_userdata(ptr ptr long) \ No newline at end of file diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index 01cab11e21..36da6e2326 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -1169,7 +1169,7 @@ void WINAPI wine_vkDestroyCommandPool(VkDevice device, VkCommandPool handle, extern NTSTATUS CDECL __wine_create_gpu_resource(PHANDLE handle, PHANDLE kmt_handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, int fd ); extern NTSTATUS CDECL __wine_open_gpu_resource(HANDLE kmt_handle, OBJECT_ATTRIBUTES *attr, DWORD access, PHANDLE handle ); extern NTSTATUS CDECL __wine_get_gpu_resource_fd(HANDLE handle, int *fd, int *needs_close); -extern NTSTATUS CDECL __wine_get_gpu_resource_info(HANDLE handle, HANDLE *kmt_handle); +extern NTSTATUS CDECL __wine_get_gpu_resource_info(HANDLE handle, HANDLE *kmt_handle, void *user_data_buf, unsigned int *user_data_len);
static NTSTATUS server_create_dxgi_resource( PHANDLE handle, PHANDLE kmt_handle, int fd, DWORD access, SECURITY_ATTRIBUTES *sa, LPCWSTR name ) { @@ -1318,7 +1318,7 @@ VkResult WINAPI wine_vkAllocateMemory(VkDevice device, const VkMemoryAllocateInf { /* occurs if the caller imports *and* exports the memory */ if (handle_types & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT && object->kmt_handle == INVALID_HANDLE_VALUE) - __wine_get_gpu_resource_info(object->handle, &object->kmt_handle); + __wine_get_gpu_resource_info(object->handle, &object->kmt_handle, NULL, NULL); } else { int fd; VkMemoryGetFdInfoKHR host_fd_info; diff --git a/server/gpu_resource.c b/server/gpu_resource.c index bc083a2f42..e9fd493ab5 100644 --- a/server/gpu_resource.c +++ b/server/gpu_resource.c @@ -22,6 +22,10 @@ struct gpu_resource struct list kernel_object; struct fd *fd; obj_handle_t kmt_handle; /* more like an ID */ + + /* used by API layers to store extra information about a resource */ + void *user_data; + data_size_t user_data_len; };
/* gpu_resource functions */ @@ -216,6 +220,7 @@ struct gpu_resource *create_gpu_resource(struct object *root, const struct unico return NULL; } resource->kmt_handle = alloc_kmt_handle( resource ); + resource->user_data = 0; allow_fd_caching( resource->fd ); } } @@ -287,12 +292,48 @@ struct gpu_resource *get_resource_obj( struct process *process, obj_handle_t han return (struct gpu_resource *)get_handle_obj( process, handle, access, &gpu_resource_ops ); }
-/* Query KMT handle of GPU Resource */ +/* Query KMT handle and user data of GPU Resource */ DECL_HANDLER(query_gpu_resource) { struct gpu_resource *resource; + data_size_t reply_size = get_reply_max_size(); + + if ((resource = get_resource_obj( current->process, req->handle, 0 ))) + { + reply->kmt_handle = resource->kmt_handle; + + if (reply_size) + { + if (reply_size >= resource->user_data_len) + set_reply_data(resource->user_data, resource->user_data_len); + else + set_error(STATUS_BUFFER_TOO_SMALL); + }
- if (!(resource = get_resource_obj( current->process, req->handle, 0 ))) return; - reply->kmt_handle = resource->kmt_handle; - release_object(resource); + release_object(resource); + } } + +/* Sets the user data of the GPU resource */ +DECL_HANDLER(set_userdata_gpu_resource) +{ + struct gpu_resource *resource; + data_size_t len = get_req_data_size(); + + if ((resource = get_resource_obj( current->process, req->handle, 0 ))) + { + free(resource->user_data); + resource->user_data = mem_alloc(len); + if (resource->user_data) + { + memcpy(resource->user_data, get_req_data(), len); + resource->user_data_len = len; + } + else + { + set_error(STATUS_NO_MEMORY); + } + + release_object(resource); + } +} \ No newline at end of file diff --git a/server/protocol.def b/server/protocol.def index a4bc550544..33d0287b37 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3960,11 +3960,18 @@ struct handle_info @END
-/* Query KMT Handle of GPU Resource */ +/* Query KMT Handle and user data of GPU Resource */ @REQ(query_gpu_resource) obj_handle_t handle; @REPLY obj_handle_t kmt_handle; + VARARG(userdata,bytes); +@END + +/* Sets the userdata of the GPU resource */ +@REQ(set_userdata_gpu_resource) + obj_handle_t handle; + VARARG(userdata,bytes); @END
Derek Lesho dlesho@codeweavers.com writes:
This patchset adds support for Vulkan shared memory in wine, which can in turn be used by API layers like DXVK or D9VK to support D3D shared resources. The final commit in the patchset adds a wine extension allowing layers to associate a custom struct describing a resource, so that they can recreate it with no outside information. In the case of DXVK and D3D11 shared resources, this is a D3D11_COMMON_TEXTURE_DESC.
While this is the simplest solution, it may be a better idea to define a standard structure/s, so that interop between i.e. DXVK and vkd3d would be possible.
Keep in mind that this functionality may also be used for resources other than textures/surfaces, like synchronization primtives.
This looks like something that belongs in the D3D layers, not in the server or ntdll.
On 11/4/19 9:39 AM, Alexandre Julliard wrote:
Derek Lesho dlesho@codeweavers.com writes:
This patchset adds support for Vulkan shared memory in wine, which can in turn be used by API layers like DXVK or D9VK to support D3D shared resources. The final commit in the patchset adds a wine extension allowing layers to associate a custom struct describing a resource, so that they can recreate it with no outside information. In the case of DXVK and D3D11 shared resources, this is a D3D11_COMMON_TEXTURE_DESC.
While this is the simplest solution, it may be a better idea to define a standard structure/s, so that interop between i.e. DXVK and vkd3d would be possible.
Keep in mind that this functionality may also be used for resources other than textures/surfaces, like synchronization primtives.
This looks like something that belongs in the D3D layers, not in the server or ntdll.
I assume you're referring to the custom data associated with the resource? I think you're right, since they could instead create a shared memory handle which they use to store a KMT handle and the resource desc.
If you're referring to the whole patchset, I think we need to at-least export some of the file descriptor<->handle functions in ntdll so we can turn the FD provided by VK_EXTERNAL_MEMORY_fd into a handle for the win32 extension.
Derek Lesho dlesho@codeweavers.com writes:
On 11/4/19 9:39 AM, Alexandre Julliard wrote:
Derek Lesho dlesho@codeweavers.com writes:
This patchset adds support for Vulkan shared memory in wine, which can in turn be used by API layers like DXVK or D9VK to support D3D shared resources. The final commit in the patchset adds a wine extension allowing layers to associate a custom struct describing a resource, so that they can recreate it with no outside information. In the case of DXVK and D3D11 shared resources, this is a D3D11_COMMON_TEXTURE_DESC.
While this is the simplest solution, it may be a better idea to define a standard structure/s, so that interop between i.e. DXVK and vkd3d would be possible.
Keep in mind that this functionality may also be used for resources other than textures/surfaces, like synchronization primtives.
This looks like something that belongs in the D3D layers, not in the server or ntdll.
I assume you're referring to the custom data associated with the resource? I think you're right, since they could instead create a shared memory handle which they use to store a KMT handle and the resource desc.
If you're referring to the whole patchset, I think we need to at-least export some of the file descriptor<->handle functions in ntdll so we can turn the FD provided by VK_EXTERNAL_MEMORY_fd into a handle for the win32 extension.
We already have fd<->handle conversion functions in ntdll, you should be able to build something on top of that.
On 11/4/19 11:50 AM, Alexandre Julliard wrote:
Derek Lesho dlesho@codeweavers.com writes:
On 11/4/19 9:39 AM, Alexandre Julliard wrote:
Derek Lesho dlesho@codeweavers.com writes:
This patchset adds support for Vulkan shared memory in wine, which can in turn be used by API layers like DXVK or D9VK to support D3D shared resources. The final commit in the patchset adds a wine extension allowing layers to associate a custom struct describing a resource, so that they can recreate it with no outside information. In the case of DXVK and D3D11 shared resources, this is a D3D11_COMMON_TEXTURE_DESC.
While this is the simplest solution, it may be a better idea to define a standard structure/s, so that interop between i.e. DXVK and vkd3d would be possible.
Keep in mind that this functionality may also be used for resources other than textures/surfaces, like synchronization primtives.
This looks like something that belongs in the D3D layers, not in the server or ntdll.
I assume you're referring to the custom data associated with the resource? I think you're right, since they could instead create a shared memory handle which they use to store a KMT handle and the resource desc.
If you're referring to the whole patchset, I think we need to at-least export some of the file descriptor<->handle functions in ntdll so we can turn the FD provided by VK_EXTERNAL_MEMORY_fd into a handle for the win32 extension.
We already have fd<->handle conversion functions in ntdll, you should be able to build something on top of that.
Yeah, I did build the shared resource functions off of those conversion functions in ntdll, then exported the shared resource functions.
Would you rather we keep this or export the fd<->handle conversion functions themselves? If we just export them, what object type would we store the vulkan resource as?
Derek Lesho dlesho@codeweavers.com writes:
On 11/4/19 11:50 AM, Alexandre Julliard wrote:
Derek Lesho dlesho@codeweavers.com writes:
On 11/4/19 9:39 AM, Alexandre Julliard wrote:
Derek Lesho dlesho@codeweavers.com writes:
This patchset adds support for Vulkan shared memory in wine, which can in turn be used by API layers like DXVK or D9VK to support D3D shared resources. The final commit in the patchset adds a wine extension allowing layers to associate a custom struct describing a resource, so that they can recreate it with no outside information. In the case of DXVK and D3D11 shared resources, this is a D3D11_COMMON_TEXTURE_DESC.
While this is the simplest solution, it may be a better idea to define a standard structure/s, so that interop between i.e. DXVK and vkd3d would be possible.
Keep in mind that this functionality may also be used for resources other than textures/surfaces, like synchronization primtives.
This looks like something that belongs in the D3D layers, not in the server or ntdll.
I assume you're referring to the custom data associated with the resource? I think you're right, since they could instead create a shared memory handle which they use to store a KMT handle and the resource desc.
If you're referring to the whole patchset, I think we need to at-least export some of the file descriptor<->handle functions in ntdll so we can turn the FD provided by VK_EXTERNAL_MEMORY_fd into a handle for the win32 extension.
We already have fd<->handle conversion functions in ntdll, you should be able to build something on top of that.
Yeah, I did build the shared resource functions off of those conversion functions in ntdll, then exported the shared resource functions.
Would you rather we keep this or export the fd<->handle conversion functions themselves? If we just export them, what object type would we store the vulkan resource as?
They are already exported. You should be able to build what you need on top of files, or mappings, or some other kernel primitive, and not change ntdll at all.
Adding new kernel object types or changing the server should be the last resort, so if you want to do that, you'll have to make a very convincing argument that the existing primitives can't be used for this.
On 11/4/19 1:00 PM, Alexandre Julliard wrote:
Derek Lesho dlesho@codeweavers.com writes:
On 11/4/19 11:50 AM, Alexandre Julliard wrote:
Derek Lesho dlesho@codeweavers.com writes:
On 11/4/19 9:39 AM, Alexandre Julliard wrote:
Derek Lesho dlesho@codeweavers.com writes:
This patchset adds support for Vulkan shared memory in wine, which can in turn be used by API layers like DXVK or D9VK to support D3D shared resources. The final commit in the patchset adds a wine extension allowing layers to associate a custom struct describing a resource, so that they can recreate it with no outside information. In the case of DXVK and D3D11 shared resources, this is a D3D11_COMMON_TEXTURE_DESC.
While this is the simplest solution, it may be a better idea to define a standard structure/s, so that interop between i.e. DXVK and vkd3d would be possible.
Keep in mind that this functionality may also be used for resources other than textures/surfaces, like synchronization primtives.
This looks like something that belongs in the D3D layers, not in the server or ntdll.
I assume you're referring to the custom data associated with the resource? I think you're right, since they could instead create a shared memory handle which they use to store a KMT handle and the resource desc.
If you're referring to the whole patchset, I think we need to at-least export some of the file descriptor<->handle functions in ntdll so we can turn the FD provided by VK_EXTERNAL_MEMORY_fd into a handle for the win32 extension.
We already have fd<->handle conversion functions in ntdll, you should be able to build something on top of that.
Yeah, I did build the shared resource functions off of those conversion functions in ntdll, then exported the shared resource functions.
Would you rather we keep this or export the fd<->handle conversion functions themselves? If we just export them, what object type would we store the vulkan resource as?
They are already exported. You should be able to build what you need on top of files, or mappings, or some other kernel primitive, and not change ntdll at all.
Adding new kernel object types or changing the server should be the last resort, so if you want to do that, you'll have to make a very convincing argument that the existing primitives can't be used for this.
Ah, I didn't see that, should have looked. I can try to redo the patchset using those in winevulkan. One issue though is the use of KMT handles, which are pretty much just resource IDs like PIDs or TIDs. How do propose we implement that without support in the server? Maybe we could use ConvertToGlobalHandle? The issue then is that the global handle isn't supposed to contain a reference to the resource.
Derek Lesho dlesho@codeweavers.com writes:
Ah, I didn't see that, should have looked. I can try to redo the patchset using those in winevulkan. One issue though is the use of KMT handles, which are pretty much just resource IDs like PIDs or TIDs. How do propose we implement that without support in the server? Maybe we could use ConvertToGlobalHandle? The issue then is that the global handle isn't supposed to contain a reference to the resource.
It depends on how the IDs are supposed to behave, but in any case ConvertToGlobalHandle() is a Win95 abomination that you should stay far away from ;-)
On 11/4/19 3:58 PM, Alexandre Julliard wrote:
Derek Lesho dlesho@codeweavers.com writes:
Ah, I didn't see that, should have looked. I can try to redo the patchset using those in winevulkan. One issue though is the use of KMT handles, which are pretty much just resource IDs like PIDs or TIDs. How do propose we implement that without support in the server? Maybe we could use ConvertToGlobalHandle? The issue then is that the global handle isn't supposed to contain a reference to the resource.
It depends on how the IDs are supposed to behave,
Reading from https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/chap38.htm..., VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT says that the ID is global, and does not contain a reference to the resource. We could possibly use a shared memory region in winevulkan to map KMT handle IDs to the names of resource objects, since object names also don't hold a reference to the object. What do you think about this solution?
but in any case ConvertToGlobalHandle() is a Win95 abomination that you should stay far away from ;-)