[PATCH 08/10] winex11: Add initial vkCreateInstance implementation.

Roderick Colenbrander <[email protected]>
Newsgroups gmane.comp.emulators.wine.patches
Message-ID <[email protected]>
Signed-off-by: Roderick Colenbrander <[email protected]>
---
 dlls/winex11.drv/vulkan.c         | 81 +++++++++++++++++++++++++++++++++++++--
 dlls/winex11.drv/vulkan_private.h | 27 +++++++++++++
 2 files changed, 105 insertions(+), 3 deletions(-)

diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c
index 8632c46010..f1c41908d8 100644
--- a/dlls/winex11.drv/vulkan.c
+++ b/dlls/winex11.drv/vulkan.c
@@ -39,6 +39,12 @@ WINE_DEFAULT_DEBUG_CHANNEL(vulkan);
 
 void* WINAPI X11DRV_vk_icdGetInstanceProcAddr(VkInstance instance, const char* pName);
 
+/* Function pointers to native calls we need. Define them by hand instead of using a MAKE_FUNCPTR macro
+ * to avoid messing with calling conventions.
+ */
+static VkResult (*pvkCreateInstance)(const VkInstanceCreateInfo*, const VkAllocationCallbacks*, VkInstance*);
+static void (*pvkDestroyInstance)(VkInstance, const VkAllocationCallbacks*);
+
 /* All Vulkan structures use this structure for the first elements. */
 struct wine_vk_structure_header
 {
@@ -47,6 +53,19 @@ struct wine_vk_structure_header
 };
 
 
+static void *wine_vk_alloc_dispatchable_object(size_t size)
+{
+    struct wine_vk_dispatchable_object *object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
+
+    if (!object)
+        return NULL;
+
+    /* Set special header for ICD loader. */
+    ((struct wine_vk_base*)object)->loader_magic = VULKAN_ICD_MAGIC_VALUE;
+
+    return object;
+}
+
 static BOOL wine_vk_init(void)
 {
     static BOOL init_done = FALSE;
@@ -57,6 +76,11 @@ static BOOL wine_vk_init(void)
 
     if (!(vulkan_handle = wine_dlopen(SONAME_LIBVULKAN, RTLD_NOW, NULL, 0))) return FALSE;
 
+#define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(vulkan_handle, #f, NULL, 0)) == NULL) return FALSE;
+LOAD_FUNCPTR(vkCreateInstance)
+LOAD_FUNCPTR(vkDestroyInstance)
+#undef LOAD_FUNCPTR
+
     return TRUE;
 }
 
@@ -109,15 +133,66 @@ static void wine_vk_instance_dump_create_info(const VkInstanceCreateInfo *info)
     }
 }
 
+/* Helper function used for freeing an instance structure. This function supports full
+ * and partial object cleanups and can thus be used for vkCreateInstance failures.
+ */
+static void wine_vk_instance_free(struct VkInstance_T *instance)
+{
+    if (!instance)
+        return;
+
+    if (instance->instance)
+        pvkDestroyInstance(instance->instance, NULL /* pAllocator */);
+
+    HeapFree(GetProcessHeap(), 0, instance);
+}
+
 VkResult WINAPI X11DRV_vkCreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
         VkInstance *pInstance)
 {
-    FIXME("stub: %p, %p, %p\n", pCreateInfo, pAllocator, pInstance);
+    VkInstance instance = NULL;
+    VkResult res;
+
+    TRACE("pCreateInfo %p, pAllocater %p, pInstance %p\n", pCreateInfo, pAllocator, pInstance);
+
+    if (pAllocator)
+    {
+        FIXME("Support for allocation callbacks not implemented yet\n");
+    }
 
     wine_vk_instance_dump_create_info(pCreateInfo);
-    return VK_ERROR_INCOMPATIBLE_DRIVER;
-}
+    if (pCreateInfo->enabledExtensionCount > 0)
+    {
+        FIXME("Extensions are not supported yet, aborting!\n");
+        res = VK_ERROR_INCOMPATIBLE_DRIVER;
+        goto err;
+    }
 
+    instance = wine_vk_alloc_dispatchable_object(sizeof(*instance));
+    if (!instance)
+    {
+        ERR("Failed to allocate memory for instance\n");
+        res = VK_ERROR_OUT_OF_HOST_MEMORY;
+        goto err;
+    }
+
+    res = pvkCreateInstance(pCreateInfo, NULL /* pAllocator */, &instance->instance);
+    if (res != VK_SUCCESS)
+    {
+        ERR("Failed to create instance, res=%d\n", res);
+        goto err;
+    }
+
+    *pInstance = instance;
+    TRACE("Done, instance=%p wrapped_instance=%p\n", instance, instance->instance);
+    return VK_SUCCESS;
+
+err:
+    if (instance)
+        wine_vk_instance_free(instance);
+
+    return res;
+}
 
 VkResult WINAPI X11DRV_vkEnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pPropertyCount,
         VkExtensionProperties* pProperties)
diff --git a/dlls/winex11.drv/vulkan_private.h b/dlls/winex11.drv/vulkan_private.h
index bb722ddb06..d3fa7be167 100644
--- a/dlls/winex11.drv/vulkan_private.h
+++ b/dlls/winex11.drv/vulkan_private.h
@@ -26,6 +26,33 @@
 
 #ifdef SONAME_LIBVULKAN
 
+/* Magic value defined by Vulkan ICD / Loader spec */
+#define VULKAN_ICD_MAGIC_VALUE 0x01CDC0DE
+
+/* Base 'class' for our Vulkan dispatchable objects such as VkDevice and VkInstance.
+ * This structure MUST be the first element of a dispatchable object as the ICD
+ * loader depends on it. For now only contains loader_magic, but over time more common
+ * functionality is expected.
+ */
+struct wine_vk_base
+{
+    /* Special section in each dispatchable object for use by the ICD loader for
+     * storing dispatch tables. The start contains a magical value '0x01CDC0DE'.
+     */
+    uintptr_t loader_magic;
+};
+
+/* Vulkan defines handles for objects through VK_DEFINE_HANDLE. As part of this
+ * it defines forward declarations for structs '_T', which the implementor (us)
+ * can use.
+ */
+struct VkInstance_T
+{
+    struct wine_vk_base base;
+    VkInstance instance; /* native instance */
+};
+
+
 struct vulkan_func
 {
     const char *name;
-- 
2.13.6
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.