winevulkan: Export symbols for Core Vulkan functions.
[wine.git] / dlls / winevulkan / make_vulkan
blob7c4dc348bead24691910c5925e3b99ab914d5fd1
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_SPEC = "winevulkan.spec"
69 WINE_VULKAN_THUNKS_C = "vulkan_thunks.c"
70 WINE_VULKAN_THUNKS_H = "vulkan_thunks.h"
72 # Extension enum values start at a certain offset (EXT_BASE).
73 # Relative to the offset each extension has a block (EXT_BLOCK_SIZE)
74 # of values.
75 # Start for a given extension is:
76 # EXT_BASE + (extension_number-1) * EXT_BLOCK_SIZE
77 EXT_BASE = 1000000000
78 EXT_BLOCK_SIZE = 1000
80 # In general instance extensions can't be automatically generated
81 # and need custom wrappers due to e.g. win32 / X11 specific code.
82 # List of supported instance extensions.
83 SUPPORTED_INSTANCE_EXTENSIONS = [
84     "VK_KHR_get_physical_device_properties2",
85     "VK_KHR_surface",
86     "VK_KHR_win32_surface",
89 BLACKLISTED_EXTENSIONS = [
90     # Handling of VK_EXT_debug_report requires some consideration. The win32
91     # loader already provides it for us and it is somewhat usable. . If we add
92     # plumbing down to the native layer, we will get each message twice as we
93     # use 2 loaders (win32+native), but we may get output from the driver.
94     # In any case callback conversion is required.
95     "VK_EXT_debug_report",
96     "VK_EXT_display_control", # Requires VK_EXT_display_surface_counter
97     "VK_EXT_hdr_metadata", # Needs WSI work.
98     "VK_GOOGLE_display_timing",
99     "VK_KHR_display", # Needs WSI work.
100     "VK_KHR_external_fence_fd",
101     "VK_KHR_external_fence_win32",
102     "VK_KHR_external_memory",
103     "VK_KHR_external_semaphore",
104     # Relates to external_semaphore and needs type conversions in bitflags.
105     "VK_KHR_external_semaphore_capabilities",
106     "VK_KHR_shared_presentable_image", # Needs WSI work.
107     "VK_NV_external_memory_win32"
110 # The Vulkan loader provides entry-points for core functionality and important
111 # extensions. Based on vulkan-1.def this amounts to WSI extensions on 1.0.51.
112 CORE_EXTENSIONS = [
113     "VK_KHR_display",
114     "VK_KHR_display_swapchain",
115     "VK_KHR_surface",
116     "VK_KHR_swapchain",
117     "VK_KHR_win32_surface"
120 # Functions part of our winevulkan graphics driver interface.
121 # DRIVER_VERSION should be bumped on any change to driver interface
122 # in FUNCTION_OVERRIDES
123 DRIVER_VERSION = 3
125 # Table of functions for which we have a special implementation.
126 # This are regular device / instance functions for which we need
127 # to more work compared to a regular thunk  or because they are
128 # part of the driver interface.
129 # - dispatch set whether we need a function pointer in the device
130 #   / instance dispatch table.
131 # - driver sets whether the api is part of the driver interface.
132 # - thunk sets whether to create a thunk in vulkan_thunks.c.
133 FUNCTION_OVERRIDES = {
134     # Global functions
135     "vkCreateInstance" : {"dispatch" : False, "driver" : True, "thunk" : False},
136     "vkEnumerateInstanceExtensionProperties" : {"dispatch" : False, "driver" : True, "thunk" : False},
137     "vkGetInstanceProcAddr": {"dispatch" : False, "driver" : True, "thunk" : False},
139     # Instance functions
140     "vkCreateDevice" : {"dispatch" : True, "driver" : False, "thunk" : False},
141     "vkDestroyInstance" : {"dispatch" : False, "driver" : True, "thunk" : False },
142     "vkEnumerateDeviceExtensionProperties" : {"dispatch" : True, "driver" : False, "thunk" : False},
143     "vkEnumeratePhysicalDevices" : {"dispatch" : True, "driver" : False, "thunk" : False},
145     # Device functions
146     "vkAllocateCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : False},
147     "vkCmdExecuteCommands" : {"dispatch" : True, "driver" : False, "thunk" : False},
148     "vkDestroyDevice" : {"dispatch" : True, "driver" : False, "thunk" : False},
149     "vkFreeCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : False},
150     "vkGetDeviceProcAddr" : {"dispatch" : False, "driver" : True, "thunk" : False},
151     "vkGetDeviceQueue" : {"dispatch": True, "driver" : False, "thunk" : False},
152     "vkQueueSubmit" : {"dispatch": True, "driver" : False, "thunk" : False},
154     # VK_KHR_surface
155     "vkDestroySurfaceKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
156     "vkGetPhysicalDeviceSurfaceSupportKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
157     "vkGetPhysicalDeviceSurfaceCapabilitiesKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
158     "vkGetPhysicalDeviceSurfaceFormatsKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
159     "vkGetPhysicalDeviceSurfacePresentModesKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
161     # VK_KHR_win32_surface
162     "vkCreateWin32SurfaceKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
163     "vkGetPhysicalDeviceWin32PresentationSupportKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
165     # VK_KHR_swapchain
166     "vkAcquireNextImageKHR": {"dispatch" : True, "driver" : True, "thunk" : True},
167     "vkCreateSwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
168     "vkDestroySwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
169     "vkGetSwapchainImagesKHR": {"dispatch" : True, "driver" : True, "thunk" : True},
170     "vkQueuePresentKHR": {"dispatch" : True, "driver" : True, "thunk" : True},
174 class Direction(Enum):
175     """ Parameter direction: input, output, input_output. """
176     INPUT = 1
177     OUTPUT = 2
178     INPUT_OUTPUT = 3
181 class VkBaseType(object):
182     def __init__(self, name, _type, requires=None):
183         """ Vulkan base type class.
185         VkBaseType is mostly used by Vulkan to define its own
186         base types like VkFlags through typedef out of e.g. uint32_t.
188         Args:
189             name (:obj:'str'): Name of the base type.
190             _type (:obj:'str'): Underlaying type
191             requires (:obj:'str', optional): Other types required.
192                 Often bitmask values pull in a *FlagBits type.
193         """
194         self.name = name
195         self.type = _type
196         self.requires = requires
197         self.required = False
199     def definition(self):
200         text = "typedef {0} {1};\n".format(self.type, self.name)
201         return text
204 class VkConstant(object):
205     def __init__(self, name, value):
206         self.name = name
207         self.value = value
209     def definition(self):
210         text = "#define {0} {1}\n".format(self.name, self.value)
211         return text
214 class VkDefine(object):
215     def __init__(self, name, value):
216         self.name = name
217         self.value = value
219     @staticmethod
220     def from_xml(define):
221         name_elem = define.find("name")
223         if name_elem is None:
224             # <type category="define" name="some_name">some_value</type>
225             # At the time of writing there is only 1 define of this category
226             # 'VK_DEFINE_NON_DISPATCHABLE_HANDLE'.
227             name = define.attrib.get("name")
229             # We override behavior of VK_DEFINE_NON_DISPATCHABLE handle as the default
230             # definition various between 64-bit (uses pointers) and 32-bit (uses uint64_t).
231             # This complicates TRACEs in the thunks, so just use uint64_t.
232             if name == "VK_DEFINE_NON_DISPATCHABLE_HANDLE":
233                 value = "#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object;"
234             else:
235                 value = define.text
236             return VkDefine(name, value)
238         # With a name element the structure is like:
239         # <type category="define"><name>some_name</name>some_value</type>
240         name = name_elem.text
242         # VK_API_VERSION is a deprecated constant and we don't really want to parse it or generate
243         # code for it. However the vk.xml feature section still references it.
244         if name == "VK_API_VERSION":
245             return VkDefine(name, "")
247         # The body of the define is basically unstructured C code. It is not meant for easy parsing.
248         # Some lines contain deprecated values or comments, which we try to filter out.
249         value = ""
250         for line in define.text.splitlines():
251             # Skip comments or deprecated values.
252             if "//" in line:
253                 continue
254             value += line
256         for child in define:
257             value += child.text
258             if child.tail is not None:
259                 value += child.tail
261         return VkDefine(name, value.rstrip(' '))
263     def definition(self):
264         if self.value is None:
265             return ""
267         # Nothing to do as the value was already put in the right form during parsing.
268         return "{0}\n".format(self.value)
271 class VkEnum(object):
272     def __init__(self, name, values):
273         self.name = name
274         self.values = values
275         self.required = False
277     @staticmethod
278     def from_xml(enum):
279         name = enum.attrib.get("name")
280         values = []
282         for v in enum.findall("enum"):
283             # Value is either a value or a bitpos, only one can exist.
284             value = v.attrib.get("value")
285             if value is None:
286                 # bitmask
287                 value = 1 << int(v.attrib.get("bitpos"))
288                 values.append(VkEnumValue(v.attrib.get("name"), value, hex=True))
289             else:
290                 # Some values are in hex form. We want to preserve the hex representation
291                 # at least when we convert back to a string. Internally we want to use int.
292                 if "0x" in value:
293                     values.append(VkEnumValue(v.attrib.get("name"), int(value, 0), hex=True))
294                 else:
295                     values.append(VkEnumValue(v.attrib.get("name"), int(value, 0)))
297         # vulkan.h contains a *_MAX_ENUM value set to 32-bit at the time of writing,
298         # which is to prepare for extensions as they can add values and hence affect
299         # the size definition.
300         max_name = re.sub(r'([0-9a-z_])([A-Z0-9])',r'\1_\2',name).upper() + "_MAX_ENUM"
301         values.append(VkEnumValue(max_name, 0x7fffffff, hex=True))
303         return VkEnum(name, values)
305     def add(self, value):
306         """ Add a value to enum. """
307         self.values.append(value)
309     def definition(self):
310         text = "typedef enum {0}\n{{\n".format(self.name)
312         # Print values sorted, values can have been added in a random order.
313         values = sorted(self.values, key=lambda value: value.value)
314         for value in values:
315             text += "    {0},\n".format(value.definition())
316         text += "}} {0};\n\n".format(self.name)
317         return text
320 class VkEnumValue(object):
321     def __init__(self, name, value, hex=False):
322         self.name = name
323         self.value = value
324         self.hex = hex
326     def __repr__(self):
327         return "{0}={1}".format(self.name, self.value)
329     def definition(self):
330         """ Convert to text definition e.g. VK_FOO = 1 """
332         # Hex is commonly used for FlagBits and sometimes within
333         # a non-FlagBits enum for a bitmask value as well.
334         if self.hex:
335             return "{0} = 0x{1:08x}".format(self.name, self.value)
336         else:
337             return "{0} = {1}".format(self.name, self.value)
340 class VkFunction(object):
341     def __init__(self, _type=None, name=None, params=[], extension=None):
342         self.extension = extension
343         self.name = name
344         self.type = _type
345         self.params = params
347         # For some functions we need some extra metadata from FUNCTION_OVERRIDES.
348         func_info = FUNCTION_OVERRIDES.get(self.name, None)
349         self.dispatch = func_info["dispatch"] if func_info is not None else True
350         self.driver = func_info["driver"] if func_info is not None else False
351         self.thunk_needed = func_info["thunk"] if func_info is not None else True
353         # Required is set while parsing which APIs and types are required
354         # and is used by the code generation.
355         self.required = False
357     @staticmethod
358     def from_xml(command, types):
359         proto = command.find("proto")
361         func_name = proto.find("name").text
362         func_type = proto.find("type").text
364         params = []
365         for param in command.findall("param"):
366             vk_param = VkParam.from_xml(param, types)
367             params.append(vk_param)
369         return VkFunction(_type=func_type, name=func_name, params=params)
371     def get_conversions(self):
372         """ Get a list of conversion functions required for this function if any.
373         Parameters which are structures may require conversion between win32
374         and the host platform. This function returns a list of conversions
375         required.
376         """
378         conversions = []
379         for param in self.params:
380             convs = param.get_conversions()
381             if convs is not None:
382                 conversions.extend(convs)
384         return conversions
386     def is_core_func(self):
387         """ Returns whether the function is a Vulkan core function.
388         Core functions are APIs defined by the Vulkan spec to be part of the
389         Core API as well as several KHR WSI extensions.
390         """
392         if self.extension is None:
393             return True
395         if self.extension in CORE_EXTENSIONS:
396             return True
398         return False
400     def is_device_func(self):
401         # If none of the other, it must be a device function
402         return not self.is_global_func() and not self.is_instance_func()
404     def is_driver_func(self):
405         """ Returns if function is part of Wine driver interface. """
406         return self.driver
408     def is_global_func(self):
409         # Treat vkGetInstanceProcAddr as a global function as it
410         # can operate with NULL for vkInstance.
411         if self.name == "vkGetInstanceProcAddr":
412             return True
413         # Global functions are not passed a dispatchable object.
414         elif self.params[0].is_dispatchable():
415             return False
416         return True
418     def is_instance_func(self):
419         # Instance functions are passed VkInstance or VkPhysicalDevice.
420         if self.params[0].type in ["VkInstance", "VkPhysicalDevice"]:
421             return True
422         return False
424     def is_required(self):
425         return self.required
427     def needs_conversion(self):
428         """ Check if the function needs any input/output type conversion.
429         Functions need input/output conversion if struct parameters have
430         alignment differences between Win32 and Linux 32-bit.
431         """
433         for p in self.params:
434             if p.needs_conversion():
435                 LOGGER.debug("Parameter {0} to {1} requires conversion".format(p.name, self.name))
436                 return True
438         return False
440     def needs_dispatch(self):
441         return self.dispatch
443     def needs_thunk(self):
444         return self.thunk_needed
446     def pfn(self, call_conv=None, conv=False):
447         """ Create function pointer. """
449         if call_conv is not None:
450             pfn = "{0} ({1} *p_{2})(".format(self.type, call_conv, self.name)
451         else:
452             pfn = "{0} (*p_{1})(".format(self.type, self.name)
454         for i, param in enumerate(self.params):
455             if param.const:
456                 pfn += param.const + " "
458             pfn += param.type
459             if conv and param.needs_conversion():
460                 pfn += "_host"
462             if param.is_pointer():
463                 pfn += " " + param.pointer
465             if param.array_len is not None:
466                 pfn += "[{0}]".format(param.array_len)
468             if i < len(self.params) - 1:
469                 pfn += ", "
470         pfn += ")"
471         return pfn
473     def prototype(self, call_conv=None, prefix=None, postfix=None):
474         """ Generate prototype for given function.
476         Args:
477             call_conv (str, optional): calling convention e.g. WINAPI
478             prefix (str, optional): prefix to append prior to function name e.g. vkFoo -> wine_vkFoo
479             postfix (str, optional): text to append after function name but prior to semicolon e.g. DECLSPEC_HIDDEN
480         """
482         proto = "{0}".format(self.type)
484         if call_conv is not None:
485             proto += " {0}".format(call_conv)
487         if prefix is not None:
488             proto += " {0}{1}(".format(prefix, self.name)
489         else:
490             proto += " {0}(".format(self.name)
492         # Add all the parameters.
493         proto += ", ".join([p.definition() for p in self.params])
495         if postfix is not None:
496             proto += ") {0}".format(postfix)
497         else:
498             proto += ")"
500         return proto
502     def body(self):
503         body = "    {0}".format(self.trace())
505         params = ", ".join([p.variable(conv=False) for p in self.params])
507         # Call the native Vulkan function.
508         if self.type == "void":
509             body += "    {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
510         else:
511             body += "    return {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
513         return body
515     def body_conversion(self):
516         body = ""
518         # Declare a variable to hold the result for non-void functions.
519         if self.type != "void":
520             body += "    {0} result;\n".format(self.type)
522         # Declare any tmp parameters for conversion.
523         for p in self.params:
524             if not p.needs_conversion():
525                 continue
527             if p.is_dynamic_array():
528                 body += "    {0}_host *{1}_host;\n".format(p.type, p.name)
529             else:
530                 body += "    {0}_host {1}_host;\n".format(p.type, p.name)
532         body += "    {0}\n".format(self.trace())
534         # Call any win_to_host conversion calls.
535         for p in self.params:
536             if not p.needs_input_conversion():
537                 continue
539             body += p.copy(Direction.INPUT)
541         # Build list of parameters containing converted and non-converted parameters.
542         # The param itself knows if conversion is needed and applies it when we set conv=True.
543         params = ", ".join([p.variable(conv=True) for p in self.params])
545         # Call the native Vulkan function.
546         if self.type == "void":
547             body += "    {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
548         else:
549             body += "    result = {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
551         body += "\n"
553         # Call any host_to_win conversion calls.
554         for p in self.params:
555             if not p.needs_output_conversion():
556                 continue
558             body += p.copy(Direction.OUTPUT)
560         # Perform any required cleanups. Most of these are for array functions.
561         for p in self.params:
562             if not p.needs_free():
563                 continue
565             body += p.free()
567         # Finally return the result.
568         if self.type != "void":
569             body += "    return result;\n"
571         return body
573     def spec(self, prefix=None):
574         """ Generate spec file entry for this function.
576         Args
577             prefix (str, optional): prefix to prepend to entry point name.
578         """
580         params = " ".join([p.spec() for p in self.params])
581         if prefix is not None:
582             return "@ stdcall {0}{1}({2})\n".format(prefix, self.name, params)
583         else:
584             return "@ stdcall {0}({1})\n".format(self.name, params)
586     def stub(self, call_conv=None, prefix=None):
587         stub = self.prototype(call_conv=call_conv, prefix=prefix)
588         stub += "\n{\n"
589         stub += "    {0}".format(self.trace(message="stub: ", trace_func="FIXME"))
591         if self.type == "VkResult":
592             stub += "    return VK_ERROR_OUT_OF_HOST_MEMORY;\n"
593         elif self.type == "VkBool32":
594             stub += "    return VK_FALSE;\n"
595         elif self.type == "PFN_vkVoidFunction":
596             stub += "    return NULL;\n"
598         stub += "}\n\n"
599         return stub
601     def thunk(self, call_conv=None, prefix=None):
602         thunk = self.prototype(call_conv=call_conv, prefix=prefix)
603         thunk += "\n{\n"
605         if self.needs_conversion():
606             thunk += "#if defined(USE_STRUCT_CONVERSION)\n"
607             thunk += self.body_conversion()
608             thunk += "#else\n"
609             thunk += self.body()
610             thunk += "#endif\n"
611         else:
612             thunk += self.body()
614         thunk += "}\n\n"
615         return thunk
617     def trace(self, message=None, trace_func=None):
618         """ Create a trace string including all parameters.
620         Args:
621             message (str, optional): text to print at start of trace message e.g. 'stub: '
622             trace_func (str, optional): used to override trace function e.g. FIXME, printf, etcetera.
623         """
624         if trace_func is not None:
625             trace = "{0}(\"".format(trace_func)
626         else:
627             trace = "TRACE(\""
629         if message is not None:
630             trace += message
632         # First loop is for all the format strings.
633         trace += ", ".join([p.format_string() for p in self.params])
634         trace += "\\n\""
636         # Second loop for parameter names and optional conversions.
637         for param in self.params:
638             if param.format_conv is not None:
639                 trace += ", " + param.format_conv.format(param.name)
640             else:
641                 trace += ", {0}".format(param.name)
642         trace += ");\n"
644         return trace
647 class VkFunctionPointer(object):
648     def __init__(self, _type, name, members):
649         self.name = name
650         self.members = members
651         self.type = _type
652         self.required = False
654     @staticmethod
655     def from_xml(funcpointer):
656         members = []
657         begin = None
659         for t in funcpointer.findall("type"):
660             # General form:
661             # <type>void</type>*       pUserData,
662             # Parsing of the tail (anything past </type>) is tricky since there
663             # can be other data on the next line like: const <type>int</type>..
664             const = begin
665             _type = t.text
666             lines = t.tail.split(",\n")
667             if lines[0][0] == "*":
668                 pointer = "*"
669                 name = lines[0][1:].strip()
670             else:
671                 pointer = None
672                 name = lines[0].strip()
674             # Filter out ); if it is contained.
675             name = name.partition(");")[0]
677             # If tail encompasses multiple lines, assign the second line to begin
678             # for the next line.
679             try:
680                 begin = lines[1].strip()
681             except IndexError:
682                 begin = None
684             members.append(VkMember(const=const, _type=_type, pointer=pointer, name=name))
686         _type = funcpointer.text
687         name = funcpointer.find("name").text
688         return VkFunctionPointer(_type, name, members)
690     def definition(self):
691         text = "{0} {1})(\n".format(self.type, self.name)
693         first = True
694         if len(self.members) > 0:
695             for m in self.members:
696                 if first:
697                     text += "    " + m.definition()
698                     first = False
699                 else:
700                     text += ",\n    " + m.definition()
701         else:
702             # Just make the compiler happy by adding a void parameter.
703             text += "void"
704         text += ");\n"
705         return text
708 class VkHandle(object):
709     def __init__(self, name, _type, parent):
710         self.name = name
711         self.type = _type
712         self.parent = parent
713         self.required = False
715     @staticmethod
716     def from_xml(handle):
717         name = handle.find("name").text
718         _type = handle.find("type").text
719         parent = handle.attrib.get("parent") # Most objects have a parent e.g. VkQueue has VkDevice.
720         return VkHandle(name, _type, parent)
722     def dispatch_table(self):
723         if not self.is_dispatchable():
724             return None
726         if self.parent is None:
727             # Should only happen for VkInstance
728             return "funcs"
729         elif self.name == "VkDevice":
730             # VkDevice has VkInstance as a parent, but has its own dispatch table.
731             return "funcs"
732         elif self.parent in ["VkInstance", "VkPhysicalDevice"]:
733             return "instance->funcs"
734         elif self.parent in ["VkDevice", "VkCommandPool"]:
735             return "device->funcs"
736         else:
737             LOGGER.error("Unhandled dispatchable parent: {0}".format(self.parent))
739     def definition(self):
740         """ Generates handle definition e.g. VK_DEFINE_HANDLE(vkInstance) """
741         return "{0}({1})\n".format(self.type, self.name)
743     def is_dispatchable(self):
744         """ Some handles like VkInstance, VkDevice are dispatchable objects,
745         which means they contain a dispatch table of function pointers.
746         """
747         return self.type == "VK_DEFINE_HANDLE"
749     def native_handle(self):
750         """ Provide access to the native handle of a dispatchable object.
752         Dispatchable objects wrap an underlying 'native' object.
753         This method provides access to the native object.
754         """
755         if not self.is_dispatchable():
756             return None
758         if self.name == "VkCommandBuffer":
759             return "command_buffer"
760         elif self.name == "VkDevice":
761             return "device"
762         elif self.name == "VkInstance":
763             return "instance"
764         elif self.name == "VkPhysicalDevice":
765             return "phys_dev"
766         elif self.name == "VkQueue":
767             return "queue"
768         else:
769             LOGGER.error("Unhandled native handle for: {0}".format(self.name))
772 class VkMember(object):
773     def __init__(self, const=None, _type=None, pointer=None, name=None, array_len=None, dyn_array_len=None, optional=False,
774             extension_structs=None):
775         self.const = const
776         self.name = name
777         self.pointer = pointer
778         self.type = _type
779         self.type_info = None
780         self.array_len = array_len
781         self.dyn_array_len = dyn_array_len
782         self.optional = optional
783         self.extension_structs = extension_structs
785     def __eq__(self, other):
786         """ Compare member based on name against a string.
788         This method is for convenience by VkStruct, which holds a number of members and needs quick checking
789         if certain members exist.
790         """
792         if self.name == other:
793             return True
795         return False
797     def __repr__(self):
798         return "{0} {1} {2} {3} {4} {5}".format(self.const, self.type, self.pointer, self.name, self.array_len,
799                 self.dyn_array_len)
801     @staticmethod
802     def from_xml(member):
803         """ Helper function for parsing a member tag within a struct or union. """
805         name_elem = member.find("name")
806         type_elem = member.find("type")
808         const = member.text.strip() if member.text else None
809         member_type = None
810         pointer = None
811         array_len = None
813         if type_elem is not None:
814             member_type = type_elem.text
815             if type_elem.tail is not None:
816                 pointer = type_elem.tail.strip() if type_elem.tail.strip() != "" else None
818         # Name of other member within, which stores the number of
819         # elements pointed to be by this member.
820         dyn_array_len = member.get("len", None)
822         if "validextensionstructs" in member.attrib:
823             extension_structs = member.get("validextensionstructs").split(",")
824         else:
825             extension_structs = None
827         # Some members are optional, which is important for conversion code e.g. not dereference NULL pointer.
828         optional = True if member.get("optional") else False
830         # Usually we need to allocate memory for dynamic arrays. We need to do the same in a few other cases
831         # like for VkCommandBufferBeginInfo.pInheritanceInfo. Just threat such cases as dynamic arrays of
832         # size 1 to simplify code generation.
833         if dyn_array_len is None and pointer is not None:
834             dyn_array_len = 1
836         # Some members are arrays, attempt to parse these. Formats include:
837         # <member><type>char</type><name>extensionName</name>[<enum>VK_MAX_EXTENSION_NAME_SIZE</enum>]</member>
838         # <member><type>uint32_t</type><name>foo</name>[4]</member>
839         if name_elem.tail and name_elem.tail[0] == '[':
840             LOGGER.debug("Found array type")
841             enum_elem = member.find("enum")
842             if enum_elem is not None:
843                 array_len = enum_elem.text
844             else:
845                 # Remove brackets around length
846                 array_len = name_elem.tail.strip("[]")
848         return VkMember(const=const, _type=member_type, pointer=pointer, name=name_elem.text, array_len=array_len,
849                 dyn_array_len=dyn_array_len, optional=optional, extension_structs=extension_structs)
851     def copy(self, input, output, direction):
852         """ Helper method for use by conversion logic to generate a C-code statement to copy this member. """
854         if self.needs_conversion():
855             if self.is_dynamic_array():
856                 if direction == Direction.OUTPUT:
857                     LOGGER.warn("TODO: implement copying of returnedonly dynamic array for {0}.{1}".format(self.type, self.name))
858                 else:
859                     # Array length is either a variable name (string) or an int.
860                     count = self.dyn_array_len if isinstance(self.dyn_array_len, int) else "{0}{1}".format(input, self.dyn_array_len)
861                     return "{0}{1} = convert_{2}_array_win_to_host({3}{1}, {4});\n".format(output, self.name, self.type, input, count)
862             elif self.is_static_array():
863                 count = self.array_len
864                 if direction == Direction.OUTPUT:
865                     # Needed by VkMemoryHeap.memoryHeaps
866                     return "convert_{0}_static_array_host_to_win({2}{1}, {3}{1}, {4});\n".format(self.type, self.name, input, output, count)
867                 else:
868                     # Nothing needed this yet.
869                     LOGGER.warn("TODO: implement copying of static array for {0}.{1}".format(self.type, self.name))
870             else:
871                 if direction == Direction.OUTPUT:
872                     return "convert_{0}_host_to_win(&{2}{1}, &{3}{1});\n".format(self.type, self.name, input, output)
873                 else:
874                     return "convert_{0}_win_to_host(&{2}{1}, &{3}{1});\n".format(self.type, self.name, input, output)
875         elif self.is_static_array():
876             bytes_count = "{0} * sizeof({1})".format(self.array_len, self.type)
877             return "memcpy({0}{1}, {2}{1}, {3});\n".format(output, self.name, input, bytes_count)
878         else:
879             return "{0}{1} = {2}{1};\n".format(output, self.name, input)
881     def definition(self, align=False, conv=False):
882         """ Generate prototype for given function.
884         Args:
885             align (bool, optional): Enable alignment if a type needs it. This adds WINE_VK_ALIGN(8) to a member.
886             conv (bool, optional): Enable conversion if a type needs it. This appends '_host' to the name.
887         """
889         text = ""
890         if self.is_const():
891             text += "const "
893         if conv and self.is_struct():
894             text += "{0}_host".format(self.type)
895         else:
896             text += self.type
898         if self.is_pointer():
899             text += " {0}{1}".format(self.pointer, self.name)
900         else:
901             if align and self.needs_alignment():
902                 text += " WINE_VK_ALIGN(8) " + self.name
903             else:
904                 text += " " + self.name
906         if self.is_static_array():
907             text += "[{0}]".format(self.array_len)
909         return text
911     def get_conversions(self):
912         """ Return any conversion description for this member and its children when conversion is needed. """
914         # Check if we need conversion either for this member itself or for any child members
915         # in case member represents a struct.
916         if not self.needs_conversion():
917             return None
919         conversions = []
921         # Collect any conversion for any member structs.
922         struct = self.type_info["data"]
923         for m in struct:
924             if m.needs_conversion():
925                 conversions.extend(m.get_conversions())
927         struct = self.type_info["data"]
928         direction = Direction.OUTPUT if struct.returnedonly else Direction.INPUT
929         if self.is_dynamic_array():
930             conversions.append(ConversionFunction(False, True, direction, struct))
931         elif self.is_static_array():
932             conversions.append(ConversionFunction(True, False, direction, struct))
933         else:
934             conversions.append(ConversionFunction(False, False, direction, struct))
936         if self.needs_free():
937             conversions.append(FreeFunction(self.is_dynamic_array(), struct))
939         return conversions
941     def is_const(self):
942         return self.const is not None
944     def is_dynamic_array(self):
945         """ Returns if the member is an array element.
946         Vulkan uses this for dynamically sized arrays for which
947         there is a 'count' parameter.
948         """
949         return self.dyn_array_len is not None
951     def is_handle(self):
952         return self.type_info["category"] == "handle"
954     def is_pointer(self):
955         return self.pointer is not None
957     def is_static_array(self):
958         """ Returns if the member is an array.
959         Vulkan uses this often for fixed size arrays in which the
960         length is part of the member.
961         """
962         return self.array_len is not None
964     def is_struct(self):
965         return self.type_info["category"] == "struct"
967     def is_union(self):
968         return self.type_info["category"] == "union"
970     def needs_alignment(self):
971         """ Check if this member needs alignment for 64-bit data.
972         Various structures need alignment on 64-bit variables due
973         to compiler differences on 32-bit between Win32 and Linux.
974         """
976         if self.is_pointer():
977             return False
978         elif self.type == "size_t":
979             return False
980         elif self.type in ["uint64_t", "VkDeviceSize"]:
981             return True
982         elif self.is_struct():
983             struct = self.type_info["data"]
984             return struct.needs_alignment()
985         elif self.is_handle():
986             # Dispatchable handles are pointers to objects, while
987             # non-dispatchable are uint64_t and hence need alignment.
988             handle = self.type_info["data"]
989             return False if handle.is_dispatchable() else True
990         return False
992     def needs_conversion(self):
993         """ Structures requiring alignment, need conversion between win32 and host. """
995         if not self.is_struct():
996             return False
998         struct = self.type_info["data"]
999         return struct.needs_conversion()
1001     def needs_free(self):
1002         if not self.needs_conversion():
1003             return False
1005         if self.is_dynamic_array():
1006             return True
1008         # TODO: some non-pointer structs and optional pointer structs may need freeing,
1009         # though none of this type have been encountered yet.
1010         return False
1012     def set_type_info(self, type_info):
1013         """ Helper function to set type information from the type registry.
1014         This is needed, because not all type data is available at time of
1015         parsing.
1016         """
1017         self.type_info = type_info
1020 class VkParam(object):
1021     """ Helper class which describes a parameter to a function call. """
1023     def __init__(self, type_info, const=None, pointer=None, name=None, array_len=None, dyn_array_len=None):
1024         self.const = const
1025         self.name = name
1026         self.array_len = array_len
1027         self.dyn_array_len = dyn_array_len
1028         self.pointer = pointer
1029         self.type_info = type_info
1030         self.type = type_info["name"] # For convenience
1031         self.handle = type_info["data"] if type_info["category"] == "handle" else None
1032         self.struct = type_info["data"] if type_info["category"] == "struct" else None
1034         self._set_direction()
1035         self._set_format_string()
1036         self._set_conversions()
1038     def __repr__(self):
1039         return "{0} {1} {2} {3} {4}".format(self.const, self.type, self.pointer, self.name, self.array_len, self.dyn_array_len)
1041     @staticmethod
1042     def from_xml(param, types):
1043         """ Helper function to create VkParam from xml. """
1045         # Parameter parsing is slightly tricky. All the data is contained within
1046         # a param tag, but some data is within subtags while others are text
1047         # before or after the type tag.
1048         # Common structure:
1049         # <param>const <type>char</type>* <name>pLayerName</name></param>
1051         name_elem = param.find("name")
1052         array_len = None
1053         name = name_elem.text
1054         # Tail contains array length e.g. for blendConstants param of vkSetBlendConstants
1055         if name_elem.tail is not None:
1056             array_len = name_elem.tail.strip("[]")
1058         # Name of other parameter in function prototype, which stores the number of
1059         # elements pointed to be by this parameter.
1060         dyn_array_len = param.get("len", None)
1062         const = param.text.strip() if param.text else None
1063         type_elem = param.find("type")
1064         pointer = type_elem.tail.strip() if type_elem.tail.strip() != "" else None
1066         # Since we have parsed all types before hand, this should not happen.
1067         type_info = types.get(type_elem.text, None)
1068         if type_info is None:
1069             LOGGER.err("type info not found for: {0}".format(type_elem.text))
1071         return VkParam(type_info, const=const, pointer=pointer, name=name, array_len=array_len, dyn_array_len=dyn_array_len)
1073     def _set_conversions(self):
1074         """ Internal helper function to configure any needed conversion functions. """
1076         self.free_func = None
1077         self.input_conv = None
1078         self.output_conv = None
1079         if not self.needs_conversion():
1080             return
1082         # Input functions require win to host conversion.
1083         if self._direction in [Direction.INPUT, Direction.INPUT_OUTPUT]:
1084             self.input_conv = ConversionFunction(False, self.is_dynamic_array(), Direction.INPUT, self.struct)
1086         # Output functions require host to win conversion.
1087         if self._direction in [Direction.INPUT_OUTPUT, Direction.OUTPUT]:
1088             self.output_conv = ConversionFunction(False, self.is_dynamic_array(), Direction.OUTPUT, self.struct)
1090         # Dynamic arrays, but also some normal structs (e.g. VkCommandBufferBeginInfo) need memory
1091         # allocation and thus some cleanup.
1092         if self.is_dynamic_array() or self.struct.needs_free():
1093             self.free_func = FreeFunction(self.is_dynamic_array(), self.struct)
1095     def _set_direction(self):
1096         """ Internal helper function to set parameter direction (input/output/input_output). """
1098         # The parameter direction needs to be determined from hints in vk.xml like returnedonly,
1099         # parameter constness and other heuristics.
1100         # For now we need to get this right for structures as we need to convert these, we may have
1101         # missed a few other edge cases (e.g. count variables).
1102         # See also https://github.com/KhronosGroup/Vulkan-Docs/issues/610
1104         if not self.is_pointer():
1105             self._direction = Direction.INPUT
1106         elif self.is_const() and self.is_pointer():
1107             self._direction = Direction.INPUT
1108         elif self.is_struct():
1109             if not self.struct.returnedonly:
1110                 self._direction = Direction.INPUT
1111                 return
1113             # Returnedonly hints towards output, however in some cases
1114             # it is inputoutput. In particular if pNext / sType exist,
1115             # which are used to link in other structures without having
1116             # to introduce new APIs. E.g. vkGetPhysicalDeviceProperties2KHR.
1117             if "pNext" in self.struct:
1118                 self._direction = Direction.INPUT_OUTPUT
1119                 return
1121             self._direction = Direction.OUTPUT
1122         else:
1123             # This should mostly be right. Count variables can be inout, but we don't care about these yet.
1124             self._direction = Direction.OUTPUT
1126     def _set_format_string(self):
1127         """ Internal helper function to be used by constructor to set format string. """
1129         # Determine a format string used by code generation for traces.
1130         # 64-bit types need a conversion function.
1131         self.format_conv = None
1132         if self.is_static_array() or self.is_pointer():
1133             self.format_str = "%p"
1134         else:
1135             if self.type_info["category"] == "bitmask":
1136                 self.format_str = "%#x"
1137             elif self.type_info["category"] == "enum":
1138                 self.format_str = "%d"
1139             elif self.is_handle():
1140                 # We use uint64_t for non-dispatchable handles as opposed to pointers
1141                 # for dispatchable handles.
1142                 if self.handle.is_dispatchable():
1143                     self.format_str = "%p"
1144                 else:
1145                     self.format_str = "0x%s"
1146                     self.format_conv = "wine_dbgstr_longlong({0})"
1147             elif self.type == "float":
1148                 self.format_str = "%f"
1149             elif self.type == "int":
1150                 self.format_str = "%d"
1151             elif self.type == "int32_t":
1152                 self.format_str = "%d"
1153             elif self.type == "size_t":
1154                 self.format_str = "0x%s"
1155                 self.format_conv = "wine_dbgstr_longlong({0})"
1156             elif self.type in ["uint32_t", "VkBool32"]:
1157                 self.format_str = "%u"
1158             elif self.type in ["uint64_t", "VkDeviceSize"]:
1159                 self.format_str = "0x%s"
1160                 self.format_conv = "wine_dbgstr_longlong({0})"
1161             elif self.type == "HANDLE":
1162                 self.format_str = "%p"
1163             elif self.type in ["VisualID", "xcb_visualid_t", "RROutput"]:
1164                 # Don't care about Linux specific types.
1165                 self.format_str = ""
1166             else:
1167                 LOGGER.warn("Unhandled type: {0}".format(self.type_info))
1169     def copy(self, direction):
1170         if direction == Direction.INPUT:
1171             if self.is_dynamic_array():
1172                 return "    {0}_host = convert_{1}_array_win_to_host({0}, {2});\n".format(self.name, self.type, self.dyn_array_len)
1173             else:
1174                 return "    convert_{0}_win_to_host({1}, &{1}_host);\n".format(self.type, self.name)
1175         else:
1176             if self.is_dynamic_array():
1177                 LOGGER.error("Unimplemented output conversion for: {0}".format(self.name))
1178             else:
1179                 return "    convert_{0}_host_to_win(&{1}_host, {1});\n".format(self.type, self.name)
1181     def definition(self, postfix=None):
1182         """ Return prototype for the parameter. E.g. 'const char *foo' """
1184         proto = ""
1185         if self.const:
1186             proto += self.const + " "
1188         proto += self.type
1190         if self.is_pointer():
1191             proto += " {0}{1}".format(self.pointer, self.name)
1192         else:
1193             proto += " " + self.name
1195         # Allows appeninding something to the variable name useful for
1196         # win32 to host conversion.
1197         if postfix is not None:
1198             proto += postfix
1200         if self.is_static_array():
1201             proto += "[{0}]".format(self.array_len)
1203         return proto
1205     def direction(self):
1206         """ Returns parameter direction: input, output, input_output.
1208         Parameter direction in Vulkan is not straight-forward, which this function determines.
1209         """
1211         return self._direction
1213     def format_string(self):
1214         return self.format_str
1216     def dispatch_table(self):
1217         """ Return functions dispatch table pointer for dispatchable objects. """
1219         if not self.is_dispatchable():
1220             return None
1222         return "{0}->{1}".format(self.name, self.handle.dispatch_table())
1224     def format_string(self):
1225         return self.format_str
1227     def free(self):
1228         if self.is_dynamic_array():
1229             if self.struct.returnedonly:
1230                 # For returnedonly, counts is stored in a pointer.
1231                 return "    free_{0}_array({1}_host, *{2});\n".format(self.type, self.name, self.dyn_array_len)
1232             else:
1233                 return "    free_{0}_array({1}_host, {2});\n".format(self.type, self.name, self.dyn_array_len)
1234         else:
1235             # We are operating on a single structure. Some structs (very rare) contain dynamic members,
1236             # which would need freeing.
1237             if self.struct.needs_free():
1238                 return "    free_{0}(&{1}_host);\n".format(self.type, self.name)
1239         return ""
1241     def get_conversions(self):
1242         """ Get a list of conversions required for this parameter if any.
1243         Parameters which are structures may require conversion between win32
1244         and the host platform. This function returns a list of conversions
1245         required.
1246         """
1248         if not self.is_struct():
1249             return None
1251         if not self.needs_conversion():
1252             return None
1254         conversions = []
1256         # Collect any member conversions first, so we can guarantee
1257         # those functions will be defined prior to usage by the
1258         # 'parent' param requiring conversion.
1259         for m in self.struct:
1260             if not m.is_struct():
1261                 continue
1263             if not m.needs_conversion():
1264                 continue
1266             conversions.extend(m.get_conversions())
1268         # Conversion requirements for the 'parent' parameter.
1269         if self.input_conv is not None:
1270             conversions.append(self.input_conv)
1271         if self.output_conv is not None:
1272             conversions.append(self.output_conv)
1273         if self.free_func is not None:
1274             conversions.append(self.free_func)
1276         return conversions
1278     def is_const(self):
1279         return self.const is not None
1281     def is_dynamic_array(self):
1282         return self.dyn_array_len is not None
1284     def is_dispatchable(self):
1285         if not self.is_handle():
1286             return False
1288         return self.handle.is_dispatchable()
1290     def is_handle(self):
1291         return self.handle is not None
1293     def is_pointer(self):
1294         return self.pointer is not None
1296     def is_static_array(self):
1297         return self.array_len is not None
1299     def is_struct(self):
1300         return self.struct is not None
1302     def needs_conversion(self):
1303         """ Returns if parameter needs conversion between win32 and host. """
1305         if not self.is_struct():
1306             return False
1308         # VkSparseImageMemoryRequirements is used by vkGetImageSparseMemoryRequirements.
1309         # This function is tricky to wrap, because how to wrap depends on whether
1310         # pSparseMemoryRequirements is NULL or not. Luckily for VkSparseImageMemoryRequirements
1311         # the alignment works out in such a way that no conversion is needed between win32 and Linux.
1312         if self.type == "VkSparseImageMemoryRequirements":
1313             return False
1315         # If a structure needs alignment changes, it means we need to
1316         # perform parameter conversion between win32 and host.
1317         if self.struct.needs_conversion():
1318             return True
1320         return False
1322     def needs_free(self):
1323         return self.free_func is not None
1325     def needs_input_conversion(self):
1326         return self.input_conv is not None
1328     def needs_output_conversion(self):
1329         return self.output_conv is not None
1331     def spec(self):
1332         """ Generate spec file entry for this parameter. """
1334         if self.type_info["category"] in ["bitmask", "enum"]:
1335             return "long"
1336         if self.is_pointer() and self.type == "char":
1337             return "str"
1338         if self.is_dispatchable() or self.is_pointer() or self.is_static_array():
1339             return "ptr"
1340         if self.is_handle() and not self.is_dispatchable():
1341             return "int64"
1342         if self.type == "float":
1343             return "float"
1344         if self.type in ["int", "int32_t", "size_t", "uint32_t", "VkBool32"]:
1345             return "long"
1346         if self.type in ["uint64_t", "VkDeviceSize"]:
1347             return "int64"
1349         LOGGER.error("Unhandled spec conversion for type: {0}".format(self.type))
1351     def variable(self, conv=False):
1352         """ Returns 'glue' code during generation of a function call on how to access the variable.
1353         This function handles various scenarios such as 'unwrapping' if dispatchable objects and
1354         renaming of parameters in case of win32 -> host conversion.
1356         Args:
1357             conv (bool, optional): Enable conversion if the param needs it. This appends '_host' to the name.
1358         """
1360         # Hack until we enable allocation callbacks from ICD to application. These are a joy
1361         # to enable one day, because of calling convention conversion.
1362         if "VkAllocationCallbacks" in self.type:
1363             LOGGER.debug("TODO: setting NULL VkAllocationCallbacks for {0}".format(self.name))
1364             return "NULL"
1366         # Dispatchable objects wrap the native handle. For thunk generation we
1367         # need to pass the native handle to the native vulkan calls.
1368         if self.is_dispatchable():
1369             return "{0}->{1}".format(self.name, self.handle.native_handle())
1370         elif conv and self.needs_conversion():
1371             if self.is_dynamic_array():
1372                 return "{0}_host".format(self.name)
1373             else:
1374                 return "&{0}_host".format(self.name)
1375         else:
1376             return self.name
1379 class VkStruct(Sequence):
1380     """ Class which represents the type union and struct. """
1382     def __init__(self, name, members, returnedonly, union=False):
1383         self.name = name
1384         self.members = members
1385         self.returnedonly = returnedonly
1386         self.required = False
1387         self.union = union
1388         self.type_info = None # To be set later.
1390     def __getitem__(self, i):
1391         return self.members[i]
1393     def __len__(self):
1394         return len(self.members)
1396     @staticmethod
1397     def from_xml(struct):
1398         # Unions and structs are the same parsing wise, but we need to
1399         # know which one we are dealing with later on for code generation.
1400         union = True if struct.attrib["category"] == "union" else False
1402         name = struct.attrib.get("name", None)
1404         # 'Output' structures for which data is filled in by the API are
1405         # marked as 'returnedonly'.
1406         returnedonly = True if struct.attrib.get("returnedonly") else False
1408         members = []
1409         for member in struct.findall("member"):
1410             vk_member = VkMember.from_xml(member)
1411             members.append(vk_member)
1413         return VkStruct(name, members, returnedonly, union=union)
1415     @staticmethod
1416     def decouple_structs(structs):
1417         """ Helper function which decouples a list of structs.
1418         Structures often depend on other structures. To make the C compiler
1419         happy we need to define 'substructures' first. This function analyzes
1420         the list of structures and reorders them in such a way that they are
1421         decoupled.
1422         """
1424         tmp_structs = list(structs) # Don't modify the original structures.
1425         decoupled_structs = []
1427         while (len(tmp_structs) > 0):
1428             for struct in tmp_structs:
1429                 dependends = False
1431                 if not struct.required:
1432                     tmp_structs.remove(struct)
1433                     continue
1435                 for m in struct:
1436                     if not (m.is_struct() or m.is_union()):
1437                         continue
1439                     found = False
1440                     # Check if a struct we depend on has already been defined.
1441                     for s in decoupled_structs:
1442                         if s.name == m.type:
1443                             found = True
1444                             break
1446                     if not found:
1447                         # Check if the struct we depend on is even in the list of structs.
1448                         # If found now, it means we haven't met all dependencies before we
1449                         # can operate on the current struct.
1450                         # When generating 'host' structs we may not be able to find a struct
1451                         # as the list would only contain the structs requiring conversion.
1452                         for s in tmp_structs:
1453                             if s.name == m.type:
1454                                 dependends = True
1455                                 break
1457                 if dependends == False:
1458                     decoupled_structs.append(struct)
1459                     tmp_structs.remove(struct)
1461         return decoupled_structs
1463     def definition(self, align=False, conv=False, postfix=None):
1464         """ Convert structure to textual definition.
1466         Args:
1467             align (bool, optional): enable alignment to 64-bit for win32 struct compatibility.
1468             conv (bool, optional): enable struct conversion if the struct needs it.
1469             postfix (str, optional): text to append to end of struct name, useful for struct renaming.
1470         """
1472         if self.union:
1473             text = "typedef union {0}".format(self.name)
1474         else:
1475             text = "typedef struct {0}".format(self.name)
1477         if postfix is not None:
1478             text += postfix
1480         text += "\n{\n"
1482         for m in self:
1483             if align and m.needs_alignment():
1484                 text += "    {0};\n".format(m.definition(align=align))
1485             elif conv and m.needs_conversion():
1486                 text += "    {0};\n".format(m.definition(conv=conv))
1487             else:
1488                 text += "    {0};\n".format(m.definition())
1490         if postfix is not None:
1491             text += "}} {0}{1};\n\n".format(self.name, postfix)
1492         else:
1493             text += "}} {0};\n\n".format(self.name)
1494         return text
1496     def needs_alignment(self):
1497         """ Check if structure needs alignment for 64-bit data.
1498         Various structures need alignment on 64-bit variables due
1499         to compiler differences on 32-bit between Win32 and Linux.
1500         """
1502         for m in self.members:
1503             if m.needs_alignment():
1504                 return True
1505         return False
1507     def needs_conversion(self):
1508         """ Returns if struct members needs conversion between win32 and host.
1509         Structures need conversion if they contain members requiring alignment
1510         or if they include other structures which need alignment.
1511         """
1513         if self.needs_alignment():
1514             return True
1516         for m in self.members:
1517             if m.needs_conversion():
1518                 return True
1519         return False
1521     def needs_free(self):
1522         """ Check if any struct member needs some memory freeing."""
1524         for m in self.members:
1525             if m.needs_free():
1526                 return True
1528             continue
1530         return False
1532     def set_type_info(self, types):
1533         """ Helper function to set type information from the type registry.
1534         This is needed, because not all type data is available at time of
1535         parsing.
1536         """
1537         for m in self.members:
1538             type_info = types[m.type]
1539             m.set_type_info(type_info)
1542 class ConversionFunction(object):
1543     def __init__(self, array, dyn_array, direction, struct):
1544         self.array = array
1545         self.direction = direction
1546         self.dyn_array = dyn_array
1547         self.struct = struct
1548         self.type = struct.name
1550         self._set_name()
1552     def __eq__(self, other):
1553         if self.name != other.name:
1554             return False
1556         return True
1558     def _generate_array_conversion_func(self):
1559         """ Helper function for generating a conversion function for array structs. """
1561         if self.direction == Direction.OUTPUT:
1562             params = ["const {0}_host *in".format(self.type), "uint32_t count"]
1563             return_type = self.type
1564         else:
1565             params = ["const {0} *in".format(self.type), "uint32_t count"]
1566             return_type = "{0}_host".format(self.type)
1568         # Generate function prototype.
1569         body = "static inline {0} *{1}(".format(return_type, self.name)
1570         body += ", ".join(p for p in params)
1571         body += ")\n{\n"
1573         body += "    {0} *out;\n".format(return_type)
1574         body += "    unsigned int i;\n\n"
1575         body += "    if (!in) return NULL;\n\n"
1577         body += "    out = heap_alloc(count * sizeof(*out));\n"
1579         body += "    for (i = 0; i < count; i++)\n"
1580         body += "    {\n"
1582         for m in self.struct:
1583             # TODO: support copying of pNext extension structures!
1584             # Luckily though no extension struct at this point needs conversion.
1585             body += "        " + m.copy("in[i].", "out[i].", self.direction)
1587         body += "    }\n\n"
1588         body += "    return out;\n"
1589         body += "}\n\n"
1590         return body
1592     def _generate_conversion_func(self):
1593         """ Helper function for generating a conversion function for non-array structs. """
1595         if self.direction == Direction.OUTPUT:
1596             params = ["const {0}_host *in".format(self.type), "{0} *out".format(self.type)]
1597         else:
1598             params = ["const {0} *in".format(self.type), "{0}_host *out".format(self.type)]
1600         body = "static inline void {0}(".format(self.name)
1602         # Generate parameter list
1603         body += ", ".join(p for p in params)
1604         body += ")\n{\n"
1606         body += "    if (!in) return;\n\n"
1608         if self.direction == Direction.INPUT and "pNext" in self.struct and self.struct.returnedonly:
1609             # We are dealing with an input_output parameter. For these we only need to copy
1610             # pNext and sType as the other fields are filled in by the host. We do potentially
1611             # have to iterate over pNext and perform conversions based on switch(sType)!
1612             # Luckily though no extension structs at this point need conversion.
1613             # TODO: support copying of pNext extension structures!
1614             body += "    out->pNext = in->pNext;\n"
1615             body += "    out->sType = in->sType;\n"
1616         else:
1617             for m in self.struct:
1618                 # TODO: support copying of pNext extension structures!
1619                 body += "    " + m.copy("in->", "out->", self.direction)
1621         body += "}\n\n"
1622         return body
1624     def _generate_static_array_conversion_func(self):
1625         """ Helper function for generating a conversion function for array structs. """
1627         if self.direction == Direction.OUTPUT:
1628             params = ["const {0}_host *in".format(self.type), "{0} *out".format(self.type), "uint32_t count"]
1629             return_type = self.type
1630         else:
1631             params = ["const {0} *in".format(self.type), "{0} *out_host".format(self.type), "uint32_t count"]
1632             return_type = "{0}_host".format(self.type)
1634         # Generate function prototype.
1635         body = "static inline void {0}(".format(self.name)
1636         body += ", ".join(p for p in params)
1637         body += ")\n{\n"
1638         body += "    unsigned int i;\n\n"
1639         body += "    if (!in) return;\n\n"
1640         body += "    for (i = 0; i < count; i++)\n"
1641         body += "    {\n"
1643         for m in self.struct:
1644             # TODO: support copying of pNext extension structures!
1645             body += "        " + m.copy("in[i].", "out[i].", self.direction)
1647         body += "    }\n"
1648         body += "}\n\n"
1649         return body
1651     def _set_name(self):
1652         if self.direction == Direction.INPUT:
1653             if self.array:
1654                 name = "convert_{0}_static_array_win_to_host".format(self.type)
1655             elif self.dyn_array:
1656                 name = "convert_{0}_array_win_to_host".format(self.type)
1657             else:
1658                 name = "convert_{0}_win_to_host".format(self.type)
1659         else: # Direction.OUTPUT
1660             if self.array:
1661                 name = "convert_{0}_static_array_host_to_win".format(self.type)
1662             elif self.dyn_array:
1663                 name = "convert_{0}_array_host_to_win".format(self.type)
1664             else:
1665                 name = "convert_{0}_host_to_win".format(self.type)
1667         self.name = name
1669     def definition(self):
1670         if self.array:
1671             return self._generate_static_array_conversion_func()
1672         elif self.dyn_array:
1673             return self._generate_array_conversion_func()
1674         else:
1675             return self._generate_conversion_func()
1678 class FreeFunction(object):
1679     def __init__(self, dyn_array, struct):
1680         self.dyn_array = dyn_array
1681         self.struct = struct
1682         self.type = struct.name
1684         if dyn_array:
1685             self.name = "free_{0}_array".format(self.type)
1686         else:
1687             self.name = "free_{0}".format(self.type)
1689     def __eq__(self, other):
1690         if self.name == other.name:
1691             return True
1693         return False
1695     def _generate_array_free_func(self):
1696         """ Helper function for cleaning up temporary buffers required for array conversions. """
1698         # Generate function prototype.
1699         body = "static inline void {0}({1}_host *in, uint32_t count)\n{{\n".format(self.name, self.type)
1701         # E.g. VkGraphicsPipelineCreateInfo_host needs freeing for pStages.
1702         if self.struct.needs_free():
1703             body += "    unsigned int i;\n\n"
1704             body += "    if (!in) return;\n\n"
1705             body += "    for (i = 0; i < count; i++)\n"
1706             body += "    {\n"
1708             for m in self.struct:
1709                 if m.needs_conversion() and m.is_dynamic_array():
1710                     if m.is_const():
1711                         # Add a cast to ignore const on conversion structs we allocated ourselves.
1712                         body += "        free_{0}_array(({0}_host *)in[i].{1}, in[i].{2});\n".format(m.type, m.name, m.dyn_array_len)
1713                     else:
1714                         body += "        free_{0}_array(in[i].{1}, in[i].{2});\n".format(m.type, m.name, m.dyn_array_len)
1715                 elif m.needs_conversion():
1716                     LOGGER.error("Unhandled conversion for {0}".format(m.name))
1717             body += "    }\n"
1718         else:
1719             body += "    if (!in) return;\n\n"
1721         body += "    heap_free(in);\n"
1723         body += "}\n\n"
1724         return body
1726     def _generate_free_func(self):
1727         # E.g. VkCommandBufferBeginInfo.pInheritanceInfo needs freeing.
1728         if not self.struct.needs_free():
1729             return ""
1731         # Generate function prototype.
1732         body = "static inline void {0}({1}_host *in)\n{{\n".format(self.name, self.type)
1734         for m in self.struct:
1735             if m.needs_conversion() and m.is_dynamic_array():
1736                 count = m.dyn_array_len if isinstance(m.dyn_array_len, int) else "in->{0}".format(m.dyn_array_len)
1737                 if m.is_const():
1738                     # Add a cast to ignore const on conversion structs we allocated ourselves.
1739                     body += "    free_{0}_array(({0}_host *)in->{1}, {2});\n".format(m.type, m.name, count)
1740                 else:
1741                     body += "    free_{0}_array(in->{1}, {2});\n".format(m.type, m.name, count)
1743         body += "}\n\n"
1744         return body
1746     def definition(self):
1747         if self.dyn_array:
1748             return self._generate_array_free_func()
1749         else:
1750             # Some structures need freeing too if they contain dynamic arrays.
1751             # E.g. VkCommandBufferBeginInfo
1752             return self._generate_free_func()
1755 class VkGenerator(object):
1756     def __init__(self, registry):
1757         self.registry = registry
1759         # Build a list conversion functions for struct conversion.
1760         self.conversions = []
1761         self.host_structs = []
1762         for func in self.registry.funcs.values():
1763             if not func.is_required():
1764                 continue
1766             if not func.needs_conversion():
1767                 continue
1769             conversions = func.get_conversions()
1770             for conv in conversions:
1771                 # Pull in any conversions for vulkan_thunks.c.
1772                 if func.needs_thunk():
1773                     # Append if we don't already have this conversion.
1774                     if not any(c == conv for c in self.conversions):
1775                         self.conversions.append(conv)
1777                 # Structs can be used in different ways by different conversions
1778                 # e.g. array vs non-array. Just make sure we pull in each struct once.
1779                 if not any(s.name == conv.struct.name for s in self.host_structs):
1780                     self.host_structs.append(conv.struct)
1782     def generate_thunks_c(self, f, prefix):
1783         f.write("/* Automatically generated from Vulkan vk.xml; DO NOT EDIT! */\n\n")
1785         f.write("#include \"config.h\"\n")
1786         f.write("#include \"wine/port.h\"\n\n")
1788         f.write("#include \"wine/debug.h\"\n")
1789         f.write("#include \"wine/heap.h\"\n")
1790         f.write("#include \"wine/vulkan.h\"\n")
1791         f.write("#include \"wine/vulkan_driver.h\"\n")
1792         f.write("#include \"vulkan_private.h\"\n\n")
1794         f.write("WINE_DEFAULT_DEBUG_CHANNEL(vulkan);\n\n")
1796         # Generate any conversion helper functions.
1797         f.write("#if defined(USE_STRUCT_CONVERSION)\n")
1798         for conv in self.conversions:
1799             f.write(conv.definition())
1800         f.write("#endif /* USE_STRUCT_CONVERSION */\n\n")
1802         # Create thunks for instance and device functions.
1803         # Global functions don't go through the thunks.
1804         for vk_func in self.registry.funcs.values():
1805             if not vk_func.is_required():
1806                 continue
1808             if vk_func.is_global_func():
1809                 continue
1811             if not vk_func.needs_thunk():
1812                 continue
1814             # Exports symbols for Core functions.
1815             if not vk_func.is_core_func():
1816                 f.write("static ")
1817             f.write(vk_func.thunk(prefix=prefix, call_conv="WINAPI"))
1819         f.write("static const struct vulkan_func vk_device_dispatch_table[] =\n{\n")
1820         for vk_func in self.registry.device_funcs:
1821             if not vk_func.is_required():
1822                 continue
1824             f.write("    {{\"{0}\", &{1}{0}}},\n".format(vk_func.name, prefix))
1825         f.write("};\n\n")
1827         f.write("static const struct vulkan_func vk_instance_dispatch_table[] =\n{\n")
1828         for vk_func in self.registry.instance_funcs:
1829             if not vk_func.is_required():
1830                 continue
1832             f.write("    {{\"{0}\", &{1}{0}}},\n".format(vk_func.name, prefix))
1833         f.write("};\n\n")
1835         f.write("void *wine_vk_get_device_proc_addr(const char *name)\n")
1836         f.write("{\n")
1837         f.write("    unsigned int i;\n")
1838         f.write("    for (i = 0; i < ARRAY_SIZE(vk_device_dispatch_table); i++)\n")
1839         f.write("    {\n")
1840         f.write("        if (strcmp(vk_device_dispatch_table[i].name, name) == 0)\n")
1841         f.write("        {\n")
1842         f.write("            TRACE(\"Found name=%s in device table\\n\", debugstr_a(name));\n")
1843         f.write("            return vk_device_dispatch_table[i].func;\n")
1844         f.write("        }\n")
1845         f.write("    }\n")
1846         f.write("    return NULL;\n")
1847         f.write("}\n\n")
1849         f.write("void *wine_vk_get_instance_proc_addr(const char *name)\n")
1850         f.write("{\n")
1851         f.write("    unsigned int i;\n")
1852         f.write("    for (i = 0; i < ARRAY_SIZE(vk_instance_dispatch_table); i++)\n")
1853         f.write("    {\n")
1854         f.write("        if (strcmp(vk_instance_dispatch_table[i].name, name) == 0)\n")
1855         f.write("        {\n")
1856         f.write("            TRACE(\"Found name=%s in instance table\\n\", debugstr_a(name));\n")
1857         f.write("            return vk_instance_dispatch_table[i].func;\n")
1858         f.write("        }\n")
1859         f.write("    }\n")
1860         f.write("    return NULL;\n")
1861         f.write("}\n\n")
1863         # Create array of device extensions.
1864         f.write("static const char * const vk_device_extensions[] =\n{\n")
1865         for ext in self.registry.extensions:
1866             if ext["type"] != "device":
1867                 continue
1869             f.write("    \"{0}\",\n".format(ext["name"]))
1870         f.write("};\n\n")
1872         # Create array of instance extensions.
1873         f.write("static const char * const vk_instance_extensions[] =\n{\n")
1874         for ext in self.registry.extensions:
1875             if ext["type"] != "instance":
1876                 continue
1878             f.write("    \"{0}\",\n".format(ext["name"]))
1879         f.write("};\n\n")
1881         f.write("BOOL wine_vk_device_extension_supported(const char *name)\n")
1882         f.write("{\n")
1883         f.write("    unsigned int i;\n")
1884         f.write("    for (i = 0; i < ARRAY_SIZE(vk_device_extensions); i++)\n")
1885         f.write("    {\n")
1886         f.write("        if (strcmp(vk_device_extensions[i], name) == 0)\n")
1887         f.write("            return TRUE;\n")
1888         f.write("    }\n")
1889         f.write("    return FALSE;\n")
1890         f.write("}\n\n")
1892         f.write("BOOL wine_vk_instance_extension_supported(const char *name)\n")
1893         f.write("{\n")
1894         f.write("    unsigned int i;\n")
1895         f.write("    for (i = 0; i < ARRAY_SIZE(vk_instance_extensions); i++)\n")
1896         f.write("    {\n")
1897         f.write("        if (strcmp(vk_instance_extensions[i], name) == 0)\n")
1898         f.write("            return TRUE;\n")
1899         f.write("    }\n")
1900         f.write("    return FALSE;\n")
1901         f.write("}\n")
1903     def generate_thunks_h(self, f, prefix):
1904         f.write("/* Automatically generated from Vulkan vk.xml; DO NOT EDIT! */\n\n")
1906         f.write("#ifndef __WINE_VULKAN_THUNKS_H\n")
1907         f.write("#define __WINE_VULKAN_THUNKS_H\n\n")
1909         f.write("/* Perform vulkan struct conversion on 32-bit x86 platforms. */\n")
1910         f.write("#if defined(__i386__)\n")
1911         f.write("#define USE_STRUCT_CONVERSION\n")
1912         f.write("#endif\n\n")
1914         f.write("/* For use by vk_icdGetInstanceProcAddr / vkGetInstanceProcAddr */\n")
1915         f.write("void *wine_vk_get_device_proc_addr(const char *name) DECLSPEC_HIDDEN;\n")
1916         f.write("void *wine_vk_get_instance_proc_addr(const char *name) DECLSPEC_HIDDEN;\n\n")
1918         f.write("BOOL wine_vk_device_extension_supported(const char *name) DECLSPEC_HIDDEN;\n")
1919         f.write("BOOL wine_vk_instance_extension_supported(const char *name) DECLSPEC_HIDDEN;\n\n")
1921         # Generate prototypes for device and instance functions requiring a custom implementation.
1922         f.write("/* Functions for which we have custom implementations outside of the thunks. */\n")
1923         for vk_func in self.registry.funcs.values():
1924             if not vk_func.is_required() or vk_func.is_global_func() or vk_func.needs_thunk():
1925                 continue
1927             if vk_func.is_core_func():
1928                 f.write("{0};\n".format(vk_func.prototype("WINAPI", prefix="wine_")))
1929             else:
1930                 f.write("{0};\n".format(vk_func.prototype("WINAPI", prefix="wine_", postfix="DECLSPEC_HIDDEN")))
1931         f.write("\n")
1933         for struct in self.host_structs:
1934             f.write(struct.definition(align=False, conv=True, postfix="_host"))
1935         f.write("\n")
1937         f.write("/* For use by vkDevice and children */\n")
1938         f.write("struct vulkan_device_funcs\n{\n")
1939         for vk_func in self.registry.device_funcs:
1940             if not vk_func.is_required():
1941                 continue
1943             if not vk_func.needs_dispatch():
1944                 LOGGER.debug("skipping {0} in vulkan_device_funcs".format(vk_func.name))
1945                 continue
1947             if vk_func.needs_conversion():
1948                 f.write("#if defined(USE_STRUCT_CONVERSION)\n")
1949                 f.write("    {0};\n".format(vk_func.pfn(conv=True)))
1950                 f.write("#else\n")
1951                 f.write("    {0};\n".format(vk_func.pfn(conv=False)))
1952                 f.write("#endif\n")
1953             else:
1954                 f.write("    {0};\n".format(vk_func.pfn(conv=False)))
1955         f.write("};\n\n")
1957         f.write("/* For use by vkInstance and children */\n")
1958         f.write("struct vulkan_instance_funcs\n{\n")
1959         for vk_func in self.registry.instance_funcs:
1960             if not vk_func.is_required():
1961                 continue
1963             if not vk_func.needs_dispatch():
1964                 LOGGER.debug("skipping {0} in vulkan_instance_funcs".format(vk_func.name))
1965                 continue
1967             if vk_func.needs_conversion():
1968                 f.write("#if defined(USE_STRUCT_CONVERSION)\n")
1969                 f.write("    {0};\n".format(vk_func.pfn(conv=True)))
1970                 f.write("#else\n")
1971                 f.write("    {0};\n".format(vk_func.pfn(conv=False)))
1972                 f.write("#endif\n")
1973             else:
1974                 f.write("    {0};\n".format(vk_func.pfn(conv=False)))
1975         f.write("};\n\n")
1977         f.write("#define ALL_VK_DEVICE_FUNCS() \\\n")
1978         first = True
1979         for vk_func in self.registry.device_funcs:
1980             if not vk_func.is_required():
1981                 continue
1983             if not vk_func.needs_dispatch():
1984                 LOGGER.debug("skipping {0} in ALL_VK_DEVICE_FUNCS".format(vk_func.name))
1985                 continue
1987             if first:
1988                 f.write("    USE_VK_FUNC({0})".format(vk_func.name))
1989                 first = False
1990             else:
1991                 f.write(" \\\n    USE_VK_FUNC({0})".format(vk_func.name))
1992         f.write("\n\n")
1994         f.write("#define ALL_VK_INSTANCE_FUNCS() \\\n")
1995         first = True
1996         for vk_func in self.registry.instance_funcs:
1997             if not vk_func.is_required():
1998                 continue
2000             if not vk_func.needs_dispatch():
2001                 LOGGER.debug("skipping {0} in ALL_VK_INSTANCE_FUNCS".format(vk_func.name))
2002                 continue
2004             if first:
2005                 f.write("    USE_VK_FUNC({0})".format(vk_func.name))
2006                 first = False
2007             else:
2008                 f.write(" \\\n    USE_VK_FUNC({0})".format(vk_func.name))
2009         f.write("\n\n")
2011         f.write("#endif /* __WINE_VULKAN_THUNKS_H */\n")
2013     def generate_vulkan_h(self, f):
2014         f.write("/* Automatically generated from Vulkan vk.xml; DO NOT EDIT! */\n\n")
2015         f.write("#ifndef __WINE_VULKAN_H\n")
2016         f.write("#define __WINE_VULKAN_H\n\n")
2018         f.write("#include <windef.h>\n")
2019         f.write("#include <stdint.h>\n\n")
2021         f.write("#ifndef VKAPI_CALL\n")
2022         f.write("#define VKAPI_CALL __stdcall\n")
2023         f.write("#endif\n\n")
2025         f.write("#ifndef VKAPI_PTR\n")
2026         f.write("#define VKAPI_PTR VKAPI_CALL\n")
2027         f.write("#endif\n\n")
2029         f.write("/* Callers can override WINE_VK_ALIGN if they want 'host' headers. */\n")
2030         f.write("#ifndef WINE_VK_ALIGN\n")
2031         f.write("#define WINE_VK_ALIGN DECLSPEC_ALIGN\n")
2032         f.write("#endif\n\n")
2034         # The overall strategy is to define independent constants and datatypes,
2035         # prior to complex structures and function calls to avoid forward declarations.
2036         for const in self.registry.consts:
2037             # For now just generate things we may not need. The amount of parsing needed
2038             # to get some of the info is tricky as you need to figure out which structure
2039             # references a certain constant.
2040             f.write(const.definition())
2041         f.write("\n")
2043         for define in self.registry.defines:
2044             f.write(define.definition())
2046         for handle in self.registry.handles:
2047             if handle.required:
2048                  f.write(handle.definition())
2049         f.write("\n")
2051         for base_type in self.registry.base_types:
2052             f.write(base_type.definition())
2053         f.write("\n")
2055         for bitmask in self.registry.bitmasks:
2056             f.write(bitmask.definition())
2057         f.write("\n")
2059         # Define enums, this includes values for some of the bitmask types as well.
2060         for enum in self.registry.enums.values():
2061             if enum.required:
2062                 f.write(enum.definition())
2064         for fp in self.registry.funcpointers:
2065             if fp.required:
2066                 f.write(fp.definition())
2067         f.write("\n")
2069         # This generates both structures and unions. Since structures
2070         # may depend on other structures/unions, we need a list of
2071         # decoupled structs.
2072         # Note: unions are stored in structs for dependency reasons,
2073         # see comment in parsing section.
2074         structs = VkStruct.decouple_structs(self.registry.structs)
2075         for struct in structs:
2076             LOGGER.debug("Generating struct: {0}".format(struct.name))
2077             f.write(struct.definition(align=True))
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("\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))
2140 class VkRegistry(object):
2141     def __init__(self, reg_filename):
2142         # Used for storage of type information.
2143         self.base_types = None
2144         self.bitmasks = None
2145         self.consts = None
2146         self.defines = None
2147         self.enums = None
2148         self.funcpointers = None
2149         self.handles = None
2150         self.structs = None
2152         # We aggregate all types in here for cross-referencing.
2153         self.funcs = {}
2154         self.types = {}
2156         # Overall strategy for parsing the registry is to first
2157         # parse all type / function definitions. Then parse
2158         # features and extensions to decide which types / functions
2159         # to actually 'pull in' for code generation. For each type or
2160         # function call we want we set a member 'required' to True.
2161         tree = ET.parse(reg_filename)
2162         root = tree.getroot()
2163         self._parse_enums(root)
2164         self._parse_types(root)
2165         self._parse_commands(root)
2167         # Pull in any required types and functions.
2168         self._parse_features(root)
2169         self._parse_extensions(root)
2171     def _mark_command_required(self, command):
2172         """ Helper function to mark a certain command and the datatypes it needs as required."""
2173         def mark_bitmask_dependencies(bitmask, types):
2174             if bitmask.requires is not None:
2175                 types[bitmask.requires]["data"].required = True
2177         def mark_funcpointer_dependencies(fp, types):
2178             for m in fp.members:
2179                 type_info = types[m.type]
2181                 # Complex types have a matching definition e.g. VkStruct.
2182                 # Not needed for base types such as uint32_t.
2183                 if "data" in type_info:
2184                     types[m.type]["data"].required = True
2186         def mark_struct_dependencies(struct, types):
2187              for m in struct:
2188                 type_info = types[m.type]
2190                 # Complex types have a matching definition e.g. VkStruct.
2191                 # Not needed for base types such as uint32_t.
2192                 if "data" in type_info:
2193                     types[m.type]["data"].required = True
2195                 if type_info["category"] == "struct":
2196                     # Yay, recurse
2197                     mark_struct_dependencies(type_info["data"], types)
2198                 elif type_info["category"] == "funcpointer":
2199                     mark_funcpointer_dependencies(type_info["data"], types)
2200                 elif type_info["category"] == "bitmask":
2201                     mark_bitmask_dependencies(type_info["data"], types)
2203         func = self.funcs[command]
2204         func.required = True
2206         # Pull in return type
2207         if func.type != "void":
2208             self.types[func.type]["data"].required = True
2210         # Analyze parameter dependencies and pull in any type needed.
2211         for p in func.params:
2212             type_info = self.types[p.type]
2214             # Check if we are dealing with a complex type e.g. VkEnum, VkStruct and others.
2215             if "data" not in type_info:
2216                 continue
2218             # Mark the complex type as required.
2219             type_info["data"].required = True
2220             if type_info["category"] == "struct":
2221                 struct = type_info["data"]
2222                 mark_struct_dependencies(struct, self.types)
2224     def _parse_commands(self, root):
2225         """ Parse command section containing the Vulkan function calls. """
2226         funcs = {}
2227         commands = root.findall("./commands/")
2228         for command in commands:
2229             func = VkFunction.from_xml(command, self.types)
2230             funcs[func.name] = func
2232         # To make life easy for the code generation, separate all function
2233         # calls out in the 3 types of vulkan functions: device, global and instance.
2234         device_funcs = []
2235         global_funcs = []
2236         instance_funcs = []
2237         for func in funcs.values():
2238             if func.is_device_func():
2239                 device_funcs.append(func)
2240             elif func.is_global_func():
2241                 global_funcs.append(func)
2242             else:
2243                 instance_funcs.append(func)
2245         # Sort function lists by name and store them.
2246         self.device_funcs = sorted(device_funcs, key=lambda func: func.name)
2247         self.global_funcs = sorted(global_funcs, key=lambda func: func.name)
2248         self.instance_funcs = sorted(instance_funcs, key=lambda func: func.name)
2250         # The funcs dictionary is used as a convenient way to lookup function
2251         # calls when needed e.g. to adjust member variables.
2252         self.funcs = OrderedDict(sorted(funcs.items()))
2254     def _parse_enums(self, root):
2255         """ Parse enums section or better described as constants section. """
2256         enums = {}
2257         self.consts = []
2258         for enum in root.findall("./enums"):
2259             name = enum.attrib.get("name")
2260             _type = enum.attrib.get("type")
2262             if _type in ("enum", "bitmask"):
2263                 enums[name] = VkEnum.from_xml(enum)
2264             else:
2265                 # If no type is set, we are dealing with API constants.
2266                 values = []
2267                 for value in enum.findall("enum"):
2268                     self.consts.append(VkConstant(value.attrib.get("name"), value.attrib.get("value")))
2270         self.enums = OrderedDict(sorted(enums.items()))
2272     def _parse_extensions(self, root):
2273         """ Parse extensions section and pull in any types and commands for this extensioin. """
2274         extensions = []
2275         exts = root.findall("./extensions/extension")
2276         for ext in exts:
2277             ext_name = ext.attrib["name"]
2279             # Set extension name on any functions calls part of this extension as we
2280             # were not aware of the name during initial parsing.
2281             commands = ext.findall("require/command")
2282             for command in commands:
2283                 cmd_name = command.attrib["name"]
2284                 self.funcs[cmd_name].extension = ext_name
2286             # Some extensions are not ready or have numbers reserved as a place holder.
2287             if ext.attrib["supported"] == "disabled":
2288                 LOGGER.debug("Skipping disabled extension: {0}".format(ext_name))
2289                 continue
2291             # Disable highly experimental extensions as the APIs are unstable and can
2292             # change between minor Vulkan revisions until API is final and becomes KHR
2293             # or NV.
2294             if "KHX" in ext_name or "NVX" in ext_name:
2295                 LOGGER.debug("Skipping experimental extension: {0}".format(ext_name))
2296                 continue
2298             # Instance extensions often require a custom implementation, so filter.
2299             ext_type = ext.attrib["type"]
2300             if ext_type == "instance" and not ext_name in SUPPORTED_INSTANCE_EXTENSIONS:
2301                 LOGGER.debug("Skipping instance extension: {0}".format(ext_name))
2302                 continue
2304             # We disable some extensions as either we haven't implemented
2305             # support yet or because they are for platforms other than win32.
2306             if ext_name in BLACKLISTED_EXTENSIONS:
2307                 LOGGER.debug("Skipping blacklisted extension: {0}".format(ext_name))
2308                 continue
2309             elif "requires" in ext.attrib:
2310                 # Check if this extension builds on top of another blacklisted
2311                 # extension.
2312                 requires = ext.attrib["requires"].split(",")
2313                 if len(set(requires).intersection(BLACKLISTED_EXTENSIONS)) > 0:
2314                     continue
2316             LOGGER.debug("Loading extension: {0}".format(ext_name))
2318             # Extensions can add enum values to Core / extension enums, so add these.
2319             enums = ext.findall("require/enum")
2320             for enum_elem in enums:
2321                 if "bitpos" in enum_elem.keys():
2322                     # We need to add an extra value to an existing enum type.
2323                     # E.g. VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG to VkFormatFeatureFlagBits.
2324                     type_name = enum_elem.attrib["extends"]
2325                     enum = self.types[type_name]["data"]
2326                     enum.add(VkEnumValue(enum_elem.attrib["name"], 1 << int(enum_elem.attrib["bitpos"]), hex=True))
2327                 elif "offset" in enum_elem.keys():
2328                     ext_number = int(ext.attrib["number"])
2329                     offset = int(enum_elem.attrib["offset"])
2330                     value = EXT_BASE + (ext_number - 1) * EXT_BLOCK_SIZE + offset
2332                     # Deal with negative values.
2333                     direction = enum_elem.attrib.get("dir")
2334                     if direction is not None:
2335                         value = -value
2337                     type_name = enum_elem.attrib["extends"]
2338                     enum = self.types[type_name]["data"]
2339                     enum.add(VkEnumValue(enum_elem.attrib["name"], value))
2341                 elif "value" in enum_elem.keys():
2342                     # For now skip, it mostly contains extension name and version info.
2343                     continue
2344                 else:
2345                     # This seems to be used to pull in constants e.g. VK_MAX_DEVICE_GROUP_KHX
2346                     continue
2348             # Store a list with extensions.
2349             ext_info = {"name" : ext_name, "type" : ext_type}
2350             extensions.append(ext_info)
2352             # Pull in any commands we need. We infer types to pull in from the command
2353             # as well.
2354             for command in commands:
2355                 cmd_name = command.attrib["name"]
2356                 self._mark_command_required(cmd_name)
2358         # Sort in alphabetical order.
2359         self.extensions = sorted(extensions, key=lambda ext: ext["name"])
2361     def _parse_features(self, root):
2362         """ Parse the feature section, which describes Core commands and types needed. """
2363         requires = root.findall("./feature/require")
2365         for require in requires:
2366             LOGGER.info("Including features for {0}".format(require.attrib.get("comment")))
2367             for tag in require:
2368                 # Only deal with command. Other values which appear are enum and type for pulling in some
2369                 # constants and macros. Tricky to parse, so don't bother right now, we will generate them
2370                 # anyway for now.
2371                 name = tag.attrib["name"]
2372                 if tag.tag == "command":
2373                     self._mark_command_required(name)
2374                 elif tag.tag == "enum":
2375                     # We could pull in relevant constants here. Unfortunately
2376                     # this only gets half of them pulled in as others indirectly
2377                     # get pulled in through structures. Constants don't harm us,
2378                     # so don't bother.
2379                     pass
2380                 elif tag.tag == "type":
2381                     # Pull in types which may not have been pulled in through commands.
2383                     # Skip pull in for vk_platform.h for now.
2384                     if name == "vk_platform":
2385                         continue
2387                     type_info = self.types[name]
2388                     type_info["data"].required = True
2390     def _parse_types(self, root):
2391         """ Parse types section, which contains all data types e.g. structs, typedefs etcetera. """
2392         types = root.findall("./types/type")
2394         base_types = []
2395         bitmasks = []
2396         defines = []
2397         funcpointers = []
2398         handles = []
2399         structs = []
2401         for t in types:
2402             type_info = {}
2403             type_info["category"] = t.attrib.get("category", None)
2405             if type_info["category"] in ["include"]:
2406                 continue
2408             if type_info["category"] == "basetype":
2409                 name = t.find("name").text
2410                 _type = t.find("type").text
2411                 basetype = VkBaseType(name, _type)
2412                 base_types.append(basetype)
2413                 type_info["data"] = basetype
2415             if type_info["category"] == "bitmask":
2416                 name = t.find("name").text
2417                 _type = t.find("type").text
2419                 # Most bitmasks have a requires attribute used to pull in
2420                 # required '*FlagBits" enum.
2421                 requires = t.attrib.get("requires")
2422                 bitmask = VkBaseType(name, _type, requires=requires)
2423                 bitmasks.append(bitmask)
2424                 type_info["data"] = bitmask
2426             if type_info["category"] == "define":
2427                 name = t.attrib.get("name")
2428                 define = VkDefine.from_xml(t)
2429                 defines.append(define)
2430                 type_info["data"] = define
2432             if type_info["category"] == "enum":
2433                 name = t.attrib.get("name")
2434                 # The type section only contains enum names, not the actual definition.
2435                 # Since we already parsed the enum before, just link it in.
2436                 try:
2437                     type_info["data"] = self.enums[name]
2438                 except KeyError as e:
2439                     # Not all enums seem to be defined yet, typically that's for
2440                     # ones ending in 'FlagBits' where future extensions may add
2441                     # definitions.
2442                     type_info["data"] = None
2444             if type_info["category"] == "funcpointer":
2445                 funcpointer = VkFunctionPointer.from_xml(t)
2446                 funcpointers.append(funcpointer)
2447                 type_info["data"] = funcpointer
2449             if type_info["category"] == "handle":
2450                 handle = VkHandle.from_xml(t)
2451                 handles.append(handle)
2452                 type_info["data"] = handle
2454             if type_info["category"] in ["struct", "union"]:
2455                 # We store unions among structs as some structs depend
2456                 # on unions. The types are very similar in parsing and
2457                 # generation anyway. The official vulkan scripts use
2458                 # a similar kind of hack.
2459                 struct = VkStruct.from_xml(t)
2460                 structs.append(struct)
2461                 type_info["data"] = struct
2463             # Name is in general within a name tag else it is an optional
2464             # attribute on the type tag.
2465             name_elem = t.find("name")
2466             if name_elem is not None:
2467                 type_info["name"] = name_elem.text
2468             else:
2469                 type_info["name"] = t.attrib.get("name", None)
2471             # Store all type data in a shared dictionary, so we can easily
2472             # look up information for a given type. There are no duplicate
2473             # names.
2474             self.types[type_info["name"]] = type_info
2476         # We need detailed type information during code generation
2477         # on structs for alignment reasons. Unfortunately structs
2478         # are parsed among other types, so there is no guarantee
2479         # that any types needed have been parsed already, so set
2480         # the data now.
2481         for struct in structs:
2482             struct.set_type_info(self.types)
2484         # Guarantee everything is sorted, so code generation doesn't have
2485         # to deal with this.
2486         self.base_types = sorted(base_types, key=lambda base_type: base_type.name)
2487         self.bitmasks = sorted(bitmasks, key=lambda bitmask: bitmask.name)
2488         self.defines = defines
2489         self.funcpointers = sorted(funcpointers, key=lambda fp: fp.name)
2490         self.handles = sorted(handles, key=lambda handle: handle.name)
2491         self.structs = sorted(structs, key=lambda struct: struct.name)
2494 def main():
2495     parser = argparse.ArgumentParser()
2496     parser.add_argument("-v", "--verbose", action="count", default=0, help="increase output verbosity")
2498     args = parser.parse_args()
2499     if args.verbose == 0:
2500         LOGGER.setLevel(logging.WARNING)
2501     elif args.verbose == 1:
2502         LOGGER.setLevel(logging.INFO)
2503     else: # > 1
2504         LOGGER.setLevel(logging.DEBUG)
2506     registry = VkRegistry("vk.xml")
2507     generator = VkGenerator(registry)
2509     with open(WINE_VULKAN_H, "w") as f:
2510         generator.generate_vulkan_h(f)
2512     with open(WINE_VULKAN_DRIVER_H, "w") as f:
2513         generator.generate_vulkan_driver_h(f)
2515     with open(WINE_VULKAN_THUNKS_H, "w") as f:
2516         generator.generate_thunks_h(f, "wine_")
2518     with open(WINE_VULKAN_THUNKS_C, "w") as f:
2519         generator.generate_thunks_c(f, "wine_")
2521     with open(WINE_VULKAN_SPEC, "w") as f:
2522         generator.generate_vulkan_spec(f)
2524 if __name__ == "__main__":
2525     main()