winevulkan: Update to VK spec version 1.3.213.
[wine.git] / dlls / winevulkan / make_vulkan
blob2d49eceb93b57cc6ed60816f2cd7dfc289e573e7
1 #!/usr/bin/env 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.3.213"
68 WINE_VK_VERSION = (1, 3)
70 # Filenames to create.
71 WINE_VULKAN_H = "../../include/wine/vulkan.h"
72 WINE_VULKAN_DRIVER_H = "../../include/wine/vulkan_driver.h"
73 WINE_VULKAN_LOADER_SPEC = "../vulkan-1/vulkan-1.spec"
74 WINE_VULKAN_JSON = "winevulkan.json"
75 WINE_VULKAN_SPEC = "winevulkan.spec"
76 WINE_VULKAN_THUNKS_C = "vulkan_thunks.c"
77 WINE_VULKAN_THUNKS_H = "vulkan_thunks.h"
78 WINE_VULKAN_LOADER_THUNKS_C = "loader_thunks.c"
79 WINE_VULKAN_LOADER_THUNKS_H = "loader_thunks.h"
81 # Extension enum values start at a certain offset (EXT_BASE).
82 # Relative to the offset each extension has a block (EXT_BLOCK_SIZE)
83 # of values.
84 # Start for a given extension is:
85 # EXT_BASE + (extension_number-1) * EXT_BLOCK_SIZE
86 EXT_BASE = 1000000000
87 EXT_BLOCK_SIZE = 1000
89 UNSUPPORTED_EXTENSIONS = [
90     # Instance extensions
91     "VK_EXT_headless_surface", # Needs WSI work.
92     "VK_KHR_display", # Needs WSI work.
93     "VK_KHR_surface_protected_capabilities",
95     # Device extensions
96     "VK_AMD_display_native_hdr",
97     "VK_EXT_full_screen_exclusive",
98     "VK_EXT_hdr_metadata", # Needs WSI work.
99     "VK_GOOGLE_display_timing",
100     "VK_KHR_external_fence_win32",
101     "VK_KHR_external_semaphore_win32",
102     # Relates to external_semaphore and needs type conversions in bitflags.
103     "VK_KHR_shared_presentable_image", # Needs WSI work.
104     "VK_KHR_win32_keyed_mutex",
105     "VK_NV_external_memory_rdma", # Needs shared resources work.
107     # Extensions for other platforms
108     "VK_EXT_external_memory_dma_buf",
109     "VK_EXT_image_drm_format_modifier",
110     "VK_EXT_physical_device_drm",
111     "VK_GOOGLE_surfaceless_query",
112     "VK_KHR_external_fence_fd",
113     "VK_KHR_external_memory_fd",
114     "VK_KHR_external_semaphore_fd",
116     # Extensions which require callback handling
117     "VK_EXT_device_memory_report",
119     # Needs https://github.com/KhronosGroup/Vulkan-Docs/pull/1848
120     # or a rework of how we detect returned structs.
121     "VK_EXT_image_compression_control",
123     # Deprecated extensions
124     "VK_NV_external_memory_capabilities",
125     "VK_NV_external_memory_win32",
128 # Either internal extensions which aren't present on the win32 platform which
129 # winevulkan may nonetheless use, or extensions we want to generate headers for
130 # but not expose to applications (useful for test commits)
131 UNEXPOSED_EXTENSIONS = {
132     "VK_KHR_external_memory_win32",
135 # The Vulkan loader provides entry-points for core functionality and important
136 # extensions. Based on vulkan-1.def this amounts to WSI extensions on 1.0.51.
137 CORE_EXTENSIONS = [
138     "VK_KHR_display",
139     "VK_KHR_display_swapchain",
140     "VK_KHR_get_surface_capabilities2",
141     "VK_KHR_surface",
142     "VK_KHR_swapchain",
143     "VK_KHR_win32_surface",
146 # Some experimental extensions are used by shipping applications so their API is extremely unlikely
147 # to change in a backwards-incompatible way. Allow translation of those extensions with WineVulkan.
148 ALLOWED_X_EXTENSIONS = [
149     "VK_NVX_binary_import",
150     "VK_NVX_image_view_handle",
153 # We can't use syscall interface for functions that may call display drivers
154 # until drivers are converted to pure Unix libraries. Also some frequently
155 # called functions use direct calls for performance reasons.
156 DIRECT_CALL_FUNCTIONS = [
157     "vkCreateDevice",
158     "vkEnumerateInstanceVersion",
159     "vkUpdateDescriptorSets",
160     "vkUpdateDescriptorSetWithTemplate",
163 # Functions part of our winevulkan graphics driver interface.
164 # DRIVER_VERSION should be bumped on any change to driver interface
165 # in FUNCTION_OVERRIDES
166 DRIVER_VERSION = 10
168 class ThunkType(Enum):
169     NONE = 1
170     PUBLIC = 2
171     PRIVATE = 3
173 # Table of functions for which we have a special implementation.
174 # These are regular device / instance functions for which we need
175 # to do more work compared to a regular thunk or because they are
176 # part of the driver interface.
177 # - dispatch set whether we need a function pointer in the device
178 #   / instance dispatch table.
179 # - driver sets whether the API is part of the driver interface.
180 # - thunk sets whether to create a thunk in vulkan_thunks.c.
181 #   - NONE means there's a fully custom implementation.
182 #   - PUBLIC means the implementation is fully auto generated.
183 #   - PRIVATE thunks can be used in custom implementations for
184 #     struct conversion.
185 # - loader_thunk sets whether to create a thunk for unix_funcs.
186 FUNCTION_OVERRIDES = {
187     # Global functions
188     "vkCreateInstance" : {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE},
189     "vkEnumerateInstanceExtensionProperties" : {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE},
190     "vkEnumerateInstanceLayerProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.NONE},
191     "vkEnumerateInstanceVersion": {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE},
192     "vkGetInstanceProcAddr": {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.NONE},
194     # Instance functions
195     "vkCreateDevice" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
196     "vkDestroyInstance" : {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE },
197     "vkEnumerateDeviceExtensionProperties" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
198     "vkEnumerateDeviceLayerProperties": {"dispatch": True, "driver": False, "thunk": ThunkType.NONE},
199     "vkEnumeratePhysicalDeviceGroups" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
200     "vkEnumeratePhysicalDevices" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
201     "vkGetPhysicalDeviceExternalBufferProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
202     "vkGetPhysicalDeviceExternalFenceProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
203     "vkGetPhysicalDeviceExternalSemaphoreProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
204     "vkGetPhysicalDeviceImageFormatProperties2" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE},
205     "vkGetPhysicalDeviceProperties2" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PUBLIC, "loader_thunk" : ThunkType.PRIVATE},
206     "vkGetPhysicalDeviceProperties2KHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PUBLIC, "loader_thunk" : ThunkType.PRIVATE},
208     # Device functions
209     "vkAllocateCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
210     "vkCreateCommandPool" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
211     "vkCreateComputePipelines" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.PRIVATE},
212     "vkCreateGraphicsPipelines" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.PRIVATE},
213     "vkDestroyCommandPool" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
214     "vkDestroyDevice" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
215     "vkFreeCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
216     "vkGetDeviceProcAddr" : {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.NONE},
217     "vkGetDeviceQueue" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
218     "vkGetDeviceQueue2" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
220     # VK_KHR_surface
221     "vkDestroySurfaceKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.NONE},
222     "vkGetPhysicalDeviceSurfaceSupportKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
223     "vkGetPhysicalDeviceSurfaceCapabilitiesKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PRIVATE},
224     "vkGetPhysicalDeviceSurfaceFormatsKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
225     "vkGetPhysicalDeviceSurfacePresentModesKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
227     # VK_KHR_get_surface_capabilities2
228     "vkGetPhysicalDeviceSurfaceCapabilities2KHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PRIVATE},
229     "vkGetPhysicalDeviceSurfaceFormats2KHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
231     # VK_KHR_win32_surface
232     "vkCreateWin32SurfaceKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.NONE},
233     "vkGetPhysicalDeviceWin32PresentationSupportKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
235     # VK_KHR_swapchain
236     "vkCreateSwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
237     "vkDestroySwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
238     "vkGetSwapchainImagesKHR": {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
239     "vkQueuePresentKHR": {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
241     # VK_KHR_external_fence_capabilities
242     "vkGetPhysicalDeviceExternalFencePropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
244     # VK_KHR_external_memory_capabilities
245     "vkGetPhysicalDeviceExternalBufferPropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
246     "vkGetPhysicalDeviceImageFormatProperties2KHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE},
248     # VK_KHR_external_semaphore_capabilities
249     "vkGetPhysicalDeviceExternalSemaphorePropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
251     # VK_KHR_device_group_creation
252     "vkEnumeratePhysicalDeviceGroupsKHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
254     # VK_KHR_device_group
255     "vkGetDeviceGroupSurfacePresentModesKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
256     "vkGetPhysicalDevicePresentRectanglesKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
258     # VK_KHR_ray_tracing_pipeline
259     "vkCreateRayTracingPipelinesKHR" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.PRIVATE},
261     # VK_EXT_calibrated_timestamps
262     "vkGetPhysicalDeviceCalibrateableTimeDomainsEXT" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
263     "vkGetCalibratedTimestampsEXT" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
265     # VK_EXT_debug_utils
266     "vkCreateDebugUtilsMessengerEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
267     "vkDestroyDebugUtilsMessengerEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
269     # VK_EXT_debug_report
270     "vkCreateDebugReportCallbackEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
271     "vkDestroyDebugReportCallbackEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
273     # VK_NV_ray_tracing
274     "vkCreateRayTracingPipelinesNV" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.PRIVATE},
277 STRUCT_CHAIN_CONVERSIONS = {
278     # Ignore to not confuse host loader.
279     "VkDeviceCreateInfo": ["VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO"],
280     "VkInstanceCreateInfo": ["VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO"],
284 class Direction(Enum):
285     """ Parameter direction: input, output, input_output. """
286     INPUT = 1
287     OUTPUT = 2
288     INPUT_OUTPUT = 3
291 class VkBaseType(object):
292     def __init__(self, name, _type, alias=None, requires=None):
293         """ Vulkan base type class.
295         VkBaseType is mostly used by Vulkan to define its own
296         base types like VkFlags through typedef out of e.g. uint32_t.
298         Args:
299             name (:obj:'str'): Name of the base type.
300             _type (:obj:'str'): Underlying type
301             alias (bool): type is an alias or not.
302             requires (:obj:'str', optional): Other types required.
303                 Often bitmask values pull in a *FlagBits type.
304         """
305         self.name = name
306         self.type = _type
307         self.alias = alias
308         self.requires = requires
309         self.required = False
311     def definition(self):
312         # Definition is similar for alias or non-alias as type
313         # is already set to alias.
314         if not self.type is None:
315             return "typedef {0} {1};\n".format(self.type, self.name)
316         else:
317             return "struct {0};\n".format(self.name)
319     def is_alias(self):
320         return bool(self.alias)
323 class VkConstant(object):
324     def __init__(self, name, value):
325         self.name = name
326         self.value = value
328     def definition(self):
329         text = "#define {0} {1}\n".format(self.name, self.value)
330         return text
333 class VkDefine(object):
334     def __init__(self, name, value):
335         self.name = name
336         self.value = value
338     @staticmethod
339     def from_xml(define):
340         name_elem = define.find("name")
342         if name_elem is None:
343             # <type category="define" name="some_name">some_value</type>
344             name = define.attrib.get("name")
346             # We override behavior of VK_USE_64_BIT_PTR_DEFINES as the default non-dispatchable handle
347             # definition various between 64-bit (uses pointers) and 32-bit (uses uint64_t).
348             # This complicates TRACEs in the thunks, so just use uint64_t.
349             if name == "VK_USE_64_BIT_PTR_DEFINES":
350                 value = "#define VK_USE_64_BIT_PTR_DEFINES 0"
351             else:
352                 value = define.text
353             return VkDefine(name, value)
355         # With a name element the structure is like:
356         # <type category="define"><name>some_name</name>some_value</type>
357         name = name_elem.text
359         # Perform minimal parsing for Vulkan constants, which we don't need, but are referenced
360         # elsewhere in vk.xml.
361         # - VK_API_VERSION is a messy, deprecated constant and we don't want generate code for it.
362         # - AHardwareBuffer/ANativeWindow are forward declarations for Android types, which leaked
363         #   into the define region.
364         if name in ["VK_API_VERSION", "AHardwareBuffer", "ANativeWindow", "CAMetalLayer"]:
365             return VkDefine(name, None)
367         # The body of the define is basically unstructured C code. It is not meant for easy parsing.
368         # Some lines contain deprecated values or comments, which we try to filter out.
369         value = ""
370         for line in define.text.splitlines():
371             # Skip comments or deprecated values.
372             if "//" in line:
373                 continue
374             value += line
376         for child in define:
377             value += child.text
378             if child.tail is not None:
379                 # Split comments for VK_API_VERSION_1_0 / VK_API_VERSION_1_1
380                 if "//" in child.tail:
381                     value += child.tail.split("//")[0]
382                 else:
383                     value += child.tail
385         return VkDefine(name, value.rstrip(' '))
387     def definition(self):
388         if self.value is None:
389             return ""
391         # Nothing to do as the value was already put in the right form during parsing.
392         return "{0}\n".format(self.value)
395 class VkEnum(object):
396     def __init__(self, name, bitwidth, alias=None):
397         if not bitwidth in [32, 64]:
398             LOGGER.error("unknown bitwidth {0} for {1}".format(bitwidth, name))
399         self.name = name
400         self.bitwidth = bitwidth
401         self.values = [] if alias == None else alias.values
402         self.required = False
403         self.alias = alias
404         self.aliased_by = []
406     @staticmethod
407     def from_alias(enum, alias):
408         name = enum.attrib.get("name")
409         aliasee = VkEnum(name, alias.bitwidth, alias=alias)
411         alias.add_aliased_by(aliasee)
412         return aliasee
414     @staticmethod
415     def from_xml(enum):
416         name = enum.attrib.get("name")
417         bitwidth = int(enum.attrib.get("bitwidth", "32"))
418         result = VkEnum(name, bitwidth)
420         for v in enum.findall("enum"):
421             value_name = v.attrib.get("name")
422             # Value is either a value or a bitpos, only one can exist.
423             value = v.attrib.get("value")
424             alias_name = v.attrib.get("alias")
425             if alias_name:
426                 result.create_alias(value_name, alias_name)
427             elif value:
428                 result.create_value(value_name, value)
429             else:
430                 # bitmask
431                 result.create_bitpos(value_name, int(v.attrib.get("bitpos")))
433         if bitwidth == 32:
434             # vulkan.h contains a *_MAX_ENUM value set to 32-bit at the time of writing,
435             # which is to prepare for extensions as they can add values and hence affect
436             # the size definition.
437             max_name = re.sub(r'([0-9a-z_])([A-Z0-9])',r'\1_\2', name).upper() + "_MAX_ENUM"
438             result.create_value(max_name, "0x7fffffff")
440         return result
442     def create_alias(self, name, alias_name):
443         """ Create an aliased value for this enum """
444         # Older GCC versions need a literal to initialize a static const uint64_t
445         # which is what we use for 64bit bitmasks.
446         if self.bitwidth == 64:
447             alias = next(x for x in self.values if x.name == alias_name)
448             self.add(VkEnumValue(name, self.bitwidth, value=alias.value, hex=alias.hex, alias=alias_name))
449         else:
450             self.add(VkEnumValue(name, self.bitwidth, alias=alias_name))
452     def create_value(self, name, value):
453         """ Create a new value for this enum """
454         # Some values are in hex form. We want to preserve the hex representation
455         # at least when we convert back to a string. Internally we want to use int.
456         hex = "0x" in value
457         self.add(VkEnumValue(name, self.bitwidth, value=int(value, 0), hex=hex))
459     def create_bitpos(self, name, pos):
460         """ Create a new bitmask value for this enum """
461         self.add(VkEnumValue(name, self.bitwidth, value=(1 << pos), hex=True))
463     def add(self, value):
464         """ Add a value to enum. """
466         # Extensions can add new enum values. When an extension is promoted to Core
467         # the registry defines the value twice once for old extension and once for
468         # new Core features. Add the duplicate if it's explicitly marked as an
469         # alias, otherwise ignore it.
470         for v in self.values:
471             if not value.is_alias() and v.value == value.value:
472                 LOGGER.debug("Adding duplicate enum value {0} to {1}".format(v, self.name))
473                 return
474         # Avoid adding duplicate aliases multiple times
475         if not any(x.name == value.name for x in self.values):
476             self.values.append(value)
478     def definition(self):
479         if self.is_alias():
480             return ""
482         default_value = 0x7ffffffe if self.bitwidth == 32 else 0xfffffffffffffffe
484         # Print values sorted, values can have been added in a random order.
485         values = sorted(self.values, key=lambda value: value.value if value.value is not None else default_value)
487         if self.bitwidth == 32:
488             text = "typedef enum {0}\n{{\n".format(self.name)
489             for value in values:
490                 text += "    {0},\n".format(value.definition())
491             text += "}} {0};\n".format(self.name)
492         elif self.bitwidth == 64:
493             text = "typedef VkFlags64 {0};\n\n".format(self.name)
494             for value in values:
495                 text += "static const {0} {1};\n".format(self.name, value.definition())
497         for aliasee in self.aliased_by:
498             text += "typedef {0} {1};\n".format(self.name, aliasee.name)
500         text += "\n"
501         return text
503     def is_alias(self):
504         return bool(self.alias)
506     def add_aliased_by(self, aliasee):
507         self.aliased_by.append(aliasee)
510 class VkEnumValue(object):
511     def __init__(self, name, bitwidth, value=None, hex=False, alias=None):
512         self.name = name
513         self.bitwidth = bitwidth
514         self.value = value
515         self.hex = hex
516         self.alias = alias
518     def __repr__(self):
519         postfix = "ull" if self.bitwidth == 64 else ""
520         if self.is_alias() and self.value == None:
521             return "{0}={1}".format(self.name, self.alias)
522         return "{0}={1}{2}".format(self.name, self.value, postfix)
524     def definition(self):
525         """ Convert to text definition e.g. VK_FOO = 1 """
526         postfix = "ull" if self.bitwidth == 64 else ""
527         if self.is_alias() and self.value == None:
528             return "{0} = {1}".format(self.name, self.alias)
530         # Hex is commonly used for FlagBits and sometimes within
531         # a non-FlagBits enum for a bitmask value as well.
532         if self.hex:
533             return "{0} = 0x{1:08x}{2}".format(self.name, self.value, postfix)
534         else:
535             return "{0} = {1}{2}".format(self.name, self.value, postfix)
537     def is_alias(self):
538         return self.alias is not None
541 class VkFunction(object):
542     def __init__(self, _type=None, name=None, params=[], alias=None):
543         self.extensions = set()
544         self.name = name
545         self.type = _type
546         self.params = params
547         self.alias = alias
549         # For some functions we need some extra metadata from FUNCTION_OVERRIDES.
550         func_info = FUNCTION_OVERRIDES.get(self.name, None)
551         self.dispatch = func_info["dispatch"] if func_info else True
552         self.driver = func_info["driver"] if func_info else False
553         self.thunk_type = func_info["thunk"] if func_info else ThunkType.PUBLIC
554         self.loader_thunk_type = func_info["loader_thunk"] if func_info and "loader_thunk" in func_info else ThunkType.PUBLIC
556         # Required is set while parsing which APIs and types are required
557         # and is used by the code generation.
558         self.required = True if func_info else False
560     @staticmethod
561     def from_alias(command, alias):
562         """ Create VkFunction from an alias command.
564         Args:
565             command: xml data for command
566             alias (VkFunction): function to use as a base for types / parameters.
568         Returns:
569             VkFunction
570         """
571         func_name = command.attrib.get("name")
572         func_type = alias.type
573         params = alias.params
575         return VkFunction(_type=func_type, name=func_name, params=params, alias=alias)
577     @staticmethod
578     def from_xml(command, types):
579         proto = command.find("proto")
580         func_name = proto.find("name").text
581         func_type = proto.find("type").text
583         params = []
584         for param in command.findall("param"):
585             vk_param = VkParam.from_xml(param, types)
586             params.append(vk_param)
588         return VkFunction(_type=func_type, name=func_name, params=params)
590     def get_conversions(self):
591         """ Get a list of conversion functions required for this function if any.
592         Parameters which are structures may require conversion between win32
593         and the host platform. This function returns a list of conversions
594         required.
595         """
597         conversions = []
598         for param in self.params:
599             convs = param.get_conversions()
600             if convs is not None:
601                 conversions.extend(convs)
603         return conversions
605     def is_alias(self):
606         return bool(self.alias)
608     def is_core_func(self):
609         """ Returns whether the function is a Vulkan core function.
610         Core functions are APIs defined by the Vulkan spec to be part of the
611         Core API as well as several KHR WSI extensions.
612         """
614         if not self.extensions:
615             return True
617         return any(ext in self.extensions for ext in CORE_EXTENSIONS)
619     def is_device_func(self):
620         # If none of the other, it must be a device function
621         return not self.is_global_func() and not self.is_instance_func() and not self.is_phys_dev_func()
623     def is_driver_func(self):
624         """ Returns if function is part of Wine driver interface. """
625         return self.driver
627     def is_global_func(self):
628         # Treat vkGetInstanceProcAddr as a global function as it
629         # can operate with NULL for vkInstance.
630         if self.name == "vkGetInstanceProcAddr":
631             return True
632         # Global functions are not passed a dispatchable object.
633         elif self.params[0].is_dispatchable():
634             return False
635         return True
637     def is_instance_func(self):
638         # Instance functions are passed VkInstance.
639         if self.params[0].type == "VkInstance":
640             return True
641         return False
643     def is_phys_dev_func(self):
644         # Physical device functions are passed VkPhysicalDevice.
645         if self.params[0].type == "VkPhysicalDevice":
646             return True
647         return False
649     def is_required(self):
650         return self.required
652     def returns_longlong(self):
653         return self.type in ["uint64_t", "VkDeviceAddress"]
655     def needs_conversion(self):
656         """ Check if the function needs any input/output type conversion.
657         Functions need input/output conversion if struct parameters have
658         alignment differences between Win32 and Linux 32-bit.
659         """
661         for p in self.params:
662             if p.needs_conversion():
663                 LOGGER.debug("Parameter {0} to {1} requires conversion".format(p.name, self.name))
664                 return True
666         return False
668     def needs_unwrapping(self):
669         """ Check if the function needs any input/output type unwrapping.
670         Functions need input/output unwrapping if struct parameters have
671         wrapped handles.
672         """
674         for p in self.params:
675             if p.needs_unwrapping():
676                 return True
678         return False
680     def needs_dispatch(self):
681         return self.dispatch
683     def needs_thunk(self):
684         return self.thunk_type != ThunkType.NONE
686     def needs_private_thunk(self):
687         return self.thunk_type == ThunkType.PRIVATE
689     def needs_exposing(self):
690         # The function needs exposed if at-least one extension isn't both UNSUPPORTED and UNEXPOSED
691         return self.is_required() and (not self.extensions or not self.extensions.issubset(UNEXPOSED_EXTENSIONS))
693     def needs_direct_call(self):
694         # vkCmd* functions are frequently called, use direct calls for performance
695         if self.name.startswith("vkCmd"):
696             return True
697         return self.is_driver_func() or self.name in DIRECT_CALL_FUNCTIONS
699     def pfn(self, prefix="p", call_conv=None, conv=False):
700         """ Create function pointer. """
702         if call_conv:
703             pfn = "{0} ({1} *{2}_{3})(".format(self.type, call_conv, prefix, self.name)
704         else:
705             pfn = "{0} (*{1}_{2})(".format(self.type, prefix, self.name)
707         for i, param in enumerate(self.params):
708             if param.const:
709                 pfn += param.const + " "
711             pfn += param.type
712             if conv and param.needs_conversion():
713                 pfn += "_host"
715             if param.is_pointer():
716                 pfn += " " + param.pointer
718             if param.array_len is not None:
719                 pfn += "[{0}]".format(param.array_len)
721             if i < len(self.params) - 1:
722                 pfn += ", "
723         pfn += ")"
724         return pfn
726     def prototype(self, call_conv=None, prefix=None, postfix=None):
727         """ Generate prototype for given function.
729         Args:
730             call_conv (str, optional): calling convention e.g. WINAPI
731             prefix (str, optional): prefix to append prior to function name e.g. vkFoo -> wine_vkFoo
732             postfix (str, optional): text to append after function name but prior to semicolon e.g. DECLSPEC_HIDDEN
733         """
735         proto = "{0}".format(self.type)
737         if call_conv is not None:
738             proto += " {0}".format(call_conv)
740         if prefix is not None:
741             proto += " {0}{1}(".format(prefix, self.name)
742         else:
743             proto += " {0}(".format(self.name)
745         # Add all the parameters.
746         proto += ", ".join([p.definition() for p in self.params])
748         if postfix is not None:
749             proto += ") {0}".format(postfix)
750         else:
751             proto += ")"
753         return proto
755     def body(self, params_prefix=""):
756         body = ""
758         if not self.needs_private_thunk():
759             body += "    {0}".format(self.trace(params_prefix=params_prefix))
761         params = ", ".join([p.variable(conv=False, params_prefix=params_prefix) for p in self.params])
763         # Call the native Vulkan function.
764         body += "    "
765         if self.returns_longlong():
766             body += "{0}result = ".format(params_prefix)
767         elif self.type != "void":
768             body += "return "
769         body += "{0}{1}.p_{2}({3});\n".format(params_prefix, self.params[0].dispatch_table(),
770                                               self.name, params)
771         if self.type == "void" or self.returns_longlong():
772             body += "    return STATUS_SUCCESS;\n"
774         return body
776     def loader_body(self):
777         body = "    struct {0}_params params;\n".format(self.name)
778         for p in self.params:
779             body += "    params.{0} = {0};\n".format(p.name)
780         body += "    ";
782         # Call the Unix function.
783         if self.type != "void" and not self.returns_longlong():
784             body += "return "
785         if self.needs_direct_call():
786             body += "unix_funcs->p_vk_call(unix_{0}, &params);\n".format(self.name)
787         else:
788             body += "vk_unix_call(unix_{0}, &params);\n".format(self.name)
789         if self.returns_longlong():
790             body += "    return params.result;\n"
791         return body
793     def body_conversion(self, conv, params_prefix=""):
794         body = ""
795         result_prefix = ""
797         # Declare a variable to hold the result for non-void functions.
798         if self.returns_longlong():
799             result_prefix = "params->"
800         elif self.type != "void":
801             body += "    {0} result;\n".format(self.type)
803         # Declare any tmp parameters for conversion.
804         for p in self.params:
805             if p.needs_conversion() and conv:
806                 if p.is_dynamic_array():
807                     body += "    {0}_host *{1}_host;\n".format(p.type, p.name)
808                 else:
809                     body += "    {0}_host {1}_host;\n".format(p.type, p.name)
810             elif p.needs_unwrapping():
811                 if p.is_dynamic_array():
812                     body += "    {0} *{1}_host;\n".format(p.type, p.name)
813                 else:
814                     body += "    {0} {1}_host;\n".format(p.type, p.name)
816         if not self.needs_private_thunk():
817             body += "    {0}\n".format(self.trace(params_prefix=params_prefix))
819         # Call any win_to_host conversion calls.
820         for p in self.params:
821             if p.needs_input_conversion() and (p.needs_unwrapping() or conv):
822                 body += p.copy(Direction.INPUT, prefix=params_prefix)
824         # Build list of parameters containing converted and non-converted parameters.
825         # The param itself knows if conversion is needed and applies it when we set conv=True.
826         params = ", ".join([p.variable(conv=conv, params_prefix=params_prefix) for p in self.params])
828         # Call the native Vulkan function.
829         if self.type == "void":
830             body += "    {0}{1}.p_{2}({3});\n".format(params_prefix, self.params[0].dispatch_table(),
831                                                       self.name, params)
832         else:
833             body += "    {0}result = {1}{2}.p_{3}({4});\n".format(result_prefix, params_prefix,
834                                                                   self.params[0].dispatch_table(),
835                                                                   self.name, params)
837         body += "\n"
839         # Call any host_to_win conversion calls.
840         for p in self.params:
841             if not p.needs_output_conversion():
842                 continue
844             body += p.copy(Direction.OUTPUT, prefix=params_prefix)
846         # Perform any required cleanups. Most of these are for array functions.
847         for p in self.params:
848             if p.needs_free() and (p.needs_unwrapping() or conv):
849                 body += p.free(prefix=params_prefix)
851         # Finally return the result.
852         if self.type != "void" and not self.returns_longlong():
853             body += "    return result;\n"
854         else:
855             body += "    return STATUS_SUCCESS;\n"
857         return body
859     def spec(self, prefix=None, symbol=None):
860         """ Generate spec file entry for this function.
862         Args
863             prefix (str, optional): prefix to prepend to entry point name.
864             symbol (str, optional): allows overriding the name of the function implementing the entry point.
865         """
867         spec = ""
868         params = " ".join([p.spec() for p in self.params])
869         if prefix is not None:
870             spec += "@ stdcall -private {0}{1}({2})".format(prefix, self.name, params)
871         else:
872             spec += "@ stdcall {0}({1})".format(self.name, params)
874         if symbol is not None:
875             spec += " " + symbol
877         spec += "\n"
878         return spec
880     def stub(self, call_conv=None, prefix=None):
881         stub = self.prototype(call_conv=call_conv, prefix=prefix)
882         stub += "\n{\n"
883         stub += "    {0}".format(self.trace(message="stub: ", trace_func="FIXME"))
885         if self.type == "VkResult":
886             stub += "    return VK_ERROR_OUT_OF_HOST_MEMORY;\n"
887         elif self.type == "VkBool32":
888             stub += "    return VK_FALSE;\n"
889         elif self.type == "PFN_vkVoidFunction":
890             stub += "    return NULL;\n"
892         stub += "}\n\n"
893         return stub
895     def thunk(self, prefix=None):
896         if prefix == "thunk_":
897             thunk = self.prototype(prefix=prefix)
898             thunk += "\n{\n"
899             params_prefix = ""
900         else:
901             thunk = "NTSTATUS {0}{1}(void *args)\n".format(prefix, self.name)
902             thunk += "{\n"
903             thunk += "    struct {0}_params *params = args;\n".format(self.name)
904             params_prefix = "params->"
906         if self.needs_conversion():
907             thunk += "#if defined(USE_STRUCT_CONVERSION)\n"
908             thunk += self.body_conversion(conv=True, params_prefix=params_prefix)
909             thunk += "#else\n"
910             if self.needs_unwrapping():
911                 thunk += self.body_conversion(conv=False, params_prefix=params_prefix)
912             else:
913                 thunk += self.body(params_prefix=params_prefix)
914             thunk += "#endif\n"
915         elif self.needs_unwrapping():
916             thunk += self.body_conversion(conv=False, params_prefix=params_prefix)
917         else:
918             thunk += self.body(params_prefix=params_prefix)
920         thunk += "}\n\n"
921         return thunk
923     def loader_thunk(self, prefix=None):
924         thunk = self.prototype(call_conv="WINAPI", prefix=prefix)
925         thunk += "\n{\n"
926         thunk += self.loader_body()
927         thunk += "}\n\n"
928         return thunk
930     def trace(self, message=None, trace_func=None, params_prefix=""):
931         """ Create a trace string including all parameters.
933         Args:
934             message (str, optional): text to print at start of trace message e.g. 'stub: '
935             trace_func (str, optional): used to override trace function e.g. FIXME, printf, etcetera.
936         """
937         if trace_func is not None:
938             trace = "{0}(\"".format(trace_func)
939         else:
940             trace = "TRACE(\""
942         if message is not None:
943             trace += message
945         # First loop is for all the format strings.
946         trace += ", ".join([p.format_string() for p in self.params])
947         trace += "\\n\""
949         # Second loop for parameter names and optional conversions.
950         for param in self.params:
951             if param.format_conv is not None:
952                 trace += ", " + param.format_conv.format("{0}{1}".format(params_prefix, param.name))
953             else:
954                 trace += ", {0}{1}".format(params_prefix, param.name)
955         trace += ");\n"
957         return trace
960 class VkFunctionPointer(object):
961     def __init__(self, _type, name, members, forward_decls):
962         self.name = name
963         self.members = members
964         self.type = _type
965         self.required = False
966         self.forward_decls = forward_decls
968     @staticmethod
969     def from_xml(funcpointer):
970         members = []
971         begin = None
973         for t in funcpointer.findall("type"):
974             # General form:
975             # <type>void</type>*       pUserData,
976             # Parsing of the tail (anything past </type>) is tricky since there
977             # can be other data on the next line like: const <type>int</type>..
979             const = True if begin and "const" in begin else False
980             _type = t.text
981             lines = t.tail.split(",\n")
982             if lines[0][0] == "*":
983                 pointer = "*"
984                 name = lines[0][1:].strip()
985             else:
986                 pointer = None
987                 name = lines[0].strip()
989             # Filter out ); if it is contained.
990             name = name.partition(");")[0]
992             # If tail encompasses multiple lines, assign the second line to begin
993             # for the next line.
994             try:
995                 begin = lines[1].strip()
996             except IndexError:
997                 begin = None
999             members.append(VkMember(const=const, _type=_type, pointer=pointer, name=name))
1001         _type = funcpointer.text
1002         name = funcpointer.find("name").text
1003         if "requires" in funcpointer.attrib:
1004             forward_decls = funcpointer.attrib.get("requires").split(",")
1005         else:
1006             forward_decls = []
1007         return VkFunctionPointer(_type, name, members, forward_decls)
1009     def definition(self):
1010         text = ""
1011         # forward declare required structs
1012         for decl in self.forward_decls:
1013             text += "typedef struct {0} {0};\n".format(decl)
1015         text += "{0} {1})(\n".format(self.type, self.name)
1017         first = True
1018         if len(self.members) > 0:
1019             for m in self.members:
1020                 if first:
1021                     text += "    " + m.definition()
1022                     first = False
1023                 else:
1024                     text += ",\n    " + m.definition()
1025         else:
1026             # Just make the compiler happy by adding a void parameter.
1027             text += "void"
1028         text += ");\n"
1029         return text
1031     def is_alias(self):
1032         return False
1034 class VkHandle(object):
1035     def __init__(self, name, _type, parent, alias=None):
1036         self.name = name
1037         self.type = _type
1038         self.parent = parent
1039         self.alias = alias
1040         self.required = False
1041         self.object_type = None
1043     @staticmethod
1044     def from_alias(handle, alias):
1045         name = handle.attrib.get("name")
1046         return VkHandle(name, alias.type, alias.parent, alias=alias)
1048     @staticmethod
1049     def from_xml(handle):
1050         name = handle.find("name").text
1051         _type = handle.find("type").text
1052         parent = handle.attrib.get("parent") # Most objects have a parent e.g. VkQueue has VkDevice.
1053         return VkHandle(name, _type, parent)
1055     def dispatch_table(self):
1056         if not self.is_dispatchable():
1057             return None
1059         if self.parent is None:
1060             # Should only happen for VkInstance
1061             return "funcs"
1062         elif self.name == "VkDevice":
1063             # VkDevice has VkInstance as a parent, but has its own dispatch table.
1064             return "funcs"
1065         elif self.parent in ["VkInstance", "VkPhysicalDevice"]:
1066             return "instance->funcs"
1067         elif self.parent in ["VkDevice", "VkCommandPool"]:
1068             return "device->funcs"
1069         else:
1070             LOGGER.error("Unhandled dispatchable parent: {0}".format(self.parent))
1072     def definition(self):
1073         """ Generates handle definition e.g. VK_DEFINE_HANDLE(vkInstance) """
1075         # Legacy types are typedef'ed to the new type if they are aliases.
1076         if self.is_alias():
1077             return "typedef {0} {1};\n".format(self.alias.name, self.name)
1079         return "{0}({1})\n".format(self.type, self.name)
1081     def is_alias(self):
1082         return self.alias is not None
1084     def is_dispatchable(self):
1085         """ Some handles like VkInstance, VkDevice are dispatchable objects,
1086         which means they contain a dispatch table of function pointers.
1087         """
1088         return self.type == "VK_DEFINE_HANDLE"
1090     def is_required(self):
1091         return self.required
1093     def native_handle(self, name):
1094         """ Provide access to the native handle of a wrapped object. """
1096         if self.name == "VkCommandPool":
1097             return "wine_cmd_pool_from_handle({0})->command_pool".format(name)
1098         if self.name == "VkDebugUtilsMessengerEXT":
1099             return "wine_debug_utils_messenger_from_handle({0})->debug_messenger".format(name)
1100         if self.name == "VkDebugReportCallbackEXT":
1101             return "wine_debug_report_callback_from_handle({0})->debug_callback".format(name)
1102         if self.name == "VkSurfaceKHR":
1103             return "wine_surface_from_handle({0})->surface".format(name)
1105         native_handle_name = None
1107         if self.name == "VkCommandBuffer":
1108             native_handle_name = "command_buffer"
1109         if self.name == "VkDevice":
1110             native_handle_name = "device"
1111         if self.name == "VkInstance":
1112             native_handle_name = "instance"
1113         if self.name == "VkPhysicalDevice":
1114             native_handle_name = "phys_dev"
1115         if self.name == "VkQueue":
1116             native_handle_name = "queue"
1118         if native_handle_name:
1119             return "{0}->{1}".format(name, native_handle_name)
1121         if self.is_dispatchable():
1122             LOGGER.error("Unhandled native handle for: {0}".format(self.name))
1123         return None
1125     def driver_handle(self, name):
1126         """ Provide access to the handle that should be passed to the wine driver """
1128         if self.name == "VkSurfaceKHR":
1129             return "wine_surface_from_handle({0})->driver_surface".format(name)
1131         return self.native_handle(name)
1133     def is_wrapped(self):
1134         return self.native_handle("test") is not None
1136     def needs_conversion(self):
1137         return False
1139     def needs_unwrapping(self):
1140         return self.is_wrapped()
1142 class VkMember(object):
1143     def __init__(self, const=False, struct_fwd_decl=False,_type=None, pointer=None, name=None, array_len=None,
1144             dyn_array_len=None, optional=False, values=None, object_type=None, bit_width=None):
1145         self.const = const
1146         self.struct_fwd_decl = struct_fwd_decl
1147         self.name = name
1148         self.pointer = pointer
1149         self.type = _type
1150         self.type_info = None
1151         self.array_len = array_len
1152         self.dyn_array_len = dyn_array_len
1153         self.optional = optional
1154         self.values = values
1155         self.object_type = object_type
1156         self.bit_width = bit_width
1158     def __eq__(self, other):
1159         """ Compare member based on name against a string.
1161         This method is for convenience by VkStruct, which holds a number of members and needs quick checking
1162         if certain members exist.
1163         """
1165         return self.name == other
1167     def __repr__(self):
1168         return "{0} {1} {2} {3} {4} {5} {6}".format(self.const, self.struct_fwd_decl, self.type, self.pointer,
1169                 self.name, self.array_len, self.dyn_array_len)
1171     @staticmethod
1172     def from_xml(member):
1173         """ Helper function for parsing a member tag within a struct or union. """
1175         name_elem = member.find("name")
1176         type_elem = member.find("type")
1178         const = False
1179         struct_fwd_decl = False
1180         member_type = None
1181         pointer = None
1182         array_len = None
1183         bit_width = None
1185         values = member.get("values")
1187         if member.text:
1188             if "const" in member.text:
1189                 const = True
1191             # Some members contain forward declarations:
1192             # - VkBaseInstructure has a member "const struct VkBaseInStructure *pNext"
1193             # - VkWaylandSurfaceCreateInfoKHR has a member "struct wl_display *display"
1194             if "struct" in member.text:
1195                 struct_fwd_decl = True
1197         if type_elem is not None:
1198             member_type = type_elem.text
1199             if type_elem.tail is not None:
1200                 pointer = type_elem.tail.strip() if type_elem.tail.strip() != "" else None
1202         # Name of other member within, which stores the number of
1203         # elements pointed to be by this member.
1204         dyn_array_len = member.get("len")
1206         # Some members are optional, which is important for conversion code e.g. not dereference NULL pointer.
1207         optional = True if member.get("optional") else False
1209         # Usually we need to allocate memory for dynamic arrays. We need to do the same in a few other cases
1210         # like for VkCommandBufferBeginInfo.pInheritanceInfo. Just threat such cases as dynamic arrays of
1211         # size 1 to simplify code generation.
1212         if dyn_array_len is None and pointer is not None:
1213             dyn_array_len = 1
1215         # Some members are arrays, attempt to parse these. Formats include:
1216         # <member><type>char</type><name>extensionName</name>[<enum>VK_MAX_EXTENSION_NAME_SIZE</enum>]</member>
1217         # <member><type>uint32_t</type><name>foo</name>[4]</member>
1218         if name_elem.tail and name_elem.tail[0] == '[':
1219             LOGGER.debug("Found array type")
1220             enum_elem = member.find("enum")
1221             if enum_elem is not None:
1222                 array_len = enum_elem.text
1223             else:
1224                 # Remove brackets around length
1225                 array_len = name_elem.tail.strip("[]")
1227         object_type = member.get("objecttype", None)
1229         # Some members are bit field values:
1230         # <member><type>uint32_t</type> <name>mask</name>:8</member>
1231         if name_elem.tail and name_elem.tail[0] == ':':
1232             LOGGER.debug("Found bit field")
1233             bit_width = int(name_elem.tail[1:])
1235         return VkMember(const=const, struct_fwd_decl=struct_fwd_decl, _type=member_type, pointer=pointer, name=name_elem.text,
1236                 array_len=array_len, dyn_array_len=dyn_array_len, optional=optional, values=values, object_type=object_type, bit_width=bit_width)
1238     def copy(self, input, output, direction, conv):
1239         """ Helper method for use by conversion logic to generate a C-code statement to copy this member.
1240             - `conv` indicates whether the statement is in a struct alignment conversion path. """
1242         if (conv and self.needs_conversion()) or self.needs_unwrapping():
1243             if self.is_dynamic_array():
1244                 if direction == Direction.OUTPUT:
1245                     LOGGER.warn("TODO: implement copying of returnedonly dynamic array for {0}.{1}".format(self.type, self.name))
1246                 else:
1247                     # Array length is either a variable name (string) or an int.
1248                     count = self.dyn_array_len if isinstance(self.dyn_array_len, int) else "{0}{1}".format(input, self.dyn_array_len)
1249                     return "{0}{1} = convert_{2}_array_win_to_host({3}{1}, {4});\n".format(output, self.name, self.type, input, count)
1250             elif self.is_static_array():
1251                 count = self.array_len
1252                 if direction == Direction.OUTPUT:
1253                     # Needed by VkMemoryHeap.memoryHeaps
1254                     return "convert_{0}_static_array_host_to_win({2}{1}, {3}{1}, {4});\n".format(self.type, self.name, input, output, count)
1255                 else:
1256                     # Nothing needed this yet.
1257                     LOGGER.warn("TODO: implement copying of static array for {0}.{1}".format(self.type, self.name))
1258             elif self.is_handle() and self.needs_unwrapping():
1259                 if direction == Direction.OUTPUT:
1260                     LOGGER.err("OUTPUT parameter {0}.{1} cannot be unwrapped".format(self.type, self.name))
1261                 else:
1262                     handle = self.type_info["data"]
1263                     return "{0}{1} = {2};\n".format(output, self.name, handle.driver_handle("{0}{1}".format(input, self.name)))
1264             elif self.is_generic_handle():
1265                 if direction == Direction.OUTPUT:
1266                     LOGGER.err("OUTPUT parameter {0}.{1} cannot be unwrapped".format(self.type, self.name))
1267                 else:
1268                     return "{0}{1} = wine_vk_unwrap_handle({2}{3}, {2}{1});\n".format(output, self.name, input, self.object_type)
1269             else:
1270                 if direction == Direction.OUTPUT:
1271                     return "convert_{0}_host_to_win(&{2}{1}, &{3}{1});\n".format(self.type, self.name, input, output)
1272                 else:
1273                     return "convert_{0}_win_to_host(&{2}{1}, &{3}{1});\n".format(self.type, self.name, input, output)
1274         elif self.is_static_array():
1275             bytes_count = "{0} * sizeof({1})".format(self.array_len, self.type)
1276             return "memcpy({0}{1}, {2}{1}, {3});\n".format(output, self.name, input, bytes_count)
1277         else:
1278             return "{0}{1} = {2}{1};\n".format(output, self.name, input)
1280     def free(self, location, conv):
1281         """ Helper method for use by conversion logic to generate a C-code statement to free this member. """
1283         if not self.needs_unwrapping() and not conv:
1284             return ""
1286         # Add a cast to ignore const on conversion structs we allocated ourselves.
1287         # sample expected output: (VkSparseMemoryBind_host *)
1288         if self.is_const():
1289             cast = "(" + self.type
1290             if self.needs_conversion() and conv:
1291                 cast += "_host"
1292             cast += " *)"
1293         else:
1294             cast = ""
1296         if self.is_dynamic_array():
1297             count = self.dyn_array_len if isinstance(self.dyn_array_len, int) else "{0}{1}".format(location, self.dyn_array_len)
1298             if self.is_struct() and self.type_info["data"].returnedonly:
1299                 # For returnedonly, counts is stored in a pointer.
1300                 return "free_{0}_array({1}{2}{3}, *{4});\n".format(self.type, cast, location, self.name, count)
1301             else:
1302                 return "free_{0}_array({1}{2}{3}, {4});\n".format(self.type, cast, location, self.name, count)
1303         else:
1304             # We are operating on a single structure. Some structs (very rare) contain dynamic members,
1305             # which would need freeing.
1306             if self.needs_free():
1307                 return "free_{0}({1}&{2}{3});\n".format(self.type, cast, location, self.name)
1308         return ""
1310     def definition(self, align=False, conv=False):
1311         """ Generate prototype for given function.
1313         Args:
1314             align (bool, optional): Enable alignment if a type needs it. This adds WINE_VK_ALIGN(8) to a member.
1315             conv (bool, optional): Enable conversion if a type needs it. This appends '_host' to the name.
1316         """
1318         text = ""
1319         if self.is_const():
1320             text += "const "
1322         if self.is_struct_forward_declaration():
1323             text += "struct "
1325         if conv and self.is_struct():
1326             text += "{0}_host".format(self.type)
1327         else:
1328             text += self.type
1330         if self.is_pointer():
1331             text += " {0}{1}".format(self.pointer, self.name)
1332         else:
1333             if align and self.needs_alignment():
1334                 text += " WINE_VK_ALIGN(8) " + self.name
1335             else:
1336                 text += " " + self.name
1338         if self.is_static_array():
1339             text += "[{0}]".format(self.array_len)
1341         if self.is_bit_field():
1342             text += ":{}".format(self.bit_width)
1344         return text
1346     def get_conversions(self):
1347         """ Return any conversion description for this member and its children when conversion is needed. """
1349         # Check if we need conversion either for this member itself or for any child members
1350         # in case member represents a struct.
1351         if not self.needs_conversion() and not self.needs_unwrapping():
1352             return None
1354         conversions = []
1356         # Collect any conversion for any member structs.
1357         if self.is_struct():
1358             struct = self.type_info["data"]
1359             for m in struct:
1360                 m.needs_struct_extensions_conversion()
1361                 if m.needs_conversion() or m.needs_unwrapping():
1362                     conversions.extend(m.get_conversions())
1364             struct.needs_struct_extensions_conversion()
1365             direction = Direction.OUTPUT if struct.returnedonly else Direction.INPUT
1366         elif self.is_handle() or self.is_generic_handle():
1367             direction = Direction.INPUT
1369         operand = self.type_info["data"]
1370         if self.is_dynamic_array():
1371             conversions.append(ConversionFunction(False, True, direction, operand))
1372         elif self.is_static_array():
1373             conversions.append(ConversionFunction(True, False, direction, operand))
1374         else:
1375             conversions.append(ConversionFunction(False, False, direction, operand))
1377         if self.needs_free():
1378             conversions.append(FreeFunction(self.is_dynamic_array(), operand))
1380         return conversions
1382     def is_const(self):
1383         return self.const
1385     def is_dynamic_array(self):
1386         """ Returns if the member is an array element.
1387         Vulkan uses this for dynamically sized arrays for which
1388         there is a 'count' parameter.
1389         """
1390         return self.dyn_array_len is not None
1392     def is_handle(self):
1393         return self.type_info["category"] == "handle"
1395     def is_pointer(self):
1396         return self.pointer is not None
1398     def is_static_array(self):
1399         """ Returns if the member is an array.
1400         Vulkan uses this often for fixed size arrays in which the
1401         length is part of the member.
1402         """
1403         return self.array_len is not None
1405     def is_struct(self):
1406         return self.type_info["category"] == "struct"
1408     def is_struct_forward_declaration(self):
1409         return self.struct_fwd_decl
1411     def is_union(self):
1412         return self.type_info["category"] == "union"
1414     def is_generic_handle(self):
1415         """ Returns True if the member is a unit64_t containing
1416         a handle with a separate object type
1417         """
1419         return self.object_type != None and self.type == "uint64_t"
1421     def is_bit_field(self):
1422         return self.bit_width is not None
1424     def needs_alignment(self):
1425         """ Check if this member needs alignment for 64-bit data.
1426         Various structures need alignment on 64-bit variables due
1427         to compiler differences on 32-bit between Win32 and Linux.
1428         """
1430         if self.is_pointer():
1431             return False
1432         elif self.type == "size_t":
1433             return False
1434         elif self.type in ["uint64_t", "VkDeviceSize"]:
1435             return True
1436         elif self.is_struct():
1437             struct = self.type_info["data"]
1438             return struct.needs_alignment()
1439         elif self.is_handle():
1440             # Dispatchable handles are pointers to objects, while
1441             # non-dispatchable are uint64_t and hence need alignment.
1442             handle = self.type_info["data"]
1443             return False if handle.is_dispatchable() else True
1444         return False
1446     def needs_conversion(self):
1447         """ Structures requiring alignment, need conversion between win32 and host. """
1449         if not self.is_struct():
1450             return False
1452         struct = self.type_info["data"]
1453         return struct.needs_conversion()
1455     def needs_unwrapping(self):
1456         """ Structures with wrapped handles need unwrapping. """
1458         if self.is_struct():
1459             struct = self.type_info["data"]
1460             return struct.needs_unwrapping()
1462         if self.is_handle():
1463             handle = self.type_info["data"]
1464             return handle.is_wrapped()
1466         if self.is_generic_handle():
1467             return True
1469         return False
1471     def needs_free(self):
1472         if not self.needs_conversion() and not self.needs_unwrapping():
1473             return False
1475         if self.is_dynamic_array():
1476             return True
1478         # TODO: some non-pointer structs and optional pointer structs may need freeing,
1479         # though none of this type have been encountered yet.
1480         return False
1482     def needs_struct_extensions_conversion(self):
1483         if not self.is_struct():
1484             return False
1486         struct = self.type_info["data"]
1487         return struct.needs_struct_extensions_conversion()
1489     def set_type_info(self, type_info):
1490         """ Helper function to set type information from the type registry.
1491         This is needed, because not all type data is available at time of
1492         parsing.
1493         """
1494         self.type_info = type_info
1497 class VkParam(object):
1498     """ Helper class which describes a parameter to a function call. """
1500     def __init__(self, type_info, const=None, pointer=None, name=None, array_len=None, dyn_array_len=None, object_type=None):
1501         self.const = const
1502         self.name = name
1503         self.array_len = array_len
1504         self.dyn_array_len = dyn_array_len
1505         self.pointer = pointer
1506         self.object_type = object_type
1507         self.type_info = type_info
1508         self.type = type_info["name"] # For convenience
1509         self.handle = type_info["data"] if type_info["category"] == "handle" else None
1510         self.struct = type_info["data"] if type_info["category"] == "struct" else None
1512         self._set_direction()
1513         self._set_format_string()
1514         self._set_conversions()
1516     def __repr__(self):
1517         return "{0} {1} {2} {3} {4} {5}".format(self.const, self.type, self.pointer, self.name, self.array_len, self.dyn_array_len)
1519     @staticmethod
1520     def from_xml(param, types):
1521         """ Helper function to create VkParam from xml. """
1523         # Parameter parsing is slightly tricky. All the data is contained within
1524         # a param tag, but some data is within subtags while others are text
1525         # before or after the type tag.
1526         # Common structure:
1527         # <param>const <type>char</type>* <name>pLayerName</name></param>
1529         name_elem = param.find("name")
1530         array_len = None
1531         name = name_elem.text
1532         # Tail contains array length e.g. for blendConstants param of vkSetBlendConstants
1533         if name_elem.tail is not None:
1534             array_len = name_elem.tail.strip("[]")
1536         # Name of other parameter in function prototype, which stores the number of
1537         # elements pointed to be by this parameter.
1538         dyn_array_len = param.get("len", None)
1540         const = param.text.strip() if param.text else None
1541         type_elem = param.find("type")
1542         pointer = type_elem.tail.strip() if type_elem.tail.strip() != "" else None
1544         # Some uint64_t are actually handles with a separate type param
1545         object_type = param.get("objecttype", None)
1547         # Since we have parsed all types before hand, this should not happen.
1548         type_info = types.get(type_elem.text, None)
1549         if type_info is None:
1550             LOGGER.err("type info not found for: {0}".format(type_elem.text))
1552         return VkParam(type_info, const=const, pointer=pointer, name=name, array_len=array_len, dyn_array_len=dyn_array_len, object_type=object_type)
1554     def _set_conversions(self):
1555         """ Internal helper function to configure any needed conversion functions. """
1557         self.free_func = None
1558         self.input_conv = None
1559         self.output_conv = None
1560         if not self.needs_conversion() and not self.needs_unwrapping():
1561             return
1563         operand = self.struct if self.is_struct() else self.handle
1565         # Input functions require win to host conversion.
1566         if self._direction in [Direction.INPUT, Direction.INPUT_OUTPUT]:
1567             self.input_conv = ConversionFunction(False, self.is_dynamic_array(), Direction.INPUT, operand)
1569         # Output functions require host to win conversion.
1570         if self._direction in [Direction.INPUT_OUTPUT, Direction.OUTPUT]:
1571             self.output_conv = ConversionFunction(False, self.is_dynamic_array(), Direction.OUTPUT, operand)
1573         # Dynamic arrays, but also some normal structs (e.g. VkCommandBufferBeginInfo) need memory
1574         # allocation and thus some cleanup.
1575         if self.is_dynamic_array() or self.struct.needs_free():
1576             self.free_func = FreeFunction(self.is_dynamic_array(), operand)
1578     def _set_direction(self):
1579         """ Internal helper function to set parameter direction (input/output/input_output). """
1581         # The parameter direction needs to be determined from hints in vk.xml like returnedonly,
1582         # parameter constness and other heuristics.
1583         # For now we need to get this right for structures as we need to convert these, we may have
1584         # missed a few other edge cases (e.g. count variables).
1585         # See also https://github.com/KhronosGroup/Vulkan-Docs/issues/610
1587         if not self.is_pointer():
1588             self._direction = Direction.INPUT
1589         elif self.is_const() and self.is_pointer():
1590             self._direction = Direction.INPUT
1591         elif self.is_struct():
1592             if not self.struct.returnedonly:
1593                 self._direction = Direction.INPUT
1594                 return
1596             # Returnedonly hints towards output, however in some cases
1597             # it is inputoutput. In particular if pNext / sType exist,
1598             # which are used to link in other structures without having
1599             # to introduce new APIs. E.g. vkGetPhysicalDeviceProperties2KHR.
1600             if "pNext" in self.struct:
1601                 self._direction = Direction.INPUT_OUTPUT
1602                 return
1604             self._direction = Direction.OUTPUT
1605         else:
1606             # This should mostly be right. Count variables can be inout, but we don't care about these yet.
1607             self._direction = Direction.OUTPUT
1609     def _set_format_string(self):
1610         """ Internal helper function to be used by constructor to set format string. """
1612         # Determine a format string used by code generation for traces.
1613         # 64-bit types need a conversion function.
1614         self.format_conv = None
1615         if self.is_static_array() or self.is_pointer():
1616             self.format_str = "%p"
1617         else:
1618             if self.type_info["category"] in ["bitmask"]:
1619                 # Since 1.2.170 bitmasks can be 32 or 64-bit, check the basetype.
1620                 if self.type_info["data"].type == "VkFlags64":
1621                     self.format_str = "0x%s"
1622                     self.format_conv = "wine_dbgstr_longlong({0})"
1623                 else:
1624                     self.format_str = "%#x"
1625             elif self.type_info["category"] in ["enum"]:
1626                 self.format_str = "%#x"
1627             elif self.is_handle():
1628                 # We use uint64_t for non-dispatchable handles as opposed to pointers
1629                 # for dispatchable handles.
1630                 if self.handle.is_dispatchable():
1631                     self.format_str = "%p"
1632                 else:
1633                     self.format_str = "0x%s"
1634                     self.format_conv = "wine_dbgstr_longlong({0})"
1635             elif self.type == "float":
1636                 self.format_str = "%f"
1637             elif self.type == "int":
1638                 self.format_str = "%d"
1639             elif self.type == "int32_t":
1640                 self.format_str = "%d"
1641             elif self.type == "size_t":
1642                 self.format_str = "0x%s"
1643                 self.format_conv = "wine_dbgstr_longlong({0})"
1644             elif self.type in ["uint16_t", "uint32_t", "VkBool32"]:
1645                 self.format_str = "%u"
1646             elif self.type in ["uint64_t", "VkDeviceAddress", "VkDeviceSize"]:
1647                 self.format_str = "0x%s"
1648                 self.format_conv = "wine_dbgstr_longlong({0})"
1649             elif self.type == "HANDLE":
1650                 self.format_str = "%p"
1651             elif self.type in ["VisualID", "xcb_visualid_t", "RROutput", "zx_handle_t"]:
1652                 # Don't care about specific types for non-Windows platforms.
1653                 self.format_str = ""
1654             else:
1655                 LOGGER.warn("Unhandled type: {0}".format(self.type_info))
1657     def copy(self, direction, prefix=""):
1658         if direction == Direction.INPUT:
1659             if self.is_dynamic_array():
1660                 return "    {1}_host = convert_{2}_array_win_to_host({0}{1}, {0}{3});\n".format(prefix, self.name, self.type, self.dyn_array_len)
1661             else:
1662                 return "    convert_{0}_win_to_host({1}{2}, &{2}_host);\n".format(self.type, prefix, self.name)
1663         else:
1664             if self.is_dynamic_array():
1665                 LOGGER.error("Unimplemented output conversion for: {0}".format(self.name))
1666             else:
1667                 return "    convert_{0}_host_to_win(&{2}_host, {1}{2});\n".format(self.type, prefix, self.name)
1669     def definition(self, postfix=None, is_member=False):
1670         """ Return prototype for the parameter. E.g. 'const char *foo' """
1672         proto = ""
1673         if self.const:
1674             proto += self.const + " "
1676         proto += self.type
1678         if self.is_pointer():
1679             proto += " {0}{1}".format(self.pointer, self.name)
1680         elif is_member and self.is_static_array():
1681             proto += " *" + self.name
1682         else:
1683             proto += " " + self.name
1685         # Allows appending something to the variable name useful for
1686         # win32 to host conversion.
1687         if postfix is not None:
1688             proto += postfix
1690         if not is_member and self.is_static_array():
1691             proto += "[{0}]".format(self.array_len)
1693         return proto
1695     def direction(self):
1696         """ Returns parameter direction: input, output, input_output.
1698         Parameter direction in Vulkan is not straight-forward, which this function determines.
1699         """
1701         return self._direction
1703     def dispatch_table(self):
1704         """ Return functions dispatch table pointer for dispatchable objects. """
1706         if not self.is_dispatchable():
1707             return None
1709         return "{0}->{1}".format(self.name, self.handle.dispatch_table())
1711     def format_string(self):
1712         return self.format_str
1714     def free(self, prefix=""):
1715         if self.is_dynamic_array():
1716             if self.is_struct() and self.struct.returnedonly:
1717                 # For returnedonly, counts is stored in a pointer.
1718                 return "    free_{0}_array({1}_host, *{2}{3});\n".format(self.type, self.name, prefix, self.dyn_array_len)
1719             else:
1720                 return "    free_{0}_array({1}_host, {2}{3});\n".format(self.type, self.name, prefix, self.dyn_array_len)
1721         else:
1722             # We are operating on a single structure. Some structs (very rare) contain dynamic members,
1723             # which would need freeing.
1724             if self.is_struct() and self.struct.needs_free():
1725                 return "    free_{0}(&{1}_host);\n".format(self.type, self.name)
1726         return ""
1728     def get_conversions(self):
1729         """ Get a list of conversions required for this parameter if any.
1730         Parameters which are structures may require conversion between win32
1731         and the host platform. This function returns a list of conversions
1732         required.
1733         """
1735         if self.is_struct():
1736             self.struct.needs_struct_extensions_conversion()
1737             for m in self.struct:
1738                 m.needs_struct_extensions_conversion()
1739         elif not self.is_handle():
1740             return None
1742         if not self.needs_conversion() and not self.needs_unwrapping():
1743             return None
1745         conversions = []
1747         # Collect any member conversions first, so we can guarantee
1748         # those functions will be defined prior to usage by the
1749         # 'parent' param requiring conversion.
1750         if self.is_struct():
1751             for m in self.struct:
1752                 if not m.is_struct():
1753                     continue
1755                 if not m.needs_conversion() and not m.needs_unwrapping():
1756                     continue
1758                 conversions.extend(m.get_conversions())
1760         # Conversion requirements for the 'parent' parameter.
1761         if self.input_conv is not None:
1762             conversions.append(self.input_conv)
1763         if self.output_conv is not None:
1764             conversions.append(self.output_conv)
1765         if self.free_func is not None:
1766             conversions.append(self.free_func)
1768         return conversions
1770     def is_const(self):
1771         return self.const is not None
1773     def is_dynamic_array(self):
1774         return self.dyn_array_len is not None
1776     def is_dispatchable(self):
1777         if not self.is_handle():
1778             return False
1780         return self.handle.is_dispatchable()
1782     def is_handle(self):
1783         return self.handle is not None
1785     def is_pointer(self):
1786         return self.pointer is not None
1788     def is_static_array(self):
1789         return self.array_len is not None
1791     def is_struct(self):
1792         return self.struct is not None
1794     def needs_conversion(self):
1795         """ Returns if parameter needs conversion between win32 and host. """
1797         if not self.is_struct():
1798             return False
1800         # VkSparseImageMemoryRequirements(2) is used by vkGetImageSparseMemoryRequirements(2).
1801         # This function is tricky to wrap, because how to wrap depends on whether
1802         # pSparseMemoryRequirements is NULL or not. Luckily for VkSparseImageMemoryRequirements(2)
1803         # the alignment works out in such a way that no conversion is needed between win32 and Linux.
1804         if self.type in ["VkSparseImageMemoryRequirements", "VkSparseImageMemoryRequirements2"]:
1805             return False
1807         # If a structure needs alignment changes, it means we need to
1808         # perform parameter conversion between win32 and host.
1809         if self.struct.needs_conversion():
1810             return True
1812         return False
1814     def needs_unwrapping(self):
1815         """ Returns if parameter needs unwrapping of handle. """
1817         # Wrapped handle parameters are handled separately, only look for wrapped handles in structs
1818         if self.is_struct():
1819             return self.struct.needs_unwrapping()
1821         if self.is_handle() and self.is_dynamic_array():
1822             return self.handle.needs_unwrapping()
1824         return False
1826     def needs_free(self):
1827         return self.free_func is not None
1829     def needs_input_conversion(self):
1830         return self.input_conv is not None
1832     def needs_output_conversion(self):
1833         return self.output_conv is not None
1835     def spec(self):
1836         """ Generate spec file entry for this parameter. """
1838         if self.is_pointer() and self.type == "char":
1839             return "str"
1840         if self.is_dispatchable() or self.is_pointer() or self.is_static_array():
1841             return "ptr"
1842         if self.type_info["category"] in ["bitmask"]:
1843             # Since 1.2.170 bitmasks can be 32 or 64-bit, check the basetype.
1844             if self.type_info["data"].type == "VkFlags64":
1845                 return "int64"
1846             else:
1847                 return "long"
1848         if self.type_info["category"] in ["enum"]:
1849             return "long"
1850         if self.is_handle() and not self.is_dispatchable():
1851             return "int64"
1852         if self.type == "float":
1853             return "float"
1854         if self.type in ["int", "int32_t", "size_t", "uint16_t", "uint32_t", "VkBool32"]:
1855             return "long"
1856         if self.type in ["uint64_t", "VkDeviceSize"]:
1857             return "int64"
1859         LOGGER.error("Unhandled spec conversion for type: {0}".format(self.type))
1861     def variable(self, conv=False, params_prefix=""):
1862         """ Returns 'glue' code during generation of a function call on how to access the variable.
1863         This function handles various scenarios such as 'unwrapping' if dispatchable objects and
1864         renaming of parameters in case of win32 -> host conversion.
1866         Args:
1867             conv (bool, optional): Enable conversion if the param needs it. This appends '_host' to the name.
1868         """
1870         # Hack until we enable allocation callbacks from ICD to application. These are a joy
1871         # to enable one day, because of calling convention conversion.
1872         if "VkAllocationCallbacks" in self.type:
1873             LOGGER.debug("TODO: setting NULL VkAllocationCallbacks for {0}".format(self.name))
1874             return "NULL"
1876         if self.needs_unwrapping() or (conv and self.needs_conversion()):
1877             if self.is_dynamic_array():
1878                 return "{0}_host".format(self.name)
1879             else:
1880                 return "&{0}_host".format(self.name)
1881         else:
1882             if self.object_type != None and self.type == "uint64_t":
1883                 return "wine_vk_unwrap_handle({0}{1}, {0}{2})".format(params_prefix, self.object_type, self.name)
1885             # We need to pass the native handle to the native Vulkan calls and
1886             # the wine driver's handle to calls which are wrapped by the driver.
1887             p = "{0}{1}".format(params_prefix, self.name)
1888             driver_handle = self.handle.driver_handle(p) if self.is_handle() else None
1889             return driver_handle if driver_handle else p
1892 class VkStruct(Sequence):
1893     """ Class which represents the type union and struct. """
1895     def __init__(self, name, members, returnedonly, structextends, alias=None, union=False):
1896         self.name = name
1897         self.members = members
1898         self.returnedonly = returnedonly
1899         self.structextends = structextends
1900         self.required = False
1901         self.alias = alias
1902         self.union = union
1903         self.type_info = None # To be set later.
1904         self.struct_extensions = []
1905         self.aliased_by = []
1907     def __getitem__(self, i):
1908         return self.members[i]
1910     def __len__(self):
1911         return len(self.members)
1913     @staticmethod
1914     def from_alias(struct, alias):
1915         name = struct.attrib.get("name")
1916         aliasee = VkStruct(name, alias.members, alias.returnedonly, alias.structextends, alias=alias)
1918         alias.add_aliased_by(aliasee)
1919         return aliasee
1921     @staticmethod
1922     def from_xml(struct):
1923         # Unions and structs are the same parsing wise, but we need to
1924         # know which one we are dealing with later on for code generation.
1925         union = True if struct.attrib["category"] == "union" else False
1927         name = struct.attrib.get("name")
1929         # 'Output' structures for which data is filled in by the API are
1930         # marked as 'returnedonly'.
1931         returnedonly = True if struct.attrib.get("returnedonly") else False
1933         structextends = struct.attrib.get("structextends")
1934         structextends = structextends.split(",") if structextends else []
1936         members = []
1937         for member in struct.findall("member"):
1938             vk_member = VkMember.from_xml(member)
1939             members.append(vk_member)
1941         return VkStruct(name, members, returnedonly, structextends, union=union)
1943     @staticmethod
1944     def decouple_structs(structs):
1945         """ Helper function which decouples a list of structs.
1946         Structures often depend on other structures. To make the C compiler
1947         happy we need to define 'substructures' first. This function analyzes
1948         the list of structures and reorders them in such a way that they are
1949         decoupled.
1950         """
1952         tmp_structs = list(structs) # Don't modify the original structures.
1953         decoupled_structs = []
1955         while (len(tmp_structs) > 0):
1956             # Iterate over a copy because we want to modify the list inside the loop.
1957             for struct in list(tmp_structs):
1958                 dependends = False
1960                 if not struct.required:
1961                     tmp_structs.remove(struct)
1962                     continue
1964                 for m in struct:
1965                     if not (m.is_struct() or m.is_union()):
1966                         continue
1968                     # VkBaseInstructure and VkBaseOutStructure reference themselves.
1969                     if m.type == struct.name:
1970                         break
1972                     found = False
1973                     # Check if a struct we depend on has already been defined.
1974                     for s in decoupled_structs:
1975                         if s.name == m.type:
1976                             found = True
1977                             break
1979                     if not found:
1980                         # Check if the struct we depend on is even in the list of structs.
1981                         # If found now, it means we haven't met all dependencies before we
1982                         # can operate on the current struct.
1983                         # When generating 'host' structs we may not be able to find a struct
1984                         # as the list would only contain the structs requiring conversion.
1985                         for s in tmp_structs:
1986                             if s.name == m.type:
1987                                 dependends = True
1988                                 break
1990                 if dependends == False:
1991                     decoupled_structs.append(struct)
1992                     tmp_structs.remove(struct)
1994         return decoupled_structs
1996     def definition(self, align=False, conv=False, postfix=None):
1997         """ Convert structure to textual definition.
1999         Args:
2000             align (bool, optional): enable alignment to 64-bit for win32 struct compatibility.
2001             conv (bool, optional): enable struct conversion if the struct needs it.
2002             postfix (str, optional): text to append to end of struct name, useful for struct renaming.
2003         """
2005         # Only define alias structs when doing conversions
2006         if self.is_alias() and not conv:
2007             return ""
2009         if self.union:
2010             text = "typedef union {0}".format(self.name)
2011         else:
2012             text = "typedef struct {0}".format(self.name)
2014         if postfix is not None:
2015             text += postfix
2017         text += "\n{\n"
2019         for m in self:
2020             if align and m.needs_alignment():
2021                 text += "    {0};\n".format(m.definition(align=align))
2022             elif conv and m.needs_conversion():
2023                 text += "    {0};\n".format(m.definition(conv=conv))
2024             else:
2025                 text += "    {0};\n".format(m.definition())
2027         if postfix is not None:
2028             text += "}} {0}{1};\n".format(self.name, postfix)
2029         else:
2030             text += "}} {0};\n".format(self.name)
2032         for aliasee in self.aliased_by:
2033             text += "typedef {0} {1};\n".format(self.name, aliasee.name)
2035         return text
2037     def is_alias(self):
2038         return bool(self.alias)
2040     def add_aliased_by(self, aliasee):
2041         self.aliased_by.append(aliasee)
2043     def needs_alignment(self):
2044         """ Check if structure needs alignment for 64-bit data.
2045         Various structures need alignment on 64-bit variables due
2046         to compiler differences on 32-bit between Win32 and Linux.
2047         """
2049         for m in self.members:
2050             if self.name == m.type:
2051                 continue
2052             if m.needs_alignment():
2053                 return True
2054         return False
2056     def needs_conversion(self):
2057         """ Returns if struct members needs conversion between win32 and host.
2058         Structures need conversion if they contain members requiring alignment
2059         or if they include other structures which need alignment.
2060         """
2062         if self.needs_alignment():
2063             return True
2065         for m in self.members:
2066             if self.name == m.type:
2067                 continue
2068             if m.needs_conversion():
2069                 return True
2070         return False
2072     def needs_unwrapping(self):
2073         """ Returns if struct members need unwrapping of handle. """
2075         for m in self.members:
2076             if self.name == m.type:
2077                 continue
2078             if m.needs_unwrapping():
2079                 return True
2080         return False
2082     def needs_free(self):
2083         """ Check if any struct member needs some memory freeing."""
2085         for m in self.members:
2086             if self.name == m.type:
2087                 continue
2088             if m.needs_free():
2089                 return True
2091         return False
2093     def needs_struct_extensions_conversion(self):
2094         """ Checks if structure extensions in pNext chain need conversion. """
2095         ret = False
2097         for e in self.struct_extensions:
2098             if e.required and e.needs_conversion():
2099                 LOGGER.error("Unhandled pNext chain alignment conversion for {0}".format(e.name))
2100                 ret = True
2101             if e.required and e.needs_unwrapping():
2102                 LOGGER.error("Unhandled pNext chain unwrapping conversion for {0}".format(e.name))
2103                 ret = True
2105         return ret
2107     def set_type_info(self, types):
2108         """ Helper function to set type information from the type registry.
2109         This is needed, because not all type data is available at time of
2110         parsing.
2111         """
2112         for m in self.members:
2113             type_info = types[m.type]
2114             m.set_type_info(type_info)
2117 class ConversionFunction(object):
2118     def __init__(self, array, dyn_array, direction, operand):
2119         self.array = array
2120         self.direction = direction
2121         self.dyn_array = dyn_array
2122         self.operand = operand
2123         self.type = operand.name
2125         self._set_name()
2127     def __eq__(self, other):
2128         return self.name == other.name
2130     def _generate_array_conversion_func(self):
2131         """ Helper function for generating a conversion function for array operands. """
2133         body = ""
2135         if self.operand.needs_conversion():
2136             body += "#if defined(USE_STRUCT_CONVERSION)\n"
2138             if self.direction == Direction.OUTPUT:
2139                 params = ["const {0}_host *in".format(self.type), "uint32_t count"]
2140                 return_type = self.type
2141             else:
2142                 params = ["const {0} *in".format(self.type), "uint32_t count"]
2143                 return_type = "{0}_host".format(self.type)
2145             # Generate function prototype.
2146             body += "static inline {0} *{1}(".format(return_type, self.name)
2147             body += ", ".join(p for p in params)
2148             body += ")\n{\n"
2150             body += "    {0} *out;\n".format(return_type)
2152         if self.operand.needs_unwrapping():
2153             if self.operand.needs_conversion():
2154                 body += "#else\n"
2156             params = ["const {0} *in".format(self.type), "uint32_t count"]
2157             return_type = "{0}".format(self.type)
2159             # Generate function prototype.
2160             body += "static inline {0} *{1}(".format(return_type, self.name)
2161             body += ", ".join(p for p in params)
2162             body += ")\n{\n"
2164             body += "    {0} *out;\n".format(return_type)
2166             if self.operand.needs_conversion():
2167                 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2169         body += "    unsigned int i;\n\n"
2170         body += "    if (!in || !count) return NULL;\n\n"
2172         body += "    out = malloc(count * sizeof(*out));\n"
2174         body += "    for (i = 0; i < count; i++)\n"
2175         body += "    {\n"
2177         if isinstance(self.operand, VkStruct):
2178             for m in self.operand:
2179                 # TODO: support copying of pNext extension structures!
2180                 # Luckily though no extension struct at this point needs conversion.
2181                 convert = m.copy("in[i].", "out[i].", self.direction, conv=True)
2182                 if self.operand.needs_conversion() and not self.operand.needs_unwrapping():
2183                     body += "        " + convert
2184                 else:
2185                     unwrap = m.copy("in[i].", "out[i].", self.direction, conv=False)
2186                     if unwrap == convert:
2187                         body += "        " + unwrap
2188                     else:
2189                         body += "#if defined(USE_STRUCT_CONVERSION)\n"
2190                         body += "        " + convert
2191                         body += "#else\n"
2192                         body += "        " + unwrap
2193                         body += "#endif /* USE_STRUCT_CONVERSION */\n"
2195         elif isinstance(self.operand, VkHandle) and self.direction == Direction.INPUT:
2196             body += "        out[i] = " + self.operand.driver_handle("in[i]") + ";\n"
2197         else:
2198             LOGGER.warn("Unhandled conversion operand type")
2199             body += "        out[i] = in[i];\n"
2201         body += "    }\n\n"
2202         body += "    return out;\n"
2203         body += "}\n"
2205         if not self.operand.needs_unwrapping():
2206             body += "#endif /* USE_STRUCT_CONVERSION */\n"
2208         body += "\n"
2210         return body
2212     def _generate_conversion_func(self):
2213         """ Helper function for generating a conversion function for non-array operands. """
2215         # It doesn't make sense to generate conversion functions for non-struct variables
2216         # which aren't in arrays, as this should be handled by the copy() function
2217         if not isinstance(self.operand, VkStruct):
2218             return ""
2220         body = ""
2222         if self.operand.needs_conversion():
2223             body += "#if defined(USE_STRUCT_CONVERSION)\n"
2224             body += "static inline void {0}(".format(self.name)
2226             if self.direction == Direction.OUTPUT:
2227                 params = ["const {0}_host *in".format(self.type), "{0} *out".format(self.type)]
2228             else:
2229                 params = ["const {0} *in".format(self.type), "{0}_host *out".format(self.type)]
2231             # Generate parameter list
2232             body += ", ".join(p for p in params)
2233             body += ")\n"
2235         if self.operand.needs_unwrapping():
2236             if self.operand.needs_conversion():
2237                 body += "#else\n"
2239             body += "static inline void {0}(".format(self.name)
2241             params = ["const {0} *in".format(self.type), "{0} *out".format(self.type)]
2243             # Generate parameter list
2244             body += ", ".join(p for p in params)
2245             body += ")\n"
2247             if self.operand.needs_conversion():
2248                 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2250         body += "{\n    if (!in) return;\n\n"
2252         if self.direction == Direction.INPUT and "pNext" in self.operand and self.operand.returnedonly:
2253             # We are dealing with an input_output parameter. For these we only need to copy
2254             # pNext and sType as the other fields are filled in by the host. We do potentially
2255             # have to iterate over pNext and perform conversions based on switch(sType)!
2256             # Luckily though no extension structs at this point need conversion.
2257             # TODO: support copying of pNext extension structures!
2258             body += "    out->pNext = in->pNext;\n"
2259             body += "    out->sType = in->sType;\n"
2260         else:
2261             for m in self.operand:
2262                 # TODO: support copying of pNext extension structures!
2263                 convert = m.copy("in->", "out->", self.direction, conv=True)
2264                 if self.operand.needs_conversion() and not self.operand.needs_unwrapping():
2265                     body += "    " + convert
2266                 else:
2267                     unwrap = m.copy("in->", "out->", self.direction, conv=False)
2268                     if unwrap == convert:
2269                         body += "    " + unwrap
2270                     else:
2271                         body += "#if defined(USE_STRUCT_CONVERSION)\n"
2272                         body += "    " + convert
2273                         body += "#else\n"
2274                         body += "    " + unwrap
2275                         body += "#endif /* USE_STRUCT_CONVERSION */\n"
2277         body += "}\n"
2279         if not self.operand.needs_unwrapping():
2280             body += "#endif /* USE_STRUCT_CONVERSION */\n"
2282         body += "\n"
2284         return body
2286     def _generate_static_array_conversion_func(self):
2287         """ Helper function for generating a conversion function for array operands. """
2289         body = ""
2291         if self.operand.needs_conversion():
2292             body += "#if defined(USE_STRUCT_CONVERSION)\n"
2294             if self.direction == Direction.OUTPUT:
2295                 params = ["const {0}_host *in".format(self.type), "{0} *out".format(self.type), "uint32_t count"]
2296             else:
2297                 params = ["const {0} *in".format(self.type), "{0} *out_host".format(self.type), "uint32_t count"]
2299             # Generate function prototype.
2300             body += "static inline void {0}(".format(self.name)
2301             body += ", ".join(p for p in params)
2302             body += ")\n"
2304         if self.operand.needs_unwrapping():
2305             if self.operand.needs_conversion():
2306                 body += "#else\n"
2308             params = ["const {0} *in".format(self.type), "{0} *out".format(self.type), "uint32_t count"]
2310             # Generate function prototype.
2311             body += "static inline void {0}(".format(self.name)
2312             body += ", ".join(p for p in params)
2313             body += ")\n"
2315         body += "{\n"
2316         body += "    unsigned int i;\n\n"
2317         body += "    if (!in) return;\n\n"
2318         body += "    for (i = 0; i < count; i++)\n"
2319         body += "    {\n"
2321         if isinstance(self.operand, VkStruct):
2322             for m in self.operand:
2323                 # TODO: support copying of pNext extension structures!
2324                 convert = m.copy("in[i].", "out[i].", self.direction, conv=True)
2325                 if self.operand.needs_conversion() and not self.operand.needs_unwrapping():
2326                     body += "        " + convert
2327                 else:
2328                     unwrap = m.copy("in[i].", "out[i].", self.direction, conv=False)
2329                     if unwrap == convert:
2330                         body += "        " + unwrap
2331                     else:
2332                         body += "#if defined(USE_STRUCT_CONVERSION)\n"
2333                         body += "    " + convert
2334                         body += "#else\n"
2335                         body += "    " + unwrap
2336                         body += "#endif /* USE_STRUCT_CONVERSION */\n"
2337         elif isinstance(self.operand, VkHandle) and self.direction == Direction.INPUT:
2338             body += "        out[i] = " + self.operand.driver_handle("in[i]") + ";\n"
2339         else:
2340             LOGGER.warn("Unhandled conversion operand type")
2341             body += "        out[i] = in[i];\n"
2343         body += "    }\n"
2344         body += "}\n"
2346         if not self.operand.needs_unwrapping():
2347             body += "#endif /* USE_STRUCT_CONVERSION) */\n"
2349         body += "\n"
2351         return body
2353     def _set_name(self):
2354         if self.direction == Direction.INPUT:
2355             if self.array:
2356                 name = "convert_{0}_static_array_win_to_host".format(self.type)
2357             elif self.dyn_array:
2358                 name = "convert_{0}_array_win_to_host".format(self.type)
2359             else:
2360                 name = "convert_{0}_win_to_host".format(self.type)
2361         else: # Direction.OUTPUT
2362             if self.array:
2363                 name = "convert_{0}_static_array_host_to_win".format(self.type)
2364             elif self.dyn_array:
2365                 name = "convert_{0}_array_host_to_win".format(self.type)
2366             else:
2367                 name = "convert_{0}_host_to_win".format(self.type)
2369         self.name = name
2371     def definition(self):
2372         if self.array:
2373             return self._generate_static_array_conversion_func()
2374         elif self.dyn_array:
2375             return self._generate_array_conversion_func()
2376         else:
2377             return self._generate_conversion_func()
2380 class FreeFunction(object):
2381     def __init__(self, dyn_array, operand):
2382         self.dyn_array = dyn_array
2383         self.operand = operand
2384         self.type = operand.name
2386         if dyn_array:
2387             self.name = "free_{0}_array".format(self.type)
2388         else:
2389             self.name = "free_{0}".format(self.type)
2391     def __eq__(self, other):
2392         return self.name == other.name
2394     def _generate_array_free_func(self):
2395         """ Helper function for cleaning up temporary buffers required for array conversions. """
2397         body = ""
2399         if self.operand.needs_conversion():
2400             body += "#if defined(USE_STRUCT_CONVERSION)\n"
2401             # Generate function prototype.
2402             body += "static inline void {0}({1}_host *in, uint32_t count)\n".format(self.name, self.type)
2404         if self.operand.needs_unwrapping():
2405             if self.operand.needs_conversion():
2406                 body += "#else\n"
2408             # Generate function prototype.
2409             body += "static inline void {0}({1} *in, uint32_t count)\n".format(self.name, self.type)
2411             if self.operand.needs_conversion():
2412                 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2414         body += "{\n"
2416         # E.g. VkGraphicsPipelineCreateInfo_host needs freeing for pStages.
2417         if isinstance(self.operand, VkStruct) and self.operand.needs_free():
2418             body += "    unsigned int i;\n\n"
2419             body += "    if (!in) return;\n\n"
2420             body += "    for (i = 0; i < count; i++)\n"
2421             body += "    {\n"
2423             for m in self.operand:
2424                 if m.needs_free():
2425                     convert = m.free("in[i].", conv=True)
2426                     if self.operand.needs_conversion() and not self.operand.needs_unwrapping():
2427                         body += "        " + convert
2428                     else:
2429                         unwrap = m.free("in[i].", conv=False)
2430                         if convert == unwrap:
2431                             body += "        " + unwrap
2432                         elif unwrap == "":
2433                             body += "#if defined(USE_STRUCT_CONVERSION)\n"
2434                             body += "        " + convert
2435                             body += "#endif /* USE_STRUCT_CONVERSION */\n"
2436                         else:
2437                             body += "#if defined(USE_STRUCT_CONVERSION)\n"
2438                             body += "        " + convert
2439                             body += "#else\n"
2440                             body += "        " + unwrap
2441                             body += "#endif /* USE_STRUCT_CONVERSION */\n"
2442             body += "    }\n"
2443         else:
2444             body += "    if (!in) return;\n\n"
2446         body += "    free(in);\n"
2448         body += "}\n"
2450         if not self.operand.needs_unwrapping():
2451             body += "#endif /* USE_STRUCT_CONVERSION */\n"
2453         body += "\n"
2455         return body
2457     def _generate_free_func(self):
2458         # E.g. VkCommandBufferBeginInfo.pInheritanceInfo needs freeing.
2459         if not self.operand.needs_free():
2460             return ""
2462         if not isinstance(self.operand, VkStruct):
2463             return ""
2465         body = ""
2467         if self.operand.needs_conversion():
2468             body += "#if defined(USE_STRUCT_CONVERSION)\n"
2469             # Generate function prototype.
2470             body += "static inline void {0}({1}_host *in)\n".format(self.name, self.type)
2472         if self.operand.needs_unwrapping():
2473             if self.operand.needs_conversion():
2474                 body += "#else\n"
2476             # Generate function prototype.
2477             body += "static inline void {0}({1} *in)\n".format(self.name, self.type)
2479             if self.operand.needs_conversion():
2480                 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2482         body += "{\n"
2484         for m in self.operand:
2485             if m.needs_free():
2486                 convert = m.free("in->", conv=True)
2487                 if self.operand.needs_conversion() and not self.operand.needs_unwrapping():
2488                     body += "    " + convert
2489                 else:
2490                     unwrap = m.free("in->", conv=False)
2491                     if convert == unwrap:
2492                         body += "    " + unwrap
2493                     elif unwrap == "":
2494                         body += "#if defined(USE_STRUCT_CONVERSION)\n"
2495                         body += "    " + convert
2496                         body += "#endif /* USE_STRUCT_CONVERSION */\n"
2497                     else:
2498                         body += "#if defined(USE_STRUCT_CONVERSION)\n"
2499                         body += "    " + convert
2500                         body += "#else\n"
2501                         body += "    " + unwrap
2502                         body += "#endif /* USE_STRUCT_CONVERSION */\n"
2504         body += "}\n"
2506         if not self.operand.needs_unwrapping():
2507             body += "#endif /* USE_STRUCT_CONVERSION */\n"
2509         body += "\n"
2511         return body
2513     def definition(self):
2514         if self.dyn_array:
2515             return self._generate_array_free_func()
2516         else:
2517             # Some structures need freeing too if they contain dynamic arrays.
2518             # E.g. VkCommandBufferBeginInfo
2519             return self._generate_free_func()
2522 class StructChainConversionFunction(object):
2523     def __init__(self, direction, struct, ignores):
2524         self.direction = direction
2525         self.struct = struct
2526         self.ignores = ignores
2527         self.type = struct.name
2529         self.name = "convert_{0}_struct_chain".format(self.type)
2531     def __eq__(self, other):
2532         return self.name == other.name
2534     def prototype(self, postfix=""):
2535         return "VkResult {0}(const void *pNext, {1} *out_struct) {2}".format(self.name, self.type, postfix).strip()
2537     def definition(self):
2538         body = self.prototype()
2539         body += "\n{\n"
2541         body += "    VkBaseOutStructure *out_header = (VkBaseOutStructure *)out_struct;\n";
2542         body += "    const VkBaseInStructure *in_header;\n\n";
2544         body += "    out_header->pNext = NULL;\n\n"
2546         body += "    for (in_header = pNext; in_header; in_header = in_header->pNext)\n"
2547         body += "    {\n"
2548         body += "        switch (in_header->sType)\n"
2549         body += "        {\n"
2551         for i in self.ignores:
2552             body += "        case {0}:\n".format(i)
2553         body += "            break;\n\n"
2555         for e in self.struct.struct_extensions:
2556             if not e.required:
2557                 continue
2559             stype = next(x for x in e.members if x.name == "sType")
2561             if stype.values in self.ignores:
2562                 continue
2564             body += "        case {0}:\n".format(stype.values)
2565             body += "        {\n"
2567             body += "            const {0} *in = (const {0} *)in_header;\n".format(e.name)
2568             body += "            {0} *out;\n\n".format(e.name)
2570             body += "            if (!(out = malloc(sizeof(*out)))) goto out_of_memory;\n\n"
2572             for m in e:
2573                 if m.name == "pNext":
2574                     body += "            out->pNext = NULL;\n"
2575                 else:
2576                     convert = m.copy("in->", "out->", self.direction, conv=True)
2577                     unwrap = m.copy("in->", "out->", self.direction, conv=False)
2578                     if unwrap == convert:
2579                         body += "            " + unwrap
2580                     else:
2581                         body += "#if defined(USE_STRUCT_CONVERSION)\n"
2582                         body += "            " + convert
2583                         body += "#else\n"
2584                         body += "            " + unwrap
2585                         body += "#endif /* USE_STRUCT_CONVERSION */\n"
2587             body += "\n            out_header->pNext = (VkBaseOutStructure *)out;\n"
2588             body += "            out_header = out_header->pNext;\n"
2589             body += "            break;\n"
2590             body += "        }\n\n"
2592         body += "        default:\n"
2593         body += "            FIXME(\"Application requested a linked structure of type %u.\\n\", in_header->sType);\n"
2595         body += "        }\n"
2596         body += "    }\n\n"
2598         body += "    return VK_SUCCESS;\n"
2600         if any(x for x in self.struct.struct_extensions if x.required):
2601             body += "\nout_of_memory:\n"
2602             body += "    free_{0}_struct_chain(out_struct);\n".format(self.type)
2603             body += "    return VK_ERROR_OUT_OF_HOST_MEMORY;\n"
2605         body += "}\n\n"
2606         return body
2608 class FreeStructChainFunction(object):
2609     def __init__(self, struct):
2610         self.struct = struct
2611         self.type = struct.name
2613         self.name = "free_{0}_struct_chain".format(self.type)
2615     def __eq__(self, other):
2616         return self.name == other.name
2618     def prototype(self, postfix=""):
2619         return "void {0}({1} *s) {2}".format(self.name, self.type, postfix).strip()
2621     def definition(self):
2622         body = self.prototype()
2623         body += "\n{\n"
2625         body += "    VkBaseOutStructure *header = (void *)s->pNext;\n\n";
2627         body += "    while (header)\n"
2628         body += "    {\n"
2629         body += "        void *prev = header;\n\n"
2630         body += "        switch (header->sType)\n"
2631         body += "        {\n"
2633         for e in self.struct.struct_extensions:
2634             if not e.required:
2635                 continue
2637             if not any(m.needs_free() for m in e):
2638                 continue
2640             stype = next(x for x in e.members if x.name == "sType")
2642             body += "            case {0}:\n".format(stype.values)
2643             body += "            {\n"
2644             body += "                {0} *structure = ({0} *) header;\n".format(e.name)
2646             for m in e:
2647                 if m.needs_free():
2648                     convert = m.free("structure->", conv=True)
2649                     unwrap = m.free("structure->", conv=False)
2650                     if convert == unwrap:
2651                         body += "                " + unwrap
2652                     elif unwrap == "":
2653                         body += "#if defined(USE_STRUCT_CONVERSION)\n"
2654                         body += "                " + convert
2655                         body += "#endif /* USE_STRUCT_CONVERSION */\n"
2656                     else:
2657                         body += "#if defined(USE_STRUCT_CONVERSION)\n"
2658                         body += "                " + convert
2659                         body += "#else\n"
2660                         body += "                " + unwrap
2661                         body += "#endif /* USE_STRUCT_CONVERSION */\n"
2663             body += "                break;\n"
2664             body += "            }\n"
2666         body += "            default:\n"
2667         body += "                break;\n"
2668         body += "        }\n"
2670         body += "        header = header->pNext;\n"
2671         body += "        free(prev);\n"
2672         body += "    }\n\n"
2674         body += "    s->pNext = NULL;\n"
2676         body += "}\n\n"
2677         return body
2680 class VkGenerator(object):
2681     def __init__(self, registry):
2682         self.registry = registry
2684         # Build a list conversion functions for struct conversion.
2685         self.conversions = []
2686         self.struct_chain_conversions = []
2687         self.host_structs = []
2688         for func in self.registry.funcs.values():
2689             if not func.is_required():
2690                 continue
2692             if not func.needs_conversion() and not func.needs_unwrapping():
2693                 continue
2695             conversions = func.get_conversions()
2696             for conv in conversions:
2697                 # Pull in any conversions for vulkan_thunks.c.
2698                 if func.needs_thunk():
2699                     # Append if we don't already have this conversion.
2700                     if not any(c == conv for c in self.conversions):
2701                         self.conversions.append(conv)
2703                 if not isinstance(conv.operand, VkStruct):
2704                     continue
2706                 # Structs can be used in different ways by different conversions
2707                 # e.g. array vs non-array. Just make sure we pull in each struct once.
2708                 if not any(s.name == conv.operand.name for s in self.host_structs):
2709                     self.host_structs.append(conv.operand)
2711         for struct in self.registry.structs:
2712             if struct.name in STRUCT_CHAIN_CONVERSIONS:
2713                 self.struct_chain_conversions.append(StructChainConversionFunction(Direction.INPUT, struct, STRUCT_CHAIN_CONVERSIONS[struct.name]))
2714                 self.struct_chain_conversions.append(FreeStructChainFunction(struct))
2715                 # Once we decide to support pNext chains conversion everywhere, move this under get_conversions
2716                 for e in struct.struct_extensions:
2717                     for m in e:
2718                         if m.needs_conversion() or m.needs_unwrapping():
2719                             conversions = m.get_conversions()
2720                             for conv in conversions:
2721                                 if not any(c == conv for c in self.conversions):
2722                                     self.conversions.append(conv)
2724     def _generate_copyright(self, f, spec_file=False):
2725         f.write("# " if spec_file else "/* ")
2726         f.write("Automatically generated from Vulkan vk.xml; DO NOT EDIT!\n")
2727         lines = ["", "This file is generated from Vulkan vk.xml file covered",
2728             "by the following copyright and permission notice:"]
2729         lines.extend([l.rstrip(" ") for l in self.registry.copyright.splitlines()])
2730         for line in lines:
2731             f.write("{0}{1}".format("# " if spec_file else " * ", line).rstrip(" ") + "\n")
2732         f.write("\n" if spec_file else " */\n\n")
2734     def generate_thunks_c(self, f, prefix):
2735         self._generate_copyright(f)
2737         f.write("#if 0\n")
2738         f.write("#pragma makedep unix\n")
2739         f.write("#endif\n\n")
2741         f.write("#include \"config.h\"\n\n")
2743         f.write("#include <stdlib.h>\n\n")
2745         f.write("#include \"vulkan_private.h\"\n\n")
2747         f.write("WINE_DEFAULT_DEBUG_CHANNEL(vulkan);\n\n")
2749         # Generate any conversion helper functions.
2750         for conv in self.conversions:
2751             f.write(conv.definition())
2753         for conv in self.struct_chain_conversions:
2754             f.write(conv.definition())
2756         # Create thunks for instance and device functions.
2757         # Global functions don't go through the thunks.
2758         for vk_func in self.registry.funcs.values():
2759             if not vk_func.needs_exposing():
2760                 continue
2761             if vk_func.loader_thunk_type == ThunkType.NONE:
2762                 continue
2764             if vk_func.needs_private_thunk():
2765                 f.write(vk_func.thunk(prefix="thunk_"))
2767             if vk_func.thunk_type == ThunkType.PUBLIC:
2768                 f.write("static ")
2769                 f.write(vk_func.thunk(prefix=prefix))
2771         # Create array of device extensions.
2772         f.write("static const char * const vk_device_extensions[] =\n{\n")
2773         for ext in self.registry.extensions:
2774             if ext["type"] != "device":
2775                 continue
2776             if ext["name"] in UNEXPOSED_EXTENSIONS:
2777                 continue
2779             f.write("    \"{0}\",\n".format(ext["name"]))
2780         f.write("};\n\n")
2782         # Create array of instance extensions.
2783         f.write("static const char * const vk_instance_extensions[] =\n{\n")
2784         for ext in self.registry.extensions:
2785             if ext["type"] != "instance":
2786                 continue
2787             if ext["name"] in UNEXPOSED_EXTENSIONS:
2788                 continue
2790             f.write("    \"{0}\",\n".format(ext["name"]))
2791         f.write("};\n\n")
2793         f.write("BOOL wine_vk_device_extension_supported(const char *name)\n")
2794         f.write("{\n")
2795         f.write("    unsigned int i;\n")
2796         f.write("    for (i = 0; i < ARRAY_SIZE(vk_device_extensions); i++)\n")
2797         f.write("    {\n")
2798         f.write("        if (strcmp(vk_device_extensions[i], name) == 0)\n")
2799         f.write("            return TRUE;\n")
2800         f.write("    }\n")
2801         f.write("    return FALSE;\n")
2802         f.write("}\n\n")
2804         f.write("BOOL wine_vk_instance_extension_supported(const char *name)\n")
2805         f.write("{\n")
2806         f.write("    unsigned int i;\n")
2807         f.write("    for (i = 0; i < ARRAY_SIZE(vk_instance_extensions); i++)\n")
2808         f.write("    {\n")
2809         f.write("        if (strcmp(vk_instance_extensions[i], name) == 0)\n")
2810         f.write("            return TRUE;\n")
2811         f.write("    }\n")
2812         f.write("    return FALSE;\n")
2813         f.write("}\n\n")
2815         f.write("BOOL wine_vk_is_type_wrapped(VkObjectType type)\n")
2816         f.write("{\n")
2817         f.write("    return FALSE")
2818         for handle in self.registry.handles:
2819             if not handle.is_required() or not handle.is_wrapped() or handle.is_alias():
2820                 continue
2821             f.write(" ||\n        type == {}".format(handle.object_type))
2822         f.write(";\n")
2823         f.write("}\n\n")
2825         f.write("uint64_t wine_vk_unwrap_handle(VkObjectType type, uint64_t handle)\n")
2826         f.write("{\n")
2827         f.write("    switch(type)\n")
2828         f.write("    {\n")
2829         for handle in self.registry.handles:
2830             if not handle.is_required() or not handle.is_wrapped() or handle.is_alias():
2831                 continue
2832             f.write("    case {}:\n".format(handle.object_type))
2833             if handle.is_dispatchable():
2834                 f.write("        return (uint64_t) (uintptr_t) ")
2835                 f.write(handle.native_handle("(({}) (uintptr_t) handle)".format(handle.name)))
2836             else:
2837                 f.write("        return (uint64_t) ")
2838                 f.write(handle.native_handle("handle"))
2839             f.write(";\n");
2840         f.write("    default:\n")
2841         f.write("       return handle;\n")
2842         f.write("    }\n")
2843         f.write("}\n\n")
2845         f.write("const unixlib_entry_t __wine_unix_call_funcs[] =\n")
2846         f.write("{\n")
2847         f.write("    init_vulkan,\n")
2848         for vk_func in self.registry.funcs.values():
2849             if not vk_func.needs_exposing():
2850                 continue
2851             if vk_func.loader_thunk_type == ThunkType.NONE:
2852                 continue
2854             f.write("    {1}{0},\n".format(vk_func.name, prefix))
2855         f.write("};\n")
2856         f.write("C_ASSERT(ARRAYSIZE(__wine_unix_call_funcs) == unix_count);\n\n")
2858         f.write("static NTSTATUS WINAPI wine_vk_call(enum unix_call code, void *params)\n")
2859         f.write("{\n")
2860         f.write("    return __wine_unix_call_funcs[code](params);\n")
2861         f.write("}\n\n")
2863         f.write("const struct unix_funcs loader_funcs =\n")
2864         f.write("{\n")
2865         f.write("    wine_vk_call,\n")
2866         f.write("    wine_vk_is_available_instance_function,\n")
2867         f.write("    wine_vk_is_available_device_function,\n")
2868         f.write("};\n")
2870     def generate_thunks_h(self, f, prefix):
2871         self._generate_copyright(f)
2873         f.write("#ifndef __WINE_VULKAN_THUNKS_H\n")
2874         f.write("#define __WINE_VULKAN_THUNKS_H\n\n")
2876         f.write("#define WINE_VK_VERSION VK_API_VERSION_{0}_{1}\n\n".format(WINE_VK_VERSION[0], WINE_VK_VERSION[1]))
2878         # Generate prototypes for device and instance functions requiring a custom implementation.
2879         f.write("/* Functions for which we have custom implementations outside of the thunks. */\n")
2880         for vk_func in self.registry.funcs.values():
2881             if not vk_func.needs_exposing():
2882                 continue
2883             if vk_func.needs_thunk() and not vk_func.needs_private_thunk():
2884                 continue
2886             f.write("NTSTATUS {0}{1}(void *args) DECLSPEC_HIDDEN;\n".format(prefix, vk_func.name))
2887         f.write("\n")
2889         f.write("/* Private thunks */\n")
2890         for vk_func in self.registry.funcs.values():
2891             if vk_func.needs_private_thunk():
2892                 f.write("{0};\n".format(vk_func.prototype(prefix="thunk_", postfix="DECLSPEC_HIDDEN")))
2893         f.write("\n")
2895         for struct in self.host_structs:
2896             f.write("#if defined(USE_STRUCT_CONVERSION)\n")
2897             f.write(struct.definition(align=False, conv=True, postfix="_host"))
2898             f.write("#else\n")
2899             f.write("typedef {0} {0}_host;\n".format(struct.name))
2900             f.write("#endif\n\n")
2901         f.write("\n")
2903         for func in self.struct_chain_conversions:
2904             f.write(func.prototype(postfix="DECLSPEC_HIDDEN") + ";\n")
2905         f.write("\n")
2907         f.write("/* For use by vkDevice and children */\n")
2908         f.write("struct vulkan_device_funcs\n{\n")
2909         for vk_func in self.registry.device_funcs:
2910             if not vk_func.is_required():
2911                 continue
2913             if not vk_func.needs_dispatch():
2914                 LOGGER.debug("skipping {0} in vulkan_device_funcs".format(vk_func.name))
2915                 continue
2917             f.write("    {0};\n".format(vk_func.pfn(conv=vk_func.needs_conversion())))
2918         f.write("};\n\n")
2920         f.write("/* For use by vkInstance and children */\n")
2921         f.write("struct vulkan_instance_funcs\n{\n")
2922         for vk_func in self.registry.instance_funcs + self.registry.phys_dev_funcs:
2923             if not vk_func.is_required():
2924                 continue
2926             if not vk_func.needs_dispatch():
2927                 LOGGER.debug("skipping {0} in vulkan_instance_funcs".format(vk_func.name))
2928                 continue
2930             f.write("    {0};\n".format(vk_func.pfn(conv=vk_func.needs_conversion())))
2931         f.write("};\n\n")
2933         f.write("#define ALL_VK_DEVICE_FUNCS() \\\n")
2934         first = True
2935         for vk_func in self.registry.device_funcs:
2936             if not vk_func.is_required():
2937                 continue
2939             if not vk_func.needs_dispatch():
2940                 LOGGER.debug("skipping {0} in ALL_VK_DEVICE_FUNCS".format(vk_func.name))
2941                 continue
2943             if first:
2944                 f.write("    USE_VK_FUNC({0})".format(vk_func.name))
2945                 first = False
2946             else:
2947                 f.write(" \\\n    USE_VK_FUNC({0})".format(vk_func.name))
2948         f.write("\n\n")
2950         f.write("#define ALL_VK_INSTANCE_FUNCS() \\\n")
2951         first = True
2952         for vk_func in self.registry.instance_funcs + self.registry.phys_dev_funcs:
2953             if not vk_func.is_required():
2954                 continue
2956             if not vk_func.needs_dispatch():
2957                 LOGGER.debug("skipping {0} in ALL_VK_INSTANCE_FUNCS".format(vk_func.name))
2958                 continue
2960             if first:
2961                 f.write("    USE_VK_FUNC({0})".format(vk_func.name))
2962                 first = False
2963             else:
2964                 f.write(" \\\n    USE_VK_FUNC({0})".format(vk_func.name))
2965         f.write("\n\n")
2967         f.write("#endif /* __WINE_VULKAN_THUNKS_H */\n")
2969     def generate_loader_thunks_c(self, f):
2970         self._generate_copyright(f)
2972         f.write("#include \"vulkan_loader.h\"\n\n")
2974         f.write("WINE_DEFAULT_DEBUG_CHANNEL(vulkan);\n\n")
2976         for vk_func in self.registry.funcs.values():
2977             if not vk_func.needs_exposing():
2978                 continue
2979             if vk_func.loader_thunk_type != ThunkType.PUBLIC:
2980                 continue
2982             f.write(vk_func.loader_thunk())
2984         f.write("static const struct vulkan_func vk_device_dispatch_table[] =\n{\n")
2985         for vk_func in self.registry.device_funcs:
2986             if not vk_func.needs_exposing():
2987                 continue
2989             f.write("    {{\"{0}\", {0}}},\n".format(vk_func.name))
2990         f.write("};\n\n")
2992         f.write("static const struct vulkan_func vk_phys_dev_dispatch_table[] =\n{\n")
2993         for vk_func in self.registry.phys_dev_funcs:
2994             if not vk_func.needs_exposing():
2995                 continue
2997             f.write("    {{\"{0}\", {0}}},\n".format(vk_func.name))
2998         f.write("};\n\n")
3000         f.write("static const struct vulkan_func vk_instance_dispatch_table[] =\n{\n")
3001         for vk_func in self.registry.instance_funcs:
3002             if not vk_func.needs_exposing():
3003                 continue
3005             f.write("    {{\"{0}\", {0}}},\n".format(vk_func.name))
3006         f.write("};\n\n")
3008         f.write("void *wine_vk_get_device_proc_addr(const char *name)\n")
3009         f.write("{\n")
3010         f.write("    unsigned int i;\n")
3011         f.write("    for (i = 0; i < ARRAY_SIZE(vk_device_dispatch_table); i++)\n")
3012         f.write("    {\n")
3013         f.write("        if (strcmp(vk_device_dispatch_table[i].name, name) == 0)\n")
3014         f.write("        {\n")
3015         f.write("            TRACE(\"Found name=%s in device table\\n\", debugstr_a(name));\n")
3016         f.write("            return vk_device_dispatch_table[i].func;\n")
3017         f.write("        }\n")
3018         f.write("    }\n")
3019         f.write("    return NULL;\n")
3020         f.write("}\n\n")
3022         f.write("void *wine_vk_get_phys_dev_proc_addr(const char *name)\n")
3023         f.write("{\n")
3024         f.write("    unsigned int i;\n")
3025         f.write("    for (i = 0; i < ARRAY_SIZE(vk_phys_dev_dispatch_table); i++)\n")
3026         f.write("    {\n")
3027         f.write("        if (strcmp(vk_phys_dev_dispatch_table[i].name, name) == 0)\n")
3028         f.write("        {\n")
3029         f.write("            TRACE(\"Found name=%s in physical device table\\n\", debugstr_a(name));\n")
3030         f.write("            return vk_phys_dev_dispatch_table[i].func;\n")
3031         f.write("        }\n")
3032         f.write("    }\n")
3033         f.write("    return NULL;\n")
3034         f.write("}\n\n")
3036         f.write("void *wine_vk_get_instance_proc_addr(const char *name)\n")
3037         f.write("{\n")
3038         f.write("    unsigned int i;\n")
3039         f.write("    for (i = 0; i < ARRAY_SIZE(vk_instance_dispatch_table); i++)\n")
3040         f.write("    {\n")
3041         f.write("        if (strcmp(vk_instance_dispatch_table[i].name, name) == 0)\n")
3042         f.write("        {\n")
3043         f.write("            TRACE(\"Found name=%s in instance table\\n\", debugstr_a(name));\n")
3044         f.write("            return vk_instance_dispatch_table[i].func;\n")
3045         f.write("        }\n")
3046         f.write("    }\n")
3047         f.write("    return NULL;\n")
3048         f.write("}\n")
3050     def generate_loader_thunks_h(self, f):
3051         self._generate_copyright(f)
3053         f.write("#ifndef __WINE_VULKAN_LOADER_THUNKS_H\n")
3054         f.write("#define __WINE_VULKAN_LOADER_THUNKS_H\n\n")
3056         f.write("enum unix_call\n")
3057         f.write("{\n")
3058         f.write("    unix_init,\n")
3059         for vk_func in self.registry.funcs.values():
3060             if not vk_func.needs_exposing():
3061                 continue
3062             if vk_func.loader_thunk_type == ThunkType.NONE:
3063                 continue
3065             f.write("    unix_{0},\n".format(vk_func.name))
3066         f.write("    unix_count,\n")
3067         f.write("};\n\n")
3069         f.write("#include \"pshpack4.h\"\n\n")
3071         for vk_func in self.registry.funcs.values():
3072             if not vk_func.needs_exposing():
3073                 continue
3074             if vk_func.loader_thunk_type == ThunkType.NONE:
3075                 continue
3077             f.write("struct {0}_params\n".format(vk_func.name))
3078             f.write("{\n");
3079             for p in vk_func.params:
3080                 f.write("    {0};\n".format(p.definition(is_member=True)))
3081             if vk_func.returns_longlong():
3082                 f.write("    {0} result;\n".format(vk_func.type))
3083             f.write("};\n\n");
3085         f.write("#include \"poppack.h\"\n\n")
3086         f.write("#endif /* __WINE_VULKAN_LOADER_THUNKS_H */\n")
3088     def generate_vulkan_h(self, f):
3089         self._generate_copyright(f)
3090         f.write("#ifndef __WINE_VULKAN_H\n")
3091         f.write("#define __WINE_VULKAN_H\n\n")
3093         f.write("#include <windef.h>\n")
3094         f.write("#include <stdint.h>\n\n")
3096         f.write("/* Define WINE_VK_HOST to get 'host' headers. */\n")
3097         f.write("#ifdef WINE_VK_HOST\n")
3098         f.write("#define VKAPI_CALL\n")
3099         f.write('#define WINE_VK_ALIGN(x)\n')
3100         f.write("#endif\n\n")
3102         f.write("#ifndef VKAPI_CALL\n")
3103         f.write("#define VKAPI_CALL __stdcall\n")
3104         f.write("#endif\n\n")
3106         f.write("#ifndef VKAPI_PTR\n")
3107         f.write("#define VKAPI_PTR VKAPI_CALL\n")
3108         f.write("#endif\n\n")
3110         f.write("#ifndef WINE_VK_ALIGN\n")
3111         f.write("#define WINE_VK_ALIGN DECLSPEC_ALIGN\n")
3112         f.write("#endif\n\n")
3114         # The overall strategy is to define independent constants and datatypes,
3115         # prior to complex structures and function calls to avoid forward declarations.
3116         for const in self.registry.consts:
3117             # For now just generate things we may not need. The amount of parsing needed
3118             # to get some of the info is tricky as you need to figure out which structure
3119             # references a certain constant.
3120             f.write(const.definition())
3121         f.write("\n")
3123         for define in self.registry.defines:
3124             f.write(define.definition())
3126         for handle in self.registry.handles:
3127             # For backward compatibility also create definitions for aliases.
3128             # These types normally don't get pulled in as we use the new types
3129             # even in legacy functions if they are aliases.
3130             if handle.is_required() or handle.is_alias():
3131                  f.write(handle.definition())
3132         f.write("\n")
3134         for base_type in self.registry.base_types:
3135             f.write(base_type.definition())
3136         f.write("\n")
3138         for bitmask in self.registry.bitmasks:
3139             f.write(bitmask.definition())
3140         f.write("\n")
3142         # Define enums, this includes values for some of the bitmask types as well.
3143         for enum in self.registry.enums.values():
3144             if enum.required:
3145                 f.write(enum.definition())
3147         for fp in self.registry.funcpointers:
3148             if fp.required:
3149                 f.write(fp.definition())
3150         f.write("\n")
3152         # This generates both structures and unions. Since structures
3153         # may depend on other structures/unions, we need a list of
3154         # decoupled structs.
3155         # Note: unions are stored in structs for dependency reasons,
3156         # see comment in parsing section.
3157         structs = VkStruct.decouple_structs(self.registry.structs)
3158         for struct in structs:
3159             LOGGER.debug("Generating struct: {0}".format(struct.name))
3160             f.write(struct.definition(align=True))
3161             f.write("\n")
3163         for func in self.registry.funcs.values():
3164             if not func.is_required():
3165                 LOGGER.debug("Skipping PFN definition for: {0}".format(func.name))
3166                 continue
3168             f.write("typedef {0};\n".format(func.pfn(prefix="PFN", call_conv="VKAPI_PTR")))
3169         f.write("\n")
3171         f.write("#ifndef VK_NO_PROTOTYPES\n")
3172         for func in self.registry.funcs.values():
3173             if not func.is_required():
3174                 LOGGER.debug("Skipping API definition for: {0}".format(func.name))
3175                 continue
3177             LOGGER.debug("Generating API definition for: {0}".format(func.name))
3178             f.write("{0};\n".format(func.prototype(call_conv="VKAPI_CALL")))
3179         f.write("#endif /* VK_NO_PROTOTYPES */\n\n")
3181         f.write("#endif /* __WINE_VULKAN_H */\n")
3183     def generate_vulkan_driver_h(self, f):
3184         self._generate_copyright(f)
3185         f.write("#ifndef __WINE_VULKAN_DRIVER_H\n")
3186         f.write("#define __WINE_VULKAN_DRIVER_H\n\n")
3188         f.write("/* Wine internal vulkan driver version, needs to be bumped upon vulkan_funcs changes. */\n")
3189         f.write("#define WINE_VULKAN_DRIVER_VERSION {0}\n\n".format(DRIVER_VERSION))
3191         f.write("struct vulkan_funcs\n{\n")
3192         f.write("    /* Vulkan global functions. These are the only calls at this point a graphics driver\n")
3193         f.write("     * needs to provide. Other function calls will be provided indirectly by dispatch\n")
3194         f.write("     * tables part of dispatchable Vulkan objects such as VkInstance or vkDevice.\n")
3195         f.write("     */\n")
3197         for vk_func in self.registry.funcs.values():
3198             if not vk_func.is_driver_func():
3199                 continue
3201             pfn = vk_func.pfn()
3202             # Avoid PFN_vkVoidFunction in driver interface as Vulkan likes to put calling convention
3203             # stuff in there. For simplicity substitute with "void *".
3204             pfn = pfn.replace("PFN_vkVoidFunction", "void *")
3205             f.write("    {0};\n".format(pfn))
3207         f.write("\n")
3208         f.write("    /* winevulkan specific functions */\n")
3209         f.write("    VkSurfaceKHR (*p_wine_get_native_surface)(VkSurfaceKHR);\n")
3210         f.write("};\n\n")
3212         f.write("extern const struct vulkan_funcs * CDECL __wine_get_vulkan_driver(UINT version);\n\n")
3214         f.write("static inline void *get_vulkan_driver_device_proc_addr(\n")
3215         f.write("        const struct vulkan_funcs *vulkan_funcs, const char *name)\n{\n")
3216         f.write("    if (!name || name[0] != 'v' || name[1] != 'k') return NULL;\n\n")
3217         f.write("    name += 2;\n\n")
3218         for vk_func in self.registry.funcs.values():
3219             if vk_func.is_driver_func() and vk_func.is_device_func():
3220                 f.write('    if (!strcmp(name, "{0}"))\n'.format(vk_func.name[2:]))
3221                 f.write('        return vulkan_funcs->p_{0};\n'.format(vk_func.name))
3222         f.write("\n")
3223         f.write("    return NULL;\n}\n\n")
3225         f.write("static inline void *get_vulkan_driver_instance_proc_addr(\n")
3226         f.write("        const struct vulkan_funcs *vulkan_funcs, VkInstance instance, const char *name)\n{\n")
3227         f.write("    if (!name || name[0] != 'v' || name[1] != 'k') return NULL;\n\n")
3228         f.write("    name += 2;\n\n")
3229         for vk_func in self.registry.funcs.values():
3230             if vk_func.is_driver_func() and vk_func.is_global_func() and vk_func.name != "vkGetInstanceProcAddr":
3231                 f.write('    if (!strcmp(name, "{0}"))\n'.format(vk_func.name[2:]))
3232                 f.write('        return vulkan_funcs->p_{0};\n'.format(vk_func.name))
3233         f.write("\n")
3234         f.write("    if (!instance) return NULL;\n\n")
3235         for vk_func in self.registry.funcs.values():
3236             if vk_func.is_driver_func() and (vk_func.is_instance_func() or vk_func.is_phys_dev_func()):
3237                 f.write('    if (!strcmp(name, "{0}"))\n'.format(vk_func.name[2:]))
3238                 f.write('        return vulkan_funcs->p_{0};\n'.format(vk_func.name))
3239         f.write("\n")
3240         f.write("    name -= 2;\n\n")
3241         f.write("    return get_vulkan_driver_device_proc_addr(vulkan_funcs, name);\n}\n\n")
3243         f.write("#endif /* __WINE_VULKAN_DRIVER_H */\n")
3245     def generate_vulkan_spec(self, f):
3246         self._generate_copyright(f, spec_file=True)
3247         f.write("@ stdcall -private vk_icdGetInstanceProcAddr(ptr str)\n")
3248         f.write("@ stdcall -private vk_icdGetPhysicalDeviceProcAddr(ptr str)\n")
3249         f.write("@ stdcall -private vk_icdNegotiateLoaderICDInterfaceVersion(ptr)\n")
3251         # Export symbols for all Vulkan Core functions.
3252         for func in self.registry.funcs.values():
3253             if not func.is_core_func():
3254                 continue
3256             # We support all Core functions except for VK_KHR_display* APIs.
3257             # Create stubs for unsupported Core functions.
3258             if func.is_required():
3259                 f.write(func.spec())
3260             else:
3261                 f.write("@ stub {0}\n".format(func.name))
3263         f.write("@ stdcall -private DllRegisterServer()\n")
3264         f.write("@ stdcall -private DllUnregisterServer()\n")
3266     def generate_vulkan_loader_spec(self, f):
3267         self._generate_copyright(f, spec_file=True)
3269         # Export symbols for all Vulkan Core functions.
3270         for func in self.registry.funcs.values():
3271             if not func.is_core_func():
3272                 continue
3274             # We support all Core functions except for VK_KHR_display* APIs.
3275             # Create stubs for unsupported Core functions.
3276             if func.is_required():
3277                 f.write(func.spec(symbol="winevulkan." + func.name))
3278             else:
3279                 f.write("@ stub {0}\n".format(func.name))
3282 class VkRegistry(object):
3283     def __init__(self, reg_filename):
3284         # Used for storage of type information.
3285         self.base_types = None
3286         self.bitmasks = None
3287         self.consts = None
3288         self.defines = None
3289         self.enums = None
3290         self.funcpointers = None
3291         self.handles = None
3292         self.structs = None
3294         # We aggregate all types in here for cross-referencing.
3295         self.funcs = {}
3296         self.types = {}
3298         self.version_regex = re.compile(
3299             r'^'
3300             r'VK_VERSION_'
3301             r'(?P<major>[0-9])'
3302             r'_'
3303             r'(?P<minor>[0-9])'
3304             r'$'
3305         )
3307         # Overall strategy for parsing the registry is to first
3308         # parse all type / function definitions. Then parse
3309         # features and extensions to decide which types / functions
3310         # to actually 'pull in' for code generation. For each type or
3311         # function call we want we set a member 'required' to True.
3312         tree = ET.parse(reg_filename)
3313         root = tree.getroot()
3314         self._parse_enums(root)
3315         self._parse_types(root)
3316         self._parse_commands(root)
3318         # Pull in any required types and functions.
3319         self._parse_features(root)
3320         self._parse_extensions(root)
3322         self._match_object_types()
3324         self.copyright = root.find('./comment').text
3326     def _is_feature_supported(self, feature):
3327         version = self.version_regex.match(feature)
3328         if not version:
3329             return True
3331         version = tuple(map(int, version.group('major', 'minor')))
3332         return version <= WINE_VK_VERSION
3334     def _is_extension_supported(self, extension):
3335         # We disable some extensions as either we haven't implemented
3336         # support yet or because they are for platforms other than win32.
3337         return extension not in UNSUPPORTED_EXTENSIONS
3339     def _mark_command_required(self, command):
3340         """ Helper function to mark a certain command and the datatypes it needs as required."""
3341         def mark_bitmask_dependencies(bitmask, types):
3342             if bitmask.requires is not None:
3343                 types[bitmask.requires]["data"].required = True
3345         def mark_funcpointer_dependencies(fp, types):
3346             for m in fp.members:
3347                 type_info = types[m.type]
3349                 # Complex types have a matching definition e.g. VkStruct.
3350                 # Not needed for base types such as uint32_t.
3351                 if "data" in type_info:
3352                     types[m.type]["data"].required = True
3354         def mark_struct_dependencies(struct, types):
3355              for m in struct:
3356                 type_info = types[m.type]
3358                 # Complex types have a matching definition e.g. VkStruct.
3359                 # Not needed for base types such as uint32_t.
3360                 if "data" in type_info:
3361                     types[m.type]["data"].required = True
3363                 if type_info["category"] == "struct" and struct.name != m.type:
3364                     # Yay, recurse
3365                     mark_struct_dependencies(type_info["data"], types)
3366                 elif type_info["category"] == "funcpointer":
3367                     mark_funcpointer_dependencies(type_info["data"], types)
3368                 elif type_info["category"] == "bitmask":
3369                     mark_bitmask_dependencies(type_info["data"], types)
3371         func = self.funcs[command]
3372         func.required = True
3374         # Pull in return type
3375         if func.type != "void":
3376             self.types[func.type]["data"].required = True
3378         # Analyze parameter dependencies and pull in any type needed.
3379         for p in func.params:
3380             type_info = self.types[p.type]
3382             # Check if we are dealing with a complex type e.g. VkEnum, VkStruct and others.
3383             if "data" not in type_info:
3384                 continue
3386             # Mark the complex type as required.
3387             type_info["data"].required = True
3388             if type_info["category"] == "struct":
3389                 struct = type_info["data"]
3390                 mark_struct_dependencies(struct, self.types)
3391             elif type_info["category"] == "bitmask":
3392                 mark_bitmask_dependencies(type_info["data"], self.types)
3394     def _match_object_types(self):
3395         """ Matches each handle with the correct object type. """
3396         # Use upper case comparison for simplicity.
3397         object_types = {}
3398         for value in self.enums["VkObjectType"].values:
3399             object_name = "VK" + value.name[len("VK_OBJECT_TYPE"):].replace("_", "")
3400             object_types[object_name] = value.name
3402         for handle in self.handles:
3403             if not handle.is_required():
3404                 continue
3405             handle.object_type = object_types.get(handle.name.upper())
3406             if not handle.object_type:
3407                 LOGGER.warning("No object type found for {}".format(handle.name))
3409     def _parse_commands(self, root):
3410         """ Parse command section containing the Vulkan function calls. """
3411         funcs = {}
3412         commands = root.findall("./commands/")
3414         # As of Vulkan 1.1, various extensions got promoted to Core.
3415         # The old commands (e.g. KHR) are available for backwards compatibility
3416         # and are marked in vk.xml as 'alias' to the non-extension type.
3417         # The registry likes to avoid data duplication, so parameters and other
3418         # metadata need to be looked up from the Core command.
3419         # We parse the alias commands in a second pass.
3420         alias_commands = []
3421         for command in commands:
3422             alias_name = command.attrib.get("alias")
3423             if alias_name:
3424                 alias_commands.append(command)
3425                 continue
3427             func = VkFunction.from_xml(command, self.types)
3428             funcs[func.name] = func
3430         for command in alias_commands:
3431             alias_name = command.attrib.get("alias")
3432             alias = funcs[alias_name]
3433             func = VkFunction.from_alias(command, alias)
3434             funcs[func.name] = func
3436         # To make life easy for the code generation, separate all function
3437         # calls out in the 4 types of Vulkan functions:
3438         # device, global, physical device and instance.
3439         device_funcs = []
3440         global_funcs = []
3441         phys_dev_funcs = []
3442         instance_funcs = []
3443         for func in funcs.values():
3444             if func.is_device_func():
3445                 device_funcs.append(func)
3446             elif func.is_global_func():
3447                 global_funcs.append(func)
3448             elif func.is_phys_dev_func():
3449                 phys_dev_funcs.append(func)
3450             else:
3451                 instance_funcs.append(func)
3453         # Sort function lists by name and store them.
3454         self.device_funcs = sorted(device_funcs, key=lambda func: func.name)
3455         self.global_funcs = sorted(global_funcs, key=lambda func: func.name)
3456         self.phys_dev_funcs = sorted(phys_dev_funcs, key=lambda func: func.name)
3457         self.instance_funcs = sorted(instance_funcs, key=lambda func: func.name)
3459         # The funcs dictionary is used as a convenient way to lookup function
3460         # calls when needed e.g. to adjust member variables.
3461         self.funcs = OrderedDict(sorted(funcs.items()))
3463     def _parse_enums(self, root):
3464         """ Parse enums section or better described as constants section. """
3465         enums = {}
3466         self.consts = []
3467         for enum in root.findall("./enums"):
3468             name = enum.attrib.get("name")
3469             _type = enum.attrib.get("type")
3471             if _type in ("enum", "bitmask"):
3472                 enums[name] = VkEnum.from_xml(enum)
3473             else:
3474                 # If no type is set, we are dealing with API constants.
3475                 for value in enum.findall("enum"):
3476                     # If enum is an alias, set the value to the alias name.
3477                     # E.g. VK_LUID_SIZE_KHR is an alias to VK_LUID_SIZE.
3478                     alias = value.attrib.get("alias")
3479                     if alias:
3480                         self.consts.append(VkConstant(value.attrib.get("name"), alias))
3481                     else:
3482                         self.consts.append(VkConstant(value.attrib.get("name"), value.attrib.get("value")))
3484         self.enums = OrderedDict(sorted(enums.items()))
3486     def _process_require_enum(self, enum_elem, ext=None, only_aliased=False):
3487         if "extends" in enum_elem.keys():
3488             enum = self.types[enum_elem.attrib["extends"]]["data"]
3490             # Need to define VkEnumValues which were aliased to by another value. This is necessary
3491             # from VK spec version 1.2.135 where the provisional VK_KHR_ray_tracing extension was
3492             # added which altered VK_NV_ray_tracing's VkEnumValues to alias to the provisional
3493             # extension.
3494             aliased = False
3495             for _, t in self.types.items():
3496                 if t["category"] != "enum":
3497                     continue
3498                 if not t["data"]:
3499                     continue
3500                 for value in t["data"].values:
3501                     if value.alias == enum_elem.attrib["name"]:
3502                         aliased = True
3504             if only_aliased and not aliased:
3505                 return
3507             if "bitpos" in enum_elem.keys():
3508                 # We need to add an extra value to an existing enum type.
3509                 # E.g. VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG to VkFormatFeatureFlagBits.
3510                 enum.create_bitpos(enum_elem.attrib["name"], int(enum_elem.attrib["bitpos"]))
3512             elif "offset" in enum_elem.keys():
3513                 # Extensions promoted to Core, have the extension number as part
3514                 # of the enum value. Else retrieve from the extension tag.
3515                 if enum_elem.attrib.get("extnumber"):
3516                     ext_number = int(enum_elem.attrib.get("extnumber"))
3517                 else:
3518                     ext_number = int(ext.attrib["number"])
3519                 offset = int(enum_elem.attrib["offset"])
3520                 value = EXT_BASE + (ext_number - 1) * EXT_BLOCK_SIZE + offset
3522                 # Deal with negative values.
3523                 direction = enum_elem.attrib.get("dir")
3524                 if direction is not None:
3525                     value = -value
3527                 enum.create_value(enum_elem.attrib["name"], str(value))
3529             elif "value" in enum_elem.keys():
3530                 enum.create_value(enum_elem.attrib["name"], enum_elem.attrib["value"])
3531             elif "alias" in enum_elem.keys():
3532                 enum.create_alias(enum_elem.attrib["name"], enum_elem.attrib["alias"])
3534         elif "value" in enum_elem.keys():
3535             # Constant with an explicit value
3536             if only_aliased:
3537                 return
3539             self.consts.append(VkConstant(enum_elem.attrib["name"], enum_elem.attrib["value"]))
3540         elif "alias" in enum_elem.keys():
3541             # Aliased constant
3542             if not only_aliased:
3543                 return
3545             self.consts.append(VkConstant(enum_elem.attrib["name"], enum_elem.attrib["alias"]))
3547     @staticmethod
3548     def _require_type(type_info):
3549         if type_info.is_alias():
3550             type_info = type_info.alias
3551         type_info.required = True
3552         if type(type_info) == VkStruct:
3553             for member in type_info.members:
3554                 if "data" in member.type_info:
3555                   VkRegistry._require_type(member.type_info["data"])
3557     def _parse_extensions(self, root):
3558         """ Parse extensions section and pull in any types and commands for this extension. """
3559         extensions = []
3560         exts = root.findall("./extensions/extension")
3561         deferred_exts = []
3562         skipped_exts = UNSUPPORTED_EXTENSIONS.copy()
3564         def process_ext(ext, deferred=False):
3565             ext_name = ext.attrib["name"]
3567             # Set extension name on any functions calls part of this extension as we
3568             # were not aware of the name during initial parsing.
3569             commands = ext.findall("require/command")
3570             for command in commands:
3571                 cmd_name = command.attrib["name"]
3572                 # Need to verify that the command is defined, and otherwise skip it.
3573                 # vkCreateScreenSurfaceQNX is declared in <extensions> but not defined in
3574                 # <commands>. A command without a definition cannot be enabled, so it's valid for
3575                 # the XML file to handle this, but because of the manner in which we parse the XML
3576                 # file we pre-populate from <commands> before we check if a command is enabled.
3577                 if cmd_name in self.funcs:
3578                     self.funcs[cmd_name].extensions.add(ext_name)
3580             # Some extensions are not ready or have numbers reserved as a place holder.
3581             if ext.attrib["supported"] == "disabled":
3582                 LOGGER.debug("Skipping disabled extension: {0}".format(ext_name))
3583                 skipped_exts.append(ext_name)
3584                 return
3586             # Defer extensions with 'sortorder' as they are order-dependent for spec-parsing.
3587             if not deferred and "sortorder" in ext.attrib:
3588                 deferred_exts.append(ext)
3589                 return
3591             # Disable highly experimental extensions as the APIs are unstable and can
3592             # change between minor Vulkan revisions until API is final and becomes KHR
3593             # or NV.
3594             if ("KHX" in ext_name or "NVX" in ext_name) and ext_name not in ALLOWED_X_EXTENSIONS:
3595                 LOGGER.debug("Skipping experimental extension: {0}".format(ext_name))
3596                 skipped_exts.append(ext_name)
3597                 return
3599             # Extensions can define VkEnumValues which alias to provisional extensions. Pre-process
3600             # extensions to define any required VkEnumValues before the platform check below.
3601             for require in ext.findall("require"):
3602                 # Extensions can add enum values to Core / extension enums, so add these.
3603                 for enum_elem in require.findall("enum"):
3604                     self._process_require_enum(enum_elem, ext, only_aliased=True)
3606             platform = ext.attrib.get("platform")
3607             if platform and platform != "win32":
3608                 LOGGER.debug("Skipping extensions {0} for platform {1}".format(ext_name, platform))
3609                 skipped_exts.append(ext_name)
3610                 return
3612             if not self._is_extension_supported(ext_name):
3613                 LOGGER.debug("Skipping unsupported extension: {0}".format(ext_name))
3614                 skipped_exts.append(ext_name)
3615                 return
3616             elif "requires" in ext.attrib:
3617                 # Check if this extension builds on top of another unsupported extension.
3618                 requires = ext.attrib["requires"].split(",")
3619                 if len(set(requires).intersection(skipped_exts)) > 0:
3620                     skipped_exts.append(ext_name)
3621                     return
3623             LOGGER.debug("Loading extension: {0}".format(ext_name))
3625             # Extensions can define one or more require sections each requiring
3626             # different features (e.g. Vulkan 1.1). Parse each require section
3627             # separately, so we can skip sections we don't want.
3628             for require in ext.findall("require"):
3629                 # Extensions can add enum values to Core / extension enums, so add these.
3630                 for enum_elem in require.findall("enum"):
3631                     self._process_require_enum(enum_elem, ext)
3633                 for t in require.findall("type"):
3634                     type_info = self.types[t.attrib["name"]]["data"]
3635                     self._require_type(type_info)
3636                 feature = require.attrib.get("feature")
3637                 if feature and not self._is_feature_supported(feature):
3638                     continue
3640                 required_extension = require.attrib.get("extension")
3641                 if required_extension and not self._is_extension_supported(required_extension):
3642                     continue
3644                 # Pull in any commands we need. We infer types to pull in from the command
3645                 # as well.
3646                 for command in require.findall("command"):
3647                     cmd_name = command.attrib["name"]
3648                     self._mark_command_required(cmd_name)
3651             # Store a list with extensions.
3652             ext_info = {"name" : ext_name, "type" : ext.attrib["type"]}
3653             extensions.append(ext_info)
3656         # Process extensions, allowing for sortorder to defer extension processing
3657         for ext in exts:
3658             process_ext(ext)
3660         deferred_exts.sort(key=lambda ext: ext.attrib["sortorder"])
3662         # Respect sortorder
3663         for ext in deferred_exts:
3664             process_ext(ext, deferred=True)
3666         # Sort in alphabetical order.
3667         self.extensions = sorted(extensions, key=lambda ext: ext["name"])
3669     def _parse_features(self, root):
3670         """ Parse the feature section, which describes Core commands and types needed. """
3672         for feature in root.findall("./feature"):
3673             feature_name = feature.attrib["name"]
3674             for require in feature.findall("require"):
3675                 LOGGER.info("Including features for {0}".format(require.attrib.get("comment")))
3676                 for tag in require:
3677                     if tag.tag == "comment":
3678                         continue
3679                     elif tag.tag == "command":
3680                         if not self._is_feature_supported(feature_name):
3681                             continue
3682                         name = tag.attrib["name"]
3683                         self._mark_command_required(name)
3684                     elif tag.tag == "enum":
3685                         self._process_require_enum(tag)
3686                     elif tag.tag == "type":
3687                         name = tag.attrib["name"]
3689                         # Skip pull in for vk_platform.h for now.
3690                         if name == "vk_platform":
3691                             continue
3693                         type_info = self.types[name]
3694                         type_info["data"].required = True
3696     def _parse_types(self, root):
3697         """ Parse types section, which contains all data types e.g. structs, typedefs etcetera. """
3698         types = root.findall("./types/type")
3700         base_types = []
3701         bitmasks = []
3702         defines = []
3703         funcpointers = []
3704         handles = []
3705         structs = []
3707         alias_types = []
3708         for t in types:
3709             type_info = {}
3710             type_info["category"] = t.attrib.get("category", None)
3711             type_info["requires"] = t.attrib.get("requires", None)
3713             # We parse aliases in a second pass when we know more.
3714             alias = t.attrib.get("alias")
3715             if alias:
3716                 LOGGER.debug("Alias found: {0}".format(alias))
3717                 alias_types.append(t)
3718                 continue
3720             if type_info["category"] in ["include"]:
3721                 continue
3723             if type_info["category"] == "basetype":
3724                 name = t.find("name").text
3725                 _type = None
3726                 if not t.find("type") is None:
3727                     _type = t.find("type").text
3728                     tail = t.find("type").tail
3729                     if tail is not None:
3730                         _type += tail.strip()
3731                 basetype = VkBaseType(name, _type)
3732                 base_types.append(basetype)
3733                 type_info["data"] = basetype
3735             # Basic C types don't need us to define them, but we do need data for them
3736             if type_info["requires"] == "vk_platform":
3737                 requires = type_info["requires"]
3738                 basic_c = VkBaseType(name, _type, requires=requires)
3739                 type_info["data"] = basic_c
3741             if type_info["category"] == "bitmask":
3742                 name = t.find("name").text
3743                 _type = t.find("type").text
3745                 # Most bitmasks have a requires attribute used to pull in
3746                 # required '*FlagBits" enum.
3747                 requires = type_info["requires"]
3748                 bitmask = VkBaseType(name, _type, requires=requires)
3749                 bitmasks.append(bitmask)
3750                 type_info["data"] = bitmask
3752             if type_info["category"] == "define":
3753                 define = VkDefine.from_xml(t)
3754                 defines.append(define)
3755                 type_info["data"] = define
3757             if type_info["category"] == "enum":
3758                 name = t.attrib.get("name")
3759                 # The type section only contains enum names, not the actual definition.
3760                 # Since we already parsed the enum before, just link it in.
3761                 try:
3762                     type_info["data"] = self.enums[name]
3763                 except KeyError as e:
3764                     # Not all enums seem to be defined yet, typically that's for
3765                     # ones ending in 'FlagBits' where future extensions may add
3766                     # definitions.
3767                     type_info["data"] = None
3769             if type_info["category"] == "funcpointer":
3770                 funcpointer = VkFunctionPointer.from_xml(t)
3771                 funcpointers.append(funcpointer)
3772                 type_info["data"] = funcpointer
3774             if type_info["category"] == "handle":
3775                 handle = VkHandle.from_xml(t)
3776                 handles.append(handle)
3777                 type_info["data"] = handle
3779             if type_info["category"] in ["struct", "union"]:
3780                 # We store unions among structs as some structs depend
3781                 # on unions. The types are very similar in parsing and
3782                 # generation anyway. The official Vulkan scripts use
3783                 # a similar kind of hack.
3784                 struct = VkStruct.from_xml(t)
3785                 structs.append(struct)
3786                 type_info["data"] = struct
3788             # Name is in general within a name tag else it is an optional
3789             # attribute on the type tag.
3790             name_elem = t.find("name")
3791             if name_elem is not None:
3792                 type_info["name"] = name_elem.text
3793             else:
3794                 type_info["name"] = t.attrib.get("name", None)
3796             # Store all type data in a shared dictionary, so we can easily
3797             # look up information for a given type. There are no duplicate
3798             # names.
3799             self.types[type_info["name"]] = type_info
3801         # Second pass for alias types, so we can retrieve all data from
3802         # the aliased object.
3803         for t in alias_types:
3804             type_info = {}
3805             type_info["category"] = t.attrib.get("category")
3806             type_info["name"] = t.attrib.get("name")
3808             alias = t.attrib.get("alias")
3810             if type_info["category"] == "bitmask":
3811                 bitmask = VkBaseType(type_info["name"], alias, alias=self.types[alias]["data"])
3812                 bitmasks.append(bitmask)
3813                 type_info["data"] = bitmask
3815             if type_info["category"] == "enum":
3816                 enum = VkEnum.from_alias(t, self.types[alias]["data"])
3817                 type_info["data"] = enum
3818                 self.enums[enum.name] = enum
3820             if type_info["category"] == "handle":
3821                 handle = VkHandle.from_alias(t, self.types[alias]["data"])
3822                 handles.append(handle)
3823                 type_info["data"] = handle
3825             if type_info["category"] == "struct":
3826                 struct = VkStruct.from_alias(t, self.types[alias]["data"])
3827                 structs.append(struct)
3828                 type_info["data"] = struct
3830             self.types[type_info["name"]] = type_info
3832         # We need detailed type information during code generation
3833         # on structs for alignment reasons. Unfortunately structs
3834         # are parsed among other types, so there is no guarantee
3835         # that any types needed have been parsed already, so set
3836         # the data now.
3837         for struct in structs:
3838             struct.set_type_info(self.types)
3840             # Alias structures have enum values equivalent to those of the
3841             # structure which they are aliased against. we need to ignore alias
3842             # structs when populating the struct extensions list, otherwise we
3843             # will create duplicate case entries.
3844             if struct.alias:
3845                 continue
3847             for structextend in struct.structextends:
3848                 s = self.types[structextend]["data"]
3849                 s.struct_extensions.append(struct)
3851         # Guarantee everything is sorted, so code generation doesn't have
3852         # to deal with this.
3853         self.base_types = sorted(base_types, key=lambda base_type: base_type.name)
3854         self.bitmasks = sorted(bitmasks, key=lambda bitmask: bitmask.name)
3855         self.defines = defines
3856         self.enums = OrderedDict(sorted(self.enums.items()))
3857         self.funcpointers = sorted(funcpointers, key=lambda fp: fp.name)
3858         self.handles = sorted(handles, key=lambda handle: handle.name)
3859         self.structs = sorted(structs, key=lambda struct: struct.name)
3861 def generate_vulkan_json(f):
3862     f.write("{\n")
3863     f.write("    \"file_format_version\": \"1.0.0\",\n")
3864     f.write("    \"ICD\": {\n")
3865     f.write("        \"library_path\": \".\\\\winevulkan.dll\",\n")
3866     f.write("        \"api_version\": \"{0}\"\n".format(VK_XML_VERSION))
3867     f.write("    }\n")
3868     f.write("}\n")
3870 def set_working_directory():
3871     path = os.path.abspath(__file__)
3872     path = os.path.dirname(path)
3873     os.chdir(path)
3875 def download_vk_xml(filename):
3876     url = "https://raw.githubusercontent.com/KhronosGroup/Vulkan-Docs/v{0}/xml/vk.xml".format(VK_XML_VERSION)
3877     if not os.path.isfile(filename):
3878         urllib.request.urlretrieve(url, filename)
3880 def main():
3881     parser = argparse.ArgumentParser()
3882     parser.add_argument("-v", "--verbose", action="count", default=0, help="increase output verbosity")
3883     parser.add_argument("-x", "--xml", default=None, type=str, help="path to specification XML file")
3885     args = parser.parse_args()
3886     if args.verbose == 0:
3887         LOGGER.setLevel(logging.WARNING)
3888     elif args.verbose == 1:
3889         LOGGER.setLevel(logging.INFO)
3890     else: # > 1
3891         LOGGER.setLevel(logging.DEBUG)
3893     set_working_directory()
3895     if args.xml:
3896         vk_xml = args.xml
3897     else:
3898         vk_xml = "vk-{0}.xml".format(VK_XML_VERSION)
3899         download_vk_xml(vk_xml)
3901     registry = VkRegistry(vk_xml)
3902     generator = VkGenerator(registry)
3904     with open(WINE_VULKAN_H, "w") as f:
3905         generator.generate_vulkan_h(f)
3907     with open(WINE_VULKAN_DRIVER_H, "w") as f:
3908         generator.generate_vulkan_driver_h(f)
3910     with open(WINE_VULKAN_THUNKS_H, "w") as f:
3911         generator.generate_thunks_h(f, "wine_")
3913     with open(WINE_VULKAN_THUNKS_C, "w") as f:
3914         generator.generate_thunks_c(f, "wine_")
3916     with open(WINE_VULKAN_LOADER_THUNKS_H, "w") as f:
3917         generator.generate_loader_thunks_h(f)
3919     with open(WINE_VULKAN_LOADER_THUNKS_C, "w") as f:
3920         generator.generate_loader_thunks_c(f)
3922     with open(WINE_VULKAN_JSON, "w") as f:
3923         generate_vulkan_json(f)
3925     with open(WINE_VULKAN_SPEC, "w") as f:
3926         generator.generate_vulkan_spec(f)
3928     with open(WINE_VULKAN_LOADER_SPEC, "w") as f:
3929         generator.generate_vulkan_loader_spec(f)
3931 if __name__ == "__main__":
3932     main()