winevulkan: Separate PE and Unix VkQueue structs.
[wine.git] / dlls / winevulkan / make_vulkan
blobcd03fb548bbf6a7df5b901cafe8642e87925f242
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.226"
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_metal_objects",
111     "VK_EXT_physical_device_drm",
112     "VK_GOOGLE_surfaceless_query",
113     "VK_KHR_external_fence_fd",
114     "VK_KHR_external_memory_fd",
115     "VK_KHR_external_semaphore_fd",
116     "VK_SEC_amigo_profiling", # Angle specific.
118     # Extensions which require callback handling
119     "VK_EXT_device_memory_report",
121     # Deprecated extensions
122     "VK_NV_external_memory_capabilities",
123     "VK_NV_external_memory_win32",
126 # Either internal extensions which aren't present on the win32 platform which
127 # winevulkan may nonetheless use, or extensions we want to generate headers for
128 # but not expose to applications (useful for test commits)
129 UNEXPOSED_EXTENSIONS = {
130     "VK_KHR_external_memory_win32",
133 # The Vulkan loader provides entry-points for core functionality and important
134 # extensions. Based on vulkan-1.def this amounts to WSI extensions on 1.0.51.
135 CORE_EXTENSIONS = [
136     "VK_KHR_display",
137     "VK_KHR_display_swapchain",
138     "VK_KHR_get_surface_capabilities2",
139     "VK_KHR_surface",
140     "VK_KHR_swapchain",
141     "VK_KHR_win32_surface",
144 # Some experimental extensions are used by shipping applications so their API is extremely unlikely
145 # to change in a backwards-incompatible way. Allow translation of those extensions with WineVulkan.
146 ALLOWED_X_EXTENSIONS = [
147     "VK_NVX_binary_import",
148     "VK_NVX_image_view_handle",
151 # Some frequently called functions use direct calls for performance reasons.
152 DIRECT_CALL_FUNCTIONS = [
153     "vkUpdateDescriptorSets",
154     "vkUpdateDescriptorSetWithTemplate",
157 # Functions part of our winevulkan graphics driver interface.
158 # DRIVER_VERSION should be bumped on any change to driver interface
159 # in FUNCTION_OVERRIDES
160 DRIVER_VERSION = 11
162 class ThunkType(Enum):
163     NONE = 1
164     PUBLIC = 2
165     PRIVATE = 3
167 # Table of functions for which we have a special implementation.
168 # These are regular device / instance functions for which we need
169 # to do more work compared to a regular thunk or because they are
170 # part of the driver interface.
171 # - dispatch set whether we need a function pointer in the device
172 #   / instance dispatch table.
173 # - driver sets whether the API is part of the driver interface.
174 # - thunk sets whether to create a thunk in vulkan_thunks.c.
175 #   - NONE means there's a fully custom implementation.
176 #   - PUBLIC means the implementation is fully auto generated.
177 #   - PRIVATE thunks can be used in custom implementations for
178 #     struct conversion.
179 # - loader_thunk sets whether to create a thunk for unix funcs.
180 FUNCTION_OVERRIDES = {
181     # Global functions
182     "vkCreateInstance" : {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE},
183     "vkEnumerateInstanceExtensionProperties" : {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE},
184     "vkEnumerateInstanceLayerProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.NONE},
185     "vkEnumerateInstanceVersion": {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE},
186     "vkGetInstanceProcAddr": {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.NONE},
188     # Instance functions
189     "vkCreateDevice" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE, "extra_param" : "client_ptr"},
190     "vkDestroyInstance" : {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE },
191     "vkEnumerateDeviceExtensionProperties" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
192     "vkEnumerateDeviceLayerProperties": {"dispatch": True, "driver": False, "thunk": ThunkType.NONE},
193     "vkEnumeratePhysicalDeviceGroups" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
194     "vkEnumeratePhysicalDevices" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
195     "vkGetPhysicalDeviceExternalBufferProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
196     "vkGetPhysicalDeviceExternalFenceProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
197     "vkGetPhysicalDeviceExternalSemaphoreProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
198     "vkGetPhysicalDeviceImageFormatProperties2" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE},
199     "vkGetPhysicalDeviceProperties2" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PUBLIC, "loader_thunk" : ThunkType.PRIVATE},
200     "vkGetPhysicalDeviceProperties2KHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PUBLIC, "loader_thunk" : ThunkType.PRIVATE},
202     # Device functions
203     "vkAllocateCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
204     "vkCreateCommandPool" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
205     "vkCreateComputePipelines" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.PRIVATE},
206     "vkCreateGraphicsPipelines" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.PRIVATE},
207     "vkDestroyCommandPool" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
208     "vkDestroyDevice" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE},
209     "vkFreeCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
210     "vkGetDeviceProcAddr" : {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.NONE},
211     "vkGetDeviceQueue" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
212     "vkGetDeviceQueue2" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
214     # VK_KHR_surface
215     "vkDestroySurfaceKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.NONE},
216     "vkGetPhysicalDeviceSurfaceSupportKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
217     "vkGetPhysicalDeviceSurfaceCapabilitiesKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PRIVATE},
218     "vkGetPhysicalDeviceSurfaceFormatsKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
219     "vkGetPhysicalDeviceSurfacePresentModesKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
221     # VK_KHR_get_surface_capabilities2
222     "vkGetPhysicalDeviceSurfaceCapabilities2KHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PRIVATE},
223     "vkGetPhysicalDeviceSurfaceFormats2KHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
225     # VK_KHR_win32_surface
226     "vkCreateWin32SurfaceKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.NONE},
227     "vkGetPhysicalDeviceWin32PresentationSupportKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
229     # VK_KHR_swapchain
230     "vkCreateSwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
231     "vkDestroySwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
232     "vkGetSwapchainImagesKHR": {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
233     "vkQueuePresentKHR": {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
235     # VK_KHR_external_fence_capabilities
236     "vkGetPhysicalDeviceExternalFencePropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
238     # VK_KHR_external_memory_capabilities
239     "vkGetPhysicalDeviceExternalBufferPropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
240     "vkGetPhysicalDeviceImageFormatProperties2KHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE},
242     # VK_KHR_external_semaphore_capabilities
243     "vkGetPhysicalDeviceExternalSemaphorePropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
245     # VK_KHR_device_group_creation
246     "vkEnumeratePhysicalDeviceGroupsKHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
248     # VK_KHR_device_group
249     "vkGetDeviceGroupSurfacePresentModesKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
250     "vkGetPhysicalDevicePresentRectanglesKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
252     # VK_KHR_ray_tracing_pipeline
253     "vkCreateRayTracingPipelinesKHR" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.PRIVATE},
255     # VK_EXT_calibrated_timestamps
256     "vkGetPhysicalDeviceCalibrateableTimeDomainsEXT" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
257     "vkGetCalibratedTimestampsEXT" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
259     # VK_EXT_debug_utils
260     "vkCreateDebugUtilsMessengerEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
261     "vkDestroyDebugUtilsMessengerEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
263     # VK_EXT_debug_report
264     "vkCreateDebugReportCallbackEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
265     "vkDestroyDebugReportCallbackEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
267     # VK_NV_ray_tracing
268     "vkCreateRayTracingPipelinesNV" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.PRIVATE},
271 STRUCT_CHAIN_CONVERSIONS = {
272     # Ignore to not confuse host loader.
273     "VkDeviceCreateInfo": ["VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO"],
274     "VkInstanceCreateInfo": ["VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO"],
278 class Direction(Enum):
279     """ Parameter direction: input, output, input_output. """
280     INPUT = 1
281     OUTPUT = 2
282     INPUT_OUTPUT = 3
285 class VkBaseType(object):
286     def __init__(self, name, _type, alias=None, requires=None):
287         """ Vulkan base type class.
289         VkBaseType is mostly used by Vulkan to define its own
290         base types like VkFlags through typedef out of e.g. uint32_t.
292         Args:
293             name (:obj:'str'): Name of the base type.
294             _type (:obj:'str'): Underlying type
295             alias (bool): type is an alias or not.
296             requires (:obj:'str', optional): Other types required.
297                 Often bitmask values pull in a *FlagBits type.
298         """
299         self.name = name
300         self.type = _type
301         self.alias = alias
302         self.requires = requires
303         self.required = False
305     def definition(self):
306         # Definition is similar for alias or non-alias as type
307         # is already set to alias.
308         if not self.type is None:
309             return "typedef {0} {1};\n".format(self.type, self.name)
310         else:
311             return "struct {0};\n".format(self.name)
313     def is_alias(self):
314         return bool(self.alias)
317 class VkConstant(object):
318     def __init__(self, name, value):
319         self.name = name
320         self.value = value
322     def definition(self):
323         text = "#define {0} {1}\n".format(self.name, self.value)
324         return text
327 class VkDefine(object):
328     def __init__(self, name, value):
329         self.name = name
330         self.value = value
332     @staticmethod
333     def from_xml(define):
334         name_elem = define.find("name")
336         if name_elem is None:
337             # <type category="define" name="some_name">some_value</type>
338             name = define.attrib.get("name")
340             # We override behavior of VK_USE_64_BIT_PTR_DEFINES as the default non-dispatchable handle
341             # definition various between 64-bit (uses pointers) and 32-bit (uses uint64_t).
342             # This complicates TRACEs in the thunks, so just use uint64_t.
343             if name == "VK_USE_64_BIT_PTR_DEFINES":
344                 value = "#define VK_USE_64_BIT_PTR_DEFINES 0"
345             else:
346                 value = define.text
347             return VkDefine(name, value)
349         # With a name element the structure is like:
350         # <type category="define"><name>some_name</name>some_value</type>
351         name = name_elem.text
353         # Perform minimal parsing for Vulkan constants, which we don't need, but are referenced
354         # elsewhere in vk.xml.
355         # - VK_API_VERSION is a messy, deprecated constant and we don't want generate code for it.
356         # - AHardwareBuffer/ANativeWindow are forward declarations for Android types, which leaked
357         #   into the define region.
358         if name in ["VK_API_VERSION", "AHardwareBuffer", "ANativeWindow", "CAMetalLayer"]:
359             return VkDefine(name, None)
361         # The body of the define is basically unstructured C code. It is not meant for easy parsing.
362         # Some lines contain deprecated values or comments, which we try to filter out.
363         value = ""
364         for line in define.text.splitlines():
365             # Skip comments or deprecated values.
366             if "//" in line:
367                 continue
368             value += line
370         for child in define:
371             value += child.text
372             if child.tail is not None:
373                 # Split comments for VK_API_VERSION_1_0 / VK_API_VERSION_1_1
374                 if "//" in child.tail:
375                     value += child.tail.split("//")[0]
376                 else:
377                     value += child.tail
379         return VkDefine(name, value.rstrip(' '))
381     def definition(self):
382         if self.value is None:
383             return ""
385         # Nothing to do as the value was already put in the right form during parsing.
386         return "{0}\n".format(self.value)
389 class VkEnum(object):
390     def __init__(self, name, bitwidth, alias=None):
391         if not bitwidth in [32, 64]:
392             LOGGER.error("unknown bitwidth {0} for {1}".format(bitwidth, name))
393         self.name = name
394         self.bitwidth = bitwidth
395         self.values = [] if alias == None else alias.values
396         self.required = False
397         self.alias = alias
398         self.aliased_by = []
400     @staticmethod
401     def from_alias(enum, alias):
402         name = enum.attrib.get("name")
403         aliasee = VkEnum(name, alias.bitwidth, alias=alias)
405         alias.add_aliased_by(aliasee)
406         return aliasee
408     @staticmethod
409     def from_xml(enum):
410         name = enum.attrib.get("name")
411         bitwidth = int(enum.attrib.get("bitwidth", "32"))
412         result = VkEnum(name, bitwidth)
414         for v in enum.findall("enum"):
415             value_name = v.attrib.get("name")
416             # Value is either a value or a bitpos, only one can exist.
417             value = v.attrib.get("value")
418             alias_name = v.attrib.get("alias")
419             if alias_name:
420                 result.create_alias(value_name, alias_name)
421             elif value:
422                 result.create_value(value_name, value)
423             else:
424                 # bitmask
425                 result.create_bitpos(value_name, int(v.attrib.get("bitpos")))
427         if bitwidth == 32:
428             # vulkan.h contains a *_MAX_ENUM value set to 32-bit at the time of writing,
429             # which is to prepare for extensions as they can add values and hence affect
430             # the size definition.
431             max_name = re.sub(r'([0-9a-z_])([A-Z0-9])',r'\1_\2', name).upper() + "_MAX_ENUM"
432             result.create_value(max_name, "0x7fffffff")
434         return result
436     def create_alias(self, name, alias_name):
437         """ Create an aliased value for this enum """
438         self.add(VkEnumValue(name, self.bitwidth, alias=alias_name))
440     def create_value(self, name, value):
441         """ Create a new value for this enum """
442         # Some values are in hex form. We want to preserve the hex representation
443         # at least when we convert back to a string. Internally we want to use int.
444         hex = "0x" in value
445         self.add(VkEnumValue(name, self.bitwidth, value=int(value, 0), hex=hex))
447     def create_bitpos(self, name, pos):
448         """ Create a new bitmask value for this enum """
449         self.add(VkEnumValue(name, self.bitwidth, value=(1 << pos), hex=True))
451     def add(self, value):
452         """ Add a value to enum. """
454         # Extensions can add new enum values. When an extension is promoted to Core
455         # the registry defines the value twice once for old extension and once for
456         # new Core features. Add the duplicate if it's explicitly marked as an
457         # alias, otherwise ignore it.
458         for v in self.values:
459             if not value.is_alias() and v.value == value.value:
460                 LOGGER.debug("Adding duplicate enum value {0} to {1}".format(v, self.name))
461                 return
462         # Avoid adding duplicate aliases multiple times
463         if not any(x.name == value.name for x in self.values):
464             self.values.append(value)
466     def fixup_64bit_aliases(self):
467         """ Replace 64bit aliases with literal values """
468         # Older GCC versions need a literal to initialize a static const uint64_t
469         # which is what we use for 64bit bitmasks.
470         if self.bitwidth != 64:
471             return
472         for value in self.values:
473             if not value.is_alias():
474                 continue
475             alias = next(x for x in self.values if x.name == value.alias)
476             value.hex = alias.hex
477             value.value = alias.value
479     def definition(self):
480         if self.is_alias():
481             return ""
483         default_value = 0x7ffffffe if self.bitwidth == 32 else 0xfffffffffffffffe
485         # Print values sorted, values can have been added in a random order.
486         values = sorted(self.values, key=lambda value: value.value if value.value is not None else default_value)
488         if self.bitwidth == 32:
489             text = "typedef enum {0}\n{{\n".format(self.name)
490             for value in values:
491                 text += "    {0},\n".format(value.definition())
492             text += "}} {0};\n".format(self.name)
493         elif self.bitwidth == 64:
494             text = "typedef VkFlags64 {0};\n\n".format(self.name)
495             for value in values:
496                 text += "static const {0} {1};\n".format(self.name, value.definition())
498         for aliasee in self.aliased_by:
499             text += "typedef {0} {1};\n".format(self.name, aliasee.name)
501         text += "\n"
502         return text
504     def is_alias(self):
505         return bool(self.alias)
507     def add_aliased_by(self, aliasee):
508         self.aliased_by.append(aliasee)
511 class VkEnumValue(object):
512     def __init__(self, name, bitwidth, value=None, hex=False, alias=None):
513         self.name = name
514         self.bitwidth = bitwidth
515         self.value = value
516         self.hex = hex
517         self.alias = alias
519     def __repr__(self):
520         postfix = "ull" if self.bitwidth == 64 else ""
521         if self.is_alias() and self.value == None:
522             return "{0}={1}".format(self.name, self.alias)
523         return "{0}={1}{2}".format(self.name, self.value, postfix)
525     def definition(self):
526         """ Convert to text definition e.g. VK_FOO = 1 """
527         postfix = "ull" if self.bitwidth == 64 else ""
528         if self.is_alias() and self.value == None:
529             return "{0} = {1}".format(self.name, self.alias)
531         # Hex is commonly used for FlagBits and sometimes within
532         # a non-FlagBits enum for a bitmask value as well.
533         if self.hex:
534             return "{0} = 0x{1:08x}{2}".format(self.name, self.value, postfix)
535         else:
536             return "{0} = {1}{2}".format(self.name, self.value, postfix)
538     def is_alias(self):
539         return self.alias is not None
542 class VkFunction(object):
543     def __init__(self, _type=None, name=None, params=[], alias=None):
544         self.extensions = set()
545         self.name = name
546         self.type = _type
547         self.params = params
548         self.alias = alias
550         # For some functions we need some extra metadata from FUNCTION_OVERRIDES.
551         func_info = FUNCTION_OVERRIDES.get(self.name, None)
552         self.dispatch = func_info["dispatch"] if func_info else True
553         self.driver = func_info["driver"] if func_info else False
554         self.thunk_type = func_info["thunk"] if func_info else ThunkType.PUBLIC
555         self.loader_thunk_type = func_info["loader_thunk"] if func_info and "loader_thunk" in func_info else ThunkType.PUBLIC
556         self.extra_param = func_info["extra_param"] if func_info and "extra_param" in func_info else None
558         # Required is set while parsing which APIs and types are required
559         # and is used by the code generation.
560         self.required = True if func_info else False
562     @staticmethod
563     def from_alias(command, alias):
564         """ Create VkFunction from an alias command.
566         Args:
567             command: xml data for command
568             alias (VkFunction): function to use as a base for types / parameters.
570         Returns:
571             VkFunction
572         """
573         func_name = command.attrib.get("name")
574         func_type = alias.type
575         params = alias.params
577         return VkFunction(_type=func_type, name=func_name, params=params, alias=alias)
579     @staticmethod
580     def from_xml(command, types):
581         proto = command.find("proto")
582         func_name = proto.find("name").text
583         func_type = proto.find("type").text
585         params = []
586         for param in command.findall("param"):
587             vk_param = VkParam.from_xml(param, types)
588             params.append(vk_param)
590         return VkFunction(_type=func_type, name=func_name, params=params)
592     def get_conversions(self):
593         """ Get a list of conversion functions required for this function if any.
594         Parameters which are structures may require conversion between win32
595         and the host platform. This function returns a list of conversions
596         required.
597         """
599         conversions = []
600         for param in self.params:
601             convs = param.get_conversions()
602             if convs is not None:
603                 conversions.extend(convs)
605         return conversions
607     def is_alias(self):
608         return bool(self.alias)
610     def is_core_func(self):
611         """ Returns whether the function is a Vulkan core function.
612         Core functions are APIs defined by the Vulkan spec to be part of the
613         Core API as well as several KHR WSI extensions.
614         """
616         if not self.extensions:
617             return True
619         return any(ext in self.extensions for ext in CORE_EXTENSIONS)
621     def is_device_func(self):
622         # If none of the other, it must be a device function
623         return not self.is_global_func() and not self.is_instance_func() and not self.is_phys_dev_func()
625     def is_driver_func(self):
626         """ Returns if function is part of Wine driver interface. """
627         return self.driver
629     def is_global_func(self):
630         # Treat vkGetInstanceProcAddr as a global function as it
631         # can operate with NULL for vkInstance.
632         if self.name == "vkGetInstanceProcAddr":
633             return True
634         # Global functions are not passed a dispatchable object.
635         elif self.params[0].is_dispatchable():
636             return False
637         return True
639     def is_instance_func(self):
640         # Instance functions are passed VkInstance.
641         if self.params[0].type == "VkInstance":
642             return True
643         return False
645     def is_phys_dev_func(self):
646         # Physical device functions are passed VkPhysicalDevice.
647         if self.params[0].type == "VkPhysicalDevice":
648             return True
649         return False
651     def is_required(self):
652         return self.required
654     def returns_longlong(self):
655         return self.type in ["uint64_t", "VkDeviceAddress"]
657     def needs_conversion(self):
658         """ Check if the function needs any input/output type conversion.
659         Functions need input/output conversion if struct parameters have
660         alignment differences between Win32 and Linux 32-bit.
661         """
663         for p in self.params:
664             if p.needs_conversion():
665                 LOGGER.debug("Parameter {0} to {1} requires conversion".format(p.name, self.name))
666                 return True
668         return False
670     def needs_unwrapping(self):
671         """ Check if the function needs any input/output type unwrapping.
672         Functions need input/output unwrapping if struct parameters have
673         wrapped handles.
674         """
676         for p in self.params:
677             if p.needs_unwrapping():
678                 return True
680         return False
682     def needs_dispatch(self):
683         return self.dispatch
685     def needs_thunk(self):
686         return self.thunk_type != ThunkType.NONE
688     def needs_private_thunk(self):
689         return self.thunk_type == ThunkType.PRIVATE
691     def needs_exposing(self):
692         # The function needs exposed if at-least one extension isn't both UNSUPPORTED and UNEXPOSED
693         return self.is_required() and (not self.extensions or not self.extensions.issubset(UNEXPOSED_EXTENSIONS))
695     def needs_direct_call(self):
696         # vkCmd* functions are frequently called, use direct calls for performance
697         if self.name.startswith("vkCmd"):
698             return True
699         return self.name in DIRECT_CALL_FUNCTIONS
701     def pfn(self, prefix="p", call_conv=None, conv=False):
702         """ Create function pointer. """
704         if call_conv:
705             pfn = "{0} ({1} *{2}_{3})(".format(self.type, call_conv, prefix, self.name)
706         else:
707             pfn = "{0} (*{1}_{2})(".format(self.type, prefix, self.name)
709         for i, param in enumerate(self.params):
710             if param.const:
711                 pfn += param.const + " "
713             pfn += param.type
714             if conv and param.needs_conversion():
715                 pfn += "_host"
717             if param.is_pointer():
718                 pfn += " " + param.pointer
720             if param.array_len is not None:
721                 pfn += "[{0}]".format(param.array_len)
723             if i < len(self.params) - 1:
724                 pfn += ", "
725         pfn += ")"
726         return pfn
728     def prototype(self, call_conv=None, prefix=None, postfix=None):
729         """ Generate prototype for given function.
731         Args:
732             call_conv (str, optional): calling convention e.g. WINAPI
733             prefix (str, optional): prefix to append prior to function name e.g. vkFoo -> wine_vkFoo
734             postfix (str, optional): text to append after function name but prior to semicolon e.g. DECLSPEC_HIDDEN
735         """
737         proto = "{0}".format(self.type)
739         if call_conv is not None:
740             proto += " {0}".format(call_conv)
742         if prefix is not None:
743             proto += " {0}{1}(".format(prefix, self.name)
744         else:
745             proto += " {0}(".format(self.name)
747         # Add all the parameters.
748         proto += ", ".join([p.definition() for p in self.params])
750         if postfix is not None:
751             proto += ") {0}".format(postfix)
752         else:
753             proto += ")"
755         return proto
757     def body(self, params_prefix=""):
758         body = ""
760         if not self.needs_private_thunk():
761             body += "    {0}".format(self.trace(params_prefix=params_prefix))
763         params = ", ".join([p.variable(conv=False, params_prefix=params_prefix) for p in self.params])
765         # Call the native Vulkan function.
766         body += "    "
767         if self.returns_longlong():
768             body += "{0}result = ".format(params_prefix)
769         elif self.type != "void":
770             body += "return "
771         body += "{0}.p_{1}({2});\n".format(self.params[0].dispatch_table(params_prefix),
772                                            self.name, params)
773         if self.type == "void" or self.returns_longlong():
774             body += "    return STATUS_SUCCESS;\n"
776         return body
778     def loader_body(self):
779         body = "    struct {0}_params params;\n".format(self.name)
780         for p in self.params:
781             body += "    params.{0} = {0};\n".format(p.name)
782         body += "    ";
784         # Call the Unix function.
785         if self.type != "void" and not self.returns_longlong():
786             body += "return "
787         if self.needs_direct_call():
788             body += "p_vk_direct_unix_call(unix_handle, unix_{0}, &params);\n".format(self.name)
789         else:
790             body += "vk_unix_call(unix_{0}, &params);\n".format(self.name)
791         if self.returns_longlong():
792             body += "    return params.result;\n"
793         return body
795     def body_conversion(self, conv, params_prefix=""):
796         body = ""
797         result_prefix = ""
799         # Declare a variable to hold the result for non-void functions.
800         if self.returns_longlong():
801             result_prefix = "params->"
802         elif self.type != "void":
803             body += "    {0} result;\n".format(self.type)
805         # Declare any tmp parameters for conversion.
806         for p in self.params:
807             if p.needs_conversion() and conv:
808                 if p.is_dynamic_array():
809                     body += "    {0}_host *{1}_host;\n".format(p.type, p.name)
810                 else:
811                     body += "    {0}_host {1}_host;\n".format(p.type, p.name)
812             elif p.needs_unwrapping():
813                 if p.is_dynamic_array():
814                     body += "    {0} *{1}_host;\n".format(p.type, p.name)
815                 else:
816                     body += "    {0} {1}_host;\n".format(p.type, p.name)
818         if not self.needs_private_thunk():
819             body += "    {0}\n".format(self.trace(params_prefix=params_prefix))
821         # Call any win_to_host conversion calls.
822         for p in self.params:
823             if p.needs_input_conversion() and (p.needs_unwrapping() or conv):
824                 body += p.copy(Direction.INPUT, prefix=params_prefix)
826         # Build list of parameters containing converted and non-converted parameters.
827         # The param itself knows if conversion is needed and applies it when we set conv=True.
828         params = ", ".join([p.variable(conv=conv, params_prefix=params_prefix) for p in self.params])
830         # Call the native Vulkan function.
831         if self.type == "void":
832             body += "    {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(params_prefix),
833                                                    self.name, params)
834         else:
835             body += "    {0}result = {1}.p_{2}({3});\n".format(result_prefix,
836                                                                self.params[0].dispatch_table(params_prefix),
837                                                                self.name, params)
839         body += "\n"
841         # Call any host_to_win conversion calls.
842         for p in self.params:
843             if not p.needs_output_conversion():
844                 continue
846             body += p.copy(Direction.OUTPUT, prefix=params_prefix)
848         # Perform any required cleanups. Most of these are for array functions.
849         for p in self.params:
850             if p.needs_free() and (p.needs_unwrapping() or conv):
851                 body += p.free(prefix=params_prefix)
853         # Finally return the result.
854         if self.type != "void" and not self.returns_longlong():
855             body += "    return result;\n"
856         else:
857             body += "    return STATUS_SUCCESS;\n"
859         return body
861     def spec(self, prefix=None, symbol=None):
862         """ Generate spec file entry for this function.
864         Args
865             prefix (str, optional): prefix to prepend to entry point name.
866             symbol (str, optional): allows overriding the name of the function implementing the entry point.
867         """
869         spec = ""
870         params = " ".join([p.spec() for p in self.params])
871         if prefix is not None:
872             spec += "@ stdcall -private {0}{1}({2})".format(prefix, self.name, params)
873         else:
874             spec += "@ stdcall {0}({1})".format(self.name, params)
876         if symbol is not None:
877             spec += " " + symbol
879         spec += "\n"
880         return spec
882     def stub(self, call_conv=None, prefix=None):
883         stub = self.prototype(call_conv=call_conv, prefix=prefix)
884         stub += "\n{\n"
885         stub += "    {0}".format(self.trace(message="stub: ", trace_func="FIXME"))
887         if self.type == "VkResult":
888             stub += "    return VK_ERROR_OUT_OF_HOST_MEMORY;\n"
889         elif self.type == "VkBool32":
890             stub += "    return VK_FALSE;\n"
891         elif self.type == "PFN_vkVoidFunction":
892             stub += "    return NULL;\n"
894         stub += "}\n\n"
895         return stub
897     def thunk(self, prefix=None):
898         if prefix == "thunk_":
899             thunk = self.prototype(prefix=prefix)
900             thunk += "\n{\n"
901             params_prefix = ""
902         else:
903             thunk = "NTSTATUS {0}{1}(void *args)\n".format(prefix, self.name)
904             thunk += "{\n"
905             thunk += "    struct {0}_params *params = args;\n".format(self.name)
906             params_prefix = "params->"
908         if self.needs_conversion():
909             thunk += "#if defined(USE_STRUCT_CONVERSION)\n"
910             thunk += self.body_conversion(conv=True, params_prefix=params_prefix)
911             thunk += "#else\n"
912             if self.needs_unwrapping():
913                 thunk += self.body_conversion(conv=False, params_prefix=params_prefix)
914             else:
915                 thunk += self.body(params_prefix=params_prefix)
916             thunk += "#endif\n"
917         elif self.needs_unwrapping():
918             thunk += self.body_conversion(conv=False, params_prefix=params_prefix)
919         else:
920             thunk += self.body(params_prefix=params_prefix)
922         thunk += "}\n\n"
923         return thunk
925     def loader_thunk(self, prefix=None):
926         thunk = self.prototype(call_conv="WINAPI", prefix=prefix)
927         thunk += "\n{\n"
928         thunk += self.loader_body()
929         thunk += "}\n\n"
930         return thunk
932     def trace(self, message=None, trace_func=None, params_prefix=""):
933         """ Create a trace string including all parameters.
935         Args:
936             message (str, optional): text to print at start of trace message e.g. 'stub: '
937             trace_func (str, optional): used to override trace function e.g. FIXME, printf, etcetera.
938         """
939         if trace_func is not None:
940             trace = "{0}(\"".format(trace_func)
941         else:
942             trace = "TRACE(\""
944         if message is not None:
945             trace += message
947         # First loop is for all the format strings.
948         trace += ", ".join([p.format_string() for p in self.params])
949         trace += "\\n\""
951         # Second loop for parameter names and optional conversions.
952         for param in self.params:
953             if param.format_conv is not None:
954                 trace += ", " + param.format_conv.format("{0}{1}".format(params_prefix, param.name))
955             else:
956                 trace += ", {0}{1}".format(params_prefix, param.name)
957         trace += ");\n"
959         return trace
962 class VkFunctionPointer(object):
963     def __init__(self, _type, name, members, forward_decls):
964         self.name = name
965         self.members = members
966         self.type = _type
967         self.required = False
968         self.forward_decls = forward_decls
970     @staticmethod
971     def from_xml(funcpointer):
972         members = []
973         begin = None
975         for t in funcpointer.findall("type"):
976             # General form:
977             # <type>void</type>*       pUserData,
978             # Parsing of the tail (anything past </type>) is tricky since there
979             # can be other data on the next line like: const <type>int</type>..
981             const = True if begin and "const" in begin else False
982             _type = t.text
983             lines = t.tail.split(",\n")
984             if lines[0][0] == "*":
985                 pointer = "*"
986                 name = lines[0][1:].strip()
987             else:
988                 pointer = None
989                 name = lines[0].strip()
991             # Filter out ); if it is contained.
992             name = name.partition(");")[0]
994             # If tail encompasses multiple lines, assign the second line to begin
995             # for the next line.
996             try:
997                 begin = lines[1].strip()
998             except IndexError:
999                 begin = None
1001             members.append(VkMember(const=const, _type=_type, pointer=pointer, name=name))
1003         _type = funcpointer.text
1004         name = funcpointer.find("name").text
1005         if "requires" in funcpointer.attrib:
1006             forward_decls = funcpointer.attrib.get("requires").split(",")
1007         else:
1008             forward_decls = []
1009         return VkFunctionPointer(_type, name, members, forward_decls)
1011     def definition(self):
1012         text = ""
1013         # forward declare required structs
1014         for decl in self.forward_decls:
1015             text += "typedef struct {0} {0};\n".format(decl)
1017         text += "{0} {1})(\n".format(self.type, self.name)
1019         first = True
1020         if len(self.members) > 0:
1021             for m in self.members:
1022                 if first:
1023                     text += "    " + m.definition()
1024                     first = False
1025                 else:
1026                     text += ",\n    " + m.definition()
1027         else:
1028             # Just make the compiler happy by adding a void parameter.
1029             text += "void"
1030         text += ");\n"
1031         return text
1033     def is_alias(self):
1034         return False
1036 class VkHandle(object):
1037     def __init__(self, name, _type, parent, alias=None):
1038         self.name = name
1039         self.type = _type
1040         self.parent = parent
1041         self.alias = alias
1042         self.required = False
1043         self.object_type = None
1045     @staticmethod
1046     def from_alias(handle, alias):
1047         name = handle.attrib.get("name")
1048         return VkHandle(name, alias.type, alias.parent, alias=alias)
1050     @staticmethod
1051     def from_xml(handle):
1052         name = handle.find("name").text
1053         _type = handle.find("type").text
1054         parent = handle.attrib.get("parent") # Most objects have a parent e.g. VkQueue has VkDevice.
1055         return VkHandle(name, _type, parent)
1057     def dispatch_table(self, param):
1058         if not self.is_dispatchable():
1059             return None
1061         if self.parent is None:
1062             # Should only happen for VkInstance
1063             return "{0}->funcs".format(param)
1064         elif self.name == "VkDevice":
1065             return "wine_device_from_handle({0})->funcs".format(param)
1066         elif self.name == "VkQueue":
1067             return "wine_queue_from_handle({0})->device->funcs".format(param)
1068         elif self.parent in ["VkInstance", "VkPhysicalDevice"]:
1069             return "{0}->instance->funcs".format(param)
1070         elif self.parent in ["VkDevice", "VkCommandPool"]:
1071             return "{0}->device->funcs".format(param)
1072         else:
1073             LOGGER.error("Unhandled dispatchable parent: {0}".format(self.parent))
1075     def definition(self):
1076         """ Generates handle definition e.g. VK_DEFINE_HANDLE(vkInstance) """
1078         # Legacy types are typedef'ed to the new type if they are aliases.
1079         if self.is_alias():
1080             return "typedef {0} {1};\n".format(self.alias.name, self.name)
1082         return "{0}({1})\n".format(self.type, self.name)
1084     def is_alias(self):
1085         return self.alias is not None
1087     def is_dispatchable(self):
1088         """ Some handles like VkInstance, VkDevice are dispatchable objects,
1089         which means they contain a dispatch table of function pointers.
1090         """
1091         return self.type == "VK_DEFINE_HANDLE"
1093     def is_required(self):
1094         return self.required
1096     def native_handle(self, name):
1097         """ Provide access to the native handle of a wrapped object. """
1099         if self.name == "VkCommandPool":
1100             return "wine_cmd_pool_from_handle({0})->command_pool".format(name)
1101         if self.name == "VkDebugUtilsMessengerEXT":
1102             return "wine_debug_utils_messenger_from_handle({0})->debug_messenger".format(name)
1103         if self.name == "VkDebugReportCallbackEXT":
1104             return "wine_debug_report_callback_from_handle({0})->debug_callback".format(name)
1105         if self.name == "VkDevice":
1106             return "wine_device_from_handle({0})->device".format(name)
1107         if self.name == "VkQueue":
1108             return "wine_queue_from_handle({0})->queue".format(name)
1109         if self.name == "VkSurfaceKHR":
1110             return "wine_surface_from_handle({0})->surface".format(name)
1112         native_handle_name = None
1114         if self.name == "VkCommandBuffer":
1115             native_handle_name = "command_buffer"
1116         if self.name == "VkInstance":
1117             native_handle_name = "instance"
1118         if self.name == "VkPhysicalDevice":
1119             native_handle_name = "phys_dev"
1121         if native_handle_name:
1122             return "{0}->{1}".format(name, native_handle_name)
1124         if self.is_dispatchable():
1125             LOGGER.error("Unhandled native handle for: {0}".format(self.name))
1126         return None
1128     def driver_handle(self, name):
1129         """ Provide access to the handle that should be passed to the wine driver """
1131         if self.name == "VkSurfaceKHR":
1132             return "wine_surface_from_handle({0})->driver_surface".format(name)
1134         return self.native_handle(name)
1136     def is_wrapped(self):
1137         return self.native_handle("test") is not None
1139     def needs_conversion(self):
1140         return False
1142     def needs_unwrapping(self):
1143         return self.is_wrapped()
1145 class VkMember(object):
1146     def __init__(self, const=False, struct_fwd_decl=False,_type=None, pointer=None, name=None, array_len=None,
1147             dyn_array_len=None, optional=False, values=None, object_type=None, bit_width=None):
1148         self.const = const
1149         self.struct_fwd_decl = struct_fwd_decl
1150         self.name = name
1151         self.pointer = pointer
1152         self.type = _type
1153         self.type_info = None
1154         self.array_len = array_len
1155         self.dyn_array_len = dyn_array_len
1156         self.optional = optional
1157         self.values = values
1158         self.object_type = object_type
1159         self.bit_width = bit_width
1161     def __eq__(self, other):
1162         """ Compare member based on name against a string.
1164         This method is for convenience by VkStruct, which holds a number of members and needs quick checking
1165         if certain members exist.
1166         """
1168         return self.name == other
1170     def __repr__(self):
1171         return "{0} {1} {2} {3} {4} {5} {6}".format(self.const, self.struct_fwd_decl, self.type, self.pointer,
1172                 self.name, self.array_len, self.dyn_array_len)
1174     @staticmethod
1175     def from_xml(member):
1176         """ Helper function for parsing a member tag within a struct or union. """
1178         name_elem = member.find("name")
1179         type_elem = member.find("type")
1181         const = False
1182         struct_fwd_decl = False
1183         member_type = None
1184         pointer = None
1185         array_len = None
1186         bit_width = None
1188         values = member.get("values")
1190         if member.text:
1191             if "const" in member.text:
1192                 const = True
1194             # Some members contain forward declarations:
1195             # - VkBaseInstructure has a member "const struct VkBaseInStructure *pNext"
1196             # - VkWaylandSurfaceCreateInfoKHR has a member "struct wl_display *display"
1197             if "struct" in member.text:
1198                 struct_fwd_decl = True
1200         if type_elem is not None:
1201             member_type = type_elem.text
1202             if type_elem.tail is not None:
1203                 pointer = type_elem.tail.strip() if type_elem.tail.strip() != "" else None
1205         # Name of other member within, which stores the number of
1206         # elements pointed to be by this member.
1207         dyn_array_len = member.get("len")
1209         # Some members are optional, which is important for conversion code e.g. not dereference NULL pointer.
1210         optional = True if member.get("optional") else False
1212         # Usually we need to allocate memory for dynamic arrays. We need to do the same in a few other cases
1213         # like for VkCommandBufferBeginInfo.pInheritanceInfo. Just threat such cases as dynamic arrays of
1214         # size 1 to simplify code generation.
1215         if dyn_array_len is None and pointer is not None:
1216             dyn_array_len = 1
1218         # Some members are arrays, attempt to parse these. Formats include:
1219         # <member><type>char</type><name>extensionName</name>[<enum>VK_MAX_EXTENSION_NAME_SIZE</enum>]</member>
1220         # <member><type>uint32_t</type><name>foo</name>[4]</member>
1221         if name_elem.tail and name_elem.tail[0] == '[':
1222             LOGGER.debug("Found array type")
1223             enum_elem = member.find("enum")
1224             if enum_elem is not None:
1225                 array_len = enum_elem.text
1226             else:
1227                 # Remove brackets around length
1228                 array_len = name_elem.tail.strip("[]")
1230         object_type = member.get("objecttype", None)
1232         # Some members are bit field values:
1233         # <member><type>uint32_t</type> <name>mask</name>:8</member>
1234         if name_elem.tail and name_elem.tail[0] == ':':
1235             LOGGER.debug("Found bit field")
1236             bit_width = int(name_elem.tail[1:])
1238         return VkMember(const=const, struct_fwd_decl=struct_fwd_decl, _type=member_type, pointer=pointer, name=name_elem.text,
1239                 array_len=array_len, dyn_array_len=dyn_array_len, optional=optional, values=values, object_type=object_type, bit_width=bit_width)
1241     def copy(self, input, output, direction, conv):
1242         """ Helper method for use by conversion logic to generate a C-code statement to copy this member.
1243             - `conv` indicates whether the statement is in a struct alignment conversion path. """
1245         if (conv and self.needs_conversion()) or self.needs_unwrapping():
1246             if self.is_dynamic_array():
1247                 if direction == Direction.OUTPUT:
1248                     LOGGER.warn("TODO: implement copying of returnedonly dynamic array for {0}.{1}".format(self.type, self.name))
1249                 else:
1250                     # Array length is either a variable name (string) or an int.
1251                     count = self.dyn_array_len if isinstance(self.dyn_array_len, int) else "{0}{1}".format(input, self.dyn_array_len)
1252                     return "{0}{1} = convert_{2}_array_win_to_host({3}{1}, {4});\n".format(output, self.name, self.type, input, count)
1253             elif self.is_static_array():
1254                 count = self.array_len
1255                 if direction == Direction.OUTPUT:
1256                     # Needed by VkMemoryHeap.memoryHeaps
1257                     return "convert_{0}_static_array_host_to_win({2}{1}, {3}{1}, {4});\n".format(self.type, self.name, input, output, count)
1258                 else:
1259                     # Nothing needed this yet.
1260                     LOGGER.warn("TODO: implement copying of static array for {0}.{1}".format(self.type, self.name))
1261             elif self.is_handle() and self.needs_unwrapping():
1262                 if direction == Direction.OUTPUT:
1263                     LOGGER.err("OUTPUT parameter {0}.{1} cannot be unwrapped".format(self.type, self.name))
1264                 else:
1265                     handle = self.type_info["data"]
1266                     return "{0}{1} = {2};\n".format(output, self.name, handle.driver_handle("{0}{1}".format(input, self.name)))
1267             elif self.is_generic_handle():
1268                 if direction == Direction.OUTPUT:
1269                     LOGGER.err("OUTPUT parameter {0}.{1} cannot be unwrapped".format(self.type, self.name))
1270                 else:
1271                     return "{0}{1} = wine_vk_unwrap_handle({2}{3}, {2}{1});\n".format(output, self.name, input, self.object_type)
1272             else:
1273                 if direction == Direction.OUTPUT:
1274                     return "convert_{0}_host_to_win(&{2}{1}, &{3}{1});\n".format(self.type, self.name, input, output)
1275                 else:
1276                     return "convert_{0}_win_to_host(&{2}{1}, &{3}{1});\n".format(self.type, self.name, input, output)
1277         elif self.is_static_array():
1278             bytes_count = "{0} * sizeof({1})".format(self.array_len, self.type)
1279             return "memcpy({0}{1}, {2}{1}, {3});\n".format(output, self.name, input, bytes_count)
1280         else:
1281             return "{0}{1} = {2}{1};\n".format(output, self.name, input)
1283     def free(self, location, conv):
1284         """ Helper method for use by conversion logic to generate a C-code statement to free this member. """
1286         if not self.needs_unwrapping() and not conv:
1287             return ""
1289         # Add a cast to ignore const on conversion structs we allocated ourselves.
1290         # sample expected output: (VkSparseMemoryBind_host *)
1291         if self.is_const():
1292             cast = "(" + self.type
1293             if self.needs_conversion() and conv:
1294                 cast += "_host"
1295             cast += " *)"
1296         else:
1297             cast = ""
1299         if self.is_dynamic_array():
1300             count = self.dyn_array_len if isinstance(self.dyn_array_len, int) else "{0}{1}".format(location, self.dyn_array_len)
1301             if self.is_struct() and self.type_info["data"].returnedonly:
1302                 # For returnedonly, counts is stored in a pointer.
1303                 return "free_{0}_array({1}{2}{3}, *{4});\n".format(self.type, cast, location, self.name, count)
1304             else:
1305                 return "free_{0}_array({1}{2}{3}, {4});\n".format(self.type, cast, location, self.name, count)
1306         else:
1307             # We are operating on a single structure. Some structs (very rare) contain dynamic members,
1308             # which would need freeing.
1309             if self.needs_free():
1310                 return "free_{0}({1}&{2}{3});\n".format(self.type, cast, location, self.name)
1311         return ""
1313     def definition(self, align=False, conv=False):
1314         """ Generate prototype for given function.
1316         Args:
1317             align (bool, optional): Enable alignment if a type needs it. This adds WINE_VK_ALIGN(8) to a member.
1318             conv (bool, optional): Enable conversion if a type needs it. This appends '_host' to the name.
1319         """
1321         text = ""
1322         if self.is_const():
1323             text += "const "
1325         if self.is_struct_forward_declaration():
1326             text += "struct "
1328         if conv and self.is_struct():
1329             text += "{0}_host".format(self.type)
1330         else:
1331             text += self.type
1333         if self.is_pointer():
1334             text += " {0}{1}".format(self.pointer, self.name)
1335         else:
1336             if align and self.needs_alignment():
1337                 text += " WINE_VK_ALIGN(8) " + self.name
1338             else:
1339                 text += " " + self.name
1341         if self.is_static_array():
1342             text += "[{0}]".format(self.array_len)
1344         if self.is_bit_field():
1345             text += ":{}".format(self.bit_width)
1347         return text
1349     def get_conversions(self):
1350         """ Return any conversion description for this member and its children when conversion is needed. """
1352         # Check if we need conversion either for this member itself or for any child members
1353         # in case member represents a struct.
1354         if not self.needs_conversion() and not self.needs_unwrapping():
1355             return None
1357         conversions = []
1359         # Collect any conversion for any member structs.
1360         if self.is_struct():
1361             struct = self.type_info["data"]
1362             for m in struct:
1363                 m.needs_struct_extensions_conversion()
1364                 if m.needs_conversion() or m.needs_unwrapping():
1365                     conversions.extend(m.get_conversions())
1367             struct.needs_struct_extensions_conversion()
1368             direction = Direction.OUTPUT if struct.returnedonly else Direction.INPUT
1369         elif self.is_handle() or self.is_generic_handle():
1370             direction = Direction.INPUT
1372         operand = self.type_info["data"]
1373         if self.is_dynamic_array():
1374             conversions.append(ConversionFunction(False, True, direction, operand))
1375         elif self.is_static_array():
1376             conversions.append(ConversionFunction(True, False, direction, operand))
1377         else:
1378             conversions.append(ConversionFunction(False, False, direction, operand))
1380         if self.needs_free():
1381             conversions.append(FreeFunction(self.is_dynamic_array(), operand))
1383         return conversions
1385     def is_const(self):
1386         return self.const
1388     def is_dynamic_array(self):
1389         """ Returns if the member is an array element.
1390         Vulkan uses this for dynamically sized arrays for which
1391         there is a 'count' parameter.
1392         """
1393         return self.dyn_array_len is not None
1395     def is_handle(self):
1396         return self.type_info["category"] == "handle"
1398     def is_pointer(self):
1399         return self.pointer is not None
1401     def is_static_array(self):
1402         """ Returns if the member is an array.
1403         Vulkan uses this often for fixed size arrays in which the
1404         length is part of the member.
1405         """
1406         return self.array_len is not None
1408     def is_struct(self):
1409         return self.type_info["category"] == "struct"
1411     def is_struct_forward_declaration(self):
1412         return self.struct_fwd_decl
1414     def is_union(self):
1415         return self.type_info["category"] == "union"
1417     def is_generic_handle(self):
1418         """ Returns True if the member is a unit64_t containing
1419         a handle with a separate object type
1420         """
1422         return self.object_type != None and self.type == "uint64_t"
1424     def is_bit_field(self):
1425         return self.bit_width is not None
1427     def needs_alignment(self):
1428         """ Check if this member needs alignment for 64-bit data.
1429         Various structures need alignment on 64-bit variables due
1430         to compiler differences on 32-bit between Win32 and Linux.
1431         """
1433         if self.is_pointer():
1434             return False
1435         elif self.type == "size_t":
1436             return False
1437         elif self.type in ["uint64_t", "VkDeviceSize"]:
1438             return True
1439         elif self.is_struct():
1440             struct = self.type_info["data"]
1441             return struct.needs_alignment()
1442         elif self.is_handle():
1443             # Dispatchable handles are pointers to objects, while
1444             # non-dispatchable are uint64_t and hence need alignment.
1445             handle = self.type_info["data"]
1446             return False if handle.is_dispatchable() else True
1447         return False
1449     def needs_conversion(self):
1450         """ Structures requiring alignment, need conversion between win32 and host. """
1452         if not self.is_struct():
1453             return False
1455         struct = self.type_info["data"]
1456         return struct.needs_conversion()
1458     def needs_unwrapping(self):
1459         """ Structures with wrapped handles need unwrapping. """
1461         if self.is_struct():
1462             struct = self.type_info["data"]
1463             return struct.needs_unwrapping()
1465         if self.is_handle():
1466             handle = self.type_info["data"]
1467             return handle.is_wrapped()
1469         if self.is_generic_handle():
1470             return True
1472         return False
1474     def needs_free(self):
1475         if not self.needs_conversion() and not self.needs_unwrapping():
1476             return False
1478         if self.is_dynamic_array():
1479             return True
1481         # TODO: some non-pointer structs and optional pointer structs may need freeing,
1482         # though none of this type have been encountered yet.
1483         return False
1485     def needs_struct_extensions_conversion(self):
1486         if not self.is_struct():
1487             return False
1489         struct = self.type_info["data"]
1490         return struct.needs_struct_extensions_conversion()
1492     def set_type_info(self, type_info):
1493         """ Helper function to set type information from the type registry.
1494         This is needed, because not all type data is available at time of
1495         parsing.
1496         """
1497         self.type_info = type_info
1500 class VkParam(object):
1501     """ Helper class which describes a parameter to a function call. """
1503     def __init__(self, type_info, const=None, pointer=None, name=None, array_len=None, dyn_array_len=None, object_type=None):
1504         self.const = const
1505         self.name = name
1506         self.array_len = array_len
1507         self.dyn_array_len = dyn_array_len
1508         self.pointer = pointer
1509         self.object_type = object_type
1510         self.type_info = type_info
1511         self.type = type_info["name"] # For convenience
1512         self.handle = type_info["data"] if type_info["category"] == "handle" else None
1513         self.struct = type_info["data"] if type_info["category"] == "struct" else None
1515         self._set_direction()
1516         self._set_format_string()
1517         self._set_conversions()
1519     def __repr__(self):
1520         return "{0} {1} {2} {3} {4} {5}".format(self.const, self.type, self.pointer, self.name, self.array_len, self.dyn_array_len)
1522     @staticmethod
1523     def from_xml(param, types):
1524         """ Helper function to create VkParam from xml. """
1526         # Parameter parsing is slightly tricky. All the data is contained within
1527         # a param tag, but some data is within subtags while others are text
1528         # before or after the type tag.
1529         # Common structure:
1530         # <param>const <type>char</type>* <name>pLayerName</name></param>
1532         name_elem = param.find("name")
1533         array_len = None
1534         name = name_elem.text
1535         # Tail contains array length e.g. for blendConstants param of vkSetBlendConstants
1536         if name_elem.tail is not None:
1537             array_len = name_elem.tail.strip("[]")
1539         # Name of other parameter in function prototype, which stores the number of
1540         # elements pointed to be by this parameter.
1541         dyn_array_len = param.get("len", None)
1543         const = param.text.strip() if param.text else None
1544         type_elem = param.find("type")
1545         pointer = type_elem.tail.strip() if type_elem.tail.strip() != "" else None
1547         # Some uint64_t are actually handles with a separate type param
1548         object_type = param.get("objecttype", None)
1550         # Since we have parsed all types before hand, this should not happen.
1551         type_info = types.get(type_elem.text, None)
1552         if type_info is None:
1553             LOGGER.err("type info not found for: {0}".format(type_elem.text))
1555         return VkParam(type_info, const=const, pointer=pointer, name=name, array_len=array_len, dyn_array_len=dyn_array_len, object_type=object_type)
1557     def _set_conversions(self):
1558         """ Internal helper function to configure any needed conversion functions. """
1560         self.free_func = None
1561         self.input_conv = None
1562         self.output_conv = None
1563         if not self.needs_conversion() and not self.needs_unwrapping():
1564             return
1566         operand = self.struct if self.is_struct() else self.handle
1568         # Input functions require win to host conversion.
1569         if self._direction in [Direction.INPUT, Direction.INPUT_OUTPUT]:
1570             self.input_conv = ConversionFunction(False, self.is_dynamic_array(), Direction.INPUT, operand)
1572         # Output functions require host to win conversion.
1573         if self._direction in [Direction.INPUT_OUTPUT, Direction.OUTPUT]:
1574             self.output_conv = ConversionFunction(False, self.is_dynamic_array(), Direction.OUTPUT, operand)
1576         # Dynamic arrays, but also some normal structs (e.g. VkCommandBufferBeginInfo) need memory
1577         # allocation and thus some cleanup.
1578         if self.is_dynamic_array() or self.struct.needs_free():
1579             self.free_func = FreeFunction(self.is_dynamic_array(), operand)
1581     def _set_direction(self):
1582         """ Internal helper function to set parameter direction (input/output/input_output). """
1584         # The parameter direction needs to be determined from hints in vk.xml like returnedonly,
1585         # parameter constness and other heuristics.
1586         # For now we need to get this right for structures as we need to convert these, we may have
1587         # missed a few other edge cases (e.g. count variables).
1588         # See also https://github.com/KhronosGroup/Vulkan-Docs/issues/610
1590         if not self.is_pointer():
1591             self._direction = Direction.INPUT
1592         elif self.is_const() and self.is_pointer():
1593             self._direction = Direction.INPUT
1594         elif self.is_struct():
1595             if not self.struct.returnedonly:
1596                 self._direction = Direction.INPUT
1597                 return
1599             # Returnedonly hints towards output, however in some cases
1600             # it is inputoutput. In particular if pNext / sType exist,
1601             # which are used to link in other structures without having
1602             # to introduce new APIs. E.g. vkGetPhysicalDeviceProperties2KHR.
1603             if "pNext" in self.struct:
1604                 self._direction = Direction.INPUT_OUTPUT
1605                 return
1607             self._direction = Direction.OUTPUT
1608         else:
1609             # This should mostly be right. Count variables can be inout, but we don't care about these yet.
1610             self._direction = Direction.OUTPUT
1612     def _set_format_string(self):
1613         """ Internal helper function to be used by constructor to set format string. """
1615         # Determine a format string used by code generation for traces.
1616         # 64-bit types need a conversion function.
1617         self.format_conv = None
1618         if self.is_static_array() or self.is_pointer():
1619             self.format_str = "%p"
1620         else:
1621             if self.type_info["category"] in ["bitmask"]:
1622                 # Since 1.2.170 bitmasks can be 32 or 64-bit, check the basetype.
1623                 if self.type_info["data"].type == "VkFlags64":
1624                     self.format_str = "0x%s"
1625                     self.format_conv = "wine_dbgstr_longlong({0})"
1626                 else:
1627                     self.format_str = "%#x"
1628             elif self.type_info["category"] in ["enum"]:
1629                 self.format_str = "%#x"
1630             elif self.is_handle():
1631                 # We use uint64_t for non-dispatchable handles as opposed to pointers
1632                 # for dispatchable handles.
1633                 if self.handle.is_dispatchable():
1634                     self.format_str = "%p"
1635                 else:
1636                     self.format_str = "0x%s"
1637                     self.format_conv = "wine_dbgstr_longlong({0})"
1638             elif self.type == "float":
1639                 self.format_str = "%f"
1640             elif self.type == "int":
1641                 self.format_str = "%d"
1642             elif self.type == "int32_t":
1643                 self.format_str = "%d"
1644             elif self.type == "size_t":
1645                 self.format_str = "0x%s"
1646                 self.format_conv = "wine_dbgstr_longlong({0})"
1647             elif self.type in ["uint16_t", "uint32_t", "VkBool32"]:
1648                 self.format_str = "%u"
1649             elif self.type in ["uint64_t", "VkDeviceAddress", "VkDeviceSize"]:
1650                 self.format_str = "0x%s"
1651                 self.format_conv = "wine_dbgstr_longlong({0})"
1652             elif self.type == "HANDLE":
1653                 self.format_str = "%p"
1654             elif self.type in ["VisualID", "xcb_visualid_t", "RROutput", "zx_handle_t"]:
1655                 # Don't care about specific types for non-Windows platforms.
1656                 self.format_str = ""
1657             else:
1658                 LOGGER.warn("Unhandled type: {0}".format(self.type_info))
1660     def copy(self, direction, prefix=""):
1661         if direction == Direction.INPUT:
1662             if self.is_dynamic_array():
1663                 return "    {1}_host = convert_{2}_array_win_to_host({0}{1}, {0}{3});\n".format(prefix, self.name, self.type, self.dyn_array_len)
1664             else:
1665                 return "    convert_{0}_win_to_host({1}{2}, &{2}_host);\n".format(self.type, prefix, self.name)
1666         else:
1667             if self.is_dynamic_array():
1668                 LOGGER.error("Unimplemented output conversion for: {0}".format(self.name))
1669             else:
1670                 return "    convert_{0}_host_to_win(&{2}_host, {1}{2});\n".format(self.type, prefix, self.name)
1672     def definition(self, postfix=None, is_member=False):
1673         """ Return prototype for the parameter. E.g. 'const char *foo' """
1675         proto = ""
1676         if self.const:
1677             proto += self.const + " "
1679         proto += self.type
1681         if self.is_pointer():
1682             proto += " {0}{1}".format(self.pointer, self.name)
1683         elif is_member and self.is_static_array():
1684             proto += " *" + self.name
1685         else:
1686             proto += " " + self.name
1688         # Allows appending something to the variable name useful for
1689         # win32 to host conversion.
1690         if postfix is not None:
1691             proto += postfix
1693         if not is_member and self.is_static_array():
1694             proto += "[{0}]".format(self.array_len)
1696         return proto
1698     def direction(self):
1699         """ Returns parameter direction: input, output, input_output.
1701         Parameter direction in Vulkan is not straight-forward, which this function determines.
1702         """
1704         return self._direction
1706     def dispatch_table(self, params_prefix=""):
1707         """ Return functions dispatch table pointer for dispatchable objects. """
1709         if not self.is_dispatchable():
1710             return None
1712         return self.handle.dispatch_table(params_prefix + self.name)
1714     def format_string(self):
1715         return self.format_str
1717     def free(self, prefix=""):
1718         if self.is_dynamic_array():
1719             if self.is_struct() and self.struct.returnedonly:
1720                 # For returnedonly, counts is stored in a pointer.
1721                 return "    free_{0}_array({1}_host, *{2}{3});\n".format(self.type, self.name, prefix, self.dyn_array_len)
1722             else:
1723                 return "    free_{0}_array({1}_host, {2}{3});\n".format(self.type, self.name, prefix, self.dyn_array_len)
1724         else:
1725             # We are operating on a single structure. Some structs (very rare) contain dynamic members,
1726             # which would need freeing.
1727             if self.is_struct() and self.struct.needs_free():
1728                 return "    free_{0}(&{1}_host);\n".format(self.type, self.name)
1729         return ""
1731     def get_conversions(self):
1732         """ Get a list of conversions required for this parameter if any.
1733         Parameters which are structures may require conversion between win32
1734         and the host platform. This function returns a list of conversions
1735         required.
1736         """
1738         if self.is_struct():
1739             self.struct.needs_struct_extensions_conversion()
1740             for m in self.struct:
1741                 m.needs_struct_extensions_conversion()
1742         elif not self.is_handle():
1743             return None
1745         if not self.needs_conversion() and not self.needs_unwrapping():
1746             return None
1748         conversions = []
1750         # Collect any member conversions first, so we can guarantee
1751         # those functions will be defined prior to usage by the
1752         # 'parent' param requiring conversion.
1753         if self.is_struct():
1754             for m in self.struct:
1755                 if not m.is_struct():
1756                     continue
1758                 if not m.needs_conversion() and not m.needs_unwrapping():
1759                     continue
1761                 conversions.extend(m.get_conversions())
1763         # Conversion requirements for the 'parent' parameter.
1764         if self.input_conv is not None:
1765             conversions.append(self.input_conv)
1766         if self.output_conv is not None:
1767             conversions.append(self.output_conv)
1768         if self.free_func is not None:
1769             conversions.append(self.free_func)
1771         return conversions
1773     def is_const(self):
1774         return self.const is not None
1776     def is_dynamic_array(self):
1777         return self.dyn_array_len is not None
1779     def is_dispatchable(self):
1780         if not self.is_handle():
1781             return False
1783         return self.handle.is_dispatchable()
1785     def is_handle(self):
1786         return self.handle is not None
1788     def is_pointer(self):
1789         return self.pointer is not None
1791     def is_static_array(self):
1792         return self.array_len is not None
1794     def is_struct(self):
1795         return self.struct is not None
1797     def needs_conversion(self):
1798         """ Returns if parameter needs conversion between win32 and host. """
1800         if not self.is_struct():
1801             return False
1803         # VkSparseImageMemoryRequirements(2) is used by vkGetImageSparseMemoryRequirements(2).
1804         # This function is tricky to wrap, because how to wrap depends on whether
1805         # pSparseMemoryRequirements is NULL or not. Luckily for VkSparseImageMemoryRequirements(2)
1806         # the alignment works out in such a way that no conversion is needed between win32 and Linux.
1807         if self.type in ["VkSparseImageMemoryRequirements", "VkSparseImageMemoryRequirements2"]:
1808             return False
1810         # If a structure needs alignment changes, it means we need to
1811         # perform parameter conversion between win32 and host.
1812         if self.struct.needs_conversion():
1813             return True
1815         return False
1817     def needs_unwrapping(self):
1818         """ Returns if parameter needs unwrapping of handle. """
1820         # Wrapped handle parameters are handled separately, only look for wrapped handles in structs
1821         if self.is_struct():
1822             return self.struct.needs_unwrapping()
1824         if self.is_handle() and self.is_dynamic_array():
1825             return self.handle.needs_unwrapping()
1827         return False
1829     def needs_free(self):
1830         return self.free_func is not None
1832     def needs_input_conversion(self):
1833         return self.input_conv is not None
1835     def needs_output_conversion(self):
1836         return self.output_conv is not None
1838     def spec(self):
1839         """ Generate spec file entry for this parameter. """
1841         if self.is_pointer() and self.type == "char":
1842             return "str"
1843         if self.is_dispatchable() or self.is_pointer() or self.is_static_array():
1844             return "ptr"
1845         if self.type_info["category"] in ["bitmask"]:
1846             # Since 1.2.170 bitmasks can be 32 or 64-bit, check the basetype.
1847             if self.type_info["data"].type == "VkFlags64":
1848                 return "int64"
1849             else:
1850                 return "long"
1851         if self.type_info["category"] in ["enum"]:
1852             return "long"
1853         if self.is_handle() and not self.is_dispatchable():
1854             return "int64"
1855         if self.type == "float":
1856             return "float"
1857         if self.type in ["int", "int32_t", "size_t", "uint16_t", "uint32_t", "VkBool32"]:
1858             return "long"
1859         if self.type in ["uint64_t", "VkDeviceSize"]:
1860             return "int64"
1862         LOGGER.error("Unhandled spec conversion for type: {0}".format(self.type))
1864     def variable(self, conv=False, params_prefix=""):
1865         """ Returns 'glue' code during generation of a function call on how to access the variable.
1866         This function handles various scenarios such as 'unwrapping' if dispatchable objects and
1867         renaming of parameters in case of win32 -> host conversion.
1869         Args:
1870             conv (bool, optional): Enable conversion if the param needs it. This appends '_host' to the name.
1871         """
1873         # Hack until we enable allocation callbacks from ICD to application. These are a joy
1874         # to enable one day, because of calling convention conversion.
1875         if "VkAllocationCallbacks" in self.type:
1876             LOGGER.debug("TODO: setting NULL VkAllocationCallbacks for {0}".format(self.name))
1877             return "NULL"
1879         if self.needs_unwrapping() or (conv and self.needs_conversion()):
1880             if self.is_dynamic_array():
1881                 return "{0}_host".format(self.name)
1882             else:
1883                 return "&{0}_host".format(self.name)
1884         else:
1885             if self.object_type != None and self.type == "uint64_t":
1886                 return "wine_vk_unwrap_handle({0}{1}, {0}{2})".format(params_prefix, self.object_type, self.name)
1888             # We need to pass the native handle to the native Vulkan calls and
1889             # the wine driver's handle to calls which are wrapped by the driver.
1890             p = "{0}{1}".format(params_prefix, self.name)
1891             driver_handle = self.handle.driver_handle(p) if self.is_handle() else None
1892             return driver_handle if driver_handle else p
1895 class VkStruct(Sequence):
1896     """ Class which represents the type union and struct. """
1898     def __init__(self, name, members, returnedonly, structextends, alias=None, union=False):
1899         self.name = name
1900         self.members = members
1901         self.returnedonly = returnedonly
1902         self.structextends = structextends
1903         self.required = False
1904         self.alias = alias
1905         self.union = union
1906         self.type_info = None # To be set later.
1907         self.struct_extensions = []
1908         self.aliased_by = []
1910     def __getitem__(self, i):
1911         return self.members[i]
1913     def __len__(self):
1914         return len(self.members)
1916     @staticmethod
1917     def from_alias(struct, alias):
1918         name = struct.attrib.get("name")
1919         aliasee = VkStruct(name, alias.members, alias.returnedonly, alias.structextends, alias=alias)
1921         alias.add_aliased_by(aliasee)
1922         return aliasee
1924     @staticmethod
1925     def from_xml(struct):
1926         # Unions and structs are the same parsing wise, but we need to
1927         # know which one we are dealing with later on for code generation.
1928         union = True if struct.attrib["category"] == "union" else False
1930         name = struct.attrib.get("name")
1932         # 'Output' structures for which data is filled in by the API are
1933         # marked as 'returnedonly'.
1934         returnedonly = True if struct.attrib.get("returnedonly") else False
1936         structextends = struct.attrib.get("structextends")
1937         structextends = structextends.split(",") if structextends else []
1939         members = []
1940         for member in struct.findall("member"):
1941             vk_member = VkMember.from_xml(member)
1942             members.append(vk_member)
1944         return VkStruct(name, members, returnedonly, structextends, union=union)
1946     @staticmethod
1947     def decouple_structs(structs):
1948         """ Helper function which decouples a list of structs.
1949         Structures often depend on other structures. To make the C compiler
1950         happy we need to define 'substructures' first. This function analyzes
1951         the list of structures and reorders them in such a way that they are
1952         decoupled.
1953         """
1955         tmp_structs = list(structs) # Don't modify the original structures.
1956         decoupled_structs = []
1958         while (len(tmp_structs) > 0):
1959             # Iterate over a copy because we want to modify the list inside the loop.
1960             for struct in list(tmp_structs):
1961                 dependends = False
1963                 if not struct.required:
1964                     tmp_structs.remove(struct)
1965                     continue
1967                 for m in struct:
1968                     if not (m.is_struct() or m.is_union()):
1969                         continue
1971                     # VkBaseInstructure and VkBaseOutStructure reference themselves.
1972                     if m.type == struct.name:
1973                         break
1975                     found = False
1976                     # Check if a struct we depend on has already been defined.
1977                     for s in decoupled_structs:
1978                         if s.name == m.type:
1979                             found = True
1980                             break
1982                     if not found:
1983                         # Check if the struct we depend on is even in the list of structs.
1984                         # If found now, it means we haven't met all dependencies before we
1985                         # can operate on the current struct.
1986                         # When generating 'host' structs we may not be able to find a struct
1987                         # as the list would only contain the structs requiring conversion.
1988                         for s in tmp_structs:
1989                             if s.name == m.type:
1990                                 dependends = True
1991                                 break
1993                 if dependends == False:
1994                     decoupled_structs.append(struct)
1995                     tmp_structs.remove(struct)
1997         return decoupled_structs
1999     def definition(self, align=False, conv=False, postfix=None):
2000         """ Convert structure to textual definition.
2002         Args:
2003             align (bool, optional): enable alignment to 64-bit for win32 struct compatibility.
2004             conv (bool, optional): enable struct conversion if the struct needs it.
2005             postfix (str, optional): text to append to end of struct name, useful for struct renaming.
2006         """
2008         # Only define alias structs when doing conversions
2009         if self.is_alias() and not conv:
2010             return ""
2012         if self.union:
2013             text = "typedef union {0}".format(self.name)
2014         else:
2015             text = "typedef struct {0}".format(self.name)
2017         if postfix is not None:
2018             text += postfix
2020         text += "\n{\n"
2022         for m in self:
2023             if align and m.needs_alignment():
2024                 text += "    {0};\n".format(m.definition(align=align))
2025             elif conv and m.needs_conversion():
2026                 text += "    {0};\n".format(m.definition(conv=conv))
2027             else:
2028                 text += "    {0};\n".format(m.definition())
2030         if postfix is not None:
2031             text += "}} {0}{1};\n".format(self.name, postfix)
2032         else:
2033             text += "}} {0};\n".format(self.name)
2035         for aliasee in self.aliased_by:
2036             text += "typedef {0} {1};\n".format(self.name, aliasee.name)
2038         return text
2040     def is_alias(self):
2041         return bool(self.alias)
2043     def add_aliased_by(self, aliasee):
2044         self.aliased_by.append(aliasee)
2046     def needs_alignment(self):
2047         """ Check if structure needs alignment for 64-bit data.
2048         Various structures need alignment on 64-bit variables due
2049         to compiler differences on 32-bit between Win32 and Linux.
2050         """
2052         for m in self.members:
2053             if self.name == m.type:
2054                 continue
2055             if m.needs_alignment():
2056                 return True
2057         return False
2059     def needs_conversion(self):
2060         """ Returns if struct members needs conversion between win32 and host.
2061         Structures need conversion if they contain members requiring alignment
2062         or if they include other structures which need alignment.
2063         """
2065         if self.needs_alignment():
2066             return True
2068         for m in self.members:
2069             if self.name == m.type:
2070                 continue
2071             if m.needs_conversion():
2072                 return True
2073         return False
2075     def needs_unwrapping(self):
2076         """ Returns if struct members need unwrapping of handle. """
2078         for m in self.members:
2079             if self.name == m.type:
2080                 continue
2081             if m.needs_unwrapping():
2082                 return True
2083         return False
2085     def needs_free(self):
2086         """ Check if any struct member needs some memory freeing."""
2088         for m in self.members:
2089             if self.name == m.type:
2090                 continue
2091             if m.needs_free():
2092                 return True
2094         return False
2096     def needs_struct_extensions_conversion(self):
2097         """ Checks if structure extensions in pNext chain need conversion. """
2098         ret = False
2100         for e in self.struct_extensions:
2101             if e.required and e.needs_conversion():
2102                 LOGGER.error("Unhandled pNext chain alignment conversion for {0}".format(e.name))
2103                 ret = True
2104             if e.required and e.needs_unwrapping():
2105                 LOGGER.error("Unhandled pNext chain unwrapping conversion for {0}".format(e.name))
2106                 ret = True
2108         return ret
2110     def set_type_info(self, types):
2111         """ Helper function to set type information from the type registry.
2112         This is needed, because not all type data is available at time of
2113         parsing.
2114         """
2115         for m in self.members:
2116             type_info = types[m.type]
2117             m.set_type_info(type_info)
2120 class ConversionFunction(object):
2121     def __init__(self, array, dyn_array, direction, operand):
2122         self.array = array
2123         self.direction = direction
2124         self.dyn_array = dyn_array
2125         self.operand = operand
2126         self.type = operand.name
2128         self._set_name()
2130     def __eq__(self, other):
2131         return self.name == other.name
2133     def _generate_array_conversion_func(self):
2134         """ Helper function for generating a conversion function for array operands. """
2136         body = ""
2138         if self.operand.needs_conversion():
2139             body += "#if defined(USE_STRUCT_CONVERSION)\n"
2141             if self.direction == Direction.OUTPUT:
2142                 params = ["const {0}_host *in".format(self.type), "uint32_t count"]
2143                 return_type = self.type
2144             else:
2145                 params = ["const {0} *in".format(self.type), "uint32_t count"]
2146                 return_type = "{0}_host".format(self.type)
2148             # Generate function prototype.
2149             body += "static inline {0} *{1}(".format(return_type, self.name)
2150             body += ", ".join(p for p in params)
2151             body += ")\n{\n"
2153             body += "    {0} *out;\n".format(return_type)
2155         if self.operand.needs_unwrapping():
2156             if self.operand.needs_conversion():
2157                 body += "#else\n"
2159             params = ["const {0} *in".format(self.type), "uint32_t count"]
2160             return_type = "{0}".format(self.type)
2162             # Generate function prototype.
2163             body += "static inline {0} *{1}(".format(return_type, self.name)
2164             body += ", ".join(p for p in params)
2165             body += ")\n{\n"
2167             body += "    {0} *out;\n".format(return_type)
2169             if self.operand.needs_conversion():
2170                 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2172         body += "    unsigned int i;\n\n"
2173         body += "    if (!in || !count) return NULL;\n\n"
2175         body += "    out = malloc(count * sizeof(*out));\n"
2177         body += "    for (i = 0; i < count; i++)\n"
2178         body += "    {\n"
2180         if isinstance(self.operand, VkStruct):
2181             for m in self.operand:
2182                 # TODO: support copying of pNext extension structures!
2183                 # Luckily though no extension struct at this point needs conversion.
2184                 convert = m.copy("in[i].", "out[i].", self.direction, conv=True)
2185                 if self.operand.needs_conversion() and not self.operand.needs_unwrapping():
2186                     body += "        " + convert
2187                 else:
2188                     unwrap = m.copy("in[i].", "out[i].", self.direction, conv=False)
2189                     if unwrap == convert:
2190                         body += "        " + unwrap
2191                     else:
2192                         body += "#if defined(USE_STRUCT_CONVERSION)\n"
2193                         body += "        " + convert
2194                         body += "#else\n"
2195                         body += "        " + unwrap
2196                         body += "#endif /* USE_STRUCT_CONVERSION */\n"
2198         elif isinstance(self.operand, VkHandle) and self.direction == Direction.INPUT:
2199             body += "        out[i] = " + self.operand.driver_handle("in[i]") + ";\n"
2200         else:
2201             LOGGER.warn("Unhandled conversion operand type")
2202             body += "        out[i] = in[i];\n"
2204         body += "    }\n\n"
2205         body += "    return out;\n"
2206         body += "}\n"
2208         if not self.operand.needs_unwrapping():
2209             body += "#endif /* USE_STRUCT_CONVERSION */\n"
2211         body += "\n"
2213         return body
2215     def _generate_conversion_func(self):
2216         """ Helper function for generating a conversion function for non-array operands. """
2218         # It doesn't make sense to generate conversion functions for non-struct variables
2219         # which aren't in arrays, as this should be handled by the copy() function
2220         if not isinstance(self.operand, VkStruct):
2221             return ""
2223         body = ""
2225         if self.operand.needs_conversion():
2226             body += "#if defined(USE_STRUCT_CONVERSION)\n"
2227             body += "static inline void {0}(".format(self.name)
2229             if self.direction == Direction.OUTPUT:
2230                 params = ["const {0}_host *in".format(self.type), "{0} *out".format(self.type)]
2231             else:
2232                 params = ["const {0} *in".format(self.type), "{0}_host *out".format(self.type)]
2234             # Generate parameter list
2235             body += ", ".join(p for p in params)
2236             body += ")\n"
2238         if self.operand.needs_unwrapping():
2239             if self.operand.needs_conversion():
2240                 body += "#else\n"
2242             body += "static inline void {0}(".format(self.name)
2244             params = ["const {0} *in".format(self.type), "{0} *out".format(self.type)]
2246             # Generate parameter list
2247             body += ", ".join(p for p in params)
2248             body += ")\n"
2250             if self.operand.needs_conversion():
2251                 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2253         body += "{\n    if (!in) return;\n\n"
2255         if self.direction == Direction.INPUT and "pNext" in self.operand and self.operand.returnedonly:
2256             # We are dealing with an input_output parameter. For these we only need to copy
2257             # pNext and sType as the other fields are filled in by the host. We do potentially
2258             # have to iterate over pNext and perform conversions based on switch(sType)!
2259             # Luckily though no extension structs at this point need conversion.
2260             # TODO: support copying of pNext extension structures!
2261             body += "    out->pNext = in->pNext;\n"
2262             body += "    out->sType = in->sType;\n"
2263         else:
2264             for m in self.operand:
2265                 # TODO: support copying of pNext extension structures!
2266                 convert = m.copy("in->", "out->", self.direction, conv=True)
2267                 if self.operand.needs_conversion() and not self.operand.needs_unwrapping():
2268                     body += "    " + convert
2269                 else:
2270                     unwrap = m.copy("in->", "out->", self.direction, conv=False)
2271                     if unwrap == convert:
2272                         body += "    " + unwrap
2273                     else:
2274                         body += "#if defined(USE_STRUCT_CONVERSION)\n"
2275                         body += "    " + convert
2276                         body += "#else\n"
2277                         body += "    " + unwrap
2278                         body += "#endif /* USE_STRUCT_CONVERSION */\n"
2280         body += "}\n"
2282         if not self.operand.needs_unwrapping():
2283             body += "#endif /* USE_STRUCT_CONVERSION */\n"
2285         body += "\n"
2287         return body
2289     def _generate_static_array_conversion_func(self):
2290         """ Helper function for generating a conversion function for array operands. """
2292         body = ""
2294         if self.operand.needs_conversion():
2295             body += "#if defined(USE_STRUCT_CONVERSION)\n"
2297             if self.direction == Direction.OUTPUT:
2298                 params = ["const {0}_host *in".format(self.type), "{0} *out".format(self.type), "uint32_t count"]
2299             else:
2300                 params = ["const {0} *in".format(self.type), "{0} *out_host".format(self.type), "uint32_t count"]
2302             # Generate function prototype.
2303             body += "static inline void {0}(".format(self.name)
2304             body += ", ".join(p for p in params)
2305             body += ")\n"
2307         if self.operand.needs_unwrapping():
2308             if self.operand.needs_conversion():
2309                 body += "#else\n"
2311             params = ["const {0} *in".format(self.type), "{0} *out".format(self.type), "uint32_t count"]
2313             # Generate function prototype.
2314             body += "static inline void {0}(".format(self.name)
2315             body += ", ".join(p for p in params)
2316             body += ")\n"
2318         body += "{\n"
2319         body += "    unsigned int i;\n\n"
2320         body += "    if (!in) return;\n\n"
2321         body += "    for (i = 0; i < count; i++)\n"
2322         body += "    {\n"
2324         if isinstance(self.operand, VkStruct):
2325             for m in self.operand:
2326                 # TODO: support copying of pNext extension structures!
2327                 convert = m.copy("in[i].", "out[i].", self.direction, conv=True)
2328                 if self.operand.needs_conversion() and not self.operand.needs_unwrapping():
2329                     body += "        " + convert
2330                 else:
2331                     unwrap = m.copy("in[i].", "out[i].", self.direction, conv=False)
2332                     if unwrap == convert:
2333                         body += "        " + unwrap
2334                     else:
2335                         body += "#if defined(USE_STRUCT_CONVERSION)\n"
2336                         body += "    " + convert
2337                         body += "#else\n"
2338                         body += "    " + unwrap
2339                         body += "#endif /* USE_STRUCT_CONVERSION */\n"
2340         elif isinstance(self.operand, VkHandle) and self.direction == Direction.INPUT:
2341             body += "        out[i] = " + self.operand.driver_handle("in[i]") + ";\n"
2342         else:
2343             LOGGER.warn("Unhandled conversion operand type")
2344             body += "        out[i] = in[i];\n"
2346         body += "    }\n"
2347         body += "}\n"
2349         if not self.operand.needs_unwrapping():
2350             body += "#endif /* USE_STRUCT_CONVERSION) */\n"
2352         body += "\n"
2354         return body
2356     def _set_name(self):
2357         if self.direction == Direction.INPUT:
2358             if self.array:
2359                 name = "convert_{0}_static_array_win_to_host".format(self.type)
2360             elif self.dyn_array:
2361                 name = "convert_{0}_array_win_to_host".format(self.type)
2362             else:
2363                 name = "convert_{0}_win_to_host".format(self.type)
2364         else: # Direction.OUTPUT
2365             if self.array:
2366                 name = "convert_{0}_static_array_host_to_win".format(self.type)
2367             elif self.dyn_array:
2368                 name = "convert_{0}_array_host_to_win".format(self.type)
2369             else:
2370                 name = "convert_{0}_host_to_win".format(self.type)
2372         self.name = name
2374     def definition(self):
2375         if self.array:
2376             return self._generate_static_array_conversion_func()
2377         elif self.dyn_array:
2378             return self._generate_array_conversion_func()
2379         else:
2380             return self._generate_conversion_func()
2383 class FreeFunction(object):
2384     def __init__(self, dyn_array, operand):
2385         self.dyn_array = dyn_array
2386         self.operand = operand
2387         self.type = operand.name
2389         if dyn_array:
2390             self.name = "free_{0}_array".format(self.type)
2391         else:
2392             self.name = "free_{0}".format(self.type)
2394     def __eq__(self, other):
2395         return self.name == other.name
2397     def _generate_array_free_func(self):
2398         """ Helper function for cleaning up temporary buffers required for array conversions. """
2400         body = ""
2402         if self.operand.needs_conversion():
2403             body += "#if defined(USE_STRUCT_CONVERSION)\n"
2404             # Generate function prototype.
2405             body += "static inline void {0}({1}_host *in, uint32_t count)\n".format(self.name, self.type)
2407         if self.operand.needs_unwrapping():
2408             if self.operand.needs_conversion():
2409                 body += "#else\n"
2411             # Generate function prototype.
2412             body += "static inline void {0}({1} *in, uint32_t count)\n".format(self.name, self.type)
2414             if self.operand.needs_conversion():
2415                 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2417         body += "{\n"
2419         # E.g. VkGraphicsPipelineCreateInfo_host needs freeing for pStages.
2420         if isinstance(self.operand, VkStruct) and self.operand.needs_free():
2421             body += "    unsigned int i;\n\n"
2422             body += "    if (!in) return;\n\n"
2423             body += "    for (i = 0; i < count; i++)\n"
2424             body += "    {\n"
2426             for m in self.operand:
2427                 if m.needs_free():
2428                     convert = m.free("in[i].", conv=True)
2429                     if self.operand.needs_conversion() and not self.operand.needs_unwrapping():
2430                         body += "        " + convert
2431                     else:
2432                         unwrap = m.free("in[i].", conv=False)
2433                         if convert == unwrap:
2434                             body += "        " + unwrap
2435                         elif unwrap == "":
2436                             body += "#if defined(USE_STRUCT_CONVERSION)\n"
2437                             body += "        " + convert
2438                             body += "#endif /* USE_STRUCT_CONVERSION */\n"
2439                         else:
2440                             body += "#if defined(USE_STRUCT_CONVERSION)\n"
2441                             body += "        " + convert
2442                             body += "#else\n"
2443                             body += "        " + unwrap
2444                             body += "#endif /* USE_STRUCT_CONVERSION */\n"
2445             body += "    }\n"
2446         else:
2447             body += "    if (!in) return;\n\n"
2449         body += "    free(in);\n"
2451         body += "}\n"
2453         if not self.operand.needs_unwrapping():
2454             body += "#endif /* USE_STRUCT_CONVERSION */\n"
2456         body += "\n"
2458         return body
2460     def _generate_free_func(self):
2461         # E.g. VkCommandBufferBeginInfo.pInheritanceInfo needs freeing.
2462         if not self.operand.needs_free():
2463             return ""
2465         if not isinstance(self.operand, VkStruct):
2466             return ""
2468         body = ""
2470         if self.operand.needs_conversion():
2471             body += "#if defined(USE_STRUCT_CONVERSION)\n"
2472             # Generate function prototype.
2473             body += "static inline void {0}({1}_host *in)\n".format(self.name, self.type)
2475         if self.operand.needs_unwrapping():
2476             if self.operand.needs_conversion():
2477                 body += "#else\n"
2479             # Generate function prototype.
2480             body += "static inline void {0}({1} *in)\n".format(self.name, self.type)
2482             if self.operand.needs_conversion():
2483                 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2485         body += "{\n"
2487         for m in self.operand:
2488             if m.needs_free():
2489                 convert = m.free("in->", conv=True)
2490                 if self.operand.needs_conversion() and not self.operand.needs_unwrapping():
2491                     body += "    " + convert
2492                 else:
2493                     unwrap = m.free("in->", conv=False)
2494                     if convert == unwrap:
2495                         body += "    " + unwrap
2496                     elif unwrap == "":
2497                         body += "#if defined(USE_STRUCT_CONVERSION)\n"
2498                         body += "    " + convert
2499                         body += "#endif /* USE_STRUCT_CONVERSION */\n"
2500                     else:
2501                         body += "#if defined(USE_STRUCT_CONVERSION)\n"
2502                         body += "    " + convert
2503                         body += "#else\n"
2504                         body += "    " + unwrap
2505                         body += "#endif /* USE_STRUCT_CONVERSION */\n"
2507         body += "}\n"
2509         if not self.operand.needs_unwrapping():
2510             body += "#endif /* USE_STRUCT_CONVERSION */\n"
2512         body += "\n"
2514         return body
2516     def definition(self):
2517         if self.dyn_array:
2518             return self._generate_array_free_func()
2519         else:
2520             # Some structures need freeing too if they contain dynamic arrays.
2521             # E.g. VkCommandBufferBeginInfo
2522             return self._generate_free_func()
2525 class StructChainConversionFunction(object):
2526     def __init__(self, direction, struct, ignores):
2527         self.direction = direction
2528         self.struct = struct
2529         self.ignores = ignores
2530         self.type = struct.name
2532         self.name = "convert_{0}_struct_chain".format(self.type)
2534     def __eq__(self, other):
2535         return self.name == other.name
2537     def prototype(self, postfix=""):
2538         return "VkResult {0}(const void *pNext, {1} *out_struct) {2}".format(self.name, self.type, postfix).strip()
2540     def definition(self):
2541         body = self.prototype()
2542         body += "\n{\n"
2544         body += "    VkBaseOutStructure *out_header = (VkBaseOutStructure *)out_struct;\n";
2545         body += "    const VkBaseInStructure *in_header;\n\n";
2547         body += "    out_header->pNext = NULL;\n\n"
2549         body += "    for (in_header = pNext; in_header; in_header = in_header->pNext)\n"
2550         body += "    {\n"
2551         body += "        switch (in_header->sType)\n"
2552         body += "        {\n"
2554         for i in self.ignores:
2555             body += "        case {0}:\n".format(i)
2556         body += "            break;\n\n"
2558         for e in self.struct.struct_extensions:
2559             if not e.required:
2560                 continue
2562             stype = next(x for x in e.members if x.name == "sType")
2564             if stype.values in self.ignores:
2565                 continue
2567             body += "        case {0}:\n".format(stype.values)
2568             body += "        {\n"
2570             body += "            const {0} *in = (const {0} *)in_header;\n".format(e.name)
2571             body += "            {0} *out;\n\n".format(e.name)
2573             body += "            if (!(out = malloc(sizeof(*out)))) goto out_of_memory;\n\n"
2575             for m in e:
2576                 if m.name == "pNext":
2577                     body += "            out->pNext = NULL;\n"
2578                 else:
2579                     convert = m.copy("in->", "out->", self.direction, conv=True)
2580                     unwrap = m.copy("in->", "out->", self.direction, conv=False)
2581                     if unwrap == convert:
2582                         body += "            " + unwrap
2583                     else:
2584                         body += "#if defined(USE_STRUCT_CONVERSION)\n"
2585                         body += "            " + convert
2586                         body += "#else\n"
2587                         body += "            " + unwrap
2588                         body += "#endif /* USE_STRUCT_CONVERSION */\n"
2590             body += "\n            out_header->pNext = (VkBaseOutStructure *)out;\n"
2591             body += "            out_header = out_header->pNext;\n"
2592             body += "            break;\n"
2593             body += "        }\n\n"
2595         body += "        default:\n"
2596         body += "            FIXME(\"Application requested a linked structure of type %u.\\n\", in_header->sType);\n"
2598         body += "        }\n"
2599         body += "    }\n\n"
2601         body += "    return VK_SUCCESS;\n"
2603         if any(x for x in self.struct.struct_extensions if x.required):
2604             body += "\nout_of_memory:\n"
2605             body += "    free_{0}_struct_chain(out_struct);\n".format(self.type)
2606             body += "    return VK_ERROR_OUT_OF_HOST_MEMORY;\n"
2608         body += "}\n\n"
2609         return body
2611 class FreeStructChainFunction(object):
2612     def __init__(self, struct):
2613         self.struct = struct
2614         self.type = struct.name
2616         self.name = "free_{0}_struct_chain".format(self.type)
2618     def __eq__(self, other):
2619         return self.name == other.name
2621     def prototype(self, postfix=""):
2622         return "void {0}({1} *s) {2}".format(self.name, self.type, postfix).strip()
2624     def definition(self):
2625         body = self.prototype()
2626         body += "\n{\n"
2628         body += "    VkBaseOutStructure *header = (void *)s->pNext;\n\n";
2630         body += "    while (header)\n"
2631         body += "    {\n"
2632         body += "        void *prev = header;\n\n"
2633         body += "        switch (header->sType)\n"
2634         body += "        {\n"
2636         for e in self.struct.struct_extensions:
2637             if not e.required:
2638                 continue
2640             if not any(m.needs_free() for m in e):
2641                 continue
2643             stype = next(x for x in e.members if x.name == "sType")
2645             body += "            case {0}:\n".format(stype.values)
2646             body += "            {\n"
2647             body += "                {0} *structure = ({0} *) header;\n".format(e.name)
2649             for m in e:
2650                 if m.needs_free():
2651                     convert = m.free("structure->", conv=True)
2652                     unwrap = m.free("structure->", conv=False)
2653                     if convert == unwrap:
2654                         body += "                " + unwrap
2655                     elif unwrap == "":
2656                         body += "#if defined(USE_STRUCT_CONVERSION)\n"
2657                         body += "                " + convert
2658                         body += "#endif /* USE_STRUCT_CONVERSION */\n"
2659                     else:
2660                         body += "#if defined(USE_STRUCT_CONVERSION)\n"
2661                         body += "                " + convert
2662                         body += "#else\n"
2663                         body += "                " + unwrap
2664                         body += "#endif /* USE_STRUCT_CONVERSION */\n"
2666             body += "                break;\n"
2667             body += "            }\n"
2669         body += "            default:\n"
2670         body += "                break;\n"
2671         body += "        }\n"
2673         body += "        header = header->pNext;\n"
2674         body += "        free(prev);\n"
2675         body += "    }\n\n"
2677         body += "    s->pNext = NULL;\n"
2679         body += "}\n\n"
2680         return body
2683 class VkGenerator(object):
2684     def __init__(self, registry):
2685         self.registry = registry
2687         # Build a list conversion functions for struct conversion.
2688         self.conversions = []
2689         self.struct_chain_conversions = []
2690         self.host_structs = []
2691         for func in self.registry.funcs.values():
2692             if not func.is_required():
2693                 continue
2695             if not func.needs_conversion() and not func.needs_unwrapping():
2696                 continue
2698             conversions = func.get_conversions()
2699             for conv in conversions:
2700                 # Pull in any conversions for vulkan_thunks.c.
2701                 if func.needs_thunk():
2702                     # Append if we don't already have this conversion.
2703                     if not any(c == conv for c in self.conversions):
2704                         self.conversions.append(conv)
2706                 if not isinstance(conv.operand, VkStruct):
2707                     continue
2709                 # Structs can be used in different ways by different conversions
2710                 # e.g. array vs non-array. Just make sure we pull in each struct once.
2711                 if not any(s.name == conv.operand.name for s in self.host_structs):
2712                     self.host_structs.append(conv.operand)
2714         for struct in self.registry.structs:
2715             if struct.name in STRUCT_CHAIN_CONVERSIONS:
2716                 self.struct_chain_conversions.append(StructChainConversionFunction(Direction.INPUT, struct, STRUCT_CHAIN_CONVERSIONS[struct.name]))
2717                 self.struct_chain_conversions.append(FreeStructChainFunction(struct))
2718                 # Once we decide to support pNext chains conversion everywhere, move this under get_conversions
2719                 for e in struct.struct_extensions:
2720                     for m in e:
2721                         if m.needs_conversion() or m.needs_unwrapping():
2722                             conversions = m.get_conversions()
2723                             for conv in conversions:
2724                                 if not any(c == conv for c in self.conversions):
2725                                     self.conversions.append(conv)
2727     def _generate_copyright(self, f, spec_file=False):
2728         f.write("# " if spec_file else "/* ")
2729         f.write("Automatically generated from Vulkan vk.xml; DO NOT EDIT!\n")
2730         lines = ["", "This file is generated from Vulkan vk.xml file covered",
2731             "by the following copyright and permission notice:"]
2732         lines.extend([l.rstrip(" ") for l in self.registry.copyright.splitlines()])
2733         for line in lines:
2734             f.write("{0}{1}".format("# " if spec_file else " * ", line).rstrip(" ") + "\n")
2735         f.write("\n" if spec_file else " */\n\n")
2737     def generate_thunks_c(self, f, prefix):
2738         self._generate_copyright(f)
2740         f.write("#if 0\n")
2741         f.write("#pragma makedep unix\n")
2742         f.write("#endif\n\n")
2744         f.write("#include \"config.h\"\n\n")
2746         f.write("#include <stdlib.h>\n\n")
2748         f.write("#include \"vulkan_private.h\"\n\n")
2750         f.write("WINE_DEFAULT_DEBUG_CHANNEL(vulkan);\n\n")
2752         # Generate any conversion helper functions.
2753         for conv in self.conversions:
2754             f.write(conv.definition())
2756         for conv in self.struct_chain_conversions:
2757             f.write(conv.definition())
2759         # Create thunks for instance and device functions.
2760         # Global functions don't go through the thunks.
2761         for vk_func in self.registry.funcs.values():
2762             if not vk_func.needs_exposing():
2763                 continue
2764             if vk_func.loader_thunk_type == ThunkType.NONE:
2765                 continue
2767             if vk_func.needs_private_thunk():
2768                 f.write(vk_func.thunk(prefix="thunk_"))
2770             if vk_func.thunk_type == ThunkType.PUBLIC:
2771                 f.write("static ")
2772                 f.write(vk_func.thunk(prefix=prefix))
2774         # Create array of device extensions.
2775         f.write("static const char * const vk_device_extensions[] =\n{\n")
2776         for ext in self.registry.extensions:
2777             if ext["type"] != "device":
2778                 continue
2779             if ext["name"] in UNEXPOSED_EXTENSIONS:
2780                 continue
2782             f.write("    \"{0}\",\n".format(ext["name"]))
2783         f.write("};\n\n")
2785         # Create array of instance extensions.
2786         f.write("static const char * const vk_instance_extensions[] =\n{\n")
2787         for ext in self.registry.extensions:
2788             if ext["type"] != "instance":
2789                 continue
2790             if ext["name"] in UNEXPOSED_EXTENSIONS:
2791                 continue
2793             f.write("    \"{0}\",\n".format(ext["name"]))
2794         f.write("};\n\n")
2796         f.write("BOOL wine_vk_device_extension_supported(const char *name)\n")
2797         f.write("{\n")
2798         f.write("    unsigned int i;\n")
2799         f.write("    for (i = 0; i < ARRAY_SIZE(vk_device_extensions); i++)\n")
2800         f.write("    {\n")
2801         f.write("        if (strcmp(vk_device_extensions[i], name) == 0)\n")
2802         f.write("            return TRUE;\n")
2803         f.write("    }\n")
2804         f.write("    return FALSE;\n")
2805         f.write("}\n\n")
2807         f.write("BOOL wine_vk_instance_extension_supported(const char *name)\n")
2808         f.write("{\n")
2809         f.write("    unsigned int i;\n")
2810         f.write("    for (i = 0; i < ARRAY_SIZE(vk_instance_extensions); i++)\n")
2811         f.write("    {\n")
2812         f.write("        if (strcmp(vk_instance_extensions[i], name) == 0)\n")
2813         f.write("            return TRUE;\n")
2814         f.write("    }\n")
2815         f.write("    return FALSE;\n")
2816         f.write("}\n\n")
2818         f.write("BOOL wine_vk_is_type_wrapped(VkObjectType type)\n")
2819         f.write("{\n")
2820         f.write("    return FALSE")
2821         for handle in self.registry.handles:
2822             if not handle.is_required() or not handle.is_wrapped() or handle.is_alias():
2823                 continue
2824             f.write(" ||\n        type == {}".format(handle.object_type))
2825         f.write(";\n")
2826         f.write("}\n\n")
2828         f.write("uint64_t wine_vk_unwrap_handle(VkObjectType type, uint64_t handle)\n")
2829         f.write("{\n")
2830         f.write("    switch(type)\n")
2831         f.write("    {\n")
2832         for handle in self.registry.handles:
2833             if not handle.is_required() or not handle.is_wrapped() or handle.is_alias():
2834                 continue
2835             f.write("    case {}:\n".format(handle.object_type))
2836             if handle.is_dispatchable():
2837                 f.write("        return (uint64_t) (uintptr_t) ")
2838                 f.write(handle.native_handle("(({}) (uintptr_t) handle)".format(handle.name)))
2839             else:
2840                 f.write("        return (uint64_t) ")
2841                 f.write(handle.native_handle("handle"))
2842             f.write(";\n");
2843         f.write("    default:\n")
2844         f.write("       return handle;\n")
2845         f.write("    }\n")
2846         f.write("}\n\n")
2848         f.write("const unixlib_entry_t __wine_unix_call_funcs[] =\n")
2849         f.write("{\n")
2850         f.write("    init_vulkan,\n")
2851         f.write("    vk_is_available_instance_function,\n")
2852         f.write("    vk_is_available_device_function,\n")
2853         for vk_func in self.registry.funcs.values():
2854             if not vk_func.needs_exposing():
2855                 continue
2856             if vk_func.loader_thunk_type == ThunkType.NONE:
2857                 continue
2859             f.write("    {1}{0},\n".format(vk_func.name, prefix))
2860         f.write("};\n")
2861         f.write("C_ASSERT(ARRAYSIZE(__wine_unix_call_funcs) == unix_count);\n\n")
2863         f.write("NTSTATUS WINAPI vk_direct_unix_call(unixlib_handle_t handle, unsigned int code, void *params)\n")
2864         f.write("{\n")
2865         f.write("    return __wine_unix_call_funcs[code](params);\n")
2866         f.write("}\n")
2868     def generate_thunks_h(self, f, prefix):
2869         self._generate_copyright(f)
2871         f.write("#ifndef __WINE_VULKAN_THUNKS_H\n")
2872         f.write("#define __WINE_VULKAN_THUNKS_H\n\n")
2874         f.write("#define WINE_VK_VERSION VK_API_VERSION_{0}_{1}\n\n".format(WINE_VK_VERSION[0], WINE_VK_VERSION[1]))
2876         # Generate prototypes for device and instance functions requiring a custom implementation.
2877         f.write("/* Functions for which we have custom implementations outside of the thunks. */\n")
2878         for vk_func in self.registry.funcs.values():
2879             if not vk_func.needs_exposing():
2880                 continue
2881             if vk_func.needs_thunk() and not vk_func.needs_private_thunk():
2882                 continue
2884             f.write("NTSTATUS {0}{1}(void *args) DECLSPEC_HIDDEN;\n".format(prefix, vk_func.name))
2885         f.write("\n")
2887         f.write("/* Private thunks */\n")
2888         for vk_func in self.registry.funcs.values():
2889             if vk_func.needs_private_thunk():
2890                 f.write("{0};\n".format(vk_func.prototype(prefix="thunk_", postfix="DECLSPEC_HIDDEN")))
2891         f.write("\n")
2893         for struct in self.host_structs:
2894             f.write("#if defined(USE_STRUCT_CONVERSION)\n")
2895             f.write(struct.definition(align=False, conv=True, postfix="_host"))
2896             f.write("#else\n")
2897             f.write("typedef {0} {0}_host;\n".format(struct.name))
2898             f.write("#endif\n\n")
2899         f.write("\n")
2901         for func in self.struct_chain_conversions:
2902             f.write(func.prototype(postfix="DECLSPEC_HIDDEN") + ";\n")
2903         f.write("\n")
2905         f.write("/* For use by vkDevice and children */\n")
2906         f.write("struct vulkan_device_funcs\n{\n")
2907         for vk_func in self.registry.device_funcs:
2908             if not vk_func.is_required():
2909                 continue
2911             if not vk_func.needs_dispatch():
2912                 LOGGER.debug("skipping {0} in vulkan_device_funcs".format(vk_func.name))
2913                 continue
2915             f.write("    {0};\n".format(vk_func.pfn(conv=vk_func.needs_conversion())))
2916         f.write("};\n\n")
2918         f.write("/* For use by vkInstance and children */\n")
2919         f.write("struct vulkan_instance_funcs\n{\n")
2920         for vk_func in self.registry.instance_funcs + self.registry.phys_dev_funcs:
2921             if not vk_func.is_required():
2922                 continue
2924             if not vk_func.needs_dispatch():
2925                 LOGGER.debug("skipping {0} in vulkan_instance_funcs".format(vk_func.name))
2926                 continue
2928             f.write("    {0};\n".format(vk_func.pfn(conv=vk_func.needs_conversion())))
2929         f.write("};\n\n")
2931         f.write("#define ALL_VK_DEVICE_FUNCS() \\\n")
2932         first = True
2933         for vk_func in self.registry.device_funcs:
2934             if not vk_func.is_required():
2935                 continue
2937             if not vk_func.needs_dispatch():
2938                 LOGGER.debug("skipping {0} in ALL_VK_DEVICE_FUNCS".format(vk_func.name))
2939                 continue
2941             if first:
2942                 f.write("    USE_VK_FUNC({0})".format(vk_func.name))
2943                 first = False
2944             else:
2945                 f.write(" \\\n    USE_VK_FUNC({0})".format(vk_func.name))
2946         f.write("\n\n")
2948         f.write("#define ALL_VK_INSTANCE_FUNCS() \\\n")
2949         first = True
2950         for vk_func in self.registry.instance_funcs + self.registry.phys_dev_funcs:
2951             if not vk_func.is_required():
2952                 continue
2954             if not vk_func.needs_dispatch():
2955                 LOGGER.debug("skipping {0} in ALL_VK_INSTANCE_FUNCS".format(vk_func.name))
2956                 continue
2958             if first:
2959                 f.write("    USE_VK_FUNC({0})".format(vk_func.name))
2960                 first = False
2961             else:
2962                 f.write(" \\\n    USE_VK_FUNC({0})".format(vk_func.name))
2963         f.write("\n\n")
2965         f.write("#endif /* __WINE_VULKAN_THUNKS_H */\n")
2967     def generate_loader_thunks_c(self, f):
2968         self._generate_copyright(f)
2970         f.write("#include \"vulkan_loader.h\"\n\n")
2972         f.write("WINE_DEFAULT_DEBUG_CHANNEL(vulkan);\n\n")
2974         for vk_func in self.registry.funcs.values():
2975             if not vk_func.needs_exposing():
2976                 continue
2977             if vk_func.loader_thunk_type != ThunkType.PUBLIC:
2978                 continue
2980             f.write(vk_func.loader_thunk())
2982         f.write("static const struct vulkan_func vk_device_dispatch_table[] =\n{\n")
2983         for vk_func in self.registry.device_funcs:
2984             if not vk_func.needs_exposing():
2985                 continue
2987             f.write("    {{\"{0}\", {0}}},\n".format(vk_func.name))
2988         f.write("};\n\n")
2990         f.write("static const struct vulkan_func vk_phys_dev_dispatch_table[] =\n{\n")
2991         for vk_func in self.registry.phys_dev_funcs:
2992             if not vk_func.needs_exposing():
2993                 continue
2995             f.write("    {{\"{0}\", {0}}},\n".format(vk_func.name))
2996         f.write("};\n\n")
2998         f.write("static const struct vulkan_func vk_instance_dispatch_table[] =\n{\n")
2999         for vk_func in self.registry.instance_funcs:
3000             if not vk_func.needs_exposing():
3001                 continue
3003             f.write("    {{\"{0}\", {0}}},\n".format(vk_func.name))
3004         f.write("};\n\n")
3006         f.write("void *wine_vk_get_device_proc_addr(const char *name)\n")
3007         f.write("{\n")
3008         f.write("    unsigned int i;\n")
3009         f.write("    for (i = 0; i < ARRAY_SIZE(vk_device_dispatch_table); i++)\n")
3010         f.write("    {\n")
3011         f.write("        if (strcmp(vk_device_dispatch_table[i].name, name) == 0)\n")
3012         f.write("        {\n")
3013         f.write("            TRACE(\"Found name=%s in device table\\n\", debugstr_a(name));\n")
3014         f.write("            return vk_device_dispatch_table[i].func;\n")
3015         f.write("        }\n")
3016         f.write("    }\n")
3017         f.write("    return NULL;\n")
3018         f.write("}\n\n")
3020         f.write("void *wine_vk_get_phys_dev_proc_addr(const char *name)\n")
3021         f.write("{\n")
3022         f.write("    unsigned int i;\n")
3023         f.write("    for (i = 0; i < ARRAY_SIZE(vk_phys_dev_dispatch_table); i++)\n")
3024         f.write("    {\n")
3025         f.write("        if (strcmp(vk_phys_dev_dispatch_table[i].name, name) == 0)\n")
3026         f.write("        {\n")
3027         f.write("            TRACE(\"Found name=%s in physical device table\\n\", debugstr_a(name));\n")
3028         f.write("            return vk_phys_dev_dispatch_table[i].func;\n")
3029         f.write("        }\n")
3030         f.write("    }\n")
3031         f.write("    return NULL;\n")
3032         f.write("}\n\n")
3034         f.write("void *wine_vk_get_instance_proc_addr(const char *name)\n")
3035         f.write("{\n")
3036         f.write("    unsigned int i;\n")
3037         f.write("    for (i = 0; i < ARRAY_SIZE(vk_instance_dispatch_table); i++)\n")
3038         f.write("    {\n")
3039         f.write("        if (strcmp(vk_instance_dispatch_table[i].name, name) == 0)\n")
3040         f.write("        {\n")
3041         f.write("            TRACE(\"Found name=%s in instance table\\n\", debugstr_a(name));\n")
3042         f.write("            return vk_instance_dispatch_table[i].func;\n")
3043         f.write("        }\n")
3044         f.write("    }\n")
3045         f.write("    return NULL;\n")
3046         f.write("}\n")
3048     def generate_loader_thunks_h(self, f):
3049         self._generate_copyright(f)
3051         f.write("#ifndef __WINE_VULKAN_LOADER_THUNKS_H\n")
3052         f.write("#define __WINE_VULKAN_LOADER_THUNKS_H\n\n")
3054         f.write("enum unix_call\n")
3055         f.write("{\n")
3056         f.write("    unix_init,\n")
3057         f.write("    unix_is_available_instance_function,\n")
3058         f.write("    unix_is_available_device_function,\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.extra_param:
3082                 f.write("    void *{0};\n".format(vk_func.extra_param))
3083             if vk_func.returns_longlong():
3084                 f.write("    {0} result;\n".format(vk_func.type))
3085             f.write("};\n\n");
3087         f.write("#include \"poppack.h\"\n\n")
3088         f.write("#endif /* __WINE_VULKAN_LOADER_THUNKS_H */\n")
3090     def generate_vulkan_h(self, f):
3091         self._generate_copyright(f)
3092         f.write("#ifndef __WINE_VULKAN_H\n")
3093         f.write("#define __WINE_VULKAN_H\n\n")
3095         f.write("#include <windef.h>\n")
3096         f.write("#include <stdint.h>\n\n")
3098         f.write("/* Define WINE_VK_HOST to get 'host' headers. */\n")
3099         f.write("#ifdef WINE_VK_HOST\n")
3100         f.write("#define VKAPI_CALL\n")
3101         f.write('#define WINE_VK_ALIGN(x)\n')
3102         f.write("#endif\n\n")
3104         f.write("#ifndef VKAPI_CALL\n")
3105         f.write("#define VKAPI_CALL __stdcall\n")
3106         f.write("#endif\n\n")
3108         f.write("#ifndef VKAPI_PTR\n")
3109         f.write("#define VKAPI_PTR VKAPI_CALL\n")
3110         f.write("#endif\n\n")
3112         f.write("#ifndef WINE_VK_ALIGN\n")
3113         f.write("#define WINE_VK_ALIGN DECLSPEC_ALIGN\n")
3114         f.write("#endif\n\n")
3116         # The overall strategy is to define independent constants and datatypes,
3117         # prior to complex structures and function calls to avoid forward declarations.
3118         for const in self.registry.consts:
3119             # For now just generate things we may not need. The amount of parsing needed
3120             # to get some of the info is tricky as you need to figure out which structure
3121             # references a certain constant.
3122             f.write(const.definition())
3123         f.write("\n")
3125         for define in self.registry.defines:
3126             f.write(define.definition())
3128         for handle in self.registry.handles:
3129             # For backward compatibility also create definitions for aliases.
3130             # These types normally don't get pulled in as we use the new types
3131             # even in legacy functions if they are aliases.
3132             if handle.is_required() or handle.is_alias():
3133                  f.write(handle.definition())
3134         f.write("\n")
3136         for base_type in self.registry.base_types:
3137             f.write(base_type.definition())
3138         f.write("\n")
3140         for bitmask in self.registry.bitmasks:
3141             f.write(bitmask.definition())
3142         f.write("\n")
3144         # Define enums, this includes values for some of the bitmask types as well.
3145         for enum in self.registry.enums.values():
3146             if enum.required:
3147                 f.write(enum.definition())
3149         for fp in self.registry.funcpointers:
3150             if fp.required:
3151                 f.write(fp.definition())
3152         f.write("\n")
3154         # This generates both structures and unions. Since structures
3155         # may depend on other structures/unions, we need a list of
3156         # decoupled structs.
3157         # Note: unions are stored in structs for dependency reasons,
3158         # see comment in parsing section.
3159         structs = VkStruct.decouple_structs(self.registry.structs)
3160         for struct in structs:
3161             LOGGER.debug("Generating struct: {0}".format(struct.name))
3162             f.write(struct.definition(align=True))
3163             f.write("\n")
3165         for func in self.registry.funcs.values():
3166             if not func.is_required():
3167                 LOGGER.debug("Skipping PFN definition for: {0}".format(func.name))
3168                 continue
3170             f.write("typedef {0};\n".format(func.pfn(prefix="PFN", call_conv="VKAPI_PTR")))
3171         f.write("\n")
3173         f.write("#ifndef VK_NO_PROTOTYPES\n")
3174         for func in self.registry.funcs.values():
3175             if not func.is_required():
3176                 LOGGER.debug("Skipping API definition for: {0}".format(func.name))
3177                 continue
3179             LOGGER.debug("Generating API definition for: {0}".format(func.name))
3180             f.write("{0};\n".format(func.prototype(call_conv="VKAPI_CALL")))
3181         f.write("#endif /* VK_NO_PROTOTYPES */\n\n")
3183         f.write("#endif /* __WINE_VULKAN_H */\n")
3185     def generate_vulkan_driver_h(self, f):
3186         self._generate_copyright(f)
3187         f.write("#ifndef __WINE_VULKAN_DRIVER_H\n")
3188         f.write("#define __WINE_VULKAN_DRIVER_H\n\n")
3190         f.write("/* Wine internal vulkan driver version, needs to be bumped upon vulkan_funcs changes. */\n")
3191         f.write("#define WINE_VULKAN_DRIVER_VERSION {0}\n\n".format(DRIVER_VERSION))
3193         f.write("struct vulkan_funcs\n{\n")
3194         f.write("    /* Vulkan global functions. These are the only calls at this point a graphics driver\n")
3195         f.write("     * needs to provide. Other function calls will be provided indirectly by dispatch\n")
3196         f.write("     * tables part of dispatchable Vulkan objects such as VkInstance or vkDevice.\n")
3197         f.write("     */\n")
3199         for vk_func in self.registry.funcs.values():
3200             if not vk_func.is_driver_func():
3201                 continue
3203             pfn = vk_func.pfn()
3204             # Avoid PFN_vkVoidFunction in driver interface as Vulkan likes to put calling convention
3205             # stuff in there. For simplicity substitute with "void *".
3206             pfn = pfn.replace("PFN_vkVoidFunction", "void *")
3207             f.write("    {0};\n".format(pfn))
3209         f.write("\n")
3210         f.write("    /* winevulkan specific functions */\n")
3211         f.write("    VkSurfaceKHR (*p_wine_get_native_surface)(VkSurfaceKHR);\n")
3212         f.write("};\n\n")
3214         f.write("extern const struct vulkan_funcs * __wine_get_vulkan_driver(UINT version);\n\n")
3216         f.write("static inline void *get_vulkan_driver_device_proc_addr(\n")
3217         f.write("        const struct vulkan_funcs *vulkan_funcs, const char *name)\n{\n")
3218         f.write("    if (!name || name[0] != 'v' || name[1] != 'k') return NULL;\n\n")
3219         f.write("    name += 2;\n\n")
3220         for vk_func in self.registry.funcs.values():
3221             if vk_func.is_driver_func() and vk_func.is_device_func():
3222                 f.write('    if (!strcmp(name, "{0}"))\n'.format(vk_func.name[2:]))
3223                 f.write('        return vulkan_funcs->p_{0};\n'.format(vk_func.name))
3224         f.write("\n")
3225         f.write("    return NULL;\n}\n\n")
3227         f.write("static inline void *get_vulkan_driver_instance_proc_addr(\n")
3228         f.write("        const struct vulkan_funcs *vulkan_funcs, VkInstance instance, const char *name)\n{\n")
3229         f.write("    if (!name || name[0] != 'v' || name[1] != 'k') return NULL;\n\n")
3230         f.write("    name += 2;\n\n")
3231         for vk_func in self.registry.funcs.values():
3232             if vk_func.is_driver_func() and vk_func.is_global_func() and vk_func.name != "vkGetInstanceProcAddr":
3233                 f.write('    if (!strcmp(name, "{0}"))\n'.format(vk_func.name[2:]))
3234                 f.write('        return vulkan_funcs->p_{0};\n'.format(vk_func.name))
3235         f.write("\n")
3236         f.write("    if (!instance) return NULL;\n\n")
3237         for vk_func in self.registry.funcs.values():
3238             if vk_func.is_driver_func() and (vk_func.is_instance_func() or vk_func.is_phys_dev_func()):
3239                 f.write('    if (!strcmp(name, "{0}"))\n'.format(vk_func.name[2:]))
3240                 f.write('        return vulkan_funcs->p_{0};\n'.format(vk_func.name))
3241         f.write("\n")
3242         f.write("    name -= 2;\n\n")
3243         f.write("    return get_vulkan_driver_device_proc_addr(vulkan_funcs, name);\n}\n\n")
3245         f.write("#endif /* __WINE_VULKAN_DRIVER_H */\n")
3247     def generate_vulkan_spec(self, f):
3248         self._generate_copyright(f, spec_file=True)
3249         f.write("@ stdcall -private vk_icdGetInstanceProcAddr(ptr str)\n")
3250         f.write("@ stdcall -private vk_icdGetPhysicalDeviceProcAddr(ptr str)\n")
3251         f.write("@ stdcall -private vk_icdNegotiateLoaderICDInterfaceVersion(ptr)\n")
3253         # Export symbols for all Vulkan Core functions.
3254         for func in self.registry.funcs.values():
3255             if not func.is_core_func():
3256                 continue
3258             # We support all Core functions except for VK_KHR_display* APIs.
3259             # Create stubs for unsupported Core functions.
3260             if func.is_required():
3261                 f.write(func.spec())
3262             else:
3263                 f.write("@ stub {0}\n".format(func.name))
3265         f.write("@ stdcall -private DllRegisterServer()\n")
3266         f.write("@ stdcall -private DllUnregisterServer()\n")
3268     def generate_vulkan_loader_spec(self, f):
3269         self._generate_copyright(f, spec_file=True)
3271         # Export symbols for all Vulkan Core functions.
3272         for func in self.registry.funcs.values():
3273             if not func.is_core_func():
3274                 continue
3276             # We support all Core functions except for VK_KHR_display* APIs.
3277             # Create stubs for unsupported Core functions.
3278             if func.is_required():
3279                 f.write(func.spec(symbol="winevulkan." + func.name))
3280             else:
3281                 f.write("@ stub {0}\n".format(func.name))
3284 class VkRegistry(object):
3285     def __init__(self, reg_filename):
3286         # Used for storage of type information.
3287         self.base_types = None
3288         self.bitmasks = None
3289         self.consts = None
3290         self.defines = None
3291         self.enums = None
3292         self.funcpointers = None
3293         self.handles = None
3294         self.structs = None
3296         # We aggregate all types in here for cross-referencing.
3297         self.funcs = {}
3298         self.types = {}
3300         self.version_regex = re.compile(
3301             r'^'
3302             r'VK_VERSION_'
3303             r'(?P<major>[0-9])'
3304             r'_'
3305             r'(?P<minor>[0-9])'
3306             r'$'
3307         )
3309         # Overall strategy for parsing the registry is to first
3310         # parse all type / function definitions. Then parse
3311         # features and extensions to decide which types / functions
3312         # to actually 'pull in' for code generation. For each type or
3313         # function call we want we set a member 'required' to True.
3314         tree = ET.parse(reg_filename)
3315         root = tree.getroot()
3316         self._parse_enums(root)
3317         self._parse_types(root)
3318         self._parse_commands(root)
3320         # Pull in any required types and functions.
3321         self._parse_features(root)
3322         self._parse_extensions(root)
3324         for enum in self.enums.values():
3325             enum.fixup_64bit_aliases()
3327         self._match_object_types()
3329         self.copyright = root.find('./comment').text
3331     def _is_feature_supported(self, feature):
3332         version = self.version_regex.match(feature)
3333         if not version:
3334             return True
3336         version = tuple(map(int, version.group('major', 'minor')))
3337         return version <= WINE_VK_VERSION
3339     def _is_extension_supported(self, extension):
3340         # We disable some extensions as either we haven't implemented
3341         # support yet or because they are for platforms other than win32.
3342         return extension not in UNSUPPORTED_EXTENSIONS
3344     def _mark_command_required(self, command):
3345         """ Helper function to mark a certain command and the datatypes it needs as required."""
3346         def mark_bitmask_dependencies(bitmask, types):
3347             if bitmask.requires is not None:
3348                 types[bitmask.requires]["data"].required = True
3350         def mark_funcpointer_dependencies(fp, types):
3351             for m in fp.members:
3352                 type_info = types[m.type]
3354                 # Complex types have a matching definition e.g. VkStruct.
3355                 # Not needed for base types such as uint32_t.
3356                 if "data" in type_info:
3357                     types[m.type]["data"].required = True
3359         def mark_struct_dependencies(struct, types):
3360              for m in struct:
3361                 type_info = types[m.type]
3363                 # Complex types have a matching definition e.g. VkStruct.
3364                 # Not needed for base types such as uint32_t.
3365                 if "data" in type_info:
3366                     types[m.type]["data"].required = True
3368                 if type_info["category"] == "struct" and struct.name != m.type:
3369                     # Yay, recurse
3370                     mark_struct_dependencies(type_info["data"], types)
3371                 elif type_info["category"] == "funcpointer":
3372                     mark_funcpointer_dependencies(type_info["data"], types)
3373                 elif type_info["category"] == "bitmask":
3374                     mark_bitmask_dependencies(type_info["data"], types)
3376         func = self.funcs[command]
3377         func.required = True
3379         # Pull in return type
3380         if func.type != "void":
3381             self.types[func.type]["data"].required = True
3383         # Analyze parameter dependencies and pull in any type needed.
3384         for p in func.params:
3385             type_info = self.types[p.type]
3387             # Check if we are dealing with a complex type e.g. VkEnum, VkStruct and others.
3388             if "data" not in type_info:
3389                 continue
3391             # Mark the complex type as required.
3392             type_info["data"].required = True
3393             if type_info["category"] == "struct":
3394                 struct = type_info["data"]
3395                 mark_struct_dependencies(struct, self.types)
3396             elif type_info["category"] == "bitmask":
3397                 mark_bitmask_dependencies(type_info["data"], self.types)
3399     def _match_object_types(self):
3400         """ Matches each handle with the correct object type. """
3401         # Use upper case comparison for simplicity.
3402         object_types = {}
3403         for value in self.enums["VkObjectType"].values:
3404             object_name = "VK" + value.name[len("VK_OBJECT_TYPE"):].replace("_", "")
3405             object_types[object_name] = value.name
3407         for handle in self.handles:
3408             if not handle.is_required():
3409                 continue
3410             handle.object_type = object_types.get(handle.name.upper())
3411             if not handle.object_type:
3412                 LOGGER.warning("No object type found for {}".format(handle.name))
3414     def _parse_commands(self, root):
3415         """ Parse command section containing the Vulkan function calls. """
3416         funcs = {}
3417         commands = root.findall("./commands/")
3419         # As of Vulkan 1.1, various extensions got promoted to Core.
3420         # The old commands (e.g. KHR) are available for backwards compatibility
3421         # and are marked in vk.xml as 'alias' to the non-extension type.
3422         # The registry likes to avoid data duplication, so parameters and other
3423         # metadata need to be looked up from the Core command.
3424         # We parse the alias commands in a second pass.
3425         alias_commands = []
3426         for command in commands:
3427             alias_name = command.attrib.get("alias")
3428             if alias_name:
3429                 alias_commands.append(command)
3430                 continue
3432             func = VkFunction.from_xml(command, self.types)
3433             funcs[func.name] = func
3435         for command in alias_commands:
3436             alias_name = command.attrib.get("alias")
3437             alias = funcs[alias_name]
3438             func = VkFunction.from_alias(command, alias)
3439             funcs[func.name] = func
3441         # To make life easy for the code generation, separate all function
3442         # calls out in the 4 types of Vulkan functions:
3443         # device, global, physical device and instance.
3444         device_funcs = []
3445         global_funcs = []
3446         phys_dev_funcs = []
3447         instance_funcs = []
3448         for func in funcs.values():
3449             if func.is_device_func():
3450                 device_funcs.append(func)
3451             elif func.is_global_func():
3452                 global_funcs.append(func)
3453             elif func.is_phys_dev_func():
3454                 phys_dev_funcs.append(func)
3455             else:
3456                 instance_funcs.append(func)
3458         # Sort function lists by name and store them.
3459         self.device_funcs = sorted(device_funcs, key=lambda func: func.name)
3460         self.global_funcs = sorted(global_funcs, key=lambda func: func.name)
3461         self.phys_dev_funcs = sorted(phys_dev_funcs, key=lambda func: func.name)
3462         self.instance_funcs = sorted(instance_funcs, key=lambda func: func.name)
3464         # The funcs dictionary is used as a convenient way to lookup function
3465         # calls when needed e.g. to adjust member variables.
3466         self.funcs = OrderedDict(sorted(funcs.items()))
3468     def _parse_enums(self, root):
3469         """ Parse enums section or better described as constants section. """
3470         enums = {}
3471         self.consts = []
3472         for enum in root.findall("./enums"):
3473             name = enum.attrib.get("name")
3474             _type = enum.attrib.get("type")
3476             if _type in ("enum", "bitmask"):
3477                 enums[name] = VkEnum.from_xml(enum)
3478             else:
3479                 # If no type is set, we are dealing with API constants.
3480                 for value in enum.findall("enum"):
3481                     # If enum is an alias, set the value to the alias name.
3482                     # E.g. VK_LUID_SIZE_KHR is an alias to VK_LUID_SIZE.
3483                     alias = value.attrib.get("alias")
3484                     if alias:
3485                         self.consts.append(VkConstant(value.attrib.get("name"), alias))
3486                     else:
3487                         self.consts.append(VkConstant(value.attrib.get("name"), value.attrib.get("value")))
3489         self.enums = OrderedDict(sorted(enums.items()))
3491     def _process_require_enum(self, enum_elem, ext=None, only_aliased=False):
3492         if "extends" in enum_elem.keys():
3493             enum = self.types[enum_elem.attrib["extends"]]["data"]
3495             # Need to define VkEnumValues which were aliased to by another value. This is necessary
3496             # from VK spec version 1.2.135 where the provisional VK_KHR_ray_tracing extension was
3497             # added which altered VK_NV_ray_tracing's VkEnumValues to alias to the provisional
3498             # extension.
3499             aliased = False
3500             for _, t in self.types.items():
3501                 if t["category"] != "enum":
3502                     continue
3503                 if not t["data"]:
3504                     continue
3505                 for value in t["data"].values:
3506                     if value.alias == enum_elem.attrib["name"]:
3507                         aliased = True
3509             if only_aliased and not aliased:
3510                 return
3512             if "bitpos" in enum_elem.keys():
3513                 # We need to add an extra value to an existing enum type.
3514                 # E.g. VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG to VkFormatFeatureFlagBits.
3515                 enum.create_bitpos(enum_elem.attrib["name"], int(enum_elem.attrib["bitpos"]))
3517             elif "offset" in enum_elem.keys():
3518                 # Extensions promoted to Core, have the extension number as part
3519                 # of the enum value. Else retrieve from the extension tag.
3520                 if enum_elem.attrib.get("extnumber"):
3521                     ext_number = int(enum_elem.attrib.get("extnumber"))
3522                 else:
3523                     ext_number = int(ext.attrib["number"])
3524                 offset = int(enum_elem.attrib["offset"])
3525                 value = EXT_BASE + (ext_number - 1) * EXT_BLOCK_SIZE + offset
3527                 # Deal with negative values.
3528                 direction = enum_elem.attrib.get("dir")
3529                 if direction is not None:
3530                     value = -value
3532                 enum.create_value(enum_elem.attrib["name"], str(value))
3534             elif "value" in enum_elem.keys():
3535                 enum.create_value(enum_elem.attrib["name"], enum_elem.attrib["value"])
3536             elif "alias" in enum_elem.keys():
3537                 enum.create_alias(enum_elem.attrib["name"], enum_elem.attrib["alias"])
3539         elif "value" in enum_elem.keys():
3540             # Constant with an explicit value
3541             if only_aliased:
3542                 return
3544             self.consts.append(VkConstant(enum_elem.attrib["name"], enum_elem.attrib["value"]))
3545         elif "alias" in enum_elem.keys():
3546             # Aliased constant
3547             if not only_aliased:
3548                 return
3550             self.consts.append(VkConstant(enum_elem.attrib["name"], enum_elem.attrib["alias"]))
3552     @staticmethod
3553     def _require_type(type_info):
3554         if type_info.is_alias():
3555             type_info = type_info.alias
3556         type_info.required = True
3557         if type(type_info) == VkStruct:
3558             for member in type_info.members:
3559                 if "data" in member.type_info:
3560                   VkRegistry._require_type(member.type_info["data"])
3562     def _parse_extensions(self, root):
3563         """ Parse extensions section and pull in any types and commands for this extension. """
3564         extensions = []
3565         exts = root.findall("./extensions/extension")
3566         deferred_exts = []
3567         skipped_exts = UNSUPPORTED_EXTENSIONS.copy()
3569         def process_ext(ext, deferred=False):
3570             ext_name = ext.attrib["name"]
3572             # Set extension name on any functions calls part of this extension as we
3573             # were not aware of the name during initial parsing.
3574             commands = ext.findall("require/command")
3575             for command in commands:
3576                 cmd_name = command.attrib["name"]
3577                 # Need to verify that the command is defined, and otherwise skip it.
3578                 # vkCreateScreenSurfaceQNX is declared in <extensions> but not defined in
3579                 # <commands>. A command without a definition cannot be enabled, so it's valid for
3580                 # the XML file to handle this, but because of the manner in which we parse the XML
3581                 # file we pre-populate from <commands> before we check if a command is enabled.
3582                 if cmd_name in self.funcs:
3583                     self.funcs[cmd_name].extensions.add(ext_name)
3585             # Some extensions are not ready or have numbers reserved as a place holder.
3586             if ext.attrib["supported"] == "disabled":
3587                 LOGGER.debug("Skipping disabled extension: {0}".format(ext_name))
3588                 skipped_exts.append(ext_name)
3589                 return
3591             # Defer extensions with 'sortorder' as they are order-dependent for spec-parsing.
3592             if not deferred and "sortorder" in ext.attrib:
3593                 deferred_exts.append(ext)
3594                 return
3596             # Disable highly experimental extensions as the APIs are unstable and can
3597             # change between minor Vulkan revisions until API is final and becomes KHR
3598             # or NV.
3599             if ("KHX" in ext_name or "NVX" in ext_name) and ext_name not in ALLOWED_X_EXTENSIONS:
3600                 LOGGER.debug("Skipping experimental extension: {0}".format(ext_name))
3601                 skipped_exts.append(ext_name)
3602                 return
3604             # Extensions can define VkEnumValues which alias to provisional extensions. Pre-process
3605             # extensions to define any required VkEnumValues before the platform check below.
3606             for require in ext.findall("require"):
3607                 # Extensions can add enum values to Core / extension enums, so add these.
3608                 for enum_elem in require.findall("enum"):
3609                     self._process_require_enum(enum_elem, ext, only_aliased=True)
3611             platform = ext.attrib.get("platform")
3612             if platform and platform != "win32":
3613                 LOGGER.debug("Skipping extensions {0} for platform {1}".format(ext_name, platform))
3614                 skipped_exts.append(ext_name)
3615                 return
3617             if not self._is_extension_supported(ext_name):
3618                 LOGGER.debug("Skipping unsupported extension: {0}".format(ext_name))
3619                 skipped_exts.append(ext_name)
3620                 return
3621             elif "requires" in ext.attrib:
3622                 # Check if this extension builds on top of another unsupported extension.
3623                 requires = ext.attrib["requires"].split(",")
3624                 if len(set(requires).intersection(skipped_exts)) > 0:
3625                     skipped_exts.append(ext_name)
3626                     return
3628             LOGGER.debug("Loading extension: {0}".format(ext_name))
3630             # Extensions can define one or more require sections each requiring
3631             # different features (e.g. Vulkan 1.1). Parse each require section
3632             # separately, so we can skip sections we don't want.
3633             for require in ext.findall("require"):
3634                 # Extensions can add enum values to Core / extension enums, so add these.
3635                 for enum_elem in require.findall("enum"):
3636                     self._process_require_enum(enum_elem, ext)
3638                 for t in require.findall("type"):
3639                     type_info = self.types[t.attrib["name"]]["data"]
3640                     self._require_type(type_info)
3641                 feature = require.attrib.get("feature")
3642                 if feature and not self._is_feature_supported(feature):
3643                     continue
3645                 required_extension = require.attrib.get("extension")
3646                 if required_extension and not self._is_extension_supported(required_extension):
3647                     continue
3649                 # Pull in any commands we need. We infer types to pull in from the command
3650                 # as well.
3651                 for command in require.findall("command"):
3652                     cmd_name = command.attrib["name"]
3653                     self._mark_command_required(cmd_name)
3656             # Store a list with extensions.
3657             ext_info = {"name" : ext_name, "type" : ext.attrib["type"]}
3658             extensions.append(ext_info)
3661         # Process extensions, allowing for sortorder to defer extension processing
3662         for ext in exts:
3663             process_ext(ext)
3665         deferred_exts.sort(key=lambda ext: ext.attrib["sortorder"])
3667         # Respect sortorder
3668         for ext in deferred_exts:
3669             process_ext(ext, deferred=True)
3671         # Sort in alphabetical order.
3672         self.extensions = sorted(extensions, key=lambda ext: ext["name"])
3674     def _parse_features(self, root):
3675         """ Parse the feature section, which describes Core commands and types needed. """
3677         for feature in root.findall("./feature"):
3678             feature_name = feature.attrib["name"]
3679             for require in feature.findall("require"):
3680                 LOGGER.info("Including features for {0}".format(require.attrib.get("comment")))
3681                 for tag in require:
3682                     if tag.tag == "comment":
3683                         continue
3684                     elif tag.tag == "command":
3685                         if not self._is_feature_supported(feature_name):
3686                             continue
3687                         name = tag.attrib["name"]
3688                         self._mark_command_required(name)
3689                     elif tag.tag == "enum":
3690                         self._process_require_enum(tag)
3691                     elif tag.tag == "type":
3692                         name = tag.attrib["name"]
3694                         # Skip pull in for vk_platform.h for now.
3695                         if name == "vk_platform":
3696                             continue
3698                         type_info = self.types[name]
3699                         type_info["data"].required = True
3701     def _parse_types(self, root):
3702         """ Parse types section, which contains all data types e.g. structs, typedefs etcetera. """
3703         types = root.findall("./types/type")
3705         base_types = []
3706         bitmasks = []
3707         defines = []
3708         funcpointers = []
3709         handles = []
3710         structs = []
3712         alias_types = []
3713         for t in types:
3714             type_info = {}
3715             type_info["category"] = t.attrib.get("category", None)
3716             type_info["requires"] = t.attrib.get("requires", None)
3718             # We parse aliases in a second pass when we know more.
3719             alias = t.attrib.get("alias")
3720             if alias:
3721                 LOGGER.debug("Alias found: {0}".format(alias))
3722                 alias_types.append(t)
3723                 continue
3725             if type_info["category"] in ["include"]:
3726                 continue
3728             if type_info["category"] == "basetype":
3729                 name = t.find("name").text
3730                 _type = None
3731                 if not t.find("type") is None:
3732                     _type = t.find("type").text
3733                     tail = t.find("type").tail
3734                     if tail is not None:
3735                         _type += tail.strip()
3736                 basetype = VkBaseType(name, _type)
3737                 base_types.append(basetype)
3738                 type_info["data"] = basetype
3740             # Basic C types don't need us to define them, but we do need data for them
3741             if type_info["requires"] == "vk_platform":
3742                 requires = type_info["requires"]
3743                 basic_c = VkBaseType(name, _type, requires=requires)
3744                 type_info["data"] = basic_c
3746             if type_info["category"] == "bitmask":
3747                 name = t.find("name").text
3748                 _type = t.find("type").text
3750                 # Most bitmasks have a requires attribute used to pull in
3751                 # required '*FlagBits" enum.
3752                 requires = type_info["requires"]
3753                 bitmask = VkBaseType(name, _type, requires=requires)
3754                 bitmasks.append(bitmask)
3755                 type_info["data"] = bitmask
3757             if type_info["category"] == "define":
3758                 define = VkDefine.from_xml(t)
3759                 defines.append(define)
3760                 type_info["data"] = define
3762             if type_info["category"] == "enum":
3763                 name = t.attrib.get("name")
3764                 # The type section only contains enum names, not the actual definition.
3765                 # Since we already parsed the enum before, just link it in.
3766                 try:
3767                     type_info["data"] = self.enums[name]
3768                 except KeyError as e:
3769                     # Not all enums seem to be defined yet, typically that's for
3770                     # ones ending in 'FlagBits' where future extensions may add
3771                     # definitions.
3772                     type_info["data"] = None
3774             if type_info["category"] == "funcpointer":
3775                 funcpointer = VkFunctionPointer.from_xml(t)
3776                 funcpointers.append(funcpointer)
3777                 type_info["data"] = funcpointer
3779             if type_info["category"] == "handle":
3780                 handle = VkHandle.from_xml(t)
3781                 handles.append(handle)
3782                 type_info["data"] = handle
3784             if type_info["category"] in ["struct", "union"]:
3785                 # We store unions among structs as some structs depend
3786                 # on unions. The types are very similar in parsing and
3787                 # generation anyway. The official Vulkan scripts use
3788                 # a similar kind of hack.
3789                 struct = VkStruct.from_xml(t)
3790                 structs.append(struct)
3791                 type_info["data"] = struct
3793             # Name is in general within a name tag else it is an optional
3794             # attribute on the type tag.
3795             name_elem = t.find("name")
3796             if name_elem is not None:
3797                 type_info["name"] = name_elem.text
3798             else:
3799                 type_info["name"] = t.attrib.get("name", None)
3801             # Store all type data in a shared dictionary, so we can easily
3802             # look up information for a given type. There are no duplicate
3803             # names.
3804             self.types[type_info["name"]] = type_info
3806         # Second pass for alias types, so we can retrieve all data from
3807         # the aliased object.
3808         for t in alias_types:
3809             type_info = {}
3810             type_info["category"] = t.attrib.get("category")
3811             type_info["name"] = t.attrib.get("name")
3813             alias = t.attrib.get("alias")
3815             if type_info["category"] == "bitmask":
3816                 bitmask = VkBaseType(type_info["name"], alias, alias=self.types[alias]["data"])
3817                 bitmasks.append(bitmask)
3818                 type_info["data"] = bitmask
3820             if type_info["category"] == "enum":
3821                 enum = VkEnum.from_alias(t, self.types[alias]["data"])
3822                 type_info["data"] = enum
3823                 self.enums[enum.name] = enum
3825             if type_info["category"] == "handle":
3826                 handle = VkHandle.from_alias(t, self.types[alias]["data"])
3827                 handles.append(handle)
3828                 type_info["data"] = handle
3830             if type_info["category"] == "struct":
3831                 struct = VkStruct.from_alias(t, self.types[alias]["data"])
3832                 structs.append(struct)
3833                 type_info["data"] = struct
3835             self.types[type_info["name"]] = type_info
3837         # We need detailed type information during code generation
3838         # on structs for alignment reasons. Unfortunately structs
3839         # are parsed among other types, so there is no guarantee
3840         # that any types needed have been parsed already, so set
3841         # the data now.
3842         for struct in structs:
3843             struct.set_type_info(self.types)
3845             # Alias structures have enum values equivalent to those of the
3846             # structure which they are aliased against. we need to ignore alias
3847             # structs when populating the struct extensions list, otherwise we
3848             # will create duplicate case entries.
3849             if struct.alias:
3850                 continue
3852             for structextend in struct.structextends:
3853                 s = self.types[structextend]["data"]
3854                 s.struct_extensions.append(struct)
3856         # Guarantee everything is sorted, so code generation doesn't have
3857         # to deal with this.
3858         self.base_types = sorted(base_types, key=lambda base_type: base_type.name)
3859         self.bitmasks = sorted(bitmasks, key=lambda bitmask: bitmask.name)
3860         self.defines = defines
3861         self.enums = OrderedDict(sorted(self.enums.items()))
3862         self.funcpointers = sorted(funcpointers, key=lambda fp: fp.name)
3863         self.handles = sorted(handles, key=lambda handle: handle.name)
3864         self.structs = sorted(structs, key=lambda struct: struct.name)
3866 def generate_vulkan_json(f):
3867     f.write("{\n")
3868     f.write("    \"file_format_version\": \"1.0.0\",\n")
3869     f.write("    \"ICD\": {\n")
3870     f.write("        \"library_path\": \".\\\\winevulkan.dll\",\n")
3871     f.write("        \"api_version\": \"{0}\"\n".format(VK_XML_VERSION))
3872     f.write("    }\n")
3873     f.write("}\n")
3875 def set_working_directory():
3876     path = os.path.abspath(__file__)
3877     path = os.path.dirname(path)
3878     os.chdir(path)
3880 def download_vk_xml(filename):
3881     url = "https://raw.githubusercontent.com/KhronosGroup/Vulkan-Docs/v{0}/xml/vk.xml".format(VK_XML_VERSION)
3882     if not os.path.isfile(filename):
3883         urllib.request.urlretrieve(url, filename)
3885 def main():
3886     parser = argparse.ArgumentParser()
3887     parser.add_argument("-v", "--verbose", action="count", default=0, help="increase output verbosity")
3888     parser.add_argument("-x", "--xml", default=None, type=str, help="path to specification XML file")
3890     args = parser.parse_args()
3891     if args.verbose == 0:
3892         LOGGER.setLevel(logging.WARNING)
3893     elif args.verbose == 1:
3894         LOGGER.setLevel(logging.INFO)
3895     else: # > 1
3896         LOGGER.setLevel(logging.DEBUG)
3898     set_working_directory()
3900     if args.xml:
3901         vk_xml = args.xml
3902     else:
3903         vk_xml = "vk-{0}.xml".format(VK_XML_VERSION)
3904         download_vk_xml(vk_xml)
3906     registry = VkRegistry(vk_xml)
3907     generator = VkGenerator(registry)
3909     with open(WINE_VULKAN_H, "w") as f:
3910         generator.generate_vulkan_h(f)
3912     with open(WINE_VULKAN_DRIVER_H, "w") as f:
3913         generator.generate_vulkan_driver_h(f)
3915     with open(WINE_VULKAN_THUNKS_H, "w") as f:
3916         generator.generate_thunks_h(f, "wine_")
3918     with open(WINE_VULKAN_THUNKS_C, "w") as f:
3919         generator.generate_thunks_c(f, "wine_")
3921     with open(WINE_VULKAN_LOADER_THUNKS_H, "w") as f:
3922         generator.generate_loader_thunks_h(f)
3924     with open(WINE_VULKAN_LOADER_THUNKS_C, "w") as f:
3925         generator.generate_loader_thunks_c(f)
3927     with open(WINE_VULKAN_JSON, "w") as f:
3928         generate_vulkan_json(f)
3930     with open(WINE_VULKAN_SPEC, "w") as f:
3931         generator.generate_vulkan_spec(f)
3933     with open(WINE_VULKAN_LOADER_SPEC, "w") as f:
3934         generator.generate_vulkan_loader_spec(f)
3936 if __name__ == "__main__":
3937     main()