2 # Wine Vulkan generator
4 # Copyright 2017-2018 Roderick Colenbrander
6 # This library is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU Lesser General Public
8 # License as published by the Free Software Foundation; either
9 # version 2.1 of the License, or (at your option) any later version.
11 # This library is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # Lesser General Public License for more details.
16 # You should have received a copy of the GNU Lesser General Public
17 # License along with this library; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 import xml.etree.ElementTree as ET
26 from collections import OrderedDict
27 from collections.abc import Sequence
30 # This script generates code for a Wine Vulkan ICD driver from Vulkan's vk.xml.
31 # Generating the code is like 10x worse than OpenGL, which is mostly a calling
32 # convention passthrough.
34 # The script parses vk.xml and maps functions and types to helper objects. These
35 # helper objects simplify the xml parsing and map closely to the Vulkan types.
36 # The code generation utilizes the helper objects during code generation and
37 # most of the ugly work is carried out by these objects.
39 # Vulkan ICD challenges:
40 # - Vulkan ICD loader (vulkan-1.dll) relies on a section at the start of
41 # 'dispatchable handles' (e.g. VkDevice, VkInstance) for it to insert
42 # its private data. It uses this area to stare its own dispatch tables
43 # for loader internal use. This means any dispatchable objects need wrapping.
45 # - Vulkan structures have different alignment between win32 and 32-bit Linux.
46 # This means structures with alignment differences need conversion logic.
47 # Often structures are nested, so the parent structure may not need any
48 # conversion, but some child may need some.
50 # vk.xml parsing challenges:
51 # - Contains type data for all platforms (generic Vulkan, Windows, Linux,..).
52 # Parsing of extension information required to pull in types and functions
53 # we really want to generate. Just tying all the data together is tricky.
55 # - Extensions can affect core types e.g. add new enum values, bitflags or
56 # additional structure chaining through 'pNext' / 'sType'.
58 # - Arrays are used all over the place for parameters or for structure members.
59 # Array length is often stored in a previous parameter or another structure
60 # member and thus needs careful parsing.
62 LOGGER = logging.Logger("vulkan")
63 LOGGER.addHandler(logging.StreamHandler())
65 # Filenames to create.
66 WINE_VULKAN_H = "../../include/wine/vulkan.h"
67 WINE_VULKAN_DRIVER_H = "../../include/wine/vulkan_driver.h"
68 WINE_VULKAN_THUNKS_C = "vulkan_thunks.c"
69 WINE_VULKAN_THUNKS_H = "vulkan_thunks.h"
71 # Extension enum values start at a certain offset (EXT_BASE).
72 # Relative to the offset each extension has a block (EXT_BLOCK_SIZE)
74 # Start for a given extension is:
75 # EXT_BASE + (extension_number-1) * EXT_BLOCK_SIZE
79 # In general instance extensions can't be automatically generated
80 # and need custom wrappers due to e.g. win32 / X11 specific code.
81 # List of supported instance extensions.
82 SUPPORTED_EXTENSIONS = [
84 "VK_KHR_win32_surface",
88 # Functions part of our winevulkan graphics driver interface.
89 # DRIVER_VERSION should be bumped on any change to driver interface
90 # in FUNCTION_OVERRIDES
93 # Table of functions for which we have a special implementation.
94 # This are regular device / instance functions for which we need
95 # to more work compared to a regular thunk or because they are
96 # part of the driver interface.
97 # - dispatch set whether we need a function pointer in the device
98 # / instance dispatch table.
99 # - driver sets whether the api is part of the driver interface.
100 # - thunk sets whether to create a thunk in vulkan_thunks.c.
101 FUNCTION_OVERRIDES = {
103 "vkCreateInstance" : {"dispatch" : False, "driver" : True, "thunk" : False},
104 "vkEnumerateInstanceExtensionProperties" : {"dispatch" : False, "driver" : True, "thunk" : False},
105 "vkGetInstanceProcAddr": {"dispatch" : False, "driver" : True, "thunk" : False},
108 "vkCreateDevice" : {"dispatch" : True, "driver" : False, "thunk" : False},
109 "vkDestroyInstance" : {"dispatch" : True, "driver" : True, "thunk" : False },
110 "vkEnumerateDeviceExtensionProperties" : {"dispatch" : True, "driver" : False, "thunk" : False},
111 "vkEnumeratePhysicalDevices" : {"dispatch" : True, "driver" : False, "thunk" : False},
114 "vkAllocateCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : False},
115 "vkCmdExecuteCommands" : {"dispatch" : True, "driver" : False, "thunk" : False},
116 "vkDestroyDevice" : {"dispatch" : True, "driver" : False, "thunk" : False},
117 "vkFreeCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : False},
118 "vkGetDeviceProcAddr" : {"dispatch" : True, "driver" : True, "thunk" : False},
119 "vkGetDeviceQueue" : {"dispatch": True, "driver" : False, "thunk" : False},
120 "vkQueueSubmit" : {"dispatch": True, "driver" : False, "thunk" : False},
123 "vkDestroySurfaceKHR" : {"dispatch" : True, "driver" : True, "thunk" : False},
124 "vkGetPhysicalDeviceSurfaceSupportKHR" : {"dispatch" : True, "driver" : True, "thunk" : False},
125 "vkGetPhysicalDeviceSurfaceCapabilitiesKHR" : {"dispatch" : True, "driver" : True, "thunk" : False},
126 "vkGetPhysicalDeviceSurfaceFormatsKHR" : {"dispatch" : True, "driver" : True, "thunk" : False},
127 "vkGetPhysicalDeviceSurfacePresentModesKHR" : {"dispatch" : True, "driver" : True, "thunk" : False},
129 # VK_KHR_win32_surface
130 "vkCreateWin32SurfaceKHR" : {"dispatch" : True, "driver" : True, "thunk" : False},
131 "vkGetPhysicalDeviceWin32PresentationSupportKHR" : {"dispatch" : True, "driver" : True, "thunk" : False},
134 "vkAcquireNextImageKHR": {"dispatch" : True, "driver" : True, "thunk" : False},
135 "vkCreateSwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : False},
136 "vkDestroySwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : False},
137 "vkGetSwapchainImagesKHR": {"dispatch" : True, "driver" : True, "thunk" : False},
138 "vkQueuePresentKHR": {"dispatch" : True, "driver" : True, "thunk" : False},
142 class Direction(Enum):
143 """ Parameter direction: input, output, input_output. """
149 class VkBaseType(object):
150 def __init__(self, name, _type, requires=None):
151 """ Vulkan base type class.
153 VkBaseType is mostly used by Vulkan to define its own
154 base types like VkFlags through typedef out of e.g. uint32_t.
157 name (:obj:'str'): Name of the base type.
158 _type (:obj:'str'): Underlaying type
159 requires (:obj:'str', optional): Other types required.
160 Often bitmask values pull in a *FlagBits type.
164 self.requires = requires
165 self.required = False
167 def definition(self):
168 text = "typedef {0} {1};\n".format(self.type, self.name)
172 class VkConstant(object):
173 def __init__(self, name, value):
177 def definition(self):
178 text = "#define {0} {1}\n".format(self.name, self.value)
182 class VkDefine(object):
183 def __init__(self, name, value):
188 def from_xml(define):
189 name_elem = define.find("name")
191 if name_elem is None:
192 # <type category="define" name="some_name">some_value</type>
193 # At the time of writing there is only 1 define of this category
194 # 'VK_DEFINE_NON_DISPATCHABLE_HANDLE'.
195 name = define.attrib.get("name")
197 # We override behavior of VK_DEFINE_NON_DISPATCHABLE handle as the default
198 # definition various between 64-bit (uses pointers) and 32-bit (uses uint64_t).
199 # This complicates TRACEs in the thunks, so just use uint64_t.
200 if name == "VK_DEFINE_NON_DISPATCHABLE_HANDLE":
201 value = "#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object;"
204 return VkDefine(name, value)
206 # With a name element the structure is like:
207 # <type category="define"><name>some_name</name>some_value</type>
208 name = name_elem.text
210 # VK_API_VERSION is a deprecated constant and we don't really want to parse it or generate
211 # code for it. However the vk.xml feature section still references it.
212 if name == "VK_API_VERSION":
213 return VkDefine(name, "")
215 # The body of the define is basically unstructured C code. It is not meant for easy parsing.
216 # Some lines contain deprecated values or comments, which we try to filter out.
218 for line in define.text.splitlines():
219 # Skip comments or deprecated values.
226 if child.tail is not None:
229 return VkDefine(name, value.rstrip(' '))
231 def definition(self):
232 if self.value is None:
235 # Nothing to do as the value was already put in the right form during parsing.
236 return "{0}\n".format(self.value)
239 class VkEnum(object):
240 def __init__(self, name, values):
243 self.required = False
247 name = enum.attrib.get("name")
250 for v in enum.findall("enum"):
251 # Value is either a value or a bitpos, only one can exist.
252 value = v.attrib.get("value")
255 value = 1 << int(v.attrib.get("bitpos"))
256 values.append(VkEnumValue(v.attrib.get("name"), value, hex=True))
258 # Some values are in hex form. We want to preserve the hex representation
259 # at least when we convert back to a string. Internally we want to use int.
261 values.append(VkEnumValue(v.attrib.get("name"), int(value, 0), hex=True))
263 values.append(VkEnumValue(v.attrib.get("name"), int(value, 0)))
265 # vulkan.h contains a *_MAX_ENUM value set to 32-bit at the time of writing,
266 # which is to prepare for extensions as they can add values and hence affect
267 # the size definition.
268 max_name = re.sub(r'([0-9a-z_])([A-Z0-9])',r'\1_\2',name).upper() + "_MAX_ENUM"
269 values.append(VkEnumValue(max_name, 0x7fffffff, hex=True))
271 return VkEnum(name, values)
273 def add(self, value):
274 """ Add a value to enum. """
275 self.values.append(value)
277 def definition(self):
278 text = "typedef enum {0}\n{{\n".format(self.name)
280 # Print values sorted, values can have been added in a random order.
281 values = sorted(self.values, key=lambda value: value.value)
283 text += " {0},\n".format(value.definition())
284 text += "}} {0};\n\n".format(self.name)
288 class VkEnumValue(object):
289 def __init__(self, name, value, hex=False):
295 return "{0}={1}".format(self.name, self.value)
297 def definition(self):
298 """ Convert to text definition e.g. VK_FOO = 1 """
300 # Hex is commonly used for FlagBits and sometimes within
301 # a non-FlagBits enum for a bitmask value as well.
303 return "{0} = 0x{1:08x}".format(self.name, self.value)
305 return "{0} = {1}".format(self.name, self.value)
308 class VkFunction(object):
309 def __init__(self, _type=None, name=None, params=[], extension=None):
310 self.extension = extension
315 # For some functions we need some extra metadata from FUNCTION_OVERRIDES.
316 func_info = FUNCTION_OVERRIDES.get(self.name, None)
317 self.dispatch = func_info["dispatch"] if func_info is not None else True
318 self.driver = func_info["driver"] if func_info is not None else False
319 self.thunk_needed = func_info["thunk"] if func_info is not None else True
321 # Required is set while parsing which APIs and types are required
322 # and is used by the code generation.
323 self.required = False
326 def from_xml(command, types):
327 proto = command.find("proto")
329 func_name = proto.find("name").text
330 func_type = proto.find("type").text
333 for param in command.findall("param"):
334 vk_param = VkParam.from_xml(param, types)
335 params.append(vk_param)
337 return VkFunction(_type=func_type, name=func_name, params=params)
339 def get_conversions(self):
340 """ Get a list of conversion functions required for this function if any.
341 Parameters which are structures may require conversion between win32
342 and the host platform. This function returns a list of conversions
347 for param in self.params:
348 convs = param.get_conversions()
349 if convs is not None:
350 conversions.extend(convs)
354 def is_device_func(self):
355 # If none of the other, it must be a device function
356 return not self.is_global_func() and not self.is_instance_func()
358 def is_driver_func(self):
359 """ Returns if function is part of Wine driver interface. """
362 def is_global_func(self):
363 # Treat vkGetInstanceProcAddr as a global function as it
364 # can operate with NULL for vkInstance.
365 if self.name == "vkGetInstanceProcAddr":
367 # Global functions are not passed a dispatchable object.
368 elif self.params[0].is_dispatchable():
372 def is_instance_func(self):
373 # Instance functions are passed VkInstance or VkPhysicalDevice.
374 if self.params[0].type in ["VkInstance", "VkPhysicalDevice"]:
378 def is_required(self):
381 def needs_conversion(self):
382 """ Check if the function needs any input/output type conversion.
383 Functions need input/output conversion if struct parameters have
384 alignment differences between Win32 and Linux 32-bit.
387 for p in self.params:
388 if p.needs_conversion():
389 LOGGER.debug("Parameter {0} to {1} requires conversion".format(p.name, self.name))
394 def needs_dispatch(self):
397 def needs_thunk(self):
398 return self.thunk_needed
400 def pfn(self, call_conv=None, conv=False):
401 """ Create function pointer. """
403 if call_conv is not None:
404 pfn = "{0} ({1} *p_{2})(".format(self.type, call_conv, self.name)
406 pfn = "{0} (*p_{1})(".format(self.type, self.name)
408 for i, param in enumerate(self.params):
410 pfn += param.const + " "
413 if conv and param.needs_conversion():
416 if param.is_pointer():
417 pfn += " " + param.pointer
419 if param.array_len is not None:
420 pfn += "[{0}]".format(param.array_len)
422 if i < len(self.params) - 1:
427 def prototype(self, call_conv=None, prefix=None, postfix=None):
428 """ Generate prototype for given function.
431 call_conv (str, optional): calling convention e.g. WINAPI
432 prefix (str, optional): prefix to append prior to function name e.g. vkFoo -> wine_vkFoo
433 postfix (str, optional): text to append after function name but prior to semicolon e.g. DECLSPEC_HIDDEN
436 proto = "{0}".format(self.type)
438 if call_conv is not None:
439 proto += " {0}".format(call_conv)
441 if prefix is not None:
442 proto += " {0}{1}(".format(prefix, self.name)
444 proto += " {0}(".format(self.name)
446 # Add all the paremeters.
447 proto += ", ".join([p.definition() for p in self.params])
449 if postfix is not None:
450 proto += ") {0}".format(postfix)
457 body = " {0}".format(self.trace())
459 params = ", ".join([p.variable(conv=False) for p in self.params])
461 # Call the native Vulkan function.
462 if self.type == "void":
463 body += " {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
465 body += " return {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
469 def body_conversion(self):
472 # Declare a variable to hold the result for non-void functions.
473 if self.type != "void":
474 body += " {0} result;\n".format(self.type)
476 # Declare any tmp parameters for conversion.
477 for p in self.params:
478 if not p.needs_conversion():
481 if p.is_dynamic_array():
482 body += " {0}_host *{1}_host;\n".format(p.type, p.name)
484 body += " {0}_host {1}_host;\n".format(p.type, p.name)
486 body += " {0}\n".format(self.trace())
488 # Call any win_to_host conversion calls.
489 for p in self.params:
490 if not p.needs_input_conversion():
493 body += p.copy(Direction.INPUT)
495 # Build list of parameters containing converted and non-converted parameters.
496 # The param itself knows if conversion is needed and applies it when we set conv=True.
497 params = ", ".join([p.variable(conv=True) for p in self.params])
499 # Call the native Vulkan function.
500 if self.type == "void":
501 body += " {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
503 body += " result = {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
507 # Call any host_to_win conversion calls.
508 for p in self.params:
509 if not p.needs_output_conversion():
512 body += p.copy(Direction.OUTPUT)
514 # Perform any required cleanups. Most of these are for array functions.
515 for p in self.params:
516 if not p.needs_free():
521 # Finally return the result.
522 if self.type != "void":
523 body += " return result;\n"
527 def stub(self, call_conv=None, prefix=None):
528 stub = self.prototype(call_conv=call_conv, prefix=prefix)
530 stub += " {0}".format(self.trace(message="stub: ", trace_func="FIXME"))
532 if self.type == "VkResult":
533 stub += " return VK_ERROR_OUT_OF_HOST_MEMORY;\n"
534 elif self.type == "VkBool32":
535 stub += " return VK_FALSE;\n"
536 elif self.type == "PFN_vkVoidFunction":
537 stub += " return NULL;\n"
542 def thunk(self, call_conv=None, prefix=None):
543 thunk = self.prototype(call_conv=call_conv, prefix=prefix)
546 if self.needs_conversion():
547 thunk += "#if defined(USE_STRUCT_CONVERSION)\n"
548 thunk += self.body_conversion()
558 def trace(self, message=None, trace_func=None):
559 """ Create a trace string including all parameters.
562 message (str, optional): text to print at start of trace message e.g. 'stub: '
563 trace_func (str, optional): used to override trace function e.g. FIXME, printf, etcetera.
565 if trace_func is not None:
566 trace = "{0}(\"".format(trace_func)
570 if message is not None:
573 # First loop is for all the format strings.
574 trace += ", ".join([p.format_string() for p in self.params])
577 # Second loop for parameter names and optional conversions.
578 for param in self.params:
579 if param.format_conv is not None:
580 trace += ", " + param.format_conv.format(param.name)
582 trace += ", {0}".format(param.name)
588 class VkFunctionPointer(object):
589 def __init__(self, _type, name, members):
591 self.members = members
593 self.required = False
596 def from_xml(funcpointer):
600 for t in funcpointer.findall("type"):
602 # <type>void</type>* pUserData,
603 # Parsing of the tail (anything past </type>) is tricky since there
604 # can be other data on the next line like: const <type>int</type>..
607 lines = t.tail.split(",\n")
608 if lines[0][0] == "*":
610 name = lines[0][1:].strip()
613 name = lines[0].strip()
615 # Filter out ); if it is contained.
616 name = name.partition(");")[0]
618 # If tail encompasses multiple lines, assign the second line to begin
621 begin = lines[1].strip()
625 members.append(VkMember(const=const, _type=_type, pointer=pointer, name=name))
627 _type = funcpointer.text
628 name = funcpointer.find("name").text
629 return VkFunctionPointer(_type, name, members)
631 def definition(self):
632 text = "{0} {1})(\n".format(self.type, self.name)
635 if len(self.members) > 0:
636 for m in self.members:
638 text += " " + m.definition()
641 text += ",\n " + m.definition()
643 # Just make the compiler happy by adding a void parameter.
649 class VkHandle(object):
650 def __init__(self, name, _type, parent):
654 self.required = False
657 def from_xml(handle):
658 name = handle.find("name").text
659 _type = handle.find("type").text
660 parent = handle.attrib.get("parent") # Most objects have a parent e.g. VkQueue has VkDevice.
661 return VkHandle(name, _type, parent)
663 def dispatch_table(self):
664 if not self.is_dispatchable():
667 if self.parent is None:
668 # Should only happen for VkInstance
670 elif self.name == "VkDevice":
671 # VkDevice has VkInstance as a parent, but has its own dispatch table.
673 elif self.parent in ["VkInstance", "VkPhysicalDevice"]:
674 return "instance->funcs"
675 elif self.parent in ["VkDevice", "VkCommandPool"]:
676 return "device->funcs"
678 LOGGER.error("Unhandled dispatchable parent: {0}".format(self.parent))
680 def definition(self):
681 """ Generates handle definition e.g. VK_DEFINE_HANDLE(vkInstance) """
682 return "{0}({1})\n".format(self.type, self.name)
684 def is_dispatchable(self):
685 """ Some handles like VkInstance, VkDevice are dispatchable objects,
686 which means they contain a dispatch table of function pointers.
688 return self.type == "VK_DEFINE_HANDLE"
690 def native_handle(self):
691 """ Provide access to the native handle of a dispatchable object.
693 Dispatchable objects wrap an underlying 'native' object.
694 This method provides access to the native object.
696 if not self.is_dispatchable():
699 if self.name == "VkCommandBuffer":
700 return "command_buffer"
701 elif self.name == "VkDevice":
703 elif self.name == "VkInstance":
705 elif self.name == "VkPhysicalDevice":
707 elif self.name == "VkQueue":
710 LOGGER.error("Unhandled native handle for: {0}".format(self.name))
713 class VkMember(object):
714 def __init__(self, const=None, _type=None, pointer=None, name=None, array_len=None, dyn_array_len=None, optional=False,
715 extension_structs=None):
718 self.pointer = pointer
720 self.type_info = None
721 self.array_len = array_len
722 self.dyn_array_len = dyn_array_len
723 self.optional = optional
724 self.extension_structs = extension_structs
726 def __eq__(self, other):
727 """ Compare member based on name against a string.
729 This method is for convenience by VkStruct, which holds a number of members and needs quick checking
730 if certain members exist.
733 if self.name == other:
739 return "{0} {1} {2} {3} {4} {5}".format(self.const, self.type, self.pointer, self.name, self.array_len,
743 def from_xml(member):
744 """ Helper function for parsing a member tag within a struct or union. """
746 name_elem = member.find("name")
747 type_elem = member.find("type")
749 const = member.text.strip() if member.text else None
754 if type_elem is not None:
755 member_type = type_elem.text
756 if type_elem.tail is not None:
757 pointer = type_elem.tail.strip() if type_elem.tail.strip() != "" else None
759 # Name of other member within, which stores the number of
760 # elements pointed to be by this member.
761 dyn_array_len = member.get("len", None)
763 if "validextensionstructs" in member.attrib:
764 extension_structs = member.get("validextensionstructs").split(",")
766 extension_structs = None
768 # Some members are optional, which is important for conversion code e.g. not dereference NULL pointer.
769 optional = True if member.get("optional") else False
771 # Usually we need to allocate memory for dynamic arrays. We need to do the same in a few other cases
772 # like for VkCommandBufferBeginInfo.pInheritanceInfo. Just threat such cases as dynamic arrays of
773 # size 1 to simplify code generation.
774 if dyn_array_len is None and pointer is not None:
777 # Some members are arrays, attempt to parse these. Formats include:
778 # <member><type>char</type><name>extensionName</name>[<enum>VK_MAX_EXTENSION_NAME_SIZE</enum>]</member>
779 # <member><type>uint32_t</type><name>foo</name>[4]</member>
780 if name_elem.tail and name_elem.tail[0] == '[':
781 LOGGER.debug("Found array type")
782 enum_elem = member.find("enum")
783 if enum_elem is not None:
784 array_len = enum_elem.text
786 # Remove brackets around length
787 array_len = name_elem.tail.strip("[]")
789 return VkMember(const=const, _type=member_type, pointer=pointer, name=name_elem.text, array_len=array_len,
790 dyn_array_len=dyn_array_len, optional=optional, extension_structs=extension_structs)
792 def copy(self, input, output, direction):
793 """ Helper method for use by conversion logic to generate a C-code statement to copy this member. """
795 if self.needs_conversion():
796 if self.is_dynamic_array():
797 if direction == Direction.OUTPUT:
798 LOGGER.warn("TODO: implement copying of returnedonly dynamic array for {0}.{1}".format(self.type, self.name))
800 # Array length is either a variable name (string) or an int.
801 count = self.dyn_array_len if isinstance(self.dyn_array_len, int) else "{0}{1}".format(input, self.dyn_array_len)
802 return "{0}{1} = convert_{2}_array_win_to_host({3}{1}, {4});\n".format(output, self.name, self.type, input, count)
803 elif self.is_static_array():
804 count = self.array_len
805 if direction == Direction.OUTPUT:
806 # Needed by VkMemoryHeap.memoryHeaps
807 return "convert_{0}_static_array_host_to_win({2}{1}, {3}{1}, {4});\n".format(self.type, self.name, input, output, count)
809 # Nothing needed this yet.
810 LOGGER.warn("TODO: implement copying of static array for {0}.{1}".format(self.type, self.name))
812 if direction == Direction.OUTPUT:
813 return "convert_{0}_host_to_win(&{2}{1}, &{3}{1});\n".format(self.type, self.name, input, output)
815 return "convert_{0}_win_to_host(&{2}{1}, &{3}{1});\n".format(self.type, self.name, input, output)
816 elif self.is_static_array():
817 bytes_count = "{0} * sizeof({1})".format(self.array_len, self.type)
818 return "memcpy({0}{1}, {2}{1}, {3});\n".format(output, self.name, input, bytes_count)
820 return "{0}{1} = {2}{1};\n".format(output, self.name, input)
822 def definition(self, align=False, conv=False):
823 """ Generate prototype for given function.
826 align (bool, optional): Enable alignment if a type needs it. This adds WINE_VK_ALIGN(8) to a member.
827 conv (bool, optional): Enable conversion if a type needs it. This appends '_host' to the name.
834 if conv and self.is_struct():
835 text += "{0}_host".format(self.type)
839 if self.is_pointer():
840 text += " {0}{1}".format(self.pointer, self.name)
842 if align and self.needs_alignment():
843 text += " WINE_VK_ALIGN(8) " + self.name
845 text += " " + self.name
847 if self.is_static_array():
848 text += "[{0}]".format(self.array_len)
852 def get_conversions(self):
853 """ Return any conversion description for this member and its children when conversion is needed. """
855 # Check if we need conversion either for this member itself or for any child members
856 # in case member represents a struct.
857 if not self.needs_conversion():
862 # Collect any conversion for any member structs.
863 struct = self.type_info["data"]
865 if m.needs_conversion():
866 conversions.extend(m.get_conversions())
868 struct = self.type_info["data"]
869 direction = Direction.OUTPUT if struct.returnedonly else Direction.INPUT
870 if self.is_dynamic_array():
871 conversions.append(ConversionFunction(False, True, direction, struct))
872 elif self.is_static_array():
873 conversions.append(ConversionFunction(True, False, direction, struct))
875 conversions.append(ConversionFunction(False, False, direction, struct))
877 if self.needs_free():
878 conversions.append(FreeFunction(self.is_dynamic_array(), struct))
883 return self.const is not None
885 def is_dynamic_array(self):
886 """ Returns if the member is an array element.
887 Vulkan uses this for dynamically sized arrays for which
888 there is a 'count' parameter.
890 return self.dyn_array_len is not None
893 return self.type_info["category"] == "handle"
895 def is_pointer(self):
896 return self.pointer is not None
898 def is_static_array(self):
899 """ Returns if the member is an array.
900 Vulkan uses this often for fixed size arrays in which the
901 length is part of the member.
903 return self.array_len is not None
906 return self.type_info["category"] == "struct"
909 return self.type_info["category"] == "union"
911 def needs_alignment(self):
912 """ Check if this member needs alignment for 64-bit data.
913 Various structures need alignment on 64-bit variables due
914 to compiler differences on 32-bit between Win32 and Linux.
917 if self.is_pointer():
919 elif self.type == "size_t":
921 elif self.type in ["uint64_t", "VkDeviceSize"]:
923 elif self.is_struct():
924 struct = self.type_info["data"]
925 return struct.needs_alignment()
926 elif self.is_handle():
927 # Dispatchable handles are pointers to objects, while
928 # non-dispatchable are uint64_t and hence need alignment.
929 handle = self.type_info["data"]
930 return False if handle.is_dispatchable() else True
933 def needs_conversion(self):
934 """ Structures requiring alignment, need conversion between win32 and host. """
936 if not self.is_struct():
939 struct = self.type_info["data"]
940 return struct.needs_conversion()
942 def needs_free(self):
943 if not self.needs_conversion():
946 if self.is_dynamic_array():
949 # TODO: some non-pointer structs and optional pointer structs may need freeing,
950 # though none of this type have been encountered yet.
953 def set_type_info(self, type_info):
954 """ Helper function to set type information from the type registry.
955 This is needed, because not all type data is available at time of
958 self.type_info = type_info
961 class VkParam(object):
962 """ Helper class which describes a parameter to a function call. """
964 def __init__(self, type_info, const=None, pointer=None, name=None, array_len=None, dyn_array_len=None):
967 self.array_len = array_len
968 self.dyn_array_len = dyn_array_len
969 self.pointer = pointer
970 self.type_info = type_info
971 self.type = type_info["name"] # For convenience
972 self.handle = type_info["data"] if type_info["category"] == "handle" else None
973 self.struct = type_info["data"] if type_info["category"] == "struct" else None
975 self._set_direction()
976 self._set_format_string()
977 self._set_conversions()
980 return "{0} {1} {2} {3} {4}".format(self.const, self.type, self.pointer, self.name, self.array_len, self.dyn_array_len)
983 def from_xml(param, types):
984 """ Helper function to create VkParam from xml. """
986 # Parameter parsing is slightly tricky. All the data is contained within
987 # a param tag, but some data is within subtags while others are text
988 # before or after the type tag.
990 # <param>const <type>char</type>* <name>pLayerName</name></param>
992 name_elem = param.find("name")
994 name = name_elem.text
995 # Tail contains array length e.g. for blendConstants param of vkSetBlendConstants
996 if name_elem.tail is not None:
997 array_len = name_elem.tail.strip("[]")
999 # Name of other parameter in function prototype, which stores the number of
1000 # elements pointed to be by this parameter.
1001 dyn_array_len = param.get("len", None)
1003 const = param.text.strip() if param.text else None
1004 type_elem = param.find("type")
1005 pointer = type_elem.tail.strip() if type_elem.tail.strip() != "" else None
1007 # Since we have parsed all types before hand, this should not happen.
1008 type_info = types.get(type_elem.text, None)
1009 if type_info is None:
1010 LOGGER.err("type info not found for: {0}".format(type_elem.text))
1012 return VkParam(type_info, const=const, pointer=pointer, name=name, array_len=array_len, dyn_array_len=dyn_array_len)
1014 def _set_conversions(self):
1015 """ Internal helper function to configure any needed conversion functions. """
1017 self.free_func = None
1018 self.input_conv = None
1019 self.output_conv = None
1020 if not self.needs_conversion():
1023 # Input functions require win to host conversion.
1024 if self._direction in [Direction.INPUT, Direction.INPUT_OUTPUT]:
1025 self.input_conv = ConversionFunction(False, self.is_dynamic_array(), Direction.INPUT, self.struct)
1027 # Output functions require host to win conversion.
1028 if self._direction in [Direction.INPUT_OUTPUT, Direction.OUTPUT]:
1029 self.output_conv = ConversionFunction(False, self.is_dynamic_array(), Direction.OUTPUT, self.struct)
1031 # Dynamic arrays, but also some normal structs (e.g. VkCommandBufferBeginInfo) need memory
1032 # allocation and thus some cleanup.
1033 if self.is_dynamic_array() or self.struct.needs_free():
1034 self.free_func = FreeFunction(self.is_dynamic_array(), self.struct)
1036 def _set_direction(self):
1037 """ Internal helper function to set parameter direction (input/output/input_output). """
1039 # The parameter direction needs to be determined from hints in vk.xml like returnedonly,
1040 # parameter constness and other heuristics.
1041 # For now we need to get this right for structures as we need to convert these, we may have
1042 # missed a few other edge cases (e.g. count variables).
1043 # See also https://github.com/KhronosGroup/Vulkan-Docs/issues/610
1045 if not self.is_pointer():
1046 self._direction = Direction.INPUT
1047 elif self.is_const() and self.is_pointer():
1048 self._direction = Direction.INPUT
1049 elif self.is_struct():
1050 if not self.struct.returnedonly:
1051 self._direction = Direction.INPUT
1054 # Returnedonly hints towards output, however in some cases
1055 # it is inputoutput. In particular if pNext / sType exist,
1056 # which are used to link in other structures without having
1057 # to introduce new APIs. E.g. vkGetPhysicalDeviceProperties2KHR.
1058 if "pNext" in self.struct:
1059 self._direction = Direction.INPUT_OUTPUT
1062 self._direction = Direction.OUTPUT
1064 # This should mostly be right. Count variables can be inout, but we don't care about these yet.
1065 self._direction = Direction.OUTPUT
1067 def _set_format_string(self):
1068 """ Internal helper function to be used by constructor to set format string. """
1070 # Determine a format string used by code generation for traces.
1071 # 64-bit types need a conversion function.
1072 self.format_conv = None
1073 if self.is_static_array() or self.is_pointer():
1074 self.format_str = "%p"
1076 if self.type_info["category"] == "bitmask":
1077 self.format_str = "%#x"
1078 elif self.type_info["category"] == "enum":
1079 self.format_str = "%d"
1080 elif self.is_handle():
1081 # We use uint64_t for non-dispatchable handles as opposed to pointers
1082 # for dispatchable handles.
1083 if self.handle.is_dispatchable():
1084 self.format_str = "%p"
1086 self.format_str = "0x%s"
1087 self.format_conv = "wine_dbgstr_longlong({0})"
1088 elif self.type == "float":
1089 self.format_str = "%f"
1090 elif self.type == "int":
1091 self.format_str = "%d"
1092 elif self.type == "int32_t":
1093 self.format_str = "%d"
1094 elif self.type == "size_t":
1095 self.format_str = "0x%s"
1096 self.format_conv = "wine_dbgstr_longlong({0})"
1097 elif self.type in ["uint32_t", "VkBool32"]:
1098 self.format_str = "%u"
1099 elif self.type in ["uint64_t", "VkDeviceSize"]:
1100 self.format_str = "0x%s"
1101 self.format_conv = "wine_dbgstr_longlong({0})"
1102 elif self.type == "HANDLE":
1103 self.format_str = "%p"
1104 elif self.type in ["VisualID", "xcb_visualid_t", "RROutput"]:
1105 # Don't care about Linux specific types.
1106 self.format_str = ""
1108 LOGGER.warn("Unhandled type: {0}".format(self.type_info))
1110 def copy(self, direction):
1111 if direction == Direction.INPUT:
1112 if self.is_dynamic_array():
1113 return " {0}_host = convert_{1}_array_win_to_host({0}, {2});\n".format(self.name, self.type, self.dyn_array_len)
1115 return " convert_{0}_win_to_host({1}, &{1}_host);\n".format(self.type, self.name)
1117 if self.is_dynamic_array():
1118 LOGGER.error("Unimplemented output conversion for: {0}".format(self.name))
1120 return " convert_{0}_host_to_win(&{1}_host, {1});\n".format(self.type, self.name)
1122 def definition(self, postfix=None):
1123 """ Return prototype for the parameter. E.g. 'const char *foo' """
1127 proto += self.const + " "
1131 if self.is_pointer():
1132 proto += " {0}{1}".format(self.pointer, self.name)
1134 proto += " " + self.name
1136 # Allows appeninding something to the variable name useful for
1137 # win32 to host conversion.
1138 if postfix is not None:
1141 if self.is_static_array():
1142 proto += "[{0}]".format(self.array_len)
1146 def direction(self):
1147 """ Returns parameter direction: input, output, input_output.
1149 Parameter direction in Vulkan is not straight-forward, which this function determines.
1152 return self._direction
1154 def format_string(self):
1155 return self.format_str
1157 def dispatch_table(self):
1158 """ Return functions dispatch table pointer for dispatchable objects. """
1160 if not self.is_dispatchable():
1163 return "{0}->{1}".format(self.name, self.handle.dispatch_table())
1165 def format_string(self):
1166 return self.format_str
1169 if self.is_dynamic_array():
1170 if self.struct.returnedonly:
1171 # For returnedonly, counts is stored in a pointer.
1172 return " free_{0}_array({1}_host, *{2});\n".format(self.type, self.name, self.dyn_array_len)
1174 return " free_{0}_array({1}_host, {2});\n".format(self.type, self.name, self.dyn_array_len)
1176 # We are operating on a single structure. Some structs (very rare) contain dynamic members,
1177 # which would need freeing.
1178 if self.struct.needs_free():
1179 return " free_{0}(&{1}_host);\n".format(self.type, self.name)
1182 def get_conversions(self):
1183 """ Get a list of conversions required for this parameter if any.
1184 Parameters which are structures may require conversion between win32
1185 and the host platform. This function returns a list of conversions
1189 if not self.is_struct():
1192 if not self.needs_conversion():
1197 # Collect any member conversions first, so we can guarantee
1198 # those functions will be defined prior to usage by the
1199 # 'parent' param requiring conversion.
1200 for m in self.struct:
1201 if not m.is_struct():
1204 if not m.needs_conversion():
1207 conversions.extend(m.get_conversions())
1209 # Conversion requirements for the 'parent' parameter.
1210 if self.input_conv is not None:
1211 conversions.append(self.input_conv)
1212 if self.output_conv is not None:
1213 conversions.append(self.output_conv)
1214 if self.free_func is not None:
1215 conversions.append(self.free_func)
1220 return self.const is not None
1222 def is_dynamic_array(self):
1223 return self.dyn_array_len is not None
1225 def is_dispatchable(self):
1226 if not self.is_handle():
1229 return self.handle.is_dispatchable()
1231 def is_handle(self):
1232 return self.handle is not None
1234 def is_pointer(self):
1235 return self.pointer is not None
1237 def is_static_array(self):
1238 return self.array_len is not None
1240 def is_struct(self):
1241 return self.struct is not None
1243 def needs_conversion(self):
1244 """ Returns if parameter needs conversion between win32 and host. """
1246 if not self.is_struct():
1249 # VkSparseImageMemoryRequirements is used by vkGetImageSparseMemoryRequirements.
1250 # This function is tricky to wrap, because how to wrap depends on whether
1251 # pSparseMemoryRequirements is NULL or not. Luckily for VkSparseImageMemoryRequirements
1252 # the alignment works out in such a way that no conversion is needed between win32 and Linux.
1253 if self.type == "VkSparseImageMemoryRequirements":
1256 # If a structure needs alignment changes, it means we need to
1257 # perform parameter conversion between win32 and host.
1258 if self.struct.needs_conversion():
1263 def needs_free(self):
1264 return self.free_func is not None
1266 def needs_input_conversion(self):
1267 return self.input_conv is not None
1269 def needs_output_conversion(self):
1270 return self.output_conv is not None
1272 def variable(self, conv=False):
1273 """ Returns 'glue' code during generation of a function call on how to access the variable.
1274 This function handles various scenarios such as 'unwrapping' if dispatchable objects and
1275 renaming of parameters in case of win32 -> host conversion.
1278 conv (bool, optional): Enable conversion if the param needs it. This appends '_host' to the name.
1281 # Hack until we enable allocation callbacks from ICD to application. These are a joy
1282 # to enable one day, because of calling convention conversion.
1283 if "VkAllocationCallbacks" in self.type:
1284 LOGGER.debug("TODO: setting NULL VkAllocationCallbacks for {0}".format(self.name))
1287 # Dispatchable objects wrap the native handle. For thunk generation we
1288 # need to pass the native handle to the native vulkan calls.
1289 if self.is_dispatchable():
1290 return "{0}->{1}".format(self.name, self.handle.native_handle())
1291 elif conv and self.needs_conversion():
1292 if self.is_dynamic_array():
1293 return "{0}_host".format(self.name)
1295 return "&{0}_host".format(self.name)
1300 class VkStruct(Sequence):
1301 """ Class which represents the type union and struct. """
1303 def __init__(self, name, members, returnedonly, union=False):
1305 self.members = members
1306 self.returnedonly = returnedonly
1307 self.required = False
1309 self.type_info = None # To be set later.
1311 def __getitem__(self, i):
1312 return self.members[i]
1315 return len(self.members)
1318 def from_xml(struct):
1319 # Unions and structs are the same parsing wise, but we need to
1320 # know which one we are dealing with later on for code generation.
1321 union = True if struct.attrib["category"] == "union" else False
1323 name = struct.attrib.get("name", None)
1325 # 'Output' structures for which data is filled in by the API are
1326 # marked as 'returnedonly'.
1327 returnedonly = True if struct.attrib.get("returnedonly") else False
1330 for member in struct.findall("member"):
1331 vk_member = VkMember.from_xml(member)
1332 members.append(vk_member)
1334 return VkStruct(name, members, returnedonly, union=union)
1337 def decouple_structs(structs):
1338 """ Helper function which decouples a list of structs.
1339 Structures often depend on other structures. To make the C compiler
1340 happy we need to define 'substructures' first. This function analyzes
1341 the list of structures and reorders them in such a way that they are
1345 tmp_structs = list(structs) # Don't modify the original structures.
1346 decoupled_structs = []
1348 while (len(tmp_structs) > 0):
1349 for struct in tmp_structs:
1352 if not struct.required:
1353 tmp_structs.remove(struct)
1357 if not (m.is_struct() or m.is_union()):
1361 # Check if a struct we depend on has already been defined.
1362 for s in decoupled_structs:
1363 if s.name == m.type:
1368 # Check if the struct we depend on is even in the list of structs.
1369 # If found now, it means we haven't met all dependencies before we
1370 # can operate on the current struct.
1371 # When generating 'host' structs we may not be able to find a struct
1372 # as the list would only contain the structs requiring conversion.
1373 for s in tmp_structs:
1374 if s.name == m.type:
1378 if dependends == False:
1379 decoupled_structs.append(struct)
1380 tmp_structs.remove(struct)
1382 return decoupled_structs
1384 def definition(self, align=False, conv=False, postfix=None):
1385 """ Convert structure to textual definition.
1388 align (bool, optional): enable alignment to 64-bit for win32 struct compatibility.
1389 conv (bool, optional): enable struct conversion if the struct needs it.
1390 postfix (str, optional): text to append to end of struct name, useful for struct renaming.
1394 text = "typedef union {0}".format(self.name)
1396 text = "typedef struct {0}".format(self.name)
1398 if postfix is not None:
1404 if align and m.needs_alignment():
1405 text += " {0};\n".format(m.definition(align=align))
1406 elif conv and m.needs_conversion():
1407 text += " {0};\n".format(m.definition(conv=conv))
1409 text += " {0};\n".format(m.definition())
1411 if postfix is not None:
1412 text += "}} {0}{1};\n\n".format(self.name, postfix)
1414 text += "}} {0};\n\n".format(self.name)
1417 def needs_alignment(self):
1418 """ Check if structure needs alignment for 64-bit data.
1419 Various structures need alignment on 64-bit variables due
1420 to compiler differences on 32-bit between Win32 and Linux.
1423 for m in self.members:
1424 if m.needs_alignment():
1428 def needs_conversion(self):
1429 """ Returns if struct members needs conversion between win32 and host.
1430 Structures need conversion if they contain members requiring alignment
1431 or if they include other structures which need alignment.
1434 if self.needs_alignment():
1437 for m in self.members:
1438 if m.needs_conversion():
1442 def needs_free(self):
1443 """ Check if any struct member needs some memory freeing."""
1445 for m in self.members:
1453 def set_type_info(self, types):
1454 """ Helper function to set type information from the type registry.
1455 This is needed, because not all type data is available at time of
1458 for m in self.members:
1459 type_info = types[m.type]
1460 m.set_type_info(type_info)
1463 class ConversionFunction(object):
1464 def __init__(self, array, dyn_array, direction, struct):
1466 self.direction = direction
1467 self.dyn_array = dyn_array
1468 self.struct = struct
1469 self.type = struct.name
1473 def __eq__(self, other):
1474 if self.name != other.name:
1479 def _generate_array_conversion_func(self):
1480 """ Helper function for generating a conversion function for array structs. """
1482 if self.direction == Direction.OUTPUT:
1483 params = ["const {0}_host *in".format(self.type), "uint32_t count"]
1484 return_type = self.type
1486 params = ["const {0} *in".format(self.type), "uint32_t count"]
1487 return_type = "{0}_host".format(self.type)
1489 # Generate function prototype.
1490 body = "static inline {0} *{1}(".format(return_type, self.name)
1491 body += ", ".join(p for p in params)
1494 body += " {0} *out;\n".format(return_type)
1495 body += " unsigned int i;\n\n"
1496 body += " if (!in) return NULL;\n\n"
1498 body += " out = heap_alloc(count * sizeof(*out));\n"
1500 body += " for (i = 0; i < count; i++)\n"
1503 for m in self.struct:
1504 # TODO: support copying of pNext extension structures!
1505 # Luckily though no extension struct at this point needs conversion.
1506 body += " " + m.copy("in[i].", "out[i].", self.direction)
1509 body += " return out;\n"
1513 def _generate_conversion_func(self):
1514 """ Helper function for generating a conversion function for non-array structs. """
1516 if self.direction == Direction.OUTPUT:
1517 params = ["const {0}_host *in".format(self.type), "{0} *out".format(self.type)]
1519 params = ["const {0} *in".format(self.type), "{0}_host *out".format(self.type)]
1521 body = "static inline void {0}(".format(self.name)
1523 # Generate parameter list
1524 body += ", ".join(p for p in params)
1527 body += " if (!in) return;\n\n"
1529 if self.direction == Direction.INPUT and "pNext" in self.struct and self.struct.returnedonly:
1530 # We are dealing with an input_output parameter. For these we only need to copy
1531 # pNext and sType as the other fields are filled in by the host. We do potentially
1532 # have to iterate over pNext and perform conversions based on switch(sType)!
1533 # Luckily though no extension structs at this point need conversion.
1534 # TODO: support copying of pNext extension structures!
1535 body += " out->pNext = in->pNext;\n"
1536 body += " out->sType = in->sType;\n"
1538 for m in self.struct:
1539 # TODO: support copying of pNext extension structures!
1540 body += " " + m.copy("in->", "out->", self.direction)
1545 def _generate_static_array_conversion_func(self):
1546 """ Helper function for generating a conversion function for array structs. """
1548 if self.direction == Direction.OUTPUT:
1549 params = ["const {0}_host *in".format(self.type), "{0} *out".format(self.type), "uint32_t count"]
1550 return_type = self.type
1552 params = ["const {0} *in".format(self.type), "{0} *out_host".format(self.type), "uint32_t count"]
1553 return_type = "{0}_host".format(self.type)
1555 # Generate function prototype.
1556 body = "static inline void {0}(".format(self.name)
1557 body += ", ".join(p for p in params)
1559 body += " unsigned int i;\n\n"
1560 body += " if (!in) return;\n\n"
1561 body += " for (i = 0; i < count; i++)\n"
1564 for m in self.struct:
1565 # TODO: support copying of pNext extension structures!
1566 body += " " + m.copy("in[i].", "out[i].", self.direction)
1572 def _set_name(self):
1573 if self.direction == Direction.INPUT:
1575 name = "convert_{0}_static_array_win_to_host".format(self.type)
1576 elif self.dyn_array:
1577 name = "convert_{0}_array_win_to_host".format(self.type)
1579 name = "convert_{0}_win_to_host".format(self.type)
1580 else: # Direction.OUTPUT
1582 name = "convert_{0}_static_array_host_to_win".format(self.type)
1583 elif self.dyn_array:
1584 name = "convert_{0}_array_host_to_win".format(self.type)
1586 name = "convert_{0}_host_to_win".format(self.type)
1590 def definition(self):
1592 return self._generate_static_array_conversion_func()
1593 elif self.dyn_array:
1594 return self._generate_array_conversion_func()
1596 return self._generate_conversion_func()
1599 class FreeFunction(object):
1600 def __init__(self, dyn_array, struct):
1601 self.dyn_array = dyn_array
1602 self.struct = struct
1603 self.type = struct.name
1606 self.name = "free_{0}_array".format(self.type)
1608 self.name = "free_{0}".format(self.type)
1610 def __eq__(self, other):
1611 if self.name == other.name:
1616 def _generate_array_free_func(self):
1617 """ Helper function for cleaning up temporary buffers required for array conversions. """
1619 # Generate function prototype.
1620 body = "static inline void {0}({1}_host *in, uint32_t count)\n{{\n".format(self.name, self.type)
1622 # E.g. VkGraphicsPipelineCreateInfo_host needs freeing for pStages.
1623 if self.struct.needs_free():
1624 body += " unsigned int i;\n\n"
1625 body += " if (!in) return;\n\n"
1626 body += " for (i = 0; i < count; i++)\n"
1629 for m in self.struct:
1630 if m.needs_conversion() and m.is_dynamic_array():
1632 # Add a cast to ignore const on conversion structs we allocated ourselves.
1633 body += " free_{0}_array(({0}_host *)in[i].{1}, in[i].{2});\n".format(m.type, m.name, m.dyn_array_len)
1635 body += " free_{0}_array(in[i].{1}, in[i].{2});\n".format(m.type, m.name, m.dyn_array_len)
1636 elif m.needs_conversion():
1637 LOGGER.error("Unhandled conversion for {0}".format(m.name))
1640 body += " if (!in) return;\n\n"
1642 body += " heap_free(in);\n"
1647 def _generate_free_func(self):
1648 # E.g. VkCommandBufferBeginInfo.pInheritanceInfo needs freeing.
1649 if not self.struct.needs_free():
1652 # Generate function prototype.
1653 body = "static inline void {0}({1}_host *in)\n{{\n".format(self.name, self.type)
1655 for m in self.struct:
1656 if m.needs_conversion() and m.is_dynamic_array():
1657 count = m.dyn_array_len if isinstance(m.dyn_array_len, int) else "in->{0}".format(m.dyn_array_len)
1659 # Add a cast to ignore const on conversion structs we allocated ourselves.
1660 body += " free_{0}_array(({0}_host *)in->{1}, {2});\n".format(m.type, m.name, count)
1662 body += " free_{0}_array(in->{1}, {2});\n".format(m.type, m.name, count)
1667 def definition(self):
1669 return self._generate_array_free_func()
1671 # Some structures need freeing too if they contain dynamic arrays.
1672 # E.g. VkCommandBufferBeginInfo
1673 return self._generate_free_func()
1676 class VkGenerator(object):
1677 def __init__(self, registry):
1678 self.registry = registry
1680 # Build a list conversion functions for struct conversion.
1681 self.conversions = []
1682 self.host_structs = []
1683 for func in self.registry.funcs.values():
1684 if not func.is_required():
1687 if not func.needs_conversion():
1690 conversions = func.get_conversions()
1691 for conv in conversions:
1692 # Pull in any conversions for vulkan_thunks.c. Driver conversions we
1693 # handle manually in vulkan.c if needed.
1694 if not func.is_driver_func():
1695 # Append if we don't already have this conversion.
1696 if not any(c == conv for c in self.conversions):
1697 self.conversions.append(conv)
1699 # Structs can be used in different ways by different conversions
1700 # e.g. array vs non-array. Just make sure we pull in each struct once.
1701 if not any(s.name == conv.struct.name for s in self.host_structs):
1702 self.host_structs.append(conv.struct)
1704 def generate_thunks_c(self, f, prefix):
1705 f.write("/* Automatically generated from Vulkan vk.xml; DO NOT EDIT! */\n\n")
1707 f.write("#include \"config.h\"\n")
1708 f.write("#include \"wine/port.h\"\n\n")
1710 f.write("#include \"wine/debug.h\"\n")
1711 f.write("#include \"wine/heap.h\"\n")
1712 f.write("#include \"wine/vulkan.h\"\n")
1713 f.write("#include \"wine/vulkan_driver.h\"\n")
1714 f.write("#include \"vulkan_private.h\"\n\n")
1716 f.write("WINE_DEFAULT_DEBUG_CHANNEL(vulkan);\n\n")
1718 # Generate any conversion helper functions.
1719 f.write("#if defined(USE_STRUCT_CONVERSION)\n")
1720 for conv in self.conversions:
1721 f.write(conv.definition())
1722 f.write("#endif /* USE_STRUCT_CONVERSION */\n\n")
1724 # Create thunks for instance and device functions.
1725 # Global functions don't go through the thunks.
1726 for vk_func in self.registry.funcs.values():
1727 if not vk_func.is_required():
1730 if vk_func.is_global_func():
1733 if not vk_func.needs_thunk():
1736 f.write("static " + vk_func.thunk(prefix=prefix, call_conv="WINAPI"))
1738 f.write("static const struct vulkan_func vk_device_dispatch_table[] =\n{\n")
1739 for vk_func in self.registry.device_funcs:
1740 if not vk_func.is_required():
1743 if not vk_func.needs_dispatch():
1744 LOGGER.debug("skipping {0} in device dispatch table".format(vk_func.name))
1747 f.write(" {{\"{0}\", &{1}{0}}},\n".format(vk_func.name, prefix))
1750 f.write("static const struct vulkan_func vk_instance_dispatch_table[] =\n{\n")
1751 for vk_func in self.registry.instance_funcs:
1752 if not vk_func.is_required():
1755 if not vk_func.needs_dispatch():
1756 LOGGER.debug("skipping {0} in instance dispatch table".format(vk_func.name))
1759 f.write(" {{\"{0}\", &{1}{0}}},\n".format(vk_func.name, prefix))
1762 f.write("void *wine_vk_get_device_proc_addr(const char *name)\n")
1764 f.write(" unsigned int i;\n")
1765 f.write(" for (i = 0; i < ARRAY_SIZE(vk_device_dispatch_table); i++)\n")
1767 f.write(" if (strcmp(vk_device_dispatch_table[i].name, name) == 0)\n")
1769 f.write(" TRACE(\"Found name=%s in device table\\n\", name);\n")
1770 f.write(" return vk_device_dispatch_table[i].func;\n")
1773 f.write(" return NULL;\n")
1776 f.write("void *wine_vk_get_instance_proc_addr(const char *name)\n")
1778 f.write(" unsigned int i;\n")
1779 f.write(" for (i = 0; i < ARRAY_SIZE(vk_instance_dispatch_table); i++)\n")
1781 f.write(" if (strcmp(vk_instance_dispatch_table[i].name, name) == 0)\n")
1783 f.write(" TRACE(\"Found name=%s in instance table\\n\", name);\n")
1784 f.write(" return vk_instance_dispatch_table[i].func;\n")
1787 f.write(" return NULL;\n")
1790 # Create array of device extensions.
1791 f.write("static const char * const vk_device_extensions[] =\n{\n")
1792 for ext in self.registry.extensions:
1793 if ext["type"] != "device":
1796 f.write(" \"{0}\",\n".format(ext["name"]))
1799 f.write("BOOL wine_vk_device_extension_supported(const char *name)\n")
1801 f.write(" unsigned int i;\n")
1802 f.write(" for (i = 0; i < ARRAY_SIZE(vk_device_extensions); i++)\n")
1804 f.write(" if (strcmp(vk_device_extensions[i], name) == 0)\n")
1805 f.write(" return TRUE;\n")
1807 f.write(" return FALSE;\n")
1810 def generate_thunks_h(self, f, prefix):
1811 f.write("/* Automatically generated from Vulkan vk.xml; DO NOT EDIT! */\n\n")
1813 f.write("#ifndef __WINE_VULKAN_THUNKS_H\n")
1814 f.write("#define __WINE_VULKAN_THUNKS_H\n\n")
1816 f.write("/* Perform vulkan struct conversion on 32-bit x86 platforms. */\n")
1817 f.write("#if defined(__i386__)\n")
1818 f.write("#define USE_STRUCT_CONVERSION\n")
1819 f.write("#endif\n\n")
1821 f.write("/* For use by vk_icdGetInstanceProcAddr / vkGetInstanceProcAddr */\n")
1822 f.write("void *wine_vk_get_device_proc_addr(const char *name) DECLSPEC_HIDDEN;\n")
1823 f.write("void *wine_vk_get_instance_proc_addr(const char *name) DECLSPEC_HIDDEN;\n\n")
1825 f.write("BOOL wine_vk_device_extension_supported(const char *name) DECLSPEC_HIDDEN;\n\n")
1827 # Generate prototypes for device and instance functions requiring a custom implementation.
1828 f.write("/* Functions for which we have custom implementations outside of the thunks. */\n")
1829 for vk_func in self.registry.funcs.values():
1830 if not vk_func.is_required() or vk_func.is_global_func() or vk_func.needs_thunk():
1833 f.write("{0};\n".format(vk_func.prototype("WINAPI", prefix="wine_", postfix="DECLSPEC_HIDDEN")))
1836 for struct in self.host_structs:
1837 f.write(struct.definition(align=False, conv=True, postfix="_host"))
1840 f.write("/* For use by vkDevice and children */\n")
1841 f.write("struct vulkan_device_funcs\n{\n")
1842 for vk_func in self.registry.device_funcs:
1843 if not vk_func.is_required():
1846 if not vk_func.needs_dispatch() or vk_func.is_driver_func():
1847 LOGGER.debug("skipping {0} in vulkan_device_funcs".format(vk_func.name))
1850 if vk_func.needs_conversion():
1851 f.write("#if defined(USE_STRUCT_CONVERSION)\n")
1852 f.write(" {0};\n".format(vk_func.pfn(conv=True)))
1854 f.write(" {0};\n".format(vk_func.pfn(conv=False)))
1857 f.write(" {0};\n".format(vk_func.pfn(conv=False)))
1860 f.write("/* For use by vkInstance and children */\n")
1861 f.write("struct vulkan_instance_funcs\n{\n")
1862 for vk_func in self.registry.instance_funcs:
1863 if not vk_func.is_required():
1866 if not vk_func.needs_dispatch() or vk_func.is_driver_func():
1867 LOGGER.debug("skipping {0} in vulkan_instance_funcs".format(vk_func.name))
1870 if vk_func.needs_conversion():
1871 f.write("#if defined(USE_STRUCT_CONVERSION)\n")
1872 f.write(" {0};\n".format(vk_func.pfn(conv=True)))
1874 f.write(" {0};\n".format(vk_func.pfn(conv=False)))
1877 f.write(" {0};\n".format(vk_func.pfn(conv=False)))
1880 f.write("#define ALL_VK_DEVICE_FUNCS() \\\n")
1882 for vk_func in self.registry.device_funcs:
1883 if not vk_func.is_required():
1886 if not vk_func.needs_dispatch() or vk_func.is_driver_func():
1887 LOGGER.debug("skipping {0} in ALL_VK_DEVICE_FUNCS".format(vk_func.name))
1891 f.write(" USE_VK_FUNC({0})".format(vk_func.name))
1894 f.write(" \\\n USE_VK_FUNC({0})".format(vk_func.name))
1897 f.write("#define ALL_VK_INSTANCE_FUNCS() \\\n")
1899 for vk_func in self.registry.instance_funcs:
1900 if not vk_func.is_required():
1903 if not vk_func.needs_dispatch() or vk_func.is_driver_func():
1904 LOGGER.debug("skipping {0} in ALL_VK_INSTANCE_FUNCS".format(vk_func.name))
1908 f.write(" USE_VK_FUNC({0})".format(vk_func.name))
1911 f.write("\\\n USE_VK_FUNC({0})".format(vk_func.name))
1914 f.write("#endif /* __WINE_VULKAN_THUNKS_H */\n")
1916 def generate_vulkan_h(self, f):
1917 f.write("/* Automatically generated from Vulkan vk.xml; DO NOT EDIT! */\n\n")
1918 f.write("#ifndef __WINE_VULKAN_H\n")
1919 f.write("#define __WINE_VULKAN_H\n\n")
1921 f.write("#include <windef.h>\n")
1922 f.write("#include <stdint.h>\n\n")
1924 f.write("#ifndef VKAPI_CALL\n")
1925 f.write("#define VKAPI_CALL __stdcall\n")
1926 f.write("#endif\n\n")
1928 f.write("#ifndef VKAPI_PTR\n")
1929 f.write("#define VKAPI_PTR VKAPI_CALL\n")
1930 f.write("#endif\n\n")
1932 f.write("/* Callers can override WINE_VK_ALIGN if they want 'host' headers. */\n")
1933 f.write("#ifndef WINE_VK_ALIGN\n")
1934 f.write("#define WINE_VK_ALIGN DECLSPEC_ALIGN\n")
1935 f.write("#endif\n\n")
1937 # The overall strategy is to define independent constants and datatypes,
1938 # prior to complex structures and function calls to avoid forward declarations.
1939 for const in self.registry.consts:
1940 # For now just generate things we may not need. The amount of parsing needed
1941 # to get some of the info is tricky as you need to figure out which structure
1942 # references a certain constant.
1943 f.write(const.definition())
1946 for define in self.registry.defines:
1947 f.write(define.definition())
1949 for handle in self.registry.handles:
1951 f.write(handle.definition())
1954 for base_type in self.registry.base_types:
1955 f.write(base_type.definition())
1958 for bitmask in self.registry.bitmasks:
1959 f.write(bitmask.definition())
1962 # Define enums, this includes values for some of the bitmask types as well.
1963 for enum in self.registry.enums.values():
1965 f.write(enum.definition())
1967 for fp in self.registry.funcpointers:
1969 f.write(fp.definition())
1972 # This generates both structures and unions. Since structures
1973 # may depend on other structures/unions, we need a list of
1974 # decoupled structs.
1975 # Note: unions are stored in structs for dependency reasons,
1976 # see comment in parsing section.
1977 structs = VkStruct.decouple_structs(self.registry.structs)
1978 for struct in structs:
1979 LOGGER.debug("Generating struct: {0}".format(struct.name))
1980 f.write(struct.definition(align=True))
1982 for func in self.registry.funcs.values():
1983 if not func.is_required():
1984 LOGGER.debug("Skipping API definition for: {0}".format(func.name))
1987 LOGGER.debug("Generating API definition for: {0}".format(func.name))
1988 f.write("{0};\n".format(func.prototype(call_conv="VKAPI_CALL")))
1991 f.write("#endif /* __WINE_VULKAN_H */\n")
1993 def generate_vulkan_driver_h(self, f):
1994 f.write("/* Automatically generated from Vulkan vk.xml; DO NOT EDIT! */\n\n")
1995 f.write("#ifndef __WINE_VULKAN_DRIVER_H\n")
1996 f.write("#define __WINE_VULKAN_DRIVER_H\n\n")
1998 f.write("/* Wine internal vulkan driver version, needs to be bumped upon vulkan_funcs changes. */\n")
1999 f.write("#define WINE_VULKAN_DRIVER_VERSION {0}\n\n".format(DRIVER_VERSION))
2001 f.write("struct vulkan_funcs\n{\n")
2002 f.write(" /* Vulkan global functions. These are the only calls at this point a graphics driver\n")
2003 f.write(" * needs to provide. Other function calls will be provided indirectly by dispatch\n")
2004 f.write(" * tables part of dispatchable Vulkan objects such as VkInstance or vkDevice.\n")
2007 for vk_func in self.registry.funcs.values():
2008 if not vk_func.is_required() or not vk_func.is_driver_func():
2012 # Avoid PFN_vkVoidFunction in driver interface as Vulkan likes to put calling convention
2013 # stuff in there. For simplicity substitute with "void *".
2014 pfn = pfn.replace("PFN_vkVoidFunction", "void *")
2015 f.write(" {0};\n".format(pfn))
2018 f.write("extern const struct vulkan_funcs * CDECL __wine_get_vulkan_driver(HDC hdc, UINT version);\n\n")
2019 f.write("#endif /* __WINE_VULKAN_DRIVER_H */\n")
2022 class VkRegistry(object):
2023 def __init__(self, reg_filename):
2024 # Used for storage of type information.
2025 self.base_types = None
2026 self.bitmasks = None
2030 self.funcpointers = None
2034 # We aggregate all types in here for cross-referencing.
2038 # Overall strategy for parsing the registry is to first
2039 # parse all type / function definitions. Then parse
2040 # features and extensions to decide which types / functions
2041 # to actually 'pull in' for code generation. For each type or
2042 # function call we want we set a member 'required' to True.
2043 tree = ET.parse(reg_filename)
2044 root = tree.getroot()
2045 self._parse_enums(root)
2046 self._parse_types(root)
2047 self._parse_commands(root)
2049 # Pull in any required types and functions.
2050 self._parse_features(root)
2051 self._parse_extensions(root)
2053 def _mark_command_required(self, command):
2054 """ Helper function to mark a certain command and the datatypes it needs as required."""
2055 def mark_bitmask_dependencies(bitmask, types):
2056 if bitmask.requires is not None:
2057 types[bitmask.requires]["data"].required = True
2059 def mark_funcpointer_dependencies(fp, types):
2060 for m in fp.members:
2061 type_info = types[m.type]
2063 # Complex types have a matching definition e.g. VkStruct.
2064 # Not needed for base types such as uint32_t.
2065 if "data" in type_info:
2066 types[m.type]["data"].required = True
2068 def mark_struct_dependencies(struct, types):
2070 type_info = types[m.type]
2072 # Complex types have a matching definition e.g. VkStruct.
2073 # Not needed for base types such as uint32_t.
2074 if "data" in type_info:
2075 types[m.type]["data"].required = True
2077 if type_info["category"] == "struct":
2079 mark_struct_dependencies(type_info["data"], types)
2080 elif type_info["category"] == "funcpointer":
2081 mark_funcpointer_dependencies(type_info["data"], types)
2082 elif type_info["category"] == "bitmask":
2083 mark_bitmask_dependencies(type_info["data"], types)
2085 func = self.funcs[command]
2086 func.required = True
2088 # Pull in return type
2089 if func.type != "void":
2090 self.types[func.type]["data"].required = True
2092 # Analyze parameter dependencies and pull in any type needed.
2093 for p in func.params:
2094 type_info = self.types[p.type]
2096 # Check if we are dealing with a complex type e.g. VkEnum, VkStruct and others.
2097 if "data" not in type_info:
2100 # Mark the complex type as required.
2101 type_info["data"].required = True
2102 if type_info["category"] == "struct":
2103 struct = type_info["data"]
2104 mark_struct_dependencies(struct, self.types)
2106 def _parse_commands(self, root):
2107 """ Parse command section containing the Vulkan function calls. """
2109 commands = root.findall("./commands/")
2110 for command in commands:
2111 func = VkFunction.from_xml(command, self.types)
2112 funcs[func.name] = func
2114 # To make life easy for the code generation, separate all function
2115 # calls out in the 3 types of vulkan functions: device, global and instance.
2119 for func in funcs.values():
2120 if func.is_device_func():
2121 device_funcs.append(func)
2122 elif func.is_global_func():
2123 global_funcs.append(func)
2125 instance_funcs.append(func)
2127 # Sort function lists by name and store them.
2128 self.device_funcs = sorted(device_funcs, key=lambda func: func.name)
2129 self.global_funcs = sorted(global_funcs, key=lambda func: func.name)
2130 self.instance_funcs = sorted(instance_funcs, key=lambda func: func.name)
2132 # The funcs dictionary is used as a convenient way to lookup function
2133 # calls when needed e.g. to adjust member variables.
2134 self.funcs = OrderedDict(sorted(funcs.items()))
2136 def _parse_enums(self, root):
2137 """ Parse enums section or better described as constants section. """
2140 for enum in root.findall("./enums"):
2141 name = enum.attrib.get("name")
2142 _type = enum.attrib.get("type")
2144 if _type in ("enum", "bitmask"):
2145 enums[name] = VkEnum.from_xml(enum)
2147 # If no type is set, we are dealing with API constants.
2149 for value in enum.findall("enum"):
2150 self.consts.append(VkConstant(value.attrib.get("name"), value.attrib.get("value")))
2152 self.enums = OrderedDict(sorted(enums.items()))
2154 def _parse_extensions(self, root):
2155 """ Parse extensions section and pull in any types and commands for this extensioin. """
2157 exts = root.findall("./extensions/extension")
2159 ext_name = ext.attrib["name"]
2161 # Some extensions are not ready or have numbers reserved as a place holder.
2162 if ext.attrib["supported"] == "disabled":
2163 LOGGER.debug("Skipping disabled extension: {0}".format(ext_name))
2166 # We only support a handful of extensions for now through a whitelist.
2167 if ext_name not in SUPPORTED_EXTENSIONS:
2168 LOGGER.debug("Skipping blacklisted extension: {0}".format(ext_name))
2171 LOGGER.debug("Loading extension: {0}".format(ext_name))
2173 # Extensions can add enum values to Core / extension enums, so add these.
2174 enums = ext.findall("require/enum")
2175 for enum_elem in enums:
2176 if "bitpos" in enum_elem.keys():
2177 # We need to add an extra value to an existing enum type.
2178 # E.g. VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG to VkFormatFeatureFlagBits.
2179 type_name = enum_elem.attrib["extends"]
2180 enum = self.types[type_name]["data"]
2181 enum.add(VkEnumValue(enum_elem.attrib["name"], 1 << int(enum_elem.attrib["bitpos"]), hex=True))
2182 elif "offset" in enum_elem.keys():
2183 ext_number = int(ext.attrib["number"])
2184 offset = int(enum_elem.attrib["offset"])
2185 value = EXT_BASE + (ext_number - 1) * EXT_BLOCK_SIZE + offset
2187 # Deal with negative values.
2188 direction = enum_elem.attrib.get("dir")
2189 if direction is not None:
2192 type_name = enum_elem.attrib["extends"]
2193 enum = self.types[type_name]["data"]
2194 enum.add(VkEnumValue(enum_elem.attrib["name"], value))
2196 elif "value" in enum_elem.keys():
2197 # For now skip, it mostly contains extension name and version info.
2200 # This seems to be used to pull in constants e.g. VK_MAX_DEVICE_GROUP_KHX
2203 # Store a list with extensions.
2204 ext_type = ext.attrib["type"]
2205 ext_info = {"name" : ext_name, "type" : ext_type}
2206 extensions.append(ext_info)
2208 commands = ext.findall("require/command")
2212 # Pull in any commands we need. We infer types to pull in from the command
2214 for command in commands:
2215 cmd_name = command.attrib["name"]
2216 self._mark_command_required(cmd_name)
2218 # Set extension name on the function call as we were not aware of the
2219 # name during initial parsing.
2220 self.funcs[cmd_name].extension = ext_name
2222 # Sort in alphabetical order.
2223 self.extensions = sorted(extensions, key=lambda ext: ext["name"])
2225 def _parse_features(self, root):
2226 """ Parse the feature section, which describes Core commands and types needed. """
2227 requires = root.findall("./feature/require")
2229 for require in requires:
2230 LOGGER.info("Including features for {0}".format(require.attrib.get("comment")))
2232 # Only deal with command. Other values which appear are enum and type for pulling in some
2233 # constants and macros. Tricky to parse, so don't bother right now, we will generate them
2235 name = tag.attrib["name"]
2236 if tag.tag == "command":
2237 self._mark_command_required(name)
2238 elif tag.tag == "enum":
2239 # We could pull in relevant constants here. Unfortunately
2240 # this only gets half of them pulled in as others indirectly
2241 # get pulled in through structures. Constants don't harm us,
2244 elif tag.tag == "type":
2245 # Pull in types which may not have been pulled in through commands.
2247 # Skip pull in for vk_platform.h for now.
2248 if name == "vk_platform":
2251 type_info = self.types[name]
2252 type_info["data"].required = True
2254 def _parse_types(self, root):
2255 """ Parse types section, which contains all data types e.g. structs, typedefs etcetera. """
2256 types = root.findall("./types/type")
2267 type_info["category"] = t.attrib.get("category", None)
2269 if type_info["category"] in ["include"]:
2272 if type_info["category"] == "basetype":
2273 name = t.find("name").text
2274 _type = t.find("type").text
2275 basetype = VkBaseType(name, _type)
2276 base_types.append(basetype)
2277 type_info["data"] = basetype
2279 if type_info["category"] == "bitmask":
2280 name = t.find("name").text
2281 _type = t.find("type").text
2283 # Most bitmasks have a requires attribute used to pull in
2284 # required '*FlagBits" enum.
2285 requires = t.attrib.get("requires")
2286 bitmask = VkBaseType(name, _type, requires=requires)
2287 bitmasks.append(bitmask)
2288 type_info["data"] = bitmask
2290 if type_info["category"] == "define":
2291 name = t.attrib.get("name")
2292 define = VkDefine.from_xml(t)
2293 defines.append(define)
2294 type_info["data"] = define
2296 if type_info["category"] == "enum":
2297 name = t.attrib.get("name")
2298 # The type section only contains enum names, not the actual definition.
2299 # Since we already parsed the enum before, just link it in.
2301 type_info["data"] = self.enums[name]
2302 except KeyError as e:
2303 # Not all enums seem to be defined yet, typically that's for
2304 # ones ending in 'FlagBits' where future extensions may add
2306 type_info["data"] = None
2308 if type_info["category"] == "funcpointer":
2309 funcpointer = VkFunctionPointer.from_xml(t)
2310 funcpointers.append(funcpointer)
2311 type_info["data"] = funcpointer
2313 if type_info["category"] == "handle":
2314 handle = VkHandle.from_xml(t)
2315 handles.append(handle)
2316 type_info["data"] = handle
2318 if type_info["category"] in ["struct", "union"]:
2319 # We store unions among structs as some structs depend
2320 # on unions. The types are very similar in parsing and
2321 # generation anyway. The official vulkan scripts use
2322 # a similar kind of hack.
2323 struct = VkStruct.from_xml(t)
2324 structs.append(struct)
2325 type_info["data"] = struct
2327 # Name is in general within a name tag else it is an optional
2328 # attribute on the type tag.
2329 name_elem = t.find("name")
2330 if name_elem is not None:
2331 type_info["name"] = name_elem.text
2333 type_info["name"] = t.attrib.get("name", None)
2335 # Store all type data in a shared dictionary, so we can easily
2336 # look up information for a given type. There are no duplicate
2338 self.types[type_info["name"]] = type_info
2340 # We need detailed type information during code generation
2341 # on structs for alignment reasons. Unfortunately structs
2342 # are parsed among other types, so there is no guarantee
2343 # that any types needed have been parsed already, so set
2345 for struct in structs:
2346 struct.set_type_info(self.types)
2348 # Guarantee everything is sorted, so code generation doesn't have
2349 # to deal with this.
2350 self.base_types = sorted(base_types, key=lambda base_type: base_type.name)
2351 self.bitmasks = sorted(bitmasks, key=lambda bitmask: bitmask.name)
2352 self.defines = defines
2353 self.funcpointers = sorted(funcpointers, key=lambda fp: fp.name)
2354 self.handles = sorted(handles, key=lambda handle: handle.name)
2355 self.structs = sorted(structs, key=lambda struct: struct.name)
2359 parser = argparse.ArgumentParser()
2360 parser.add_argument("-v", "--verbose", action="count", default=0, help="increase output verbosity")
2362 args = parser.parse_args()
2363 if args.verbose == 0:
2364 LOGGER.setLevel(logging.WARNING)
2365 elif args.verbose == 1:
2366 LOGGER.setLevel(logging.INFO)
2368 LOGGER.setLevel(logging.DEBUG)
2370 registry = VkRegistry("vk.xml")
2371 generator = VkGenerator(registry)
2373 with open(WINE_VULKAN_H, "w") as f:
2374 generator.generate_vulkan_h(f)
2376 with open(WINE_VULKAN_DRIVER_H, "w") as f:
2377 generator.generate_vulkan_driver_h(f)
2379 with open(WINE_VULKAN_THUNKS_H, "w") as f:
2380 generator.generate_thunks_h(f, "wine_")
2382 with open(WINE_VULKAN_THUNKS_C, "w") as f:
2383 generator.generate_thunks_c(f, "wine_")
2385 if __name__ == "__main__":