ninput: Implement SetPropertyInteractionContext().
[wine.git] / dlls / winevulkan / make_vulkan
blobc32d9edc4e345c7e6ea943268bbb7912b56a0fda
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 os
24 import re
25 import sys
26 import urllib.request
27 import xml.etree.ElementTree as ET
28 from collections import OrderedDict
29 from collections.abc import Sequence
30 from enum import Enum
32 # This script generates code for a Wine Vulkan ICD driver from Vulkan's vk.xml.
33 # Generating the code is like 10x worse than OpenGL, which is mostly a calling
34 # convention passthrough.
36 # The script parses vk.xml and maps functions and types to helper objects. These
37 # helper objects simplify the xml parsing and map closely to the Vulkan types.
38 # The code generation utilizes the helper objects during code generation and
39 # most of the ugly work is carried out by these objects.
41 # Vulkan ICD challenges:
42 # - Vulkan ICD loader (vulkan-1.dll) relies on a section at the start of
43 #   'dispatchable handles' (e.g. VkDevice, VkInstance) for it to insert
44 #   its private data. It uses this area to stare its own dispatch tables
45 #   for loader internal use. This means any dispatchable objects need wrapping.
47 # - Vulkan structures have different alignment between win32 and 32-bit Linux.
48 #   This means structures with alignment differences need conversion logic.
49 #   Often structures are nested, so the parent structure may not need any
50 #   conversion, but some child may need some.
52 # vk.xml parsing challenges:
53 # - Contains type data for all platforms (generic Vulkan, Windows, Linux,..).
54 #   Parsing of extension information required to pull in types and functions
55 #   we really want to generate. Just tying all the data together is tricky.
57 # - Extensions can affect core types e.g. add new enum values, bitflags or
58 #   additional structure chaining through 'pNext' / 'sType'.
60 # - Arrays are used all over the place for parameters or for structure members.
61 #   Array length is often stored in a previous parameter or another structure
62 #   member and thus needs careful parsing.
64 LOGGER = logging.Logger("vulkan")
65 LOGGER.addHandler(logging.StreamHandler())
67 VK_XML_VERSION = "1.1.76"
69 # Filenames to create.
70 WINE_VULKAN_H = "../../include/wine/vulkan.h"
71 WINE_VULKAN_DRIVER_H = "../../include/wine/vulkan_driver.h"
72 WINE_VULKAN_LOADER_SPEC = "../vulkan-1/vulkan-1.spec"
73 WINE_VULKAN_SPEC = "winevulkan.spec"
74 WINE_VULKAN_THUNKS_C = "vulkan_thunks.c"
75 WINE_VULKAN_THUNKS_H = "vulkan_thunks.h"
77 # Extension enum values start at a certain offset (EXT_BASE).
78 # Relative to the offset each extension has a block (EXT_BLOCK_SIZE)
79 # of values.
80 # Start for a given extension is:
81 # EXT_BASE + (extension_number-1) * EXT_BLOCK_SIZE
82 EXT_BASE = 1000000000
83 EXT_BLOCK_SIZE = 1000
85 # In general instance extensions can't be automatically generated
86 # and need custom wrappers due to e.g. win32 / X11 specific code.
87 # List of supported instance extensions.
88 SUPPORTED_INSTANCE_EXTENSIONS = [
89     "VK_KHR_get_physical_device_properties2",
90     "VK_KHR_surface",
91     "VK_KHR_win32_surface",
94 BLACKLISTED_EXTENSIONS = [
95     # Handling of VK_EXT_debug_report requires some consideration. The win32
96     # loader already provides it for us and it is somewhat usable. If we add
97     # plumbing down to the native layer, we will get each message twice as we
98     # use 2 loaders (win32+native), but we may get output from the driver.
99     # In any case callback conversion is required.
100     "VK_EXT_debug_report",
101     "VK_EXT_display_control", # Requires VK_EXT_display_surface_counter
102     "VK_EXT_external_memory_dma_buf", # Linux specific
103     "VK_EXT_hdr_metadata", # Needs WSI work.
104     "VK_GOOGLE_display_timing",
105     "VK_KHR_device_group", # Needs some thought, but part of Vulkan 1.1 Core.
106     "VK_KHR_display", # Needs WSI work.
107     "VK_KHR_external_fence",
108     "VK_KHR_external_fence_fd",
109     "VK_KHR_external_fence_win32",
110     "VK_KHR_external_memory",
111     "VK_KHR_external_semaphore",
112     # Relates to external_semaphore and needs type conversions in bitflags.
113     "VK_KHR_external_semaphore_capabilities",
114     "VK_KHR_shared_presentable_image", # Needs WSI work.
115     "VK_KHR_win32_keyed_mutex",
116     "VK_NV_external_memory_win32",
119 # The Vulkan loader provides entry-points for core functionality and important
120 # extensions. Based on vulkan-1.def this amounts to WSI extensions on 1.0.51.
121 CORE_EXTENSIONS = [
122     "VK_KHR_display",
123     "VK_KHR_display_swapchain",
124     "VK_KHR_surface",
125     "VK_KHR_swapchain",
126     "VK_KHR_win32_surface",
129 # Functions part of our winevulkan graphics driver interface.
130 # DRIVER_VERSION should be bumped on any change to driver interface
131 # in FUNCTION_OVERRIDES
132 DRIVER_VERSION = 3
134 # Table of functions for which we have a special implementation.
135 # These are regular device / instance functions for which we need
136 # to do more work compared to a regular thunk or because they are
137 # part of the driver interface.
138 # - dispatch set whether we need a function pointer in the device
139 #   / instance dispatch table.
140 # - driver sets whether the API is part of the driver interface.
141 # - thunk sets whether to create a thunk in vulkan_thunks.c.
142 FUNCTION_OVERRIDES = {
143     # Global functions
144     "vkCreateInstance" : {"dispatch" : False, "driver" : True, "thunk" : False},
145     "vkEnumerateInstanceExtensionProperties" : {"dispatch" : False, "driver" : True, "thunk" : False},
146     "vkGetInstanceProcAddr": {"dispatch" : False, "driver" : True, "thunk" : False},
148     # Instance functions
149     "vkCreateDevice" : {"dispatch" : True, "driver" : False, "thunk" : False},
150     "vkDestroyInstance" : {"dispatch" : False, "driver" : True, "thunk" : False },
151     "vkEnumerateDeviceExtensionProperties" : {"dispatch" : True, "driver" : False, "thunk" : False},
152     "vkEnumeratePhysicalDevices" : {"dispatch" : True, "driver" : False, "thunk" : False},
154     # Device functions
155     "vkAllocateCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : False},
156     "vkCmdExecuteCommands" : {"dispatch" : True, "driver" : False, "thunk" : False},
157     "vkDestroyDevice" : {"dispatch" : True, "driver" : False, "thunk" : False},
158     "vkFreeCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : False},
159     "vkGetDeviceProcAddr" : {"dispatch" : False, "driver" : True, "thunk" : False},
160     "vkGetDeviceQueue" : {"dispatch": True, "driver" : False, "thunk" : False},
161     "vkQueueSubmit" : {"dispatch": True, "driver" : False, "thunk" : False},
163     # VK_KHR_surface
164     "vkDestroySurfaceKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
165     "vkGetPhysicalDeviceSurfaceSupportKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
166     "vkGetPhysicalDeviceSurfaceCapabilitiesKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
167     "vkGetPhysicalDeviceSurfaceFormatsKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
168     "vkGetPhysicalDeviceSurfacePresentModesKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
170     # VK_KHR_win32_surface
171     "vkCreateWin32SurfaceKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
172     "vkGetPhysicalDeviceWin32PresentationSupportKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
174     # VK_KHR_swapchain
175     "vkAcquireNextImageKHR": {"dispatch" : True, "driver" : True, "thunk" : True},
176     "vkCreateSwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
177     "vkDestroySwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
178     "vkGetSwapchainImagesKHR": {"dispatch" : True, "driver" : True, "thunk" : True},
179     "vkQueuePresentKHR": {"dispatch" : True, "driver" : True, "thunk" : True},
183 class Direction(Enum):
184     """ Parameter direction: input, output, input_output. """
185     INPUT = 1
186     OUTPUT = 2
187     INPUT_OUTPUT = 3
190 class VkBaseType(object):
191     def __init__(self, name, _type, alias=False, requires=None):
192         """ Vulkan base type class.
194         VkBaseType is mostly used by Vulkan to define its own
195         base types like VkFlags through typedef out of e.g. uint32_t.
197         Args:
198             name (:obj:'str'): Name of the base type.
199             _type (:obj:'str'): Underlaying type
200             alias (bool): type is an alias or not.
201             requires (:obj:'str', optional): Other types required.
202                 Often bitmask values pull in a *FlagBits type.
203         """
204         self.name = name
205         self.type = _type
206         self.alias = alias
207         self.requires = requires
208         self.required = False
210     def definition(self):
211         # Definition is similar for alias or non-alias as type
212         # is already set to alias.
213         return "typedef {0} {1};\n".format(self.type, self.name)
215     def is_alias(self):
216         return self.alias
219 class VkConstant(object):
220     def __init__(self, name, value):
221         self.name = name
222         self.value = value
224     def definition(self):
225         text = "#define {0} {1}\n".format(self.name, self.value)
226         return text
229 class VkDefine(object):
230     def __init__(self, name, value):
231         self.name = name
232         self.value = value
234     @staticmethod
235     def from_xml(define):
236         name_elem = define.find("name")
238         if name_elem is None:
239             # <type category="define" name="some_name">some_value</type>
240             # At the time of writing there is only 1 define of this category
241             # 'VK_DEFINE_NON_DISPATCHABLE_HANDLE'.
242             name = define.attrib.get("name")
244             # We override behavior of VK_DEFINE_NON_DISPATCHABLE handle as the default
245             # definition various between 64-bit (uses pointers) and 32-bit (uses uint64_t).
246             # This complicates TRACEs in the thunks, so just use uint64_t.
247             if name == "VK_DEFINE_NON_DISPATCHABLE_HANDLE":
248                 value = "#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object;"
249             else:
250                 value = define.text
251             return VkDefine(name, value)
253         # With a name element the structure is like:
254         # <type category="define"><name>some_name</name>some_value</type>
255         name = name_elem.text
257         # Perform minimal parsing for Vulkan constants, which we don't need, but are referenced
258         # elsewhere in vk.xml.
259         # - VK_API_VERSION is a messy, deprecated constant and we don't want generate code for it.
260         # - AHardwareBuffer/ANativeWindow are forard declarations for Android types, which leaked
261         #   into the define region.
262         if name in ["VK_API_VERSION", "AHardwareBuffer", "ANativeWindow"]:
263             return VkDefine(name, None)
265         # The body of the define is basically unstructured C code. It is not meant for easy parsing.
266         # Some lines contain deprecated values or comments, which we try to filter out.
267         value = ""
268         for line in define.text.splitlines():
269             # Skip comments or deprecated values.
270             if "//" in line:
271                 continue
272             value += line
274         for child in define:
275             value += child.text
276             if child.tail is not None:
277                 # Split comments for VK_API_VERSION_1_0 / VK_API_VERSION_1_1
278                 if "//" in child.tail:
279                     value += child.tail.split("//")[0]
280                 else:
281                     value += child.tail
283         return VkDefine(name, value.rstrip(' '))
285     def definition(self):
286         if self.value is None:
287             return ""
289         # Nothing to do as the value was already put in the right form during parsing.
290         return "{0}\n".format(self.value)
293 class VkEnum(object):
294     def __init__(self, name, values, alias=False):
295         self.name = name
296         self.values = values
297         self.required = False
298         self.alias = alias
300     @staticmethod
301     def from_alias(enum, alias):
302         name = enum.attrib.get("name")
303         return VkEnum(name, alias.values)
305     @staticmethod
306     def from_xml(enum):
307         name = enum.attrib.get("name")
308         values = []
310         for v in enum.findall("enum"):
311             # Value is either a value or a bitpos, only one can exist.
312             value = v.attrib.get("value")
313             if value is None:
314                 # bitmask
315                 value = 1 << int(v.attrib.get("bitpos"))
316                 values.append(VkEnumValue(v.attrib.get("name"), value, hex=True))
317             else:
318                 # Some values are in hex form. We want to preserve the hex representation
319                 # at least when we convert back to a string. Internally we want to use int.
320                 if "0x" in value:
321                     values.append(VkEnumValue(v.attrib.get("name"), int(value, 0), hex=True))
322                 else:
323                     values.append(VkEnumValue(v.attrib.get("name"), int(value, 0)))
325         # vulkan.h contains a *_MAX_ENUM value set to 32-bit at the time of writing,
326         # which is to prepare for extensions as they can add values and hence affect
327         # the size definition.
328         max_name = re.sub(r'([0-9a-z_])([A-Z0-9])',r'\1_\2',name).upper() + "_MAX_ENUM"
329         values.append(VkEnumValue(max_name, 0x7fffffff, hex=True))
331         return VkEnum(name, values)
333     def add(self, value):
334         """ Add a value to enum. """
336         # Extensions can add new enum values. When an extension is promoted to Core
337         # the registry defines the value twice once for old extension and once for
338         # new Core features. Ignore the duplicate entry.
339         for v in self.values:
340             if v.value == value.value:
341                 LOGGER.debug("Adding duplicate enum value {0} to {1}".format(v, self.name))
342                 return
343         self.values.append(value)
345     def definition(self):
346         text = "typedef enum {0}\n{{\n".format(self.name)
348         # Print values sorted, values can have been added in a random order.
349         values = sorted(self.values, key=lambda value: value.value)
350         for value in values:
351             text += "    {0},\n".format(value.definition())
352         text += "}} {0};\n\n".format(self.name)
353         return text
355     def is_alias(self):
356         return self.alias
359 class VkEnumValue(object):
360     def __init__(self, name, value, hex=False):
361         self.name = name
362         self.value = value
363         self.hex = hex
365     def __repr__(self):
366         return "{0}={1}".format(self.name, self.value)
368     def definition(self):
369         """ Convert to text definition e.g. VK_FOO = 1 """
371         # Hex is commonly used for FlagBits and sometimes within
372         # a non-FlagBits enum for a bitmask value as well.
373         if self.hex:
374             return "{0} = 0x{1:08x}".format(self.name, self.value)
375         else:
376             return "{0} = {1}".format(self.name, self.value)
379 class VkFunction(object):
380     def __init__(self, _type=None, name=None, params=[], extensions=[], alias=False):
381         self.extensions = []
382         self.name = name
383         self.type = _type
384         self.params = params
385         self.alias = alias
387         # For some functions we need some extra metadata from FUNCTION_OVERRIDES.
388         func_info = FUNCTION_OVERRIDES.get(self.name, None)
389         self.dispatch = func_info["dispatch"] if func_info is not None else True
390         self.driver = func_info["driver"] if func_info is not None else False
391         self.thunk_needed = func_info["thunk"] if func_info is not None else True
393         # Required is set while parsing which APIs and types are required
394         # and is used by the code generation.
395         self.required = False
397     @staticmethod
398     def from_alias(command, alias):
399         """ Create VkFunction from an alias command.
401         Args:
402             command: xml data for command
403             alias (VkFunction): function to use as a base for types / parameters.
405         Returns:
406             VkFunction
407         """
408         func_name = command.attrib.get("name")
409         func_type = alias.type
410         params = alias.params
412         return VkFunction(_type=func_type, name=func_name, params=params, alias=True)
414     @staticmethod
415     def from_xml(command, types):
416         proto = command.find("proto")
417         func_name = proto.find("name").text
418         func_type = proto.find("type").text
420         params = []
421         for param in command.findall("param"):
422             vk_param = VkParam.from_xml(param, types)
423             params.append(vk_param)
425         return VkFunction(_type=func_type, name=func_name, params=params)
427     def get_conversions(self):
428         """ Get a list of conversion functions required for this function if any.
429         Parameters which are structures may require conversion between win32
430         and the host platform. This function returns a list of conversions
431         required.
432         """
434         conversions = []
435         for param in self.params:
436             convs = param.get_conversions()
437             if convs is not None:
438                 conversions.extend(convs)
440         return conversions
442     def is_alias(self):
443         return self.alias
445     def is_core_func(self):
446         """ Returns whether the function is a Vulkan core function.
447         Core functions are APIs defined by the Vulkan spec to be part of the
448         Core API as well as several KHR WSI extensions.
449         """
451         if not self.extensions:
452             return True
454         return any(ext in self.extensions for ext in CORE_EXTENSIONS)
456     def is_device_func(self):
457         # If none of the other, it must be a device function
458         return not self.is_global_func() and not self.is_instance_func()
460     def is_driver_func(self):
461         """ Returns if function is part of Wine driver interface. """
462         return self.driver
464     def is_global_func(self):
465         # Treat vkGetInstanceProcAddr as a global function as it
466         # can operate with NULL for vkInstance.
467         if self.name == "vkGetInstanceProcAddr":
468             return True
469         # Global functions are not passed a dispatchable object.
470         elif self.params[0].is_dispatchable():
471             return False
472         return True
474     def is_instance_func(self):
475         # Instance functions are passed VkInstance or VkPhysicalDevice.
476         if self.params[0].type in ["VkInstance", "VkPhysicalDevice"]:
477             return True
478         return False
480     def is_required(self):
481         return self.required
483     def needs_conversion(self):
484         """ Check if the function needs any input/output type conversion.
485         Functions need input/output conversion if struct parameters have
486         alignment differences between Win32 and Linux 32-bit.
487         """
489         for p in self.params:
490             if p.needs_conversion():
491                 LOGGER.debug("Parameter {0} to {1} requires conversion".format(p.name, self.name))
492                 return True
494         return False
496     def needs_dispatch(self):
497         return self.dispatch
499     def needs_thunk(self):
500         return self.thunk_needed
502     def pfn(self, prefix="p", call_conv=None, conv=False):
503         """ Create function pointer. """
505         if call_conv:
506             pfn = "{0} ({1} *{2}_{3})(".format(self.type, call_conv, prefix, self.name)
507         else:
508             pfn = "{0} (*{1}_{2})(".format(self.type, prefix, self.name)
510         for i, param in enumerate(self.params):
511             if param.const:
512                 pfn += param.const + " "
514             pfn += param.type
515             if conv and param.needs_conversion():
516                 pfn += "_host"
518             if param.is_pointer():
519                 pfn += " " + param.pointer
521             if param.array_len is not None:
522                 pfn += "[{0}]".format(param.array_len)
524             if i < len(self.params) - 1:
525                 pfn += ", "
526         pfn += ")"
527         return pfn
529     def prototype(self, call_conv=None, prefix=None, postfix=None):
530         """ Generate prototype for given function.
532         Args:
533             call_conv (str, optional): calling convention e.g. WINAPI
534             prefix (str, optional): prefix to append prior to function name e.g. vkFoo -> wine_vkFoo
535             postfix (str, optional): text to append after function name but prior to semicolon e.g. DECLSPEC_HIDDEN
536         """
538         proto = "{0}".format(self.type)
540         if call_conv is not None:
541             proto += " {0}".format(call_conv)
543         if prefix is not None:
544             proto += " {0}{1}(".format(prefix, self.name)
545         else:
546             proto += " {0}(".format(self.name)
548         # Add all the parameters.
549         proto += ", ".join([p.definition() for p in self.params])
551         if postfix is not None:
552             proto += ") {0}".format(postfix)
553         else:
554             proto += ")"
556         return proto
558     def body(self):
559         body = "    {0}".format(self.trace())
561         params = ", ".join([p.variable(conv=False) for p in self.params])
563         # Call the native Vulkan function.
564         if self.type == "void":
565             body += "    {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
566         else:
567             body += "    return {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
569         return body
571     def body_conversion(self):
572         body = ""
574         # Declare a variable to hold the result for non-void functions.
575         if self.type != "void":
576             body += "    {0} result;\n".format(self.type)
578         # Declare any tmp parameters for conversion.
579         for p in self.params:
580             if not p.needs_conversion():
581                 continue
583             if p.is_dynamic_array():
584                 body += "    {0}_host *{1}_host;\n".format(p.type, p.name)
585             else:
586                 body += "    {0}_host {1}_host;\n".format(p.type, p.name)
588         body += "    {0}\n".format(self.trace())
590         # Call any win_to_host conversion calls.
591         for p in self.params:
592             if not p.needs_input_conversion():
593                 continue
595             body += p.copy(Direction.INPUT)
597         # Build list of parameters containing converted and non-converted parameters.
598         # The param itself knows if conversion is needed and applies it when we set conv=True.
599         params = ", ".join([p.variable(conv=True) for p in self.params])
601         # Call the native Vulkan function.
602         if self.type == "void":
603             body += "    {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
604         else:
605             body += "    result = {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
607         body += "\n"
609         # Call any host_to_win conversion calls.
610         for p in self.params:
611             if not p.needs_output_conversion():
612                 continue
614             body += p.copy(Direction.OUTPUT)
616         # Perform any required cleanups. Most of these are for array functions.
617         for p in self.params:
618             if not p.needs_free():
619                 continue
621             body += p.free()
623         # Finally return the result.
624         if self.type != "void":
625             body += "    return result;\n"
627         return body
629     def spec(self, prefix=None, symbol=None):
630         """ Generate spec file entry for this function.
632         Args
633             prefix (str, optional): prefix to prepend to entry point name.
634             symbol (str, optional): allows overriding the name of the function implementing the entry point.
635         """
637         spec = ""
638         params = " ".join([p.spec() for p in self.params])
639         if prefix is not None:
640             spec += "@ stdcall {0}{1}({2})".format(prefix, self.name, params)
641         else:
642             spec += "@ stdcall {0}({1})".format(self.name, params)
644         if symbol is not None:
645             spec += " " + symbol
647         spec += "\n"
648         return spec
650     def stub(self, call_conv=None, prefix=None):
651         stub = self.prototype(call_conv=call_conv, prefix=prefix)
652         stub += "\n{\n"
653         stub += "    {0}".format(self.trace(message="stub: ", trace_func="FIXME"))
655         if self.type == "VkResult":
656             stub += "    return VK_ERROR_OUT_OF_HOST_MEMORY;\n"
657         elif self.type == "VkBool32":
658             stub += "    return VK_FALSE;\n"
659         elif self.type == "PFN_vkVoidFunction":
660             stub += "    return NULL;\n"
662         stub += "}\n\n"
663         return stub
665     def thunk(self, call_conv=None, prefix=None):
666         thunk = self.prototype(call_conv=call_conv, prefix=prefix)
667         thunk += "\n{\n"
669         if self.needs_conversion():
670             thunk += "#if defined(USE_STRUCT_CONVERSION)\n"
671             thunk += self.body_conversion()
672             thunk += "#else\n"
673             thunk += self.body()
674             thunk += "#endif\n"
675         else:
676             thunk += self.body()
678         thunk += "}\n\n"
679         return thunk
681     def trace(self, message=None, trace_func=None):
682         """ Create a trace string including all parameters.
684         Args:
685             message (str, optional): text to print at start of trace message e.g. 'stub: '
686             trace_func (str, optional): used to override trace function e.g. FIXME, printf, etcetera.
687         """
688         if trace_func is not None:
689             trace = "{0}(\"".format(trace_func)
690         else:
691             trace = "TRACE(\""
693         if message is not None:
694             trace += message
696         # First loop is for all the format strings.
697         trace += ", ".join([p.format_string() for p in self.params])
698         trace += "\\n\""
700         # Second loop for parameter names and optional conversions.
701         for param in self.params:
702             if param.format_conv is not None:
703                 trace += ", " + param.format_conv.format(param.name)
704             else:
705                 trace += ", {0}".format(param.name)
706         trace += ");\n"
708         return trace
711 class VkFunctionPointer(object):
712     def __init__(self, _type, name, members):
713         self.name = name
714         self.members = members
715         self.type = _type
716         self.required = False
718     @staticmethod
719     def from_xml(funcpointer):
720         members = []
721         begin = None
723         for t in funcpointer.findall("type"):
724             # General form:
725             # <type>void</type>*       pUserData,
726             # Parsing of the tail (anything past </type>) is tricky since there
727             # can be other data on the next line like: const <type>int</type>..
729             const = True if begin and "const" in begin else False
730             _type = t.text
731             lines = t.tail.split(",\n")
732             if lines[0][0] == "*":
733                 pointer = "*"
734                 name = lines[0][1:].strip()
735             else:
736                 pointer = None
737                 name = lines[0].strip()
739             # Filter out ); if it is contained.
740             name = name.partition(");")[0]
742             # If tail encompasses multiple lines, assign the second line to begin
743             # for the next line.
744             try:
745                 begin = lines[1].strip()
746             except IndexError:
747                 begin = None
749             members.append(VkMember(const=const, _type=_type, pointer=pointer, name=name))
751         _type = funcpointer.text
752         name = funcpointer.find("name").text
753         return VkFunctionPointer(_type, name, members)
755     def definition(self):
756         text = "{0} {1})(\n".format(self.type, self.name)
758         first = True
759         if len(self.members) > 0:
760             for m in self.members:
761                 if first:
762                     text += "    " + m.definition()
763                     first = False
764                 else:
765                     text += ",\n    " + m.definition()
766         else:
767             # Just make the compiler happy by adding a void parameter.
768             text += "void"
769         text += ");\n"
770         return text
773 class VkHandle(object):
774     def __init__(self, name, _type, parent, alias=None):
775         self.name = name
776         self.type = _type
777         self.parent = parent
778         self.alias = alias
779         self.required = False
781     @staticmethod
782     def from_alias(handle, alias):
783         name = handle.attrib.get("name")
784         return VkHandle(name, alias.type, alias.parent, alias=alias)
786     @staticmethod
787     def from_xml(handle):
788         name = handle.find("name").text
789         _type = handle.find("type").text
790         parent = handle.attrib.get("parent") # Most objects have a parent e.g. VkQueue has VkDevice.
791         return VkHandle(name, _type, parent)
793     def dispatch_table(self):
794         if not self.is_dispatchable():
795             return None
797         if self.parent is None:
798             # Should only happen for VkInstance
799             return "funcs"
800         elif self.name == "VkDevice":
801             # VkDevice has VkInstance as a parent, but has its own dispatch table.
802             return "funcs"
803         elif self.parent in ["VkInstance", "VkPhysicalDevice"]:
804             return "instance->funcs"
805         elif self.parent in ["VkDevice", "VkCommandPool"]:
806             return "device->funcs"
807         else:
808             LOGGER.error("Unhandled dispatchable parent: {0}".format(self.parent))
810     def definition(self):
811         """ Generates handle definition e.g. VK_DEFINE_HANDLE(vkInstance) """
813         # Legacy types are typedef'ed to the new type if they are aliases.
814         if self.is_alias():
815             return "typedef {0} {1};\n".format(self.alias.name, self.name)
817         return "{0}({1})\n".format(self.type, self.name)
819     def is_alias(self):
820         return self.alias is not None
822     def is_dispatchable(self):
823         """ Some handles like VkInstance, VkDevice are dispatchable objects,
824         which means they contain a dispatch table of function pointers.
825         """
826         return self.type == "VK_DEFINE_HANDLE"
828     def is_required(self):
829         return self.required
831     def native_handle(self):
832         """ Provide access to the native handle of a dispatchable object.
834         Dispatchable objects wrap an underlying 'native' object.
835         This method provides access to the native object.
836         """
837         if not self.is_dispatchable():
838             return None
840         if self.name == "VkCommandBuffer":
841             return "command_buffer"
842         elif self.name == "VkDevice":
843             return "device"
844         elif self.name == "VkInstance":
845             return "instance"
846         elif self.name == "VkPhysicalDevice":
847             return "phys_dev"
848         elif self.name == "VkQueue":
849             return "queue"
850         else:
851             LOGGER.error("Unhandled native handle for: {0}".format(self.name))
854 class VkMember(object):
855     def __init__(self, const=False, struct_fwd_decl=False,_type=None, pointer=None, name=None, array_len=None,
856             dyn_array_len=None, optional=False, extension_structs=None):
857         self.const = const
858         self.struct_fwd_decl = struct_fwd_decl
859         self.name = name
860         self.pointer = pointer
861         self.type = _type
862         self.type_info = None
863         self.array_len = array_len
864         self.dyn_array_len = dyn_array_len
865         self.optional = optional
866         self.extension_structs = extension_structs
868     def __eq__(self, other):
869         """ Compare member based on name against a string.
871         This method is for convenience by VkStruct, which holds a number of members and needs quick checking
872         if certain members exist.
873         """
875         if self.name == other:
876             return True
878         return False
880     def __repr__(self):
881         return "{0} {1} {2} {3} {4} {5} {6}".format(self.const, self.struct_fwd_decl, self.type, self.pointer,
882                 self.name, self.array_len, self.dyn_array_len)
884     @staticmethod
885     def from_xml(member):
886         """ Helper function for parsing a member tag within a struct or union. """
888         name_elem = member.find("name")
889         type_elem = member.find("type")
891         const = False
892         struct_fwd_decl = False
893         member_type = None
894         pointer = None
895         array_len = None
897         if member.text:
898             if "const" in member.text:
899                 const = True
901             # Some members contain forward declarations:
902             # - VkBaseInstructure has a member "const struct VkBaseInStructure *pNext"
903             # - VkWaylandSurfaceCreateInfoKHR has a member "struct wl_display *display"
904             if "struct" in member.text:
905                 struct_fwd_decl = True
907         if type_elem is not None:
908             member_type = type_elem.text
909             if type_elem.tail is not None:
910                 pointer = type_elem.tail.strip() if type_elem.tail.strip() != "" else None
912         # Name of other member within, which stores the number of
913         # elements pointed to be by this member.
914         dyn_array_len = member.get("len", None)
916         if "validextensionstructs" in member.attrib:
917             extension_structs = member.get("validextensionstructs").split(",")
918         else:
919             extension_structs = None
921         # Some members are optional, which is important for conversion code e.g. not dereference NULL pointer.
922         optional = True if member.get("optional") else False
924         # Usually we need to allocate memory for dynamic arrays. We need to do the same in a few other cases
925         # like for VkCommandBufferBeginInfo.pInheritanceInfo. Just threat such cases as dynamic arrays of
926         # size 1 to simplify code generation.
927         if dyn_array_len is None and pointer is not None:
928             dyn_array_len = 1
930         # Some members are arrays, attempt to parse these. Formats include:
931         # <member><type>char</type><name>extensionName</name>[<enum>VK_MAX_EXTENSION_NAME_SIZE</enum>]</member>
932         # <member><type>uint32_t</type><name>foo</name>[4]</member>
933         if name_elem.tail and name_elem.tail[0] == '[':
934             LOGGER.debug("Found array type")
935             enum_elem = member.find("enum")
936             if enum_elem is not None:
937                 array_len = enum_elem.text
938             else:
939                 # Remove brackets around length
940                 array_len = name_elem.tail.strip("[]")
942         return VkMember(const=const, struct_fwd_decl=struct_fwd_decl, _type=member_type, pointer=pointer, name=name_elem.text,
943                 array_len=array_len, dyn_array_len=dyn_array_len, optional=optional, extension_structs=extension_structs)
945     def copy(self, input, output, direction):
946         """ Helper method for use by conversion logic to generate a C-code statement to copy this member. """
948         if self.needs_conversion():
949             if self.is_dynamic_array():
950                 if direction == Direction.OUTPUT:
951                     LOGGER.warn("TODO: implement copying of returnedonly dynamic array for {0}.{1}".format(self.type, self.name))
952                 else:
953                     # Array length is either a variable name (string) or an int.
954                     count = self.dyn_array_len if isinstance(self.dyn_array_len, int) else "{0}{1}".format(input, self.dyn_array_len)
955                     return "{0}{1} = convert_{2}_array_win_to_host({3}{1}, {4});\n".format(output, self.name, self.type, input, count)
956             elif self.is_static_array():
957                 count = self.array_len
958                 if direction == Direction.OUTPUT:
959                     # Needed by VkMemoryHeap.memoryHeaps
960                     return "convert_{0}_static_array_host_to_win({2}{1}, {3}{1}, {4});\n".format(self.type, self.name, input, output, count)
961                 else:
962                     # Nothing needed this yet.
963                     LOGGER.warn("TODO: implement copying of static array for {0}.{1}".format(self.type, self.name))
964             else:
965                 if direction == Direction.OUTPUT:
966                     return "convert_{0}_host_to_win(&{2}{1}, &{3}{1});\n".format(self.type, self.name, input, output)
967                 else:
968                     return "convert_{0}_win_to_host(&{2}{1}, &{3}{1});\n".format(self.type, self.name, input, output)
969         elif self.is_static_array():
970             bytes_count = "{0} * sizeof({1})".format(self.array_len, self.type)
971             return "memcpy({0}{1}, {2}{1}, {3});\n".format(output, self.name, input, bytes_count)
972         else:
973             return "{0}{1} = {2}{1};\n".format(output, self.name, input)
975     def definition(self, align=False, conv=False):
976         """ Generate prototype for given function.
978         Args:
979             align (bool, optional): Enable alignment if a type needs it. This adds WINE_VK_ALIGN(8) to a member.
980             conv (bool, optional): Enable conversion if a type needs it. This appends '_host' to the name.
981         """
983         text = ""
984         if self.is_const():
985             text += "const "
987         if self.is_struct_forward_declaration():
988             text += "struct "
990         if conv and self.is_struct():
991             text += "{0}_host".format(self.type)
992         else:
993             text += self.type
995         if self.is_pointer():
996             text += " {0}{1}".format(self.pointer, self.name)
997         else:
998             if align and self.needs_alignment():
999                 text += " WINE_VK_ALIGN(8) " + self.name
1000             else:
1001                 text += " " + self.name
1003         if self.is_static_array():
1004             text += "[{0}]".format(self.array_len)
1006         return text
1008     def get_conversions(self):
1009         """ Return any conversion description for this member and its children when conversion is needed. """
1011         # Check if we need conversion either for this member itself or for any child members
1012         # in case member represents a struct.
1013         if not self.needs_conversion():
1014             return None
1016         conversions = []
1018         # Collect any conversion for any member structs.
1019         struct = self.type_info["data"]
1020         for m in struct:
1021             if m.needs_conversion():
1022                 conversions.extend(m.get_conversions())
1024         struct = self.type_info["data"]
1025         direction = Direction.OUTPUT if struct.returnedonly else Direction.INPUT
1026         if self.is_dynamic_array():
1027             conversions.append(ConversionFunction(False, True, direction, struct))
1028         elif self.is_static_array():
1029             conversions.append(ConversionFunction(True, False, direction, struct))
1030         else:
1031             conversions.append(ConversionFunction(False, False, direction, struct))
1033         if self.needs_free():
1034             conversions.append(FreeFunction(self.is_dynamic_array(), struct))
1036         return conversions
1038     def is_const(self):
1039         return self.const
1041     def is_dynamic_array(self):
1042         """ Returns if the member is an array element.
1043         Vulkan uses this for dynamically sized arrays for which
1044         there is a 'count' parameter.
1045         """
1046         return self.dyn_array_len is not None
1048     def is_handle(self):
1049         return self.type_info["category"] == "handle"
1051     def is_pointer(self):
1052         return self.pointer is not None
1054     def is_static_array(self):
1055         """ Returns if the member is an array.
1056         Vulkan uses this often for fixed size arrays in which the
1057         length is part of the member.
1058         """
1059         return self.array_len is not None
1061     def is_struct(self):
1062         return self.type_info["category"] == "struct"
1064     def is_struct_forward_declaration(self):
1065         return self.struct_fwd_decl
1067     def is_union(self):
1068         return self.type_info["category"] == "union"
1070     def needs_alignment(self):
1071         """ Check if this member needs alignment for 64-bit data.
1072         Various structures need alignment on 64-bit variables due
1073         to compiler differences on 32-bit between Win32 and Linux.
1074         """
1076         if self.is_pointer():
1077             return False
1078         elif self.type == "size_t":
1079             return False
1080         elif self.type in ["uint64_t", "VkDeviceSize"]:
1081             return True
1082         elif self.is_struct():
1083             struct = self.type_info["data"]
1084             return struct.needs_alignment()
1085         elif self.is_handle():
1086             # Dispatchable handles are pointers to objects, while
1087             # non-dispatchable are uint64_t and hence need alignment.
1088             handle = self.type_info["data"]
1089             return False if handle.is_dispatchable() else True
1090         return False
1092     def needs_conversion(self):
1093         """ Structures requiring alignment, need conversion between win32 and host. """
1095         if not self.is_struct():
1096             return False
1098         struct = self.type_info["data"]
1099         return struct.needs_conversion()
1101     def needs_free(self):
1102         if not self.needs_conversion():
1103             return False
1105         if self.is_dynamic_array():
1106             return True
1108         # TODO: some non-pointer structs and optional pointer structs may need freeing,
1109         # though none of this type have been encountered yet.
1110         return False
1112     def set_type_info(self, type_info):
1113         """ Helper function to set type information from the type registry.
1114         This is needed, because not all type data is available at time of
1115         parsing.
1116         """
1117         self.type_info = type_info
1120 class VkParam(object):
1121     """ Helper class which describes a parameter to a function call. """
1123     def __init__(self, type_info, const=None, pointer=None, name=None, array_len=None, dyn_array_len=None):
1124         self.const = const
1125         self.name = name
1126         self.array_len = array_len
1127         self.dyn_array_len = dyn_array_len
1128         self.pointer = pointer
1129         self.type_info = type_info
1130         self.type = type_info["name"] # For convenience
1131         self.handle = type_info["data"] if type_info["category"] == "handle" else None
1132         self.struct = type_info["data"] if type_info["category"] == "struct" else None
1134         self._set_direction()
1135         self._set_format_string()
1136         self._set_conversions()
1138     def __repr__(self):
1139         return "{0} {1} {2} {3} {4}".format(self.const, self.type, self.pointer, self.name, self.array_len, self.dyn_array_len)
1141     @staticmethod
1142     def from_xml(param, types):
1143         """ Helper function to create VkParam from xml. """
1145         # Parameter parsing is slightly tricky. All the data is contained within
1146         # a param tag, but some data is within subtags while others are text
1147         # before or after the type tag.
1148         # Common structure:
1149         # <param>const <type>char</type>* <name>pLayerName</name></param>
1151         name_elem = param.find("name")
1152         array_len = None
1153         name = name_elem.text
1154         # Tail contains array length e.g. for blendConstants param of vkSetBlendConstants
1155         if name_elem.tail is not None:
1156             array_len = name_elem.tail.strip("[]")
1158         # Name of other parameter in function prototype, which stores the number of
1159         # elements pointed to be by this parameter.
1160         dyn_array_len = param.get("len", None)
1162         const = param.text.strip() if param.text else None
1163         type_elem = param.find("type")
1164         pointer = type_elem.tail.strip() if type_elem.tail.strip() != "" else None
1166         # Since we have parsed all types before hand, this should not happen.
1167         type_info = types.get(type_elem.text, None)
1168         if type_info is None:
1169             LOGGER.err("type info not found for: {0}".format(type_elem.text))
1171         return VkParam(type_info, const=const, pointer=pointer, name=name, array_len=array_len, dyn_array_len=dyn_array_len)
1173     def _set_conversions(self):
1174         """ Internal helper function to configure any needed conversion functions. """
1176         self.free_func = None
1177         self.input_conv = None
1178         self.output_conv = None
1179         if not self.needs_conversion():
1180             return
1182         # Input functions require win to host conversion.
1183         if self._direction in [Direction.INPUT, Direction.INPUT_OUTPUT]:
1184             self.input_conv = ConversionFunction(False, self.is_dynamic_array(), Direction.INPUT, self.struct)
1186         # Output functions require host to win conversion.
1187         if self._direction in [Direction.INPUT_OUTPUT, Direction.OUTPUT]:
1188             self.output_conv = ConversionFunction(False, self.is_dynamic_array(), Direction.OUTPUT, self.struct)
1190         # Dynamic arrays, but also some normal structs (e.g. VkCommandBufferBeginInfo) need memory
1191         # allocation and thus some cleanup.
1192         if self.is_dynamic_array() or self.struct.needs_free():
1193             self.free_func = FreeFunction(self.is_dynamic_array(), self.struct)
1195     def _set_direction(self):
1196         """ Internal helper function to set parameter direction (input/output/input_output). """
1198         # The parameter direction needs to be determined from hints in vk.xml like returnedonly,
1199         # parameter constness and other heuristics.
1200         # For now we need to get this right for structures as we need to convert these, we may have
1201         # missed a few other edge cases (e.g. count variables).
1202         # See also https://github.com/KhronosGroup/Vulkan-Docs/issues/610
1204         if not self.is_pointer():
1205             self._direction = Direction.INPUT
1206         elif self.is_const() and self.is_pointer():
1207             self._direction = Direction.INPUT
1208         elif self.is_struct():
1209             if not self.struct.returnedonly:
1210                 self._direction = Direction.INPUT
1211                 return
1213             # Returnedonly hints towards output, however in some cases
1214             # it is inputoutput. In particular if pNext / sType exist,
1215             # which are used to link in other structures without having
1216             # to introduce new APIs. E.g. vkGetPhysicalDeviceProperties2KHR.
1217             if "pNext" in self.struct:
1218                 self._direction = Direction.INPUT_OUTPUT
1219                 return
1221             self._direction = Direction.OUTPUT
1222         else:
1223             # This should mostly be right. Count variables can be inout, but we don't care about these yet.
1224             self._direction = Direction.OUTPUT
1226     def _set_format_string(self):
1227         """ Internal helper function to be used by constructor to set format string. """
1229         # Determine a format string used by code generation for traces.
1230         # 64-bit types need a conversion function.
1231         self.format_conv = None
1232         if self.is_static_array() or self.is_pointer():
1233             self.format_str = "%p"
1234         else:
1235             if self.type_info["category"] in ["bitmask", "enum"]:
1236                 self.format_str = "%#x"
1237             elif self.is_handle():
1238                 # We use uint64_t for non-dispatchable handles as opposed to pointers
1239                 # for dispatchable handles.
1240                 if self.handle.is_dispatchable():
1241                     self.format_str = "%p"
1242                 else:
1243                     self.format_str = "0x%s"
1244                     self.format_conv = "wine_dbgstr_longlong({0})"
1245             elif self.type == "float":
1246                 self.format_str = "%f"
1247             elif self.type == "int":
1248                 self.format_str = "%d"
1249             elif self.type == "int32_t":
1250                 self.format_str = "%d"
1251             elif self.type == "size_t":
1252                 self.format_str = "0x%s"
1253                 self.format_conv = "wine_dbgstr_longlong({0})"
1254             elif self.type in ["uint32_t", "VkBool32"]:
1255                 self.format_str = "%u"
1256             elif self.type in ["uint64_t", "VkDeviceSize"]:
1257                 self.format_str = "0x%s"
1258                 self.format_conv = "wine_dbgstr_longlong({0})"
1259             elif self.type == "HANDLE":
1260                 self.format_str = "%p"
1261             elif self.type in ["VisualID", "xcb_visualid_t", "RROutput"]:
1262                 # Don't care about Linux specific types.
1263                 self.format_str = ""
1264             else:
1265                 LOGGER.warn("Unhandled type: {0}".format(self.type_info))
1267     def copy(self, direction):
1268         if direction == Direction.INPUT:
1269             if self.is_dynamic_array():
1270                 return "    {0}_host = convert_{1}_array_win_to_host({0}, {2});\n".format(self.name, self.type, self.dyn_array_len)
1271             else:
1272                 return "    convert_{0}_win_to_host({1}, &{1}_host);\n".format(self.type, self.name)
1273         else:
1274             if self.is_dynamic_array():
1275                 LOGGER.error("Unimplemented output conversion for: {0}".format(self.name))
1276             else:
1277                 return "    convert_{0}_host_to_win(&{1}_host, {1});\n".format(self.type, self.name)
1279     def definition(self, postfix=None):
1280         """ Return prototype for the parameter. E.g. 'const char *foo' """
1282         proto = ""
1283         if self.const:
1284             proto += self.const + " "
1286         proto += self.type
1288         if self.is_pointer():
1289             proto += " {0}{1}".format(self.pointer, self.name)
1290         else:
1291             proto += " " + self.name
1293         # Allows appending something to the variable name useful for
1294         # win32 to host conversion.
1295         if postfix is not None:
1296             proto += postfix
1298         if self.is_static_array():
1299             proto += "[{0}]".format(self.array_len)
1301         return proto
1303     def direction(self):
1304         """ Returns parameter direction: input, output, input_output.
1306         Parameter direction in Vulkan is not straight-forward, which this function determines.
1307         """
1309         return self._direction
1311     def format_string(self):
1312         return self.format_str
1314     def dispatch_table(self):
1315         """ Return functions dispatch table pointer for dispatchable objects. """
1317         if not self.is_dispatchable():
1318             return None
1320         return "{0}->{1}".format(self.name, self.handle.dispatch_table())
1322     def format_string(self):
1323         return self.format_str
1325     def free(self):
1326         if self.is_dynamic_array():
1327             if self.struct.returnedonly:
1328                 # For returnedonly, counts is stored in a pointer.
1329                 return "    free_{0}_array({1}_host, *{2});\n".format(self.type, self.name, self.dyn_array_len)
1330             else:
1331                 return "    free_{0}_array({1}_host, {2});\n".format(self.type, self.name, self.dyn_array_len)
1332         else:
1333             # We are operating on a single structure. Some structs (very rare) contain dynamic members,
1334             # which would need freeing.
1335             if self.struct.needs_free():
1336                 return "    free_{0}(&{1}_host);\n".format(self.type, self.name)
1337         return ""
1339     def get_conversions(self):
1340         """ Get a list of conversions required for this parameter if any.
1341         Parameters which are structures may require conversion between win32
1342         and the host platform. This function returns a list of conversions
1343         required.
1344         """
1346         if not self.is_struct():
1347             return None
1349         if not self.needs_conversion():
1350             return None
1352         conversions = []
1354         # Collect any member conversions first, so we can guarantee
1355         # those functions will be defined prior to usage by the
1356         # 'parent' param requiring conversion.
1357         for m in self.struct:
1358             if not m.is_struct():
1359                 continue
1361             if not m.needs_conversion():
1362                 continue
1364             conversions.extend(m.get_conversions())
1366         # Conversion requirements for the 'parent' parameter.
1367         if self.input_conv is not None:
1368             conversions.append(self.input_conv)
1369         if self.output_conv is not None:
1370             conversions.append(self.output_conv)
1371         if self.free_func is not None:
1372             conversions.append(self.free_func)
1374         return conversions
1376     def is_const(self):
1377         return self.const is not None
1379     def is_dynamic_array(self):
1380         return self.dyn_array_len is not None
1382     def is_dispatchable(self):
1383         if not self.is_handle():
1384             return False
1386         return self.handle.is_dispatchable()
1388     def is_handle(self):
1389         return self.handle is not None
1391     def is_pointer(self):
1392         return self.pointer is not None
1394     def is_static_array(self):
1395         return self.array_len is not None
1397     def is_struct(self):
1398         return self.struct is not None
1400     def needs_conversion(self):
1401         """ Returns if parameter needs conversion between win32 and host. """
1403         if not self.is_struct():
1404             return False
1406         # VkSparseImageMemoryRequirements(2) is used by vkGetImageSparseMemoryRequirements(2).
1407         # This function is tricky to wrap, because how to wrap depends on whether
1408         # pSparseMemoryRequirements is NULL or not. Luckily for VkSparseImageMemoryRequirements(2)
1409         # the alignment works out in such a way that no conversion is needed between win32 and Linux.
1410         if self.type in ["VkSparseImageMemoryRequirements", "VkSparseImageMemoryRequirements2"]:
1411             return False
1413         # If a structure needs alignment changes, it means we need to
1414         # perform parameter conversion between win32 and host.
1415         if self.struct.needs_conversion():
1416             return True
1418         return False
1420     def needs_free(self):
1421         return self.free_func is not None
1423     def needs_input_conversion(self):
1424         return self.input_conv is not None
1426     def needs_output_conversion(self):
1427         return self.output_conv is not None
1429     def spec(self):
1430         """ Generate spec file entry for this parameter. """
1432         if self.type_info["category"] in ["bitmask", "enum"]:
1433             return "long"
1434         if self.is_pointer() and self.type == "char":
1435             return "str"
1436         if self.is_dispatchable() or self.is_pointer() or self.is_static_array():
1437             return "ptr"
1438         if self.is_handle() and not self.is_dispatchable():
1439             return "int64"
1440         if self.type == "float":
1441             return "float"
1442         if self.type in ["int", "int32_t", "size_t", "uint32_t", "VkBool32"]:
1443             return "long"
1444         if self.type in ["uint64_t", "VkDeviceSize"]:
1445             return "int64"
1447         LOGGER.error("Unhandled spec conversion for type: {0}".format(self.type))
1449     def variable(self, conv=False):
1450         """ Returns 'glue' code during generation of a function call on how to access the variable.
1451         This function handles various scenarios such as 'unwrapping' if dispatchable objects and
1452         renaming of parameters in case of win32 -> host conversion.
1454         Args:
1455             conv (bool, optional): Enable conversion if the param needs it. This appends '_host' to the name.
1456         """
1458         # Hack until we enable allocation callbacks from ICD to application. These are a joy
1459         # to enable one day, because of calling convention conversion.
1460         if "VkAllocationCallbacks" in self.type:
1461             LOGGER.debug("TODO: setting NULL VkAllocationCallbacks for {0}".format(self.name))
1462             return "NULL"
1464         # Dispatchable objects wrap the native handle. For thunk generation we
1465         # need to pass the native handle to the native Vulkan calls.
1466         if self.is_dispatchable():
1467             return "{0}->{1}".format(self.name, self.handle.native_handle())
1468         elif conv and self.needs_conversion():
1469             if self.is_dynamic_array():
1470                 return "{0}_host".format(self.name)
1471             else:
1472                 return "&{0}_host".format(self.name)
1473         else:
1474             return self.name
1477 class VkStruct(Sequence):
1478     """ Class which represents the type union and struct. """
1480     def __init__(self, name, members, returnedonly, alias=False, union=False):
1481         self.name = name
1482         self.members = members
1483         self.returnedonly = returnedonly
1484         self.required = False
1485         self.alias = alias
1486         self.union = union
1487         self.type_info = None # To be set later.
1489     def __getitem__(self, i):
1490         return self.members[i]
1492     def __len__(self):
1493         return len(self.members)
1495     @staticmethod
1496     def from_alias(struct, alias):
1497         name = struct.attrib.get("name")
1498         return VkStruct(name, alias.members, alias.returnedonly, alias=True)
1500     @staticmethod
1501     def from_xml(struct):
1502         # Unions and structs are the same parsing wise, but we need to
1503         # know which one we are dealing with later on for code generation.
1504         union = True if struct.attrib["category"] == "union" else False
1506         name = struct.attrib.get("name", None)
1508         # 'Output' structures for which data is filled in by the API are
1509         # marked as 'returnedonly'.
1510         returnedonly = True if struct.attrib.get("returnedonly") else False
1512         members = []
1513         for member in struct.findall("member"):
1514             vk_member = VkMember.from_xml(member)
1515             members.append(vk_member)
1517         return VkStruct(name, members, returnedonly, union=union)
1519     @staticmethod
1520     def decouple_structs(structs):
1521         """ Helper function which decouples a list of structs.
1522         Structures often depend on other structures. To make the C compiler
1523         happy we need to define 'substructures' first. This function analyzes
1524         the list of structures and reorders them in such a way that they are
1525         decoupled.
1526         """
1528         tmp_structs = list(structs) # Don't modify the original structures.
1529         decoupled_structs = []
1531         while (len(tmp_structs) > 0):
1532             for struct in tmp_structs:
1533                 dependends = False
1535                 if not struct.required:
1536                     tmp_structs.remove(struct)
1537                     continue
1539                 for m in struct:
1540                     if not (m.is_struct() or m.is_union()):
1541                         continue
1543                     # VkBaseInstructure and VkBaseOutStructure reference themselves.
1544                     if m.type == struct.name:
1545                         break
1547                     found = False
1548                     # Check if a struct we depend on has already been defined.
1549                     for s in decoupled_structs:
1550                         if s.name == m.type:
1551                             found = True
1552                             break
1554                     if not found:
1555                         # Check if the struct we depend on is even in the list of structs.
1556                         # If found now, it means we haven't met all dependencies before we
1557                         # can operate on the current struct.
1558                         # When generating 'host' structs we may not be able to find a struct
1559                         # as the list would only contain the structs requiring conversion.
1560                         for s in tmp_structs:
1561                             if s.name == m.type:
1562                                 dependends = True
1563                                 break
1565                 if dependends == False:
1566                     decoupled_structs.append(struct)
1567                     tmp_structs.remove(struct)
1569         return decoupled_structs
1571     def definition(self, align=False, conv=False, postfix=None):
1572         """ Convert structure to textual definition.
1574         Args:
1575             align (bool, optional): enable alignment to 64-bit for win32 struct compatibility.
1576             conv (bool, optional): enable struct conversion if the struct needs it.
1577             postfix (str, optional): text to append to end of struct name, useful for struct renaming.
1578         """
1580         if self.union:
1581             text = "typedef union {0}".format(self.name)
1582         else:
1583             text = "typedef struct {0}".format(self.name)
1585         if postfix is not None:
1586             text += postfix
1588         text += "\n{\n"
1590         for m in self:
1591             if align and m.needs_alignment():
1592                 text += "    {0};\n".format(m.definition(align=align))
1593             elif conv and m.needs_conversion():
1594                 text += "    {0};\n".format(m.definition(conv=conv))
1595             else:
1596                 text += "    {0};\n".format(m.definition())
1598         if postfix is not None:
1599             text += "}} {0}{1};\n\n".format(self.name, postfix)
1600         else:
1601             text += "}} {0};\n\n".format(self.name)
1602         return text
1604     def is_alias(self):
1605         return self.alias
1607     def needs_alignment(self):
1608         """ Check if structure needs alignment for 64-bit data.
1609         Various structures need alignment on 64-bit variables due
1610         to compiler differences on 32-bit between Win32 and Linux.
1611         """
1613         for m in self.members:
1614             if m.needs_alignment():
1615                 return True
1616         return False
1618     def needs_conversion(self):
1619         """ Returns if struct members needs conversion between win32 and host.
1620         Structures need conversion if they contain members requiring alignment
1621         or if they include other structures which need alignment.
1622         """
1624         if self.needs_alignment():
1625             return True
1627         for m in self.members:
1628             if m.needs_conversion():
1629                 return True
1630         return False
1632     def needs_free(self):
1633         """ Check if any struct member needs some memory freeing."""
1635         for m in self.members:
1636             if m.needs_free():
1637                 return True
1639             continue
1641         return False
1643     def set_type_info(self, types):
1644         """ Helper function to set type information from the type registry.
1645         This is needed, because not all type data is available at time of
1646         parsing.
1647         """
1648         for m in self.members:
1649             type_info = types[m.type]
1650             m.set_type_info(type_info)
1653 class ConversionFunction(object):
1654     def __init__(self, array, dyn_array, direction, struct):
1655         self.array = array
1656         self.direction = direction
1657         self.dyn_array = dyn_array
1658         self.struct = struct
1659         self.type = struct.name
1661         self._set_name()
1663     def __eq__(self, other):
1664         if self.name != other.name:
1665             return False
1667         return True
1669     def _generate_array_conversion_func(self):
1670         """ Helper function for generating a conversion function for array structs. """
1672         if self.direction == Direction.OUTPUT:
1673             params = ["const {0}_host *in".format(self.type), "uint32_t count"]
1674             return_type = self.type
1675         else:
1676             params = ["const {0} *in".format(self.type), "uint32_t count"]
1677             return_type = "{0}_host".format(self.type)
1679         # Generate function prototype.
1680         body = "static inline {0} *{1}(".format(return_type, self.name)
1681         body += ", ".join(p for p in params)
1682         body += ")\n{\n"
1684         body += "    {0} *out;\n".format(return_type)
1685         body += "    unsigned int i;\n\n"
1686         body += "    if (!in) return NULL;\n\n"
1688         body += "    out = heap_alloc(count * sizeof(*out));\n"
1690         body += "    for (i = 0; i < count; i++)\n"
1691         body += "    {\n"
1693         for m in self.struct:
1694             # TODO: support copying of pNext extension structures!
1695             # Luckily though no extension struct at this point needs conversion.
1696             body += "        " + m.copy("in[i].", "out[i].", self.direction)
1698         body += "    }\n\n"
1699         body += "    return out;\n"
1700         body += "}\n\n"
1701         return body
1703     def _generate_conversion_func(self):
1704         """ Helper function for generating a conversion function for non-array structs. """
1706         if self.direction == Direction.OUTPUT:
1707             params = ["const {0}_host *in".format(self.type), "{0} *out".format(self.type)]
1708         else:
1709             params = ["const {0} *in".format(self.type), "{0}_host *out".format(self.type)]
1711         body = "static inline void {0}(".format(self.name)
1713         # Generate parameter list
1714         body += ", ".join(p for p in params)
1715         body += ")\n{\n"
1717         body += "    if (!in) return;\n\n"
1719         if self.direction == Direction.INPUT and "pNext" in self.struct and self.struct.returnedonly:
1720             # We are dealing with an input_output parameter. For these we only need to copy
1721             # pNext and sType as the other fields are filled in by the host. We do potentially
1722             # have to iterate over pNext and perform conversions based on switch(sType)!
1723             # Luckily though no extension structs at this point need conversion.
1724             # TODO: support copying of pNext extension structures!
1725             body += "    out->pNext = in->pNext;\n"
1726             body += "    out->sType = in->sType;\n"
1727         else:
1728             for m in self.struct:
1729                 # TODO: support copying of pNext extension structures!
1730                 body += "    " + m.copy("in->", "out->", self.direction)
1732         body += "}\n\n"
1733         return body
1735     def _generate_static_array_conversion_func(self):
1736         """ Helper function for generating a conversion function for array structs. """
1738         if self.direction == Direction.OUTPUT:
1739             params = ["const {0}_host *in".format(self.type), "{0} *out".format(self.type), "uint32_t count"]
1740             return_type = self.type
1741         else:
1742             params = ["const {0} *in".format(self.type), "{0} *out_host".format(self.type), "uint32_t count"]
1743             return_type = "{0}_host".format(self.type)
1745         # Generate function prototype.
1746         body = "static inline void {0}(".format(self.name)
1747         body += ", ".join(p for p in params)
1748         body += ")\n{\n"
1749         body += "    unsigned int i;\n\n"
1750         body += "    if (!in) return;\n\n"
1751         body += "    for (i = 0; i < count; i++)\n"
1752         body += "    {\n"
1754         for m in self.struct:
1755             # TODO: support copying of pNext extension structures!
1756             body += "        " + m.copy("in[i].", "out[i].", self.direction)
1758         body += "    }\n"
1759         body += "}\n\n"
1760         return body
1762     def _set_name(self):
1763         if self.direction == Direction.INPUT:
1764             if self.array:
1765                 name = "convert_{0}_static_array_win_to_host".format(self.type)
1766             elif self.dyn_array:
1767                 name = "convert_{0}_array_win_to_host".format(self.type)
1768             else:
1769                 name = "convert_{0}_win_to_host".format(self.type)
1770         else: # Direction.OUTPUT
1771             if self.array:
1772                 name = "convert_{0}_static_array_host_to_win".format(self.type)
1773             elif self.dyn_array:
1774                 name = "convert_{0}_array_host_to_win".format(self.type)
1775             else:
1776                 name = "convert_{0}_host_to_win".format(self.type)
1778         self.name = name
1780     def definition(self):
1781         if self.array:
1782             return self._generate_static_array_conversion_func()
1783         elif self.dyn_array:
1784             return self._generate_array_conversion_func()
1785         else:
1786             return self._generate_conversion_func()
1789 class FreeFunction(object):
1790     def __init__(self, dyn_array, struct):
1791         self.dyn_array = dyn_array
1792         self.struct = struct
1793         self.type = struct.name
1795         if dyn_array:
1796             self.name = "free_{0}_array".format(self.type)
1797         else:
1798             self.name = "free_{0}".format(self.type)
1800     def __eq__(self, other):
1801         if self.name == other.name:
1802             return True
1804         return False
1806     def _generate_array_free_func(self):
1807         """ Helper function for cleaning up temporary buffers required for array conversions. """
1809         # Generate function prototype.
1810         body = "static inline void {0}({1}_host *in, uint32_t count)\n{{\n".format(self.name, self.type)
1812         # E.g. VkGraphicsPipelineCreateInfo_host needs freeing for pStages.
1813         if self.struct.needs_free():
1814             body += "    unsigned int i;\n\n"
1815             body += "    if (!in) return;\n\n"
1816             body += "    for (i = 0; i < count; i++)\n"
1817             body += "    {\n"
1819             for m in self.struct:
1820                 if m.needs_conversion() and m.is_dynamic_array():
1821                     if m.is_const():
1822                         # Add a cast to ignore const on conversion structs we allocated ourselves.
1823                         body += "        free_{0}_array(({0}_host *)in[i].{1}, in[i].{2});\n".format(m.type, m.name, m.dyn_array_len)
1824                     else:
1825                         body += "        free_{0}_array(in[i].{1}, in[i].{2});\n".format(m.type, m.name, m.dyn_array_len)
1826                 elif m.needs_conversion():
1827                     LOGGER.error("Unhandled conversion for {0}".format(m.name))
1828             body += "    }\n"
1829         else:
1830             body += "    if (!in) return;\n\n"
1832         body += "    heap_free(in);\n"
1834         body += "}\n\n"
1835         return body
1837     def _generate_free_func(self):
1838         # E.g. VkCommandBufferBeginInfo.pInheritanceInfo needs freeing.
1839         if not self.struct.needs_free():
1840             return ""
1842         # Generate function prototype.
1843         body = "static inline void {0}({1}_host *in)\n{{\n".format(self.name, self.type)
1845         for m in self.struct:
1846             if m.needs_conversion() and m.is_dynamic_array():
1847                 count = m.dyn_array_len if isinstance(m.dyn_array_len, int) else "in->{0}".format(m.dyn_array_len)
1848                 if m.is_const():
1849                     # Add a cast to ignore const on conversion structs we allocated ourselves.
1850                     body += "    free_{0}_array(({0}_host *)in->{1}, {2});\n".format(m.type, m.name, count)
1851                 else:
1852                     body += "    free_{0}_array(in->{1}, {2});\n".format(m.type, m.name, count)
1854         body += "}\n\n"
1855         return body
1857     def definition(self):
1858         if self.dyn_array:
1859             return self._generate_array_free_func()
1860         else:
1861             # Some structures need freeing too if they contain dynamic arrays.
1862             # E.g. VkCommandBufferBeginInfo
1863             return self._generate_free_func()
1866 class VkGenerator(object):
1867     def __init__(self, registry):
1868         self.registry = registry
1870         # Build a list conversion functions for struct conversion.
1871         self.conversions = []
1872         self.host_structs = []
1873         for func in self.registry.funcs.values():
1874             if not func.is_required():
1875                 continue
1877             if not func.needs_conversion():
1878                 continue
1880             conversions = func.get_conversions()
1881             for conv in conversions:
1882                 # Pull in any conversions for vulkan_thunks.c.
1883                 if func.needs_thunk():
1884                     # Append if we don't already have this conversion.
1885                     if not any(c == conv for c in self.conversions):
1886                         self.conversions.append(conv)
1888                 # Structs can be used in different ways by different conversions
1889                 # e.g. array vs non-array. Just make sure we pull in each struct once.
1890                 if not any(s.name == conv.struct.name for s in self.host_structs):
1891                     self.host_structs.append(conv.struct)
1893     def _generate_copyright(self, f, spec_file=False):
1894         f.write("# " if spec_file else "/* ")
1895         f.write("Automatically generated from Vulkan vk.xml; DO NOT EDIT!\n")
1896         lines = ["", "This file is generated from Vulkan vk.xml file covered",
1897             "by the following copyright and permission notice:"]
1898         lines.extend([l.rstrip(" ") for l in self.registry.copyright.splitlines()])
1899         for line in lines:
1900             f.write("{0}{1}".format("# " if spec_file else " * ", line).rstrip(" ") + "\n")
1901         f.write("\n" if spec_file else " */\n\n")
1903     def generate_thunks_c(self, f, prefix):
1904         self._generate_copyright(f)
1905         f.write("#include \"config.h\"\n")
1906         f.write("#include \"wine/port.h\"\n\n")
1908         f.write("#include \"vulkan_private.h\"\n\n")
1910         f.write("WINE_DEFAULT_DEBUG_CHANNEL(vulkan);\n\n")
1912         # Generate any conversion helper functions.
1913         f.write("#if defined(USE_STRUCT_CONVERSION)\n")
1914         for conv in self.conversions:
1915             f.write(conv.definition())
1916         f.write("#endif /* USE_STRUCT_CONVERSION */\n\n")
1918         # Create thunks for instance and device functions.
1919         # Global functions don't go through the thunks.
1920         for vk_func in self.registry.funcs.values():
1921             if not vk_func.is_required():
1922                 continue
1924             if vk_func.is_global_func():
1925                 continue
1927             if not vk_func.needs_thunk():
1928                 continue
1930             # Exports symbols for Core functions.
1931             if not vk_func.is_core_func():
1932                 f.write("static ")
1933             f.write(vk_func.thunk(prefix=prefix, call_conv="WINAPI"))
1935         f.write("static const struct vulkan_func vk_device_dispatch_table[] =\n{\n")
1936         for vk_func in self.registry.device_funcs:
1937             if not vk_func.is_required():
1938                 continue
1940             f.write("    {{\"{0}\", &{1}{0}}},\n".format(vk_func.name, prefix))
1941         f.write("};\n\n")
1943         f.write("static const struct vulkan_func vk_instance_dispatch_table[] =\n{\n")
1944         for vk_func in self.registry.instance_funcs:
1945             if not vk_func.is_required():
1946                 continue
1948             f.write("    {{\"{0}\", &{1}{0}}},\n".format(vk_func.name, prefix))
1949         f.write("};\n\n")
1951         f.write("void *wine_vk_get_device_proc_addr(const char *name)\n")
1952         f.write("{\n")
1953         f.write("    unsigned int i;\n")
1954         f.write("    for (i = 0; i < ARRAY_SIZE(vk_device_dispatch_table); i++)\n")
1955         f.write("    {\n")
1956         f.write("        if (strcmp(vk_device_dispatch_table[i].name, name) == 0)\n")
1957         f.write("        {\n")
1958         f.write("            TRACE(\"Found name=%s in device table\\n\", debugstr_a(name));\n")
1959         f.write("            return vk_device_dispatch_table[i].func;\n")
1960         f.write("        }\n")
1961         f.write("    }\n")
1962         f.write("    return NULL;\n")
1963         f.write("}\n\n")
1965         f.write("void *wine_vk_get_instance_proc_addr(const char *name)\n")
1966         f.write("{\n")
1967         f.write("    unsigned int i;\n")
1968         f.write("    for (i = 0; i < ARRAY_SIZE(vk_instance_dispatch_table); i++)\n")
1969         f.write("    {\n")
1970         f.write("        if (strcmp(vk_instance_dispatch_table[i].name, name) == 0)\n")
1971         f.write("        {\n")
1972         f.write("            TRACE(\"Found name=%s in instance table\\n\", debugstr_a(name));\n")
1973         f.write("            return vk_instance_dispatch_table[i].func;\n")
1974         f.write("        }\n")
1975         f.write("    }\n")
1976         f.write("    return NULL;\n")
1977         f.write("}\n\n")
1979         # Create array of device extensions.
1980         f.write("static const char * const vk_device_extensions[] =\n{\n")
1981         for ext in self.registry.extensions:
1982             if ext["type"] != "device":
1983                 continue
1985             f.write("    \"{0}\",\n".format(ext["name"]))
1986         f.write("};\n\n")
1988         # Create array of instance extensions.
1989         f.write("static const char * const vk_instance_extensions[] =\n{\n")
1990         for ext in self.registry.extensions:
1991             if ext["type"] != "instance":
1992                 continue
1994             f.write("    \"{0}\",\n".format(ext["name"]))
1995         f.write("};\n\n")
1997         f.write("BOOL wine_vk_device_extension_supported(const char *name)\n")
1998         f.write("{\n")
1999         f.write("    unsigned int i;\n")
2000         f.write("    for (i = 0; i < ARRAY_SIZE(vk_device_extensions); i++)\n")
2001         f.write("    {\n")
2002         f.write("        if (strcmp(vk_device_extensions[i], name) == 0)\n")
2003         f.write("            return TRUE;\n")
2004         f.write("    }\n")
2005         f.write("    return FALSE;\n")
2006         f.write("}\n\n")
2008         f.write("BOOL wine_vk_instance_extension_supported(const char *name)\n")
2009         f.write("{\n")
2010         f.write("    unsigned int i;\n")
2011         f.write("    for (i = 0; i < ARRAY_SIZE(vk_instance_extensions); i++)\n")
2012         f.write("    {\n")
2013         f.write("        if (strcmp(vk_instance_extensions[i], name) == 0)\n")
2014         f.write("            return TRUE;\n")
2015         f.write("    }\n")
2016         f.write("    return FALSE;\n")
2017         f.write("}\n")
2019     def generate_thunks_h(self, f, prefix):
2020         self._generate_copyright(f)
2022         f.write("#ifndef __WINE_VULKAN_THUNKS_H\n")
2023         f.write("#define __WINE_VULKAN_THUNKS_H\n\n")
2025         # Generate prototypes for device and instance functions requiring a custom implementation.
2026         f.write("/* Functions for which we have custom implementations outside of the thunks. */\n")
2027         for vk_func in self.registry.funcs.values():
2028             if not vk_func.is_required() or vk_func.is_global_func() or vk_func.needs_thunk():
2029                 continue
2031             if vk_func.is_core_func():
2032                 f.write("{0};\n".format(vk_func.prototype("WINAPI", prefix="wine_")))
2033             else:
2034                 f.write("{0};\n".format(vk_func.prototype("WINAPI", prefix="wine_", postfix="DECLSPEC_HIDDEN")))
2035         f.write("\n")
2037         for struct in self.host_structs:
2038             f.write(struct.definition(align=False, conv=True, postfix="_host"))
2039         f.write("\n")
2041         f.write("/* For use by vkDevice and children */\n")
2042         f.write("struct vulkan_device_funcs\n{\n")
2043         for vk_func in self.registry.device_funcs:
2044             if not vk_func.is_required():
2045                 continue
2047             if not vk_func.needs_dispatch():
2048                 LOGGER.debug("skipping {0} in vulkan_device_funcs".format(vk_func.name))
2049                 continue
2051             if vk_func.needs_conversion():
2052                 f.write("#if defined(USE_STRUCT_CONVERSION)\n")
2053                 f.write("    {0};\n".format(vk_func.pfn(conv=True)))
2054                 f.write("#else\n")
2055                 f.write("    {0};\n".format(vk_func.pfn(conv=False)))
2056                 f.write("#endif\n")
2057             else:
2058                 f.write("    {0};\n".format(vk_func.pfn(conv=False)))
2059         f.write("};\n\n")
2061         f.write("/* For use by vkInstance and children */\n")
2062         f.write("struct vulkan_instance_funcs\n{\n")
2063         for vk_func in self.registry.instance_funcs:
2064             if not vk_func.is_required():
2065                 continue
2067             if not vk_func.needs_dispatch():
2068                 LOGGER.debug("skipping {0} in vulkan_instance_funcs".format(vk_func.name))
2069                 continue
2071             if vk_func.needs_conversion():
2072                 f.write("#if defined(USE_STRUCT_CONVERSION)\n")
2073                 f.write("    {0};\n".format(vk_func.pfn(conv=True)))
2074                 f.write("#else\n")
2075                 f.write("    {0};\n".format(vk_func.pfn(conv=False)))
2076                 f.write("#endif\n")
2077             else:
2078                 f.write("    {0};\n".format(vk_func.pfn(conv=False)))
2079         f.write("};\n\n")
2081         f.write("#define ALL_VK_DEVICE_FUNCS() \\\n")
2082         first = True
2083         for vk_func in self.registry.device_funcs:
2084             if not vk_func.is_required():
2085                 continue
2087             if not vk_func.needs_dispatch():
2088                 LOGGER.debug("skipping {0} in ALL_VK_DEVICE_FUNCS".format(vk_func.name))
2089                 continue
2091             if first:
2092                 f.write("    USE_VK_FUNC({0})".format(vk_func.name))
2093                 first = False
2094             else:
2095                 f.write(" \\\n    USE_VK_FUNC({0})".format(vk_func.name))
2096         f.write("\n\n")
2098         f.write("#define ALL_VK_INSTANCE_FUNCS() \\\n")
2099         first = True
2100         for vk_func in self.registry.instance_funcs:
2101             if not vk_func.is_required():
2102                 continue
2104             if not vk_func.needs_dispatch():
2105                 LOGGER.debug("skipping {0} in ALL_VK_INSTANCE_FUNCS".format(vk_func.name))
2106                 continue
2108             if first:
2109                 f.write("    USE_VK_FUNC({0})".format(vk_func.name))
2110                 first = False
2111             else:
2112                 f.write(" \\\n    USE_VK_FUNC({0})".format(vk_func.name))
2113         f.write("\n\n")
2115         f.write("#endif /* __WINE_VULKAN_THUNKS_H */\n")
2117     def generate_vulkan_h(self, f):
2118         self._generate_copyright(f)
2119         f.write("#ifndef __WINE_VULKAN_H\n")
2120         f.write("#define __WINE_VULKAN_H\n\n")
2122         f.write("#include <windef.h>\n")
2123         f.write("#include <stdint.h>\n\n")
2125         f.write("/* Define WINE_VK_HOST to get 'host' headers. */\n")
2126         f.write("#ifdef WINE_VK_HOST\n")
2127         f.write("#define VKAPI_CALL\n")
2128         f.write('#define WINE_VK_ALIGN(x)\n')
2129         f.write("#endif\n\n")
2131         f.write("#ifndef VKAPI_CALL\n")
2132         f.write("#define VKAPI_CALL __stdcall\n")
2133         f.write("#endif\n\n")
2135         f.write("#ifndef VKAPI_PTR\n")
2136         f.write("#define VKAPI_PTR VKAPI_CALL\n")
2137         f.write("#endif\n\n")
2139         f.write("#ifndef WINE_VK_ALIGN\n")
2140         f.write("#define WINE_VK_ALIGN DECLSPEC_ALIGN\n")
2141         f.write("#endif\n\n")
2143         # The overall strategy is to define independent constants and datatypes,
2144         # prior to complex structures and function calls to avoid forward declarations.
2145         for const in self.registry.consts:
2146             # For now just generate things we may not need. The amount of parsing needed
2147             # to get some of the info is tricky as you need to figure out which structure
2148             # references a certain constant.
2149             f.write(const.definition())
2150         f.write("\n")
2152         for define in self.registry.defines:
2153             f.write(define.definition())
2155         for handle in self.registry.handles:
2156             # For backwards compatiblity also create definitions for aliases.
2157             # These types normally don't get pulled in as we use the new types
2158             # even in legacy functions if they are aliases.
2159             if handle.is_required() or handle.is_alias():
2160                  f.write(handle.definition())
2161         f.write("\n")
2163         for base_type in self.registry.base_types:
2164             f.write(base_type.definition())
2165         f.write("\n")
2167         for bitmask in self.registry.bitmasks:
2168             f.write(bitmask.definition())
2169         f.write("\n")
2171         # Define enums, this includes values for some of the bitmask types as well.
2172         for enum in self.registry.enums.values():
2173             if enum.required:
2174                 f.write(enum.definition())
2176         for fp in self.registry.funcpointers:
2177             if fp.required:
2178                 f.write(fp.definition())
2179         f.write("\n")
2181         # This generates both structures and unions. Since structures
2182         # may depend on other structures/unions, we need a list of
2183         # decoupled structs.
2184         # Note: unions are stored in structs for dependency reasons,
2185         # see comment in parsing section.
2186         structs = VkStruct.decouple_structs(self.registry.structs)
2187         for struct in structs:
2188             LOGGER.debug("Generating struct: {0}".format(struct.name))
2189             f.write(struct.definition(align=True))
2191         for func in self.registry.funcs.values():
2192             if not func.is_required():
2193                 LOGGER.debug("Skipping PFN definition for: {0}".format(func.name))
2194                 continue
2196             f.write("typedef {0};\n".format(func.pfn(prefix="PFN", call_conv="VKAPI_PTR")))
2197         f.write("\n")
2199         f.write("#ifndef VK_NO_PROTOTYPES\n")
2200         for func in self.registry.funcs.values():
2201             if not func.is_required():
2202                 LOGGER.debug("Skipping API definition for: {0}".format(func.name))
2203                 continue
2205             LOGGER.debug("Generating API definition for: {0}".format(func.name))
2206             f.write("{0};\n".format(func.prototype(call_conv="VKAPI_CALL")))
2207         f.write("#endif /* VK_NO_PROTOTYPES */\n\n")
2209         f.write("#endif /* __WINE_VULKAN_H */\n")
2211     def generate_vulkan_driver_h(self, f):
2212         self._generate_copyright(f)
2213         f.write("#ifndef __WINE_VULKAN_DRIVER_H\n")
2214         f.write("#define __WINE_VULKAN_DRIVER_H\n\n")
2216         f.write("/* Wine internal vulkan driver version, needs to be bumped upon vulkan_funcs changes. */\n")
2217         f.write("#define WINE_VULKAN_DRIVER_VERSION {0}\n\n".format(DRIVER_VERSION))
2219         f.write("struct vulkan_funcs\n{\n")
2220         f.write("    /* Vulkan global functions. These are the only calls at this point a graphics driver\n")
2221         f.write("     * needs to provide. Other function calls will be provided indirectly by dispatch\n")
2222         f.write("     * tables part of dispatchable Vulkan objects such as VkInstance or vkDevice.\n")
2223         f.write("     */\n")
2225         for vk_func in self.registry.funcs.values():
2226             if not vk_func.is_required() or not vk_func.is_driver_func():
2227                 continue
2229             pfn = vk_func.pfn()
2230             # Avoid PFN_vkVoidFunction in driver interface as Vulkan likes to put calling convention
2231             # stuff in there. For simplicity substitute with "void *".
2232             pfn = pfn.replace("PFN_vkVoidFunction", "void *")
2233             f.write("    {0};\n".format(pfn))
2234         f.write("};\n\n")
2236         f.write("extern const struct vulkan_funcs * CDECL __wine_get_vulkan_driver(HDC hdc, UINT version);\n\n")
2237         f.write("#endif /* __WINE_VULKAN_DRIVER_H */\n")
2239     def generate_vulkan_spec(self, f):
2240         self._generate_copyright(f, spec_file=True)
2241         f.write("@ stdcall vk_icdGetInstanceProcAddr(ptr str) wine_vk_icdGetInstanceProcAddr\n")
2242         f.write("@ stdcall vk_icdNegotiateLoaderICDInterfaceVersion(ptr) wine_vk_icdNegotiateLoaderICDInterfaceVersion\n")
2244         # Export symbols for all Vulkan Core functions.
2245         for func in self.registry.funcs.values():
2246             if not func.is_core_func():
2247                 continue
2249             # Not an ICD level function.
2250             if func.name == "vkEnumerateInstanceLayerProperties":
2251                 continue
2253             # We support all Core functions except for VK_KHR_display* APIs.
2254             # Create stubs for unsupported Core functions.
2255             if func.is_required():
2256                 f.write(func.spec(prefix="wine_"))
2257             else:
2258                 f.write("@ stub {0}\n".format(func.name))
2260     def generate_vulkan_loader_spec(self, f):
2261         self._generate_copyright(f, spec_file=True)
2263         # Export symbols for all Vulkan Core functions.
2264         for func in self.registry.funcs.values():
2265             if not func.is_core_func():
2266                 continue
2268             # We support all Core functions except for VK_KHR_display* APIs.
2269             # Create stubs for unsupported Core functions.
2270             if func.is_required():
2271                 # Global functions need a custom implementation, except for
2272                 # vkCreateInstance, which we can just forward.
2273                 if func.is_global_func() and func.name != "vkCreateInstance":
2274                     f.write(func.spec())
2275                 else:
2276                     f.write(func.spec(symbol="winevulkan.wine_" + func.name))
2277             else:
2278                 f.write("@ stub {0}\n".format(func.name))
2281 class VkRegistry(object):
2282     def __init__(self, reg_filename):
2283         # Used for storage of type information.
2284         self.base_types = None
2285         self.bitmasks = None
2286         self.consts = None
2287         self.defines = None
2288         self.enums = None
2289         self.funcpointers = None
2290         self.handles = None
2291         self.structs = None
2293         # We aggregate all types in here for cross-referencing.
2294         self.funcs = {}
2295         self.types = {}
2297         # Overall strategy for parsing the registry is to first
2298         # parse all type / function definitions. Then parse
2299         # features and extensions to decide which types / functions
2300         # to actually 'pull in' for code generation. For each type or
2301         # function call we want we set a member 'required' to True.
2302         tree = ET.parse(reg_filename)
2303         root = tree.getroot()
2304         self._parse_enums(root)
2305         self._parse_types(root)
2306         self._parse_commands(root)
2308         # Pull in any required types and functions.
2309         self._parse_features(root)
2310         self._parse_extensions(root)
2312         self.copyright = root.find('./comment').text
2314     def _mark_command_required(self, command):
2315         """ Helper function to mark a certain command and the datatypes it needs as required."""
2316         def mark_bitmask_dependencies(bitmask, types):
2317             if bitmask.requires is not None:
2318                 types[bitmask.requires]["data"].required = True
2320         def mark_funcpointer_dependencies(fp, types):
2321             for m in fp.members:
2322                 type_info = types[m.type]
2324                 # Complex types have a matching definition e.g. VkStruct.
2325                 # Not needed for base types such as uint32_t.
2326                 if "data" in type_info:
2327                     types[m.type]["data"].required = True
2329         def mark_struct_dependencies(struct, types):
2330              for m in struct:
2331                 type_info = types[m.type]
2333                 # Complex types have a matching definition e.g. VkStruct.
2334                 # Not needed for base types such as uint32_t.
2335                 if "data" in type_info:
2336                     types[m.type]["data"].required = True
2338                 if type_info["category"] == "struct":
2339                     # Yay, recurse
2340                     mark_struct_dependencies(type_info["data"], types)
2341                 elif type_info["category"] == "funcpointer":
2342                     mark_funcpointer_dependencies(type_info["data"], types)
2343                 elif type_info["category"] == "bitmask":
2344                     mark_bitmask_dependencies(type_info["data"], types)
2346         func = self.funcs[command]
2347         func.required = True
2349         # Pull in return type
2350         if func.type != "void":
2351             self.types[func.type]["data"].required = True
2353         # Analyze parameter dependencies and pull in any type needed.
2354         for p in func.params:
2355             type_info = self.types[p.type]
2357             # Check if we are dealing with a complex type e.g. VkEnum, VkStruct and others.
2358             if "data" not in type_info:
2359                 continue
2361             # Mark the complex type as required.
2362             type_info["data"].required = True
2363             if type_info["category"] == "struct":
2364                 struct = type_info["data"]
2365                 mark_struct_dependencies(struct, self.types)
2367     def _parse_commands(self, root):
2368         """ Parse command section containing the Vulkan function calls. """
2369         funcs = {}
2370         commands = root.findall("./commands/")
2372         # As of Vulkan 1.1, various extensions got promoted to Core.
2373         # The old commands (e.g. KHR) are available for backwards compatibility
2374         # and are marked in vk.xml as 'alias' to the non-extension type.
2375         # The registry likes to avoid data duplication, so parameters and other
2376         # metadata need to be looked up from the Core command.
2377         # We parse the alias commands in a second pass.
2378         alias_commands = []
2379         for command in commands:
2380             alias_name = command.attrib.get("alias")
2381             if alias_name:
2382                 alias_commands.append(command)
2383                 continue
2385             func = VkFunction.from_xml(command, self.types)
2386             funcs[func.name] = func
2388         for command in alias_commands:
2389             alias_name = command.attrib.get("alias")
2390             alias = funcs[alias_name]
2391             func = VkFunction.from_alias(command, alias)
2392             funcs[func.name] = func
2394         # To make life easy for the code generation, separate all function
2395         # calls out in the 3 types of Vulkan functions: device, global and instance.
2396         device_funcs = []
2397         global_funcs = []
2398         instance_funcs = []
2399         for func in funcs.values():
2400             if func.is_device_func():
2401                 device_funcs.append(func)
2402             elif func.is_global_func():
2403                 global_funcs.append(func)
2404             else:
2405                 instance_funcs.append(func)
2407         # Sort function lists by name and store them.
2408         self.device_funcs = sorted(device_funcs, key=lambda func: func.name)
2409         self.global_funcs = sorted(global_funcs, key=lambda func: func.name)
2410         self.instance_funcs = sorted(instance_funcs, key=lambda func: func.name)
2412         # The funcs dictionary is used as a convenient way to lookup function
2413         # calls when needed e.g. to adjust member variables.
2414         self.funcs = OrderedDict(sorted(funcs.items()))
2416     def _parse_enums(self, root):
2417         """ Parse enums section or better described as constants section. """
2418         enums = {}
2419         self.consts = []
2420         for enum in root.findall("./enums"):
2421             name = enum.attrib.get("name")
2422             _type = enum.attrib.get("type")
2424             if _type in ("enum", "bitmask"):
2425                 enums[name] = VkEnum.from_xml(enum)
2426             else:
2427                 # If no type is set, we are dealing with API constants.
2428                 for value in enum.findall("enum"):
2429                     # If enum is an alias, set the value to the alias name.
2430                     # E.g. VK_LUID_SIZE_KHR is an alias to VK_LUID_SIZE.
2431                     alias = value.attrib.get("alias")
2432                     if alias:
2433                         self.consts.append(VkConstant(value.attrib.get("name"), alias))
2434                     else:
2435                         self.consts.append(VkConstant(value.attrib.get("name"), value.attrib.get("value")))
2437         self.enums = OrderedDict(sorted(enums.items()))
2439     def _parse_extensions(self, root):
2440         """ Parse extensions section and pull in any types and commands for this extensioin. """
2441         extensions = []
2442         exts = root.findall("./extensions/extension")
2443         for ext in exts:
2444             ext_name = ext.attrib["name"]
2446             # Set extension name on any functions calls part of this extension as we
2447             # were not aware of the name during initial parsing.
2448             commands = ext.findall("require/command")
2449             for command in commands:
2450                 cmd_name = command.attrib["name"]
2451                 self.funcs[cmd_name].extensions.append(ext_name)
2453             # Some extensions are not ready or have numbers reserved as a place holder.
2454             if ext.attrib["supported"] == "disabled":
2455                 LOGGER.debug("Skipping disabled extension: {0}".format(ext_name))
2456                 continue
2458             # Disable highly experimental extensions as the APIs are unstable and can
2459             # change between minor Vulkan revisions until API is final and becomes KHR
2460             # or NV.
2461             if "KHX" in ext_name or "NVX" in ext_name:
2462                 LOGGER.debug("Skipping experimental extension: {0}".format(ext_name))
2463                 continue
2465             # Instance extensions often require a custom implementation, so filter.
2466             ext_type = ext.attrib["type"]
2467             if ext_type == "instance" and not ext_name in SUPPORTED_INSTANCE_EXTENSIONS:
2468                 LOGGER.debug("Skipping instance extension: {0}".format(ext_name))
2469                 continue
2471             # We disable some extensions as either we haven't implemented
2472             # support yet or because they are for platforms other than win32.
2473             if ext_name in BLACKLISTED_EXTENSIONS:
2474                 LOGGER.debug("Skipping blacklisted extension: {0}".format(ext_name))
2475                 continue
2476             elif "requires" in ext.attrib:
2477                 # Check if this extension builds on top of another blacklisted
2478                 # extension.
2479                 requires = ext.attrib["requires"].split(",")
2480                 if len(set(requires).intersection(BLACKLISTED_EXTENSIONS)) > 0:
2481                     continue
2483             LOGGER.debug("Loading extension: {0}".format(ext_name))
2485             # Extensions can define one or more require sections each requiring
2486             # different features (e.g. Vulkan 1.1). Parse each require section
2487             # separately, so we can skip sections we don't want.
2488             for require in ext.findall("require"):
2489                 feature = require.attrib.get("feature")
2490                 if feature == "VK_VERSION_1_1":
2491                     continue
2493                 # Extensions can add enum values to Core / extension enums, so add these.
2494                 for enum_elem in require.findall("enum"):
2495                     if "bitpos" in enum_elem.keys():
2496                         # We need to add an extra value to an existing enum type.
2497                         # E.g. VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG to VkFormatFeatureFlagBits.
2498                         type_name = enum_elem.attrib["extends"]
2499                         enum = self.types[type_name]["data"]
2500                         enum.add(VkEnumValue(enum_elem.attrib["name"], 1 << int(enum_elem.attrib["bitpos"]), hex=True))
2501                     elif "offset" in enum_elem.keys():
2502                         # Extensions promoted to Core, have the extension number as part
2503                         # of the enum value. Else retrieve from the extension tag.
2504                         if enum_elem.attrib.get("extnumber") is not None:
2505                             ext_number = int(enum_elem.attrib.get("extnumber"))
2506                         else:
2507                             ext_number = int(ext.attrib["number"])
2508                         offset = int(enum_elem.attrib["offset"])
2509                         value = EXT_BASE + (ext_number - 1) * EXT_BLOCK_SIZE + offset
2511                         # Deal with negative values.
2512                         direction = enum_elem.attrib.get("dir")
2513                         if direction is not None:
2514                             value = -value
2516                         type_name = enum_elem.attrib["extends"]
2517                         enum = self.types[type_name]["data"]
2518                         enum.add(VkEnumValue(enum_elem.attrib["name"], value))
2520                     elif "value" in enum_elem.keys():
2521                         self.consts.append(VkConstant(enum_elem.attrib.get("name"), enum_elem.attrib.get("value")))
2522                         continue
2523                     else:
2524                         # This seems to be used to pull in constants e.g. VK_MAX_DEVICE_GROUP_KHX
2525                         continue
2527                 # Pull in any commands we need. We infer types to pull in from the command
2528                 # as well.
2529                 for command in require.findall("command"):
2530                     cmd_name = command.attrib["name"]
2531                     self._mark_command_required(cmd_name)
2533             # Store a list with extensions.
2534             ext_info = {"name" : ext_name, "type" : ext_type}
2535             extensions.append(ext_info)
2537         # Sort in alphabetical order.
2538         self.extensions = sorted(extensions, key=lambda ext: ext["name"])
2540     def _parse_features(self, root):
2541         """ Parse the feature section, which describes Core commands and types needed. """
2543         # For now limit to 1.0 features as various 1.1 features need more work.
2544         # In particular interop extensions promoted to Core.
2545         requires = root.findall("./feature/[@name='VK_VERSION_1_0']/require")
2547         for require in requires:
2548             LOGGER.info("Including features for {0}".format(require.attrib.get("comment")))
2549             for tag in require:
2550                 # Only deal with command. Other values which appear are enum and type for pulling in some
2551                 # constants and macros. Tricky to parse, so don't bother right now, we will generate them
2552                 # anyway for now.
2553                 if tag.tag == "comment":
2554                     continue
2555                 elif tag.tag == "command":
2556                     name = tag.attrib["name"]
2557                     self._mark_command_required(name)
2558                 elif tag.tag == "enum":
2559                     # We could pull in relevant constants here. Unfortunately
2560                     # this only gets half of them pulled in as others indirectly
2561                     # get pulled in through structures. Constants don't harm us,
2562                     # so don't bother.
2563                     pass
2564                 elif tag.tag == "type":
2565                     # Pull in types which may not have been pulled in through commands.
2566                     name = tag.attrib["name"]
2568                     # Skip pull in for vk_platform.h for now.
2569                     if name == "vk_platform":
2570                         continue
2572                     type_info = self.types[name]
2573                     type_info["data"].required = True
2575     def _parse_types(self, root):
2576         """ Parse types section, which contains all data types e.g. structs, typedefs etcetera. """
2577         types = root.findall("./types/type")
2579         base_types = []
2580         bitmasks = []
2581         defines = []
2582         funcpointers = []
2583         handles = []
2584         structs = []
2586         alias_types = []
2587         for t in types:
2588             type_info = {}
2589             type_info["category"] = t.attrib.get("category", None)
2591             # We parse aliases in a second pass when we know more.
2592             alias = t.attrib.get("alias")
2593             if alias:
2594                 LOGGER.debug("Alias found: {0}".format(alias))
2595                 alias_types.append(t)
2596                 continue
2598             if type_info["category"] in ["include"]:
2599                 continue
2601             if type_info["category"] == "basetype":
2602                 name = t.find("name").text
2603                 _type = t.find("type").text
2604                 basetype = VkBaseType(name, _type)
2605                 base_types.append(basetype)
2606                 type_info["data"] = basetype
2608             if type_info["category"] == "bitmask":
2609                 name = t.find("name").text
2610                 _type = t.find("type").text
2612                 # Most bitmasks have a requires attribute used to pull in
2613                 # required '*FlagBits" enum.
2614                 requires = t.attrib.get("requires")
2615                 bitmask = VkBaseType(name, _type, requires=requires)
2616                 bitmasks.append(bitmask)
2617                 type_info["data"] = bitmask
2619             if type_info["category"] == "define":
2620                 define = VkDefine.from_xml(t)
2621                 defines.append(define)
2622                 type_info["data"] = define
2624             if type_info["category"] == "enum":
2625                 name = t.attrib.get("name")
2626                 # The type section only contains enum names, not the actual definition.
2627                 # Since we already parsed the enum before, just link it in.
2628                 try:
2629                     type_info["data"] = self.enums[name]
2630                 except KeyError as e:
2631                     # Not all enums seem to be defined yet, typically that's for
2632                     # ones ending in 'FlagBits' where future extensions may add
2633                     # definitions.
2634                     type_info["data"] = None
2636             if type_info["category"] == "funcpointer":
2637                 funcpointer = VkFunctionPointer.from_xml(t)
2638                 funcpointers.append(funcpointer)
2639                 type_info["data"] = funcpointer
2641             if type_info["category"] == "handle":
2642                 handle = VkHandle.from_xml(t)
2643                 handles.append(handle)
2644                 type_info["data"] = handle
2646             if type_info["category"] in ["struct", "union"]:
2647                 # We store unions among structs as some structs depend
2648                 # on unions. The types are very similar in parsing and
2649                 # generation anyway. The official Vulkan scripts use
2650                 # a similar kind of hack.
2651                 struct = VkStruct.from_xml(t)
2652                 structs.append(struct)
2653                 type_info["data"] = struct
2655             # Name is in general within a name tag else it is an optional
2656             # attribute on the type tag.
2657             name_elem = t.find("name")
2658             if name_elem is not None:
2659                 type_info["name"] = name_elem.text
2660             else:
2661                 type_info["name"] = t.attrib.get("name", None)
2663             # Store all type data in a shared dictionary, so we can easily
2664             # look up information for a given type. There are no duplicate
2665             # names.
2666             self.types[type_info["name"]] = type_info
2668         # Second pass for alias types, so we can retrieve all data from
2669         # the aliased object.
2670         for t in alias_types:
2671             type_info = {}
2672             type_info["category"] = t.attrib.get("category")
2673             type_info["name"] = t.attrib.get("name")
2675             alias = t.attrib.get("alias")
2677             if type_info["category"] == "bitmask":
2678                 bitmask = VkBaseType(type_info["name"], alias, alias=True)
2679                 bitmasks.append(bitmask)
2680                 type_info["data"] = bitmask
2682             if type_info["category"] == "enum":
2683                 enum = VkEnum.from_alias(t, self.types[alias]["data"])
2684                 type_info["data"] = enum
2685                 self.enums[enum.name] = enum
2687             if type_info["category"] == "handle":
2688                 handle = VkHandle.from_alias(t, self.types[alias]["data"])
2689                 handles.append(handle)
2690                 type_info["data"] = handle
2692             if type_info["category"] == "struct":
2693                 struct = VkStruct.from_alias(t, self.types[alias]["data"])
2694                 structs.append(struct)
2695                 type_info["data"] = struct
2697             self.types[type_info["name"]] = type_info
2699         # We need detailed type information during code generation
2700         # on structs for alignment reasons. Unfortunately structs
2701         # are parsed among other types, so there is no guarantee
2702         # that any types needed have been parsed already, so set
2703         # the data now.
2704         for struct in structs:
2705             struct.set_type_info(self.types)
2707         # Guarantee everything is sorted, so code generation doesn't have
2708         # to deal with this.
2709         self.base_types = sorted(base_types, key=lambda base_type: base_type.name)
2710         self.bitmasks = sorted(bitmasks, key=lambda bitmask: bitmask.name)
2711         self.defines = defines
2712         self.enums = OrderedDict(sorted(self.enums.items()))
2713         self.funcpointers = sorted(funcpointers, key=lambda fp: fp.name)
2714         self.handles = sorted(handles, key=lambda handle: handle.name)
2715         self.structs = sorted(structs, key=lambda struct: struct.name)
2717 def download_vk_xml(filename):
2718     url = "https://raw.github.com/KhronosGroup/Vulkan-Docs/v{0}/xml/vk.xml".format(VK_XML_VERSION)
2719     if not os.path.isfile(filename):
2720         urllib.request.urlretrieve(url, filename)
2722 def main():
2723     parser = argparse.ArgumentParser()
2724     parser.add_argument("-v", "--verbose", action="count", default=0, help="increase output verbosity")
2726     args = parser.parse_args()
2727     if args.verbose == 0:
2728         LOGGER.setLevel(logging.WARNING)
2729     elif args.verbose == 1:
2730         LOGGER.setLevel(logging.INFO)
2731     else: # > 1
2732         LOGGER.setLevel(logging.DEBUG)
2734     vk_xml = "vk-{0}.xml".format(VK_XML_VERSION)
2735     download_vk_xml(vk_xml)
2736     registry = VkRegistry(vk_xml)
2737     generator = VkGenerator(registry)
2739     with open(WINE_VULKAN_H, "w") as f:
2740         generator.generate_vulkan_h(f)
2742     with open(WINE_VULKAN_DRIVER_H, "w") as f:
2743         generator.generate_vulkan_driver_h(f)
2745     with open(WINE_VULKAN_THUNKS_H, "w") as f:
2746         generator.generate_thunks_h(f, "wine_")
2748     with open(WINE_VULKAN_THUNKS_C, "w") as f:
2749         generator.generate_thunks_c(f, "wine_")
2751     with open(WINE_VULKAN_SPEC, "w") as f:
2752         generator.generate_vulkan_spec(f)
2754     with open(WINE_VULKAN_LOADER_SPEC, "w") as f:
2755         generator.generate_vulkan_loader_spec(f)
2757 if __name__ == "__main__":
2758     main()