Signed-off-by: Roderick Colenbrander thunderbird2k@gmail.com --- dlls/winevulkan/Makefile.in | 3 +- dlls/winevulkan/make_vulkan | 192 ++++++++++++++++++++++++++++++++++++++- dlls/winevulkan/vulkan.c | 13 +-- 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/make_vulkan b/dlls/winevulkan/make_vulkan index b786354168..5bac258294 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -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.c b/dlls/winevulkan/vulkan.c index 72e4a95857..06139d1d22 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; @@ -149,6 +139,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", debugstr_a(name)); return NULL; } 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 */