winevulkan: Tweak the wording of a comment.
[wine.git] / dlls / winevulkan / make_vulkan
blobf0583b4003854a6cfd95505c699d34f70ad85a12
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_LOADER_SPEC = "../vulkan-1/vulkan-1.spec"
69 WINE_VULKAN_SPEC = "winevulkan.spec"
70 WINE_VULKAN_THUNKS_C = "vulkan_thunks.c"
71 WINE_VULKAN_THUNKS_H = "vulkan_thunks.h"
73 # Extension enum values start at a certain offset (EXT_BASE).
74 # Relative to the offset each extension has a block (EXT_BLOCK_SIZE)
75 # of values.
76 # Start for a given extension is:
77 # EXT_BASE + (extension_number-1) * EXT_BLOCK_SIZE
78 EXT_BASE = 1000000000
79 EXT_BLOCK_SIZE = 1000
81 # In general instance extensions can't be automatically generated
82 # and need custom wrappers due to e.g. win32 / X11 specific code.
83 # List of supported instance extensions.
84 SUPPORTED_INSTANCE_EXTENSIONS = [
85     "VK_KHR_get_physical_device_properties2",
86     "VK_KHR_surface",
87     "VK_KHR_win32_surface",
90 BLACKLISTED_EXTENSIONS = [
91     # Handling of VK_EXT_debug_report requires some consideration. The win32
92     # loader already provides it for us and it is somewhat usable. . If we add
93     # plumbing down to the native layer, we will get each message twice as we
94     # use 2 loaders (win32+native), but we may get output from the driver.
95     # In any case callback conversion is required.
96     "VK_EXT_debug_report",
97     "VK_EXT_display_control", # Requires VK_EXT_display_surface_counter
98     "VK_EXT_hdr_metadata", # Needs WSI work.
99     "VK_GOOGLE_display_timing",
100     "VK_KHR_display", # Needs WSI work.
101     "VK_KHR_external_fence_fd",
102     "VK_KHR_external_fence_win32",
103     "VK_KHR_external_memory",
104     "VK_KHR_external_semaphore",
105     # Relates to external_semaphore and needs type conversions in bitflags.
106     "VK_KHR_external_semaphore_capabilities",
107     "VK_KHR_shared_presentable_image", # Needs WSI work.
108     "VK_NV_external_memory_win32"
111 # The Vulkan loader provides entry-points for core functionality and important
112 # extensions. Based on vulkan-1.def this amounts to WSI extensions on 1.0.51.
113 CORE_EXTENSIONS = [
114     "VK_KHR_display",
115     "VK_KHR_display_swapchain",
116     "VK_KHR_surface",
117     "VK_KHR_swapchain",
118     "VK_KHR_win32_surface"
121 # Functions part of our winevulkan graphics driver interface.
122 # DRIVER_VERSION should be bumped on any change to driver interface
123 # in FUNCTION_OVERRIDES
124 DRIVER_VERSION = 3
126 # Table of functions for which we have a special implementation.
127 # These are regular device / instance functions for which we need
128 # to do more work compared to a regular thunk or because they are
129 # part of the driver interface.
130 # - dispatch set whether we need a function pointer in the device
131 #   / instance dispatch table.
132 # - driver sets whether the API is part of the driver interface.
133 # - thunk sets whether to create a thunk in vulkan_thunks.c.
134 FUNCTION_OVERRIDES = {
135     # Global functions
136     "vkCreateInstance" : {"dispatch" : False, "driver" : True, "thunk" : False},
137     "vkEnumerateInstanceExtensionProperties" : {"dispatch" : False, "driver" : True, "thunk" : False},
138     "vkGetInstanceProcAddr": {"dispatch" : False, "driver" : True, "thunk" : False},
140     # Instance functions
141     "vkCreateDevice" : {"dispatch" : True, "driver" : False, "thunk" : False},
142     "vkDestroyInstance" : {"dispatch" : False, "driver" : True, "thunk" : False },
143     "vkEnumerateDeviceExtensionProperties" : {"dispatch" : True, "driver" : False, "thunk" : False},
144     "vkEnumeratePhysicalDevices" : {"dispatch" : True, "driver" : False, "thunk" : False},
146     # Device functions
147     "vkAllocateCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : False},
148     "vkCmdExecuteCommands" : {"dispatch" : True, "driver" : False, "thunk" : False},
149     "vkDestroyDevice" : {"dispatch" : True, "driver" : False, "thunk" : False},
150     "vkFreeCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : False},
151     "vkGetDeviceProcAddr" : {"dispatch" : False, "driver" : True, "thunk" : False},
152     "vkGetDeviceQueue" : {"dispatch": True, "driver" : False, "thunk" : False},
153     "vkQueueSubmit" : {"dispatch": True, "driver" : False, "thunk" : False},
155     # VK_KHR_surface
156     "vkDestroySurfaceKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
157     "vkGetPhysicalDeviceSurfaceSupportKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
158     "vkGetPhysicalDeviceSurfaceCapabilitiesKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
159     "vkGetPhysicalDeviceSurfaceFormatsKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
160     "vkGetPhysicalDeviceSurfacePresentModesKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
162     # VK_KHR_win32_surface
163     "vkCreateWin32SurfaceKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
164     "vkGetPhysicalDeviceWin32PresentationSupportKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
166     # VK_KHR_swapchain
167     "vkAcquireNextImageKHR": {"dispatch" : True, "driver" : True, "thunk" : True},
168     "vkCreateSwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
169     "vkDestroySwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
170     "vkGetSwapchainImagesKHR": {"dispatch" : True, "driver" : True, "thunk" : True},
171     "vkQueuePresentKHR": {"dispatch" : True, "driver" : True, "thunk" : True},
175 class Direction(Enum):
176     """ Parameter direction: input, output, input_output. """
177     INPUT = 1
178     OUTPUT = 2
179     INPUT_OUTPUT = 3
182 class VkBaseType(object):
183     def __init__(self, name, _type, requires=None):
184         """ Vulkan base type class.
186         VkBaseType is mostly used by Vulkan to define its own
187         base types like VkFlags through typedef out of e.g. uint32_t.
189         Args:
190             name (:obj:'str'): Name of the base type.
191             _type (:obj:'str'): Underlaying type
192             requires (:obj:'str', optional): Other types required.
193                 Often bitmask values pull in a *FlagBits type.
194         """
195         self.name = name
196         self.type = _type
197         self.requires = requires
198         self.required = False
200     def definition(self):
201         text = "typedef {0} {1};\n".format(self.type, self.name)
202         return text
205 class VkConstant(object):
206     def __init__(self, name, value):
207         self.name = name
208         self.value = value
210     def definition(self):
211         text = "#define {0} {1}\n".format(self.name, self.value)
212         return text
215 class VkDefine(object):
216     def __init__(self, name, value):
217         self.name = name
218         self.value = value
220     @staticmethod
221     def from_xml(define):
222         name_elem = define.find("name")
224         if name_elem is None:
225             # <type category="define" name="some_name">some_value</type>
226             # At the time of writing there is only 1 define of this category
227             # 'VK_DEFINE_NON_DISPATCHABLE_HANDLE'.
228             name = define.attrib.get("name")
230             # We override behavior of VK_DEFINE_NON_DISPATCHABLE handle as the default
231             # definition various between 64-bit (uses pointers) and 32-bit (uses uint64_t).
232             # This complicates TRACEs in the thunks, so just use uint64_t.
233             if name == "VK_DEFINE_NON_DISPATCHABLE_HANDLE":
234                 value = "#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object;"
235             else:
236                 value = define.text
237             return VkDefine(name, value)
239         # With a name element the structure is like:
240         # <type category="define"><name>some_name</name>some_value</type>
241         name = name_elem.text
243         # VK_API_VERSION is a deprecated constant and we don't really want to parse it or generate
244         # code for it. However the vk.xml feature section still references it.
245         if name == "VK_API_VERSION":
246             return VkDefine(name, "")
248         # The body of the define is basically unstructured C code. It is not meant for easy parsing.
249         # Some lines contain deprecated values or comments, which we try to filter out.
250         value = ""
251         for line in define.text.splitlines():
252             # Skip comments or deprecated values.
253             if "//" in line:
254                 continue
255             value += line
257         for child in define:
258             value += child.text
259             if child.tail is not None:
260                 value += child.tail
262         return VkDefine(name, value.rstrip(' '))
264     def definition(self):
265         if self.value is None:
266             return ""
268         # Nothing to do as the value was already put in the right form during parsing.
269         return "{0}\n".format(self.value)
272 class VkEnum(object):
273     def __init__(self, name, values):
274         self.name = name
275         self.values = values
276         self.required = False
278     @staticmethod
279     def from_xml(enum):
280         name = enum.attrib.get("name")
281         values = []
283         for v in enum.findall("enum"):
284             # Value is either a value or a bitpos, only one can exist.
285             value = v.attrib.get("value")
286             if value is None:
287                 # bitmask
288                 value = 1 << int(v.attrib.get("bitpos"))
289                 values.append(VkEnumValue(v.attrib.get("name"), value, hex=True))
290             else:
291                 # Some values are in hex form. We want to preserve the hex representation
292                 # at least when we convert back to a string. Internally we want to use int.
293                 if "0x" in value:
294                     values.append(VkEnumValue(v.attrib.get("name"), int(value, 0), hex=True))
295                 else:
296                     values.append(VkEnumValue(v.attrib.get("name"), int(value, 0)))
298         # vulkan.h contains a *_MAX_ENUM value set to 32-bit at the time of writing,
299         # which is to prepare for extensions as they can add values and hence affect
300         # the size definition.
301         max_name = re.sub(r'([0-9a-z_])([A-Z0-9])',r'\1_\2',name).upper() + "_MAX_ENUM"
302         values.append(VkEnumValue(max_name, 0x7fffffff, hex=True))
304         return VkEnum(name, values)
306     def add(self, value):
307         """ Add a value to enum. """
308         self.values.append(value)
310     def definition(self):
311         text = "typedef enum {0}\n{{\n".format(self.name)
313         # Print values sorted, values can have been added in a random order.
314         values = sorted(self.values, key=lambda value: value.value)
315         for value in values:
316             text += "    {0},\n".format(value.definition())
317         text += "}} {0};\n\n".format(self.name)
318         return text
321 class VkEnumValue(object):
322     def __init__(self, name, value, hex=False):
323         self.name = name
324         self.value = value
325         self.hex = hex
327     def __repr__(self):
328         return "{0}={1}".format(self.name, self.value)
330     def definition(self):
331         """ Convert to text definition e.g. VK_FOO = 1 """
333         # Hex is commonly used for FlagBits and sometimes within
334         # a non-FlagBits enum for a bitmask value as well.
335         if self.hex:
336             return "{0} = 0x{1:08x}".format(self.name, self.value)
337         else:
338             return "{0} = {1}".format(self.name, self.value)
341 class VkFunction(object):
342     def __init__(self, _type=None, name=None, params=[], extension=None):
343         self.extension = extension
344         self.name = name
345         self.type = _type
346         self.params = params
348         # For some functions we need some extra metadata from FUNCTION_OVERRIDES.
349         func_info = FUNCTION_OVERRIDES.get(self.name, None)
350         self.dispatch = func_info["dispatch"] if func_info is not None else True
351         self.driver = func_info["driver"] if func_info is not None else False
352         self.thunk_needed = func_info["thunk"] if func_info is not None else True
354         # Required is set while parsing which APIs and types are required
355         # and is used by the code generation.
356         self.required = False
358     @staticmethod
359     def from_xml(command, types):
360         proto = command.find("proto")
362         func_name = proto.find("name").text
363         func_type = proto.find("type").text
365         params = []
366         for param in command.findall("param"):
367             vk_param = VkParam.from_xml(param, types)
368             params.append(vk_param)
370         return VkFunction(_type=func_type, name=func_name, params=params)
372     def get_conversions(self):
373         """ Get a list of conversion functions required for this function if any.
374         Parameters which are structures may require conversion between win32
375         and the host platform. This function returns a list of conversions
376         required.
377         """
379         conversions = []
380         for param in self.params:
381             convs = param.get_conversions()
382             if convs is not None:
383                 conversions.extend(convs)
385         return conversions
387     def is_core_func(self):
388         """ Returns whether the function is a Vulkan core function.
389         Core functions are APIs defined by the Vulkan spec to be part of the
390         Core API as well as several KHR WSI extensions.
391         """
393         if self.extension is None:
394             return True
396         if self.extension in CORE_EXTENSIONS:
397             return True
399         return False
401     def is_device_func(self):
402         # If none of the other, it must be a device function
403         return not self.is_global_func() and not self.is_instance_func()
405     def is_driver_func(self):
406         """ Returns if function is part of Wine driver interface. """
407         return self.driver
409     def is_global_func(self):
410         # Treat vkGetInstanceProcAddr as a global function as it
411         # can operate with NULL for vkInstance.
412         if self.name == "vkGetInstanceProcAddr":
413             return True
414         # Global functions are not passed a dispatchable object.
415         elif self.params[0].is_dispatchable():
416             return False
417         return True
419     def is_instance_func(self):
420         # Instance functions are passed VkInstance or VkPhysicalDevice.
421         if self.params[0].type in ["VkInstance", "VkPhysicalDevice"]:
422             return True
423         return False
425     def is_required(self):
426         return self.required
428     def needs_conversion(self):
429         """ Check if the function needs any input/output type conversion.
430         Functions need input/output conversion if struct parameters have
431         alignment differences between Win32 and Linux 32-bit.
432         """
434         for p in self.params:
435             if p.needs_conversion():
436                 LOGGER.debug("Parameter {0} to {1} requires conversion".format(p.name, self.name))
437                 return True
439         return False
441     def needs_dispatch(self):
442         return self.dispatch
444     def needs_thunk(self):
445         return self.thunk_needed
447     def pfn(self, prefix="p", call_conv=None, conv=False):
448         """ Create function pointer. """
450         if call_conv:
451             pfn = "{0} ({1} *{2}_{3})(".format(self.type, call_conv, prefix, self.name)
452         else:
453             pfn = "{0} (*{1}_{2})(".format(self.type, prefix, self.name)
455         for i, param in enumerate(self.params):
456             if param.const:
457                 pfn += param.const + " "
459             pfn += param.type
460             if conv and param.needs_conversion():
461                 pfn += "_host"
463             if param.is_pointer():
464                 pfn += " " + param.pointer
466             if param.array_len is not None:
467                 pfn += "[{0}]".format(param.array_len)
469             if i < len(self.params) - 1:
470                 pfn += ", "
471         pfn += ")"
472         return pfn
474     def prototype(self, call_conv=None, prefix=None, postfix=None):
475         """ Generate prototype for given function.
477         Args:
478             call_conv (str, optional): calling convention e.g. WINAPI
479             prefix (str, optional): prefix to append prior to function name e.g. vkFoo -> wine_vkFoo
480             postfix (str, optional): text to append after function name but prior to semicolon e.g. DECLSPEC_HIDDEN
481         """
483         proto = "{0}".format(self.type)
485         if call_conv is not None:
486             proto += " {0}".format(call_conv)
488         if prefix is not None:
489             proto += " {0}{1}(".format(prefix, self.name)
490         else:
491             proto += " {0}(".format(self.name)
493         # Add all the parameters.
494         proto += ", ".join([p.definition() for p in self.params])
496         if postfix is not None:
497             proto += ") {0}".format(postfix)
498         else:
499             proto += ")"
501         return proto
503     def body(self):
504         body = "    {0}".format(self.trace())
506         params = ", ".join([p.variable(conv=False) for p in self.params])
508         # Call the native Vulkan function.
509         if self.type == "void":
510             body += "    {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
511         else:
512             body += "    return {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
514         return body
516     def body_conversion(self):
517         body = ""
519         # Declare a variable to hold the result for non-void functions.
520         if self.type != "void":
521             body += "    {0} result;\n".format(self.type)
523         # Declare any tmp parameters for conversion.
524         for p in self.params:
525             if not p.needs_conversion():
526                 continue
528             if p.is_dynamic_array():
529                 body += "    {0}_host *{1}_host;\n".format(p.type, p.name)
530             else:
531                 body += "    {0}_host {1}_host;\n".format(p.type, p.name)
533         body += "    {0}\n".format(self.trace())
535         # Call any win_to_host conversion calls.
536         for p in self.params:
537             if not p.needs_input_conversion():
538                 continue
540             body += p.copy(Direction.INPUT)
542         # Build list of parameters containing converted and non-converted parameters.
543         # The param itself knows if conversion is needed and applies it when we set conv=True.
544         params = ", ".join([p.variable(conv=True) for p in self.params])
546         # Call the native Vulkan function.
547         if self.type == "void":
548             body += "    {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
549         else:
550             body += "    result = {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
552         body += "\n"
554         # Call any host_to_win conversion calls.
555         for p in self.params:
556             if not p.needs_output_conversion():
557                 continue
559             body += p.copy(Direction.OUTPUT)
561         # Perform any required cleanups. Most of these are for array functions.
562         for p in self.params:
563             if not p.needs_free():
564                 continue
566             body += p.free()
568         # Finally return the result.
569         if self.type != "void":
570             body += "    return result;\n"
572         return body
574     def spec(self, prefix=None, symbol=None):
575         """ Generate spec file entry for this function.
577         Args
578             prefix (str, optional): prefix to prepend to entry point name.
579             symbol (str, optional): allows overriding the name of the function implementing the entry point.
580         """
582         spec = ""
583         params = " ".join([p.spec() for p in self.params])
584         if prefix is not None:
585             spec += "@ stdcall {0}{1}({2})".format(prefix, self.name, params)
586         else:
587             spec += "@ stdcall {0}({1})".format(self.name, params)
589         if symbol is not None:
590             spec += " " + symbol
592         spec += "\n"
593         return spec
595     def stub(self, call_conv=None, prefix=None):
596         stub = self.prototype(call_conv=call_conv, prefix=prefix)
597         stub += "\n{\n"
598         stub += "    {0}".format(self.trace(message="stub: ", trace_func="FIXME"))
600         if self.type == "VkResult":
601             stub += "    return VK_ERROR_OUT_OF_HOST_MEMORY;\n"
602         elif self.type == "VkBool32":
603             stub += "    return VK_FALSE;\n"
604         elif self.type == "PFN_vkVoidFunction":
605             stub += "    return NULL;\n"
607         stub += "}\n\n"
608         return stub
610     def thunk(self, call_conv=None, prefix=None):
611         thunk = self.prototype(call_conv=call_conv, prefix=prefix)
612         thunk += "\n{\n"
614         if self.needs_conversion():
615             thunk += "#if defined(USE_STRUCT_CONVERSION)\n"
616             thunk += self.body_conversion()
617             thunk += "#else\n"
618             thunk += self.body()
619             thunk += "#endif\n"
620         else:
621             thunk += self.body()
623         thunk += "}\n\n"
624         return thunk
626     def trace(self, message=None, trace_func=None):
627         """ Create a trace string including all parameters.
629         Args:
630             message (str, optional): text to print at start of trace message e.g. 'stub: '
631             trace_func (str, optional): used to override trace function e.g. FIXME, printf, etcetera.
632         """
633         if trace_func is not None:
634             trace = "{0}(\"".format(trace_func)
635         else:
636             trace = "TRACE(\""
638         if message is not None:
639             trace += message
641         # First loop is for all the format strings.
642         trace += ", ".join([p.format_string() for p in self.params])
643         trace += "\\n\""
645         # Second loop for parameter names and optional conversions.
646         for param in self.params:
647             if param.format_conv is not None:
648                 trace += ", " + param.format_conv.format(param.name)
649             else:
650                 trace += ", {0}".format(param.name)
651         trace += ");\n"
653         return trace
656 class VkFunctionPointer(object):
657     def __init__(self, _type, name, members):
658         self.name = name
659         self.members = members
660         self.type = _type
661         self.required = False
663     @staticmethod
664     def from_xml(funcpointer):
665         members = []
666         begin = None
668         for t in funcpointer.findall("type"):
669             # General form:
670             # <type>void</type>*       pUserData,
671             # Parsing of the tail (anything past </type>) is tricky since there
672             # can be other data on the next line like: const <type>int</type>..
673             const = begin
674             _type = t.text
675             lines = t.tail.split(",\n")
676             if lines[0][0] == "*":
677                 pointer = "*"
678                 name = lines[0][1:].strip()
679             else:
680                 pointer = None
681                 name = lines[0].strip()
683             # Filter out ); if it is contained.
684             name = name.partition(");")[0]
686             # If tail encompasses multiple lines, assign the second line to begin
687             # for the next line.
688             try:
689                 begin = lines[1].strip()
690             except IndexError:
691                 begin = None
693             members.append(VkMember(const=const, _type=_type, pointer=pointer, name=name))
695         _type = funcpointer.text
696         name = funcpointer.find("name").text
697         return VkFunctionPointer(_type, name, members)
699     def definition(self):
700         text = "{0} {1})(\n".format(self.type, self.name)
702         first = True
703         if len(self.members) > 0:
704             for m in self.members:
705                 if first:
706                     text += "    " + m.definition()
707                     first = False
708                 else:
709                     text += ",\n    " + m.definition()
710         else:
711             # Just make the compiler happy by adding a void parameter.
712             text += "void"
713         text += ");\n"
714         return text
717 class VkHandle(object):
718     def __init__(self, name, _type, parent):
719         self.name = name
720         self.type = _type
721         self.parent = parent
722         self.required = False
724     @staticmethod
725     def from_xml(handle):
726         name = handle.find("name").text
727         _type = handle.find("type").text
728         parent = handle.attrib.get("parent") # Most objects have a parent e.g. VkQueue has VkDevice.
729         return VkHandle(name, _type, parent)
731     def dispatch_table(self):
732         if not self.is_dispatchable():
733             return None
735         if self.parent is None:
736             # Should only happen for VkInstance
737             return "funcs"
738         elif self.name == "VkDevice":
739             # VkDevice has VkInstance as a parent, but has its own dispatch table.
740             return "funcs"
741         elif self.parent in ["VkInstance", "VkPhysicalDevice"]:
742             return "instance->funcs"
743         elif self.parent in ["VkDevice", "VkCommandPool"]:
744             return "device->funcs"
745         else:
746             LOGGER.error("Unhandled dispatchable parent: {0}".format(self.parent))
748     def definition(self):
749         """ Generates handle definition e.g. VK_DEFINE_HANDLE(vkInstance) """
750         return "{0}({1})\n".format(self.type, self.name)
752     def is_dispatchable(self):
753         """ Some handles like VkInstance, VkDevice are dispatchable objects,
754         which means they contain a dispatch table of function pointers.
755         """
756         return self.type == "VK_DEFINE_HANDLE"
758     def native_handle(self):
759         """ Provide access to the native handle of a dispatchable object.
761         Dispatchable objects wrap an underlying 'native' object.
762         This method provides access to the native object.
763         """
764         if not self.is_dispatchable():
765             return None
767         if self.name == "VkCommandBuffer":
768             return "command_buffer"
769         elif self.name == "VkDevice":
770             return "device"
771         elif self.name == "VkInstance":
772             return "instance"
773         elif self.name == "VkPhysicalDevice":
774             return "phys_dev"
775         elif self.name == "VkQueue":
776             return "queue"
777         else:
778             LOGGER.error("Unhandled native handle for: {0}".format(self.name))
781 class VkMember(object):
782     def __init__(self, const=None, _type=None, pointer=None, name=None, array_len=None, dyn_array_len=None, optional=False,
783             extension_structs=None):
784         self.const = const
785         self.name = name
786         self.pointer = pointer
787         self.type = _type
788         self.type_info = None
789         self.array_len = array_len
790         self.dyn_array_len = dyn_array_len
791         self.optional = optional
792         self.extension_structs = extension_structs
794     def __eq__(self, other):
795         """ Compare member based on name against a string.
797         This method is for convenience by VkStruct, which holds a number of members and needs quick checking
798         if certain members exist.
799         """
801         if self.name == other:
802             return True
804         return False
806     def __repr__(self):
807         return "{0} {1} {2} {3} {4} {5}".format(self.const, self.type, self.pointer, self.name, self.array_len,
808                 self.dyn_array_len)
810     @staticmethod
811     def from_xml(member):
812         """ Helper function for parsing a member tag within a struct or union. """
814         name_elem = member.find("name")
815         type_elem = member.find("type")
817         const = member.text.strip() if member.text else None
818         member_type = None
819         pointer = None
820         array_len = None
822         if type_elem is not None:
823             member_type = type_elem.text
824             if type_elem.tail is not None:
825                 pointer = type_elem.tail.strip() if type_elem.tail.strip() != "" else None
827         # Name of other member within, which stores the number of
828         # elements pointed to be by this member.
829         dyn_array_len = member.get("len", None)
831         if "validextensionstructs" in member.attrib:
832             extension_structs = member.get("validextensionstructs").split(",")
833         else:
834             extension_structs = None
836         # Some members are optional, which is important for conversion code e.g. not dereference NULL pointer.
837         optional = True if member.get("optional") else False
839         # Usually we need to allocate memory for dynamic arrays. We need to do the same in a few other cases
840         # like for VkCommandBufferBeginInfo.pInheritanceInfo. Just threat such cases as dynamic arrays of
841         # size 1 to simplify code generation.
842         if dyn_array_len is None and pointer is not None:
843             dyn_array_len = 1
845         # Some members are arrays, attempt to parse these. Formats include:
846         # <member><type>char</type><name>extensionName</name>[<enum>VK_MAX_EXTENSION_NAME_SIZE</enum>]</member>
847         # <member><type>uint32_t</type><name>foo</name>[4]</member>
848         if name_elem.tail and name_elem.tail[0] == '[':
849             LOGGER.debug("Found array type")
850             enum_elem = member.find("enum")
851             if enum_elem is not None:
852                 array_len = enum_elem.text
853             else:
854                 # Remove brackets around length
855                 array_len = name_elem.tail.strip("[]")
857         return VkMember(const=const, _type=member_type, pointer=pointer, name=name_elem.text, array_len=array_len,
858                 dyn_array_len=dyn_array_len, optional=optional, extension_structs=extension_structs)
860     def copy(self, input, output, direction):
861         """ Helper method for use by conversion logic to generate a C-code statement to copy this member. """
863         if self.needs_conversion():
864             if self.is_dynamic_array():
865                 if direction == Direction.OUTPUT:
866                     LOGGER.warn("TODO: implement copying of returnedonly dynamic array for {0}.{1}".format(self.type, self.name))
867                 else:
868                     # Array length is either a variable name (string) or an int.
869                     count = self.dyn_array_len if isinstance(self.dyn_array_len, int) else "{0}{1}".format(input, self.dyn_array_len)
870                     return "{0}{1} = convert_{2}_array_win_to_host({3}{1}, {4});\n".format(output, self.name, self.type, input, count)
871             elif self.is_static_array():
872                 count = self.array_len
873                 if direction == Direction.OUTPUT:
874                     # Needed by VkMemoryHeap.memoryHeaps
875                     return "convert_{0}_static_array_host_to_win({2}{1}, {3}{1}, {4});\n".format(self.type, self.name, input, output, count)
876                 else:
877                     # Nothing needed this yet.
878                     LOGGER.warn("TODO: implement copying of static array for {0}.{1}".format(self.type, self.name))
879             else:
880                 if direction == Direction.OUTPUT:
881                     return "convert_{0}_host_to_win(&{2}{1}, &{3}{1});\n".format(self.type, self.name, input, output)
882                 else:
883                     return "convert_{0}_win_to_host(&{2}{1}, &{3}{1});\n".format(self.type, self.name, input, output)
884         elif self.is_static_array():
885             bytes_count = "{0} * sizeof({1})".format(self.array_len, self.type)
886             return "memcpy({0}{1}, {2}{1}, {3});\n".format(output, self.name, input, bytes_count)
887         else:
888             return "{0}{1} = {2}{1};\n".format(output, self.name, input)
890     def definition(self, align=False, conv=False):
891         """ Generate prototype for given function.
893         Args:
894             align (bool, optional): Enable alignment if a type needs it. This adds WINE_VK_ALIGN(8) to a member.
895             conv (bool, optional): Enable conversion if a type needs it. This appends '_host' to the name.
896         """
898         text = ""
899         if self.is_const():
900             text += "const "
902         if conv and self.is_struct():
903             text += "{0}_host".format(self.type)
904         else:
905             text += self.type
907         if self.is_pointer():
908             text += " {0}{1}".format(self.pointer, self.name)
909         else:
910             if align and self.needs_alignment():
911                 text += " WINE_VK_ALIGN(8) " + self.name
912             else:
913                 text += " " + self.name
915         if self.is_static_array():
916             text += "[{0}]".format(self.array_len)
918         return text
920     def get_conversions(self):
921         """ Return any conversion description for this member and its children when conversion is needed. """
923         # Check if we need conversion either for this member itself or for any child members
924         # in case member represents a struct.
925         if not self.needs_conversion():
926             return None
928         conversions = []
930         # Collect any conversion for any member structs.
931         struct = self.type_info["data"]
932         for m in struct:
933             if m.needs_conversion():
934                 conversions.extend(m.get_conversions())
936         struct = self.type_info["data"]
937         direction = Direction.OUTPUT if struct.returnedonly else Direction.INPUT
938         if self.is_dynamic_array():
939             conversions.append(ConversionFunction(False, True, direction, struct))
940         elif self.is_static_array():
941             conversions.append(ConversionFunction(True, False, direction, struct))
942         else:
943             conversions.append(ConversionFunction(False, False, direction, struct))
945         if self.needs_free():
946             conversions.append(FreeFunction(self.is_dynamic_array(), struct))
948         return conversions
950     def is_const(self):
951         return self.const is not None
953     def is_dynamic_array(self):
954         """ Returns if the member is an array element.
955         Vulkan uses this for dynamically sized arrays for which
956         there is a 'count' parameter.
957         """
958         return self.dyn_array_len is not None
960     def is_handle(self):
961         return self.type_info["category"] == "handle"
963     def is_pointer(self):
964         return self.pointer is not None
966     def is_static_array(self):
967         """ Returns if the member is an array.
968         Vulkan uses this often for fixed size arrays in which the
969         length is part of the member.
970         """
971         return self.array_len is not None
973     def is_struct(self):
974         return self.type_info["category"] == "struct"
976     def is_union(self):
977         return self.type_info["category"] == "union"
979     def needs_alignment(self):
980         """ Check if this member needs alignment for 64-bit data.
981         Various structures need alignment on 64-bit variables due
982         to compiler differences on 32-bit between Win32 and Linux.
983         """
985         if self.is_pointer():
986             return False
987         elif self.type == "size_t":
988             return False
989         elif self.type in ["uint64_t", "VkDeviceSize"]:
990             return True
991         elif self.is_struct():
992             struct = self.type_info["data"]
993             return struct.needs_alignment()
994         elif self.is_handle():
995             # Dispatchable handles are pointers to objects, while
996             # non-dispatchable are uint64_t and hence need alignment.
997             handle = self.type_info["data"]
998             return False if handle.is_dispatchable() else True
999         return False
1001     def needs_conversion(self):
1002         """ Structures requiring alignment, need conversion between win32 and host. """
1004         if not self.is_struct():
1005             return False
1007         struct = self.type_info["data"]
1008         return struct.needs_conversion()
1010     def needs_free(self):
1011         if not self.needs_conversion():
1012             return False
1014         if self.is_dynamic_array():
1015             return True
1017         # TODO: some non-pointer structs and optional pointer structs may need freeing,
1018         # though none of this type have been encountered yet.
1019         return False
1021     def set_type_info(self, type_info):
1022         """ Helper function to set type information from the type registry.
1023         This is needed, because not all type data is available at time of
1024         parsing.
1025         """
1026         self.type_info = type_info
1029 class VkParam(object):
1030     """ Helper class which describes a parameter to a function call. """
1032     def __init__(self, type_info, const=None, pointer=None, name=None, array_len=None, dyn_array_len=None):
1033         self.const = const
1034         self.name = name
1035         self.array_len = array_len
1036         self.dyn_array_len = dyn_array_len
1037         self.pointer = pointer
1038         self.type_info = type_info
1039         self.type = type_info["name"] # For convenience
1040         self.handle = type_info["data"] if type_info["category"] == "handle" else None
1041         self.struct = type_info["data"] if type_info["category"] == "struct" else None
1043         self._set_direction()
1044         self._set_format_string()
1045         self._set_conversions()
1047     def __repr__(self):
1048         return "{0} {1} {2} {3} {4}".format(self.const, self.type, self.pointer, self.name, self.array_len, self.dyn_array_len)
1050     @staticmethod
1051     def from_xml(param, types):
1052         """ Helper function to create VkParam from xml. """
1054         # Parameter parsing is slightly tricky. All the data is contained within
1055         # a param tag, but some data is within subtags while others are text
1056         # before or after the type tag.
1057         # Common structure:
1058         # <param>const <type>char</type>* <name>pLayerName</name></param>
1060         name_elem = param.find("name")
1061         array_len = None
1062         name = name_elem.text
1063         # Tail contains array length e.g. for blendConstants param of vkSetBlendConstants
1064         if name_elem.tail is not None:
1065             array_len = name_elem.tail.strip("[]")
1067         # Name of other parameter in function prototype, which stores the number of
1068         # elements pointed to be by this parameter.
1069         dyn_array_len = param.get("len", None)
1071         const = param.text.strip() if param.text else None
1072         type_elem = param.find("type")
1073         pointer = type_elem.tail.strip() if type_elem.tail.strip() != "" else None
1075         # Since we have parsed all types before hand, this should not happen.
1076         type_info = types.get(type_elem.text, None)
1077         if type_info is None:
1078             LOGGER.err("type info not found for: {0}".format(type_elem.text))
1080         return VkParam(type_info, const=const, pointer=pointer, name=name, array_len=array_len, dyn_array_len=dyn_array_len)
1082     def _set_conversions(self):
1083         """ Internal helper function to configure any needed conversion functions. """
1085         self.free_func = None
1086         self.input_conv = None
1087         self.output_conv = None
1088         if not self.needs_conversion():
1089             return
1091         # Input functions require win to host conversion.
1092         if self._direction in [Direction.INPUT, Direction.INPUT_OUTPUT]:
1093             self.input_conv = ConversionFunction(False, self.is_dynamic_array(), Direction.INPUT, self.struct)
1095         # Output functions require host to win conversion.
1096         if self._direction in [Direction.INPUT_OUTPUT, Direction.OUTPUT]:
1097             self.output_conv = ConversionFunction(False, self.is_dynamic_array(), Direction.OUTPUT, self.struct)
1099         # Dynamic arrays, but also some normal structs (e.g. VkCommandBufferBeginInfo) need memory
1100         # allocation and thus some cleanup.
1101         if self.is_dynamic_array() or self.struct.needs_free():
1102             self.free_func = FreeFunction(self.is_dynamic_array(), self.struct)
1104     def _set_direction(self):
1105         """ Internal helper function to set parameter direction (input/output/input_output). """
1107         # The parameter direction needs to be determined from hints in vk.xml like returnedonly,
1108         # parameter constness and other heuristics.
1109         # For now we need to get this right for structures as we need to convert these, we may have
1110         # missed a few other edge cases (e.g. count variables).
1111         # See also https://github.com/KhronosGroup/Vulkan-Docs/issues/610
1113         if not self.is_pointer():
1114             self._direction = Direction.INPUT
1115         elif self.is_const() and self.is_pointer():
1116             self._direction = Direction.INPUT
1117         elif self.is_struct():
1118             if not self.struct.returnedonly:
1119                 self._direction = Direction.INPUT
1120                 return
1122             # Returnedonly hints towards output, however in some cases
1123             # it is inputoutput. In particular if pNext / sType exist,
1124             # which are used to link in other structures without having
1125             # to introduce new APIs. E.g. vkGetPhysicalDeviceProperties2KHR.
1126             if "pNext" in self.struct:
1127                 self._direction = Direction.INPUT_OUTPUT
1128                 return
1130             self._direction = Direction.OUTPUT
1131         else:
1132             # This should mostly be right. Count variables can be inout, but we don't care about these yet.
1133             self._direction = Direction.OUTPUT
1135     def _set_format_string(self):
1136         """ Internal helper function to be used by constructor to set format string. """
1138         # Determine a format string used by code generation for traces.
1139         # 64-bit types need a conversion function.
1140         self.format_conv = None
1141         if self.is_static_array() or self.is_pointer():
1142             self.format_str = "%p"
1143         else:
1144             if self.type_info["category"] in ["bitmask", "enum"]:
1145                 self.format_str = "%#x"
1146             elif self.is_handle():
1147                 # We use uint64_t for non-dispatchable handles as opposed to pointers
1148                 # for dispatchable handles.
1149                 if self.handle.is_dispatchable():
1150                     self.format_str = "%p"
1151                 else:
1152                     self.format_str = "0x%s"
1153                     self.format_conv = "wine_dbgstr_longlong({0})"
1154             elif self.type == "float":
1155                 self.format_str = "%f"
1156             elif self.type == "int":
1157                 self.format_str = "%d"
1158             elif self.type == "int32_t":
1159                 self.format_str = "%d"
1160             elif self.type == "size_t":
1161                 self.format_str = "0x%s"
1162                 self.format_conv = "wine_dbgstr_longlong({0})"
1163             elif self.type in ["uint32_t", "VkBool32"]:
1164                 self.format_str = "%u"
1165             elif self.type in ["uint64_t", "VkDeviceSize"]:
1166                 self.format_str = "0x%s"
1167                 self.format_conv = "wine_dbgstr_longlong({0})"
1168             elif self.type == "HANDLE":
1169                 self.format_str = "%p"
1170             elif self.type in ["VisualID", "xcb_visualid_t", "RROutput"]:
1171                 # Don't care about Linux specific types.
1172                 self.format_str = ""
1173             else:
1174                 LOGGER.warn("Unhandled type: {0}".format(self.type_info))
1176     def copy(self, direction):
1177         if direction == Direction.INPUT:
1178             if self.is_dynamic_array():
1179                 return "    {0}_host = convert_{1}_array_win_to_host({0}, {2});\n".format(self.name, self.type, self.dyn_array_len)
1180             else:
1181                 return "    convert_{0}_win_to_host({1}, &{1}_host);\n".format(self.type, self.name)
1182         else:
1183             if self.is_dynamic_array():
1184                 LOGGER.error("Unimplemented output conversion for: {0}".format(self.name))
1185             else:
1186                 return "    convert_{0}_host_to_win(&{1}_host, {1});\n".format(self.type, self.name)
1188     def definition(self, postfix=None):
1189         """ Return prototype for the parameter. E.g. 'const char *foo' """
1191         proto = ""
1192         if self.const:
1193             proto += self.const + " "
1195         proto += self.type
1197         if self.is_pointer():
1198             proto += " {0}{1}".format(self.pointer, self.name)
1199         else:
1200             proto += " " + self.name
1202         # Allows appending something to the variable name useful for
1203         # win32 to host conversion.
1204         if postfix is not None:
1205             proto += postfix
1207         if self.is_static_array():
1208             proto += "[{0}]".format(self.array_len)
1210         return proto
1212     def direction(self):
1213         """ Returns parameter direction: input, output, input_output.
1215         Parameter direction in Vulkan is not straight-forward, which this function determines.
1216         """
1218         return self._direction
1220     def format_string(self):
1221         return self.format_str
1223     def dispatch_table(self):
1224         """ Return functions dispatch table pointer for dispatchable objects. """
1226         if not self.is_dispatchable():
1227             return None
1229         return "{0}->{1}".format(self.name, self.handle.dispatch_table())
1231     def format_string(self):
1232         return self.format_str
1234     def free(self):
1235         if self.is_dynamic_array():
1236             if self.struct.returnedonly:
1237                 # For returnedonly, counts is stored in a pointer.
1238                 return "    free_{0}_array({1}_host, *{2});\n".format(self.type, self.name, self.dyn_array_len)
1239             else:
1240                 return "    free_{0}_array({1}_host, {2});\n".format(self.type, self.name, self.dyn_array_len)
1241         else:
1242             # We are operating on a single structure. Some structs (very rare) contain dynamic members,
1243             # which would need freeing.
1244             if self.struct.needs_free():
1245                 return "    free_{0}(&{1}_host);\n".format(self.type, self.name)
1246         return ""
1248     def get_conversions(self):
1249         """ Get a list of conversions required for this parameter if any.
1250         Parameters which are structures may require conversion between win32
1251         and the host platform. This function returns a list of conversions
1252         required.
1253         """
1255         if not self.is_struct():
1256             return None
1258         if not self.needs_conversion():
1259             return None
1261         conversions = []
1263         # Collect any member conversions first, so we can guarantee
1264         # those functions will be defined prior to usage by the
1265         # 'parent' param requiring conversion.
1266         for m in self.struct:
1267             if not m.is_struct():
1268                 continue
1270             if not m.needs_conversion():
1271                 continue
1273             conversions.extend(m.get_conversions())
1275         # Conversion requirements for the 'parent' parameter.
1276         if self.input_conv is not None:
1277             conversions.append(self.input_conv)
1278         if self.output_conv is not None:
1279             conversions.append(self.output_conv)
1280         if self.free_func is not None:
1281             conversions.append(self.free_func)
1283         return conversions
1285     def is_const(self):
1286         return self.const is not None
1288     def is_dynamic_array(self):
1289         return self.dyn_array_len is not None
1291     def is_dispatchable(self):
1292         if not self.is_handle():
1293             return False
1295         return self.handle.is_dispatchable()
1297     def is_handle(self):
1298         return self.handle is not None
1300     def is_pointer(self):
1301         return self.pointer is not None
1303     def is_static_array(self):
1304         return self.array_len is not None
1306     def is_struct(self):
1307         return self.struct is not None
1309     def needs_conversion(self):
1310         """ Returns if parameter needs conversion between win32 and host. """
1312         if not self.is_struct():
1313             return False
1315         # VkSparseImageMemoryRequirements is used by vkGetImageSparseMemoryRequirements.
1316         # This function is tricky to wrap, because how to wrap depends on whether
1317         # pSparseMemoryRequirements is NULL or not. Luckily for VkSparseImageMemoryRequirements
1318         # the alignment works out in such a way that no conversion is needed between win32 and Linux.
1319         if self.type == "VkSparseImageMemoryRequirements":
1320             return False
1322         # If a structure needs alignment changes, it means we need to
1323         # perform parameter conversion between win32 and host.
1324         if self.struct.needs_conversion():
1325             return True
1327         return False
1329     def needs_free(self):
1330         return self.free_func is not None
1332     def needs_input_conversion(self):
1333         return self.input_conv is not None
1335     def needs_output_conversion(self):
1336         return self.output_conv is not None
1338     def spec(self):
1339         """ Generate spec file entry for this parameter. """
1341         if self.type_info["category"] in ["bitmask", "enum"]:
1342             return "long"
1343         if self.is_pointer() and self.type == "char":
1344             return "str"
1345         if self.is_dispatchable() or self.is_pointer() or self.is_static_array():
1346             return "ptr"
1347         if self.is_handle() and not self.is_dispatchable():
1348             return "int64"
1349         if self.type == "float":
1350             return "float"
1351         if self.type in ["int", "int32_t", "size_t", "uint32_t", "VkBool32"]:
1352             return "long"
1353         if self.type in ["uint64_t", "VkDeviceSize"]:
1354             return "int64"
1356         LOGGER.error("Unhandled spec conversion for type: {0}".format(self.type))
1358     def variable(self, conv=False):
1359         """ Returns 'glue' code during generation of a function call on how to access the variable.
1360         This function handles various scenarios such as 'unwrapping' if dispatchable objects and
1361         renaming of parameters in case of win32 -> host conversion.
1363         Args:
1364             conv (bool, optional): Enable conversion if the param needs it. This appends '_host' to the name.
1365         """
1367         # Hack until we enable allocation callbacks from ICD to application. These are a joy
1368         # to enable one day, because of calling convention conversion.
1369         if "VkAllocationCallbacks" in self.type:
1370             LOGGER.debug("TODO: setting NULL VkAllocationCallbacks for {0}".format(self.name))
1371             return "NULL"
1373         # Dispatchable objects wrap the native handle. For thunk generation we
1374         # need to pass the native handle to the native Vulkan calls.
1375         if self.is_dispatchable():
1376             return "{0}->{1}".format(self.name, self.handle.native_handle())
1377         elif conv and self.needs_conversion():
1378             if self.is_dynamic_array():
1379                 return "{0}_host".format(self.name)
1380             else:
1381                 return "&{0}_host".format(self.name)
1382         else:
1383             return self.name
1386 class VkStruct(Sequence):
1387     """ Class which represents the type union and struct. """
1389     def __init__(self, name, members, returnedonly, union=False):
1390         self.name = name
1391         self.members = members
1392         self.returnedonly = returnedonly
1393         self.required = False
1394         self.union = union
1395         self.type_info = None # To be set later.
1397     def __getitem__(self, i):
1398         return self.members[i]
1400     def __len__(self):
1401         return len(self.members)
1403     @staticmethod
1404     def from_xml(struct):
1405         # Unions and structs are the same parsing wise, but we need to
1406         # know which one we are dealing with later on for code generation.
1407         union = True if struct.attrib["category"] == "union" else False
1409         name = struct.attrib.get("name", None)
1411         # 'Output' structures for which data is filled in by the API are
1412         # marked as 'returnedonly'.
1413         returnedonly = True if struct.attrib.get("returnedonly") else False
1415         members = []
1416         for member in struct.findall("member"):
1417             vk_member = VkMember.from_xml(member)
1418             members.append(vk_member)
1420         return VkStruct(name, members, returnedonly, union=union)
1422     @staticmethod
1423     def decouple_structs(structs):
1424         """ Helper function which decouples a list of structs.
1425         Structures often depend on other structures. To make the C compiler
1426         happy we need to define 'substructures' first. This function analyzes
1427         the list of structures and reorders them in such a way that they are
1428         decoupled.
1429         """
1431         tmp_structs = list(structs) # Don't modify the original structures.
1432         decoupled_structs = []
1434         while (len(tmp_structs) > 0):
1435             for struct in tmp_structs:
1436                 dependends = False
1438                 if not struct.required:
1439                     tmp_structs.remove(struct)
1440                     continue
1442                 for m in struct:
1443                     if not (m.is_struct() or m.is_union()):
1444                         continue
1446                     found = False
1447                     # Check if a struct we depend on has already been defined.
1448                     for s in decoupled_structs:
1449                         if s.name == m.type:
1450                             found = True
1451                             break
1453                     if not found:
1454                         # Check if the struct we depend on is even in the list of structs.
1455                         # If found now, it means we haven't met all dependencies before we
1456                         # can operate on the current struct.
1457                         # When generating 'host' structs we may not be able to find a struct
1458                         # as the list would only contain the structs requiring conversion.
1459                         for s in tmp_structs:
1460                             if s.name == m.type:
1461                                 dependends = True
1462                                 break
1464                 if dependends == False:
1465                     decoupled_structs.append(struct)
1466                     tmp_structs.remove(struct)
1468         return decoupled_structs
1470     def definition(self, align=False, conv=False, postfix=None):
1471         """ Convert structure to textual definition.
1473         Args:
1474             align (bool, optional): enable alignment to 64-bit for win32 struct compatibility.
1475             conv (bool, optional): enable struct conversion if the struct needs it.
1476             postfix (str, optional): text to append to end of struct name, useful for struct renaming.
1477         """
1479         if self.union:
1480             text = "typedef union {0}".format(self.name)
1481         else:
1482             text = "typedef struct {0}".format(self.name)
1484         if postfix is not None:
1485             text += postfix
1487         text += "\n{\n"
1489         for m in self:
1490             if align and m.needs_alignment():
1491                 text += "    {0};\n".format(m.definition(align=align))
1492             elif conv and m.needs_conversion():
1493                 text += "    {0};\n".format(m.definition(conv=conv))
1494             else:
1495                 text += "    {0};\n".format(m.definition())
1497         if postfix is not None:
1498             text += "}} {0}{1};\n\n".format(self.name, postfix)
1499         else:
1500             text += "}} {0};\n\n".format(self.name)
1501         return text
1503     def needs_alignment(self):
1504         """ Check if structure needs alignment for 64-bit data.
1505         Various structures need alignment on 64-bit variables due
1506         to compiler differences on 32-bit between Win32 and Linux.
1507         """
1509         for m in self.members:
1510             if m.needs_alignment():
1511                 return True
1512         return False
1514     def needs_conversion(self):
1515         """ Returns if struct members needs conversion between win32 and host.
1516         Structures need conversion if they contain members requiring alignment
1517         or if they include other structures which need alignment.
1518         """
1520         if self.needs_alignment():
1521             return True
1523         for m in self.members:
1524             if m.needs_conversion():
1525                 return True
1526         return False
1528     def needs_free(self):
1529         """ Check if any struct member needs some memory freeing."""
1531         for m in self.members:
1532             if m.needs_free():
1533                 return True
1535             continue
1537         return False
1539     def set_type_info(self, types):
1540         """ Helper function to set type information from the type registry.
1541         This is needed, because not all type data is available at time of
1542         parsing.
1543         """
1544         for m in self.members:
1545             type_info = types[m.type]
1546             m.set_type_info(type_info)
1549 class ConversionFunction(object):
1550     def __init__(self, array, dyn_array, direction, struct):
1551         self.array = array
1552         self.direction = direction
1553         self.dyn_array = dyn_array
1554         self.struct = struct
1555         self.type = struct.name
1557         self._set_name()
1559     def __eq__(self, other):
1560         if self.name != other.name:
1561             return False
1563         return True
1565     def _generate_array_conversion_func(self):
1566         """ Helper function for generating a conversion function for array structs. """
1568         if self.direction == Direction.OUTPUT:
1569             params = ["const {0}_host *in".format(self.type), "uint32_t count"]
1570             return_type = self.type
1571         else:
1572             params = ["const {0} *in".format(self.type), "uint32_t count"]
1573             return_type = "{0}_host".format(self.type)
1575         # Generate function prototype.
1576         body = "static inline {0} *{1}(".format(return_type, self.name)
1577         body += ", ".join(p for p in params)
1578         body += ")\n{\n"
1580         body += "    {0} *out;\n".format(return_type)
1581         body += "    unsigned int i;\n\n"
1582         body += "    if (!in) return NULL;\n\n"
1584         body += "    out = heap_alloc(count * sizeof(*out));\n"
1586         body += "    for (i = 0; i < count; i++)\n"
1587         body += "    {\n"
1589         for m in self.struct:
1590             # TODO: support copying of pNext extension structures!
1591             # Luckily though no extension struct at this point needs conversion.
1592             body += "        " + m.copy("in[i].", "out[i].", self.direction)
1594         body += "    }\n\n"
1595         body += "    return out;\n"
1596         body += "}\n\n"
1597         return body
1599     def _generate_conversion_func(self):
1600         """ Helper function for generating a conversion function for non-array structs. """
1602         if self.direction == Direction.OUTPUT:
1603             params = ["const {0}_host *in".format(self.type), "{0} *out".format(self.type)]
1604         else:
1605             params = ["const {0} *in".format(self.type), "{0}_host *out".format(self.type)]
1607         body = "static inline void {0}(".format(self.name)
1609         # Generate parameter list
1610         body += ", ".join(p for p in params)
1611         body += ")\n{\n"
1613         body += "    if (!in) return;\n\n"
1615         if self.direction == Direction.INPUT and "pNext" in self.struct and self.struct.returnedonly:
1616             # We are dealing with an input_output parameter. For these we only need to copy
1617             # pNext and sType as the other fields are filled in by the host. We do potentially
1618             # have to iterate over pNext and perform conversions based on switch(sType)!
1619             # Luckily though no extension structs at this point need conversion.
1620             # TODO: support copying of pNext extension structures!
1621             body += "    out->pNext = in->pNext;\n"
1622             body += "    out->sType = in->sType;\n"
1623         else:
1624             for m in self.struct:
1625                 # TODO: support copying of pNext extension structures!
1626                 body += "    " + m.copy("in->", "out->", self.direction)
1628         body += "}\n\n"
1629         return body
1631     def _generate_static_array_conversion_func(self):
1632         """ Helper function for generating a conversion function for array structs. """
1634         if self.direction == Direction.OUTPUT:
1635             params = ["const {0}_host *in".format(self.type), "{0} *out".format(self.type), "uint32_t count"]
1636             return_type = self.type
1637         else:
1638             params = ["const {0} *in".format(self.type), "{0} *out_host".format(self.type), "uint32_t count"]
1639             return_type = "{0}_host".format(self.type)
1641         # Generate function prototype.
1642         body = "static inline void {0}(".format(self.name)
1643         body += ", ".join(p for p in params)
1644         body += ")\n{\n"
1645         body += "    unsigned int i;\n\n"
1646         body += "    if (!in) return;\n\n"
1647         body += "    for (i = 0; i < count; i++)\n"
1648         body += "    {\n"
1650         for m in self.struct:
1651             # TODO: support copying of pNext extension structures!
1652             body += "        " + m.copy("in[i].", "out[i].", self.direction)
1654         body += "    }\n"
1655         body += "}\n\n"
1656         return body
1658     def _set_name(self):
1659         if self.direction == Direction.INPUT:
1660             if self.array:
1661                 name = "convert_{0}_static_array_win_to_host".format(self.type)
1662             elif self.dyn_array:
1663                 name = "convert_{0}_array_win_to_host".format(self.type)
1664             else:
1665                 name = "convert_{0}_win_to_host".format(self.type)
1666         else: # Direction.OUTPUT
1667             if self.array:
1668                 name = "convert_{0}_static_array_host_to_win".format(self.type)
1669             elif self.dyn_array:
1670                 name = "convert_{0}_array_host_to_win".format(self.type)
1671             else:
1672                 name = "convert_{0}_host_to_win".format(self.type)
1674         self.name = name
1676     def definition(self):
1677         if self.array:
1678             return self._generate_static_array_conversion_func()
1679         elif self.dyn_array:
1680             return self._generate_array_conversion_func()
1681         else:
1682             return self._generate_conversion_func()
1685 class FreeFunction(object):
1686     def __init__(self, dyn_array, struct):
1687         self.dyn_array = dyn_array
1688         self.struct = struct
1689         self.type = struct.name
1691         if dyn_array:
1692             self.name = "free_{0}_array".format(self.type)
1693         else:
1694             self.name = "free_{0}".format(self.type)
1696     def __eq__(self, other):
1697         if self.name == other.name:
1698             return True
1700         return False
1702     def _generate_array_free_func(self):
1703         """ Helper function for cleaning up temporary buffers required for array conversions. """
1705         # Generate function prototype.
1706         body = "static inline void {0}({1}_host *in, uint32_t count)\n{{\n".format(self.name, self.type)
1708         # E.g. VkGraphicsPipelineCreateInfo_host needs freeing for pStages.
1709         if self.struct.needs_free():
1710             body += "    unsigned int i;\n\n"
1711             body += "    if (!in) return;\n\n"
1712             body += "    for (i = 0; i < count; i++)\n"
1713             body += "    {\n"
1715             for m in self.struct:
1716                 if m.needs_conversion() and m.is_dynamic_array():
1717                     if m.is_const():
1718                         # Add a cast to ignore const on conversion structs we allocated ourselves.
1719                         body += "        free_{0}_array(({0}_host *)in[i].{1}, in[i].{2});\n".format(m.type, m.name, m.dyn_array_len)
1720                     else:
1721                         body += "        free_{0}_array(in[i].{1}, in[i].{2});\n".format(m.type, m.name, m.dyn_array_len)
1722                 elif m.needs_conversion():
1723                     LOGGER.error("Unhandled conversion for {0}".format(m.name))
1724             body += "    }\n"
1725         else:
1726             body += "    if (!in) return;\n\n"
1728         body += "    heap_free(in);\n"
1730         body += "}\n\n"
1731         return body
1733     def _generate_free_func(self):
1734         # E.g. VkCommandBufferBeginInfo.pInheritanceInfo needs freeing.
1735         if not self.struct.needs_free():
1736             return ""
1738         # Generate function prototype.
1739         body = "static inline void {0}({1}_host *in)\n{{\n".format(self.name, self.type)
1741         for m in self.struct:
1742             if m.needs_conversion() and m.is_dynamic_array():
1743                 count = m.dyn_array_len if isinstance(m.dyn_array_len, int) else "in->{0}".format(m.dyn_array_len)
1744                 if m.is_const():
1745                     # Add a cast to ignore const on conversion structs we allocated ourselves.
1746                     body += "    free_{0}_array(({0}_host *)in->{1}, {2});\n".format(m.type, m.name, count)
1747                 else:
1748                     body += "    free_{0}_array(in->{1}, {2});\n".format(m.type, m.name, count)
1750         body += "}\n\n"
1751         return body
1753     def definition(self):
1754         if self.dyn_array:
1755             return self._generate_array_free_func()
1756         else:
1757             # Some structures need freeing too if they contain dynamic arrays.
1758             # E.g. VkCommandBufferBeginInfo
1759             return self._generate_free_func()
1762 class VkGenerator(object):
1763     def __init__(self, registry):
1764         self.registry = registry
1766         # Build a list conversion functions for struct conversion.
1767         self.conversions = []
1768         self.host_structs = []
1769         for func in self.registry.funcs.values():
1770             if not func.is_required():
1771                 continue
1773             if not func.needs_conversion():
1774                 continue
1776             conversions = func.get_conversions()
1777             for conv in conversions:
1778                 # Pull in any conversions for vulkan_thunks.c.
1779                 if func.needs_thunk():
1780                     # Append if we don't already have this conversion.
1781                     if not any(c == conv for c in self.conversions):
1782                         self.conversions.append(conv)
1784                 # Structs can be used in different ways by different conversions
1785                 # e.g. array vs non-array. Just make sure we pull in each struct once.
1786                 if not any(s.name == conv.struct.name for s in self.host_structs):
1787                     self.host_structs.append(conv.struct)
1789     def generate_thunks_c(self, f, prefix):
1790         f.write("/* Automatically generated from Vulkan vk.xml; DO NOT EDIT! */\n\n")
1792         f.write("#include \"config.h\"\n")
1793         f.write("#include \"wine/port.h\"\n\n")
1795         f.write("#include \"vulkan_private.h\"\n\n")
1797         f.write("WINE_DEFAULT_DEBUG_CHANNEL(vulkan);\n\n")
1799         # Generate any conversion helper functions.
1800         f.write("#if defined(USE_STRUCT_CONVERSION)\n")
1801         for conv in self.conversions:
1802             f.write(conv.definition())
1803         f.write("#endif /* USE_STRUCT_CONVERSION */\n\n")
1805         # Create thunks for instance and device functions.
1806         # Global functions don't go through the thunks.
1807         for vk_func in self.registry.funcs.values():
1808             if not vk_func.is_required():
1809                 continue
1811             if vk_func.is_global_func():
1812                 continue
1814             if not vk_func.needs_thunk():
1815                 continue
1817             # Exports symbols for Core functions.
1818             if not vk_func.is_core_func():
1819                 f.write("static ")
1820             f.write(vk_func.thunk(prefix=prefix, call_conv="WINAPI"))
1822         f.write("static const struct vulkan_func vk_device_dispatch_table[] =\n{\n")
1823         for vk_func in self.registry.device_funcs:
1824             if not vk_func.is_required():
1825                 continue
1827             f.write("    {{\"{0}\", &{1}{0}}},\n".format(vk_func.name, prefix))
1828         f.write("};\n\n")
1830         f.write("static const struct vulkan_func vk_instance_dispatch_table[] =\n{\n")
1831         for vk_func in self.registry.instance_funcs:
1832             if not vk_func.is_required():
1833                 continue
1835             f.write("    {{\"{0}\", &{1}{0}}},\n".format(vk_func.name, prefix))
1836         f.write("};\n\n")
1838         f.write("void *wine_vk_get_device_proc_addr(const char *name)\n")
1839         f.write("{\n")
1840         f.write("    unsigned int i;\n")
1841         f.write("    for (i = 0; i < ARRAY_SIZE(vk_device_dispatch_table); i++)\n")
1842         f.write("    {\n")
1843         f.write("        if (strcmp(vk_device_dispatch_table[i].name, name) == 0)\n")
1844         f.write("        {\n")
1845         f.write("            TRACE(\"Found name=%s in device table\\n\", debugstr_a(name));\n")
1846         f.write("            return vk_device_dispatch_table[i].func;\n")
1847         f.write("        }\n")
1848         f.write("    }\n")
1849         f.write("    return NULL;\n")
1850         f.write("}\n\n")
1852         f.write("void *wine_vk_get_instance_proc_addr(const char *name)\n")
1853         f.write("{\n")
1854         f.write("    unsigned int i;\n")
1855         f.write("    for (i = 0; i < ARRAY_SIZE(vk_instance_dispatch_table); i++)\n")
1856         f.write("    {\n")
1857         f.write("        if (strcmp(vk_instance_dispatch_table[i].name, name) == 0)\n")
1858         f.write("        {\n")
1859         f.write("            TRACE(\"Found name=%s in instance table\\n\", debugstr_a(name));\n")
1860         f.write("            return vk_instance_dispatch_table[i].func;\n")
1861         f.write("        }\n")
1862         f.write("    }\n")
1863         f.write("    return NULL;\n")
1864         f.write("}\n\n")
1866         # Create array of device extensions.
1867         f.write("static const char * const vk_device_extensions[] =\n{\n")
1868         for ext in self.registry.extensions:
1869             if ext["type"] != "device":
1870                 continue
1872             f.write("    \"{0}\",\n".format(ext["name"]))
1873         f.write("};\n\n")
1875         # Create array of instance extensions.
1876         f.write("static const char * const vk_instance_extensions[] =\n{\n")
1877         for ext in self.registry.extensions:
1878             if ext["type"] != "instance":
1879                 continue
1881             f.write("    \"{0}\",\n".format(ext["name"]))
1882         f.write("};\n\n")
1884         f.write("BOOL wine_vk_device_extension_supported(const char *name)\n")
1885         f.write("{\n")
1886         f.write("    unsigned int i;\n")
1887         f.write("    for (i = 0; i < ARRAY_SIZE(vk_device_extensions); i++)\n")
1888         f.write("    {\n")
1889         f.write("        if (strcmp(vk_device_extensions[i], name) == 0)\n")
1890         f.write("            return TRUE;\n")
1891         f.write("    }\n")
1892         f.write("    return FALSE;\n")
1893         f.write("}\n\n")
1895         f.write("BOOL wine_vk_instance_extension_supported(const char *name)\n")
1896         f.write("{\n")
1897         f.write("    unsigned int i;\n")
1898         f.write("    for (i = 0; i < ARRAY_SIZE(vk_instance_extensions); i++)\n")
1899         f.write("    {\n")
1900         f.write("        if (strcmp(vk_instance_extensions[i], name) == 0)\n")
1901         f.write("            return TRUE;\n")
1902         f.write("    }\n")
1903         f.write("    return FALSE;\n")
1904         f.write("}\n")
1906     def generate_thunks_h(self, f, prefix):
1907         f.write("/* Automatically generated from Vulkan vk.xml; DO NOT EDIT! */\n\n")
1909         f.write("#ifndef __WINE_VULKAN_THUNKS_H\n")
1910         f.write("#define __WINE_VULKAN_THUNKS_H\n\n")
1912         # Generate prototypes for device and instance functions requiring a custom implementation.
1913         f.write("/* Functions for which we have custom implementations outside of the thunks. */\n")
1914         for vk_func in self.registry.funcs.values():
1915             if not vk_func.is_required() or vk_func.is_global_func() or vk_func.needs_thunk():
1916                 continue
1918             if vk_func.is_core_func():
1919                 f.write("{0};\n".format(vk_func.prototype("WINAPI", prefix="wine_")))
1920             else:
1921                 f.write("{0};\n".format(vk_func.prototype("WINAPI", prefix="wine_", postfix="DECLSPEC_HIDDEN")))
1922         f.write("\n")
1924         for struct in self.host_structs:
1925             f.write(struct.definition(align=False, conv=True, postfix="_host"))
1926         f.write("\n")
1928         f.write("/* For use by vkDevice and children */\n")
1929         f.write("struct vulkan_device_funcs\n{\n")
1930         for vk_func in self.registry.device_funcs:
1931             if not vk_func.is_required():
1932                 continue
1934             if not vk_func.needs_dispatch():
1935                 LOGGER.debug("skipping {0} in vulkan_device_funcs".format(vk_func.name))
1936                 continue
1938             if vk_func.needs_conversion():
1939                 f.write("#if defined(USE_STRUCT_CONVERSION)\n")
1940                 f.write("    {0};\n".format(vk_func.pfn(conv=True)))
1941                 f.write("#else\n")
1942                 f.write("    {0};\n".format(vk_func.pfn(conv=False)))
1943                 f.write("#endif\n")
1944             else:
1945                 f.write("    {0};\n".format(vk_func.pfn(conv=False)))
1946         f.write("};\n\n")
1948         f.write("/* For use by vkInstance and children */\n")
1949         f.write("struct vulkan_instance_funcs\n{\n")
1950         for vk_func in self.registry.instance_funcs:
1951             if not vk_func.is_required():
1952                 continue
1954             if not vk_func.needs_dispatch():
1955                 LOGGER.debug("skipping {0} in vulkan_instance_funcs".format(vk_func.name))
1956                 continue
1958             if vk_func.needs_conversion():
1959                 f.write("#if defined(USE_STRUCT_CONVERSION)\n")
1960                 f.write("    {0};\n".format(vk_func.pfn(conv=True)))
1961                 f.write("#else\n")
1962                 f.write("    {0};\n".format(vk_func.pfn(conv=False)))
1963                 f.write("#endif\n")
1964             else:
1965                 f.write("    {0};\n".format(vk_func.pfn(conv=False)))
1966         f.write("};\n\n")
1968         f.write("#define ALL_VK_DEVICE_FUNCS() \\\n")
1969         first = True
1970         for vk_func in self.registry.device_funcs:
1971             if not vk_func.is_required():
1972                 continue
1974             if not vk_func.needs_dispatch():
1975                 LOGGER.debug("skipping {0} in ALL_VK_DEVICE_FUNCS".format(vk_func.name))
1976                 continue
1978             if first:
1979                 f.write("    USE_VK_FUNC({0})".format(vk_func.name))
1980                 first = False
1981             else:
1982                 f.write(" \\\n    USE_VK_FUNC({0})".format(vk_func.name))
1983         f.write("\n\n")
1985         f.write("#define ALL_VK_INSTANCE_FUNCS() \\\n")
1986         first = True
1987         for vk_func in self.registry.instance_funcs:
1988             if not vk_func.is_required():
1989                 continue
1991             if not vk_func.needs_dispatch():
1992                 LOGGER.debug("skipping {0} in ALL_VK_INSTANCE_FUNCS".format(vk_func.name))
1993                 continue
1995             if first:
1996                 f.write("    USE_VK_FUNC({0})".format(vk_func.name))
1997                 first = False
1998             else:
1999                 f.write(" \\\n    USE_VK_FUNC({0})".format(vk_func.name))
2000         f.write("\n\n")
2002         f.write("#endif /* __WINE_VULKAN_THUNKS_H */\n")
2004     def generate_vulkan_h(self, f):
2005         f.write("/* Automatically generated from Vulkan vk.xml; DO NOT EDIT! */\n\n")
2006         f.write("#ifndef __WINE_VULKAN_H\n")
2007         f.write("#define __WINE_VULKAN_H\n\n")
2009         f.write("#include <windef.h>\n")
2010         f.write("#include <stdint.h>\n\n")
2012         f.write("#ifndef VKAPI_CALL\n")
2013         f.write("#define VKAPI_CALL __stdcall\n")
2014         f.write("#endif\n\n")
2016         f.write("#ifndef VKAPI_PTR\n")
2017         f.write("#define VKAPI_PTR VKAPI_CALL\n")
2018         f.write("#endif\n\n")
2020         f.write("/* Callers can override WINE_VK_ALIGN if they want 'host' headers. */\n")
2021         f.write("#ifndef WINE_VK_ALIGN\n")
2022         f.write("#define WINE_VK_ALIGN DECLSPEC_ALIGN\n")
2023         f.write("#endif\n\n")
2025         # The overall strategy is to define independent constants and datatypes,
2026         # prior to complex structures and function calls to avoid forward declarations.
2027         for const in self.registry.consts:
2028             # For now just generate things we may not need. The amount of parsing needed
2029             # to get some of the info is tricky as you need to figure out which structure
2030             # references a certain constant.
2031             f.write(const.definition())
2032         f.write("\n")
2034         for define in self.registry.defines:
2035             f.write(define.definition())
2037         for handle in self.registry.handles:
2038             if handle.required:
2039                  f.write(handle.definition())
2040         f.write("\n")
2042         for base_type in self.registry.base_types:
2043             f.write(base_type.definition())
2044         f.write("\n")
2046         for bitmask in self.registry.bitmasks:
2047             f.write(bitmask.definition())
2048         f.write("\n")
2050         # Define enums, this includes values for some of the bitmask types as well.
2051         for enum in self.registry.enums.values():
2052             if enum.required:
2053                 f.write(enum.definition())
2055         for fp in self.registry.funcpointers:
2056             if fp.required:
2057                 f.write(fp.definition())
2058         f.write("\n")
2060         # This generates both structures and unions. Since structures
2061         # may depend on other structures/unions, we need a list of
2062         # decoupled structs.
2063         # Note: unions are stored in structs for dependency reasons,
2064         # see comment in parsing section.
2065         structs = VkStruct.decouple_structs(self.registry.structs)
2066         for struct in structs:
2067             LOGGER.debug("Generating struct: {0}".format(struct.name))
2068             f.write(struct.definition(align=True))
2070         for func in self.registry.funcs.values():
2071             if not func.is_required():
2072                 LOGGER.debug("Skipping PFN definition for: {0}".format(func.name))
2073                 continue
2075             f.write("typedef {0};\n".format(func.pfn(prefix="PFN", call_conv="VKAPI_PTR")))
2076         f.write("\n")
2078         f.write("#ifndef VK_NO_PROTOTYPES\n")
2079         for func in self.registry.funcs.values():
2080             if not func.is_required():
2081                 LOGGER.debug("Skipping API definition for: {0}".format(func.name))
2082                 continue
2084             LOGGER.debug("Generating API definition for: {0}".format(func.name))
2085             f.write("{0};\n".format(func.prototype(call_conv="VKAPI_CALL")))
2086         f.write("#endif /* VK_NO_PROTOTYPES */\n\n")
2088         f.write("#endif /* __WINE_VULKAN_H */\n")
2090     def generate_vulkan_driver_h(self, f):
2091         f.write("/* Automatically generated from Vulkan vk.xml; DO NOT EDIT! */\n\n")
2092         f.write("#ifndef __WINE_VULKAN_DRIVER_H\n")
2093         f.write("#define __WINE_VULKAN_DRIVER_H\n\n")
2095         f.write("/* Wine internal vulkan driver version, needs to be bumped upon vulkan_funcs changes. */\n")
2096         f.write("#define WINE_VULKAN_DRIVER_VERSION {0}\n\n".format(DRIVER_VERSION))
2098         f.write("struct vulkan_funcs\n{\n")
2099         f.write("    /* Vulkan global functions. These are the only calls at this point a graphics driver\n")
2100         f.write("     * needs to provide. Other function calls will be provided indirectly by dispatch\n")
2101         f.write("     * tables part of dispatchable Vulkan objects such as VkInstance or vkDevice.\n")
2102         f.write("     */\n")
2104         for vk_func in self.registry.funcs.values():
2105             if not vk_func.is_required() or not vk_func.is_driver_func():
2106                 continue
2108             pfn = vk_func.pfn()
2109             # Avoid PFN_vkVoidFunction in driver interface as Vulkan likes to put calling convention
2110             # stuff in there. For simplicity substitute with "void *".
2111             pfn = pfn.replace("PFN_vkVoidFunction", "void *")
2112             f.write("    {0};\n".format(pfn))
2113         f.write("};\n\n")
2115         f.write("extern const struct vulkan_funcs * CDECL __wine_get_vulkan_driver(HDC hdc, UINT version);\n\n")
2116         f.write("#endif /* __WINE_VULKAN_DRIVER_H */\n")
2118     def generate_vulkan_spec(self, f):
2119         f.write("# Automatically generated from Vulkan vk.xml; DO NOT EDIT!\n\n")
2120         f.write("@ stdcall vk_icdGetInstanceProcAddr(ptr str) wine_vk_icdGetInstanceProcAddr\n")
2121         f.write("@ stdcall vk_icdNegotiateLoaderICDInterfaceVersion(ptr) wine_vk_icdNegotiateLoaderICDInterfaceVersion\n")
2123         # Export symbols for all Vulkan Core functions.
2124         for func in self.registry.funcs.values():
2125             if not func.is_core_func():
2126                 continue
2128             # Not an ICD level function.
2129             if func.name == "vkEnumerateInstanceLayerProperties":
2130                 continue
2132             # We support all Core functions except for VK_KHR_display* APIs.
2133             # Create stubs for unsupported Core functions.
2134             if func.is_required():
2135                 f.write(func.spec(prefix="wine_"))
2136             else:
2137                 f.write("@ stub {0}\n".format(func.name))
2139     def generate_vulkan_loader_spec(self, f):
2140         f.write("# Automatically generated from Vulkan vk.xml; DO NOT EDIT!\n\n")
2142         # Export symbols for all Vulkan Core functions.
2143         for func in self.registry.funcs.values():
2144             if not func.is_core_func():
2145                 continue
2147             # We support all Core functions except for VK_KHR_display* APIs.
2148             # Create stubs for unsupported Core functions.
2149             if func.is_required():
2150                 # Global functions need a custom implementation, except for
2151                 # vkCreateInstance, which we can just forward.
2152                 if func.is_global_func() and func.name != "vkCreateInstance":
2153                     f.write(func.spec())
2154                 else:
2155                     f.write(func.spec(symbol="winevulkan.wine_" + func.name))
2156             else:
2157                 f.write("@ stub {0}\n".format(func.name))
2160 class VkRegistry(object):
2161     def __init__(self, reg_filename):
2162         # Used for storage of type information.
2163         self.base_types = None
2164         self.bitmasks = None
2165         self.consts = None
2166         self.defines = None
2167         self.enums = None
2168         self.funcpointers = None
2169         self.handles = None
2170         self.structs = None
2172         # We aggregate all types in here for cross-referencing.
2173         self.funcs = {}
2174         self.types = {}
2176         # Overall strategy for parsing the registry is to first
2177         # parse all type / function definitions. Then parse
2178         # features and extensions to decide which types / functions
2179         # to actually 'pull in' for code generation. For each type or
2180         # function call we want we set a member 'required' to True.
2181         tree = ET.parse(reg_filename)
2182         root = tree.getroot()
2183         self._parse_enums(root)
2184         self._parse_types(root)
2185         self._parse_commands(root)
2187         # Pull in any required types and functions.
2188         self._parse_features(root)
2189         self._parse_extensions(root)
2191     def _mark_command_required(self, command):
2192         """ Helper function to mark a certain command and the datatypes it needs as required."""
2193         def mark_bitmask_dependencies(bitmask, types):
2194             if bitmask.requires is not None:
2195                 types[bitmask.requires]["data"].required = True
2197         def mark_funcpointer_dependencies(fp, types):
2198             for m in fp.members:
2199                 type_info = types[m.type]
2201                 # Complex types have a matching definition e.g. VkStruct.
2202                 # Not needed for base types such as uint32_t.
2203                 if "data" in type_info:
2204                     types[m.type]["data"].required = True
2206         def mark_struct_dependencies(struct, types):
2207              for m in struct:
2208                 type_info = types[m.type]
2210                 # Complex types have a matching definition e.g. VkStruct.
2211                 # Not needed for base types such as uint32_t.
2212                 if "data" in type_info:
2213                     types[m.type]["data"].required = True
2215                 if type_info["category"] == "struct":
2216                     # Yay, recurse
2217                     mark_struct_dependencies(type_info["data"], types)
2218                 elif type_info["category"] == "funcpointer":
2219                     mark_funcpointer_dependencies(type_info["data"], types)
2220                 elif type_info["category"] == "bitmask":
2221                     mark_bitmask_dependencies(type_info["data"], types)
2223         func = self.funcs[command]
2224         func.required = True
2226         # Pull in return type
2227         if func.type != "void":
2228             self.types[func.type]["data"].required = True
2230         # Analyze parameter dependencies and pull in any type needed.
2231         for p in func.params:
2232             type_info = self.types[p.type]
2234             # Check if we are dealing with a complex type e.g. VkEnum, VkStruct and others.
2235             if "data" not in type_info:
2236                 continue
2238             # Mark the complex type as required.
2239             type_info["data"].required = True
2240             if type_info["category"] == "struct":
2241                 struct = type_info["data"]
2242                 mark_struct_dependencies(struct, self.types)
2244     def _parse_commands(self, root):
2245         """ Parse command section containing the Vulkan function calls. """
2246         funcs = {}
2247         commands = root.findall("./commands/")
2248         for command in commands:
2249             func = VkFunction.from_xml(command, self.types)
2250             funcs[func.name] = func
2252         # To make life easy for the code generation, separate all function
2253         # calls out in the 3 types of Vulkan functions: device, global and instance.
2254         device_funcs = []
2255         global_funcs = []
2256         instance_funcs = []
2257         for func in funcs.values():
2258             if func.is_device_func():
2259                 device_funcs.append(func)
2260             elif func.is_global_func():
2261                 global_funcs.append(func)
2262             else:
2263                 instance_funcs.append(func)
2265         # Sort function lists by name and store them.
2266         self.device_funcs = sorted(device_funcs, key=lambda func: func.name)
2267         self.global_funcs = sorted(global_funcs, key=lambda func: func.name)
2268         self.instance_funcs = sorted(instance_funcs, key=lambda func: func.name)
2270         # The funcs dictionary is used as a convenient way to lookup function
2271         # calls when needed e.g. to adjust member variables.
2272         self.funcs = OrderedDict(sorted(funcs.items()))
2274     def _parse_enums(self, root):
2275         """ Parse enums section or better described as constants section. """
2276         enums = {}
2277         self.consts = []
2278         for enum in root.findall("./enums"):
2279             name = enum.attrib.get("name")
2280             _type = enum.attrib.get("type")
2282             if _type in ("enum", "bitmask"):
2283                 enums[name] = VkEnum.from_xml(enum)
2284             else:
2285                 # If no type is set, we are dealing with API constants.
2286                 values = []
2287                 for value in enum.findall("enum"):
2288                     self.consts.append(VkConstant(value.attrib.get("name"), value.attrib.get("value")))
2290         self.enums = OrderedDict(sorted(enums.items()))
2292     def _parse_extensions(self, root):
2293         """ Parse extensions section and pull in any types and commands for this extensioin. """
2294         extensions = []
2295         exts = root.findall("./extensions/extension")
2296         for ext in exts:
2297             ext_name = ext.attrib["name"]
2299             # Set extension name on any functions calls part of this extension as we
2300             # were not aware of the name during initial parsing.
2301             commands = ext.findall("require/command")
2302             for command in commands:
2303                 cmd_name = command.attrib["name"]
2304                 self.funcs[cmd_name].extension = ext_name
2306             # Some extensions are not ready or have numbers reserved as a place holder.
2307             if ext.attrib["supported"] == "disabled":
2308                 LOGGER.debug("Skipping disabled extension: {0}".format(ext_name))
2309                 continue
2311             # Disable highly experimental extensions as the APIs are unstable and can
2312             # change between minor Vulkan revisions until API is final and becomes KHR
2313             # or NV.
2314             if "KHX" in ext_name or "NVX" in ext_name:
2315                 LOGGER.debug("Skipping experimental extension: {0}".format(ext_name))
2316                 continue
2318             # Instance extensions often require a custom implementation, so filter.
2319             ext_type = ext.attrib["type"]
2320             if ext_type == "instance" and not ext_name in SUPPORTED_INSTANCE_EXTENSIONS:
2321                 LOGGER.debug("Skipping instance extension: {0}".format(ext_name))
2322                 continue
2324             # We disable some extensions as either we haven't implemented
2325             # support yet or because they are for platforms other than win32.
2326             if ext_name in BLACKLISTED_EXTENSIONS:
2327                 LOGGER.debug("Skipping blacklisted extension: {0}".format(ext_name))
2328                 continue
2329             elif "requires" in ext.attrib:
2330                 # Check if this extension builds on top of another blacklisted
2331                 # extension.
2332                 requires = ext.attrib["requires"].split(",")
2333                 if len(set(requires).intersection(BLACKLISTED_EXTENSIONS)) > 0:
2334                     continue
2336             LOGGER.debug("Loading extension: {0}".format(ext_name))
2338             # Extensions can add enum values to Core / extension enums, so add these.
2339             enums = ext.findall("require/enum")
2340             for enum_elem in enums:
2341                 if "bitpos" in enum_elem.keys():
2342                     # We need to add an extra value to an existing enum type.
2343                     # E.g. VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG to VkFormatFeatureFlagBits.
2344                     type_name = enum_elem.attrib["extends"]
2345                     enum = self.types[type_name]["data"]
2346                     enum.add(VkEnumValue(enum_elem.attrib["name"], 1 << int(enum_elem.attrib["bitpos"]), hex=True))
2347                 elif "offset" in enum_elem.keys():
2348                     ext_number = int(ext.attrib["number"])
2349                     offset = int(enum_elem.attrib["offset"])
2350                     value = EXT_BASE + (ext_number - 1) * EXT_BLOCK_SIZE + offset
2352                     # Deal with negative values.
2353                     direction = enum_elem.attrib.get("dir")
2354                     if direction is not None:
2355                         value = -value
2357                     type_name = enum_elem.attrib["extends"]
2358                     enum = self.types[type_name]["data"]
2359                     enum.add(VkEnumValue(enum_elem.attrib["name"], value))
2361                 elif "value" in enum_elem.keys():
2362                     self.consts.append(VkConstant(enum_elem.attrib.get("name"), enum_elem.attrib.get("value")))
2363                     continue
2364                 else:
2365                     # This seems to be used to pull in constants e.g. VK_MAX_DEVICE_GROUP_KHX
2366                     continue
2368             # Store a list with extensions.
2369             ext_info = {"name" : ext_name, "type" : ext_type}
2370             extensions.append(ext_info)
2372             # Pull in any commands we need. We infer types to pull in from the command
2373             # as well.
2374             for command in commands:
2375                 cmd_name = command.attrib["name"]
2376                 self._mark_command_required(cmd_name)
2378         # Sort in alphabetical order.
2379         self.extensions = sorted(extensions, key=lambda ext: ext["name"])
2381     def _parse_features(self, root):
2382         """ Parse the feature section, which describes Core commands and types needed. """
2383         requires = root.findall("./feature/require")
2385         for require in requires:
2386             LOGGER.info("Including features for {0}".format(require.attrib.get("comment")))
2387             for tag in require:
2388                 # Only deal with command. Other values which appear are enum and type for pulling in some
2389                 # constants and macros. Tricky to parse, so don't bother right now, we will generate them
2390                 # anyway for now.
2391                 name = tag.attrib["name"]
2392                 if tag.tag == "command":
2393                     self._mark_command_required(name)
2394                 elif tag.tag == "enum":
2395                     # We could pull in relevant constants here. Unfortunately
2396                     # this only gets half of them pulled in as others indirectly
2397                     # get pulled in through structures. Constants don't harm us,
2398                     # so don't bother.
2399                     pass
2400                 elif tag.tag == "type":
2401                     # Pull in types which may not have been pulled in through commands.
2403                     # Skip pull in for vk_platform.h for now.
2404                     if name == "vk_platform":
2405                         continue
2407                     type_info = self.types[name]
2408                     type_info["data"].required = True
2410     def _parse_types(self, root):
2411         """ Parse types section, which contains all data types e.g. structs, typedefs etcetera. """
2412         types = root.findall("./types/type")
2414         base_types = []
2415         bitmasks = []
2416         defines = []
2417         funcpointers = []
2418         handles = []
2419         structs = []
2421         for t in types:
2422             type_info = {}
2423             type_info["category"] = t.attrib.get("category", None)
2425             if type_info["category"] in ["include"]:
2426                 continue
2428             if type_info["category"] == "basetype":
2429                 name = t.find("name").text
2430                 _type = t.find("type").text
2431                 basetype = VkBaseType(name, _type)
2432                 base_types.append(basetype)
2433                 type_info["data"] = basetype
2435             if type_info["category"] == "bitmask":
2436                 name = t.find("name").text
2437                 _type = t.find("type").text
2439                 # Most bitmasks have a requires attribute used to pull in
2440                 # required '*FlagBits" enum.
2441                 requires = t.attrib.get("requires")
2442                 bitmask = VkBaseType(name, _type, requires=requires)
2443                 bitmasks.append(bitmask)
2444                 type_info["data"] = bitmask
2446             if type_info["category"] == "define":
2447                 name = t.attrib.get("name")
2448                 define = VkDefine.from_xml(t)
2449                 defines.append(define)
2450                 type_info["data"] = define
2452             if type_info["category"] == "enum":
2453                 name = t.attrib.get("name")
2454                 # The type section only contains enum names, not the actual definition.
2455                 # Since we already parsed the enum before, just link it in.
2456                 try:
2457                     type_info["data"] = self.enums[name]
2458                 except KeyError as e:
2459                     # Not all enums seem to be defined yet, typically that's for
2460                     # ones ending in 'FlagBits' where future extensions may add
2461                     # definitions.
2462                     type_info["data"] = None
2464             if type_info["category"] == "funcpointer":
2465                 funcpointer = VkFunctionPointer.from_xml(t)
2466                 funcpointers.append(funcpointer)
2467                 type_info["data"] = funcpointer
2469             if type_info["category"] == "handle":
2470                 handle = VkHandle.from_xml(t)
2471                 handles.append(handle)
2472                 type_info["data"] = handle
2474             if type_info["category"] in ["struct", "union"]:
2475                 # We store unions among structs as some structs depend
2476                 # on unions. The types are very similar in parsing and
2477                 # generation anyway. The official Vulkan scripts use
2478                 # a similar kind of hack.
2479                 struct = VkStruct.from_xml(t)
2480                 structs.append(struct)
2481                 type_info["data"] = struct
2483             # Name is in general within a name tag else it is an optional
2484             # attribute on the type tag.
2485             name_elem = t.find("name")
2486             if name_elem is not None:
2487                 type_info["name"] = name_elem.text
2488             else:
2489                 type_info["name"] = t.attrib.get("name", None)
2491             # Store all type data in a shared dictionary, so we can easily
2492             # look up information for a given type. There are no duplicate
2493             # names.
2494             self.types[type_info["name"]] = type_info
2496         # We need detailed type information during code generation
2497         # on structs for alignment reasons. Unfortunately structs
2498         # are parsed among other types, so there is no guarantee
2499         # that any types needed have been parsed already, so set
2500         # the data now.
2501         for struct in structs:
2502             struct.set_type_info(self.types)
2504         # Guarantee everything is sorted, so code generation doesn't have
2505         # to deal with this.
2506         self.base_types = sorted(base_types, key=lambda base_type: base_type.name)
2507         self.bitmasks = sorted(bitmasks, key=lambda bitmask: bitmask.name)
2508         self.defines = defines
2509         self.funcpointers = sorted(funcpointers, key=lambda fp: fp.name)
2510         self.handles = sorted(handles, key=lambda handle: handle.name)
2511         self.structs = sorted(structs, key=lambda struct: struct.name)
2514 def main():
2515     parser = argparse.ArgumentParser()
2516     parser.add_argument("-v", "--verbose", action="count", default=0, help="increase output verbosity")
2518     args = parser.parse_args()
2519     if args.verbose == 0:
2520         LOGGER.setLevel(logging.WARNING)
2521     elif args.verbose == 1:
2522         LOGGER.setLevel(logging.INFO)
2523     else: # > 1
2524         LOGGER.setLevel(logging.DEBUG)
2526     registry = VkRegistry("vk.xml")
2527     generator = VkGenerator(registry)
2529     with open(WINE_VULKAN_H, "w") as f:
2530         generator.generate_vulkan_h(f)
2532     with open(WINE_VULKAN_DRIVER_H, "w") as f:
2533         generator.generate_vulkan_driver_h(f)
2535     with open(WINE_VULKAN_THUNKS_H, "w") as f:
2536         generator.generate_thunks_h(f, "wine_")
2538     with open(WINE_VULKAN_THUNKS_C, "w") as f:
2539         generator.generate_thunks_c(f, "wine_")
2541     with open(WINE_VULKAN_SPEC, "w") as f:
2542         generator.generate_vulkan_spec(f)
2544     with open(WINE_VULKAN_LOADER_SPEC, "w") as f:
2545         generator.generate_vulkan_loader_spec(f)
2547 if __name__ == "__main__":
2548     main()