[PATCH 3/4] winevulkan: Add support for VK_KHR_external_memory_fd.

Derek Lesho dlesho at codeweavers.com
Wed Oct 30 11:46:49 CDT 2019


Signed-off-by: Derek Lesho <dlesho at 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;
 
-- 
2.23.0




More information about the wine-devel mailing list