winevulkan: Add instance funcs stubs.

Signed-off-by: Roderick Colenbrander <thunderbird2k@gmail.com>
Signed-off-by: Józef Kucia <jkucia@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Roderick Colenbrander 2018-03-01 16:37:04 +01:00 committed by Alexandre Julliard
parent 75b68a8585
commit 586a18995f
6 changed files with 322 additions and 15 deletions

View File

@ -2,6 +2,7 @@ MODULE = winevulkan.dll
IMPORTS = user32 gdi32
C_SRCS = \
vulkan.c
vulkan.c \
vulkan_thunks.c
RC_SRCS = version.rc

View File

@ -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()

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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 */