[PATCH v3 09/10] winevulkan: Add instance funcs stubs.

Roderick Colenbrander thunderbird2k at gmail.com
Mon Feb 26 01:14:34 CST 2018


Signed-off-by: Roderick Colenbrander <thunderbird2k at gmail.com>
---
 dlls/winevulkan/Makefile.in      |   3 +-
 dlls/winevulkan/vulkan.c         |  13 +--
 dlls/winevulkan/vulkan.py        | 192 ++++++++++++++++++++++++++++++++++++++-
 dlls/winevulkan/vulkan_private.h |  12 +++
 dlls/winevulkan/vulkan_thunks.c  | 102 +++++++++++++++++++++
 dlls/winevulkan/vulkan_thunks.h  |   9 ++
 6 files changed, 316 insertions(+), 15 deletions(-)
 create mode 100644 dlls/winevulkan/vulkan_thunks.c
 create mode 100644 dlls/winevulkan/vulkan_thunks.h

diff --git a/dlls/winevulkan/Makefile.in b/dlls/winevulkan/Makefile.in
index 859c731c6e..a3c40bd398 100644
--- a/dlls/winevulkan/Makefile.in
+++ b/dlls/winevulkan/Makefile.in
@@ -2,6 +2,7 @@ MODULE    = winevulkan.dll
 IMPORTS   = user32 gdi32
 
 C_SRCS = \
-	vulkan.c
+	vulkan.c \
+	vulkan_thunks.c
 
 RC_SRCS = version.rc
diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c
index c43903d767..6a0913a59b 100644
--- a/dlls/winevulkan/vulkan.c
+++ b/dlls/winevulkan/vulkan.c
@@ -38,16 +38,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(vulkan);
  */
 #define WINE_VULKAN_ICD_VERSION 4
 
-#ifndef ARRAY_SIZE
-#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
-#endif
-
-struct vulkan_func
-{
-    const char *name;
-    void *func;
-};
-
 static void *wine_vk_get_global_proc_addr(const char *name);
 
 static const struct vulkan_funcs *vk_funcs = NULL;
@@ -151,6 +141,9 @@ static PFN_vkVoidFunction WINAPI wine_vkGetInstanceProcAddr(VkInstance instance,
         return NULL;
     }
 
+    func = wine_vk_get_instance_proc_addr(name);
+    if (func) return func;
+
     FIXME("Unsupported device or instance function: '%s'\n", name);
     return NULL;
 }
diff --git a/dlls/winevulkan/vulkan.py b/dlls/winevulkan/vulkan.py
index b786354168..5bac258294 100755
--- a/dlls/winevulkan/vulkan.py
+++ b/dlls/winevulkan/vulkan.py
@@ -78,15 +78,18 @@ DRIVER_VERSION = 1
 # This are regular device / instance functions for which we need
 # to more work compared to a regular thunk  or because they are
 # part of the driver interface.
+# - dispatch set whether we need a function pointer in the device
+#   / instance dispatch table.
 # - driver sets whether the api is part of the driver interface.
+# - thunk sets whether to create a thunk in vulkan_thunks.c.
 FUNCTION_OVERRIDES = {
     # Global functions
-    "vkCreateInstance" : {"driver" : True},
-    "vkEnumerateInstanceExtensionProperties" : {"driver" : True},
-    "vkGetInstanceProcAddr": {"driver" : True},
+    "vkCreateInstance" : {"dispatch" : False, "driver" : True, "thunk" : False},
+    "vkEnumerateInstanceExtensionProperties" : {"dispatch" : False, "driver" : True, "thunk" : False},
+    "vkGetInstanceProcAddr": {"dispatch" : False, "driver" : True, "thunk" : False},
 
     # Instance functions
-    "vkDestroyInstance" : {"driver" : True},
+    "vkDestroyInstance" : {"dispatch" : True, "driver" : True, "thunk" : False },
 }
 
 
@@ -258,7 +261,9 @@ class VkFunction(object):
 
         # For some functions we need some extra metadata from FUNCTION_OVERRIDES.
         func_info = FUNCTION_OVERRIDES.get(self.name, None)
+        self.dispatch = func_info["dispatch"] if func_info is not None else True
         self.driver = func_info["driver"] if func_info is not None else False
+        self.thunk_needed = func_info["thunk"] if func_info is not None else True
 
         # Required is set while parsing which APIs and types are required
         # and is used by the code generation.
@@ -305,6 +310,12 @@ class VkFunction(object):
     def is_required(self):
         return self.required
 
+    def needs_dispatch(self):
+        return self.dispatch
+
+    def needs_thunk(self):
+        return self.thunk_needed
+
     def pfn(self, call_conv=None, conv=False):
         """ Create function pointer. """
 
@@ -361,6 +372,48 @@ class VkFunction(object):
 
         return proto
 
+    def stub(self, call_conv=None, prefix=None):
+        stub = self.prototype(call_conv=call_conv, prefix=prefix)
+        stub += "\n{\n"
+        stub += "    {0}".format(self.trace(message="stub: ", trace_func="FIXME"))
+
+        if self.type == "VkResult":
+            stub += "    return VK_ERROR_OUT_OF_HOST_MEMORY;\n"
+        elif self.type == "VkBool32":
+            stub += "    return VK_FALSE;\n"
+
+        stub += "}\n\n"
+        return stub
+
+    def trace(self, message=None, trace_func=None):
+        """ Create a trace string including all parameters.
+
+        Args:
+            message (str, optional): text to print at start of trace message e.g. 'stub: '
+            trace_func (str, optional): used to override trace function e.g. FIXME, printf, etcetera.
+        """
+        if trace_func is not None:
+            trace = "{0}(\"".format(trace_func)
+        else:
+            trace = "TRACE(\""
+
+        if message is not None:
+            trace += message
+
+        # First loop is for all the format strings.
+        trace += ", ".join([p.format_string() for p in self.params])
+        trace += "\\n\""
+
+        # Second loop for parameter names and optional conversions.
+        for param in self.params:
+            if param.format_conv is not None:
+                trace += ", " + param.format_conv.format(param.name)
+            else:
+                trace += ", {0}".format(param.name)
+        trace += ");\n"
+
+        return trace
+
 
 class VkFunctionPointer(object):
     def __init__(self, _type, name, members):
@@ -630,6 +683,8 @@ class VkParam(object):
         self.handle = type_info["data"] if type_info["category"] == "handle" else None
         self.struct = type_info["data"] if type_info["category"] == "struct" else None
 
+        self._set_format_string()
+
     def __repr__(self):
         return "{0} {1} {2} {3} {4}".format(self.const, self.type, self.pointer, self.name, self.array_len, self.dyn_array_len)
 
@@ -665,6 +720,49 @@ class VkParam(object):
 
         return VkParam(type_info, const=const, pointer=pointer, name=name, array_len=array_len, dyn_array_len=dyn_array_len)
 
+    def _set_format_string(self):
+        """ Internal helper function to be used by constructor to set format string. """
+
+        # Determine a format string used by code generation for traces.
+        # 64-bit types need a conversion function.
+        self.format_conv = None
+        if self.is_static_array() or self.is_pointer():
+            self.format_str = "%p"
+        else:
+            if self.type_info["category"] == "bitmask":
+                self.format_str = "%#x"
+            elif self.type_info["category"] == "enum":
+                self.format_str = "%d"
+            elif self.is_handle():
+                # We use uint64_t for non-dispatchable handles as opposed to pointers
+                # for dispatchable handles.
+                if self.handle.is_dispatchable():
+                    self.format_str = "%p"
+                else:
+                    self.format_str = "0x%s"
+                    self.format_conv = "wine_dbgstr_longlong({0})"
+            elif self.type == "float":
+                self.format_str = "%f"
+            elif self.type == "int":
+                self.format_str = "%d"
+            elif self.type == "int32_t":
+                self.format_str = "%d"
+            elif self.type == "size_t":
+                self.format_str = "0x%s"
+                self.format_conv = "wine_dbgstr_longlong({0})"
+            elif self.type in ["uint32_t", "VkBool32"]:
+                self.format_str = "%u"
+            elif self.type in ["uint64_t", "VkDeviceSize"]:
+                self.format_str = "0x%s"
+                self.format_conv = "wine_dbgstr_longlong({0})"
+            elif self.type == "HANDLE":
+                self.format_str = "%p"
+            elif self.type in ["VisualID", "xcb_visualid_t", "RROutput"]:
+                # Don't care about Linux specific types.
+                self.format_str = ""
+            else:
+                LOGGER.warn("Unhandled type: {0}".format(self.type_info))
+
     def definition(self, postfix=None):
         """ Return prototype for the parameter. E.g. 'const char *foo' """
 
@@ -689,6 +787,17 @@ class VkParam(object):
 
         return proto
 
+    def direction(self):
+        """ Returns parameter direction: input, output, input_output.
+
+        Parameter direction in Vulkan is not straight-forward, which this function determines.
+        """
+
+        return self._direction
+
+    def format_string(self):
+        return self.format_str
+
     def is_const(self):
         return self.const is not None
 
@@ -856,6 +965,75 @@ class VkGenerator(object):
     def __init__(self, registry):
         self.registry = registry
 
+    def generate_thunks_c(self, f, prefix):
+        f.write("/* Automatically generated from Vulkan vk.xml; DO NOT EDIT! */\n\n")
+
+        f.write("#include \"config.h\"\n")
+        f.write("#include \"wine/port.h\"\n\n")
+
+        f.write("#include \"wine/debug.h\"\n")
+        f.write("#include \"wine/vulkan.h\"\n")
+        f.write("#include \"wine/vulkan_driver.h\"\n")
+        f.write("#include \"vulkan_private.h\"\n\n")
+
+        f.write("WINE_DEFAULT_DEBUG_CHANNEL(vulkan);\n\n")
+
+        # Create thunks for instance functions.
+        # Global functions don't go through the thunks.
+        for vk_func in self.registry.funcs.values():
+            if not vk_func.is_required():
+                continue
+
+            if vk_func.is_global_func():
+                continue
+
+            # We don't support device functions yet as other plumbing
+            # is needed first.
+            if vk_func.is_device_func():
+                continue
+
+            if not vk_func.needs_thunk():
+                continue
+
+            f.write("static " + vk_func.stub(prefix=prefix, call_conv="WINAPI"))
+
+        f.write("static const struct vulkan_func vk_instance_dispatch_table[] =\n{\n")
+        for vk_func in self.registry.instance_funcs:
+            if not vk_func.is_required():
+                continue
+
+            if not vk_func.needs_dispatch():
+                LOGGER.debug("skipping {0} in instance dispatch table".format(vk_func.name))
+                continue
+
+            f.write("    {{\"{0}\", &{1}{0}}},\n".format(vk_func.name, prefix))
+        f.write("};\n\n")
+
+        f.write("void *wine_vk_get_instance_proc_addr(const char *name)\n")
+        f.write("{\n")
+        f.write("    unsigned int i;\n")
+        f.write("    for (i = 0; i < ARRAY_SIZE(vk_instance_dispatch_table); i++)\n")
+        f.write("    {\n")
+        f.write("        if (strcmp(vk_instance_dispatch_table[i].name, name) == 0)\n")
+        f.write("        {\n")
+        f.write("            TRACE(\"Found pName=%s in instance table\\n\", name);\n")
+        f.write("            return vk_instance_dispatch_table[i].func;\n")
+        f.write("        }\n")
+        f.write("    }\n")
+        f.write("    return NULL;\n")
+        f.write("}\n\n")
+
+    def generate_thunks_h(self, f, prefix):
+        f.write("/* Automatically generated from Vulkan vk.xml; DO NOT EDIT! */\n\n")
+
+        f.write("#ifndef __WINE_VULKAN_THUNKS_H\n")
+        f.write("#define __WINE_VULKAN_THUNKS_H\n\n")
+
+        f.write("/* For use by vk_icdGetInstanceProcAddr / vkGetInstanceProcAddr */\n")
+        f.write("void *wine_vk_get_instance_proc_addr(const char *name) DECLSPEC_HIDDEN;\n\n")
+
+        f.write("#endif /* __WINE_VULKAN_THUNKS_H */\n")
+
     def generate_vulkan_h(self, f):
         f.write("/* Automatically generated from Vulkan vk.xml; DO NOT EDIT! */\n\n")
         f.write("#ifndef __WINE_VULKAN_H\n")
@@ -1247,5 +1425,11 @@ def main():
     with open(WINE_VULKAN_DRIVER_H, "w") as f:
         generator.generate_vulkan_driver_h(f)
 
+    with open(WINE_VULKAN_THUNKS_H, "w") as f:
+        generator.generate_thunks_h(f, "wine_")
+
+    with open(WINE_VULKAN_THUNKS_C, "w") as f:
+        generator.generate_thunks_c(f, "wine_")
+
 if __name__ == "__main__":
     main()
diff --git a/dlls/winevulkan/vulkan_private.h b/dlls/winevulkan/vulkan_private.h
index 6b83e875a2..5688137833 100644
--- a/dlls/winevulkan/vulkan_private.h
+++ b/dlls/winevulkan/vulkan_private.h
@@ -20,9 +20,21 @@
 #ifndef __WINE_VULKAN_PRIVATE_H
 #define __WINE_VULKAN_PRIVATE_H
 
+#include "vulkan_thunks.h"
+
 /* Magic value defined by Vulkan ICD / Loader spec */
 #define VULKAN_ICD_MAGIC_VALUE 0x01CDC0DE
 
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
+#endif
+
+struct vulkan_func
+{
+    const char *name;
+    void *func;
+};
+
 /* 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
diff --git a/dlls/winevulkan/vulkan_thunks.c b/dlls/winevulkan/vulkan_thunks.c
new file mode 100644
index 0000000000..6578f082c8
--- /dev/null
+++ b/dlls/winevulkan/vulkan_thunks.c
@@ -0,0 +1,102 @@
+/* Automatically generated from Vulkan vk.xml; DO NOT EDIT! */
+
+#include "config.h"
+#include "wine/port.h"
+
+#include "wine/debug.h"
+#include "wine/vulkan.h"
+#include "wine/vulkan_driver.h"
+#include "vulkan_private.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(vulkan);
+
+static VkResult WINAPI wine_vkCreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDevice *pDevice)
+{
+    FIXME("stub: %p, %p, %p, %p\n", physicalDevice, pCreateInfo, pAllocator, pDevice);
+    return VK_ERROR_OUT_OF_HOST_MEMORY;
+}
+
+static VkResult WINAPI wine_vkEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, const char *pLayerName, uint32_t *pPropertyCount, VkExtensionProperties *pProperties)
+{
+    FIXME("stub: %p, %p, %p, %p\n", physicalDevice, pLayerName, pPropertyCount, pProperties);
+    return VK_ERROR_OUT_OF_HOST_MEMORY;
+}
+
+static VkResult WINAPI wine_vkEnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount, VkLayerProperties *pProperties)
+{
+    FIXME("stub: %p, %p, %p\n", physicalDevice, pPropertyCount, pProperties);
+    return VK_ERROR_OUT_OF_HOST_MEMORY;
+}
+
+static VkResult WINAPI wine_vkEnumeratePhysicalDevices(VkInstance instance, uint32_t *pPhysicalDeviceCount, VkPhysicalDevice *pPhysicalDevices)
+{
+    FIXME("stub: %p, %p, %p\n", instance, pPhysicalDeviceCount, pPhysicalDevices);
+    return VK_ERROR_OUT_OF_HOST_MEMORY;
+}
+
+static void WINAPI wine_vkGetPhysicalDeviceFeatures(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures *pFeatures)
+{
+    FIXME("stub: %p, %p\n", physicalDevice, pFeatures);
+}
+
+static void WINAPI wine_vkGetPhysicalDeviceFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties *pFormatProperties)
+{
+    FIXME("stub: %p, %d, %p\n", physicalDevice, format, pFormatProperties);
+}
+
+static VkResult WINAPI wine_vkGetPhysicalDeviceImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkImageFormatProperties *pImageFormatProperties)
+{
+    FIXME("stub: %p, %d, %d, %d, %#x, %#x, %p\n", physicalDevice, format, type, tiling, usage, flags, pImageFormatProperties);
+    return VK_ERROR_OUT_OF_HOST_MEMORY;
+}
+
+static void WINAPI wine_vkGetPhysicalDeviceMemoryProperties(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties *pMemoryProperties)
+{
+    FIXME("stub: %p, %p\n", physicalDevice, pMemoryProperties);
+}
+
+static void WINAPI wine_vkGetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties *pProperties)
+{
+    FIXME("stub: %p, %p\n", physicalDevice, pProperties);
+}
+
+static void WINAPI wine_vkGetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice, uint32_t *pQueueFamilyPropertyCount, VkQueueFamilyProperties *pQueueFamilyProperties)
+{
+    FIXME("stub: %p, %p, %p\n", physicalDevice, pQueueFamilyPropertyCount, pQueueFamilyProperties);
+}
+
+static void WINAPI wine_vkGetPhysicalDeviceSparseImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkSampleCountFlagBits samples, VkImageUsageFlags usage, VkImageTiling tiling, uint32_t *pPropertyCount, VkSparseImageFormatProperties *pProperties)
+{
+    FIXME("stub: %p, %d, %d, %d, %#x, %d, %p, %p\n", physicalDevice, format, type, samples, usage, tiling, pPropertyCount, pProperties);
+}
+
+static const struct vulkan_func vk_instance_dispatch_table[] =
+{
+    {"vkCreateDevice", &wine_vkCreateDevice},
+    {"vkDestroyInstance", &wine_vkDestroyInstance},
+    {"vkEnumerateDeviceExtensionProperties", &wine_vkEnumerateDeviceExtensionProperties},
+    {"vkEnumerateDeviceLayerProperties", &wine_vkEnumerateDeviceLayerProperties},
+    {"vkEnumeratePhysicalDevices", &wine_vkEnumeratePhysicalDevices},
+    {"vkGetPhysicalDeviceFeatures", &wine_vkGetPhysicalDeviceFeatures},
+    {"vkGetPhysicalDeviceFormatProperties", &wine_vkGetPhysicalDeviceFormatProperties},
+    {"vkGetPhysicalDeviceImageFormatProperties", &wine_vkGetPhysicalDeviceImageFormatProperties},
+    {"vkGetPhysicalDeviceMemoryProperties", &wine_vkGetPhysicalDeviceMemoryProperties},
+    {"vkGetPhysicalDeviceProperties", &wine_vkGetPhysicalDeviceProperties},
+    {"vkGetPhysicalDeviceQueueFamilyProperties", &wine_vkGetPhysicalDeviceQueueFamilyProperties},
+    {"vkGetPhysicalDeviceSparseImageFormatProperties", &wine_vkGetPhysicalDeviceSparseImageFormatProperties},
+};
+
+void *wine_vk_get_instance_proc_addr(const char *name)
+{
+    unsigned int i;
+    for (i = 0; i < ARRAY_SIZE(vk_instance_dispatch_table); i++)
+    {
+        if (strcmp(vk_instance_dispatch_table[i].name, name) == 0)
+        {
+            TRACE("Found pName=%s in instance table\n", name);
+            return vk_instance_dispatch_table[i].func;
+        }
+    }
+    return NULL;
+}
+
diff --git a/dlls/winevulkan/vulkan_thunks.h b/dlls/winevulkan/vulkan_thunks.h
new file mode 100644
index 0000000000..dbfd83c115
--- /dev/null
+++ b/dlls/winevulkan/vulkan_thunks.h
@@ -0,0 +1,9 @@
+/* Automatically generated from Vulkan vk.xml; DO NOT EDIT! */
+
+#ifndef __WINE_VULKAN_THUNKS_H
+#define __WINE_VULKAN_THUNKS_H
+
+/* For use by vk_icdGetInstanceProcAddr / vkGetInstanceProcAddr */
+void *wine_vk_get_instance_proc_addr(const char *name) DECLSPEC_HIDDEN;
+
+#endif /* __WINE_VULKAN_THUNKS_H */
-- 
2.14.3




More information about the wine-devel mailing list