winevulkan: Implement vkQueueBindSparse and vkQueueWaitIdle.
[wine.git] / dlls / winevulkan / make_vulkan
blobc835b997fce41d7f25679718f91fd99ee87bf275
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_surface",
84     "VK_KHR_win32_surface",
85     "VK_KHR_swapchain",
88 # Functions part of our winevulkan graphics driver interface.
89 # DRIVER_VERSION should be bumped on any change to driver interface
90 # in FUNCTION_OVERRIDES
91 DRIVER_VERSION = 3
93 # Table of functions for which we have a special implementation.
94 # This are regular device / instance functions for which we need
95 # to more work compared to a regular thunk  or because they are
96 # part of the driver interface.
97 # - dispatch set whether we need a function pointer in the device
98 #   / instance dispatch table.
99 # - driver sets whether the api is part of the driver interface.
100 # - thunk sets whether to create a thunk in vulkan_thunks.c.
101 FUNCTION_OVERRIDES = {
102     # Global functions
103     "vkCreateInstance" : {"dispatch" : False, "driver" : True, "thunk" : False},
104     "vkEnumerateInstanceExtensionProperties" : {"dispatch" : False, "driver" : True, "thunk" : False},
105     "vkGetInstanceProcAddr": {"dispatch" : False, "driver" : True, "thunk" : False},
107     # Instance functions
108     "vkCreateDevice" : {"dispatch" : True, "driver" : False, "thunk" : False},
109     "vkDestroyInstance" : {"dispatch" : True, "driver" : True, "thunk" : False },
110     "vkEnumerateDeviceExtensionProperties" : {"dispatch" : True, "driver" : False, "thunk" : False},
111     "vkEnumeratePhysicalDevices" : {"dispatch" : True, "driver" : False, "thunk" : False},
113     # Device functions
114     "vkAllocateCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : False},
115     "vkCmdExecuteCommands" : {"dispatch" : True, "driver" : False, "thunk" : False},
116     "vkDestroyDevice" : {"dispatch" : True, "driver" : False, "thunk" : False},
117     "vkFreeCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : False},
118     "vkGetDeviceProcAddr" : {"dispatch" : True, "driver" : True, "thunk" : False},
119     "vkGetDeviceQueue" : {"dispatch": True, "driver" : False, "thunk" : False},
120     "vkQueueSubmit" : {"dispatch": True, "driver" : False, "thunk" : False},
122     # VK_KHR_surface
123     "vkDestroySurfaceKHR" : {"dispatch" : True, "driver" : True, "thunk" : False},
124     "vkGetPhysicalDeviceSurfaceSupportKHR" : {"dispatch" : True, "driver" : True, "thunk" : False},
125     "vkGetPhysicalDeviceSurfaceCapabilitiesKHR" : {"dispatch" : True, "driver" : True, "thunk" : False},
126     "vkGetPhysicalDeviceSurfaceFormatsKHR" : {"dispatch" : True, "driver" : True, "thunk" : False},
127     "vkGetPhysicalDeviceSurfacePresentModesKHR" : {"dispatch" : True, "driver" : True, "thunk" : False},
129     # VK_KHR_win32_surface
130     "vkCreateWin32SurfaceKHR" : {"dispatch" : True, "driver" : True, "thunk" : False},
131     "vkGetPhysicalDeviceWin32PresentationSupportKHR" : {"dispatch" : True, "driver" : True, "thunk" : False},
133     # VK_KHR_swapchain
134     "vkAcquireNextImageKHR": {"dispatch" : True, "driver" : True, "thunk" : False},
135     "vkCreateSwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : False},
136     "vkDestroySwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : False},
137     "vkGetSwapchainImagesKHR": {"dispatch" : True, "driver" : True, "thunk" : False},
138     "vkQueuePresentKHR": {"dispatch" : True, "driver" : True, "thunk" : False},
142 class Direction(Enum):
143     """ Parameter direction: input, output, input_output. """
144     INPUT = 1
145     OUTPUT = 2
146     INPUT_OUTPUT = 3
149 class VkBaseType(object):
150     def __init__(self, name, _type, requires=None):
151         """ Vulkan base type class.
153         VkBaseType is mostly used by Vulkan to define its own
154         base types like VkFlags through typedef out of e.g. uint32_t.
156         Args:
157             name (:obj:'str'): Name of the base type.
158             _type (:obj:'str'): Underlaying type
159             requires (:obj:'str', optional): Other types required.
160                 Often bitmask values pull in a *FlagBits type.
161         """
162         self.name = name
163         self.type = _type
164         self.requires = requires
165         self.required = False
167     def definition(self):
168         text = "typedef {0} {1};\n".format(self.type, self.name)
169         return text
172 class VkConstant(object):
173     def __init__(self, name, value):
174         self.name = name
175         self.value = value
177     def definition(self):
178         text = "#define {0} {1}\n".format(self.name, self.value)
179         return text
182 class VkDefine(object):
183     def __init__(self, name, value):
184         self.name = name
185         self.value = value
187     @staticmethod
188     def from_xml(define):
189         name_elem = define.find("name")
191         if name_elem is None:
192             # <type category="define" name="some_name">some_value</type>
193             # At the time of writing there is only 1 define of this category
194             # 'VK_DEFINE_NON_DISPATCHABLE_HANDLE'.
195             name = define.attrib.get("name")
197             # We override behavior of VK_DEFINE_NON_DISPATCHABLE handle as the default
198             # definition various between 64-bit (uses pointers) and 32-bit (uses uint64_t).
199             # This complicates TRACEs in the thunks, so just use uint64_t.
200             if name == "VK_DEFINE_NON_DISPATCHABLE_HANDLE":
201                 value = "#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object;"
202             else:
203                 value = define.text
204             return VkDefine(name, value)
206         # With a name element the structure is like:
207         # <type category="define"><name>some_name</name>some_value</type>
208         name = name_elem.text
210         # VK_API_VERSION is a deprecated constant and we don't really want to parse it or generate
211         # code for it. However the vk.xml feature section still references it.
212         if name == "VK_API_VERSION":
213             return VkDefine(name, "")
215         # The body of the define is basically unstructured C code. It is not meant for easy parsing.
216         # Some lines contain deprecated values or comments, which we try to filter out.
217         value = ""
218         for line in define.text.splitlines():
219             # Skip comments or deprecated values.
220             if "//" in line:
221                 continue
222             value += line
224         for child in define:
225             value += child.text
226             if child.tail is not None:
227                 value += child.tail
229         return VkDefine(name, value.rstrip(' '))
231     def definition(self):
232         if self.value is None:
233             return ""
235         # Nothing to do as the value was already put in the right form during parsing.
236         return "{0}\n".format(self.value)
239 class VkEnum(object):
240     def __init__(self, name, values):
241         self.name = name
242         self.values = values
243         self.required = False
245     @staticmethod
246     def from_xml(enum):
247         name = enum.attrib.get("name")
248         values = []
250         for v in enum.findall("enum"):
251             # Value is either a value or a bitpos, only one can exist.
252             value = v.attrib.get("value")
253             if value is None:
254                 # bitmask
255                 value = 1 << int(v.attrib.get("bitpos"))
256                 values.append(VkEnumValue(v.attrib.get("name"), value, hex=True))
257             else:
258                 # Some values are in hex form. We want to preserve the hex representation
259                 # at least when we convert back to a string. Internally we want to use int.
260                 if "0x" in value:
261                     values.append(VkEnumValue(v.attrib.get("name"), int(value, 0), hex=True))
262                 else:
263                     values.append(VkEnumValue(v.attrib.get("name"), int(value, 0)))
265         # vulkan.h contains a *_MAX_ENUM value set to 32-bit at the time of writing,
266         # which is to prepare for extensions as they can add values and hence affect
267         # the size definition.
268         max_name = re.sub(r'([0-9a-z_])([A-Z0-9])',r'\1_\2',name).upper() + "_MAX_ENUM"
269         values.append(VkEnumValue(max_name, 0x7fffffff, hex=True))
271         return VkEnum(name, values)
273     def add(self, value):
274         """ Add a value to enum. """
275         self.values.append(value)
277     def definition(self):
278         text = "typedef enum {0}\n{{\n".format(self.name)
280         # Print values sorted, values can have been added in a random order.
281         values = sorted(self.values, key=lambda value: value.value)
282         for value in values:
283             text += "    {0},\n".format(value.definition())
284         text += "}} {0};\n\n".format(self.name)
285         return text
288 class VkEnumValue(object):
289     def __init__(self, name, value, hex=False):
290         self.name = name
291         self.value = value
292         self.hex = hex
294     def __repr__(self):
295         return "{0}={1}".format(self.name, self.value)
297     def definition(self):
298         """ Convert to text definition e.g. VK_FOO = 1 """
300         # Hex is commonly used for FlagBits and sometimes within
301         # a non-FlagBits enum for a bitmask value as well.
302         if self.hex:
303             return "{0} = 0x{1:08x}".format(self.name, self.value)
304         else:
305             return "{0} = {1}".format(self.name, self.value)
308 class VkFunction(object):
309     def __init__(self, _type=None, name=None, params=[], extension=None):
310         self.extension = extension
311         self.name = name
312         self.type = _type
313         self.params = params
315         # For some functions we need some extra metadata from FUNCTION_OVERRIDES.
316         func_info = FUNCTION_OVERRIDES.get(self.name, None)
317         self.dispatch = func_info["dispatch"] if func_info is not None else True
318         self.driver = func_info["driver"] if func_info is not None else False
319         self.thunk_needed = func_info["thunk"] if func_info is not None else True
321         # Required is set while parsing which APIs and types are required
322         # and is used by the code generation.
323         self.required = False
325     @staticmethod
326     def from_xml(command, types):
327         proto = command.find("proto")
329         func_name = proto.find("name").text
330         func_type = proto.find("type").text
332         params = []
333         for param in command.findall("param"):
334             vk_param = VkParam.from_xml(param, types)
335             params.append(vk_param)
337         return VkFunction(_type=func_type, name=func_name, params=params)
339     def get_conversions(self):
340         """ Get a list of conversion functions required for this function if any.
341         Parameters which are structures may require conversion between win32
342         and the host platform. This function returns a list of conversions
343         required.
344         """
346         conversions = []
347         for param in self.params:
348             convs = param.get_conversions()
349             if convs is not None:
350                 conversions.extend(convs)
352         return conversions
354     def is_device_func(self):
355         # If none of the other, it must be a device function
356         return not self.is_global_func() and not self.is_instance_func()
358     def is_driver_func(self):
359         """ Returns if function is part of Wine driver interface. """
360         return self.driver
362     def is_global_func(self):
363         # Treat vkGetInstanceProcAddr as a global function as it
364         # can operate with NULL for vkInstance.
365         if self.name == "vkGetInstanceProcAddr":
366             return True
367         # Global functions are not passed a dispatchable object.
368         elif self.params[0].is_dispatchable():
369             return False
370         return True
372     def is_instance_func(self):
373         # Instance functions are passed VkInstance or VkPhysicalDevice.
374         if self.params[0].type in ["VkInstance", "VkPhysicalDevice"]:
375             return True
376         return False
378     def is_required(self):
379         return self.required
381     def needs_conversion(self):
382         """ Check if the function needs any input/output type conversion.
383         Functions need input/output conversion if struct parameters have
384         alignment differences between Win32 and Linux 32-bit.
385         """
387         for p in self.params:
388             if p.needs_conversion():
389                 LOGGER.debug("Parameter {0} to {1} requires conversion".format(p.name, self.name))
390                 return True
392         return False
394     def needs_dispatch(self):
395         return self.dispatch
397     def needs_thunk(self):
398         return self.thunk_needed
400     def pfn(self, call_conv=None, conv=False):
401         """ Create function pointer. """
403         if call_conv is not None:
404             pfn = "{0} ({1} *p_{2})(".format(self.type, call_conv, self.name)
405         else:
406             pfn = "{0} (*p_{1})(".format(self.type, self.name)
408         for i, param in enumerate(self.params):
409             if param.const:
410                 pfn += param.const + " "
412             pfn += param.type
413             if conv and param.needs_conversion():
414                 pfn += "_host"
416             if param.is_pointer():
417                 pfn += " " + param.pointer
419             if param.array_len is not None:
420                 pfn += "[{0}]".format(param.array_len)
422             if i < len(self.params) - 1:
423                 pfn += ", "
424         pfn += ")"
425         return pfn
427     def prototype(self, call_conv=None, prefix=None, postfix=None):
428         """ Generate prototype for given function.
430         Args:
431             call_conv (str, optional): calling convention e.g. WINAPI
432             prefix (str, optional): prefix to append prior to function name e.g. vkFoo -> wine_vkFoo
433             postfix (str, optional): text to append after function name but prior to semicolon e.g. DECLSPEC_HIDDEN
434         """
436         proto = "{0}".format(self.type)
438         if call_conv is not None:
439             proto += " {0}".format(call_conv)
441         if prefix is not None:
442             proto += " {0}{1}(".format(prefix, self.name)
443         else:
444             proto += " {0}(".format(self.name)
446         # Add all the paremeters.
447         proto += ", ".join([p.definition() for p in self.params])
449         if postfix is not None:
450             proto += ") {0}".format(postfix)
451         else:
452             proto += ")"
454         return proto
456     def body(self):
457         body = "    {0}".format(self.trace())
459         params = ", ".join([p.variable(conv=False) for p in self.params])
461         # Call the native Vulkan function.
462         if self.type == "void":
463             body += "    {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
464         else:
465             body += "    return {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
467         return body
469     def body_conversion(self):
470         body = ""
472         # Declare a variable to hold the result for non-void functions.
473         if self.type != "void":
474             body += "    {0} result;\n".format(self.type)
476         # Declare any tmp parameters for conversion.
477         for p in self.params:
478             if not p.needs_conversion():
479                 continue
481             if p.is_dynamic_array():
482                 body += "    {0}_host *{1}_host;\n".format(p.type, p.name)
483             else:
484                 body += "    {0}_host {1}_host;\n".format(p.type, p.name)
486         body += "    {0}\n".format(self.trace())
488         # Call any win_to_host conversion calls.
489         for p in self.params:
490             if not p.needs_input_conversion():
491                 continue
493             body += p.copy(Direction.INPUT)
495         # Build list of parameters containing converted and non-converted parameters.
496         # The param itself knows if conversion is needed and applies it when we set conv=True.
497         params = ", ".join([p.variable(conv=True) for p in self.params])
499         # Call the native Vulkan function.
500         if self.type == "void":
501             body += "    {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
502         else:
503             body += "    result = {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
505         body += "\n"
507         # Call any host_to_win conversion calls.
508         for p in self.params:
509             if not p.needs_output_conversion():
510                 continue
512             body += p.copy(Direction.OUTPUT)
514         # Perform any required cleanups. Most of these are for array functions.
515         for p in self.params:
516             if not p.needs_free():
517                 continue
519             body += p.free()
521         # Finally return the result.
522         if self.type != "void":
523             body += "    return result;\n"
525         return body
527     def stub(self, call_conv=None, prefix=None):
528         stub = self.prototype(call_conv=call_conv, prefix=prefix)
529         stub += "\n{\n"
530         stub += "    {0}".format(self.trace(message="stub: ", trace_func="FIXME"))
532         if self.type == "VkResult":
533             stub += "    return VK_ERROR_OUT_OF_HOST_MEMORY;\n"
534         elif self.type == "VkBool32":
535             stub += "    return VK_FALSE;\n"
536         elif self.type == "PFN_vkVoidFunction":
537             stub += "    return NULL;\n"
539         stub += "}\n\n"
540         return stub
542     def thunk(self, call_conv=None, prefix=None):
543         thunk = self.prototype(call_conv=call_conv, prefix=prefix)
544         thunk += "\n{\n"
546         if self.needs_conversion():
547             thunk += "#if defined(USE_STRUCT_CONVERSION)\n"
548             thunk += self.body_conversion()
549             thunk += "#else\n"
550             thunk += self.body()
551             thunk += "#endif\n"
552         else:
553             thunk += self.body()
555         thunk += "}\n\n"
556         return thunk
558     def trace(self, message=None, trace_func=None):
559         """ Create a trace string including all parameters.
561         Args:
562             message (str, optional): text to print at start of trace message e.g. 'stub: '
563             trace_func (str, optional): used to override trace function e.g. FIXME, printf, etcetera.
564         """
565         if trace_func is not None:
566             trace = "{0}(\"".format(trace_func)
567         else:
568             trace = "TRACE(\""
570         if message is not None:
571             trace += message
573         # First loop is for all the format strings.
574         trace += ", ".join([p.format_string() for p in self.params])
575         trace += "\\n\""
577         # Second loop for parameter names and optional conversions.
578         for param in self.params:
579             if param.format_conv is not None:
580                 trace += ", " + param.format_conv.format(param.name)
581             else:
582                 trace += ", {0}".format(param.name)
583         trace += ");\n"
585         return trace
588 class VkFunctionPointer(object):
589     def __init__(self, _type, name, members):
590         self.name = name
591         self.members = members
592         self.type = _type
593         self.required = False
595     @staticmethod
596     def from_xml(funcpointer):
597         members = []
598         begin = None
600         for t in funcpointer.findall("type"):
601             # General form:
602             # <type>void</type>*       pUserData,
603             # Parsing of the tail (anything past </type>) is tricky since there
604             # can be other data on the next line like: const <type>int</type>..
605             const = begin
606             _type = t.text
607             lines = t.tail.split(",\n")
608             if lines[0][0] == "*":
609                 pointer = "*"
610                 name = lines[0][1:].strip()
611             else:
612                 pointer = None
613                 name = lines[0].strip()
615             # Filter out ); if it is contained.
616             name = name.partition(");")[0]
618             # If tail encompasses multiple lines, assign the second line to begin
619             # for the next line.
620             try:
621                 begin = lines[1].strip()
622             except IndexError:
623                 begin = None
625             members.append(VkMember(const=const, _type=_type, pointer=pointer, name=name))
627         _type = funcpointer.text
628         name = funcpointer.find("name").text
629         return VkFunctionPointer(_type, name, members)
631     def definition(self):
632         text = "{0} {1})(\n".format(self.type, self.name)
634         first = True
635         if len(self.members) > 0:
636             for m in self.members:
637                 if first:
638                     text += "    " + m.definition()
639                     first = False
640                 else:
641                     text += ",\n    " + m.definition()
642         else:
643             # Just make the compiler happy by adding a void parameter.
644             text += "void"
645         text += ");\n"
646         return text
649 class VkHandle(object):
650     def __init__(self, name, _type, parent):
651         self.name = name
652         self.type = _type
653         self.parent = parent
654         self.required = False
656     @staticmethod
657     def from_xml(handle):
658         name = handle.find("name").text
659         _type = handle.find("type").text
660         parent = handle.attrib.get("parent") # Most objects have a parent e.g. VkQueue has VkDevice.
661         return VkHandle(name, _type, parent)
663     def dispatch_table(self):
664         if not self.is_dispatchable():
665             return None
667         if self.parent is None:
668             # Should only happen for VkInstance
669             return "funcs"
670         elif self.name == "VkDevice":
671             # VkDevice has VkInstance as a parent, but has its own dispatch table.
672             return "funcs"
673         elif self.parent in ["VkInstance", "VkPhysicalDevice"]:
674             return "instance->funcs"
675         elif self.parent in ["VkDevice", "VkCommandPool"]:
676             return "device->funcs"
677         else:
678             LOGGER.error("Unhandled dispatchable parent: {0}".format(self.parent))
680     def definition(self):
681         """ Generates handle definition e.g. VK_DEFINE_HANDLE(vkInstance) """
682         return "{0}({1})\n".format(self.type, self.name)
684     def is_dispatchable(self):
685         """ Some handles like VkInstance, VkDevice are dispatchable objects,
686         which means they contain a dispatch table of function pointers.
687         """
688         return self.type == "VK_DEFINE_HANDLE"
690     def native_handle(self):
691         """ Provide access to the native handle of a dispatchable object.
693         Dispatchable objects wrap an underlying 'native' object.
694         This method provides access to the native object.
695         """
696         if not self.is_dispatchable():
697             return None
699         if self.name == "VkCommandBuffer":
700             return "command_buffer"
701         elif self.name == "VkDevice":
702             return "device"
703         elif self.name == "VkInstance":
704             return "instance"
705         elif self.name == "VkPhysicalDevice":
706             return "phys_dev"
707         elif self.name == "VkQueue":
708             return "queue"
709         else:
710             LOGGER.error("Unhandled native handle for: {0}".format(self.name))
713 class VkMember(object):
714     def __init__(self, const=None, _type=None, pointer=None, name=None, array_len=None, dyn_array_len=None, optional=False,
715             extension_structs=None):
716         self.const = const
717         self.name = name
718         self.pointer = pointer
719         self.type = _type
720         self.type_info = None
721         self.array_len = array_len
722         self.dyn_array_len = dyn_array_len
723         self.optional = optional
724         self.extension_structs = extension_structs
726     def __eq__(self, other):
727         """ Compare member based on name against a string.
729         This method is for convenience by VkStruct, which holds a number of members and needs quick checking
730         if certain members exist.
731         """
733         if self.name == other:
734             return True
736         return False
738     def __repr__(self):
739         return "{0} {1} {2} {3} {4} {5}".format(self.const, self.type, self.pointer, self.name, self.array_len,
740                 self.dyn_array_len)
742     @staticmethod
743     def from_xml(member):
744         """ Helper function for parsing a member tag within a struct or union. """
746         name_elem = member.find("name")
747         type_elem = member.find("type")
749         const = member.text.strip() if member.text else None
750         member_type = None
751         pointer = None
752         array_len = None
754         if type_elem is not None:
755             member_type = type_elem.text
756             if type_elem.tail is not None:
757                 pointer = type_elem.tail.strip() if type_elem.tail.strip() != "" else None
759         # Name of other member within, which stores the number of
760         # elements pointed to be by this member.
761         dyn_array_len = member.get("len", None)
763         if "validextensionstructs" in member.attrib:
764             extension_structs = member.get("validextensionstructs").split(",")
765         else:
766             extension_structs = None
768         # Some members are optional, which is important for conversion code e.g. not dereference NULL pointer.
769         optional = True if member.get("optional") else False
771         # Usually we need to allocate memory for dynamic arrays. We need to do the same in a few other cases
772         # like for VkCommandBufferBeginInfo.pInheritanceInfo. Just threat such cases as dynamic arrays of
773         # size 1 to simplify code generation.
774         if dyn_array_len is None and pointer is not None:
775             dyn_array_len = 1
777         # Some members are arrays, attempt to parse these. Formats include:
778         # <member><type>char</type><name>extensionName</name>[<enum>VK_MAX_EXTENSION_NAME_SIZE</enum>]</member>
779         # <member><type>uint32_t</type><name>foo</name>[4]</member>
780         if name_elem.tail and name_elem.tail[0] == '[':
781             LOGGER.debug("Found array type")
782             enum_elem = member.find("enum")
783             if enum_elem is not None:
784                 array_len = enum_elem.text
785             else:
786                 # Remove brackets around length
787                 array_len = name_elem.tail.strip("[]")
789         return VkMember(const=const, _type=member_type, pointer=pointer, name=name_elem.text, array_len=array_len,
790                 dyn_array_len=dyn_array_len, optional=optional, extension_structs=extension_structs)
792     def copy(self, input, output, direction):
793         """ Helper method for use by conversion logic to generate a C-code statement to copy this member. """
795         if self.needs_conversion():
796             if self.is_dynamic_array():
797                 if direction == Direction.OUTPUT:
798                     LOGGER.warn("TODO: implement copying of returnedonly dynamic array for {0}.{1}".format(self.type, self.name))
799                 else:
800                     # Array length is either a variable name (string) or an int.
801                     count = self.dyn_array_len if isinstance(self.dyn_array_len, int) else "{0}{1}".format(input, self.dyn_array_len)
802                     return "{0}{1} = convert_{2}_array_win_to_host({3}{1}, {4});\n".format(output, self.name, self.type, input, count)
803             elif self.is_static_array():
804                 count = self.array_len
805                 if direction == Direction.OUTPUT:
806                     # Needed by VkMemoryHeap.memoryHeaps
807                     return "convert_{0}_static_array_host_to_win({2}{1}, {3}{1}, {4});\n".format(self.type, self.name, input, output, count)
808                 else:
809                     # Nothing needed this yet.
810                     LOGGER.warn("TODO: implement copying of static array for {0}.{1}".format(self.type, self.name))
811             else:
812                 if direction == Direction.OUTPUT:
813                     return "convert_{0}_host_to_win(&{2}{1}, &{3}{1});\n".format(self.type, self.name, input, output)
814                 else:
815                     return "convert_{0}_win_to_host(&{2}{1}, &{3}{1});\n".format(self.type, self.name, input, output)
816         elif self.is_static_array():
817             bytes_count = "{0} * sizeof({1})".format(self.array_len, self.type)
818             return "memcpy({0}{1}, {2}{1}, {3});\n".format(output, self.name, input, bytes_count)
819         else:
820             return "{0}{1} = {2}{1};\n".format(output, self.name, input)
822     def definition(self, align=False, conv=False):
823         """ Generate prototype for given function.
825         Args:
826             align (bool, optional): Enable alignment if a type needs it. This adds WINE_VK_ALIGN(8) to a member.
827             conv (bool, optional): Enable conversion if a type needs it. This appends '_host' to the name.
828         """
830         text = ""
831         if self.is_const():
832             text += "const "
834         if conv and self.is_struct():
835             text += "{0}_host".format(self.type)
836         else:
837             text += self.type
839         if self.is_pointer():
840             text += " {0}{1}".format(self.pointer, self.name)
841         else:
842             if align and self.needs_alignment():
843                 text += " WINE_VK_ALIGN(8) " + self.name
844             else:
845                 text += " " + self.name
847         if self.is_static_array():
848             text += "[{0}]".format(self.array_len)
850         return text
852     def get_conversions(self):
853         """ Return any conversion description for this member and its children when conversion is needed. """
855         # Check if we need conversion either for this member itself or for any child members
856         # in case member represents a struct.
857         if not self.needs_conversion():
858             return None
860         conversions = []
862         # Collect any conversion for any member structs.
863         struct = self.type_info["data"]
864         for m in struct:
865             if m.needs_conversion():
866                 conversions.extend(m.get_conversions())
868         struct = self.type_info["data"]
869         direction = Direction.OUTPUT if struct.returnedonly else Direction.INPUT
870         if self.is_dynamic_array():
871             conversions.append(ConversionFunction(False, True, direction, struct))
872         elif self.is_static_array():
873             conversions.append(ConversionFunction(True, False, direction, struct))
874         else:
875             conversions.append(ConversionFunction(False, False, direction, struct))
877         if self.needs_free():
878             conversions.append(FreeFunction(self.is_dynamic_array(), struct))
880         return conversions
882     def is_const(self):
883         return self.const is not None
885     def is_dynamic_array(self):
886         """ Returns if the member is an array element.
887         Vulkan uses this for dynamically sized arrays for which
888         there is a 'count' parameter.
889         """
890         return self.dyn_array_len is not None
892     def is_handle(self):
893         return self.type_info["category"] == "handle"
895     def is_pointer(self):
896         return self.pointer is not None
898     def is_static_array(self):
899         """ Returns if the member is an array.
900         Vulkan uses this often for fixed size arrays in which the
901         length is part of the member.
902         """
903         return self.array_len is not None
905     def is_struct(self):
906         return self.type_info["category"] == "struct"
908     def is_union(self):
909         return self.type_info["category"] == "union"
911     def needs_alignment(self):
912         """ Check if this member needs alignment for 64-bit data.
913         Various structures need alignment on 64-bit variables due
914         to compiler differences on 32-bit between Win32 and Linux.
915         """
917         if self.is_pointer():
918             return False
919         elif self.type == "size_t":
920             return False
921         elif self.type in ["uint64_t", "VkDeviceSize"]:
922             return True
923         elif self.is_struct():
924             struct = self.type_info["data"]
925             return struct.needs_alignment()
926         elif self.is_handle():
927             # Dispatchable handles are pointers to objects, while
928             # non-dispatchable are uint64_t and hence need alignment.
929             handle = self.type_info["data"]
930             return False if handle.is_dispatchable() else True
931         return False
933     def needs_conversion(self):
934         """ Structures requiring alignment, need conversion between win32 and host. """
936         if not self.is_struct():
937             return False
939         struct = self.type_info["data"]
940         return struct.needs_conversion()
942     def needs_free(self):
943         if not self.needs_conversion():
944             return False
946         if self.is_dynamic_array():
947             return True
949         # TODO: some non-pointer structs and optional pointer structs may need freeing,
950         # though none of this type have been encountered yet.
951         return False
953     def set_type_info(self, type_info):
954         """ Helper function to set type information from the type registry.
955         This is needed, because not all type data is available at time of
956         parsing.
957         """
958         self.type_info = type_info
961 class VkParam(object):
962     """ Helper class which describes a parameter to a function call. """
964     def __init__(self, type_info, const=None, pointer=None, name=None, array_len=None, dyn_array_len=None):
965         self.const = const
966         self.name = name
967         self.array_len = array_len
968         self.dyn_array_len = dyn_array_len
969         self.pointer = pointer
970         self.type_info = type_info
971         self.type = type_info["name"] # For convenience
972         self.handle = type_info["data"] if type_info["category"] == "handle" else None
973         self.struct = type_info["data"] if type_info["category"] == "struct" else None
975         self._set_direction()
976         self._set_format_string()
977         self._set_conversions()
979     def __repr__(self):
980         return "{0} {1} {2} {3} {4}".format(self.const, self.type, self.pointer, self.name, self.array_len, self.dyn_array_len)
982     @staticmethod
983     def from_xml(param, types):
984         """ Helper function to create VkParam from xml. """
986         # Parameter parsing is slightly tricky. All the data is contained within
987         # a param tag, but some data is within subtags while others are text
988         # before or after the type tag.
989         # Common structure:
990         # <param>const <type>char</type>* <name>pLayerName</name></param>
992         name_elem = param.find("name")
993         array_len = None
994         name = name_elem.text
995         # Tail contains array length e.g. for blendConstants param of vkSetBlendConstants
996         if name_elem.tail is not None:
997             array_len = name_elem.tail.strip("[]")
999         # Name of other parameter in function prototype, which stores the number of
1000         # elements pointed to be by this parameter.
1001         dyn_array_len = param.get("len", None)
1003         const = param.text.strip() if param.text else None
1004         type_elem = param.find("type")
1005         pointer = type_elem.tail.strip() if type_elem.tail.strip() != "" else None
1007         # Since we have parsed all types before hand, this should not happen.
1008         type_info = types.get(type_elem.text, None)
1009         if type_info is None:
1010             LOGGER.err("type info not found for: {0}".format(type_elem.text))
1012         return VkParam(type_info, const=const, pointer=pointer, name=name, array_len=array_len, dyn_array_len=dyn_array_len)
1014     def _set_conversions(self):
1015         """ Internal helper function to configure any needed conversion functions. """
1017         self.free_func = None
1018         self.input_conv = None
1019         self.output_conv = None
1020         if not self.needs_conversion():
1021             return
1023         # Input functions require win to host conversion.
1024         if self._direction in [Direction.INPUT, Direction.INPUT_OUTPUT]:
1025             self.input_conv = ConversionFunction(False, self.is_dynamic_array(), Direction.INPUT, self.struct)
1027         # Output functions require host to win conversion.
1028         if self._direction in [Direction.INPUT_OUTPUT, Direction.OUTPUT]:
1029             self.output_conv = ConversionFunction(False, self.is_dynamic_array(), Direction.OUTPUT, self.struct)
1031         # Dynamic arrays, but also some normal structs (e.g. VkCommandBufferBeginInfo) need memory
1032         # allocation and thus some cleanup.
1033         if self.is_dynamic_array() or self.struct.needs_free():
1034             self.free_func = FreeFunction(self.is_dynamic_array(), self.struct)
1036     def _set_direction(self):
1037         """ Internal helper function to set parameter direction (input/output/input_output). """
1039         # The parameter direction needs to be determined from hints in vk.xml like returnedonly,
1040         # parameter constness and other heuristics.
1041         # For now we need to get this right for structures as we need to convert these, we may have
1042         # missed a few other edge cases (e.g. count variables).
1043         # See also https://github.com/KhronosGroup/Vulkan-Docs/issues/610
1045         if not self.is_pointer():
1046             self._direction = Direction.INPUT
1047         elif self.is_const() and self.is_pointer():
1048             self._direction = Direction.INPUT
1049         elif self.is_struct():
1050             if not self.struct.returnedonly:
1051                 self._direction = Direction.INPUT
1052                 return
1054             # Returnedonly hints towards output, however in some cases
1055             # it is inputoutput. In particular if pNext / sType exist,
1056             # which are used to link in other structures without having
1057             # to introduce new APIs. E.g. vkGetPhysicalDeviceProperties2KHR.
1058             if "pNext" in self.struct:
1059                 self._direction = Direction.INPUT_OUTPUT
1060                 return
1062             self._direction = Direction.OUTPUT
1063         else:
1064             # This should mostly be right. Count variables can be inout, but we don't care about these yet.
1065             self._direction = Direction.OUTPUT
1067     def _set_format_string(self):
1068         """ Internal helper function to be used by constructor to set format string. """
1070         # Determine a format string used by code generation for traces.
1071         # 64-bit types need a conversion function.
1072         self.format_conv = None
1073         if self.is_static_array() or self.is_pointer():
1074             self.format_str = "%p"
1075         else:
1076             if self.type_info["category"] == "bitmask":
1077                 self.format_str = "%#x"
1078             elif self.type_info["category"] == "enum":
1079                 self.format_str = "%d"
1080             elif self.is_handle():
1081                 # We use uint64_t for non-dispatchable handles as opposed to pointers
1082                 # for dispatchable handles.
1083                 if self.handle.is_dispatchable():
1084                     self.format_str = "%p"
1085                 else:
1086                     self.format_str = "0x%s"
1087                     self.format_conv = "wine_dbgstr_longlong({0})"
1088             elif self.type == "float":
1089                 self.format_str = "%f"
1090             elif self.type == "int":
1091                 self.format_str = "%d"
1092             elif self.type == "int32_t":
1093                 self.format_str = "%d"
1094             elif self.type == "size_t":
1095                 self.format_str = "0x%s"
1096                 self.format_conv = "wine_dbgstr_longlong({0})"
1097             elif self.type in ["uint32_t", "VkBool32"]:
1098                 self.format_str = "%u"
1099             elif self.type in ["uint64_t", "VkDeviceSize"]:
1100                 self.format_str = "0x%s"
1101                 self.format_conv = "wine_dbgstr_longlong({0})"
1102             elif self.type == "HANDLE":
1103                 self.format_str = "%p"
1104             elif self.type in ["VisualID", "xcb_visualid_t", "RROutput"]:
1105                 # Don't care about Linux specific types.
1106                 self.format_str = ""
1107             else:
1108                 LOGGER.warn("Unhandled type: {0}".format(self.type_info))
1110     def copy(self, direction):
1111         if direction == Direction.INPUT:
1112             if self.is_dynamic_array():
1113                 return "    {0}_host = convert_{1}_array_win_to_host({0}, {2});\n".format(self.name, self.type, self.dyn_array_len)
1114             else:
1115                 return "    convert_{0}_win_to_host({1}, &{1}_host);\n".format(self.type, self.name)
1116         else:
1117             if self.is_dynamic_array():
1118                 LOGGER.error("Unimplemented output conversion for: {0}".format(self.name))
1119             else:
1120                 return "    convert_{0}_host_to_win(&{1}_host, {1});\n".format(self.type, self.name)
1122     def definition(self, postfix=None):
1123         """ Return prototype for the parameter. E.g. 'const char *foo' """
1125         proto = ""
1126         if self.const:
1127             proto += self.const + " "
1129         proto += self.type
1131         if self.is_pointer():
1132             proto += " {0}{1}".format(self.pointer, self.name)
1133         else:
1134             proto += " " + self.name
1136         # Allows appeninding something to the variable name useful for
1137         # win32 to host conversion.
1138         if postfix is not None:
1139             proto += postfix
1141         if self.is_static_array():
1142             proto += "[{0}]".format(self.array_len)
1144         return proto
1146     def direction(self):
1147         """ Returns parameter direction: input, output, input_output.
1149         Parameter direction in Vulkan is not straight-forward, which this function determines.
1150         """
1152         return self._direction
1154     def format_string(self):
1155         return self.format_str
1157     def dispatch_table(self):
1158         """ Return functions dispatch table pointer for dispatchable objects. """
1160         if not self.is_dispatchable():
1161             return None
1163         return "{0}->{1}".format(self.name, self.handle.dispatch_table())
1165     def format_string(self):
1166         return self.format_str
1168     def free(self):
1169         if self.is_dynamic_array():
1170             if self.struct.returnedonly:
1171                 # For returnedonly, counts is stored in a pointer.
1172                 return "    free_{0}_array({1}_host, *{2});\n".format(self.type, self.name, self.dyn_array_len)
1173             else:
1174                 return "    free_{0}_array({1}_host, {2});\n".format(self.type, self.name, self.dyn_array_len)
1175         else:
1176             # We are operating on a single structure. Some structs (very rare) contain dynamic members,
1177             # which would need freeing.
1178             if self.struct.needs_free():
1179                 return "    free_{0}(&{1}_host);\n".format(self.type, self.name)
1180         return ""
1182     def get_conversions(self):
1183         """ Get a list of conversions required for this parameter if any.
1184         Parameters which are structures may require conversion between win32
1185         and the host platform. This function returns a list of conversions
1186         required.
1187         """
1189         if not self.is_struct():
1190             return None
1192         if not self.needs_conversion():
1193             return None
1195         conversions = []
1197         # Collect any member conversions first, so we can guarantee
1198         # those functions will be defined prior to usage by the
1199         # 'parent' param requiring conversion.
1200         for m in self.struct:
1201             if not m.is_struct():
1202                 continue
1204             if not m.needs_conversion():
1205                 continue
1207             conversions.extend(m.get_conversions())
1209         # Conversion requirements for the 'parent' parameter.
1210         if self.input_conv is not None:
1211             conversions.append(self.input_conv)
1212         if self.output_conv is not None:
1213             conversions.append(self.output_conv)
1214         if self.free_func is not None:
1215             conversions.append(self.free_func)
1217         return conversions
1219     def is_const(self):
1220         return self.const is not None
1222     def is_dynamic_array(self):
1223         return self.dyn_array_len is not None
1225     def is_dispatchable(self):
1226         if not self.is_handle():
1227             return False
1229         return self.handle.is_dispatchable()
1231     def is_handle(self):
1232         return self.handle is not None
1234     def is_pointer(self):
1235         return self.pointer is not None
1237     def is_static_array(self):
1238         return self.array_len is not None
1240     def is_struct(self):
1241         return self.struct is not None
1243     def needs_conversion(self):
1244         """ Returns if parameter needs conversion between win32 and host. """
1246         if not self.is_struct():
1247             return False
1249         # VkSparseImageMemoryRequirements is used by vkGetImageSparseMemoryRequirements.
1250         # This function is tricky to wrap, because how to wrap depends on whether
1251         # pSparseMemoryRequirements is NULL or not. Luckily for VkSparseImageMemoryRequirements
1252         # the alignment works out in such a way that no conversion is needed between win32 and Linux.
1253         if self.type == "VkSparseImageMemoryRequirements":
1254             return False
1256         # If a structure needs alignment changes, it means we need to
1257         # perform parameter conversion between win32 and host.
1258         if self.struct.needs_conversion():
1259             return True
1261         return False
1263     def needs_free(self):
1264         return self.free_func is not None
1266     def needs_input_conversion(self):
1267         return self.input_conv is not None
1269     def needs_output_conversion(self):
1270         return self.output_conv is not None
1272     def variable(self, conv=False):
1273         """ Returns 'glue' code during generation of a function call on how to access the variable.
1274         This function handles various scenarios such as 'unwrapping' if dispatchable objects and
1275         renaming of parameters in case of win32 -> host conversion.
1277         Args:
1278             conv (bool, optional): Enable conversion if the param needs it. This appends '_host' to the name.
1279         """
1281         # Hack until we enable allocation callbacks from ICD to application. These are a joy
1282         # to enable one day, because of calling convention conversion.
1283         if "VkAllocationCallbacks" in self.type:
1284             LOGGER.debug("TODO: setting NULL VkAllocationCallbacks for {0}".format(self.name))
1285             return "NULL"
1287         # Dispatchable objects wrap the native handle. For thunk generation we
1288         # need to pass the native handle to the native vulkan calls.
1289         if self.is_dispatchable():
1290             return "{0}->{1}".format(self.name, self.handle.native_handle())
1291         elif conv and self.needs_conversion():
1292             if self.is_dynamic_array():
1293                 return "{0}_host".format(self.name)
1294             else:
1295                 return "&{0}_host".format(self.name)
1296         else:
1297             return self.name
1300 class VkStruct(Sequence):
1301     """ Class which represents the type union and struct. """
1303     def __init__(self, name, members, returnedonly, union=False):
1304         self.name = name
1305         self.members = members
1306         self.returnedonly = returnedonly
1307         self.required = False
1308         self.union = union
1309         self.type_info = None # To be set later.
1311     def __getitem__(self, i):
1312         return self.members[i]
1314     def __len__(self):
1315         return len(self.members)
1317     @staticmethod
1318     def from_xml(struct):
1319         # Unions and structs are the same parsing wise, but we need to
1320         # know which one we are dealing with later on for code generation.
1321         union = True if struct.attrib["category"] == "union" else False
1323         name = struct.attrib.get("name", None)
1325         # 'Output' structures for which data is filled in by the API are
1326         # marked as 'returnedonly'.
1327         returnedonly = True if struct.attrib.get("returnedonly") else False
1329         members = []
1330         for member in struct.findall("member"):
1331             vk_member = VkMember.from_xml(member)
1332             members.append(vk_member)
1334         return VkStruct(name, members, returnedonly, union=union)
1336     @staticmethod
1337     def decouple_structs(structs):
1338         """ Helper function which decouples a list of structs.
1339         Structures often depend on other structures. To make the C compiler
1340         happy we need to define 'substructures' first. This function analyzes
1341         the list of structures and reorders them in such a way that they are
1342         decoupled.
1343         """
1345         tmp_structs = list(structs) # Don't modify the original structures.
1346         decoupled_structs = []
1348         while (len(tmp_structs) > 0):
1349             for struct in tmp_structs:
1350                 dependends = False
1352                 if not struct.required:
1353                     tmp_structs.remove(struct)
1354                     continue
1356                 for m in struct:
1357                     if not (m.is_struct() or m.is_union()):
1358                         continue
1360                     found = False
1361                     # Check if a struct we depend on has already been defined.
1362                     for s in decoupled_structs:
1363                         if s.name == m.type:
1364                             found = True
1365                             break
1367                     if not found:
1368                         # Check if the struct we depend on is even in the list of structs.
1369                         # If found now, it means we haven't met all dependencies before we
1370                         # can operate on the current struct.
1371                         # When generating 'host' structs we may not be able to find a struct
1372                         # as the list would only contain the structs requiring conversion.
1373                         for s in tmp_structs:
1374                             if s.name == m.type:
1375                                 dependends = True
1376                                 break
1378                 if dependends == False:
1379                     decoupled_structs.append(struct)
1380                     tmp_structs.remove(struct)
1382         return decoupled_structs
1384     def definition(self, align=False, conv=False, postfix=None):
1385         """ Convert structure to textual definition.
1387         Args:
1388             align (bool, optional): enable alignment to 64-bit for win32 struct compatibility.
1389             conv (bool, optional): enable struct conversion if the struct needs it.
1390             postfix (str, optional): text to append to end of struct name, useful for struct renaming.
1391         """
1393         if self.union:
1394             text = "typedef union {0}".format(self.name)
1395         else:
1396             text = "typedef struct {0}".format(self.name)
1398         if postfix is not None:
1399             text += postfix
1401         text += "\n{\n"
1403         for m in self:
1404             if align and m.needs_alignment():
1405                 text += "    {0};\n".format(m.definition(align=align))
1406             elif conv and m.needs_conversion():
1407                 text += "    {0};\n".format(m.definition(conv=conv))
1408             else:
1409                 text += "    {0};\n".format(m.definition())
1411         if postfix is not None:
1412             text += "}} {0}{1};\n\n".format(self.name, postfix)
1413         else:
1414             text += "}} {0};\n\n".format(self.name)
1415         return text
1417     def needs_alignment(self):
1418         """ Check if structure needs alignment for 64-bit data.
1419         Various structures need alignment on 64-bit variables due
1420         to compiler differences on 32-bit between Win32 and Linux.
1421         """
1423         for m in self.members:
1424             if m.needs_alignment():
1425                 return True
1426         return False
1428     def needs_conversion(self):
1429         """ Returns if struct members needs conversion between win32 and host.
1430         Structures need conversion if they contain members requiring alignment
1431         or if they include other structures which need alignment.
1432         """
1434         if self.needs_alignment():
1435             return True
1437         for m in self.members:
1438             if m.needs_conversion():
1439                 return True
1440         return False
1442     def needs_free(self):
1443         """ Check if any struct member needs some memory freeing."""
1445         for m in self.members:
1446             if m.needs_free():
1447                 return True
1449             continue
1451         return False
1453     def set_type_info(self, types):
1454         """ Helper function to set type information from the type registry.
1455         This is needed, because not all type data is available at time of
1456         parsing.
1457         """
1458         for m in self.members:
1459             type_info = types[m.type]
1460             m.set_type_info(type_info)
1463 class ConversionFunction(object):
1464     def __init__(self, array, dyn_array, direction, struct):
1465         self.array = array
1466         self.direction = direction
1467         self.dyn_array = dyn_array
1468         self.struct = struct
1469         self.type = struct.name
1471         self._set_name()
1473     def __eq__(self, other):
1474         if self.name != other.name:
1475             return False
1477         return True
1479     def _generate_array_conversion_func(self):
1480         """ Helper function for generating a conversion function for array structs. """
1482         if self.direction == Direction.OUTPUT:
1483             params = ["const {0}_host *in".format(self.type), "uint32_t count"]
1484             return_type = self.type
1485         else:
1486             params = ["const {0} *in".format(self.type), "uint32_t count"]
1487             return_type = "{0}_host".format(self.type)
1489         # Generate function prototype.
1490         body = "static inline {0} *{1}(".format(return_type, self.name)
1491         body += ", ".join(p for p in params)
1492         body += ")\n{\n"
1494         body += "    {0} *out;\n".format(return_type)
1495         body += "    unsigned int i;\n\n"
1496         body += "    if (!in) return NULL;\n\n"
1498         body += "    out = heap_alloc(count * sizeof(*out));\n"
1500         body += "    for (i = 0; i < count; i++)\n"
1501         body += "    {\n"
1503         for m in self.struct:
1504             # TODO: support copying of pNext extension structures!
1505             # Luckily though no extension struct at this point needs conversion.
1506             body += "        " + m.copy("in[i].", "out[i].", self.direction)
1508         body += "    }\n\n"
1509         body += "    return out;\n"
1510         body += "}\n\n"
1511         return body
1513     def _generate_conversion_func(self):
1514         """ Helper function for generating a conversion function for non-array structs. """
1516         if self.direction == Direction.OUTPUT:
1517             params = ["const {0}_host *in".format(self.type), "{0} *out".format(self.type)]
1518         else:
1519             params = ["const {0} *in".format(self.type), "{0}_host *out".format(self.type)]
1521         body = "static inline void {0}(".format(self.name)
1523         # Generate parameter list
1524         body += ", ".join(p for p in params)
1525         body += ")\n{\n"
1527         body += "    if (!in) return;\n\n"
1529         if self.direction == Direction.INPUT and "pNext" in self.struct and self.struct.returnedonly:
1530             # We are dealing with an input_output parameter. For these we only need to copy
1531             # pNext and sType as the other fields are filled in by the host. We do potentially
1532             # have to iterate over pNext and perform conversions based on switch(sType)!
1533             # Luckily though no extension structs at this point need conversion.
1534             # TODO: support copying of pNext extension structures!
1535             body += "    out->pNext = in->pNext;\n"
1536             body += "    out->sType = in->sType;\n"
1537         else:
1538             for m in self.struct:
1539                 # TODO: support copying of pNext extension structures!
1540                 body += "    " + m.copy("in->", "out->", self.direction)
1542         body += "}\n\n"
1543         return body
1545     def _generate_static_array_conversion_func(self):
1546         """ Helper function for generating a conversion function for array structs. """
1548         if self.direction == Direction.OUTPUT:
1549             params = ["const {0}_host *in".format(self.type), "{0} *out".format(self.type), "uint32_t count"]
1550             return_type = self.type
1551         else:
1552             params = ["const {0} *in".format(self.type), "{0} *out_host".format(self.type), "uint32_t count"]
1553             return_type = "{0}_host".format(self.type)
1555         # Generate function prototype.
1556         body = "static inline void {0}(".format(self.name)
1557         body += ", ".join(p for p in params)
1558         body += ")\n{\n"
1559         body += "    unsigned int i;\n\n"
1560         body += "    if (!in) return;\n\n"
1561         body += "    for (i = 0; i < count; i++)\n"
1562         body += "    {\n"
1564         for m in self.struct:
1565             # TODO: support copying of pNext extension structures!
1566             body += "        " + m.copy("in[i].", "out[i].", self.direction)
1568         body += "    }\n"
1569         body += "}\n\n"
1570         return body
1572     def _set_name(self):
1573         if self.direction == Direction.INPUT:
1574             if self.array:
1575                 name = "convert_{0}_static_array_win_to_host".format(self.type)
1576             elif self.dyn_array:
1577                 name = "convert_{0}_array_win_to_host".format(self.type)
1578             else:
1579                 name = "convert_{0}_win_to_host".format(self.type)
1580         else: # Direction.OUTPUT
1581             if self.array:
1582                 name = "convert_{0}_static_array_host_to_win".format(self.type)
1583             elif self.dyn_array:
1584                 name = "convert_{0}_array_host_to_win".format(self.type)
1585             else:
1586                 name = "convert_{0}_host_to_win".format(self.type)
1588         self.name = name
1590     def definition(self):
1591         if self.array:
1592             return self._generate_static_array_conversion_func()
1593         elif self.dyn_array:
1594             return self._generate_array_conversion_func()
1595         else:
1596             return self._generate_conversion_func()
1599 class FreeFunction(object):
1600     def __init__(self, dyn_array, struct):
1601         self.dyn_array = dyn_array
1602         self.struct = struct
1603         self.type = struct.name
1605         if dyn_array:
1606             self.name = "free_{0}_array".format(self.type)
1607         else:
1608             self.name = "free_{0}".format(self.type)
1610     def __eq__(self, other):
1611         if self.name == other.name:
1612             return True
1614         return False
1616     def _generate_array_free_func(self):
1617         """ Helper function for cleaning up temporary buffers required for array conversions. """
1619         # Generate function prototype.
1620         body = "static inline void {0}({1}_host *in, uint32_t count)\n{{\n".format(self.name, self.type)
1622         # E.g. VkGraphicsPipelineCreateInfo_host needs freeing for pStages.
1623         if self.struct.needs_free():
1624             body += "    unsigned int i;\n\n"
1625             body += "    if (!in) return;\n\n"
1626             body += "    for (i = 0; i < count; i++)\n"
1627             body += "    {\n"
1629             for m in self.struct:
1630                 if m.needs_conversion() and m.is_dynamic_array():
1631                     if m.is_const():
1632                         # Add a cast to ignore const on conversion structs we allocated ourselves.
1633                         body += "        free_{0}_array(({0}_host *)in[i].{1}, in[i].{2});\n".format(m.type, m.name, m.dyn_array_len)
1634                     else:
1635                         body += "        free_{0}_array(in[i].{1}, in[i].{2});\n".format(m.type, m.name, m.dyn_array_len)
1636                 elif m.needs_conversion():
1637                     LOGGER.error("Unhandled conversion for {0}".format(m.name))
1638             body += "    }\n"
1639         else:
1640             body += "    if (!in) return;\n\n"
1642         body += "    heap_free(in);\n"
1644         body += "}\n\n"
1645         return body
1647     def _generate_free_func(self):
1648         # E.g. VkCommandBufferBeginInfo.pInheritanceInfo needs freeing.
1649         if not self.struct.needs_free():
1650             return ""
1652         # Generate function prototype.
1653         body = "static inline void {0}({1}_host *in)\n{{\n".format(self.name, self.type)
1655         for m in self.struct:
1656             if m.needs_conversion() and m.is_dynamic_array():
1657                 count = m.dyn_array_len if isinstance(m.dyn_array_len, int) else "in->{0}".format(m.dyn_array_len)
1658                 if m.is_const():
1659                     # Add a cast to ignore const on conversion structs we allocated ourselves.
1660                     body += "    free_{0}_array(({0}_host *)in->{1}, {2});\n".format(m.type, m.name, count)
1661                 else:
1662                     body += "    free_{0}_array(in->{1}, {2});\n".format(m.type, m.name, count)
1664         body += "}\n\n"
1665         return body
1667     def definition(self):
1668         if self.dyn_array:
1669             return self._generate_array_free_func()
1670         else:
1671             # Some structures need freeing too if they contain dynamic arrays.
1672             # E.g. VkCommandBufferBeginInfo
1673             return self._generate_free_func()
1676 class VkGenerator(object):
1677     def __init__(self, registry):
1678         self.registry = registry
1680         # Build a list conversion functions for struct conversion.
1681         self.conversions = []
1682         self.host_structs = []
1683         for func in self.registry.funcs.values():
1684             if not func.is_required():
1685                 continue
1687             if not func.needs_conversion():
1688                 continue
1690             conversions = func.get_conversions()
1691             for conv in conversions:
1692                 # Pull in any conversions for vulkan_thunks.c. Driver conversions we
1693                 # handle manually in vulkan.c if needed.
1694                 if not func.is_driver_func():
1695                     # Append if we don't already have this conversion.
1696                     if not any(c == conv for c in self.conversions):
1697                         self.conversions.append(conv)
1699                 # Structs can be used in different ways by different conversions
1700                 # e.g. array vs non-array. Just make sure we pull in each struct once.
1701                 if not any(s.name == conv.struct.name for s in self.host_structs):
1702                     self.host_structs.append(conv.struct)
1704     def generate_thunks_c(self, f, prefix):
1705         f.write("/* Automatically generated from Vulkan vk.xml; DO NOT EDIT! */\n\n")
1707         f.write("#include \"config.h\"\n")
1708         f.write("#include \"wine/port.h\"\n\n")
1710         f.write("#include \"wine/debug.h\"\n")
1711         f.write("#include \"wine/heap.h\"\n")
1712         f.write("#include \"wine/vulkan.h\"\n")
1713         f.write("#include \"wine/vulkan_driver.h\"\n")
1714         f.write("#include \"vulkan_private.h\"\n\n")
1716         f.write("WINE_DEFAULT_DEBUG_CHANNEL(vulkan);\n\n")
1718         # Generate any conversion helper functions.
1719         f.write("#if defined(USE_STRUCT_CONVERSION)\n")
1720         for conv in self.conversions:
1721             f.write(conv.definition())
1722         f.write("#endif /* USE_STRUCT_CONVERSION */\n\n")
1724         # Create thunks for instance and device functions.
1725         # Global functions don't go through the thunks.
1726         for vk_func in self.registry.funcs.values():
1727             if not vk_func.is_required():
1728                 continue
1730             if vk_func.is_global_func():
1731                 continue
1733             if not vk_func.needs_thunk():
1734                 continue
1736             f.write("static " + vk_func.thunk(prefix=prefix, call_conv="WINAPI"))
1738         f.write("static const struct vulkan_func vk_device_dispatch_table[] =\n{\n")
1739         for vk_func in self.registry.device_funcs:
1740             if not vk_func.is_required():
1741                 continue
1743             if not vk_func.needs_dispatch():
1744                 LOGGER.debug("skipping {0} in device dispatch table".format(vk_func.name))
1745                 continue
1747             f.write("    {{\"{0}\", &{1}{0}}},\n".format(vk_func.name, prefix))
1748         f.write("};\n\n")
1750         f.write("static const struct vulkan_func vk_instance_dispatch_table[] =\n{\n")
1751         for vk_func in self.registry.instance_funcs:
1752             if not vk_func.is_required():
1753                 continue
1755             if not vk_func.needs_dispatch():
1756                 LOGGER.debug("skipping {0} in instance dispatch table".format(vk_func.name))
1757                 continue
1759             f.write("    {{\"{0}\", &{1}{0}}},\n".format(vk_func.name, prefix))
1760         f.write("};\n\n")
1762         f.write("void *wine_vk_get_device_proc_addr(const char *name)\n")
1763         f.write("{\n")
1764         f.write("    unsigned int i;\n")
1765         f.write("    for (i = 0; i < ARRAY_SIZE(vk_device_dispatch_table); i++)\n")
1766         f.write("    {\n")
1767         f.write("        if (strcmp(vk_device_dispatch_table[i].name, name) == 0)\n")
1768         f.write("        {\n")
1769         f.write("            TRACE(\"Found name=%s in device table\\n\", name);\n")
1770         f.write("            return vk_device_dispatch_table[i].func;\n")
1771         f.write("        }\n")
1772         f.write("    }\n")
1773         f.write("    return NULL;\n")
1774         f.write("}\n\n")
1776         f.write("void *wine_vk_get_instance_proc_addr(const char *name)\n")
1777         f.write("{\n")
1778         f.write("    unsigned int i;\n")
1779         f.write("    for (i = 0; i < ARRAY_SIZE(vk_instance_dispatch_table); i++)\n")
1780         f.write("    {\n")
1781         f.write("        if (strcmp(vk_instance_dispatch_table[i].name, name) == 0)\n")
1782         f.write("        {\n")
1783         f.write("            TRACE(\"Found name=%s in instance table\\n\", name);\n")
1784         f.write("            return vk_instance_dispatch_table[i].func;\n")
1785         f.write("        }\n")
1786         f.write("    }\n")
1787         f.write("    return NULL;\n")
1788         f.write("}\n\n")
1790         # Create array of device extensions.
1791         f.write("static const char * const vk_device_extensions[] =\n{\n")
1792         for ext in self.registry.extensions:
1793             if ext["type"] != "device":
1794                 continue
1796             f.write("    \"{0}\",\n".format(ext["name"]))
1797         f.write("};\n\n")
1799         f.write("BOOL wine_vk_device_extension_supported(const char *name)\n")
1800         f.write("{\n")
1801         f.write("    unsigned int i;\n")
1802         f.write("    for (i = 0; i < ARRAY_SIZE(vk_device_extensions); i++)\n")
1803         f.write("    {\n")
1804         f.write("        if (strcmp(vk_device_extensions[i], name) == 0)\n")
1805         f.write("            return TRUE;\n")
1806         f.write("    }\n")
1807         f.write("    return FALSE;\n")
1808         f.write("}\n")
1810     def generate_thunks_h(self, f, prefix):
1811         f.write("/* Automatically generated from Vulkan vk.xml; DO NOT EDIT! */\n\n")
1813         f.write("#ifndef __WINE_VULKAN_THUNKS_H\n")
1814         f.write("#define __WINE_VULKAN_THUNKS_H\n\n")
1816         f.write("/* Perform vulkan struct conversion on 32-bit x86 platforms. */\n")
1817         f.write("#if defined(__i386__)\n")
1818         f.write("#define USE_STRUCT_CONVERSION\n")
1819         f.write("#endif\n\n")
1821         f.write("/* For use by vk_icdGetInstanceProcAddr / vkGetInstanceProcAddr */\n")
1822         f.write("void *wine_vk_get_device_proc_addr(const char *name) DECLSPEC_HIDDEN;\n")
1823         f.write("void *wine_vk_get_instance_proc_addr(const char *name) DECLSPEC_HIDDEN;\n\n")
1825         f.write("BOOL wine_vk_device_extension_supported(const char *name) DECLSPEC_HIDDEN;\n\n")
1827         # Generate prototypes for device and instance functions requiring a custom implementation.
1828         f.write("/* Functions for which we have custom implementations outside of the thunks. */\n")
1829         for vk_func in self.registry.funcs.values():
1830             if not vk_func.is_required() or vk_func.is_global_func() or vk_func.needs_thunk():
1831                 continue
1833             f.write("{0};\n".format(vk_func.prototype("WINAPI", prefix="wine_", postfix="DECLSPEC_HIDDEN")))
1834         f.write("\n")
1836         for struct in self.host_structs:
1837             f.write(struct.definition(align=False, conv=True, postfix="_host"))
1838         f.write("\n")
1840         f.write("/* For use by vkDevice and children */\n")
1841         f.write("struct vulkan_device_funcs\n{\n")
1842         for vk_func in self.registry.device_funcs:
1843             if not vk_func.is_required():
1844                 continue
1846             if not vk_func.needs_dispatch() or vk_func.is_driver_func():
1847                 LOGGER.debug("skipping {0} in vulkan_device_funcs".format(vk_func.name))
1848                 continue
1850             if vk_func.needs_conversion():
1851                 f.write("#if defined(USE_STRUCT_CONVERSION)\n")
1852                 f.write("    {0};\n".format(vk_func.pfn(conv=True)))
1853                 f.write("#else\n")
1854                 f.write("    {0};\n".format(vk_func.pfn(conv=False)))
1855                 f.write("#endif\n")
1856             else:
1857                 f.write("    {0};\n".format(vk_func.pfn(conv=False)))
1858         f.write("};\n\n")
1860         f.write("/* For use by vkInstance and children */\n")
1861         f.write("struct vulkan_instance_funcs\n{\n")
1862         for vk_func in self.registry.instance_funcs:
1863             if not vk_func.is_required():
1864                 continue
1866             if not vk_func.needs_dispatch() or vk_func.is_driver_func():
1867                 LOGGER.debug("skipping {0} in vulkan_instance_funcs".format(vk_func.name))
1868                 continue
1870             if vk_func.needs_conversion():
1871                 f.write("#if defined(USE_STRUCT_CONVERSION)\n")
1872                 f.write("    {0};\n".format(vk_func.pfn(conv=True)))
1873                 f.write("#else\n")
1874                 f.write("    {0};\n".format(vk_func.pfn(conv=False)))
1875                 f.write("#endif\n")
1876             else:
1877                 f.write("    {0};\n".format(vk_func.pfn(conv=False)))
1878         f.write("};\n\n")
1880         f.write("#define ALL_VK_DEVICE_FUNCS() \\\n")
1881         first = True
1882         for vk_func in self.registry.device_funcs:
1883             if not vk_func.is_required():
1884                 continue
1886             if not vk_func.needs_dispatch() or vk_func.is_driver_func():
1887                 LOGGER.debug("skipping {0} in ALL_VK_DEVICE_FUNCS".format(vk_func.name))
1888                 continue
1890             if first:
1891                 f.write("    USE_VK_FUNC({0})".format(vk_func.name))
1892                 first = False
1893             else:
1894                 f.write(" \\\n    USE_VK_FUNC({0})".format(vk_func.name))
1895         f.write("\n\n")
1897         f.write("#define ALL_VK_INSTANCE_FUNCS() \\\n")
1898         first = True
1899         for vk_func in self.registry.instance_funcs:
1900             if not vk_func.is_required():
1901                 continue
1903             if not vk_func.needs_dispatch() or vk_func.is_driver_func():
1904                 LOGGER.debug("skipping {0} in ALL_VK_INSTANCE_FUNCS".format(vk_func.name))
1905                 continue
1907             if first:
1908                 f.write("    USE_VK_FUNC({0})".format(vk_func.name))
1909                 first = False
1910             else:
1911                 f.write("\\\n    USE_VK_FUNC({0})".format(vk_func.name))
1912         f.write("\n\n")
1914         f.write("#endif /* __WINE_VULKAN_THUNKS_H */\n")
1916     def generate_vulkan_h(self, f):
1917         f.write("/* Automatically generated from Vulkan vk.xml; DO NOT EDIT! */\n\n")
1918         f.write("#ifndef __WINE_VULKAN_H\n")
1919         f.write("#define __WINE_VULKAN_H\n\n")
1921         f.write("#include <windef.h>\n")
1922         f.write("#include <stdint.h>\n\n")
1924         f.write("#ifndef VKAPI_CALL\n")
1925         f.write("#define VKAPI_CALL __stdcall\n")
1926         f.write("#endif\n\n")
1928         f.write("#ifndef VKAPI_PTR\n")
1929         f.write("#define VKAPI_PTR VKAPI_CALL\n")
1930         f.write("#endif\n\n")
1932         f.write("/* Callers can override WINE_VK_ALIGN if they want 'host' headers. */\n")
1933         f.write("#ifndef WINE_VK_ALIGN\n")
1934         f.write("#define WINE_VK_ALIGN DECLSPEC_ALIGN\n")
1935         f.write("#endif\n\n")
1937         # The overall strategy is to define independent constants and datatypes,
1938         # prior to complex structures and function calls to avoid forward declarations.
1939         for const in self.registry.consts:
1940             # For now just generate things we may not need. The amount of parsing needed
1941             # to get some of the info is tricky as you need to figure out which structure
1942             # references a certain constant.
1943             f.write(const.definition())
1944         f.write("\n")
1946         for define in self.registry.defines:
1947             f.write(define.definition())
1949         for handle in self.registry.handles:
1950             if handle.required:
1951                  f.write(handle.definition())
1952         f.write("\n")
1954         for base_type in self.registry.base_types:
1955             f.write(base_type.definition())
1956         f.write("\n")
1958         for bitmask in self.registry.bitmasks:
1959             f.write(bitmask.definition())
1960         f.write("\n")
1962         # Define enums, this includes values for some of the bitmask types as well.
1963         for enum in self.registry.enums.values():
1964             if enum.required:
1965                 f.write(enum.definition())
1967         for fp in self.registry.funcpointers:
1968             if fp.required:
1969                 f.write(fp.definition())
1970         f.write("\n")
1972         # This generates both structures and unions. Since structures
1973         # may depend on other structures/unions, we need a list of
1974         # decoupled structs.
1975         # Note: unions are stored in structs for dependency reasons,
1976         # see comment in parsing section.
1977         structs = VkStruct.decouple_structs(self.registry.structs)
1978         for struct in structs:
1979             LOGGER.debug("Generating struct: {0}".format(struct.name))
1980             f.write(struct.definition(align=True))
1982         for func in self.registry.funcs.values():
1983             if not func.is_required():
1984                 LOGGER.debug("Skipping API definition for: {0}".format(func.name))
1985                 continue
1987             LOGGER.debug("Generating API definition for: {0}".format(func.name))
1988             f.write("{0};\n".format(func.prototype(call_conv="VKAPI_CALL")))
1989         f.write("\n")
1991         f.write("#endif /* __WINE_VULKAN_H */\n")
1993     def generate_vulkan_driver_h(self, f):
1994         f.write("/* Automatically generated from Vulkan vk.xml; DO NOT EDIT! */\n\n")
1995         f.write("#ifndef __WINE_VULKAN_DRIVER_H\n")
1996         f.write("#define __WINE_VULKAN_DRIVER_H\n\n")
1998         f.write("/* Wine internal vulkan driver version, needs to be bumped upon vulkan_funcs changes. */\n")
1999         f.write("#define WINE_VULKAN_DRIVER_VERSION {0}\n\n".format(DRIVER_VERSION))
2001         f.write("struct vulkan_funcs\n{\n")
2002         f.write("    /* Vulkan global functions. These are the only calls at this point a graphics driver\n")
2003         f.write("     * needs to provide. Other function calls will be provided indirectly by dispatch\n")
2004         f.write("     * tables part of dispatchable Vulkan objects such as VkInstance or vkDevice.\n")
2005         f.write("     */\n")
2007         for vk_func in self.registry.funcs.values():
2008             if not vk_func.is_required() or not vk_func.is_driver_func():
2009                 continue
2011             pfn = vk_func.pfn()
2012             # Avoid PFN_vkVoidFunction in driver interface as Vulkan likes to put calling convention
2013             # stuff in there. For simplicity substitute with "void *".
2014             pfn = pfn.replace("PFN_vkVoidFunction", "void *")
2015             f.write("    {0};\n".format(pfn))
2016         f.write("};\n\n")
2018         f.write("extern const struct vulkan_funcs * CDECL __wine_get_vulkan_driver(HDC hdc, UINT version);\n\n")
2019         f.write("#endif /* __WINE_VULKAN_DRIVER_H */\n")
2022 class VkRegistry(object):
2023     def __init__(self, reg_filename):
2024         # Used for storage of type information.
2025         self.base_types = None
2026         self.bitmasks = None
2027         self.consts = None
2028         self.defines = None
2029         self.enums = None
2030         self.funcpointers = None
2031         self.handles = None
2032         self.structs = None
2034         # We aggregate all types in here for cross-referencing.
2035         self.funcs = {}
2036         self.types = {}
2038         # Overall strategy for parsing the registry is to first
2039         # parse all type / function definitions. Then parse
2040         # features and extensions to decide which types / functions
2041         # to actually 'pull in' for code generation. For each type or
2042         # function call we want we set a member 'required' to True.
2043         tree = ET.parse(reg_filename)
2044         root = tree.getroot()
2045         self._parse_enums(root)
2046         self._parse_types(root)
2047         self._parse_commands(root)
2049         # Pull in any required types and functions.
2050         self._parse_features(root)
2051         self._parse_extensions(root)
2053     def _mark_command_required(self, command):
2054         """ Helper function to mark a certain command and the datatypes it needs as required."""
2055         def mark_bitmask_dependencies(bitmask, types):
2056             if bitmask.requires is not None:
2057                 types[bitmask.requires]["data"].required = True
2059         def mark_funcpointer_dependencies(fp, types):
2060             for m in fp.members:
2061                 type_info = types[m.type]
2063                 # Complex types have a matching definition e.g. VkStruct.
2064                 # Not needed for base types such as uint32_t.
2065                 if "data" in type_info:
2066                     types[m.type]["data"].required = True
2068         def mark_struct_dependencies(struct, types):
2069              for m in struct:
2070                 type_info = types[m.type]
2072                 # Complex types have a matching definition e.g. VkStruct.
2073                 # Not needed for base types such as uint32_t.
2074                 if "data" in type_info:
2075                     types[m.type]["data"].required = True
2077                 if type_info["category"] == "struct":
2078                     # Yay, recurse
2079                     mark_struct_dependencies(type_info["data"], types)
2080                 elif type_info["category"] == "funcpointer":
2081                     mark_funcpointer_dependencies(type_info["data"], types)
2082                 elif type_info["category"] == "bitmask":
2083                     mark_bitmask_dependencies(type_info["data"], types)
2085         func = self.funcs[command]
2086         func.required = True
2088         # Pull in return type
2089         if func.type != "void":
2090             self.types[func.type]["data"].required = True
2092         # Analyze parameter dependencies and pull in any type needed.
2093         for p in func.params:
2094             type_info = self.types[p.type]
2096             # Check if we are dealing with a complex type e.g. VkEnum, VkStruct and others.
2097             if "data" not in type_info:
2098                 continue
2100             # Mark the complex type as required.
2101             type_info["data"].required = True
2102             if type_info["category"] == "struct":
2103                 struct = type_info["data"]
2104                 mark_struct_dependencies(struct, self.types)
2106     def _parse_commands(self, root):
2107         """ Parse command section containing the Vulkan function calls. """
2108         funcs = {}
2109         commands = root.findall("./commands/")
2110         for command in commands:
2111             func = VkFunction.from_xml(command, self.types)
2112             funcs[func.name] = func
2114         # To make life easy for the code generation, separate all function
2115         # calls out in the 3 types of vulkan functions: device, global and instance.
2116         device_funcs = []
2117         global_funcs = []
2118         instance_funcs = []
2119         for func in funcs.values():
2120             if func.is_device_func():
2121                 device_funcs.append(func)
2122             elif func.is_global_func():
2123                 global_funcs.append(func)
2124             else:
2125                 instance_funcs.append(func)
2127         # Sort function lists by name and store them.
2128         self.device_funcs = sorted(device_funcs, key=lambda func: func.name)
2129         self.global_funcs = sorted(global_funcs, key=lambda func: func.name)
2130         self.instance_funcs = sorted(instance_funcs, key=lambda func: func.name)
2132         # The funcs dictionary is used as a convenient way to lookup function
2133         # calls when needed e.g. to adjust member variables.
2134         self.funcs = OrderedDict(sorted(funcs.items()))
2136     def _parse_enums(self, root):
2137         """ Parse enums section or better described as constants section. """
2138         enums = {}
2139         self.consts = []
2140         for enum in root.findall("./enums"):
2141             name = enum.attrib.get("name")
2142             _type = enum.attrib.get("type")
2144             if _type in ("enum", "bitmask"):
2145                 enums[name] = VkEnum.from_xml(enum)
2146             else:
2147                 # If no type is set, we are dealing with API constants.
2148                 values = []
2149                 for value in enum.findall("enum"):
2150                     self.consts.append(VkConstant(value.attrib.get("name"), value.attrib.get("value")))
2152         self.enums = OrderedDict(sorted(enums.items()))
2154     def _parse_extensions(self, root):
2155         """ Parse extensions section and pull in any types and commands for this extensioin. """
2156         extensions = []
2157         exts = root.findall("./extensions/extension")
2158         for ext in exts:
2159             ext_name = ext.attrib["name"]
2161             # Some extensions are not ready or have numbers reserved as a place holder.
2162             if ext.attrib["supported"] == "disabled":
2163                 LOGGER.debug("Skipping disabled extension: {0}".format(ext_name))
2164                 continue
2166             # We only support a handful of extensions for now through a whitelist.
2167             if ext_name not in SUPPORTED_EXTENSIONS:
2168                 LOGGER.debug("Skipping blacklisted extension: {0}".format(ext_name))
2169                 continue
2171             LOGGER.debug("Loading extension: {0}".format(ext_name))
2173             # Extensions can add enum values to Core / extension enums, so add these.
2174             enums = ext.findall("require/enum")
2175             for enum_elem in enums:
2176                 if "bitpos" in enum_elem.keys():
2177                     # We need to add an extra value to an existing enum type.
2178                     # E.g. VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG to VkFormatFeatureFlagBits.
2179                     type_name = enum_elem.attrib["extends"]
2180                     enum = self.types[type_name]["data"]
2181                     enum.add(VkEnumValue(enum_elem.attrib["name"], 1 << int(enum_elem.attrib["bitpos"]), hex=True))
2182                 elif "offset" in enum_elem.keys():
2183                     ext_number = int(ext.attrib["number"])
2184                     offset = int(enum_elem.attrib["offset"])
2185                     value = EXT_BASE + (ext_number - 1) * EXT_BLOCK_SIZE + offset
2187                     # Deal with negative values.
2188                     direction = enum_elem.attrib.get("dir")
2189                     if direction is not None:
2190                         value = -value
2192                     type_name = enum_elem.attrib["extends"]
2193                     enum = self.types[type_name]["data"]
2194                     enum.add(VkEnumValue(enum_elem.attrib["name"], value))
2196                 elif "value" in enum_elem.keys():
2197                     # For now skip, it mostly contains extension name and version info.
2198                     continue
2199                 else:
2200                     # This seems to be used to pull in constants e.g. VK_MAX_DEVICE_GROUP_KHX
2201                     continue
2203             # Store a list with extensions.
2204             ext_type = ext.attrib["type"]
2205             ext_info = {"name" : ext_name, "type" : ext_type}
2206             extensions.append(ext_info)
2208             commands = ext.findall("require/command")
2209             if not commands:
2210                 continue
2212             # Pull in any commands we need. We infer types to pull in from the command
2213             # as well.
2214             for command in commands:
2215                 cmd_name = command.attrib["name"]
2216                 self._mark_command_required(cmd_name)
2218                 # Set extension name on the function call as we were not aware of the
2219                 # name during initial parsing.
2220                 self.funcs[cmd_name].extension = ext_name
2222         # Sort in alphabetical order.
2223         self.extensions = sorted(extensions, key=lambda ext: ext["name"])
2225     def _parse_features(self, root):
2226         """ Parse the feature section, which describes Core commands and types needed. """
2227         requires = root.findall("./feature/require")
2229         for require in requires:
2230             LOGGER.info("Including features for {0}".format(require.attrib.get("comment")))
2231             for tag in require:
2232                 # Only deal with command. Other values which appear are enum and type for pulling in some
2233                 # constants and macros. Tricky to parse, so don't bother right now, we will generate them
2234                 # anyway for now.
2235                 name = tag.attrib["name"]
2236                 if tag.tag == "command":
2237                     self._mark_command_required(name)
2238                 elif tag.tag == "enum":
2239                     # We could pull in relevant constants here. Unfortunately
2240                     # this only gets half of them pulled in as others indirectly
2241                     # get pulled in through structures. Constants don't harm us,
2242                     # so don't bother.
2243                     pass
2244                 elif tag.tag == "type":
2245                     # Pull in types which may not have been pulled in through commands.
2247                     # Skip pull in for vk_platform.h for now.
2248                     if name == "vk_platform":
2249                         continue
2251                     type_info = self.types[name]
2252                     type_info["data"].required = True
2254     def _parse_types(self, root):
2255         """ Parse types section, which contains all data types e.g. structs, typedefs etcetera. """
2256         types = root.findall("./types/type")
2258         base_types = []
2259         bitmasks = []
2260         defines = []
2261         funcpointers = []
2262         handles = []
2263         structs = []
2265         for t in types:
2266             type_info = {}
2267             type_info["category"] = t.attrib.get("category", None)
2269             if type_info["category"] in ["include"]:
2270                 continue
2272             if type_info["category"] == "basetype":
2273                 name = t.find("name").text
2274                 _type = t.find("type").text
2275                 basetype = VkBaseType(name, _type)
2276                 base_types.append(basetype)
2277                 type_info["data"] = basetype
2279             if type_info["category"] == "bitmask":
2280                 name = t.find("name").text
2281                 _type = t.find("type").text
2283                 # Most bitmasks have a requires attribute used to pull in
2284                 # required '*FlagBits" enum.
2285                 requires = t.attrib.get("requires")
2286                 bitmask = VkBaseType(name, _type, requires=requires)
2287                 bitmasks.append(bitmask)
2288                 type_info["data"] = bitmask
2290             if type_info["category"] == "define":
2291                 name = t.attrib.get("name")
2292                 define = VkDefine.from_xml(t)
2293                 defines.append(define)
2294                 type_info["data"] = define
2296             if type_info["category"] == "enum":
2297                 name = t.attrib.get("name")
2298                 # The type section only contains enum names, not the actual definition.
2299                 # Since we already parsed the enum before, just link it in.
2300                 try:
2301                     type_info["data"] = self.enums[name]
2302                 except KeyError as e:
2303                     # Not all enums seem to be defined yet, typically that's for
2304                     # ones ending in 'FlagBits' where future extensions may add
2305                     # definitions.
2306                     type_info["data"] = None
2308             if type_info["category"] == "funcpointer":
2309                 funcpointer = VkFunctionPointer.from_xml(t)
2310                 funcpointers.append(funcpointer)
2311                 type_info["data"] = funcpointer
2313             if type_info["category"] == "handle":
2314                 handle = VkHandle.from_xml(t)
2315                 handles.append(handle)
2316                 type_info["data"] = handle
2318             if type_info["category"] in ["struct", "union"]:
2319                 # We store unions among structs as some structs depend
2320                 # on unions. The types are very similar in parsing and
2321                 # generation anyway. The official vulkan scripts use
2322                 # a similar kind of hack.
2323                 struct = VkStruct.from_xml(t)
2324                 structs.append(struct)
2325                 type_info["data"] = struct
2327             # Name is in general within a name tag else it is an optional
2328             # attribute on the type tag.
2329             name_elem = t.find("name")
2330             if name_elem is not None:
2331                 type_info["name"] = name_elem.text
2332             else:
2333                 type_info["name"] = t.attrib.get("name", None)
2335             # Store all type data in a shared dictionary, so we can easily
2336             # look up information for a given type. There are no duplicate
2337             # names.
2338             self.types[type_info["name"]] = type_info
2340         # We need detailed type information during code generation
2341         # on structs for alignment reasons. Unfortunately structs
2342         # are parsed among other types, so there is no guarantee
2343         # that any types needed have been parsed already, so set
2344         # the data now.
2345         for struct in structs:
2346             struct.set_type_info(self.types)
2348         # Guarantee everything is sorted, so code generation doesn't have
2349         # to deal with this.
2350         self.base_types = sorted(base_types, key=lambda base_type: base_type.name)
2351         self.bitmasks = sorted(bitmasks, key=lambda bitmask: bitmask.name)
2352         self.defines = defines
2353         self.funcpointers = sorted(funcpointers, key=lambda fp: fp.name)
2354         self.handles = sorted(handles, key=lambda handle: handle.name)
2355         self.structs = sorted(structs, key=lambda struct: struct.name)
2358 def main():
2359     parser = argparse.ArgumentParser()
2360     parser.add_argument("-v", "--verbose", action="count", default=0, help="increase output verbosity")
2362     args = parser.parse_args()
2363     if args.verbose == 0:
2364         LOGGER.setLevel(logging.WARNING)
2365     elif args.verbose == 1:
2366         LOGGER.setLevel(logging.INFO)
2367     else: # > 1
2368         LOGGER.setLevel(logging.DEBUG)
2370     registry = VkRegistry("vk.xml")
2371     generator = VkGenerator(registry)
2373     with open(WINE_VULKAN_H, "w") as f:
2374         generator.generate_vulkan_h(f)
2376     with open(WINE_VULKAN_DRIVER_H, "w") as f:
2377         generator.generate_vulkan_driver_h(f)
2379     with open(WINE_VULKAN_THUNKS_H, "w") as f:
2380         generator.generate_thunks_h(f, "wine_")
2382     with open(WINE_VULKAN_THUNKS_C, "w") as f:
2383         generator.generate_thunks_c(f, "wine_")
2385 if __name__ == "__main__":
2386     main()