winevulkan: Implement VK_KHR_get_physical_device_properties2.
[wine.git] / dlls / winevulkan / make_vulkan
blobb8eaafa4bd45ee950ee528cbe2c2b47d4e1d5936
1 #!/usr/bin/python3
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
21 import argparse
22 import logging
23 import re
24 import sys
25 import xml.etree.ElementTree as ET
26 from collections import OrderedDict
27 from collections.abc import Sequence
28 from enum import Enum
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)
73 # of values.
74 # Start for a given extension is:
75 # EXT_BASE + (extension_number-1) * EXT_BLOCK_SIZE
76 EXT_BASE = 1000000000
77 EXT_BLOCK_SIZE = 1000
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 = [
83     "VK_KHR_get_physical_device_properties2",
84     "VK_KHR_surface",
85     "VK_KHR_win32_surface",
86     "VK_KHR_swapchain",
89 # Functions part of our winevulkan graphics driver interface.
90 # DRIVER_VERSION should be bumped on any change to driver interface
91 # in FUNCTION_OVERRIDES
92 DRIVER_VERSION = 3
94 # Table of functions for which we have a special implementation.
95 # This are regular device / instance functions for which we need
96 # to more work compared to a regular thunk  or because they are
97 # part of the driver interface.
98 # - dispatch set whether we need a function pointer in the device
99 #   / instance dispatch table.
100 # - driver sets whether the api is part of the driver interface.
101 # - thunk sets whether to create a thunk in vulkan_thunks.c.
102 FUNCTION_OVERRIDES = {
103     # Global functions
104     "vkCreateInstance" : {"dispatch" : False, "driver" : True, "thunk" : False},
105     "vkEnumerateInstanceExtensionProperties" : {"dispatch" : False, "driver" : True, "thunk" : False},
106     "vkGetInstanceProcAddr": {"dispatch" : False, "driver" : True, "thunk" : False},
108     # Instance functions
109     "vkCreateDevice" : {"dispatch" : True, "driver" : False, "thunk" : False},
110     "vkDestroyInstance" : {"dispatch" : True, "driver" : True, "thunk" : False },
111     "vkEnumerateDeviceExtensionProperties" : {"dispatch" : True, "driver" : False, "thunk" : False},
112     "vkEnumeratePhysicalDevices" : {"dispatch" : True, "driver" : False, "thunk" : False},
114     # Device functions
115     "vkAllocateCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : False},
116     "vkCmdExecuteCommands" : {"dispatch" : True, "driver" : False, "thunk" : False},
117     "vkDestroyDevice" : {"dispatch" : True, "driver" : False, "thunk" : False},
118     "vkFreeCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : False},
119     "vkGetDeviceProcAddr" : {"dispatch" : True, "driver" : True, "thunk" : False},
120     "vkGetDeviceQueue" : {"dispatch": True, "driver" : False, "thunk" : False},
121     "vkQueueSubmit" : {"dispatch": True, "driver" : False, "thunk" : False},
123     # VK_KHR_surface
124     "vkDestroySurfaceKHR" : {"dispatch" : True, "driver" : True, "thunk" : False},
125     "vkGetPhysicalDeviceSurfaceSupportKHR" : {"dispatch" : True, "driver" : True, "thunk" : False},
126     "vkGetPhysicalDeviceSurfaceCapabilitiesKHR" : {"dispatch" : True, "driver" : True, "thunk" : False},
127     "vkGetPhysicalDeviceSurfaceFormatsKHR" : {"dispatch" : True, "driver" : True, "thunk" : False},
128     "vkGetPhysicalDeviceSurfacePresentModesKHR" : {"dispatch" : True, "driver" : True, "thunk" : False},
130     # VK_KHR_win32_surface
131     "vkCreateWin32SurfaceKHR" : {"dispatch" : True, "driver" : True, "thunk" : False},
132     "vkGetPhysicalDeviceWin32PresentationSupportKHR" : {"dispatch" : True, "driver" : True, "thunk" : False},
134     # VK_KHR_swapchain
135     "vkAcquireNextImageKHR": {"dispatch" : True, "driver" : True, "thunk" : False},
136     "vkCreateSwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : False},
137     "vkDestroySwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : False},
138     "vkGetSwapchainImagesKHR": {"dispatch" : True, "driver" : True, "thunk" : False},
139     "vkQueuePresentKHR": {"dispatch" : True, "driver" : True, "thunk" : False},
143 class Direction(Enum):
144     """ Parameter direction: input, output, input_output. """
145     INPUT = 1
146     OUTPUT = 2
147     INPUT_OUTPUT = 3
150 class VkBaseType(object):
151     def __init__(self, name, _type, requires=None):
152         """ Vulkan base type class.
154         VkBaseType is mostly used by Vulkan to define its own
155         base types like VkFlags through typedef out of e.g. uint32_t.
157         Args:
158             name (:obj:'str'): Name of the base type.
159             _type (:obj:'str'): Underlaying type
160             requires (:obj:'str', optional): Other types required.
161                 Often bitmask values pull in a *FlagBits type.
162         """
163         self.name = name
164         self.type = _type
165         self.requires = requires
166         self.required = False
168     def definition(self):
169         text = "typedef {0} {1};\n".format(self.type, self.name)
170         return text
173 class VkConstant(object):
174     def __init__(self, name, value):
175         self.name = name
176         self.value = value
178     def definition(self):
179         text = "#define {0} {1}\n".format(self.name, self.value)
180         return text
183 class VkDefine(object):
184     def __init__(self, name, value):
185         self.name = name
186         self.value = value
188     @staticmethod
189     def from_xml(define):
190         name_elem = define.find("name")
192         if name_elem is None:
193             # <type category="define" name="some_name">some_value</type>
194             # At the time of writing there is only 1 define of this category
195             # 'VK_DEFINE_NON_DISPATCHABLE_HANDLE'.
196             name = define.attrib.get("name")
198             # We override behavior of VK_DEFINE_NON_DISPATCHABLE handle as the default
199             # definition various between 64-bit (uses pointers) and 32-bit (uses uint64_t).
200             # This complicates TRACEs in the thunks, so just use uint64_t.
201             if name == "VK_DEFINE_NON_DISPATCHABLE_HANDLE":
202                 value = "#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object;"
203             else:
204                 value = define.text
205             return VkDefine(name, value)
207         # With a name element the structure is like:
208         # <type category="define"><name>some_name</name>some_value</type>
209         name = name_elem.text
211         # VK_API_VERSION is a deprecated constant and we don't really want to parse it or generate
212         # code for it. However the vk.xml feature section still references it.
213         if name == "VK_API_VERSION":
214             return VkDefine(name, "")
216         # The body of the define is basically unstructured C code. It is not meant for easy parsing.
217         # Some lines contain deprecated values or comments, which we try to filter out.
218         value = ""
219         for line in define.text.splitlines():
220             # Skip comments or deprecated values.
221             if "//" in line:
222                 continue
223             value += line
225         for child in define:
226             value += child.text
227             if child.tail is not None:
228                 value += child.tail
230         return VkDefine(name, value.rstrip(' '))
232     def definition(self):
233         if self.value is None:
234             return ""
236         # Nothing to do as the value was already put in the right form during parsing.
237         return "{0}\n".format(self.value)
240 class VkEnum(object):
241     def __init__(self, name, values):
242         self.name = name
243         self.values = values
244         self.required = False
246     @staticmethod
247     def from_xml(enum):
248         name = enum.attrib.get("name")
249         values = []
251         for v in enum.findall("enum"):
252             # Value is either a value or a bitpos, only one can exist.
253             value = v.attrib.get("value")
254             if value is None:
255                 # bitmask
256                 value = 1 << int(v.attrib.get("bitpos"))
257                 values.append(VkEnumValue(v.attrib.get("name"), value, hex=True))
258             else:
259                 # Some values are in hex form. We want to preserve the hex representation
260                 # at least when we convert back to a string. Internally we want to use int.
261                 if "0x" in value:
262                     values.append(VkEnumValue(v.attrib.get("name"), int(value, 0), hex=True))
263                 else:
264                     values.append(VkEnumValue(v.attrib.get("name"), int(value, 0)))
266         # vulkan.h contains a *_MAX_ENUM value set to 32-bit at the time of writing,
267         # which is to prepare for extensions as they can add values and hence affect
268         # the size definition.
269         max_name = re.sub(r'([0-9a-z_])([A-Z0-9])',r'\1_\2',name).upper() + "_MAX_ENUM"
270         values.append(VkEnumValue(max_name, 0x7fffffff, hex=True))
272         return VkEnum(name, values)
274     def add(self, value):
275         """ Add a value to enum. """
276         self.values.append(value)
278     def definition(self):
279         text = "typedef enum {0}\n{{\n".format(self.name)
281         # Print values sorted, values can have been added in a random order.
282         values = sorted(self.values, key=lambda value: value.value)
283         for value in values:
284             text += "    {0},\n".format(value.definition())
285         text += "}} {0};\n\n".format(self.name)
286         return text
289 class VkEnumValue(object):
290     def __init__(self, name, value, hex=False):
291         self.name = name
292         self.value = value
293         self.hex = hex
295     def __repr__(self):
296         return "{0}={1}".format(self.name, self.value)
298     def definition(self):
299         """ Convert to text definition e.g. VK_FOO = 1 """
301         # Hex is commonly used for FlagBits and sometimes within
302         # a non-FlagBits enum for a bitmask value as well.
303         if self.hex:
304             return "{0} = 0x{1:08x}".format(self.name, self.value)
305         else:
306             return "{0} = {1}".format(self.name, self.value)
309 class VkFunction(object):
310     def __init__(self, _type=None, name=None, params=[], extension=None):
311         self.extension = extension
312         self.name = name
313         self.type = _type
314         self.params = params
316         # For some functions we need some extra metadata from FUNCTION_OVERRIDES.
317         func_info = FUNCTION_OVERRIDES.get(self.name, None)
318         self.dispatch = func_info["dispatch"] if func_info is not None else True
319         self.driver = func_info["driver"] if func_info is not None else False
320         self.thunk_needed = func_info["thunk"] if func_info is not None else True
322         # Required is set while parsing which APIs and types are required
323         # and is used by the code generation.
324         self.required = False
326     @staticmethod
327     def from_xml(command, types):
328         proto = command.find("proto")
330         func_name = proto.find("name").text
331         func_type = proto.find("type").text
333         params = []
334         for param in command.findall("param"):
335             vk_param = VkParam.from_xml(param, types)
336             params.append(vk_param)
338         return VkFunction(_type=func_type, name=func_name, params=params)
340     def get_conversions(self):
341         """ Get a list of conversion functions required for this function if any.
342         Parameters which are structures may require conversion between win32
343         and the host platform. This function returns a list of conversions
344         required.
345         """
347         conversions = []
348         for param in self.params:
349             convs = param.get_conversions()
350             if convs is not None:
351                 conversions.extend(convs)
353         return conversions
355     def is_device_func(self):
356         # If none of the other, it must be a device function
357         return not self.is_global_func() and not self.is_instance_func()
359     def is_driver_func(self):
360         """ Returns if function is part of Wine driver interface. """
361         return self.driver
363     def is_global_func(self):
364         # Treat vkGetInstanceProcAddr as a global function as it
365         # can operate with NULL for vkInstance.
366         if self.name == "vkGetInstanceProcAddr":
367             return True
368         # Global functions are not passed a dispatchable object.
369         elif self.params[0].is_dispatchable():
370             return False
371         return True
373     def is_instance_func(self):
374         # Instance functions are passed VkInstance or VkPhysicalDevice.
375         if self.params[0].type in ["VkInstance", "VkPhysicalDevice"]:
376             return True
377         return False
379     def is_required(self):
380         return self.required
382     def needs_conversion(self):
383         """ Check if the function needs any input/output type conversion.
384         Functions need input/output conversion if struct parameters have
385         alignment differences between Win32 and Linux 32-bit.
386         """
388         for p in self.params:
389             if p.needs_conversion():
390                 LOGGER.debug("Parameter {0} to {1} requires conversion".format(p.name, self.name))
391                 return True
393         return False
395     def needs_dispatch(self):
396         return self.dispatch
398     def needs_thunk(self):
399         return self.thunk_needed
401     def pfn(self, call_conv=None, conv=False):
402         """ Create function pointer. """
404         if call_conv is not None:
405             pfn = "{0} ({1} *p_{2})(".format(self.type, call_conv, self.name)
406         else:
407             pfn = "{0} (*p_{1})(".format(self.type, self.name)
409         for i, param in enumerate(self.params):
410             if param.const:
411                 pfn += param.const + " "
413             pfn += param.type
414             if conv and param.needs_conversion():
415                 pfn += "_host"
417             if param.is_pointer():
418                 pfn += " " + param.pointer
420             if param.array_len is not None:
421                 pfn += "[{0}]".format(param.array_len)
423             if i < len(self.params) - 1:
424                 pfn += ", "
425         pfn += ")"
426         return pfn
428     def prototype(self, call_conv=None, prefix=None, postfix=None):
429         """ Generate prototype for given function.
431         Args:
432             call_conv (str, optional): calling convention e.g. WINAPI
433             prefix (str, optional): prefix to append prior to function name e.g. vkFoo -> wine_vkFoo
434             postfix (str, optional): text to append after function name but prior to semicolon e.g. DECLSPEC_HIDDEN
435         """
437         proto = "{0}".format(self.type)
439         if call_conv is not None:
440             proto += " {0}".format(call_conv)
442         if prefix is not None:
443             proto += " {0}{1}(".format(prefix, self.name)
444         else:
445             proto += " {0}(".format(self.name)
447         # Add all the paremeters.
448         proto += ", ".join([p.definition() for p in self.params])
450         if postfix is not None:
451             proto += ") {0}".format(postfix)
452         else:
453             proto += ")"
455         return proto
457     def body(self):
458         body = "    {0}".format(self.trace())
460         params = ", ".join([p.variable(conv=False) for p in self.params])
462         # Call the native Vulkan function.
463         if self.type == "void":
464             body += "    {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
465         else:
466             body += "    return {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
468         return body
470     def body_conversion(self):
471         body = ""
473         # Declare a variable to hold the result for non-void functions.
474         if self.type != "void":
475             body += "    {0} result;\n".format(self.type)
477         # Declare any tmp parameters for conversion.
478         for p in self.params:
479             if not p.needs_conversion():
480                 continue
482             if p.is_dynamic_array():
483                 body += "    {0}_host *{1}_host;\n".format(p.type, p.name)
484             else:
485                 body += "    {0}_host {1}_host;\n".format(p.type, p.name)
487         body += "    {0}\n".format(self.trace())
489         # Call any win_to_host conversion calls.
490         for p in self.params:
491             if not p.needs_input_conversion():
492                 continue
494             body += p.copy(Direction.INPUT)
496         # Build list of parameters containing converted and non-converted parameters.
497         # The param itself knows if conversion is needed and applies it when we set conv=True.
498         params = ", ".join([p.variable(conv=True) for p in self.params])
500         # Call the native Vulkan function.
501         if self.type == "void":
502             body += "    {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
503         else:
504             body += "    result = {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
506         body += "\n"
508         # Call any host_to_win conversion calls.
509         for p in self.params:
510             if not p.needs_output_conversion():
511                 continue
513             body += p.copy(Direction.OUTPUT)
515         # Perform any required cleanups. Most of these are for array functions.
516         for p in self.params:
517             if not p.needs_free():
518                 continue
520             body += p.free()
522         # Finally return the result.
523         if self.type != "void":
524             body += "    return result;\n"
526         return body
528     def stub(self, call_conv=None, prefix=None):
529         stub = self.prototype(call_conv=call_conv, prefix=prefix)
530         stub += "\n{\n"
531         stub += "    {0}".format(self.trace(message="stub: ", trace_func="FIXME"))
533         if self.type == "VkResult":
534             stub += "    return VK_ERROR_OUT_OF_HOST_MEMORY;\n"
535         elif self.type == "VkBool32":
536             stub += "    return VK_FALSE;\n"
537         elif self.type == "PFN_vkVoidFunction":
538             stub += "    return NULL;\n"
540         stub += "}\n\n"
541         return stub
543     def thunk(self, call_conv=None, prefix=None):
544         thunk = self.prototype(call_conv=call_conv, prefix=prefix)
545         thunk += "\n{\n"
547         if self.needs_conversion():
548             thunk += "#if defined(USE_STRUCT_CONVERSION)\n"
549             thunk += self.body_conversion()
550             thunk += "#else\n"
551             thunk += self.body()
552             thunk += "#endif\n"
553         else:
554             thunk += self.body()
556         thunk += "}\n\n"
557         return thunk
559     def trace(self, message=None, trace_func=None):
560         """ Create a trace string including all parameters.
562         Args:
563             message (str, optional): text to print at start of trace message e.g. 'stub: '
564             trace_func (str, optional): used to override trace function e.g. FIXME, printf, etcetera.
565         """
566         if trace_func is not None:
567             trace = "{0}(\"".format(trace_func)
568         else:
569             trace = "TRACE(\""
571         if message is not None:
572             trace += message
574         # First loop is for all the format strings.
575         trace += ", ".join([p.format_string() for p in self.params])
576         trace += "\\n\""
578         # Second loop for parameter names and optional conversions.
579         for param in self.params:
580             if param.format_conv is not None:
581                 trace += ", " + param.format_conv.format(param.name)
582             else:
583                 trace += ", {0}".format(param.name)
584         trace += ");\n"
586         return trace
589 class VkFunctionPointer(object):
590     def __init__(self, _type, name, members):
591         self.name = name
592         self.members = members
593         self.type = _type
594         self.required = False
596     @staticmethod
597     def from_xml(funcpointer):
598         members = []
599         begin = None
601         for t in funcpointer.findall("type"):
602             # General form:
603             # <type>void</type>*       pUserData,
604             # Parsing of the tail (anything past </type>) is tricky since there
605             # can be other data on the next line like: const <type>int</type>..
606             const = begin
607             _type = t.text
608             lines = t.tail.split(",\n")
609             if lines[0][0] == "*":
610                 pointer = "*"
611                 name = lines[0][1:].strip()
612             else:
613                 pointer = None
614                 name = lines[0].strip()
616             # Filter out ); if it is contained.
617             name = name.partition(");")[0]
619             # If tail encompasses multiple lines, assign the second line to begin
620             # for the next line.
621             try:
622                 begin = lines[1].strip()
623             except IndexError:
624                 begin = None
626             members.append(VkMember(const=const, _type=_type, pointer=pointer, name=name))
628         _type = funcpointer.text
629         name = funcpointer.find("name").text
630         return VkFunctionPointer(_type, name, members)
632     def definition(self):
633         text = "{0} {1})(\n".format(self.type, self.name)
635         first = True
636         if len(self.members) > 0:
637             for m in self.members:
638                 if first:
639                     text += "    " + m.definition()
640                     first = False
641                 else:
642                     text += ",\n    " + m.definition()
643         else:
644             # Just make the compiler happy by adding a void parameter.
645             text += "void"
646         text += ");\n"
647         return text
650 class VkHandle(object):
651     def __init__(self, name, _type, parent):
652         self.name = name
653         self.type = _type
654         self.parent = parent
655         self.required = False
657     @staticmethod
658     def from_xml(handle):
659         name = handle.find("name").text
660         _type = handle.find("type").text
661         parent = handle.attrib.get("parent") # Most objects have a parent e.g. VkQueue has VkDevice.
662         return VkHandle(name, _type, parent)
664     def dispatch_table(self):
665         if not self.is_dispatchable():
666             return None
668         if self.parent is None:
669             # Should only happen for VkInstance
670             return "funcs"
671         elif self.name == "VkDevice":
672             # VkDevice has VkInstance as a parent, but has its own dispatch table.
673             return "funcs"
674         elif self.parent in ["VkInstance", "VkPhysicalDevice"]:
675             return "instance->funcs"
676         elif self.parent in ["VkDevice", "VkCommandPool"]:
677             return "device->funcs"
678         else:
679             LOGGER.error("Unhandled dispatchable parent: {0}".format(self.parent))
681     def definition(self):
682         """ Generates handle definition e.g. VK_DEFINE_HANDLE(vkInstance) """
683         return "{0}({1})\n".format(self.type, self.name)
685     def is_dispatchable(self):
686         """ Some handles like VkInstance, VkDevice are dispatchable objects,
687         which means they contain a dispatch table of function pointers.
688         """
689         return self.type == "VK_DEFINE_HANDLE"
691     def native_handle(self):
692         """ Provide access to the native handle of a dispatchable object.
694         Dispatchable objects wrap an underlying 'native' object.
695         This method provides access to the native object.
696         """
697         if not self.is_dispatchable():
698             return None
700         if self.name == "VkCommandBuffer":
701             return "command_buffer"
702         elif self.name == "VkDevice":
703             return "device"
704         elif self.name == "VkInstance":
705             return "instance"
706         elif self.name == "VkPhysicalDevice":
707             return "phys_dev"
708         elif self.name == "VkQueue":
709             return "queue"
710         else:
711             LOGGER.error("Unhandled native handle for: {0}".format(self.name))
714 class VkMember(object):
715     def __init__(self, const=None, _type=None, pointer=None, name=None, array_len=None, dyn_array_len=None, optional=False,
716             extension_structs=None):
717         self.const = const
718         self.name = name
719         self.pointer = pointer
720         self.type = _type
721         self.type_info = None
722         self.array_len = array_len
723         self.dyn_array_len = dyn_array_len
724         self.optional = optional
725         self.extension_structs = extension_structs
727     def __eq__(self, other):
728         """ Compare member based on name against a string.
730         This method is for convenience by VkStruct, which holds a number of members and needs quick checking
731         if certain members exist.
732         """
734         if self.name == other:
735             return True
737         return False
739     def __repr__(self):
740         return "{0} {1} {2} {3} {4} {5}".format(self.const, self.type, self.pointer, self.name, self.array_len,
741                 self.dyn_array_len)
743     @staticmethod
744     def from_xml(member):
745         """ Helper function for parsing a member tag within a struct or union. """
747         name_elem = member.find("name")
748         type_elem = member.find("type")
750         const = member.text.strip() if member.text else None
751         member_type = None
752         pointer = None
753         array_len = None
755         if type_elem is not None:
756             member_type = type_elem.text
757             if type_elem.tail is not None:
758                 pointer = type_elem.tail.strip() if type_elem.tail.strip() != "" else None
760         # Name of other member within, which stores the number of
761         # elements pointed to be by this member.
762         dyn_array_len = member.get("len", None)
764         if "validextensionstructs" in member.attrib:
765             extension_structs = member.get("validextensionstructs").split(",")
766         else:
767             extension_structs = None
769         # Some members are optional, which is important for conversion code e.g. not dereference NULL pointer.
770         optional = True if member.get("optional") else False
772         # Usually we need to allocate memory for dynamic arrays. We need to do the same in a few other cases
773         # like for VkCommandBufferBeginInfo.pInheritanceInfo. Just threat such cases as dynamic arrays of
774         # size 1 to simplify code generation.
775         if dyn_array_len is None and pointer is not None:
776             dyn_array_len = 1
778         # Some members are arrays, attempt to parse these. Formats include:
779         # <member><type>char</type><name>extensionName</name>[<enum>VK_MAX_EXTENSION_NAME_SIZE</enum>]</member>
780         # <member><type>uint32_t</type><name>foo</name>[4]</member>
781         if name_elem.tail and name_elem.tail[0] == '[':
782             LOGGER.debug("Found array type")
783             enum_elem = member.find("enum")
784             if enum_elem is not None:
785                 array_len = enum_elem.text
786             else:
787                 # Remove brackets around length
788                 array_len = name_elem.tail.strip("[]")
790         return VkMember(const=const, _type=member_type, pointer=pointer, name=name_elem.text, array_len=array_len,
791                 dyn_array_len=dyn_array_len, optional=optional, extension_structs=extension_structs)
793     def copy(self, input, output, direction):
794         """ Helper method for use by conversion logic to generate a C-code statement to copy this member. """
796         if self.needs_conversion():
797             if self.is_dynamic_array():
798                 if direction == Direction.OUTPUT:
799                     LOGGER.warn("TODO: implement copying of returnedonly dynamic array for {0}.{1}".format(self.type, self.name))
800                 else:
801                     # Array length is either a variable name (string) or an int.
802                     count = self.dyn_array_len if isinstance(self.dyn_array_len, int) else "{0}{1}".format(input, self.dyn_array_len)
803                     return "{0}{1} = convert_{2}_array_win_to_host({3}{1}, {4});\n".format(output, self.name, self.type, input, count)
804             elif self.is_static_array():
805                 count = self.array_len
806                 if direction == Direction.OUTPUT:
807                     # Needed by VkMemoryHeap.memoryHeaps
808                     return "convert_{0}_static_array_host_to_win({2}{1}, {3}{1}, {4});\n".format(self.type, self.name, input, output, count)
809                 else:
810                     # Nothing needed this yet.
811                     LOGGER.warn("TODO: implement copying of static array for {0}.{1}".format(self.type, self.name))
812             else:
813                 if direction == Direction.OUTPUT:
814                     return "convert_{0}_host_to_win(&{2}{1}, &{3}{1});\n".format(self.type, self.name, input, output)
815                 else:
816                     return "convert_{0}_win_to_host(&{2}{1}, &{3}{1});\n".format(self.type, self.name, input, output)
817         elif self.is_static_array():
818             bytes_count = "{0} * sizeof({1})".format(self.array_len, self.type)
819             return "memcpy({0}{1}, {2}{1}, {3});\n".format(output, self.name, input, bytes_count)
820         else:
821             return "{0}{1} = {2}{1};\n".format(output, self.name, input)
823     def definition(self, align=False, conv=False):
824         """ Generate prototype for given function.
826         Args:
827             align (bool, optional): Enable alignment if a type needs it. This adds WINE_VK_ALIGN(8) to a member.
828             conv (bool, optional): Enable conversion if a type needs it. This appends '_host' to the name.
829         """
831         text = ""
832         if self.is_const():
833             text += "const "
835         if conv and self.is_struct():
836             text += "{0}_host".format(self.type)
837         else:
838             text += self.type
840         if self.is_pointer():
841             text += " {0}{1}".format(self.pointer, self.name)
842         else:
843             if align and self.needs_alignment():
844                 text += " WINE_VK_ALIGN(8) " + self.name
845             else:
846                 text += " " + self.name
848         if self.is_static_array():
849             text += "[{0}]".format(self.array_len)
851         return text
853     def get_conversions(self):
854         """ Return any conversion description for this member and its children when conversion is needed. """
856         # Check if we need conversion either for this member itself or for any child members
857         # in case member represents a struct.
858         if not self.needs_conversion():
859             return None
861         conversions = []
863         # Collect any conversion for any member structs.
864         struct = self.type_info["data"]
865         for m in struct:
866             if m.needs_conversion():
867                 conversions.extend(m.get_conversions())
869         struct = self.type_info["data"]
870         direction = Direction.OUTPUT if struct.returnedonly else Direction.INPUT
871         if self.is_dynamic_array():
872             conversions.append(ConversionFunction(False, True, direction, struct))
873         elif self.is_static_array():
874             conversions.append(ConversionFunction(True, False, direction, struct))
875         else:
876             conversions.append(ConversionFunction(False, False, direction, struct))
878         if self.needs_free():
879             conversions.append(FreeFunction(self.is_dynamic_array(), struct))
881         return conversions
883     def is_const(self):
884         return self.const is not None
886     def is_dynamic_array(self):
887         """ Returns if the member is an array element.
888         Vulkan uses this for dynamically sized arrays for which
889         there is a 'count' parameter.
890         """
891         return self.dyn_array_len is not None
893     def is_handle(self):
894         return self.type_info["category"] == "handle"
896     def is_pointer(self):
897         return self.pointer is not None
899     def is_static_array(self):
900         """ Returns if the member is an array.
901         Vulkan uses this often for fixed size arrays in which the
902         length is part of the member.
903         """
904         return self.array_len is not None
906     def is_struct(self):
907         return self.type_info["category"] == "struct"
909     def is_union(self):
910         return self.type_info["category"] == "union"
912     def needs_alignment(self):
913         """ Check if this member needs alignment for 64-bit data.
914         Various structures need alignment on 64-bit variables due
915         to compiler differences on 32-bit between Win32 and Linux.
916         """
918         if self.is_pointer():
919             return False
920         elif self.type == "size_t":
921             return False
922         elif self.type in ["uint64_t", "VkDeviceSize"]:
923             return True
924         elif self.is_struct():
925             struct = self.type_info["data"]
926             return struct.needs_alignment()
927         elif self.is_handle():
928             # Dispatchable handles are pointers to objects, while
929             # non-dispatchable are uint64_t and hence need alignment.
930             handle = self.type_info["data"]
931             return False if handle.is_dispatchable() else True
932         return False
934     def needs_conversion(self):
935         """ Structures requiring alignment, need conversion between win32 and host. """
937         if not self.is_struct():
938             return False
940         struct = self.type_info["data"]
941         return struct.needs_conversion()
943     def needs_free(self):
944         if not self.needs_conversion():
945             return False
947         if self.is_dynamic_array():
948             return True
950         # TODO: some non-pointer structs and optional pointer structs may need freeing,
951         # though none of this type have been encountered yet.
952         return False
954     def set_type_info(self, type_info):
955         """ Helper function to set type information from the type registry.
956         This is needed, because not all type data is available at time of
957         parsing.
958         """
959         self.type_info = type_info
962 class VkParam(object):
963     """ Helper class which describes a parameter to a function call. """
965     def __init__(self, type_info, const=None, pointer=None, name=None, array_len=None, dyn_array_len=None):
966         self.const = const
967         self.name = name
968         self.array_len = array_len
969         self.dyn_array_len = dyn_array_len
970         self.pointer = pointer
971         self.type_info = type_info
972         self.type = type_info["name"] # For convenience
973         self.handle = type_info["data"] if type_info["category"] == "handle" else None
974         self.struct = type_info["data"] if type_info["category"] == "struct" else None
976         self._set_direction()
977         self._set_format_string()
978         self._set_conversions()
980     def __repr__(self):
981         return "{0} {1} {2} {3} {4}".format(self.const, self.type, self.pointer, self.name, self.array_len, self.dyn_array_len)
983     @staticmethod
984     def from_xml(param, types):
985         """ Helper function to create VkParam from xml. """
987         # Parameter parsing is slightly tricky. All the data is contained within
988         # a param tag, but some data is within subtags while others are text
989         # before or after the type tag.
990         # Common structure:
991         # <param>const <type>char</type>* <name>pLayerName</name></param>
993         name_elem = param.find("name")
994         array_len = None
995         name = name_elem.text
996         # Tail contains array length e.g. for blendConstants param of vkSetBlendConstants
997         if name_elem.tail is not None:
998             array_len = name_elem.tail.strip("[]")
1000         # Name of other parameter in function prototype, which stores the number of
1001         # elements pointed to be by this parameter.
1002         dyn_array_len = param.get("len", None)
1004         const = param.text.strip() if param.text else None
1005         type_elem = param.find("type")
1006         pointer = type_elem.tail.strip() if type_elem.tail.strip() != "" else None
1008         # Since we have parsed all types before hand, this should not happen.
1009         type_info = types.get(type_elem.text, None)
1010         if type_info is None:
1011             LOGGER.err("type info not found for: {0}".format(type_elem.text))
1013         return VkParam(type_info, const=const, pointer=pointer, name=name, array_len=array_len, dyn_array_len=dyn_array_len)
1015     def _set_conversions(self):
1016         """ Internal helper function to configure any needed conversion functions. """
1018         self.free_func = None
1019         self.input_conv = None
1020         self.output_conv = None
1021         if not self.needs_conversion():
1022             return
1024         # Input functions require win to host conversion.
1025         if self._direction in [Direction.INPUT, Direction.INPUT_OUTPUT]:
1026             self.input_conv = ConversionFunction(False, self.is_dynamic_array(), Direction.INPUT, self.struct)
1028         # Output functions require host to win conversion.
1029         if self._direction in [Direction.INPUT_OUTPUT, Direction.OUTPUT]:
1030             self.output_conv = ConversionFunction(False, self.is_dynamic_array(), Direction.OUTPUT, self.struct)
1032         # Dynamic arrays, but also some normal structs (e.g. VkCommandBufferBeginInfo) need memory
1033         # allocation and thus some cleanup.
1034         if self.is_dynamic_array() or self.struct.needs_free():
1035             self.free_func = FreeFunction(self.is_dynamic_array(), self.struct)
1037     def _set_direction(self):
1038         """ Internal helper function to set parameter direction (input/output/input_output). """
1040         # The parameter direction needs to be determined from hints in vk.xml like returnedonly,
1041         # parameter constness and other heuristics.
1042         # For now we need to get this right for structures as we need to convert these, we may have
1043         # missed a few other edge cases (e.g. count variables).
1044         # See also https://github.com/KhronosGroup/Vulkan-Docs/issues/610
1046         if not self.is_pointer():
1047             self._direction = Direction.INPUT
1048         elif self.is_const() and self.is_pointer():
1049             self._direction = Direction.INPUT
1050         elif self.is_struct():
1051             if not self.struct.returnedonly:
1052                 self._direction = Direction.INPUT
1053                 return
1055             # Returnedonly hints towards output, however in some cases
1056             # it is inputoutput. In particular if pNext / sType exist,
1057             # which are used to link in other structures without having
1058             # to introduce new APIs. E.g. vkGetPhysicalDeviceProperties2KHR.
1059             if "pNext" in self.struct:
1060                 self._direction = Direction.INPUT_OUTPUT
1061                 return
1063             self._direction = Direction.OUTPUT
1064         else:
1065             # This should mostly be right. Count variables can be inout, but we don't care about these yet.
1066             self._direction = Direction.OUTPUT
1068     def _set_format_string(self):
1069         """ Internal helper function to be used by constructor to set format string. """
1071         # Determine a format string used by code generation for traces.
1072         # 64-bit types need a conversion function.
1073         self.format_conv = None
1074         if self.is_static_array() or self.is_pointer():
1075             self.format_str = "%p"
1076         else:
1077             if self.type_info["category"] == "bitmask":
1078                 self.format_str = "%#x"
1079             elif self.type_info["category"] == "enum":
1080                 self.format_str = "%d"
1081             elif self.is_handle():
1082                 # We use uint64_t for non-dispatchable handles as opposed to pointers
1083                 # for dispatchable handles.
1084                 if self.handle.is_dispatchable():
1085                     self.format_str = "%p"
1086                 else:
1087                     self.format_str = "0x%s"
1088                     self.format_conv = "wine_dbgstr_longlong({0})"
1089             elif self.type == "float":
1090                 self.format_str = "%f"
1091             elif self.type == "int":
1092                 self.format_str = "%d"
1093             elif self.type == "int32_t":
1094                 self.format_str = "%d"
1095             elif self.type == "size_t":
1096                 self.format_str = "0x%s"
1097                 self.format_conv = "wine_dbgstr_longlong({0})"
1098             elif self.type in ["uint32_t", "VkBool32"]:
1099                 self.format_str = "%u"
1100             elif self.type in ["uint64_t", "VkDeviceSize"]:
1101                 self.format_str = "0x%s"
1102                 self.format_conv = "wine_dbgstr_longlong({0})"
1103             elif self.type == "HANDLE":
1104                 self.format_str = "%p"
1105             elif self.type in ["VisualID", "xcb_visualid_t", "RROutput"]:
1106                 # Don't care about Linux specific types.
1107                 self.format_str = ""
1108             else:
1109                 LOGGER.warn("Unhandled type: {0}".format(self.type_info))
1111     def copy(self, direction):
1112         if direction == Direction.INPUT:
1113             if self.is_dynamic_array():
1114                 return "    {0}_host = convert_{1}_array_win_to_host({0}, {2});\n".format(self.name, self.type, self.dyn_array_len)
1115             else:
1116                 return "    convert_{0}_win_to_host({1}, &{1}_host);\n".format(self.type, self.name)
1117         else:
1118             if self.is_dynamic_array():
1119                 LOGGER.error("Unimplemented output conversion for: {0}".format(self.name))
1120             else:
1121                 return "    convert_{0}_host_to_win(&{1}_host, {1});\n".format(self.type, self.name)
1123     def definition(self, postfix=None):
1124         """ Return prototype for the parameter. E.g. 'const char *foo' """
1126         proto = ""
1127         if self.const:
1128             proto += self.const + " "
1130         proto += self.type
1132         if self.is_pointer():
1133             proto += " {0}{1}".format(self.pointer, self.name)
1134         else:
1135             proto += " " + self.name
1137         # Allows appeninding something to the variable name useful for
1138         # win32 to host conversion.
1139         if postfix is not None:
1140             proto += postfix
1142         if self.is_static_array():
1143             proto += "[{0}]".format(self.array_len)
1145         return proto
1147     def direction(self):
1148         """ Returns parameter direction: input, output, input_output.
1150         Parameter direction in Vulkan is not straight-forward, which this function determines.
1151         """
1153         return self._direction
1155     def format_string(self):
1156         return self.format_str
1158     def dispatch_table(self):
1159         """ Return functions dispatch table pointer for dispatchable objects. """
1161         if not self.is_dispatchable():
1162             return None
1164         return "{0}->{1}".format(self.name, self.handle.dispatch_table())
1166     def format_string(self):
1167         return self.format_str
1169     def free(self):
1170         if self.is_dynamic_array():
1171             if self.struct.returnedonly:
1172                 # For returnedonly, counts is stored in a pointer.
1173                 return "    free_{0}_array({1}_host, *{2});\n".format(self.type, self.name, self.dyn_array_len)
1174             else:
1175                 return "    free_{0}_array({1}_host, {2});\n".format(self.type, self.name, self.dyn_array_len)
1176         else:
1177             # We are operating on a single structure. Some structs (very rare) contain dynamic members,
1178             # which would need freeing.
1179             if self.struct.needs_free():
1180                 return "    free_{0}(&{1}_host);\n".format(self.type, self.name)
1181         return ""
1183     def get_conversions(self):
1184         """ Get a list of conversions required for this parameter if any.
1185         Parameters which are structures may require conversion between win32
1186         and the host platform. This function returns a list of conversions
1187         required.
1188         """
1190         if not self.is_struct():
1191             return None
1193         if not self.needs_conversion():
1194             return None
1196         conversions = []
1198         # Collect any member conversions first, so we can guarantee
1199         # those functions will be defined prior to usage by the
1200         # 'parent' param requiring conversion.
1201         for m in self.struct:
1202             if not m.is_struct():
1203                 continue
1205             if not m.needs_conversion():
1206                 continue
1208             conversions.extend(m.get_conversions())
1210         # Conversion requirements for the 'parent' parameter.
1211         if self.input_conv is not None:
1212             conversions.append(self.input_conv)
1213         if self.output_conv is not None:
1214             conversions.append(self.output_conv)
1215         if self.free_func is not None:
1216             conversions.append(self.free_func)
1218         return conversions
1220     def is_const(self):
1221         return self.const is not None
1223     def is_dynamic_array(self):
1224         return self.dyn_array_len is not None
1226     def is_dispatchable(self):
1227         if not self.is_handle():
1228             return False
1230         return self.handle.is_dispatchable()
1232     def is_handle(self):
1233         return self.handle is not None
1235     def is_pointer(self):
1236         return self.pointer is not None
1238     def is_static_array(self):
1239         return self.array_len is not None
1241     def is_struct(self):
1242         return self.struct is not None
1244     def needs_conversion(self):
1245         """ Returns if parameter needs conversion between win32 and host. """
1247         if not self.is_struct():
1248             return False
1250         # VkSparseImageMemoryRequirements is used by vkGetImageSparseMemoryRequirements.
1251         # This function is tricky to wrap, because how to wrap depends on whether
1252         # pSparseMemoryRequirements is NULL or not. Luckily for VkSparseImageMemoryRequirements
1253         # the alignment works out in such a way that no conversion is needed between win32 and Linux.
1254         if self.type == "VkSparseImageMemoryRequirements":
1255             return False
1257         # If a structure needs alignment changes, it means we need to
1258         # perform parameter conversion between win32 and host.
1259         if self.struct.needs_conversion():
1260             return True
1262         return False
1264     def needs_free(self):
1265         return self.free_func is not None
1267     def needs_input_conversion(self):
1268         return self.input_conv is not None
1270     def needs_output_conversion(self):
1271         return self.output_conv is not None
1273     def variable(self, conv=False):
1274         """ Returns 'glue' code during generation of a function call on how to access the variable.
1275         This function handles various scenarios such as 'unwrapping' if dispatchable objects and
1276         renaming of parameters in case of win32 -> host conversion.
1278         Args:
1279             conv (bool, optional): Enable conversion if the param needs it. This appends '_host' to the name.
1280         """
1282         # Hack until we enable allocation callbacks from ICD to application. These are a joy
1283         # to enable one day, because of calling convention conversion.
1284         if "VkAllocationCallbacks" in self.type:
1285             LOGGER.debug("TODO: setting NULL VkAllocationCallbacks for {0}".format(self.name))
1286             return "NULL"
1288         # Dispatchable objects wrap the native handle. For thunk generation we
1289         # need to pass the native handle to the native vulkan calls.
1290         if self.is_dispatchable():
1291             return "{0}->{1}".format(self.name, self.handle.native_handle())
1292         elif conv and self.needs_conversion():
1293             if self.is_dynamic_array():
1294                 return "{0}_host".format(self.name)
1295             else:
1296                 return "&{0}_host".format(self.name)
1297         else:
1298             return self.name
1301 class VkStruct(Sequence):
1302     """ Class which represents the type union and struct. """
1304     def __init__(self, name, members, returnedonly, union=False):
1305         self.name = name
1306         self.members = members
1307         self.returnedonly = returnedonly
1308         self.required = False
1309         self.union = union
1310         self.type_info = None # To be set later.
1312     def __getitem__(self, i):
1313         return self.members[i]
1315     def __len__(self):
1316         return len(self.members)
1318     @staticmethod
1319     def from_xml(struct):
1320         # Unions and structs are the same parsing wise, but we need to
1321         # know which one we are dealing with later on for code generation.
1322         union = True if struct.attrib["category"] == "union" else False
1324         name = struct.attrib.get("name", None)
1326         # 'Output' structures for which data is filled in by the API are
1327         # marked as 'returnedonly'.
1328         returnedonly = True if struct.attrib.get("returnedonly") else False
1330         members = []
1331         for member in struct.findall("member"):
1332             vk_member = VkMember.from_xml(member)
1333             members.append(vk_member)
1335         return VkStruct(name, members, returnedonly, union=union)
1337     @staticmethod
1338     def decouple_structs(structs):
1339         """ Helper function which decouples a list of structs.
1340         Structures often depend on other structures. To make the C compiler
1341         happy we need to define 'substructures' first. This function analyzes
1342         the list of structures and reorders them in such a way that they are
1343         decoupled.
1344         """
1346         tmp_structs = list(structs) # Don't modify the original structures.
1347         decoupled_structs = []
1349         while (len(tmp_structs) > 0):
1350             for struct in tmp_structs:
1351                 dependends = False
1353                 if not struct.required:
1354                     tmp_structs.remove(struct)
1355                     continue
1357                 for m in struct:
1358                     if not (m.is_struct() or m.is_union()):
1359                         continue
1361                     found = False
1362                     # Check if a struct we depend on has already been defined.
1363                     for s in decoupled_structs:
1364                         if s.name == m.type:
1365                             found = True
1366                             break
1368                     if not found:
1369                         # Check if the struct we depend on is even in the list of structs.
1370                         # If found now, it means we haven't met all dependencies before we
1371                         # can operate on the current struct.
1372                         # When generating 'host' structs we may not be able to find a struct
1373                         # as the list would only contain the structs requiring conversion.
1374                         for s in tmp_structs:
1375                             if s.name == m.type:
1376                                 dependends = True
1377                                 break
1379                 if dependends == False:
1380                     decoupled_structs.append(struct)
1381                     tmp_structs.remove(struct)
1383         return decoupled_structs
1385     def definition(self, align=False, conv=False, postfix=None):
1386         """ Convert structure to textual definition.
1388         Args:
1389             align (bool, optional): enable alignment to 64-bit for win32 struct compatibility.
1390             conv (bool, optional): enable struct conversion if the struct needs it.
1391             postfix (str, optional): text to append to end of struct name, useful for struct renaming.
1392         """
1394         if self.union:
1395             text = "typedef union {0}".format(self.name)
1396         else:
1397             text = "typedef struct {0}".format(self.name)
1399         if postfix is not None:
1400             text += postfix
1402         text += "\n{\n"
1404         for m in self:
1405             if align and m.needs_alignment():
1406                 text += "    {0};\n".format(m.definition(align=align))
1407             elif conv and m.needs_conversion():
1408                 text += "    {0};\n".format(m.definition(conv=conv))
1409             else:
1410                 text += "    {0};\n".format(m.definition())
1412         if postfix is not None:
1413             text += "}} {0}{1};\n\n".format(self.name, postfix)
1414         else:
1415             text += "}} {0};\n\n".format(self.name)
1416         return text
1418     def needs_alignment(self):
1419         """ Check if structure needs alignment for 64-bit data.
1420         Various structures need alignment on 64-bit variables due
1421         to compiler differences on 32-bit between Win32 and Linux.
1422         """
1424         for m in self.members:
1425             if m.needs_alignment():
1426                 return True
1427         return False
1429     def needs_conversion(self):
1430         """ Returns if struct members needs conversion between win32 and host.
1431         Structures need conversion if they contain members requiring alignment
1432         or if they include other structures which need alignment.
1433         """
1435         if self.needs_alignment():
1436             return True
1438         for m in self.members:
1439             if m.needs_conversion():
1440                 return True
1441         return False
1443     def needs_free(self):
1444         """ Check if any struct member needs some memory freeing."""
1446         for m in self.members:
1447             if m.needs_free():
1448                 return True
1450             continue
1452         return False
1454     def set_type_info(self, types):
1455         """ Helper function to set type information from the type registry.
1456         This is needed, because not all type data is available at time of
1457         parsing.
1458         """
1459         for m in self.members:
1460             type_info = types[m.type]
1461             m.set_type_info(type_info)
1464 class ConversionFunction(object):
1465     def __init__(self, array, dyn_array, direction, struct):
1466         self.array = array
1467         self.direction = direction
1468         self.dyn_array = dyn_array
1469         self.struct = struct
1470         self.type = struct.name
1472         self._set_name()
1474     def __eq__(self, other):
1475         if self.name != other.name:
1476             return False
1478         return True
1480     def _generate_array_conversion_func(self):
1481         """ Helper function for generating a conversion function for array structs. """
1483         if self.direction == Direction.OUTPUT:
1484             params = ["const {0}_host *in".format(self.type), "uint32_t count"]
1485             return_type = self.type
1486         else:
1487             params = ["const {0} *in".format(self.type), "uint32_t count"]
1488             return_type = "{0}_host".format(self.type)
1490         # Generate function prototype.
1491         body = "static inline {0} *{1}(".format(return_type, self.name)
1492         body += ", ".join(p for p in params)
1493         body += ")\n{\n"
1495         body += "    {0} *out;\n".format(return_type)
1496         body += "    unsigned int i;\n\n"
1497         body += "    if (!in) return NULL;\n\n"
1499         body += "    out = heap_alloc(count * sizeof(*out));\n"
1501         body += "    for (i = 0; i < count; i++)\n"
1502         body += "    {\n"
1504         for m in self.struct:
1505             # TODO: support copying of pNext extension structures!
1506             # Luckily though no extension struct at this point needs conversion.
1507             body += "        " + m.copy("in[i].", "out[i].", self.direction)
1509         body += "    }\n\n"
1510         body += "    return out;\n"
1511         body += "}\n\n"
1512         return body
1514     def _generate_conversion_func(self):
1515         """ Helper function for generating a conversion function for non-array structs. """
1517         if self.direction == Direction.OUTPUT:
1518             params = ["const {0}_host *in".format(self.type), "{0} *out".format(self.type)]
1519         else:
1520             params = ["const {0} *in".format(self.type), "{0}_host *out".format(self.type)]
1522         body = "static inline void {0}(".format(self.name)
1524         # Generate parameter list
1525         body += ", ".join(p for p in params)
1526         body += ")\n{\n"
1528         body += "    if (!in) return;\n\n"
1530         if self.direction == Direction.INPUT and "pNext" in self.struct and self.struct.returnedonly:
1531             # We are dealing with an input_output parameter. For these we only need to copy
1532             # pNext and sType as the other fields are filled in by the host. We do potentially
1533             # have to iterate over pNext and perform conversions based on switch(sType)!
1534             # Luckily though no extension structs at this point need conversion.
1535             # TODO: support copying of pNext extension structures!
1536             body += "    out->pNext = in->pNext;\n"
1537             body += "    out->sType = in->sType;\n"
1538         else:
1539             for m in self.struct:
1540                 # TODO: support copying of pNext extension structures!
1541                 body += "    " + m.copy("in->", "out->", self.direction)
1543         body += "}\n\n"
1544         return body
1546     def _generate_static_array_conversion_func(self):
1547         """ Helper function for generating a conversion function for array structs. """
1549         if self.direction == Direction.OUTPUT:
1550             params = ["const {0}_host *in".format(self.type), "{0} *out".format(self.type), "uint32_t count"]
1551             return_type = self.type
1552         else:
1553             params = ["const {0} *in".format(self.type), "{0} *out_host".format(self.type), "uint32_t count"]
1554             return_type = "{0}_host".format(self.type)
1556         # Generate function prototype.
1557         body = "static inline void {0}(".format(self.name)
1558         body += ", ".join(p for p in params)
1559         body += ")\n{\n"
1560         body += "    unsigned int i;\n\n"
1561         body += "    if (!in) return;\n\n"
1562         body += "    for (i = 0; i < count; i++)\n"
1563         body += "    {\n"
1565         for m in self.struct:
1566             # TODO: support copying of pNext extension structures!
1567             body += "        " + m.copy("in[i].", "out[i].", self.direction)
1569         body += "    }\n"
1570         body += "}\n\n"
1571         return body
1573     def _set_name(self):
1574         if self.direction == Direction.INPUT:
1575             if self.array:
1576                 name = "convert_{0}_static_array_win_to_host".format(self.type)
1577             elif self.dyn_array:
1578                 name = "convert_{0}_array_win_to_host".format(self.type)
1579             else:
1580                 name = "convert_{0}_win_to_host".format(self.type)
1581         else: # Direction.OUTPUT
1582             if self.array:
1583                 name = "convert_{0}_static_array_host_to_win".format(self.type)
1584             elif self.dyn_array:
1585                 name = "convert_{0}_array_host_to_win".format(self.type)
1586             else:
1587                 name = "convert_{0}_host_to_win".format(self.type)
1589         self.name = name
1591     def definition(self):
1592         if self.array:
1593             return self._generate_static_array_conversion_func()
1594         elif self.dyn_array:
1595             return self._generate_array_conversion_func()
1596         else:
1597             return self._generate_conversion_func()
1600 class FreeFunction(object):
1601     def __init__(self, dyn_array, struct):
1602         self.dyn_array = dyn_array
1603         self.struct = struct
1604         self.type = struct.name
1606         if dyn_array:
1607             self.name = "free_{0}_array".format(self.type)
1608         else:
1609             self.name = "free_{0}".format(self.type)
1611     def __eq__(self, other):
1612         if self.name == other.name:
1613             return True
1615         return False
1617     def _generate_array_free_func(self):
1618         """ Helper function for cleaning up temporary buffers required for array conversions. """
1620         # Generate function prototype.
1621         body = "static inline void {0}({1}_host *in, uint32_t count)\n{{\n".format(self.name, self.type)
1623         # E.g. VkGraphicsPipelineCreateInfo_host needs freeing for pStages.
1624         if self.struct.needs_free():
1625             body += "    unsigned int i;\n\n"
1626             body += "    if (!in) return;\n\n"
1627             body += "    for (i = 0; i < count; i++)\n"
1628             body += "    {\n"
1630             for m in self.struct:
1631                 if m.needs_conversion() and m.is_dynamic_array():
1632                     if m.is_const():
1633                         # Add a cast to ignore const on conversion structs we allocated ourselves.
1634                         body += "        free_{0}_array(({0}_host *)in[i].{1}, in[i].{2});\n".format(m.type, m.name, m.dyn_array_len)
1635                     else:
1636                         body += "        free_{0}_array(in[i].{1}, in[i].{2});\n".format(m.type, m.name, m.dyn_array_len)
1637                 elif m.needs_conversion():
1638                     LOGGER.error("Unhandled conversion for {0}".format(m.name))
1639             body += "    }\n"
1640         else:
1641             body += "    if (!in) return;\n\n"
1643         body += "    heap_free(in);\n"
1645         body += "}\n\n"
1646         return body
1648     def _generate_free_func(self):
1649         # E.g. VkCommandBufferBeginInfo.pInheritanceInfo needs freeing.
1650         if not self.struct.needs_free():
1651             return ""
1653         # Generate function prototype.
1654         body = "static inline void {0}({1}_host *in)\n{{\n".format(self.name, self.type)
1656         for m in self.struct:
1657             if m.needs_conversion() and m.is_dynamic_array():
1658                 count = m.dyn_array_len if isinstance(m.dyn_array_len, int) else "in->{0}".format(m.dyn_array_len)
1659                 if m.is_const():
1660                     # Add a cast to ignore const on conversion structs we allocated ourselves.
1661                     body += "    free_{0}_array(({0}_host *)in->{1}, {2});\n".format(m.type, m.name, count)
1662                 else:
1663                     body += "    free_{0}_array(in->{1}, {2});\n".format(m.type, m.name, count)
1665         body += "}\n\n"
1666         return body
1668     def definition(self):
1669         if self.dyn_array:
1670             return self._generate_array_free_func()
1671         else:
1672             # Some structures need freeing too if they contain dynamic arrays.
1673             # E.g. VkCommandBufferBeginInfo
1674             return self._generate_free_func()
1677 class VkGenerator(object):
1678     def __init__(self, registry):
1679         self.registry = registry
1681         # Build a list conversion functions for struct conversion.
1682         self.conversions = []
1683         self.host_structs = []
1684         for func in self.registry.funcs.values():
1685             if not func.is_required():
1686                 continue
1688             if not func.needs_conversion():
1689                 continue
1691             conversions = func.get_conversions()
1692             for conv in conversions:
1693                 # Pull in any conversions for vulkan_thunks.c. Driver conversions we
1694                 # handle manually in vulkan.c if needed.
1695                 if not func.is_driver_func():
1696                     # Append if we don't already have this conversion.
1697                     if not any(c == conv for c in self.conversions):
1698                         self.conversions.append(conv)
1700                 # Structs can be used in different ways by different conversions
1701                 # e.g. array vs non-array. Just make sure we pull in each struct once.
1702                 if not any(s.name == conv.struct.name for s in self.host_structs):
1703                     self.host_structs.append(conv.struct)
1705     def generate_thunks_c(self, f, prefix):
1706         f.write("/* Automatically generated from Vulkan vk.xml; DO NOT EDIT! */\n\n")
1708         f.write("#include \"config.h\"\n")
1709         f.write("#include \"wine/port.h\"\n\n")
1711         f.write("#include \"wine/debug.h\"\n")
1712         f.write("#include \"wine/heap.h\"\n")
1713         f.write("#include \"wine/vulkan.h\"\n")
1714         f.write("#include \"wine/vulkan_driver.h\"\n")
1715         f.write("#include \"vulkan_private.h\"\n\n")
1717         f.write("WINE_DEFAULT_DEBUG_CHANNEL(vulkan);\n\n")
1719         # Generate any conversion helper functions.
1720         f.write("#if defined(USE_STRUCT_CONVERSION)\n")
1721         for conv in self.conversions:
1722             f.write(conv.definition())
1723         f.write("#endif /* USE_STRUCT_CONVERSION */\n\n")
1725         # Create thunks for instance and device functions.
1726         # Global functions don't go through the thunks.
1727         for vk_func in self.registry.funcs.values():
1728             if not vk_func.is_required():
1729                 continue
1731             if vk_func.is_global_func():
1732                 continue
1734             if not vk_func.needs_thunk():
1735                 continue
1737             f.write("static " + vk_func.thunk(prefix=prefix, call_conv="WINAPI"))
1739         f.write("static const struct vulkan_func vk_device_dispatch_table[] =\n{\n")
1740         for vk_func in self.registry.device_funcs:
1741             if not vk_func.is_required():
1742                 continue
1744             if not vk_func.needs_dispatch():
1745                 LOGGER.debug("skipping {0} in device dispatch table".format(vk_func.name))
1746                 continue
1748             f.write("    {{\"{0}\", &{1}{0}}},\n".format(vk_func.name, prefix))
1749         f.write("};\n\n")
1751         f.write("static const struct vulkan_func vk_instance_dispatch_table[] =\n{\n")
1752         for vk_func in self.registry.instance_funcs:
1753             if not vk_func.is_required():
1754                 continue
1756             if not vk_func.needs_dispatch():
1757                 LOGGER.debug("skipping {0} in instance dispatch table".format(vk_func.name))
1758                 continue
1760             f.write("    {{\"{0}\", &{1}{0}}},\n".format(vk_func.name, prefix))
1761         f.write("};\n\n")
1763         f.write("void *wine_vk_get_device_proc_addr(const char *name)\n")
1764         f.write("{\n")
1765         f.write("    unsigned int i;\n")
1766         f.write("    for (i = 0; i < ARRAY_SIZE(vk_device_dispatch_table); i++)\n")
1767         f.write("    {\n")
1768         f.write("        if (strcmp(vk_device_dispatch_table[i].name, name) == 0)\n")
1769         f.write("        {\n")
1770         f.write("            TRACE(\"Found name=%s in device table\\n\", name);\n")
1771         f.write("            return vk_device_dispatch_table[i].func;\n")
1772         f.write("        }\n")
1773         f.write("    }\n")
1774         f.write("    return NULL;\n")
1775         f.write("}\n\n")
1777         f.write("void *wine_vk_get_instance_proc_addr(const char *name)\n")
1778         f.write("{\n")
1779         f.write("    unsigned int i;\n")
1780         f.write("    for (i = 0; i < ARRAY_SIZE(vk_instance_dispatch_table); i++)\n")
1781         f.write("    {\n")
1782         f.write("        if (strcmp(vk_instance_dispatch_table[i].name, name) == 0)\n")
1783         f.write("        {\n")
1784         f.write("            TRACE(\"Found name=%s in instance table\\n\", name);\n")
1785         f.write("            return vk_instance_dispatch_table[i].func;\n")
1786         f.write("        }\n")
1787         f.write("    }\n")
1788         f.write("    return NULL;\n")
1789         f.write("}\n\n")
1791         # Create array of device extensions.
1792         f.write("static const char * const vk_device_extensions[] =\n{\n")
1793         for ext in self.registry.extensions:
1794             if ext["type"] != "device":
1795                 continue
1797             f.write("    \"{0}\",\n".format(ext["name"]))
1798         f.write("};\n\n")
1800         # Create array of instance extensions.
1801         f.write("static const char *vk_instance_extensions[] =\n{\n")
1802         for ext in self.registry.extensions:
1803             if ext["type"] != "instance":
1804                 continue
1806             f.write("    \"{0}\",\n".format(ext["name"]))
1807         f.write("};\n\n")
1809         f.write("BOOL wine_vk_device_extension_supported(const char *name)\n")
1810         f.write("{\n")
1811         f.write("    unsigned int i;\n")
1812         f.write("    for (i = 0; i < ARRAY_SIZE(vk_device_extensions); i++)\n")
1813         f.write("    {\n")
1814         f.write("        if (strcmp(vk_device_extensions[i], name) == 0)\n")
1815         f.write("            return TRUE;\n")
1816         f.write("    }\n")
1817         f.write("    return FALSE;\n")
1818         f.write("}\n\n")
1820         f.write("BOOL wine_vk_instance_extension_supported(const char *name)\n")
1821         f.write("{\n")
1822         f.write("    unsigned int i;\n")
1823         f.write("    for (i = 0; i < ARRAY_SIZE(vk_instance_extensions); i++)\n")
1824         f.write("    {\n")
1825         f.write("        if (strcmp(vk_instance_extensions[i], name) == 0)\n")
1826         f.write("            return TRUE;\n")
1827         f.write("    }\n")
1828         f.write("    return FALSE;\n")
1829         f.write("}\n")
1831     def generate_thunks_h(self, f, prefix):
1832         f.write("/* Automatically generated from Vulkan vk.xml; DO NOT EDIT! */\n\n")
1834         f.write("#ifndef __WINE_VULKAN_THUNKS_H\n")
1835         f.write("#define __WINE_VULKAN_THUNKS_H\n\n")
1837         f.write("/* Perform vulkan struct conversion on 32-bit x86 platforms. */\n")
1838         f.write("#if defined(__i386__)\n")
1839         f.write("#define USE_STRUCT_CONVERSION\n")
1840         f.write("#endif\n\n")
1842         f.write("/* For use by vk_icdGetInstanceProcAddr / vkGetInstanceProcAddr */\n")
1843         f.write("void *wine_vk_get_device_proc_addr(const char *name) DECLSPEC_HIDDEN;\n")
1844         f.write("void *wine_vk_get_instance_proc_addr(const char *name) DECLSPEC_HIDDEN;\n\n")
1846         f.write("BOOL wine_vk_device_extension_supported(const char *name) DECLSPEC_HIDDEN;\n")
1847         f.write("BOOL wine_vk_instance_extension_supported(const char *name) DECLSPEC_HIDDEN;\n\n")
1849         # Generate prototypes for device and instance functions requiring a custom implementation.
1850         f.write("/* Functions for which we have custom implementations outside of the thunks. */\n")
1851         for vk_func in self.registry.funcs.values():
1852             if not vk_func.is_required() or vk_func.is_global_func() or vk_func.needs_thunk():
1853                 continue
1855             f.write("{0};\n".format(vk_func.prototype("WINAPI", prefix="wine_", postfix="DECLSPEC_HIDDEN")))
1856         f.write("\n")
1858         for struct in self.host_structs:
1859             f.write(struct.definition(align=False, conv=True, postfix="_host"))
1860         f.write("\n")
1862         f.write("/* For use by vkDevice and children */\n")
1863         f.write("struct vulkan_device_funcs\n{\n")
1864         for vk_func in self.registry.device_funcs:
1865             if not vk_func.is_required():
1866                 continue
1868             if not vk_func.needs_dispatch() or vk_func.is_driver_func():
1869                 LOGGER.debug("skipping {0} in vulkan_device_funcs".format(vk_func.name))
1870                 continue
1872             if vk_func.needs_conversion():
1873                 f.write("#if defined(USE_STRUCT_CONVERSION)\n")
1874                 f.write("    {0};\n".format(vk_func.pfn(conv=True)))
1875                 f.write("#else\n")
1876                 f.write("    {0};\n".format(vk_func.pfn(conv=False)))
1877                 f.write("#endif\n")
1878             else:
1879                 f.write("    {0};\n".format(vk_func.pfn(conv=False)))
1880         f.write("};\n\n")
1882         f.write("/* For use by vkInstance and children */\n")
1883         f.write("struct vulkan_instance_funcs\n{\n")
1884         for vk_func in self.registry.instance_funcs:
1885             if not vk_func.is_required():
1886                 continue
1888             if not vk_func.needs_dispatch() or vk_func.is_driver_func():
1889                 LOGGER.debug("skipping {0} in vulkan_instance_funcs".format(vk_func.name))
1890                 continue
1892             if vk_func.needs_conversion():
1893                 f.write("#if defined(USE_STRUCT_CONVERSION)\n")
1894                 f.write("    {0};\n".format(vk_func.pfn(conv=True)))
1895                 f.write("#else\n")
1896                 f.write("    {0};\n".format(vk_func.pfn(conv=False)))
1897                 f.write("#endif\n")
1898             else:
1899                 f.write("    {0};\n".format(vk_func.pfn(conv=False)))
1900         f.write("};\n\n")
1902         f.write("#define ALL_VK_DEVICE_FUNCS() \\\n")
1903         first = True
1904         for vk_func in self.registry.device_funcs:
1905             if not vk_func.is_required():
1906                 continue
1908             if not vk_func.needs_dispatch() or vk_func.is_driver_func():
1909                 LOGGER.debug("skipping {0} in ALL_VK_DEVICE_FUNCS".format(vk_func.name))
1910                 continue
1912             if first:
1913                 f.write("    USE_VK_FUNC({0})".format(vk_func.name))
1914                 first = False
1915             else:
1916                 f.write(" \\\n    USE_VK_FUNC({0})".format(vk_func.name))
1917         f.write("\n\n")
1919         f.write("#define ALL_VK_INSTANCE_FUNCS() \\\n")
1920         first = True
1921         for vk_func in self.registry.instance_funcs:
1922             if not vk_func.is_required():
1923                 continue
1925             if not vk_func.needs_dispatch() or vk_func.is_driver_func():
1926                 LOGGER.debug("skipping {0} in ALL_VK_INSTANCE_FUNCS".format(vk_func.name))
1927                 continue
1929             if first:
1930                 f.write("    USE_VK_FUNC({0})".format(vk_func.name))
1931                 first = False
1932             else:
1933                 f.write("\\\n    USE_VK_FUNC({0})".format(vk_func.name))
1934         f.write("\n\n")
1936         f.write("#endif /* __WINE_VULKAN_THUNKS_H */\n")
1938     def generate_vulkan_h(self, f):
1939         f.write("/* Automatically generated from Vulkan vk.xml; DO NOT EDIT! */\n\n")
1940         f.write("#ifndef __WINE_VULKAN_H\n")
1941         f.write("#define __WINE_VULKAN_H\n\n")
1943         f.write("#include <windef.h>\n")
1944         f.write("#include <stdint.h>\n\n")
1946         f.write("#ifndef VKAPI_CALL\n")
1947         f.write("#define VKAPI_CALL __stdcall\n")
1948         f.write("#endif\n\n")
1950         f.write("#ifndef VKAPI_PTR\n")
1951         f.write("#define VKAPI_PTR VKAPI_CALL\n")
1952         f.write("#endif\n\n")
1954         f.write("/* Callers can override WINE_VK_ALIGN if they want 'host' headers. */\n")
1955         f.write("#ifndef WINE_VK_ALIGN\n")
1956         f.write("#define WINE_VK_ALIGN DECLSPEC_ALIGN\n")
1957         f.write("#endif\n\n")
1959         # The overall strategy is to define independent constants and datatypes,
1960         # prior to complex structures and function calls to avoid forward declarations.
1961         for const in self.registry.consts:
1962             # For now just generate things we may not need. The amount of parsing needed
1963             # to get some of the info is tricky as you need to figure out which structure
1964             # references a certain constant.
1965             f.write(const.definition())
1966         f.write("\n")
1968         for define in self.registry.defines:
1969             f.write(define.definition())
1971         for handle in self.registry.handles:
1972             if handle.required:
1973                  f.write(handle.definition())
1974         f.write("\n")
1976         for base_type in self.registry.base_types:
1977             f.write(base_type.definition())
1978         f.write("\n")
1980         for bitmask in self.registry.bitmasks:
1981             f.write(bitmask.definition())
1982         f.write("\n")
1984         # Define enums, this includes values for some of the bitmask types as well.
1985         for enum in self.registry.enums.values():
1986             if enum.required:
1987                 f.write(enum.definition())
1989         for fp in self.registry.funcpointers:
1990             if fp.required:
1991                 f.write(fp.definition())
1992         f.write("\n")
1994         # This generates both structures and unions. Since structures
1995         # may depend on other structures/unions, we need a list of
1996         # decoupled structs.
1997         # Note: unions are stored in structs for dependency reasons,
1998         # see comment in parsing section.
1999         structs = VkStruct.decouple_structs(self.registry.structs)
2000         for struct in structs:
2001             LOGGER.debug("Generating struct: {0}".format(struct.name))
2002             f.write(struct.definition(align=True))
2004         for func in self.registry.funcs.values():
2005             if not func.is_required():
2006                 LOGGER.debug("Skipping API definition for: {0}".format(func.name))
2007                 continue
2009             LOGGER.debug("Generating API definition for: {0}".format(func.name))
2010             f.write("{0};\n".format(func.prototype(call_conv="VKAPI_CALL")))
2011         f.write("\n")
2013         f.write("#endif /* __WINE_VULKAN_H */\n")
2015     def generate_vulkan_driver_h(self, f):
2016         f.write("/* Automatically generated from Vulkan vk.xml; DO NOT EDIT! */\n\n")
2017         f.write("#ifndef __WINE_VULKAN_DRIVER_H\n")
2018         f.write("#define __WINE_VULKAN_DRIVER_H\n\n")
2020         f.write("/* Wine internal vulkan driver version, needs to be bumped upon vulkan_funcs changes. */\n")
2021         f.write("#define WINE_VULKAN_DRIVER_VERSION {0}\n\n".format(DRIVER_VERSION))
2023         f.write("struct vulkan_funcs\n{\n")
2024         f.write("    /* Vulkan global functions. These are the only calls at this point a graphics driver\n")
2025         f.write("     * needs to provide. Other function calls will be provided indirectly by dispatch\n")
2026         f.write("     * tables part of dispatchable Vulkan objects such as VkInstance or vkDevice.\n")
2027         f.write("     */\n")
2029         for vk_func in self.registry.funcs.values():
2030             if not vk_func.is_required() or not vk_func.is_driver_func():
2031                 continue
2033             pfn = vk_func.pfn()
2034             # Avoid PFN_vkVoidFunction in driver interface as Vulkan likes to put calling convention
2035             # stuff in there. For simplicity substitute with "void *".
2036             pfn = pfn.replace("PFN_vkVoidFunction", "void *")
2037             f.write("    {0};\n".format(pfn))
2038         f.write("};\n\n")
2040         f.write("extern const struct vulkan_funcs * CDECL __wine_get_vulkan_driver(HDC hdc, UINT version);\n\n")
2041         f.write("#endif /* __WINE_VULKAN_DRIVER_H */\n")
2044 class VkRegistry(object):
2045     def __init__(self, reg_filename):
2046         # Used for storage of type information.
2047         self.base_types = None
2048         self.bitmasks = None
2049         self.consts = None
2050         self.defines = None
2051         self.enums = None
2052         self.funcpointers = None
2053         self.handles = None
2054         self.structs = None
2056         # We aggregate all types in here for cross-referencing.
2057         self.funcs = {}
2058         self.types = {}
2060         # Overall strategy for parsing the registry is to first
2061         # parse all type / function definitions. Then parse
2062         # features and extensions to decide which types / functions
2063         # to actually 'pull in' for code generation. For each type or
2064         # function call we want we set a member 'required' to True.
2065         tree = ET.parse(reg_filename)
2066         root = tree.getroot()
2067         self._parse_enums(root)
2068         self._parse_types(root)
2069         self._parse_commands(root)
2071         # Pull in any required types and functions.
2072         self._parse_features(root)
2073         self._parse_extensions(root)
2075     def _mark_command_required(self, command):
2076         """ Helper function to mark a certain command and the datatypes it needs as required."""
2077         def mark_bitmask_dependencies(bitmask, types):
2078             if bitmask.requires is not None:
2079                 types[bitmask.requires]["data"].required = True
2081         def mark_funcpointer_dependencies(fp, types):
2082             for m in fp.members:
2083                 type_info = types[m.type]
2085                 # Complex types have a matching definition e.g. VkStruct.
2086                 # Not needed for base types such as uint32_t.
2087                 if "data" in type_info:
2088                     types[m.type]["data"].required = True
2090         def mark_struct_dependencies(struct, types):
2091              for m in struct:
2092                 type_info = types[m.type]
2094                 # Complex types have a matching definition e.g. VkStruct.
2095                 # Not needed for base types such as uint32_t.
2096                 if "data" in type_info:
2097                     types[m.type]["data"].required = True
2099                 if type_info["category"] == "struct":
2100                     # Yay, recurse
2101                     mark_struct_dependencies(type_info["data"], types)
2102                 elif type_info["category"] == "funcpointer":
2103                     mark_funcpointer_dependencies(type_info["data"], types)
2104                 elif type_info["category"] == "bitmask":
2105                     mark_bitmask_dependencies(type_info["data"], types)
2107         func = self.funcs[command]
2108         func.required = True
2110         # Pull in return type
2111         if func.type != "void":
2112             self.types[func.type]["data"].required = True
2114         # Analyze parameter dependencies and pull in any type needed.
2115         for p in func.params:
2116             type_info = self.types[p.type]
2118             # Check if we are dealing with a complex type e.g. VkEnum, VkStruct and others.
2119             if "data" not in type_info:
2120                 continue
2122             # Mark the complex type as required.
2123             type_info["data"].required = True
2124             if type_info["category"] == "struct":
2125                 struct = type_info["data"]
2126                 mark_struct_dependencies(struct, self.types)
2128     def _parse_commands(self, root):
2129         """ Parse command section containing the Vulkan function calls. """
2130         funcs = {}
2131         commands = root.findall("./commands/")
2132         for command in commands:
2133             func = VkFunction.from_xml(command, self.types)
2134             funcs[func.name] = func
2136         # To make life easy for the code generation, separate all function
2137         # calls out in the 3 types of vulkan functions: device, global and instance.
2138         device_funcs = []
2139         global_funcs = []
2140         instance_funcs = []
2141         for func in funcs.values():
2142             if func.is_device_func():
2143                 device_funcs.append(func)
2144             elif func.is_global_func():
2145                 global_funcs.append(func)
2146             else:
2147                 instance_funcs.append(func)
2149         # Sort function lists by name and store them.
2150         self.device_funcs = sorted(device_funcs, key=lambda func: func.name)
2151         self.global_funcs = sorted(global_funcs, key=lambda func: func.name)
2152         self.instance_funcs = sorted(instance_funcs, key=lambda func: func.name)
2154         # The funcs dictionary is used as a convenient way to lookup function
2155         # calls when needed e.g. to adjust member variables.
2156         self.funcs = OrderedDict(sorted(funcs.items()))
2158     def _parse_enums(self, root):
2159         """ Parse enums section or better described as constants section. """
2160         enums = {}
2161         self.consts = []
2162         for enum in root.findall("./enums"):
2163             name = enum.attrib.get("name")
2164             _type = enum.attrib.get("type")
2166             if _type in ("enum", "bitmask"):
2167                 enums[name] = VkEnum.from_xml(enum)
2168             else:
2169                 # If no type is set, we are dealing with API constants.
2170                 values = []
2171                 for value in enum.findall("enum"):
2172                     self.consts.append(VkConstant(value.attrib.get("name"), value.attrib.get("value")))
2174         self.enums = OrderedDict(sorted(enums.items()))
2176     def _parse_extensions(self, root):
2177         """ Parse extensions section and pull in any types and commands for this extensioin. """
2178         extensions = []
2179         exts = root.findall("./extensions/extension")
2180         for ext in exts:
2181             ext_name = ext.attrib["name"]
2183             # Some extensions are not ready or have numbers reserved as a place holder.
2184             if ext.attrib["supported"] == "disabled":
2185                 LOGGER.debug("Skipping disabled extension: {0}".format(ext_name))
2186                 continue
2188             # We only support a handful of extensions for now through a whitelist.
2189             if ext_name not in SUPPORTED_EXTENSIONS:
2190                 LOGGER.debug("Skipping blacklisted extension: {0}".format(ext_name))
2191                 continue
2193             LOGGER.debug("Loading extension: {0}".format(ext_name))
2195             # Extensions can add enum values to Core / extension enums, so add these.
2196             enums = ext.findall("require/enum")
2197             for enum_elem in enums:
2198                 if "bitpos" in enum_elem.keys():
2199                     # We need to add an extra value to an existing enum type.
2200                     # E.g. VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG to VkFormatFeatureFlagBits.
2201                     type_name = enum_elem.attrib["extends"]
2202                     enum = self.types[type_name]["data"]
2203                     enum.add(VkEnumValue(enum_elem.attrib["name"], 1 << int(enum_elem.attrib["bitpos"]), hex=True))
2204                 elif "offset" in enum_elem.keys():
2205                     ext_number = int(ext.attrib["number"])
2206                     offset = int(enum_elem.attrib["offset"])
2207                     value = EXT_BASE + (ext_number - 1) * EXT_BLOCK_SIZE + offset
2209                     # Deal with negative values.
2210                     direction = enum_elem.attrib.get("dir")
2211                     if direction is not None:
2212                         value = -value
2214                     type_name = enum_elem.attrib["extends"]
2215                     enum = self.types[type_name]["data"]
2216                     enum.add(VkEnumValue(enum_elem.attrib["name"], value))
2218                 elif "value" in enum_elem.keys():
2219                     # For now skip, it mostly contains extension name and version info.
2220                     continue
2221                 else:
2222                     # This seems to be used to pull in constants e.g. VK_MAX_DEVICE_GROUP_KHX
2223                     continue
2225             # Store a list with extensions.
2226             ext_type = ext.attrib["type"]
2227             ext_info = {"name" : ext_name, "type" : ext_type}
2228             extensions.append(ext_info)
2230             commands = ext.findall("require/command")
2231             if not commands:
2232                 continue
2234             # Pull in any commands we need. We infer types to pull in from the command
2235             # as well.
2236             for command in commands:
2237                 cmd_name = command.attrib["name"]
2238                 self._mark_command_required(cmd_name)
2240                 # Set extension name on the function call as we were not aware of the
2241                 # name during initial parsing.
2242                 self.funcs[cmd_name].extension = ext_name
2244         # Sort in alphabetical order.
2245         self.extensions = sorted(extensions, key=lambda ext: ext["name"])
2247     def _parse_features(self, root):
2248         """ Parse the feature section, which describes Core commands and types needed. """
2249         requires = root.findall("./feature/require")
2251         for require in requires:
2252             LOGGER.info("Including features for {0}".format(require.attrib.get("comment")))
2253             for tag in require:
2254                 # Only deal with command. Other values which appear are enum and type for pulling in some
2255                 # constants and macros. Tricky to parse, so don't bother right now, we will generate them
2256                 # anyway for now.
2257                 name = tag.attrib["name"]
2258                 if tag.tag == "command":
2259                     self._mark_command_required(name)
2260                 elif tag.tag == "enum":
2261                     # We could pull in relevant constants here. Unfortunately
2262                     # this only gets half of them pulled in as others indirectly
2263                     # get pulled in through structures. Constants don't harm us,
2264                     # so don't bother.
2265                     pass
2266                 elif tag.tag == "type":
2267                     # Pull in types which may not have been pulled in through commands.
2269                     # Skip pull in for vk_platform.h for now.
2270                     if name == "vk_platform":
2271                         continue
2273                     type_info = self.types[name]
2274                     type_info["data"].required = True
2276     def _parse_types(self, root):
2277         """ Parse types section, which contains all data types e.g. structs, typedefs etcetera. """
2278         types = root.findall("./types/type")
2280         base_types = []
2281         bitmasks = []
2282         defines = []
2283         funcpointers = []
2284         handles = []
2285         structs = []
2287         for t in types:
2288             type_info = {}
2289             type_info["category"] = t.attrib.get("category", None)
2291             if type_info["category"] in ["include"]:
2292                 continue
2294             if type_info["category"] == "basetype":
2295                 name = t.find("name").text
2296                 _type = t.find("type").text
2297                 basetype = VkBaseType(name, _type)
2298                 base_types.append(basetype)
2299                 type_info["data"] = basetype
2301             if type_info["category"] == "bitmask":
2302                 name = t.find("name").text
2303                 _type = t.find("type").text
2305                 # Most bitmasks have a requires attribute used to pull in
2306                 # required '*FlagBits" enum.
2307                 requires = t.attrib.get("requires")
2308                 bitmask = VkBaseType(name, _type, requires=requires)
2309                 bitmasks.append(bitmask)
2310                 type_info["data"] = bitmask
2312             if type_info["category"] == "define":
2313                 name = t.attrib.get("name")
2314                 define = VkDefine.from_xml(t)
2315                 defines.append(define)
2316                 type_info["data"] = define
2318             if type_info["category"] == "enum":
2319                 name = t.attrib.get("name")
2320                 # The type section only contains enum names, not the actual definition.
2321                 # Since we already parsed the enum before, just link it in.
2322                 try:
2323                     type_info["data"] = self.enums[name]
2324                 except KeyError as e:
2325                     # Not all enums seem to be defined yet, typically that's for
2326                     # ones ending in 'FlagBits' where future extensions may add
2327                     # definitions.
2328                     type_info["data"] = None
2330             if type_info["category"] == "funcpointer":
2331                 funcpointer = VkFunctionPointer.from_xml(t)
2332                 funcpointers.append(funcpointer)
2333                 type_info["data"] = funcpointer
2335             if type_info["category"] == "handle":
2336                 handle = VkHandle.from_xml(t)
2337                 handles.append(handle)
2338                 type_info["data"] = handle
2340             if type_info["category"] in ["struct", "union"]:
2341                 # We store unions among structs as some structs depend
2342                 # on unions. The types are very similar in parsing and
2343                 # generation anyway. The official vulkan scripts use
2344                 # a similar kind of hack.
2345                 struct = VkStruct.from_xml(t)
2346                 structs.append(struct)
2347                 type_info["data"] = struct
2349             # Name is in general within a name tag else it is an optional
2350             # attribute on the type tag.
2351             name_elem = t.find("name")
2352             if name_elem is not None:
2353                 type_info["name"] = name_elem.text
2354             else:
2355                 type_info["name"] = t.attrib.get("name", None)
2357             # Store all type data in a shared dictionary, so we can easily
2358             # look up information for a given type. There are no duplicate
2359             # names.
2360             self.types[type_info["name"]] = type_info
2362         # We need detailed type information during code generation
2363         # on structs for alignment reasons. Unfortunately structs
2364         # are parsed among other types, so there is no guarantee
2365         # that any types needed have been parsed already, so set
2366         # the data now.
2367         for struct in structs:
2368             struct.set_type_info(self.types)
2370         # Guarantee everything is sorted, so code generation doesn't have
2371         # to deal with this.
2372         self.base_types = sorted(base_types, key=lambda base_type: base_type.name)
2373         self.bitmasks = sorted(bitmasks, key=lambda bitmask: bitmask.name)
2374         self.defines = defines
2375         self.funcpointers = sorted(funcpointers, key=lambda fp: fp.name)
2376         self.handles = sorted(handles, key=lambda handle: handle.name)
2377         self.structs = sorted(structs, key=lambda struct: struct.name)
2380 def main():
2381     parser = argparse.ArgumentParser()
2382     parser.add_argument("-v", "--verbose", action="count", default=0, help="increase output verbosity")
2384     args = parser.parse_args()
2385     if args.verbose == 0:
2386         LOGGER.setLevel(logging.WARNING)
2387     elif args.verbose == 1:
2388         LOGGER.setLevel(logging.INFO)
2389     else: # > 1
2390         LOGGER.setLevel(logging.DEBUG)
2392     registry = VkRegistry("vk.xml")
2393     generator = VkGenerator(registry)
2395     with open(WINE_VULKAN_H, "w") as f:
2396         generator.generate_vulkan_h(f)
2398     with open(WINE_VULKAN_DRIVER_H, "w") as f:
2399         generator.generate_vulkan_driver_h(f)
2401     with open(WINE_VULKAN_THUNKS_H, "w") as f:
2402         generator.generate_thunks_h(f, "wine_")
2404     with open(WINE_VULKAN_THUNKS_C, "w") as f:
2405         generator.generate_thunks_c(f, "wine_")
2407 if __name__ == "__main__":
2408     main()