diff --git a/dlls/winevulkan/Makefile.in b/dlls/winevulkan/Makefile.in index 859c731c6e4..a3c40bd3986 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 fd2fd7bd779..c22619af1bf 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -65,6 +65,8 @@ LOGGER.addHandler(logging.StreamHandler()) # Filenames to create. WINE_VULKAN_H = "../../include/wine/vulkan.h" WINE_VULKAN_DRIVER_H = "../../include/wine/vulkan_driver.h" +WINE_VULKAN_THUNKS_C = "vulkan_thunks.c" +WINE_VULKAN_THUNKS_H = "vulkan_thunks.h" # Functions part of our winevulkan graphics driver interface. @@ -76,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" : True }, } @@ -256,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. @@ -303,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. """ @@ -359,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): @@ -628,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) @@ -663,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' """ @@ -687,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 @@ -854,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") + + 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") @@ -1245,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 2152cb15fef..9d2cdd2fa48 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; @@ -148,6 +138,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 6b83e875a29..56881378332 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 00000000000..57d4f3549b2 --- /dev/null +++ b/dlls/winevulkan/vulkan_thunks.c @@ -0,0 +1,106 @@ +/* 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 void WINAPI wine_vkDestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator) +{ + FIXME("stub: %p, %p\n", instance, pAllocator); +} + +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 00000000000..dbfd83c1156 --- /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 */