include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / dlls / winevulkan / make_vulkan
blobdbdbc48a0581c1dcea35111863be5e2358d2f509
1 #!/usr/bin/env python3
2 # Wine Vulkan generator
4 # Copyright 2017-2018 Roderick Colenbrander
5 # Copyright 2022 Jacek Caban for CodeWeavers
7 # This library is free software; you can redistribute it and/or
8 # modify it under the terms of the GNU Lesser General Public
9 #  License as published by the Free Software Foundation; either
10 # version 2.1 of the License, or (at your option) any later version.
12 # This library is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 # Lesser General Public License for more details.
17 # You should have received a copy of the GNU Lesser General Public
18 # License along with this library; if not, write to the Free Software
19 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 import argparse
23 import logging
24 import os
25 import re
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.285"
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",
94     "VK_LUNARG_direct_driver_loading", # Implemented in the Vulkan loader
96     # Device extensions
97     "VK_AMD_display_native_hdr",
98     "VK_EXT_full_screen_exclusive",
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_video_encode_queue",
105     "VK_KHR_video_queue", # TODO Video extensions use separate headers + xml
106     "VK_KHR_win32_keyed_mutex",
107     "VK_NV_external_memory_rdma", # Needs shared resources work.
109     # Extensions for other platforms
110     "VK_EXT_external_memory_dma_buf",
111     "VK_EXT_image_drm_format_modifier",
112     "VK_EXT_metal_objects",
113     "VK_EXT_physical_device_drm",
114     "VK_GOOGLE_surfaceless_query",
115     "VK_KHR_external_fence_fd",
116     "VK_KHR_external_memory_fd",
117     "VK_KHR_external_semaphore_fd",
118     "VK_SEC_amigo_profiling", # Angle specific.
120     # Extensions which require callback handling
121     "VK_EXT_device_memory_report",
123     # Deprecated extensions
124     "VK_NV_external_memory_capabilities",
125     "VK_NV_external_memory_win32",
128 # Either internal extensions which aren't present on the win32 platform which
129 # winevulkan may nonetheless use, or extensions we want to generate headers for
130 # but not expose to applications (useful for test commits)
131 UNEXPOSED_EXTENSIONS = {
132     "VK_EXT_map_memory_placed",
133     "VK_KHR_external_memory_win32",
136 # The Vulkan loader provides entry-points for core functionality and important
137 # extensions. Based on vulkan-1.def this amounts to WSI extensions on 1.0.51.
138 CORE_EXTENSIONS = [
139     "VK_KHR_display",
140     "VK_KHR_display_swapchain",
141     "VK_KHR_get_surface_capabilities2",
142     "VK_KHR_surface",
143     "VK_KHR_swapchain",
144     "VK_KHR_win32_surface",
147 # List of surface extensions that can be exposed directly to the PE side
148 WIN_SURFACE_EXTENSIONS = [
149     "VK_KHR_win32_surface",
150     "VK_EXT_headless_surface",
153 # Some experimental extensions are used by shipping applications so their API is extremely unlikely
154 # to change in a backwards-incompatible way. Allow translation of those extensions with WineVulkan.
155 ALLOWED_X_EXTENSIONS = [
156     "VK_NVX_binary_import",
157     "VK_NVX_image_view_handle",
160 # Some frequently called functions skip traces and checks for performance reasons.
161 PERF_CRITICAL_FUNCTIONS = [
162     "vkUpdateDescriptorSets",
163     "vkUpdateDescriptorSetWithTemplate",
164     "vkGetDescriptorEXT",
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 (default: True):  set whether we need a function pointer in the device / instance dispatch table.
172 FUNCTION_OVERRIDES = {
173     # Global functions
174     "vkCreateInstance" : {"extra_param" : "client_ptr"},
176     # Instance functions
177     "vkCreateDevice" : {"extra_param" : "client_ptr"},
178     "vkGetPhysicalDeviceExternalBufferProperties" : {"dispatch" : False},
179     "vkGetPhysicalDeviceExternalFenceProperties" : {"dispatch" : False},
180     "vkGetPhysicalDeviceExternalSemaphoreProperties" : {"dispatch" : False},
182     # Device functions
183     "vkCreateCommandPool" : {"extra_param" : "client_ptr"},
184     "vkGetDeviceProcAddr" : {"dispatch" : False},
186     # VK_KHR_external_fence_capabilities
187     "vkGetPhysicalDeviceExternalFencePropertiesKHR" : {"dispatch" : False},
189     # VK_KHR_external_memory_capabilities
190     "vkGetPhysicalDeviceExternalBufferPropertiesKHR" : {"dispatch" : False},
192     # VK_KHR_external_semaphore_capabilities
193     "vkGetPhysicalDeviceExternalSemaphorePropertiesKHR" : {"dispatch" : False},
196 # functions for which a user driver entry must be generated
197 USER_DRIVER_FUNCS = {
198     "vkCreateWin32SurfaceKHR",
199     "vkDestroySurfaceKHR",
200     "vkGetDeviceProcAddr",
201     "vkGetInstanceProcAddr",
202     "vkGetPhysicalDeviceWin32PresentationSupportKHR",
203     "vkQueuePresentKHR",
206 # functions for which the unix thunk is manually implemented
207 MANUAL_UNIX_THUNKS = {
208     "vkAcquireNextImage2KHR",
209     "vkAcquireNextImageKHR",
210     "vkAllocateCommandBuffers",
211     "vkAllocateMemory",
212     "vkCreateBuffer",
213     "vkCreateCommandPool",
214     "vkCreateDebugReportCallbackEXT",
215     "vkCreateDebugUtilsMessengerEXT",
216     "vkCreateDeferredOperationKHR",
217     "vkCreateDevice",
218     "vkCreateImage",
219     "vkCreateInstance",
220     "vkCreateSwapchainKHR",
221     "vkCreateWin32SurfaceKHR",
222     "vkDestroyCommandPool",
223     "vkDestroyDebugReportCallbackEXT",
224     "vkDestroyDebugUtilsMessengerEXT",
225     "vkDestroyDeferredOperationKHR",
226     "vkDestroyDevice",
227     "vkDestroyInstance",
228     "vkDestroySurfaceKHR",
229     "vkDestroySwapchainKHR",
230     "vkEnumerateDeviceExtensionProperties",
231     "vkEnumerateDeviceLayerProperties",
232     "vkEnumerateInstanceExtensionProperties",
233     "vkEnumerateInstanceLayerProperties",
234     "vkEnumerateInstanceVersion",
235     "vkEnumeratePhysicalDeviceGroups",
236     "vkEnumeratePhysicalDeviceGroupsKHR",
237     "vkEnumeratePhysicalDevices",
238     "vkFreeCommandBuffers",
239     "vkFreeMemory",
240     "vkGetCalibratedTimestampsEXT",
241     "vkGetCalibratedTimestampsKHR",
242     "vkGetDeviceProcAddr",
243     "vkGetDeviceQueue",
244     "vkGetDeviceQueue2",
245     "vkGetInstanceProcAddr",
246     "vkGetPhysicalDeviceCalibrateableTimeDomainsEXT",
247     "vkGetPhysicalDeviceCalibrateableTimeDomainsKHR",
248     "vkGetPhysicalDeviceExternalBufferProperties",
249     "vkGetPhysicalDeviceExternalBufferPropertiesKHR",
250     "vkGetPhysicalDeviceExternalFenceProperties",
251     "vkGetPhysicalDeviceExternalFencePropertiesKHR",
252     "vkGetPhysicalDeviceExternalSemaphoreProperties",
253     "vkGetPhysicalDeviceExternalSemaphorePropertiesKHR",
254     "vkGetPhysicalDeviceImageFormatProperties2",
255     "vkGetPhysicalDeviceImageFormatProperties2KHR",
256     "vkGetPhysicalDevicePresentRectanglesKHR",
257     "vkGetPhysicalDeviceSurfaceCapabilities2KHR",
258     "vkGetPhysicalDeviceSurfaceCapabilitiesKHR",
259     "vkGetPhysicalDeviceSurfaceFormats2KHR",
260     "vkMapMemory",
261     "vkMapMemory2KHR",
262     "vkQueuePresentKHR",
263     "vkUnmapMemory",
264     "vkUnmapMemory2KHR",
267 # loader functions which are entirely manually implemented
268 MANUAL_LOADER_FUNCTIONS = {
269     "vkEnumerateInstanceLayerProperties",
270     "vkGetDeviceProcAddr",
271     "vkGetInstanceProcAddr",
274 # functions which loader thunks are manually implemented
275 MANUAL_LOADER_THUNKS = {
276     "vkAllocateCommandBuffers",
277     "vkCreateCommandPool",
278     "vkCreateDevice",
279     "vkCreateInstance",
280     "vkDestroyCommandPool",
281     "vkDestroyDevice",
282     "vkDestroyInstance",
283     "vkEnumerateInstanceExtensionProperties",
284     "vkEnumerateInstanceVersion",
285     "vkFreeCommandBuffers",
286     "vkGetPhysicalDeviceProperties2",
287     "vkGetPhysicalDeviceProperties2KHR",
290 STRUCT_CHAIN_CONVERSIONS = {
291     # Ignore to not confuse host loader.
292     "VkDeviceCreateInfo": ["VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO"],
293     "VkInstanceCreateInfo": ["VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO"],
296 # Some struct members are conditionally ignored and callers are free to leave them uninitialized.
297 # We can't deduce that from XML, so we allow expressing it here.
298 MEMBER_LENGTH_EXPRESSIONS = {
299     "VkWriteDescriptorSet": {
300         "pImageInfo":
301             "{struct}descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER || " +
302             "{struct}descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER || " +
303             "{struct}descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE || " +
304             "{struct}descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE || " +
305             "{struct}descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT || " +
306             "{struct}descriptorType == VK_DESCRIPTOR_TYPE_SAMPLE_WEIGHT_IMAGE_QCOM || " +
307             "{struct}descriptorType == VK_DESCRIPTOR_TYPE_BLOCK_MATCH_IMAGE_QCOM ? {len} : 0",
308         "pBufferInfo":
309             "{struct}descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER || " +
310             "{struct}descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER || " +
311             "{struct}descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC || " +
312             "{struct}descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC ? {len} : 0",
313     }
316 class Direction(Enum):
317     """ Parameter direction: input, output, input_output. """
318     INPUT = 1
319     OUTPUT = 2
322 class Unwrap(Enum):
323     NONE = 0
324     HOST = 1
325     DRIVER = 2
328 def api_is_vulkan(obj):
329     return "vulkan" in obj.get("api", "vulkan").split(",")
332 def convert_suffix(direction, win_type, unwrap, is_wrapped):
333     if direction == Direction.OUTPUT:
334         if not is_wrapped:
335             return "host_to_{0}".format(win_type)
336         if unwrap == Unwrap.NONE:
337             return "unwrapped_host_to_{0}".format(win_type)
338         if unwrap == Unwrap.DRIVER:
339             return "driver_to_{0}".format(win_type)
340         return "host_to_{0}".format(win_type)
341     else:
342         if not is_wrapped:
343             return "{0}_to_host".format(win_type)
344         if unwrap == Unwrap.NONE:
345             return "{0}_to_unwrapped_host".format(win_type)
346         if unwrap == Unwrap.DRIVER:
347             return "{0}_to_driver".format(win_type)
348         return "{0}_to_host".format(win_type)
351 class VkBaseType(object):
352     def __init__(self, name, _type, alias=None, requires=None):
353         """ Vulkan base type class.
355         VkBaseType is mostly used by Vulkan to define its own
356         base types like VkFlags through typedef out of e.g. uint32_t.
358         Args:
359             name (:obj:'str'): Name of the base type.
360             _type (:obj:'str'): Underlying type
361             alias (bool): type is an alias or not.
362             requires (:obj:'str', optional): Other types required.
363                 Often bitmask values pull in a *FlagBits type.
364         """
365         self.name = name
366         self.type = _type
367         self.alias = alias
368         self.requires = requires
369         self.required = False
371     def definition(self):
372         # Definition is similar for alias or non-alias as type
373         # is already set to alias.
374         if not self.type is None:
375             return "typedef {0} {1};\n".format(self.type, self.name)
376         else:
377             return "struct {0};\n".format(self.name)
379     def is_alias(self):
380         return bool(self.alias)
383 class VkConstant(object):
384     def __init__(self, name, value):
385         self.name = name
386         self.value = value
388     def definition(self):
389         text = "#define {0} {1}\n".format(self.name, self.value)
390         return text
393 class VkDefine(object):
394     def __init__(self, name, value):
395         self.name = name
396         self.value = value
398     @staticmethod
399     def from_xml(define):
400         if not api_is_vulkan(define):
401             return None
403         name_elem = define.find("name")
405         if name_elem is None:
406             # <type category="define" name="some_name">some_value</type>
407             name = define.attrib.get("name")
409             # We override behavior of VK_USE_64_BIT_PTR_DEFINES as the default non-dispatchable handle
410             # definition various between 64-bit (uses pointers) and 32-bit (uses uint64_t).
411             # This complicates TRACEs in the thunks, so just use uint64_t.
412             if name == "VK_USE_64_BIT_PTR_DEFINES":
413                 value = "#define VK_USE_64_BIT_PTR_DEFINES 0"
414             else:
415                 value = define.text
416             return VkDefine(name, value)
418         # With a name element the structure is like:
419         # <type category="define"><name>some_name</name>some_value</type>
420         name = name_elem.text
422         # Perform minimal parsing for Vulkan constants, which we don't need, but are referenced
423         # elsewhere in vk.xml.
424         # - VK_API_VERSION is a messy, deprecated constant and we don't want generate code for it.
425         # - AHardwareBuffer/ANativeWindow are forward declarations for Android types, which leaked
426         #   into the define region.
427         if name in ["VK_API_VERSION", "AHardwareBuffer", "ANativeWindow", "CAMetalLayer"]:
428             return VkDefine(name, None)
430         # The body of the define is basically unstructured C code. It is not meant for easy parsing.
431         # Some lines contain deprecated values or comments, which we try to filter out.
432         value = ""
433         for line in define.text.splitlines():
434             # Skip comments or deprecated values.
435             if "//" in line:
436                 continue
437             value += line
439         for child in define:
440             value += child.text
441             if child.tail is not None:
442                 # Split comments for VK_API_VERSION_1_0 / VK_API_VERSION_1_1
443                 if "//" in child.tail:
444                     value += child.tail.split("//")[0]
445                 else:
446                     value += child.tail
448         return VkDefine(name, value.rstrip(' '))
450     def definition(self):
451         if self.value is None:
452             return ""
454         # Nothing to do as the value was already put in the right form during parsing.
455         return "{0}\n".format(self.value)
458 class VkEnum(object):
459     def __init__(self, name, bitwidth, alias=None):
460         if not bitwidth in [32, 64]:
461             LOGGER.error("unknown bitwidth {0} for {1}".format(bitwidth, name))
462         self.name = name
463         self.bitwidth = bitwidth
464         self.values = [] if alias == None else alias.values
465         self.required = False
466         self.alias = alias
467         self.aliased_by = []
469     @staticmethod
470     def from_alias(enum, alias):
471         name = enum.attrib.get("name")
472         aliasee = VkEnum(name, alias.bitwidth, alias=alias)
474         alias.add_aliased_by(aliasee)
475         return aliasee
477     @staticmethod
478     def from_xml(enum):
479         if not api_is_vulkan(enum):
480             return None
482         name = enum.attrib.get("name")
483         bitwidth = int(enum.attrib.get("bitwidth", "32"))
484         result = VkEnum(name, bitwidth)
486         for v in enum.findall("enum"):
487             value_name = v.attrib.get("name")
488             # Value is either a value or a bitpos, only one can exist.
489             value = v.attrib.get("value")
490             alias_name = v.attrib.get("alias")
491             if alias_name:
492                 result.create_alias(value_name, alias_name)
493             elif value:
494                 result.create_value(value_name, value)
495             else:
496                 # bitmask
497                 result.create_bitpos(value_name, int(v.attrib.get("bitpos")))
499         if bitwidth == 32:
500             # vulkan.h contains a *_MAX_ENUM value set to 32-bit at the time of writing,
501             # which is to prepare for extensions as they can add values and hence affect
502             # the size definition.
503             max_name = re.sub(r'([0-9a-z_])([A-Z0-9])',r'\1_\2', name).upper() + "_MAX_ENUM"
504             result.create_value(max_name, "0x7fffffff")
506         return result
508     def create_alias(self, name, alias_name):
509         """ Create an aliased value for this enum """
510         self.add(VkEnumValue(name, self.bitwidth, alias=alias_name))
512     def create_value(self, name, value):
513         """ Create a new value for this enum """
514         # Some values are in hex form. We want to preserve the hex representation
515         # at least when we convert back to a string. Internally we want to use int.
516         hex = "0x" in value
517         self.add(VkEnumValue(name, self.bitwidth, value=int(value, 0), hex=hex))
519     def create_bitpos(self, name, pos):
520         """ Create a new bitmask value for this enum """
521         self.add(VkEnumValue(name, self.bitwidth, value=(1 << pos), hex=True))
523     def add(self, value):
524         """ Add a value to enum. """
526         # Extensions can add new enum values. When an extension is promoted to Core
527         # the registry defines the value twice once for old extension and once for
528         # new Core features. Add the duplicate if it's explicitly marked as an
529         # alias, otherwise ignore it.
530         for v in self.values:
531             if not value.is_alias() and v.value == value.value:
532                 LOGGER.debug("Adding duplicate enum value {0} to {1}".format(v, self.name))
533                 return
534         # Avoid adding duplicate aliases multiple times
535         if not any(x.name == value.name for x in self.values):
536             self.values.append(value)
538     def fixup_64bit_aliases(self):
539         """ Replace 64bit aliases with literal values """
540         # Older GCC versions need a literal to initialize a static const uint64_t
541         # which is what we use for 64bit bitmasks.
542         if self.bitwidth != 64:
543             return
544         for value in self.values:
545             if not value.is_alias():
546                 continue
547             alias = next(x for x in self.values if x.name == value.alias)
548             value.hex = alias.hex
549             value.value = alias.value
551     def definition(self):
552         if self.is_alias():
553             return ""
555         default_value = 0x7ffffffe if self.bitwidth == 32 else 0xfffffffffffffffe
557         # Print values sorted, values can have been added in a random order.
558         values = sorted(self.values, key=lambda value: value.value if value.value is not None else default_value)
560         if self.bitwidth == 32:
561             text = "typedef enum {0}\n{{\n".format(self.name)
562             for value in values:
563                 text += "    {0},\n".format(value.definition())
564             text += "}} {0};\n".format(self.name)
565         elif self.bitwidth == 64:
566             text = "typedef VkFlags64 {0};\n\n".format(self.name)
567             for value in values:
568                 text += "static const {0} {1};\n".format(self.name, value.definition())
570         for aliasee in self.aliased_by:
571             text += "typedef {0} {1};\n".format(self.name, aliasee.name)
573         text += "\n"
574         return text
576     def is_alias(self):
577         return bool(self.alias)
579     def add_aliased_by(self, aliasee):
580         self.aliased_by.append(aliasee)
583 class VkEnumValue(object):
584     def __init__(self, name, bitwidth, value=None, hex=False, alias=None):
585         self.name = name
586         self.bitwidth = bitwidth
587         self.value = value
588         self.hex = hex
589         self.alias = alias
591     def __repr__(self):
592         postfix = "ull" if self.bitwidth == 64 else ""
593         if self.is_alias() and self.value == None:
594             return "{0}={1}".format(self.name, self.alias)
595         return "{0}={1}{2}".format(self.name, self.value, postfix)
597     def definition(self):
598         """ Convert to text definition e.g. VK_FOO = 1 """
599         postfix = "ull" if self.bitwidth == 64 else ""
600         if self.is_alias() and self.value == None:
601             return "{0} = {1}".format(self.name, self.alias)
603         # Hex is commonly used for FlagBits and sometimes within
604         # a non-FlagBits enum for a bitmask value as well.
605         if self.hex:
606             return "{0} = 0x{1:08x}{2}".format(self.name, self.value, postfix)
607         else:
608             return "{0} = {1}{2}".format(self.name, self.value, postfix)
610     def is_alias(self):
611         return self.alias is not None
614 class VkFunction(object):
615     def __init__(self, _type=None, name=None, params=[], alias=None):
616         self.extensions = set()
617         self.name = name
618         self.type = _type
619         self.params = params
620         self.alias = alias
622         # For some functions we need some extra metadata from FUNCTION_OVERRIDES.
623         func_info = FUNCTION_OVERRIDES.get(self.name, {})
624         self.dispatch = func_info.get("dispatch", True)
625         self.extra_param = func_info.get("extra_param", None)
627         # Required is set while parsing which APIs and types are required
628         # and is used by the code generation.
629         self.required = True if func_info else False
631         if self.name in MANUAL_UNIX_THUNKS:
632             self.unwrap = Unwrap.NONE
633         elif self.name in USER_DRIVER_FUNCS:
634             self.unwrap = Unwrap.DRIVER
635         else:
636             self.unwrap = Unwrap.HOST
638     @staticmethod
639     def from_alias(command, alias):
640         """ Create VkFunction from an alias command.
642         Args:
643             command: xml data for command
644             alias (VkFunction): function to use as a base for types / parameters.
646         Returns:
647             VkFunction
648         """
649         if not api_is_vulkan(command):
650             return None
652         func_name = command.attrib.get("name")
653         func_type = alias.type
654         params = alias.params
656         return VkFunction(_type=func_type, name=func_name, params=params, alias=alias)
658     @staticmethod
659     def from_xml(command, types):
660         if not api_is_vulkan(command):
661             return None
663         proto = command.find("proto")
664         func_name = proto.find("name").text
665         func_type = proto.find("type").text
667         params = []
668         for param in command.findall("param"):
669             vk_param = VkParam.from_xml(param, types, params)
670             if vk_param:
671                 params.append(vk_param)
673         return VkFunction(_type=func_type, name=func_name, params=params)
675     def get_conversions(self):
676         """ Get a list of conversion functions required for this function if any.
677         Parameters which are structures may require conversion between win32
678         and the host platform. This function returns a list of conversions
679         required.
680         """
682         conversions = []
683         for param in self.params:
684             conversions.extend(param.get_conversions(self.unwrap))
685         return conversions
687     def is_alias(self):
688         return bool(self.alias)
690     def is_core_func(self):
691         """ Returns whether the function is a Vulkan core function.
692         Core functions are APIs defined by the Vulkan spec to be part of the
693         Core API as well as several KHR WSI extensions.
694         """
696         if not self.extensions:
697             return True
699         return any(ext in self.extensions for ext in CORE_EXTENSIONS)
701     def is_device_func(self):
702         # If none of the other, it must be a device function
703         return not self.is_global_func() and not self.is_instance_func() and not self.is_phys_dev_func()
705     def is_driver_func(self):
706         """ Returns if function is part of Wine driver interface. """
707         return self.name in USER_DRIVER_FUNCS
709     def is_global_func(self):
710         # Treat vkGetInstanceProcAddr as a global function as it
711         # can operate with NULL for vkInstance.
712         if self.name == "vkGetInstanceProcAddr":
713             return True
714         # Global functions are not passed a dispatchable object.
715         elif self.params[0].is_dispatchable():
716             return False
717         return True
719     def is_instance_func(self):
720         # Instance functions are passed VkInstance.
721         if self.params[0].type == "VkInstance":
722             return True
723         return False
725     def is_phys_dev_func(self):
726         # Physical device functions are passed VkPhysicalDevice.
727         if self.params[0].type == "VkPhysicalDevice":
728             return True
729         return False
731     def is_required(self):
732         return self.required
734     def returns_longlong(self):
735         return self.type in ["uint64_t", "VkDeviceAddress"]
737     def needs_dispatch(self):
738         return self.dispatch
740     def needs_private_thunk(self):
741         return self.needs_exposing() and self.name not in MANUAL_LOADER_FUNCTIONS and \
742             self.name in MANUAL_UNIX_THUNKS
744     def needs_exposing(self):
745         # The function needs exposed if at-least one extension isn't both UNSUPPORTED and UNEXPOSED
746         return self.is_required() and (not self.extensions or not self.extensions.issubset(UNEXPOSED_EXTENSIONS))
748     def is_perf_critical(self):
749         # vkCmd* functions are frequently called, do not trace for performance
750         if self.name.startswith("vkCmd") and self.type == "void":
751             return True
752         return self.name in PERF_CRITICAL_FUNCTIONS
754     def pfn(self, prefix="p", call_conv=None):
755         """ Create function pointer. """
757         if call_conv:
758             pfn = "{0} ({1} *{2}_{3})(".format(self.type, call_conv, prefix, self.name)
759         else:
760             pfn = "{0} (*{1}_{2})(".format(self.type, prefix, self.name)
762         for i, param in enumerate(self.params):
763             if param.const:
764                 pfn += param.const + " "
766             pfn += param.type
768             if param.is_pointer():
769                 pfn += " " + param.pointer
771             if param.array_len is not None:
772                 pfn += "[{0}]".format(param.array_len)
774             if i < len(self.params) - 1:
775                 pfn += ", "
776         pfn += ")"
777         return pfn
779     def prototype(self, call_conv=None, prefix=None, is_thunk=False):
780         """ Generate prototype for given function.
782         Args:
783             call_conv (str, optional): calling convention e.g. WINAPI
784             prefix (str, optional): prefix to append prior to function name e.g. vkFoo -> wine_vkFoo
785         """
787         proto = "{0}".format(self.type)
789         if call_conv is not None:
790             proto += " {0}".format(call_conv)
792         if prefix is not None:
793             proto += " {0}{1}(".format(prefix, self.name)
794         else:
795             proto += " {0}(".format(self.name)
797         # Add all the parameters.
798         proto += ", ".join([p.definition() for p in self.params])
800         if is_thunk and self.extra_param:
801             proto += ", void *" + self.extra_param
803         proto += ")"
804         return proto
806     def loader_body(self):
807         body = "    struct {0}_params params;\n".format(self.name)
808         if not self.is_perf_critical():
809             body += "    NTSTATUS status;\n"
810         for p in self.params:
811             body += "    params.{0} = {0};\n".format(p.name)
813         # Call the Unix function.
814         if self.is_perf_critical():
815             body += "    UNIX_CALL({0}, &params);\n".format(self.name)
816         else:
817             body += "    status = UNIX_CALL({0}, &params);\n".format(self.name)
818             body += "    assert(!status && \"{0}\");\n".format(self.name)
820         if self.type != "void":
821             body += "    return params.result;\n"
822         return body
824     def body(self, conv, params_prefix=""):
825         body = ""
826         needs_alloc = False
827         deferred_op = None
829         # Declare any tmp parameters for conversion.
830         for p in self.params:
831             if p.needs_variable(conv, self.unwrap):
832                 if p.is_dynamic_array():
833                     body += "    {3}{0}{1} *{2}_host;\n".format(
834                         p.type, p.pointer[:-1] if p.pointer else "",
835                         p.name, "const " if p.is_const() else "")
836                 elif p.optional:
837                     body += "    {0} *{1}_host = NULL;\n".format(p.type, p.name)
838                     needs_alloc = True
839                 elif p.pointer:
840                     body += "    {0} {1}{2}_host;\n".format(p.type, p.pointer[:-1], p.name)
841                 else:
842                     body += "    {0} {1}_host;\n".format(p.type, p.name)
843             if p.needs_alloc(conv, self.unwrap):
844                 needs_alloc = True
845             if p.type == "VkDeferredOperationKHR" and not p.is_pointer():
846                 deferred_op = p.name
848         if needs_alloc:
849             body += "    struct conversion_context local_ctx;\n"
850             body += "    struct conversion_context *ctx = &local_ctx;\n"
851         body += "\n"
853         if not self.is_perf_critical():
854             body += "    {0}\n".format(self.trace(params_prefix=params_prefix, conv=conv))
856         if self.params[0].optional and self.params[0].is_handle():
857             if self.type != "void":
858                 LOGGER.warning("return type {0} with optional handle not supported".format(self.type))
859             body += "    if (!{0}{1})\n".format(params_prefix, self.params[0].name)
860             body += "        return STATUS_SUCCESS;\n\n"
862         if needs_alloc:
863             if deferred_op is not None:
864                 body += "    if (params->{} == VK_NULL_HANDLE)\n".format(deferred_op)
865                 body += "    "
866             body += "    init_conversion_context(ctx);\n"
867             if deferred_op is not None:
868                 body += "    else\n"
869                 body += "        ctx = &wine_deferred_operation_from_handle(params->{})->ctx;\n".format(deferred_op)
871         # Call any win_to_host conversion calls.
872         unwrap = self.name not in MANUAL_UNIX_THUNKS
873         for p in self.params:
874             if p.needs_conversion(conv, self.unwrap, Direction.INPUT):
875                 body += p.copy(Direction.INPUT, conv, self.unwrap, prefix=params_prefix)
876             elif p.is_dynamic_array() and p.needs_conversion(conv, self.unwrap, Direction.OUTPUT):
877                 body += "    {0}_host = ({2}{0} && {1}) ? conversion_context_alloc(ctx, sizeof(*{0}_host) * {1}) : NULL;\n".format(
878                     p.name, p.get_dyn_array_len(params_prefix, conv), params_prefix)
880         # Build list of parameters containing converted and non-converted parameters.
881         # The param itself knows if conversion is needed and applies it when we set conv=True.
882         unwrap = Unwrap.NONE if self.name in MANUAL_UNIX_THUNKS else self.unwrap
883         params = ", ".join([p.variable(conv, unwrap, params_prefix) for p in self.params])
884         if self.extra_param:
885             if conv:
886                 params += ", UlongToPtr({0}{1})".format(params_prefix, self.extra_param)
887             else:
888                 params += ", {0}{1}".format(params_prefix, self.extra_param)
890         if self.name not in MANUAL_UNIX_THUNKS:
891             func_prefix = "{0}.p_".format(self.params[0].dispatch_table(params_prefix, conv))
892         else:
893             func_prefix = "wine_"
895         # Call the host Vulkan function.
896         if self.type == "void":
897             body += "    {0}{1}({2});\n".format(func_prefix, self.name, params)
898         else:
899             body += "    {0}result = {1}{2}({3});\n".format(params_prefix, func_prefix, self.name, params)
901         # Call any host_to_win conversion calls.
902         for p in self.params:
903             if p.needs_conversion(conv, self.unwrap, Direction.OUTPUT):
904                 body += p.copy(Direction.OUTPUT, conv, self.unwrap, prefix=params_prefix)
906         if needs_alloc:
907             if deferred_op is not None:
908                 body += "    if (params->{} == VK_NULL_HANDLE)\n".format(deferred_op)
909                 body += "    "
910             body += "    free_conversion_context(ctx);\n"
912         # Finally return the result. Performance critical functions return void to allow tail calls.
913         if not self.is_perf_critical():
914             body += "    return STATUS_SUCCESS;\n"
916         return body
918     def spec(self, prefix=None, symbol=None):
919         """ Generate spec file entry for this function.
921         Args
922             prefix (str, optional): prefix to prepend to entry point name.
923             symbol (str, optional): allows overriding the name of the function implementing the entry point.
924         """
926         spec = ""
927         params = " ".join([p.spec() for p in self.params])
928         if prefix is not None:
929             spec += "@ stdcall -private {0}{1}({2})".format(prefix, self.name, params)
930         else:
931             spec += "@ stdcall {0}({1})".format(self.name, params)
933         if symbol is not None:
934             spec += " " + symbol
936         spec += "\n"
937         return spec
939     def stub(self, call_conv=None, prefix=None):
940         stub = self.prototype(call_conv=call_conv, prefix=prefix)
941         stub += "\n{\n"
942         stub += "    {0}".format(self.trace(message="stub: ", trace_func="FIXME"))
944         if self.type == "VkResult":
945             stub += "    return VK_ERROR_OUT_OF_HOST_MEMORY;\n"
946         elif self.type == "VkBool32":
947             stub += "    return VK_FALSE;\n"
948         elif self.type == "PFN_vkVoidFunction":
949             stub += "    return NULL;\n"
951         stub += "}\n\n"
952         return stub
954     def thunk(self, prefix=None, conv=False):
955         thunk = ""
956         if not conv:
957             thunk += "#ifdef _WIN64\n"
958         if self.is_perf_critical():
959             thunk += "static void {0}{1}(void *args)\n".format(prefix, self.name)
960         else:
961             thunk += "static NTSTATUS {0}{1}(void *args)\n".format(prefix, self.name)
962         thunk += "{\n"
963         if conv:
964             thunk += "    struct\n"
965             thunk += "    {\n"
966             for p in self.params:
967                 thunk += "        {0};\n".format(p.definition(conv=True, is_member=True))
968             if self.extra_param:
969                 thunk += "        PTR32 {0};\n".format(self.extra_param)
970             if self.type != "void":
971                 thunk += "        {0} result;\n".format(self.type)
972             thunk += "    } *params = args;\n"
973         else:
974             thunk += "    struct {0}_params *params = args;\n".format(self.name)
975         thunk += self.body(conv, params_prefix="params->")
976         thunk += "}\n"
977         if not conv:
978             thunk += "#endif /* _WIN64 */\n"
979         thunk += "\n"
980         return thunk
982     def loader_thunk(self, prefix=None):
983         thunk = self.prototype(call_conv="WINAPI", prefix=prefix)
984         thunk += "\n{\n"
985         thunk += self.loader_body()
986         thunk += "}\n\n"
987         return thunk
989     def trace(self, message=None, trace_func=None, params_prefix="", conv=False):
990         """ Create a trace string including all parameters.
992         Args:
993             message (str, optional): text to print at start of trace message e.g. 'stub: '
994             trace_func (str, optional): used to override trace function e.g. FIXME, printf, etcetera.
995         """
996         if trace_func is not None:
997             trace = "{0}(\"".format(trace_func)
998         else:
999             trace = "TRACE(\""
1001         if message is not None:
1002             trace += message
1004         # First loop is for all the format strings.
1005         trace += ", ".join([p.format_string(conv) for p in self.params])
1006         trace += "\\n\""
1008         # Second loop for parameter names and optional conversions.
1009         for param in self.params:
1010             if param.format_conv is not None:
1011                 trace += ", " + param.format_conv.format("{0}{1}".format(params_prefix, param.name))
1012             else:
1013                 trace += ", {0}{1}".format(params_prefix, param.name)
1014         trace += ");\n"
1016         return trace
1019 class VkFunctionPointer(object):
1020     def __init__(self, _type, name, members, forward_decls):
1021         self.name = name
1022         self.members = members
1023         self.type = _type
1024         self.required = False
1025         self.forward_decls = forward_decls
1027     @staticmethod
1028     def from_xml(funcpointer):
1029         if not api_is_vulkan(funcpointer):
1030             return None
1032         members = []
1033         begin = None
1035         for t in funcpointer.findall("type"):
1036             # General form:
1037             # <type>void</type>*       pUserData,
1038             # Parsing of the tail (anything past </type>) is tricky since there
1039             # can be other data on the next line like: const <type>int</type>..
1041             const = True if begin and "const" in begin else False
1042             _type = t.text
1043             lines = t.tail.split(",\n")
1044             if lines[0][0] == "*":
1045                 pointer = "*"
1046                 name = lines[0][1:].strip()
1047             else:
1048                 pointer = None
1049                 name = lines[0].strip()
1051             # Filter out ); if it is contained.
1052             name = name.partition(");")[0]
1054             # If tail encompasses multiple lines, assign the second line to begin
1055             # for the next line.
1056             try:
1057                 begin = lines[1].strip()
1058             except IndexError:
1059                 begin = None
1061             members.append(VkMember(const=const, _type=_type, pointer=pointer, name=name))
1063         _type = funcpointer.text
1064         name = funcpointer.find("name").text
1065         if "requires" in funcpointer.attrib:
1066             forward_decls = funcpointer.attrib.get("requires").split(",")
1067         else:
1068             forward_decls = []
1069         return VkFunctionPointer(_type, name, members, forward_decls)
1071     def definition(self):
1072         text = ""
1073         # forward declare required structs
1074         for decl in self.forward_decls:
1075             text += "typedef struct {0} {0};\n".format(decl)
1077         text += "{0} {1})(\n".format(self.type, self.name)
1079         first = True
1080         if len(self.members) > 0:
1081             for m in self.members:
1082                 if first:
1083                     text += "    " + m.definition()
1084                     first = False
1085                 else:
1086                     text += ",\n    " + m.definition()
1087         else:
1088             # Just make the compiler happy by adding a void parameter.
1089             text += "void"
1090         text += ");\n"
1091         return text
1093     def is_alias(self):
1094         return False
1096 class VkHandle(object):
1097     def __init__(self, name, _type, parent, alias=None):
1098         self.name = name
1099         self.type = _type
1100         self.parent = parent
1101         self.alias = alias
1102         self.required = False
1103         self.object_type = None
1105     @staticmethod
1106     def from_alias(handle, alias):
1107         name = handle.attrib.get("name")
1108         return VkHandle(name, alias.type, alias.parent, alias=alias)
1110     @staticmethod
1111     def from_xml(handle):
1112         if not api_is_vulkan(handle):
1113             return None
1115         name = handle.find("name").text
1116         _type = handle.find("type").text
1117         parent = handle.attrib.get("parent") # Most objects have a parent e.g. VkQueue has VkDevice.
1118         return VkHandle(name, _type, parent)
1120     def dispatch_table(self, param):
1121         if not self.is_dispatchable():
1122             return None
1124         if self.parent is None:
1125             # Should only happen for VkInstance
1126             return "wine_instance_from_handle({0})->funcs".format(param)
1127         elif self.name == "VkCommandBuffer":
1128             return "wine_cmd_buffer_from_handle({0})->device->funcs".format(param)
1129         elif self.name == "VkDevice":
1130             return "wine_device_from_handle({0})->funcs".format(param)
1131         elif self.name == "VkPhysicalDevice":
1132             return "wine_phys_dev_from_handle({0})->instance->funcs".format(param)
1133         elif self.name == "VkQueue":
1134             return "wine_queue_from_handle({0})->device->funcs".format(param)
1135         elif self.parent in ["VkInstance", "VkPhysicalDevice"]:
1136             return "{0}->instance->funcs".format(param)
1137         elif self.parent in ["VkDevice", "VkCommandPool"]:
1138             return "{0}->device->funcs".format(param)
1139         else:
1140             LOGGER.error("Unhandled dispatchable parent: {0}".format(self.parent))
1142     def definition(self):
1143         """ Generates handle definition e.g. VK_DEFINE_HANDLE(vkInstance) """
1145         # Legacy types are typedef'ed to the new type if they are aliases.
1146         if self.is_alias():
1147             return "typedef {0} {1};\n".format(self.alias.name, self.name)
1149         return "{0}({1})\n".format(self.type, self.name)
1151     def is_alias(self):
1152         return self.alias is not None
1154     def is_dispatchable(self):
1155         """ Some handles like VkInstance, VkDevice are dispatchable objects,
1156         which means they contain a dispatch table of function pointers.
1157         """
1158         return self.type == "VK_DEFINE_HANDLE"
1160     def is_required(self):
1161         return self.required
1163     def host_handle(self, name):
1164         """ Provide access to the host handle of a wrapped object. """
1166         if self.name == "VkCommandBuffer":
1167             return "wine_cmd_buffer_from_handle({0})->host_command_buffer".format(name)
1168         if self.name == "VkCommandPool":
1169             return "wine_cmd_pool_from_handle({0})->host_command_pool".format(name)
1170         if self.name == "VkDebugUtilsMessengerEXT":
1171             return "wine_debug_utils_messenger_from_handle({0})->host_debug_messenger".format(name)
1172         if self.name == "VkDebugReportCallbackEXT":
1173             return "wine_debug_report_callback_from_handle({0})->host_debug_callback".format(name)
1174         if self.name == "VkDeferredOperationKHR":
1175             return "wine_deferred_operation_from_handle({0})->host_deferred_operation".format(name)
1176         if self.name == "VkDevice":
1177             return "wine_device_from_handle({0})->host_device".format(name)
1178         if self.name == "VkInstance":
1179             return "wine_instance_from_handle({0})->host_instance".format(name)
1180         if self.name == "VkDeviceMemory":
1181             return "wine_device_memory_from_handle({0})->host_memory".format(name)
1182         if self.name == "VkPhysicalDevice":
1183             return "wine_phys_dev_from_handle({0})->host_physical_device".format(name)
1184         if self.name == "VkQueue":
1185             return "wine_queue_from_handle({0})->host_queue".format(name)
1186         if self.name == "VkSurfaceKHR":
1187             return "wine_surface_from_handle({0})->host_surface".format(name)
1188         if self.name == "VkSwapchainKHR":
1189             return "wine_swapchain_from_handle({0})->host_swapchain".format(name)
1190         if self.is_dispatchable():
1191             LOGGER.error("Unhandled host handle for: {0}".format(self.name))
1192         return None
1194     def driver_handle(self, name):
1195         """ Provide access to the handle that should be passed to the wine driver """
1197         if self.name == "VkSurfaceKHR":
1198             return "wine_surface_from_handle({0})->driver_surface".format(name)
1200         return self.host_handle(name)
1202     def unwrap_handle(self, name, unwrap):
1203         if unwrap == Unwrap.DRIVER:
1204             return self.driver_handle(name)
1205         if unwrap == Unwrap.HOST:
1206             return self.host_handle(name)
1207         assert unwrap != Unwrap.NONE
1208         return None
1210     def is_wrapped(self):
1211         return self.host_handle("test") is not None
1214 class VkVariable(object):
1215     def __init__(self, const=False, type_info=None, type=None, name=None, pointer=None, array_len=None,
1216                  dyn_array_len=None, object_type=None, optional=False, returnedonly=False, parent=None,
1217                  selection=None, selector=None):
1218         self.const = const
1219         self.type_info = type_info
1220         self.type = type
1221         self.name = name
1222         self.parent = parent
1223         self.object_type = object_type
1224         self.optional = optional
1225         self.returnedonly = returnedonly
1226         self.selection = selection
1227         self.selector = selector
1229         self.pointer = pointer
1230         self.array_len = array_len
1231         self.dyn_array_len = dyn_array_len
1232         self.pointer_array = False
1233         if isinstance(dyn_array_len, str):
1234             i = dyn_array_len.find(",")
1235             if i != -1:
1236                 self.dyn_array_len = dyn_array_len[0:i]
1237                 self.pointer_array = True
1239         if type_info:
1240             self.set_type_info(type_info)
1242     def __eq__(self, other):
1243         """ Compare member based on name against a string. """
1244         return self.name == other
1246     def set_type_info(self, type_info):
1247         """ Helper function to set type information from the type registry.
1248         This is needed, because not all type data is available at time of
1249         parsing.
1250         """
1251         self.type_info = type_info
1252         self.handle = type_info["data"] if type_info["category"] == "handle" else None
1253         self.struct = type_info["data"] if type_info["category"] == "struct" or type_info["category"] == "union" else None
1255     def get_dyn_array_len(self, prefix, conv):
1256         if isinstance(self.dyn_array_len, int):
1257             return self.dyn_array_len
1259         len_str = self.dyn_array_len
1260         parent = self.parent
1261         len = prefix
1263         # check if length is a member of another struct (for example pAllocateInfo->commandBufferCount)
1264         i = len_str.find("->")
1265         if i != -1:
1266             var = parent[parent.index(len_str[0:i])]
1267             len_str = len_str[i+2:]
1268             len = "({0})->".format(var.value(len, conv))
1269             parent = var.struct
1271         if len_str in parent:
1272             var = parent[parent.index(len_str)]
1273             len = var.value(len, conv);
1274             if var.is_pointer():
1275                 len = "*" + len
1276         else:
1277             len += len_str
1279         if isinstance(self.parent, VkStruct) and self.parent.name in MEMBER_LENGTH_EXPRESSIONS:
1280             exprs = MEMBER_LENGTH_EXPRESSIONS[self.parent.name]
1281             if self.name in exprs:
1282                 len = exprs[self.name].format(struct=prefix, len=len)
1284         return len
1286     def is_const(self):
1287         return self.const
1289     def is_pointer(self):
1290         return self.pointer is not None
1292     def is_pointer_pointer(self):
1293         return self.pointer and self.pointer.count('*') > 1
1295     def is_pointer_size(self):
1296         if self.type in ["size_t", "HWND", "HINSTANCE"]:
1297             return True
1298         if self.is_handle() and self.handle.is_dispatchable():
1299             return True
1300         return self.is_pointer_pointer()
1302     def is_handle(self):
1303         return self.handle is not None
1305     def is_struct(self):
1306         return self.type_info["category"] == "struct"
1308     def is_union(self):
1309         return self.type_info["category"] == "union"
1311     def is_bitmask(self):
1312         return self.type_info["category"] == "bitmask"
1314     def is_enum(self):
1315         return self.type_info["category"] == "enum"
1317     def is_dynamic_array(self):
1318         """ Returns if the member is an array element.
1319         Vulkan uses this for dynamically sized arrays for which
1320         there is a 'count' parameter.
1321         """
1322         return self.dyn_array_len is not None and self.array_len is None
1324     def is_static_array(self):
1325         """ Returns if the member is an array.
1326         Vulkan uses this often for fixed size arrays in which the
1327         length is part of the member.
1328         """
1329         return self.array_len is not None
1331     def is_generic_handle(self):
1332         """ Returns True if the member is a unit64_t containing
1333         a handle with a separate object type
1334         """
1335         return self.object_type != None and self.type == "uint64_t"
1337     def needs_alignment(self):
1338         """ Check if this member needs alignment for 64-bit data.
1339         Various structures need alignment on 64-bit variables due
1340         to compiler differences on 32-bit between Win32 and Linux.
1341         """
1343         if self.is_pointer():
1344             return False
1345         elif self.type == "size_t":
1346             return False
1347         elif self.type in ["uint64_t", "VkDeviceAddress", "VkDeviceSize"]:
1348             return True
1349         elif self.is_bitmask():
1350             return self.type_info["data"].type == "VkFlags64"
1351         elif self.is_enum():
1352             return self.type_info["data"].bitwidth == 64
1353         elif self.is_struct() or self.is_union():
1354             return self.type_info["data"].needs_alignment()
1355         elif self.is_handle():
1356             # Dispatchable handles are pointers to objects, while
1357             # non-dispatchable are uint64_t and hence need alignment.
1358             return not self.handle.is_dispatchable()
1359         return False
1361     def is_wrapped(self):
1362         """ Returns if variable needs unwrapping of handle. """
1364         if self.is_struct():
1365             return self.struct.is_wrapped()
1367         if self.is_handle():
1368             return self.handle.is_wrapped()
1370         if self.is_generic_handle():
1371             return True
1373         return False
1375     def needs_alloc(self, conv, unwrap):
1376         """ Returns True if conversion needs allocation """
1377         if self.is_dynamic_array():
1378             return self.needs_conversion(conv, unwrap, Direction.INPUT, False) \
1379                 or self.needs_conversion(conv, unwrap, Direction.OUTPUT, False)
1381         return (self.is_struct() or (self.is_union() and self.selector)) and self.struct.needs_alloc(conv, unwrap)
1383     def needs_win32_type(self):
1384         return (self.is_struct() or (self.is_union() and self.selector)) and self.struct.needs_win32_type()
1386     def get_conversions(self, unwrap, parent_const=False):
1387         """ Get a list of conversions required for this parameter if any.
1388         Parameters which are structures may require conversion between win32
1389         and the host platform. This function returns a list of conversions
1390         required.
1391         """
1393         conversions = []
1395         # Collect any member conversions first, so we can guarantee
1396         # those functions will be defined prior to usage by the
1397         # 'parent' param requiring conversion.
1398         if self.is_struct() or (self.is_union() and self.selector):
1399             struct = self.struct
1400             is_const = self.is_const() if self.is_pointer() else parent_const
1402             conversions.extend(struct.get_conversions(unwrap, is_const))
1404             for conv in [False, True]:
1405                 if struct.needs_conversion(conv, unwrap, Direction.INPUT, is_const):
1406                     conversions.append(StructConversionFunction(struct, Direction.INPUT, conv, unwrap, is_const))
1407                 if struct.needs_conversion(conv, unwrap, Direction.OUTPUT, is_const):
1408                     conversions.append(StructConversionFunction(struct, Direction.OUTPUT, conv, unwrap, is_const))
1410         if self.is_static_array() or self.is_dynamic_array():
1411             for conv in [False, True]:
1412                 if self.needs_conversion(conv, unwrap, Direction.INPUT, parent_const):
1413                     conversions.append(ArrayConversionFunction(self, Direction.INPUT, conv, unwrap))
1414                 if self.needs_conversion(conv, unwrap, Direction.OUTPUT, parent_const):
1415                     conversions.append(ArrayConversionFunction(self, Direction.OUTPUT, conv, unwrap))
1417         return conversions
1419     def needs_ptr32_type(self):
1420         """ Check if variable needs to use PTR32 type. """
1422         return self.is_pointer() or self.is_pointer_size() or self.is_static_array()
1424     def value(self, prefix, conv):
1425         """ Returns code accessing member value, casting 32-bit pointers when needed. """
1427         if not conv or not self.needs_ptr32_type() or (not self.is_pointer() and self.type == "size_t"):
1428             return prefix + self.name
1430         cast_type = ""
1431         if self.const:
1432             cast_type += "const "
1434         if self.pointer_array or ((self.is_pointer() or self.is_static_array()) and self.is_pointer_size()):
1435             cast_type += "PTR32 *"
1436         else:
1437             cast_type += self.type
1438             if self.needs_win32_type():
1439                 cast_type += "32"
1441             if self.is_pointer():
1442                 cast_type += " {0}".format(self.pointer)
1443             elif self.is_static_array():
1444                 cast_type += " *"
1446         return "({0})UlongToPtr({1}{2})".format(cast_type, prefix, self.name)
1449 class VkMember(VkVariable):
1450     def __init__(self, const=False, struct_fwd_decl=False,_type=None, pointer=None, name=None, array_len=None,
1451                  dyn_array_len=None, optional=False, values=None, object_type=None, bit_width=None,
1452                  returnedonly=False, parent=None, selection=None, selector=None):
1453         VkVariable.__init__(self, const=const, type=_type, name=name, pointer=pointer, array_len=array_len,
1454                             dyn_array_len=dyn_array_len, object_type=object_type, optional=optional,
1455                             returnedonly=returnedonly, parent=parent, selection=selection, selector=selector)
1456         self.struct_fwd_decl = struct_fwd_decl
1457         self.values = values
1458         self.bit_width = bit_width
1460     def __repr__(self):
1461         return "{0} {1} {2} {3} {4} {5} {6}".format(self.const, self.struct_fwd_decl, self.type, self.pointer,
1462                 self.name, self.array_len, self.dyn_array_len)
1464     @staticmethod
1465     def from_xml(member, returnedonly, parent):
1466         """ Helper function for parsing a member tag within a struct or union. """
1468         if not api_is_vulkan(member):
1469             return None
1471         name_elem = member.find("name")
1472         type_elem = member.find("type")
1474         const = False
1475         struct_fwd_decl = False
1476         member_type = None
1477         pointer = None
1478         array_len = None
1479         bit_width = None
1481         values = member.get("values")
1483         if member.text:
1484             if "const" in member.text:
1485                 const = True
1487             # Some members contain forward declarations:
1488             # - VkBaseInstructure has a member "const struct VkBaseInStructure *pNext"
1489             # - VkWaylandSurfaceCreateInfoKHR has a member "struct wl_display *display"
1490             if "struct" in member.text:
1491                 struct_fwd_decl = True
1493         if type_elem is not None:
1494             member_type = type_elem.text
1495             if type_elem.tail is not None:
1496                 pointer = type_elem.tail.strip() if type_elem.tail.strip() != "" else None
1498         # Name of other member within, which stores the number of
1499         # elements pointed to be by this member.
1500         dyn_array_len = member.get("len")
1502         # Some members are optional, which is important for conversion code e.g. not dereference NULL pointer.
1503         optional = True if member.get("optional") else False
1505         # Usually we need to allocate memory for dynamic arrays. We need to do the same in a few other cases
1506         # like for VkCommandBufferBeginInfo.pInheritanceInfo. Just threat such cases as dynamic arrays of
1507         # size 1 to simplify code generation.
1508         if dyn_array_len is None and pointer is not None:
1509             dyn_array_len = 1
1511         # Some members are arrays, attempt to parse these. Formats include:
1512         # <member><type>char</type><name>extensionName</name>[<enum>VK_MAX_EXTENSION_NAME_SIZE</enum>]</member>
1513         # <member><type>uint32_t</type><name>foo</name>[4]</member>
1514         if name_elem.tail and name_elem.tail[0] == '[':
1515             LOGGER.debug("Found array type")
1516             enum_elem = member.find("enum")
1517             if enum_elem is not None:
1518                 array_len = enum_elem.text
1519             else:
1520                 # Remove brackets around length
1521                 array_len = name_elem.tail.strip("[]")
1523         object_type = member.get("objecttype", None)
1525         # Some members are bit field values:
1526         # <member><type>uint32_t</type> <name>mask</name>:8</member>
1527         if name_elem.tail and name_elem.tail[0] == ':':
1528             LOGGER.debug("Found bit field")
1529             bit_width = int(name_elem.tail[1:])
1531         selection = member.get("selection").split(',') if member.get("selection") else None
1532         selector = member.get("selector", None)
1534         return VkMember(const=const, struct_fwd_decl=struct_fwd_decl, _type=member_type, pointer=pointer,
1535                         name=name_elem.text, array_len=array_len, dyn_array_len=dyn_array_len, optional=optional,
1536                         values=values, object_type=object_type, bit_width=bit_width, returnedonly=returnedonly,
1537                         parent=parent, selection=selection, selector=selector)
1539     def copy(self, input, output, direction, conv, unwrap):
1540         """ Helper method for use by conversion logic to generate a C-code statement to copy this member.
1541             - `conv` indicates whether the statement is in a struct alignment conversion path. """
1543         win_type = "win32" if conv else "win64"
1544         suffix = convert_suffix(direction, win_type, unwrap, self.is_wrapped())
1546         if self.needs_conversion(conv, unwrap, direction, False):
1547             if self.is_dynamic_array():
1548                 # Array length is either a variable name (string) or an int.
1549                 count = self.get_dyn_array_len(input, conv)
1550                 pointer_part = "pointer_" if self.pointer_array else ""
1551                 if direction == Direction.OUTPUT:
1552                     return "convert_{2}_{6}array_{5}({3}{1}, {0}, {4});\n".format(self.value(output, conv),
1553                         self.name, self.type, input, count, suffix, pointer_part)
1554                 else:
1555                     return "{0}{1} = convert_{2}_{6}array_{5}(ctx, {3}, {4});\n".format(output,
1556                         self.name, self.type, self.value(input, conv), count, suffix, pointer_part)
1557             elif self.is_static_array():
1558                 count = self.array_len
1559                 if direction == Direction.OUTPUT:
1560                     # Needed by VkMemoryHeap.memoryHeaps
1561                     return "convert_{0}_array_{5}({2}{1}, {3}{1}, {4});\n".format(self.type,
1562                         self.name, input, output, count, suffix)
1563                 else:
1564                     # Nothing needed this yet.
1565                     LOGGER.warn("TODO: implement copying of static array for {0}.{1}".format(self.type, self.name))
1566             elif self.is_handle() and self.is_wrapped():
1567                 handle = self.type_info["data"]
1568                 if direction == Direction.OUTPUT:
1569                     LOGGER.err("OUTPUT parameter {0}.{1} cannot be unwrapped".format(self.type, self.name))
1570                 elif self.optional:
1571                     return "{0}{1} = {2} ? {3} : 0;\n".format(output, self.name, self.value(input, conv),
1572                         handle.unwrap_handle(self.value(input, conv), unwrap))
1573                 else:
1574                     return "{0}{1} = {2};\n".format(output, self.name,
1575                         handle.unwrap_handle(self.value(input, conv), unwrap))
1576             elif self.is_generic_handle():
1577                 if direction == Direction.OUTPUT:
1578                     LOGGER.err("OUTPUT parameter {0}.{1} cannot be unwrapped".format(self.type, self.name))
1579                 if unwrap == Unwrap.DRIVER and self.is_wrapped(Unwrap.DRIVER):
1580                     LOGGER.err("DRIVER unwrapping of {0}.{1} not implemented".format(self.type, self.name))
1581                 return "{0}{1} = wine_vk_unwrap_handle({2}{3}, {2}{1});\n".format(output, self.name, input, self.object_type)
1582             else:
1583                 selector_part = ", {0}{1}".format(input, self.selector) if self.selector else ""
1584                 if direction == Direction.OUTPUT:
1585                     return "convert_{0}_{4}(&{2}{1}, &{3}{1}{5});\n".format(self.type,
1586                         self.name, input, output, suffix, selector_part)
1587                 else:
1588                     ctx_param = "ctx, " if self.needs_alloc(conv, unwrap) else ""
1589                     return "convert_{0}_{4}({5}&{2}{1}, &{3}{1}{6});\n".format(self.type,
1590                         self.name, input, output, suffix, ctx_param, selector_part)
1591         elif self.is_static_array():
1592             bytes_count = "{0} * sizeof({1})".format(self.array_len, self.type)
1593             return "memcpy({0}{1}, {2}{1}, {3});\n".format(output, self.name, input, bytes_count)
1594         elif conv and direction == Direction.OUTPUT and self.is_pointer():
1595             return "{0}{1} = PtrToUlong({2}{1});\n".format(output, self.name, input)
1596         elif conv and direction == Direction.INPUT and self.is_pointer():
1597             return "{0}{1} = UlongToPtr({2}{1});\n".format(output, self.name, input)
1598         elif direction == Direction.INPUT:
1599             return "{0}{1} = {2};\n".format(output, self.name, self.value(input, conv))
1600         else:
1601             return "{0}{1} = {2}{1};\n".format(output, self.name, input)
1603     def definition(self, align=False, conv=False):
1604         """ Generate prototype for given function.
1606         Args:
1607             align (bool, optional): Enable alignment if a type needs it. This adds WINE_VK_ALIGN(8) to a member.
1608             conv (bool, optional): Enable conversion if a type needs it. This appends '_host' to the name.
1609         """
1611         if conv and (self.is_pointer() or self.is_pointer_size()):
1612             text = "PTR32 " + self.name
1613             if self.is_static_array():
1614                 text += "[{0}]".format(self.array_len)
1615             return text
1617         text = ""
1618         if self.is_const():
1619             text += "const "
1621         if self.is_struct_forward_declaration():
1622             text += "struct "
1624         text += self.type
1625         if conv and self.needs_win32_type():
1626             text += "32"
1628         if self.is_pointer():
1629             text += " {0}{1}".format(self.pointer, self.name)
1630         else:
1631             if align and self.needs_alignment():
1632                 if conv:
1633                     text += " DECLSPEC_ALIGN(8) " + self.name
1634                 else:
1635                     text += " WINE_VK_ALIGN(8) " + self.name
1636             else:
1637                 text += " " + self.name
1639         if self.is_static_array():
1640             text += "[{0}]".format(self.array_len)
1642         if self.is_bit_field():
1643             text += ":{}".format(self.bit_width)
1645         return text
1647     def is_struct_forward_declaration(self):
1648         return self.struct_fwd_decl
1650     def is_bit_field(self):
1651         return self.bit_width is not None
1653     def needs_conversion(self, conv, unwrap, direction, struct_const):
1654         """ Check if member needs conversion. """
1656         # we can't convert unions if we don't have a selector
1657         if self.is_union() and not self.selector:
1658             return False
1660         is_const = self.is_const() if self.is_pointer() else struct_const
1662         # const members don't needs output conversion unless they are structs with non-const pointers
1663         if direction == Direction.OUTPUT and is_const and not self.is_struct():
1664             return False
1666         if direction == Direction.INPUT:
1667             # returnedonly members don't needs input conversions
1668             if not self.is_pointer() and self.returnedonly:
1669                 return False
1670             # pointer arrays always need input conversion
1671             if conv and self.is_dynamic_array() and self.pointer_array:
1672                 return True
1674         if self.is_handle():
1675             if unwrap != Unwrap.NONE and self.handle.is_wrapped():
1676                 return True
1677             if conv and self.handle.is_dispatchable():
1678                 return True
1679         elif self.is_generic_handle():
1680             if unwrap != Unwrap.NONE:
1681                 return True
1682         elif self.is_struct() or self.is_union():
1683             if self.struct.needs_conversion(conv, unwrap, direction, is_const):
1684                 return True
1686         # if pointer member needs output conversion, it also needs input conversion
1687         # to allocate the pointer
1688         if direction == Direction.INPUT and self.is_pointer() and \
1689            self.needs_conversion(conv, unwrap, Direction.OUTPUT, struct_const):
1690             return True
1692         return False
1694 class VkParam(VkVariable):
1695     """ Helper class which describes a parameter to a function call. """
1697     def __init__(self, type_info, const=None, pointer=None, name=None, parent=None, array_len=None,
1698                  dyn_array_len=None, object_type=None, optional=False):
1699         VkVariable.__init__(self, const=const, type_info=type_info, type=type_info["name"], name=name,
1700                             pointer=pointer, array_len=array_len, dyn_array_len=dyn_array_len,
1701                             object_type=object_type, optional=optional, parent=parent)
1703         self._set_format_string()
1705     def __repr__(self):
1706         return "{0} {1} {2} {3} {4} {5}".format(self.const, self.type, self.pointer, self.name, self.array_len, self.dyn_array_len)
1708     @staticmethod
1709     def from_xml(param, types, parent):
1710         """ Helper function to create VkParam from xml. """
1712         if not api_is_vulkan(param):
1713             return None
1715         # Parameter parsing is slightly tricky. All the data is contained within
1716         # a param tag, but some data is within subtags while others are text
1717         # before or after the type tag.
1718         # Common structure:
1719         # <param>const <type>char</type>* <name>pLayerName</name></param>
1721         name_elem = param.find("name")
1722         array_len = None
1723         name = name_elem.text
1724         # Tail contains array length e.g. for blendConstants param of vkSetBlendConstants
1725         if name_elem.tail is not None:
1726             array_len = name_elem.tail.strip("[]")
1728         # Name of other parameter in function prototype, which stores the number of
1729         # elements pointed to be by this parameter.
1730         dyn_array_len = param.get("len", None)
1732         const = param.text.strip() if param.text else None
1733         type_elem = param.find("type")
1734         pointer = type_elem.tail.strip() if type_elem.tail.strip() != "" else None
1735         assert not pointer or pointer.count('*') <= 2 # only pointers and pointer of pointers are supported
1737         attr = param.get("optional")
1738         optional = attr and attr.startswith("true")
1740         # Some uint64_t are actually handles with a separate type param
1741         object_type = param.get("objecttype", None)
1743         # Since we have parsed all types before hand, this should not happen.
1744         type_info = types.get(type_elem.text, None)
1745         if type_info is None:
1746             LOGGER.err("type info not found for: {0}".format(type_elem.text))
1748         return VkParam(type_info, const=const, pointer=pointer, name=name, array_len=array_len,
1749                        dyn_array_len=dyn_array_len, object_type=object_type, optional=optional,
1750                        parent=parent)
1752     def _set_format_string(self):
1753         """ Internal helper function to be used by constructor to set format string. """
1755         # Determine a format string used by code generation for traces.
1756         # 64-bit types need a conversion function.
1757         self.format_conv = None
1758         if self.is_static_array() or self.is_pointer():
1759             self.format_str = "%p"
1760         else:
1761             if self.type_info["category"] in ["bitmask"]:
1762                 # Since 1.2.170 bitmasks can be 32 or 64-bit, check the basetype.
1763                 if self.type_info["data"].type == "VkFlags64":
1764                     self.format_str = "0x%s"
1765                     self.format_conv = "wine_dbgstr_longlong({0})"
1766                 else:
1767                     self.format_str = "%#x"
1768             elif self.type_info["category"] in ["enum"]:
1769                 self.format_str = "%#x"
1770             elif self.is_handle():
1771                 # We use uint64_t for non-dispatchable handles as opposed to pointers
1772                 # for dispatchable handles.
1773                 if self.handle.is_dispatchable():
1774                     self.format_str = "%p"
1775                 else:
1776                     self.format_str = "0x%s"
1777                     self.format_conv = "wine_dbgstr_longlong({0})"
1778             elif self.type == "float":
1779                 self.format_str = "%f"
1780             elif self.type == "int":
1781                 self.format_str = "%d"
1782             elif self.type == "int32_t":
1783                 self.format_str = "%d"
1784             elif self.type == "size_t":
1785                 self.format_str = "0x%s"
1786                 self.format_conv = "wine_dbgstr_longlong({0})"
1787             elif self.type in ["uint16_t", "uint32_t", "VkBool32"]:
1788                 self.format_str = "%u"
1789             elif self.type in ["uint64_t", "VkDeviceAddress", "VkDeviceSize"]:
1790                 self.format_str = "0x%s"
1791                 self.format_conv = "wine_dbgstr_longlong({0})"
1792             elif self.type == "HANDLE":
1793                 self.format_str = "%p"
1794             elif self.type in ["VisualID", "xcb_visualid_t", "RROutput", "zx_handle_t", "NvSciBufObj", "NvSciBufAttrList", "NvSciSyncAttrList"]:
1795                 # Don't care about specific types for non-Windows platforms.
1796                 self.format_str = ""
1797             else:
1798                 LOGGER.warn("Unhandled type: {0}".format(self.type_info))
1800     def copy(self, direction, conv, unwrap, prefix=""):
1801         win_type = "win32" if conv else "win64"
1802         suffix = convert_suffix(direction, win_type, unwrap, self.is_wrapped())
1804         if direction == Direction.INPUT:
1805             ctx_param = "ctx, " if self.needs_alloc(conv, unwrap) else ""
1806             if self.is_dynamic_array():
1807                 return "    {0}_host = convert_{2}_array_{4}({5}{1}, {3});\n".format(self.name, self.value(prefix, conv),
1808                     self.type, self.get_dyn_array_len(prefix, conv), suffix, ctx_param)
1809             elif self.optional:
1810                 ret  = "    if ({0}{1})\n".format(prefix, self.name)
1811                 ret += "    {\n"
1812                 ret += "        {0}_host = conversion_context_alloc(ctx, sizeof(*{0}_host));\n".format(self.name)
1813                 ret += "        convert_{0}_{3}({4}{1}, {2}_host);\n".format(self.type, self.value(prefix, conv),
1814                     self.name, suffix, ctx_param)
1815                 ret += "    }\n"
1816                 return ret
1817             elif self.is_struct():
1818                 return "    convert_{0}_{3}({4}{1}, &{2}_host);\n".format(self.type, self.value(prefix, conv),
1819                     self.name, suffix, ctx_param)
1820             elif self.is_pointer_size() and self.type != "size_t":
1821                 return "    {0}_host = UlongToPtr(*{1});\n".format(self.name, self.value(prefix, conv))
1822             else:
1823                 return "    {0}_host = *{1};\n".format(self.name, self.value(prefix, conv))
1824         else:
1825             if self.is_dynamic_array():
1826                 return "    convert_{0}_array_{1}({2}_host, {3}, {4});\n".format(
1827                     self.type, suffix, self.name, self.value(prefix, conv).replace('const ', ''),
1828                     self.get_dyn_array_len(prefix, conv))
1829             elif self.is_struct():
1830                 ref_part = "" if self.optional else "&"
1831                 return "    convert_{0}_host_to_{3}({4}{2}_host, {1});\n".format(
1832                     self.type, self.value(prefix, conv), self.name, win_type, ref_part)
1833             elif self.is_pointer_size() and self.type != "size_t":
1834                 return "    *{0} = PtrToUlong({1}_host);\n".format(self.value(prefix, conv), self.name)
1835             else:
1836                 return "    *{0} = {1}_host;\n".format(self.value(prefix, conv), self.name)
1838     def definition(self, postfix=None, is_member=False, conv=False):
1839         """ Return prototype for the parameter. E.g. 'const char *foo' """
1841         if is_member and conv and self.needs_ptr32_type():
1842             return "PTR32 {0}".format(self.name)
1844         proto = ""
1845         if self.const:
1846             proto += self.const + " "
1848         proto += self.type
1849         name = self.name
1850         if conv and self.needs_win32_type():
1851             proto += "32"
1853         if is_member and self.needs_alignment():
1854             proto += " DECLSPEC_ALIGN(8)"
1856         if self.is_pointer():
1857             proto += " {0}{1}".format(self.pointer, name)
1858         elif is_member and self.is_static_array():
1859             proto += " *" + name
1860         else:
1861             proto += " " + name
1863         # Allows appending something to the variable name useful for
1864         # win32 to host conversion.
1865         if postfix is not None:
1866             proto += postfix
1868         if not is_member and self.is_static_array():
1869             proto += "[{0}]".format(self.array_len)
1871         return proto
1873     def dispatch_table(self, params_prefix, conv):
1874         """ Return functions dispatch table pointer for dispatchable objects. """
1876         if not self.is_dispatchable():
1877             return None
1879         return self.handle.dispatch_table(self.value(params_prefix, conv))
1881     def format_string(self, conv):
1882         if conv and self.needs_ptr32_type() and (self.type != "size_t" or self.is_pointer()):
1883             return "%#x"
1884         return self.format_str
1886     def is_dispatchable(self):
1887         if not self.is_handle():
1888             return False
1890         return self.handle.is_dispatchable()
1892     def needs_conversion(self, conv, unwrap, direction, parent_const=False):
1893         """ Check if param needs conversion. """
1895         if self.is_pointer_pointer() and self.type != 'void':
1896             if direction == Direction.INPUT or not self.is_const():
1897                 return conv
1899         if self.is_struct():
1900             return self.struct.needs_conversion(conv, unwrap, direction, self.is_const())
1902         if self.is_handle():
1903             # non-pointer handles are handled inline in thunks
1904             if not self.is_dynamic_array() and not self.is_static_array():
1905                 return conv and self.is_pointer() and self.handle.is_dispatchable()
1907             # vkAllocateCommandBuffers is a special case, we use it in our private thunk as an input param
1908             param_direction = (Direction.INPUT if self.is_const() else Direction.OUTPUT)
1909             if self.name == "pCommandBuffers":
1910                 param_direction = Direction.INPUT
1911             if direction != param_direction:
1912                 return False
1914             if unwrap != Unwrap.NONE and self.handle.is_wrapped():
1915                 return True
1916             if conv and self.handle.is_dispatchable():
1917                 return True
1918         elif self.is_pointer() and self.is_pointer_size():
1919             return conv
1921         return False
1923     def needs_variable(self, conv, unwrap):
1924         if self.needs_conversion(conv, unwrap, Direction.INPUT):
1925             return True
1926         if self.needs_conversion(conv, unwrap, Direction.OUTPUT):
1927             return True
1928         return False
1930     def spec(self):
1931         """ Generate spec file entry for this parameter. """
1933         if self.is_pointer() and self.type == "char":
1934             return "str"
1935         if self.is_dispatchable() or self.is_pointer() or self.is_static_array():
1936             return "ptr"
1937         if self.type_info["category"] in ["bitmask"]:
1938             # Since 1.2.170 bitmasks can be 32 or 64-bit, check the basetype.
1939             if self.type_info["data"].type == "VkFlags64":
1940                 return "int64"
1941             else:
1942                 return "long"
1943         if self.type_info["category"] in ["enum"]:
1944             return "long"
1945         if self.is_handle() and not self.is_dispatchable():
1946             return "int64"
1947         if self.type == "float":
1948             return "float"
1949         if self.type in ["int", "int32_t", "size_t", "uint16_t", "uint32_t", "VkBool32"]:
1950             return "long"
1951         if self.type in ["uint64_t", "VkDeviceSize"]:
1952             return "int64"
1954         LOGGER.error("Unhandled spec conversion for type: {0}".format(self.type))
1956     def variable(self, conv, unwrap, params_prefix=""):
1957         """ Returns 'glue' code during generation of a function call on how to access the variable.
1958         This function handles various scenarios such as 'unwrapping' if dispatchable objects and
1959         renaming of parameters in case of win32 -> host conversion.
1961         Args:
1962             conv (bool, optional): Enable conversion if the param needs it. This appends '_host' to the name.
1963         """
1965         # Hack until we enable allocation callbacks from ICD to application. These are a joy
1966         # to enable one day, because of calling convention conversion.
1967         if unwrap != Unwrap.NONE and "VkAllocationCallbacks" in self.type:
1968             LOGGER.debug("TODO: setting NULL VkAllocationCallbacks for {0}".format(self.name))
1969             return "NULL"
1971         if self.needs_variable(conv, unwrap):
1972             if self.is_dynamic_array() or self.optional:
1973                 return "{0}_host".format(self.name)
1974             else:
1975                 return "&{0}_host".format(self.name)
1977         p = self.value(params_prefix, conv)
1979         if unwrap != Unwrap.NONE:
1980             unwrap_handle = None
1981             if self.object_type != None and self.type == "uint64_t":
1982                 if unwrap == Unwrap.DRIVER and self.is_wrapped(Unwrap.DRIVER):
1983                     LOGGER.err("DRIVER unwrapping of {0}.{1} not implemented".format(self.type, self.name))
1984                 unwrap_handle = "wine_vk_unwrap_handle({0}{1}, {0}{2})".format(
1985                     params_prefix, self.object_type, self.name)
1987             elif self.is_handle():
1988                 # We need to pass the host handle to the host Vulkan calls and
1989                 # the wine driver's handle to calls which are wrapped by the driver.
1990                 unwrap_handle = self.handle.unwrap_handle(p, unwrap)
1991             if unwrap_handle:
1992                 if self.optional:
1993                     unwrap_handle = "{0}{1} ? {2} : 0".format(params_prefix, self.name, unwrap_handle)
1994                 return unwrap_handle
1996         return p
1999 class VkStruct(Sequence):
2000     """ Class which represents the type union and struct. """
2002     def __init__(self, name, members, returnedonly, structextends, alias=None, union=False):
2003         self.name = name
2004         self.members = members
2005         self.returnedonly = returnedonly
2006         self.structextends = structextends
2007         self.required = False
2008         self.alias = alias
2009         self.union = union
2010         self.type_info = None # To be set later.
2011         self.struct_extensions = []
2012         self.aliased_by = []
2014     def __getitem__(self, i):
2015         return self.members[i]
2017     def __len__(self):
2018         return len(self.members)
2020     @staticmethod
2021     def from_alias(struct, alias):
2022         name = struct.attrib.get("name")
2023         aliasee = VkStruct(name, alias.members, alias.returnedonly, alias.structextends, alias=alias)
2025         alias.add_aliased_by(aliasee)
2026         return aliasee
2028     @staticmethod
2029     def from_xml(struct):
2030         if not api_is_vulkan(struct):
2031             return None
2033         # Unions and structs are the same parsing wise, but we need to
2034         # know which one we are dealing with later on for code generation.
2035         union = True if struct.attrib["category"] == "union" else False
2037         name = struct.attrib.get("name")
2039         # 'Output' structures for which data is filled in by the API are
2040         # marked as 'returnedonly'.
2041         returnedonly = True if struct.attrib.get("returnedonly") else False
2043         # Those structs seem to be broken in spec, they are specified as
2044         # returned only, but documented as input structs.
2045         if name in ["VkPipelineShaderStageRequiredSubgroupSizeCreateInfo"]:
2046             returnedonly = False
2048         # Those structs don't have returnedonly in spec, but they could (should?).
2049         if name in ["VkSurfaceCapabilitiesPresentBarrierNV"]:
2050             returnedonly = True
2052         structextends = struct.attrib.get("structextends")
2053         structextends = structextends.split(",") if structextends else []
2055         s = VkStruct(name, [], returnedonly, structextends, union=union)
2056         for member in struct.findall("member"):
2057             vk_member = VkMember.from_xml(member, returnedonly, s)
2058             if vk_member:
2059                 s.members.append(vk_member)
2061         return s
2063     @staticmethod
2064     def decouple_structs(structs):
2065         """ Helper function which decouples a list of structs.
2066         Structures often depend on other structures. To make the C compiler
2067         happy we need to define 'substructures' first. This function analyzes
2068         the list of structures and reorders them in such a way that they are
2069         decoupled.
2070         """
2072         tmp_structs = list(structs) # Don't modify the original structures.
2073         decoupled_structs = []
2075         while (len(tmp_structs) > 0):
2076             # Iterate over a copy because we want to modify the list inside the loop.
2077             for struct in list(tmp_structs):
2078                 dependends = False
2080                 if not struct.required:
2081                     tmp_structs.remove(struct)
2082                     continue
2084                 for m in struct:
2085                     if not (m.is_struct() or m.is_union()):
2086                         continue
2088                     # VkBaseInstructure and VkBaseOutStructure reference themselves.
2089                     if m.type == struct.name:
2090                         break
2092                     found = False
2093                     # Check if a struct we depend on has already been defined.
2094                     for s in decoupled_structs:
2095                         if s.name == m.type:
2096                             found = True
2097                             break
2099                     if not found:
2100                         # Check if the struct we depend on is even in the list of structs.
2101                         # If found now, it means we haven't met all dependencies before we
2102                         # can operate on the current struct.
2103                         # When generating 'host' structs we may not be able to find a struct
2104                         # as the list would only contain the structs requiring conversion.
2105                         for s in tmp_structs:
2106                             if s.name == m.type:
2107                                 dependends = True
2108                                 break
2110                 if dependends == False:
2111                     decoupled_structs.append(struct)
2112                     tmp_structs.remove(struct)
2114         return decoupled_structs
2116     def definition(self, align=False, conv=False):
2117         """ Convert structure to textual definition.
2119         Args:
2120             align (bool, optional): enable alignment to 64-bit for win32 struct compatibility.
2121             conv (bool, optional): enable struct conversion if the struct needs it.
2122             postfix (str, optional): text to append to end of struct name, useful for struct renaming.
2123         """
2125         if self.is_alias():
2126             return ""
2128         suffix = "32" if conv else ""
2129         if self.union:
2130             text = "typedef union {0}".format(self.name)
2131         else:
2132             text = "typedef struct {0}".format(self.name)
2133         text += suffix
2135         text += "\n{\n"
2137         for m in self:
2138             if align and m.needs_alignment():
2139                 text += "    {0};\n".format(m.definition(align=align, conv=conv))
2140             else:
2141                 text += "    {0};\n".format(m.definition(conv=conv))
2143         text += "}} {0}{1};\n".format(self.name, suffix)
2145         for aliasee in self.aliased_by:
2146             text += "typedef {0}{2} {1}{2};\n".format(self.name, aliasee.name, suffix)
2148         return text
2150     def is_alias(self):
2151         return bool(self.alias)
2153     def add_aliased_by(self, aliasee):
2154         self.aliased_by.append(aliasee)
2156     def needs_alignment(self):
2157         """ Check if structure needs alignment for 64-bit data.
2158         Various structures need alignment on 64-bit variables due
2159         to compiler differences on 32-bit between Win32 and Linux.
2160         """
2162         for m in self.members:
2163             if self.name == m.type:
2164                 continue
2165             if m.needs_alignment():
2166                 return True
2167         return False
2169     def is_wrapped(self):
2170         """ Returns if struct members need unwrapping of handle. """
2172         for m in self.members:
2173             if self.name == m.type:
2174                 continue
2175             if m.is_wrapped():
2176                 return True
2177         return False
2179     def needs_extensions_conversion(self, conv, direction):
2180         """ Check if struct contains extensions chain that needs to be converted """
2182         if direction == Direction.INPUT and self.name in STRUCT_CHAIN_CONVERSIONS:
2183             return True
2185         if not "pNext" in self:
2186             return False
2187         is_const = self.members[self.members.index("pNext")].is_const()
2188         # VkOpticalFlowSessionCreateInfoNV is missing const in its pNext pointer
2189         if self.name in ["VkOpticalFlowSessionCreateInfoNV",
2190                          "VkDescriptorBufferBindingInfoEXT"]:
2191             is_const = True
2193         for e in self.struct_extensions:
2194             if not e.required:
2195                 continue
2196             if e.needs_conversion(conv, Unwrap.HOST, direction, is_const, check_extensions=False):
2197                 return True
2198             if direction == Direction.INPUT:
2199                 # we need input conversion of structs containing struct chain even if it's returnedonly,
2200                 # so that we have a chance to allocate buffers
2201                 if e.needs_conversion(conv, Unwrap.HOST, Direction.OUTPUT, is_const, check_extensions=False):
2202                     return True
2204         return False
2206     def needs_conversion(self, conv, unwrap, direction, is_const, check_extensions=True):
2207         """ Check if struct needs conversion. """
2209         # VkAllocationCallbacks never needs conversion
2210         if self.name == "VkAllocationCallbacks":
2211             return False
2213         # pFixedRateFlags field is missing const, but it doesn't need output conversion
2214         if direction == Direction.OUTPUT and self.name == "VkImageCompressionControlEXT":
2215             return False
2217         needs_output_copy = False
2219         for m in self.members:
2220             if self.name == m.type:
2221                 continue
2223             if m.name == "pNext":
2224                 # pNext is a pointer, so it always needs conversion
2225                 if conv and direction == Direction.INPUT:
2226                     return True
2227                 # we need input conversion of structs containing struct chain even if it's returnedonly
2228                 if direction == Direction.INPUT and \
2229                    self.needs_conversion(conv, unwrap, Direction.OUTPUT, is_const):
2230                     return True
2231                 continue
2233             # for non-pointer members, check for returnedonly and const attributes
2234             if not m.is_pointer() or m.type == "void":
2235                 if direction == Direction.INPUT:
2236                     if self.returnedonly:
2237                         continue
2238                 else:
2239                     if is_const or m.is_const():
2240                         continue
2242             # check alignment and pointer-sized members for 32-bit conversions
2243             if conv and (direction == Direction.INPUT or not is_const):
2244                 if m.is_pointer() or m.is_pointer_size():
2245                     return True
2246                 # we don't check structs here, they will will be traversed by needs_conversion chain anyway
2247                 if not m.is_struct() and m.needs_alignment():
2248                     return True
2250             if m.needs_conversion(conv, unwrap, direction, is_const):
2251                 return True
2253             # pointers will be handled by needs_conversion, but if we have any other non-const
2254             # member, we may need to copy output
2255             if direction == Direction.OUTPUT and not m.is_pointer() and not is_const and not m.is_const():
2256                 needs_output_copy = True
2258         # if output needs any copy and we need input conversion, then we also need output conversion
2259         if needs_output_copy and self.needs_conversion(conv, unwrap, Direction.INPUT, check_extensions):
2260             return True
2262         return check_extensions and self.needs_extensions_conversion(conv, direction)
2264     def needs_alloc(self, conv, unwrap):
2265         """ Check if any struct member needs some memory allocation."""
2267         if self.needs_extensions_conversion(conv, Direction.INPUT):
2268             return True
2270         for m in self.members:
2271             if self.name == m.type:
2272                 continue
2273             if m.needs_alloc(conv, unwrap):
2274                 return True
2276         return False
2278     def needs_win32_type(self):
2279         # VkAllocationCallbacks never needs conversion
2280         if self.name == "VkAllocationCallbacks":
2281             return False
2283         for m in self.members:
2284             if self.name == m.type:
2285                 continue
2286             if m.is_pointer() or m.is_pointer_size():
2287                 return True
2288             if m.needs_alignment():
2289                 return True
2290             if (m.is_struct() or m.is_union()) and m.struct.needs_win32_type():
2291                 return True
2293     def set_type_info(self, types):
2294         """ Helper function to set type information from the type registry.
2295         This is needed, because not all type data is available at time of
2296         parsing.
2297         """
2298         for m in self.members:
2299             type_info = types[m.type]
2300             m.set_type_info(type_info)
2302     def get_conversions(self, unwrap, parent_const):
2303         conversions = []
2305         # Collect any conversion for any extension structs.
2306         for e in self.struct_extensions:
2307             if not e.required:
2308                 continue
2309             conversions.extend(e.get_conversions(Unwrap.HOST, parent_const))
2311         # Collect any conversion for any member structs.
2312         for m in self:
2313             if m.type == self.name:
2314                 continue
2315             conversions.extend(m.get_conversions(unwrap, parent_const))
2317         return conversions
2320 class StructConversionFunction(object):
2321     def __init__(self, struct, direction, conv, unwrap, const):
2322         self.direction = direction
2323         self.operand = struct
2324         self.type = struct.name
2325         self.conv = conv
2326         self.unwrap = unwrap
2327         self.const = const
2329         name = "convert_{0}_".format(self.type)
2330         win_type = "win32" if self.conv else "win64"
2331         name += convert_suffix(direction, win_type, unwrap, struct.is_wrapped())
2332         self.name = name
2334     def __eq__(self, other):
2335         return self.name == other.name
2337     def member_needs_copy(self, struct, m):
2338         if self.direction == Direction.OUTPUT:
2339             if m.name in ["sType", "pNext"]:
2340                 return False
2341             if self.const and not m.is_pointer():
2342                 return False
2343             if m.is_const() and not m.needs_conversion(self.conv, self.unwrap, Direction.OUTPUT, self.const):
2344                 return False
2345         else:
2346             if m.name == "pNext":
2347                 return True
2348             if m.name != "sType" and struct.returnedonly and not m.needs_conversion(
2349                     self.conv, self.unwrap, Direction.INPUT, self.const):
2350                 return False
2351         return True
2353     def definition(self):
2354         """ Helper function for generating a struct conversion function. """
2356         # It doesn't make sense to generate conversion functions for non-struct variables
2357         # which aren't in arrays, as this should be handled by the copy() function
2358         if not isinstance(self.operand, VkStruct):
2359             return ""
2361         body = ""
2363         if not self.conv:
2364             body += "#ifdef _WIN64\n"
2366         needs_alloc = self.direction != Direction.OUTPUT and self.operand.needs_alloc(self.conv, self.unwrap)
2367         win_type = self.type
2368         if self.conv and self.operand.needs_win32_type():
2369             win_type += "32"
2370         if self.direction == Direction.OUTPUT and self.const:
2371             win_type = "const " + win_type
2373         if self.conv:
2374             body += "static inline void {0}(".format(self.name)
2376             if self.direction == Direction.OUTPUT:
2377                 params = ["const {0} *in".format(self.type), "{0} *out".format(win_type)]
2378             else:
2379                 params = ["const {0} *in".format(win_type), "{0} *out".format(self.type)]
2381             if self.operand.union:
2382                 params.append("VkFlags selector")
2384             # Generate parameter list
2385             if needs_alloc:
2386                 body += "struct conversion_context *ctx, "
2387             body += ", ".join(p for p in params)
2388             body += ")\n"
2390         else:
2391             body += "static inline void {0}(".format(self.name)
2393             params = ["const {0} *in".format(self.type), "{0} *out".format(self.type)]
2395             # Generate parameter list
2396             if needs_alloc:
2397                 body += "struct conversion_context *ctx, "
2398             body += ", ".join(p for p in params)
2399             body += ")\n"
2401         needs_extensions = self.operand.needs_extensions_conversion(self.conv, self.direction)
2403         body += "{\n"
2404         if needs_extensions:
2405             if self.direction == Direction.INPUT:
2406                 if self.conv:
2407                     body += "    const VkBaseInStructure32 *in_header;\n"
2408                 else:
2409                     body += "    const VkBaseInStructure *in_header;\n"
2410                 body += "    VkBaseOutStructure *out_header = (void *)out;\n\n"
2411             else:
2412                 body += "    const VkBaseInStructure *in_header;\n"
2413                 if self.conv:
2414                     body += "    VkBaseOutStructure32 *out_header = (void *)out;\n\n"
2415                 else:
2416                     body += "    VkBaseOutStructure *out_header = (void *)out;\n\n"
2418         body += "    if (!in) return;\n\n"
2420         for m in self.operand:
2421             if not self.member_needs_copy(self.operand, m):
2422                 continue
2423             if m.name == "pNext" and (needs_extensions or self.conv):
2424                 body += "    out->pNext = NULL;\n"
2425                 continue
2427             if m.selection:
2428                 body += "    if ("
2429                 body += " || ".join("selector == {}".format(s) for s in m.selection)
2430                 body += ")\n    "
2432             body += "    " + m.copy("in->", "out->", self.direction, self.conv, self.unwrap)
2434         if needs_extensions:
2435             if self.conv and self.direction == Direction.INPUT:
2436                 body += "\n    for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext))\n"
2437             else:
2438                 body += "\n    for (in_header = (void *)in->pNext; in_header; in_header = (void *)in_header->pNext)\n"
2439             body += "    {\n"
2440             body += "        switch (in_header->sType)\n"
2441             body += "        {\n"
2443             ident = "            "
2445             if self.direction == Direction.INPUT and self.type in STRUCT_CHAIN_CONVERSIONS:
2446                 for i in STRUCT_CHAIN_CONVERSIONS[self.type]:
2447                     body += "        case {0}:\n".format(i)
2448                 body += ident + "break;\n"
2450             for ext in self.operand.struct_extensions:
2451                 if not ext.required:
2452                     continue
2454                 if self.direction == Direction.OUTPUT and not any([self.member_needs_copy(ext, m) for m in ext]):
2455                     continue
2457                 stype = next(x for x in ext.members if x.name == "sType").values
2458                 win_type = ext.name + "32" if self.conv and ext.needs_win32_type() else ext.name
2459                 if self.direction == Direction.INPUT:
2460                     in_type = "const " + win_type
2461                     out_type = ext.name
2462                 else:
2463                     in_type = "const " + ext.name
2464                     out_type = win_type
2466                 body += "        case {0}:\n".format(stype)
2467                 body += "        {\n"
2468                 if self.direction == Direction.INPUT:
2469                     body += ident + "{0} *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));\n".format(out_type)
2470                 elif self.conv:
2471                     body += ident + "{0} *out_ext = find_next_struct32(out_header, {1});\n".format(out_type, stype)
2472                 else:
2473                     body += ident + "{0} *out_ext = find_next_struct(out_header, {1});\n".format(out_type, stype)
2475                 copy_body = ""
2477                 for m in ext:
2478                     if m.name == "sType":
2479                         copy_body += ident + "out_ext->sType = {0};\n".format(stype)
2480                         continue
2481                     if not self.member_needs_copy(ext, m):
2482                         continue
2483                     if m.name == "pNext":
2484                         copy_body += ident + "out_ext->pNext = NULL;\n"
2485                         continue
2486                     copy_body += ident + m.copy("in_ext->", "out_ext->", self.direction, self.conv, Unwrap.HOST)
2488                 # Generate the definition of "in_ext" if we need it
2489                 if "in_ext->" in copy_body:
2490                     body += ident + "{0} *in_ext = ({0} *)in_header;\n".format(in_type)
2491                 body += copy_body
2493                 if self.direction == Direction.INPUT:
2494                     body += ident + "out_header->pNext = (void *)out_ext;\n"
2495                 body += ident + "out_header = (void *)out_ext;\n"
2496                 body += ident + "break;\n"
2497                 body += "        }\n"
2499             body += "        default:\n"
2500             if self.direction == Direction.INPUT:
2501                 body += ident + "FIXME(\"Unhandled sType %u.\\n\", in_header->sType);\n"
2502             body += "            break;\n"
2503             body += "        }\n"
2504             body += "    }\n"
2505         elif self.conv and self.direction == Direction.INPUT and "pNext" in self.operand:
2506             body += "    if (in->pNext)\n"
2507             body += "        FIXME(\"Unexpected pNext\\n\");\n"
2509         body += "}\n"
2510         if not self.conv:
2511             body += "#endif /* _WIN64 */\n"
2512         body += "\n"
2514         return body
2517 class ArrayConversionFunction(object):
2518     def __init__(self, array, direction, conv, unwrap):
2519         self.array = array
2520         self.direction = direction
2521         self.type = array.type
2522         self.conv = conv
2523         self.unwrap = unwrap
2525         if array.is_static_array() and direction == Direction.INPUT:
2526             LOGGER.error("Static array input conversion is not supported")
2528         name = "convert_{0}_".format(array.type)
2529         if array.pointer_array:
2530             name += "pointer_"
2531         name += "array_"
2532         win_type = "win32" if self.conv else "win64"
2533         name += convert_suffix(direction, win_type, unwrap, array.is_wrapped())
2534         self.name = name
2536     def __eq__(self, other):
2537         return self.name == other.name
2539     def definition(self):
2540         """ Helper function for generating a conversion function for array operands. """
2542         body = ""
2544         if not self.conv:
2545             body += "#ifdef _WIN64\n"
2547         needs_alloc = self.direction != Direction.OUTPUT and self.array.needs_alloc(self.conv, self.unwrap)
2548         pointer_array = self.array.pointer_array or self.array.is_pointer_pointer()
2550         win_type = self.type
2551         if self.conv:
2552             if self.array.needs_win32_type():
2553                 win_type += "32"
2554             elif self.array.is_handle() and self.array.handle.is_dispatchable():
2555                 win_type = "PTR32"
2556         if self.direction == Direction.OUTPUT and self.array.is_const():
2557             win_type = "const " + win_type
2558         pointer_part = self.array.pointer if self.array.pointer else "*"
2560         if self.direction == Direction.OUTPUT:
2561             if self.conv and pointer_array:
2562                 out = "PTR32 *out"
2563             else:
2564                 out = "{0} {1}out".format(win_type, pointer_part)
2565             params = ["const {0} {1}in".format(self.type, pointer_part), out, "uint32_t count"]
2566             return_type = None
2567         elif self.conv and pointer_array:
2568             params = ["const PTR32 *in", "uint32_t count"]
2569             return_type = self.type
2570         else:
2571             params = ["const {0} {1}in".format(win_type, pointer_part), "uint32_t count"]
2572             return_type = self.type
2574         needs_copy = not self.array.is_struct() or self.direction != Direction.INPUT or \
2575             not self.array.struct.returnedonly or "pNext" in self.array.struct
2577         # Generate function prototype.
2578         if return_type:
2579             body += "static inline {0}{1} {2}{3}(".format(
2580                 "const " if self.array.is_const() else "", return_type, pointer_part, self.name)
2581         else:
2582             body += "static inline void {0}(".format(self.name)
2583         if needs_alloc:
2584             body += "struct conversion_context *ctx, "
2585         body += ", ".join(p for p in params)
2586         body += ")\n{\n"
2588         if return_type:
2589             pointer = self.array.pointer.replace('const*', '*').replace(' *', '*')
2590             body += "    {0} {1}out;\n".format(return_type, pointer)
2591         if needs_copy:
2592             body += "    unsigned int i;\n\n"
2594         if return_type:
2595             body += "    if (!in || !count) return NULL;\n\n"
2596         else:
2597             body += "    if (!in) return;\n\n"
2599         if self.direction == Direction.INPUT:
2600             body += "    out = conversion_context_alloc(ctx, count * sizeof(*out));\n"
2602         if needs_copy:
2603             body += "    for (i = 0; i < count; i++)\n"
2604             body += "    {\n"
2606             if self.array.is_struct():
2607                 struct = self.array.struct
2608                 win_part = "win32" if self.conv else "win64"
2609                 suffix = convert_suffix(self.direction, win_part, self.unwrap, struct.is_wrapped())
2610                 ctx_part = ""
2611                 if self.direction == Direction.INPUT and struct.needs_alloc(self.conv, self.unwrap):
2612                     ctx_part = "ctx, "
2614                 if not pointer_array:
2615                     body += "        convert_{0}_{1}({2}&in[i], &out[i]);\n".format(
2616                         struct.name, suffix, ctx_part)
2617                 else:
2618                     if struct.needs_conversion(self.conv, self.unwrap, self.direction, False):
2619                         body += "        if (in[i])\n"
2620                         body += "        {\n"
2621                         body += "            out[i] = conversion_context_alloc(ctx, sizeof(*out[i]));\n"
2622                         if self.conv:
2623                             in_param = "({0} *)UlongToPtr(in[i])".format(win_type)
2624                         else:
2625                             in_param = "in[i]"
2626                         body += "            convert_{0}_{1}({2}{3}, out[i]);\n".format(
2627                             struct.name, suffix, ctx_part, in_param)
2628                         body += "        }\n"
2629                         body += "        else\n"
2630                         body += "            out[i] = NULL;\n"
2631                     else:
2632                         body += "        out[i] = UlongToPtr(in[i]);\n"
2633             elif self.array.is_handle():
2634                 if pointer_array:
2635                     LOGGER.error("Unhandled handle pointer arrays")
2636                 handle = self.array.handle
2637                 if not self.conv or not handle.is_dispatchable():
2638                     input = "in[i]"
2639                 elif self.direction == Direction.INPUT:
2640                     input = "UlongToPtr(in[i])"
2641                 else:
2642                     input = "PtrToUlong(in[i])"
2644                 if self.unwrap == Unwrap.NONE or not handle.is_wrapped():
2645                     body += "        out[i] = {0};\n".format(input)
2646                 elif self.direction == Direction.INPUT:
2647                     body += "        out[i] = {0};\n".format(handle.unwrap_handle(input, self.unwrap))
2648                 else:
2649                     LOGGER.warning("Unhandled handle output conversion")
2650             elif pointer_array:
2651                 if self.direction == Direction.INPUT:
2652                     body += "        out[i] = UlongToPtr(in[i]);\n"
2653                 else:
2654                     body += "        out[i] = PtrToUlong(in[i]);\n"
2655             else:
2656                 body += "        out[i] = in[i];\n"
2658             body += "    }\n"
2660         if return_type:
2661             body += "\n    return {0}out;\n".format("(void *)" if pointer_array else "")
2662         body += "}\n"
2664         if not self.conv:
2665             body += "#endif /* _WIN64 */\n"
2667         body += "\n"
2669         return body
2672 class VkGenerator(object):
2673     def __init__(self, registry):
2674         self.registry = registry
2676         # Build a list conversion functions for struct conversion.
2677         self.conversions = []
2678         self.win32_structs = []
2679         for func in self.registry.funcs.values():
2680             if not func.needs_exposing():
2681                 continue
2683             conversions = func.get_conversions()
2684             for conv in conversions:
2685                 # Append if we don't already have this conversion.
2686                 if not any(c == conv for c in self.conversions):
2687                     self.conversions.append(conv)
2689                 if not isinstance(conv, StructConversionFunction):
2690                     continue
2692                 for e in conv.operand.struct_extensions:
2693                     if not e.required or not e.needs_win32_type():
2694                         continue
2695                     if not any(s.name == e.name for s in self.win32_structs):
2696                         self.win32_structs.append(e)
2698                 if not conv.operand.needs_win32_type():
2699                     continue
2701                 # Structs can be used in different ways by different conversions
2702                 # e.g. array vs non-array. Just make sure we pull in each struct once.
2703                 if not any(s.name == conv.operand.name for s in self.win32_structs):
2704                     self.win32_structs.append(conv.operand)
2706     def _generate_copyright(self, f, spec_file=False):
2707         f.write("# " if spec_file else "/* ")
2708         f.write("Automatically generated from Vulkan vk.xml; DO NOT EDIT!\n")
2709         lines = ["", "This file is generated from Vulkan vk.xml file covered",
2710             "by the following copyright and permission notice:"]
2711         lines.extend([l.rstrip(" ") for l in self.registry.copyright.splitlines()])
2712         for line in lines:
2713             f.write("{0}{1}".format("# " if spec_file else " * ", line).rstrip(" ") + "\n")
2714         f.write("\n" if spec_file else " */\n\n")
2716     def generate_thunks_c(self, f):
2717         self._generate_copyright(f)
2719         f.write("#if 0\n")
2720         f.write("#pragma makedep unix\n")
2721         f.write("#endif\n\n")
2723         f.write("#include \"config.h\"\n\n")
2725         f.write("#include <stdlib.h>\n\n")
2727         f.write("#include \"vulkan_private.h\"\n\n")
2729         f.write("WINE_DEFAULT_DEBUG_CHANNEL(vulkan);\n\n")
2731         for struct in self.win32_structs:
2732             f.write(struct.definition(conv=True, align=True))
2733             f.write("\n")
2735         f.write("static uint64_t wine_vk_unwrap_handle(uint32_t type, uint64_t handle)\n")
2736         f.write("{\n")
2737         f.write("    switch(type)\n")
2738         f.write("    {\n")
2739         for handle in self.registry.handles:
2740             if not handle.is_required() or not handle.is_wrapped() or handle.is_alias():
2741                 continue
2742             f.write("    case {}:\n".format(handle.object_type))
2743             if handle.is_dispatchable():
2744                 f.write("        return (uint64_t) (uintptr_t) ")
2745                 f.write(handle.host_handle("(({}) (uintptr_t) handle)".format(handle.name)))
2746             else:
2747                 f.write("        return (uint64_t) ")
2748                 f.write(handle.host_handle("handle"))
2749             f.write(";\n");
2750         f.write("    default:\n")
2751         f.write("       return handle;\n")
2752         f.write("    }\n")
2753         f.write("}\n\n")
2755         # Generate any conversion helper functions.
2756         for conv in self.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.name in MANUAL_LOADER_FUNCTIONS:
2765                 continue
2767             f.write(vk_func.thunk(prefix="thunk64_"))
2768             f.write(vk_func.thunk(prefix="thunk32_", conv=True))
2770         # Create array of device extensions.
2771         f.write("static const char * const vk_device_extensions[] =\n{\n")
2772         for ext in self.registry.extensions:
2773             if ext["type"] != "device":
2774                 continue
2775             if ext["name"] in UNEXPOSED_EXTENSIONS:
2776                 continue
2778             f.write("    \"{0}\",\n".format(ext["name"]))
2779         f.write("};\n\n")
2781         # Create array of instance extensions.
2782         f.write("static const char * const vk_instance_extensions[] =\n{\n")
2783         for ext in self.registry.extensions:
2784             if ext["type"] != "instance":
2785                 continue
2786             if ext["name"] in UNEXPOSED_EXTENSIONS:
2787                 continue
2789             f.write("    \"{0}\",\n".format(ext["name"]))
2790         f.write("};\n\n")
2792         # Create array of surface extensions.
2793         f.write("static const char * const vk_host_surface_extensions[] =\n{\n")
2794         for ext in self.registry.surface_extensions:
2795             if ext["name"] not in WIN_SURFACE_EXTENSIONS:
2796                 f.write("    \"{0}\",\n".format(ext["name"]))
2797         f.write("};\n\n")
2799         f.write("BOOL wine_vk_device_extension_supported(const char *name)\n")
2800         f.write("{\n")
2801         f.write("    unsigned int i;\n")
2802         f.write("    for (i = 0; i < ARRAY_SIZE(vk_device_extensions); i++)\n")
2803         f.write("    {\n")
2804         f.write("        if (strcmp(vk_device_extensions[i], name) == 0)\n")
2805         f.write("            return TRUE;\n")
2806         f.write("    }\n")
2807         f.write("    return FALSE;\n")
2808         f.write("}\n\n")
2810         f.write("BOOL wine_vk_instance_extension_supported(const char *name)\n")
2811         f.write("{\n")
2812         f.write("    unsigned int i;\n")
2813         f.write("    for (i = 0; i < ARRAY_SIZE(vk_instance_extensions); i++)\n")
2814         f.write("    {\n")
2815         f.write("        if (strcmp(vk_instance_extensions[i], name) == 0)\n")
2816         f.write("            return TRUE;\n")
2817         f.write("    }\n")
2818         f.write("    return FALSE;\n")
2819         f.write("}\n\n")
2821         f.write("BOOL wine_vk_is_host_surface_extension(const char *name)\n")
2822         f.write("{\n")
2823         f.write("    unsigned int i;\n")
2824         f.write("    for (i = 0; i < ARRAY_SIZE(vk_host_surface_extensions); i++)\n")
2825         f.write("    {\n")
2826         f.write("        if (strcmp(vk_host_surface_extensions[i], name) == 0)\n")
2827         f.write("            return TRUE;\n")
2828         f.write("    }\n")
2829         f.write("    return FALSE;\n")
2830         f.write("}\n\n")
2832         f.write("BOOL wine_vk_is_type_wrapped(VkObjectType type)\n")
2833         f.write("{\n")
2834         f.write("    return FALSE")
2835         for handle in self.registry.handles:
2836             if not handle.is_required() or not handle.is_wrapped() or handle.is_alias():
2837                 continue
2838             f.write(" ||\n        type == {}".format(handle.object_type))
2839         f.write(";\n")
2840         f.write("}\n\n")
2843         f.write("#ifdef _WIN64\n\n")
2845         f.write("const unixlib_entry_t __wine_unix_call_funcs[] =\n")
2846         f.write("{\n")
2847         f.write("    init_vulkan,\n")
2848         f.write("    vk_is_available_instance_function,\n")
2849         f.write("    vk_is_available_device_function,\n")
2850         for vk_func in self.registry.funcs.values():
2851             if not vk_func.needs_exposing():
2852                 continue
2853             if vk_func.name in MANUAL_LOADER_FUNCTIONS:
2854                 continue
2856             if vk_func.is_perf_critical():
2857                 f.write("    (void *){1}{0},\n".format(vk_func.name, "thunk64_"))
2858             else:
2859                 f.write("    {1}{0},\n".format(vk_func.name, "thunk64_"))
2860         f.write("};\n")
2861         f.write("C_ASSERT(ARRAYSIZE(__wine_unix_call_funcs) == unix_count);\n\n")
2863         f.write("#endif /* _WIN64 */\n\n")
2865         f.write("#ifdef _WIN64\n")
2866         f.write("const unixlib_entry_t __wine_unix_call_wow64_funcs[] =\n")
2867         f.write("#else\n")
2868         f.write("const unixlib_entry_t __wine_unix_call_funcs[] =\n")
2869         f.write("#endif\n")
2870         f.write("{\n")
2871         f.write("    init_vulkan,\n")
2872         f.write("    vk_is_available_instance_function32,\n")
2873         f.write("    vk_is_available_device_function32,\n")
2874         for vk_func in self.registry.funcs.values():
2875             if not vk_func.needs_exposing():
2876                 continue
2877             if vk_func.name in MANUAL_LOADER_FUNCTIONS:
2878                 continue
2880             if vk_func.is_perf_critical():
2881                 f.write("    (void *){1}{0},\n".format(vk_func.name, "thunk32_"))
2882             else:
2883                 f.write("    {1}{0},\n".format(vk_func.name, "thunk32_"))
2884         f.write("};\n")
2885         f.write("C_ASSERT(ARRAYSIZE(__wine_unix_call_funcs) == unix_count);\n")
2887     def generate_thunks_h(self, f, prefix):
2888         self._generate_copyright(f)
2890         f.write("#ifndef __WINE_VULKAN_THUNKS_H\n")
2891         f.write("#define __WINE_VULKAN_THUNKS_H\n\n")
2893         f.write("#define WINE_VK_VERSION VK_API_VERSION_{0}_{1}\n\n".format(WINE_VK_VERSION[0], WINE_VK_VERSION[1]))
2895         # Generate prototypes for device and instance functions requiring a custom implementation.
2896         f.write("/* Functions for which we have custom implementations outside of the thunks. */\n")
2897         for vk_func in self.registry.funcs.values():
2898             if not vk_func.needs_private_thunk():
2899                 continue
2901             f.write("{0};\n".format(vk_func.prototype(prefix=prefix, is_thunk=True)))
2902         f.write("\n")
2904         f.write("/* For use by vkDevice and children */\n")
2905         f.write("struct vulkan_device_funcs\n{\n")
2906         for vk_func in self.registry.device_funcs:
2907             if not vk_func.needs_exposing():
2908                 continue
2910             if not vk_func.needs_dispatch():
2911                 LOGGER.debug("skipping {0} in vulkan_device_funcs".format(vk_func.name))
2912                 continue
2914             f.write("    {0};\n".format(vk_func.pfn()))
2915         f.write("};\n\n")
2917         f.write("/* For use by vkInstance and children */\n")
2918         f.write("struct vulkan_instance_funcs\n{\n")
2919         for vk_func in self.registry.instance_funcs + self.registry.phys_dev_funcs:
2920             if not vk_func.needs_exposing():
2921                 continue
2923             if not vk_func.needs_dispatch():
2924                 LOGGER.debug("skipping {0} in vulkan_instance_funcs".format(vk_func.name))
2925                 continue
2927             f.write("    {0};\n".format(vk_func.pfn()))
2928         f.write("};\n\n")
2930         f.write("#define ALL_VK_DEVICE_FUNCS() \\\n")
2931         first = True
2932         for vk_func in self.registry.device_funcs:
2933             if not vk_func.needs_exposing():
2934                 continue
2936             if not vk_func.needs_dispatch():
2937                 LOGGER.debug("skipping {0} in ALL_VK_DEVICE_FUNCS".format(vk_func.name))
2938                 continue
2940             if first:
2941                 f.write("    USE_VK_FUNC({0})".format(vk_func.name))
2942                 first = False
2943             else:
2944                 f.write(" \\\n    USE_VK_FUNC({0})".format(vk_func.name))
2945         f.write("\n\n")
2947         f.write("#define ALL_VK_INSTANCE_FUNCS() \\\n")
2948         first = True
2949         for vk_func in self.registry.instance_funcs + self.registry.phys_dev_funcs:
2950             if not vk_func.needs_exposing():
2951                 continue
2953             if not vk_func.needs_dispatch():
2954                 LOGGER.debug("skipping {0} in ALL_VK_INSTANCE_FUNCS".format(vk_func.name))
2955                 continue
2957             if first:
2958                 f.write("    USE_VK_FUNC({0})".format(vk_func.name))
2959                 first = False
2960             else:
2961                 f.write(" \\\n    USE_VK_FUNC({0})".format(vk_func.name))
2962         f.write("\n\n")
2964         f.write("#endif /* __WINE_VULKAN_THUNKS_H */\n")
2966     def generate_loader_thunks_c(self, f):
2967         self._generate_copyright(f)
2969         f.write("#include \"vulkan_loader.h\"\n\n")
2971         f.write("WINE_DEFAULT_DEBUG_CHANNEL(vulkan);\n\n")
2973         for vk_func in self.registry.funcs.values():
2974             if not vk_func.needs_exposing():
2975                 continue
2976             if vk_func.name in MANUAL_LOADER_THUNKS | MANUAL_LOADER_FUNCTIONS:
2977                 continue
2979             f.write(vk_func.loader_thunk())
2981         f.write("static const struct vulkan_func vk_device_dispatch_table[] =\n{\n")
2982         for vk_func in self.registry.device_funcs:
2983             if not vk_func.needs_exposing():
2984                 continue
2986             f.write("    {{\"{0}\", {0}}},\n".format(vk_func.name))
2987         f.write("};\n\n")
2989         f.write("static const struct vulkan_func vk_phys_dev_dispatch_table[] =\n{\n")
2990         for vk_func in self.registry.phys_dev_funcs:
2991             if not vk_func.needs_exposing():
2992                 continue
2994             f.write("    {{\"{0}\", {0}}},\n".format(vk_func.name))
2995         f.write("};\n\n")
2997         f.write("static const struct vulkan_func vk_instance_dispatch_table[] =\n{\n")
2998         for vk_func in self.registry.instance_funcs:
2999             if not vk_func.needs_exposing():
3000                 continue
3002             f.write("    {{\"{0}\", {0}}},\n".format(vk_func.name))
3003         f.write("};\n\n")
3005         f.write("void *wine_vk_get_device_proc_addr(const char *name)\n")
3006         f.write("{\n")
3007         f.write("    unsigned int i;\n")
3008         f.write("    for (i = 0; i < ARRAY_SIZE(vk_device_dispatch_table); i++)\n")
3009         f.write("    {\n")
3010         f.write("        if (strcmp(vk_device_dispatch_table[i].name, name) == 0)\n")
3011         f.write("        {\n")
3012         f.write("            TRACE(\"Found name=%s in device table\\n\", debugstr_a(name));\n")
3013         f.write("            return vk_device_dispatch_table[i].func;\n")
3014         f.write("        }\n")
3015         f.write("    }\n")
3016         f.write("    return NULL;\n")
3017         f.write("}\n\n")
3019         f.write("void *wine_vk_get_phys_dev_proc_addr(const char *name)\n")
3020         f.write("{\n")
3021         f.write("    unsigned int i;\n")
3022         f.write("    for (i = 0; i < ARRAY_SIZE(vk_phys_dev_dispatch_table); i++)\n")
3023         f.write("    {\n")
3024         f.write("        if (strcmp(vk_phys_dev_dispatch_table[i].name, name) == 0)\n")
3025         f.write("        {\n")
3026         f.write("            TRACE(\"Found name=%s in physical device table\\n\", debugstr_a(name));\n")
3027         f.write("            return vk_phys_dev_dispatch_table[i].func;\n")
3028         f.write("        }\n")
3029         f.write("    }\n")
3030         f.write("    return NULL;\n")
3031         f.write("}\n\n")
3033         f.write("void *wine_vk_get_instance_proc_addr(const char *name)\n")
3034         f.write("{\n")
3035         f.write("    unsigned int i;\n")
3036         f.write("    for (i = 0; i < ARRAY_SIZE(vk_instance_dispatch_table); i++)\n")
3037         f.write("    {\n")
3038         f.write("        if (strcmp(vk_instance_dispatch_table[i].name, name) == 0)\n")
3039         f.write("        {\n")
3040         f.write("            TRACE(\"Found name=%s in instance table\\n\", debugstr_a(name));\n")
3041         f.write("            return vk_instance_dispatch_table[i].func;\n")
3042         f.write("        }\n")
3043         f.write("    }\n")
3044         f.write("    return NULL;\n")
3045         f.write("}\n")
3047     def generate_loader_thunks_h(self, f):
3048         self._generate_copyright(f)
3050         f.write("#ifndef __WINE_VULKAN_LOADER_THUNKS_H\n")
3051         f.write("#define __WINE_VULKAN_LOADER_THUNKS_H\n\n")
3053         f.write("enum unix_call\n")
3054         f.write("{\n")
3055         f.write("    unix_init,\n")
3056         f.write("    unix_is_available_instance_function,\n")
3057         f.write("    unix_is_available_device_function,\n")
3058         for vk_func in self.registry.funcs.values():
3059             if not vk_func.needs_exposing():
3060                 continue
3061             if vk_func.name in MANUAL_LOADER_FUNCTIONS:
3062                 continue
3064             f.write("    unix_{0},\n".format(vk_func.name))
3065         f.write("    unix_count,\n")
3066         f.write("};\n\n")
3068         for vk_func in self.registry.funcs.values():
3069             if not vk_func.needs_exposing():
3070                 continue
3071             if vk_func.name in MANUAL_LOADER_FUNCTIONS:
3072                 continue
3074             f.write("struct {0}_params\n".format(vk_func.name))
3075             f.write("{\n");
3076             for p in vk_func.params:
3077                 f.write("    {0};\n".format(p.definition(is_member=True)))
3078             if vk_func.extra_param:
3079                 f.write("    void *{0};\n".format(vk_func.extra_param))
3080             if vk_func.type != "void":
3081                 f.write("    {0} result;\n".format(vk_func.type))
3082             f.write("};\n\n");
3084         f.write("#endif /* __WINE_VULKAN_LOADER_THUNKS_H */\n")
3086     def generate_vulkan_h(self, f):
3087         self._generate_copyright(f)
3088         f.write("#ifndef __WINE_VULKAN_H\n")
3089         f.write("#define __WINE_VULKAN_H\n\n")
3091         f.write("#include <windef.h>\n")
3092         f.write("#include <stdint.h>\n\n")
3094         f.write("/* Define WINE_VK_HOST to get 'host' headers. */\n")
3095         f.write("#ifdef WINE_VK_HOST\n")
3096         f.write("#define VKAPI_CALL\n")
3097         f.write('#define WINE_VK_ALIGN(x)\n')
3098         f.write("#endif\n\n")
3100         f.write("#ifndef VKAPI_CALL\n")
3101         f.write("#define VKAPI_CALL __stdcall\n")
3102         f.write("#endif\n\n")
3104         f.write("#ifndef VKAPI_PTR\n")
3105         f.write("#define VKAPI_PTR VKAPI_CALL\n")
3106         f.write("#endif\n\n")
3108         f.write("#ifndef WINE_VK_ALIGN\n")
3109         f.write("#define WINE_VK_ALIGN DECLSPEC_ALIGN\n")
3110         f.write("#endif\n\n")
3112         # The overall strategy is to define independent constants and datatypes,
3113         # prior to complex structures and function calls to avoid forward declarations.
3114         for const in self.registry.consts:
3115             # For now just generate things we may not need. The amount of parsing needed
3116             # to get some of the info is tricky as you need to figure out which structure
3117             # references a certain constant.
3118             f.write(const.definition())
3119         f.write("\n")
3121         for define in self.registry.defines:
3122             f.write(define.definition())
3124         for handle in self.registry.handles:
3125             # For backward compatibility also create definitions for aliases.
3126             # These types normally don't get pulled in as we use the new types
3127             # even in legacy functions if they are aliases.
3128             if handle.is_required() or handle.is_alias():
3129                  f.write(handle.definition())
3130         f.write("\n")
3132         for base_type in self.registry.base_types:
3133             f.write(base_type.definition())
3134         f.write("\n")
3136         for bitmask in self.registry.bitmasks:
3137             f.write(bitmask.definition())
3138         f.write("\n")
3140         # Define enums, this includes values for some of the bitmask types as well.
3141         for enum in self.registry.enums.values():
3142             if enum.required:
3143                 f.write(enum.definition())
3145         for fp in self.registry.funcpointers:
3146             if fp.required:
3147                 f.write(fp.definition())
3148         f.write("\n")
3150         # This generates both structures and unions. Since structures
3151         # may depend on other structures/unions, we need a list of
3152         # decoupled structs.
3153         # Note: unions are stored in structs for dependency reasons,
3154         # see comment in parsing section.
3155         structs = VkStruct.decouple_structs(self.registry.structs)
3156         for struct in structs:
3157             LOGGER.debug("Generating struct: {0}".format(struct.name))
3158             f.write(struct.definition(align=True))
3159             f.write("\n")
3161         for func in self.registry.funcs.values():
3162             if not func.is_required():
3163                 LOGGER.debug("Skipping PFN definition for: {0}".format(func.name))
3164                 continue
3166             f.write("typedef {0};\n".format(func.pfn(prefix="PFN", call_conv="VKAPI_PTR")))
3167         f.write("\n")
3169         f.write("#ifndef VK_NO_PROTOTYPES\n")
3170         for func in self.registry.funcs.values():
3171             if not func.is_required():
3172                 LOGGER.debug("Skipping API definition for: {0}".format(func.name))
3173                 continue
3175             LOGGER.debug("Generating API definition for: {0}".format(func.name))
3176             f.write("{0};\n".format(func.prototype(call_conv="VKAPI_CALL")))
3177         f.write("#endif /* VK_NO_PROTOTYPES */\n\n")
3179         f.write("#endif /* __WINE_VULKAN_H */\n")
3181     def generate_vulkan_spec(self, f):
3182         self._generate_copyright(f, spec_file=True)
3183         f.write("@ stdcall -private vk_icdGetInstanceProcAddr(ptr str)\n")
3184         f.write("@ stdcall -private vk_icdGetPhysicalDeviceProcAddr(ptr str)\n")
3185         f.write("@ stdcall -private vk_icdNegotiateLoaderICDInterfaceVersion(ptr)\n")
3187         # Export symbols for all Vulkan Core functions.
3188         for func in self.registry.funcs.values():
3189             if not func.is_core_func():
3190                 continue
3192             # We support all Core functions except for VK_KHR_display* APIs.
3193             # Create stubs for unsupported Core functions.
3194             if func.is_required():
3195                 f.write(func.spec())
3196             else:
3197                 f.write("@ stub {0}\n".format(func.name))
3199         f.write("@ stdcall -private DllRegisterServer()\n")
3200         f.write("@ stdcall -private DllUnregisterServer()\n")
3202     def generate_vulkan_loader_spec(self, f):
3203         self._generate_copyright(f, spec_file=True)
3205         # Export symbols for all Vulkan Core functions.
3206         for func in self.registry.funcs.values():
3207             if not func.is_core_func():
3208                 continue
3210             # We support all Core functions except for VK_KHR_display* APIs.
3211             # Create stubs for unsupported Core functions.
3212             if func.is_required():
3213                 f.write(func.spec(symbol="winevulkan." + func.name))
3214             else:
3215                 f.write("@ stub {0}\n".format(func.name))
3218 class VkRegistry(object):
3219     def __init__(self, reg_filename):
3220         # Used for storage of type information.
3221         self.base_types = None
3222         self.bitmasks = None
3223         self.consts = None
3224         self.defines = None
3225         self.enums = None
3226         self.funcpointers = None
3227         self.handles = None
3228         self.structs = None
3230         # We aggregate all types in here for cross-referencing.
3231         self.funcs = {}
3232         self.types = {}
3233         self.surface_extensions = []
3235         self.version_regex = re.compile(
3236             r'^'
3237             r'VK_VERSION_'
3238             r'(?P<major>[0-9])'
3239             r'_'
3240             r'(?P<minor>[0-9])'
3241             r'$'
3242         )
3244         # Overall strategy for parsing the registry is to first
3245         # parse all type / function definitions. Then parse
3246         # features and extensions to decide which types / functions
3247         # to actually 'pull in' for code generation. For each type or
3248         # function call we want we set a member 'required' to True.
3249         tree = ET.parse(reg_filename)
3250         root = tree.getroot()
3251         self._parse_enums(root)
3252         self._parse_types(root)
3253         self._parse_commands(root)
3255         # Pull in any required types and functions.
3256         self._parse_features(root)
3257         self._parse_extensions(root)
3259         for enum in self.enums.values():
3260             enum.fixup_64bit_aliases()
3262         self._match_object_types()
3264         self.copyright = root.find('./comment').text
3266     def _is_feature_supported(self, feature):
3267         version = self.version_regex.match(feature)
3268         if not version:
3269             return True
3271         version = tuple(map(int, version.group('major', 'minor')))
3272         return version <= WINE_VK_VERSION
3274     def _is_extension_supported(self, extension):
3275         # We disable some extensions as either we haven't implemented
3276         # support yet or because they are for platforms other than win32.
3277         return extension not in UNSUPPORTED_EXTENSIONS
3279     def _mark_command_required(self, command):
3280         """ Helper function to mark a certain command and the datatypes it needs as required."""
3281         def mark_bitmask_dependencies(bitmask, types):
3282             if bitmask.requires is not None:
3283                 types[bitmask.requires]["data"].required = True
3285         def mark_funcpointer_dependencies(fp, types):
3286             for m in fp.members:
3287                 type_info = types[m.type]
3289                 # Complex types have a matching definition e.g. VkStruct.
3290                 # Not needed for base types such as uint32_t.
3291                 if "data" in type_info:
3292                     types[m.type]["data"].required = True
3294         def mark_struct_dependencies(struct, types):
3295              for m in struct:
3296                 type_info = types[m.type]
3298                 # Complex types have a matching definition e.g. VkStruct.
3299                 # Not needed for base types such as uint32_t.
3300                 if "data" in type_info:
3301                     types[m.type]["data"].required = True
3303                 if type_info["category"] == "struct" and struct.name != m.type:
3304                     # Yay, recurse
3305                     mark_struct_dependencies(type_info["data"], types)
3306                 elif type_info["category"] == "funcpointer":
3307                     mark_funcpointer_dependencies(type_info["data"], types)
3308                 elif type_info["category"] == "bitmask":
3309                     mark_bitmask_dependencies(type_info["data"], types)
3311         func = self.funcs[command]
3312         func.required = True
3314         # Pull in return type
3315         if func.type != "void":
3316             self.types[func.type]["data"].required = True
3318         # Analyze parameter dependencies and pull in any type needed.
3319         for p in func.params:
3320             type_info = self.types[p.type]
3322             # Check if we are dealing with a complex type e.g. VkEnum, VkStruct and others.
3323             if "data" not in type_info:
3324                 continue
3326             # Mark the complex type as required.
3327             type_info["data"].required = True
3328             if type_info["category"] == "struct":
3329                 struct = type_info["data"]
3330                 mark_struct_dependencies(struct, self.types)
3331             elif type_info["category"] == "bitmask":
3332                 mark_bitmask_dependencies(type_info["data"], self.types)
3334     def _match_object_types(self):
3335         """ Matches each handle with the correct object type. """
3336         # Use upper case comparison for simplicity.
3337         object_types = {}
3338         for value in self.enums["VkObjectType"].values:
3339             object_name = "VK" + value.name[len("VK_OBJECT_TYPE"):].replace("_", "")
3340             object_types[object_name] = value.name
3342         for handle in self.handles:
3343             if not handle.is_required():
3344                 continue
3345             handle.object_type = object_types.get(handle.name.upper())
3346             if not handle.object_type:
3347                 LOGGER.warning("No object type found for {}".format(handle.name))
3349     def _parse_commands(self, root):
3350         """ Parse command section containing the Vulkan function calls. """
3351         funcs = {}
3352         commands = root.findall("./commands/")
3354         # As of Vulkan 1.1, various extensions got promoted to Core.
3355         # The old commands (e.g. KHR) are available for backwards compatibility
3356         # and are marked in vk.xml as 'alias' to the non-extension type.
3357         # The registry likes to avoid data duplication, so parameters and other
3358         # metadata need to be looked up from the Core command.
3359         # We parse the alias commands in a second pass.
3360         alias_commands = []
3361         for command in commands:
3362             alias_name = command.attrib.get("alias")
3363             if alias_name:
3364                 alias_commands.append(command)
3365                 continue
3367             func = VkFunction.from_xml(command, self.types)
3368             if func:
3369                 funcs[func.name] = func
3371         for command in alias_commands:
3372             alias_name = command.attrib.get("alias")
3373             alias = funcs[alias_name]
3374             func = VkFunction.from_alias(command, alias)
3375             if func:
3376                 funcs[func.name] = func
3378         # To make life easy for the code generation, separate all function
3379         # calls out in the 4 types of Vulkan functions:
3380         # device, global, physical device and instance.
3381         device_funcs = []
3382         global_funcs = []
3383         phys_dev_funcs = []
3384         instance_funcs = []
3385         for func in funcs.values():
3386             if func.is_device_func():
3387                 device_funcs.append(func)
3388             elif func.is_global_func():
3389                 global_funcs.append(func)
3390             elif func.is_phys_dev_func():
3391                 phys_dev_funcs.append(func)
3392             else:
3393                 instance_funcs.append(func)
3395         # Sort function lists by name and store them.
3396         self.device_funcs = sorted(device_funcs, key=lambda func: func.name)
3397         self.global_funcs = sorted(global_funcs, key=lambda func: func.name)
3398         self.phys_dev_funcs = sorted(phys_dev_funcs, key=lambda func: func.name)
3399         self.instance_funcs = sorted(instance_funcs, key=lambda func: func.name)
3401         # The funcs dictionary is used as a convenient way to lookup function
3402         # calls when needed e.g. to adjust member variables.
3403         self.funcs = OrderedDict(sorted(funcs.items()))
3405     def _parse_enums(self, root):
3406         """ Parse enums section or better described as constants section. """
3407         enums = {}
3408         self.consts = []
3409         for enum in root.findall("./enums"):
3410             name = enum.attrib.get("name")
3411             _type = enum.attrib.get("type")
3413             if _type in ("enum", "bitmask"):
3414                 enum_obj = VkEnum.from_xml(enum)
3415                 if enum_obj:
3416                     enums[name] = enum_obj
3417             else:
3418                 # If no type is set, we are dealing with API constants.
3419                 for value in enum.findall("enum"):
3420                     # If enum is an alias, set the value to the alias name.
3421                     # E.g. VK_LUID_SIZE_KHR is an alias to VK_LUID_SIZE.
3422                     alias = value.attrib.get("alias")
3423                     if alias:
3424                         self.consts.append(VkConstant(value.attrib.get("name"), alias))
3425                     else:
3426                         self.consts.append(VkConstant(value.attrib.get("name"), value.attrib.get("value")))
3428         self.enums = OrderedDict(sorted(enums.items()))
3430     def _process_require_enum(self, enum_elem, ext=None, only_aliased=False):
3431         if "extends" in enum_elem.keys():
3432             enum = self.types[enum_elem.attrib["extends"]]["data"]
3434             # Need to define VkEnumValues which were aliased to by another value. This is necessary
3435             # from VK spec version 1.2.135 where the provisional VK_KHR_ray_tracing extension was
3436             # added which altered VK_NV_ray_tracing's VkEnumValues to alias to the provisional
3437             # extension.
3438             aliased = False
3439             for _, t in self.types.items():
3440                 if t["category"] != "enum":
3441                     continue
3442                 if not t["data"]:
3443                     continue
3444                 for value in t["data"].values:
3445                     if value.alias == enum_elem.attrib["name"]:
3446                         aliased = True
3448             if only_aliased and not aliased:
3449                 return
3451             if "bitpos" in enum_elem.keys():
3452                 # We need to add an extra value to an existing enum type.
3453                 # E.g. VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG to VkFormatFeatureFlagBits.
3454                 enum.create_bitpos(enum_elem.attrib["name"], int(enum_elem.attrib["bitpos"]))
3456             elif "offset" in enum_elem.keys():
3457                 # Extensions promoted to Core, have the extension number as part
3458                 # of the enum value. Else retrieve from the extension tag.
3459                 if enum_elem.attrib.get("extnumber"):
3460                     ext_number = int(enum_elem.attrib.get("extnumber"))
3461                 else:
3462                     ext_number = int(ext.attrib["number"])
3463                 offset = int(enum_elem.attrib["offset"])
3464                 value = EXT_BASE + (ext_number - 1) * EXT_BLOCK_SIZE + offset
3466                 # Deal with negative values.
3467                 direction = enum_elem.attrib.get("dir")
3468                 if direction is not None:
3469                     value = -value
3471                 enum.create_value(enum_elem.attrib["name"], str(value))
3473             elif "value" in enum_elem.keys():
3474                 enum.create_value(enum_elem.attrib["name"], enum_elem.attrib["value"])
3475             elif "alias" in enum_elem.keys():
3476                 enum.create_alias(enum_elem.attrib["name"], enum_elem.attrib["alias"])
3478         elif "value" in enum_elem.keys():
3479             # Constant with an explicit value
3480             if only_aliased:
3481                 return
3483             self.consts.append(VkConstant(enum_elem.attrib["name"], enum_elem.attrib["value"]))
3484         elif "alias" in enum_elem.keys():
3485             # Aliased constant
3486             if not only_aliased:
3487                 return
3489             self.consts.append(VkConstant(enum_elem.attrib["name"], enum_elem.attrib["alias"]))
3491     @staticmethod
3492     def _require_type(type_info):
3493         if type_info.is_alias():
3494             type_info = type_info.alias
3495         type_info.required = True
3496         if type(type_info) == VkStruct:
3497             for member in type_info.members:
3498                 if "data" in member.type_info:
3499                   VkRegistry._require_type(member.type_info["data"])
3501     def _parse_extensions(self, root):
3502         """ Parse extensions section and pull in any types and commands for this extension. """
3503         extensions = []
3504         exts = root.findall("./extensions/extension")
3505         deferred_exts = []
3506         skipped_exts = UNSUPPORTED_EXTENSIONS.copy()
3508         def process_ext(ext, deferred=False):
3509             ext_name = ext.attrib["name"]
3511             if ext_name.endswith('_surface') and ext.attrib.get('depends', None) == 'VK_KHR_surface':
3512                 self.surface_extensions.append({"name" : ext_name})
3514             # Set extension name on any functions calls part of this extension as we
3515             # were not aware of the name during initial parsing.
3516             commands = ext.findall("require/command")
3517             for command in commands:
3518                 cmd_name = command.attrib["name"]
3519                 # Need to verify that the command is defined, and otherwise skip it.
3520                 # vkCreateScreenSurfaceQNX is declared in <extensions> but not defined in
3521                 # <commands>. A command without a definition cannot be enabled, so it's valid for
3522                 # the XML file to handle this, but because of the manner in which we parse the XML
3523                 # file we pre-populate from <commands> before we check if a command is enabled.
3524                 if cmd_name in self.funcs:
3525                     self.funcs[cmd_name].extensions.add(ext_name)
3527             # Some extensions are not ready or have numbers reserved as a place holder
3528             # or are only supported for VulkanSC.
3529             if not "vulkan" in ext.attrib["supported"].split(","):
3530                 LOGGER.debug("Skipping disabled extension: {0}".format(ext_name))
3531                 skipped_exts.append(ext_name)
3532                 return
3534             # Defer extensions with 'sortorder' as they are order-dependent for spec-parsing.
3535             if not deferred and "sortorder" in ext.attrib:
3536                 deferred_exts.append(ext)
3537                 return
3539             # Disable highly experimental extensions as the APIs are unstable and can
3540             # change between minor Vulkan revisions until API is final and becomes KHR
3541             # or NV.
3542             if ("KHX" in ext_name or "NVX" in ext_name) and ext_name not in ALLOWED_X_EXTENSIONS:
3543                 LOGGER.debug("Skipping experimental extension: {0}".format(ext_name))
3544                 skipped_exts.append(ext_name)
3545                 return
3547             # Extensions can define VkEnumValues which alias to provisional extensions. Pre-process
3548             # extensions to define any required VkEnumValues before the platform check below.
3549             for require in ext.findall("require"):
3550                 # Extensions can add enum values to Core / extension enums, so add these.
3551                 for enum_elem in require.findall("enum"):
3552                     self._process_require_enum(enum_elem, ext, only_aliased=True)
3554             platform = ext.attrib.get("platform")
3555             if platform and platform != "win32":
3556                 LOGGER.debug("Skipping extensions {0} for platform {1}".format(ext_name, platform))
3557                 skipped_exts.append(ext_name)
3558                 return
3560             if not self._is_extension_supported(ext_name):
3561                 LOGGER.debug("Skipping unsupported extension: {0}".format(ext_name))
3562                 skipped_exts.append(ext_name)
3563                 return
3564             elif "requires" in ext.attrib:
3565                 # Check if this extension builds on top of another unsupported extension.
3566                 requires = ext.attrib["requires"].split(",")
3567                 if len(set(requires).intersection(skipped_exts)) > 0:
3568                     skipped_exts.append(ext_name)
3569                     return
3570             elif "depends" in ext.attrib:
3571                 # The syntax for this is more complex, but this is good enough for now.
3572                 if any([sext in ext.attrib["depends"] for sext in skipped_exts]):
3573                     skipped_exts.append(ext_name)
3574                     return
3576             LOGGER.debug("Loading extension: {0}".format(ext_name))
3578             # Extensions can define one or more require sections each requiring
3579             # different features (e.g. Vulkan 1.1). Parse each require section
3580             # separately, so we can skip sections we don't want.
3581             for require in ext.findall("require"):
3582                 # Extensions can add enum values to Core / extension enums, so add these.
3583                 for enum_elem in require.findall("enum"):
3584                     self._process_require_enum(enum_elem, ext)
3586                 for t in require.findall("type"):
3587                     type_info = self.types[t.attrib["name"]]["data"]
3588                     self._require_type(type_info)
3589                 feature = require.attrib.get("feature")
3590                 if feature and not self._is_feature_supported(feature):
3591                     continue
3593                 required_extension = require.attrib.get("extension")
3594                 if required_extension and not self._is_extension_supported(required_extension):
3595                     continue
3597                 # Pull in any commands we need. We infer types to pull in from the command
3598                 # as well.
3599                 for command in require.findall("command"):
3600                     cmd_name = command.attrib["name"]
3601                     self._mark_command_required(cmd_name)
3604             # Store a list with extensions.
3605             ext_info = {"name" : ext_name, "type" : ext.attrib["type"]}
3606             extensions.append(ext_info)
3609         # Process extensions, allowing for sortorder to defer extension processing
3610         for ext in exts:
3611             process_ext(ext)
3613         deferred_exts.sort(key=lambda ext: ext.attrib["sortorder"])
3615         # Respect sortorder
3616         for ext in deferred_exts:
3617             process_ext(ext, deferred=True)
3619         # Sort in alphabetical order.
3620         self.extensions = sorted(extensions, key=lambda ext: ext["name"])
3622     def _parse_features(self, root):
3623         """ Parse the feature section, which describes Core commands and types needed. """
3625         for feature in root.findall("./feature"):
3626             if not api_is_vulkan(feature):
3627                 continue
3628             feature_name = feature.attrib["name"]
3629             for require in feature.findall("require"):
3630                 LOGGER.info("Including features for {0}".format(require.attrib.get("comment")))
3631                 for tag in require:
3632                     if tag.tag == "comment":
3633                         continue
3634                     elif tag.tag == "command":
3635                         if not self._is_feature_supported(feature_name):
3636                             continue
3637                         name = tag.attrib["name"]
3638                         self._mark_command_required(name)
3639                     elif tag.tag == "enum":
3640                         self._process_require_enum(tag)
3641                     elif tag.tag == "type":
3642                         name = tag.attrib["name"]
3644                         # Skip pull in for vk_platform.h for now.
3645                         if name == "vk_platform":
3646                             continue
3648                         type_info = self.types[name]
3649                         type_info["data"].required = True
3651     def _parse_types(self, root):
3652         """ Parse types section, which contains all data types e.g. structs, typedefs etcetera. """
3653         types = root.findall("./types/type")
3655         base_types = []
3656         bitmasks = []
3657         defines = []
3658         funcpointers = []
3659         handles = []
3660         structs = []
3662         alias_types = []
3663         for t in types:
3664             type_info = {}
3665             type_info["category"] = t.attrib.get("category", None)
3666             type_info["requires"] = t.attrib.get("requires", None)
3668             # We parse aliases in a second pass when we know more.
3669             alias = t.attrib.get("alias")
3670             if alias:
3671                 LOGGER.debug("Alias found: {0}".format(alias))
3672                 alias_types.append(t)
3673                 continue
3675             if type_info["category"] in ["include"]:
3676                 continue
3678             if type_info["category"] == "basetype":
3679                 name = t.find("name").text
3680                 _type = None
3681                 if not t.find("type") is None:
3682                     _type = t.find("type").text
3683                     tail = t.find("type").tail
3684                     if tail is not None:
3685                         _type += tail.strip()
3686                 basetype = VkBaseType(name, _type)
3687                 if basetype:
3688                     base_types.append(basetype)
3689                     type_info["data"] = basetype
3690                 else:
3691                     continue
3693             # Basic C types don't need us to define them, but we do need data for them
3694             if type_info["requires"] == "vk_platform":
3695                 requires = type_info["requires"]
3696                 basic_c = VkBaseType(name, _type, requires=requires)
3697                 type_info["data"] = basic_c
3699             if type_info["category"] == "bitmask":
3700                 name = t.find("name").text
3701                 _type = t.find("type").text
3703                 # Most bitmasks have a requires attribute used to pull in
3704                 # required '*FlagBits" enum.
3705                 requires = type_info["requires"]
3706                 bitmask = VkBaseType(name, _type, requires=requires)
3707                 bitmasks.append(bitmask)
3708                 type_info["data"] = bitmask
3710             if type_info["category"] == "define":
3711                 define = VkDefine.from_xml(t)
3712                 if define:
3713                     defines.append(define)
3714                     type_info["data"] = define
3715                 else:
3716                     continue
3718             if type_info["category"] == "enum":
3719                 name = t.attrib.get("name")
3720                 # The type section only contains enum names, not the actual definition.
3721                 # Since we already parsed the enum before, just link it in.
3722                 try:
3723                     type_info["data"] = self.enums[name]
3724                 except KeyError:
3725                     # Not all enums seem to be defined yet, typically that's for
3726                     # ones ending in 'FlagBits' where future extensions may add
3727                     # definitions.
3728                     type_info["data"] = None
3730             if type_info["category"] == "funcpointer":
3731                 funcpointer = VkFunctionPointer.from_xml(t)
3732                 if funcpointer:
3733                     funcpointers.append(funcpointer)
3734                     type_info["data"] = funcpointer
3735                 else:
3736                     continue
3738             if type_info["category"] == "handle":
3739                 handle = VkHandle.from_xml(t)
3740                 if handle:
3741                     handles.append(handle)
3742                     type_info["data"] = handle
3743                 else:
3744                     continue
3746             if type_info["category"] in ["struct", "union"]:
3747                 # We store unions among structs as some structs depend
3748                 # on unions. The types are very similar in parsing and
3749                 # generation anyway. The official Vulkan scripts use
3750                 # a similar kind of hack.
3751                 struct = VkStruct.from_xml(t)
3752                 if struct:
3753                     structs.append(struct)
3754                     type_info["data"] = struct
3755                 else:
3756                     continue
3758             # Name is in general within a name tag else it is an optional
3759             # attribute on the type tag.
3760             name_elem = t.find("name")
3761             if name_elem is not None:
3762                 type_info["name"] = name_elem.text
3763             else:
3764                 type_info["name"] = t.attrib.get("name", None)
3766             # Store all type data in a shared dictionary, so we can easily
3767             # look up information for a given type. There are no duplicate
3768             # names.
3769             self.types[type_info["name"]] = type_info
3771         # Second pass for alias types, so we can retrieve all data from
3772         # the aliased object.
3773         for t in alias_types:
3774             type_info = {}
3775             type_info["category"] = t.attrib.get("category")
3776             type_info["name"] = t.attrib.get("name")
3778             alias = t.attrib.get("alias")
3780             if type_info["category"] == "bitmask":
3781                 bitmask = VkBaseType(type_info["name"], alias, alias=self.types[alias]["data"])
3782                 bitmasks.append(bitmask)
3783                 type_info["data"] = bitmask
3785             if type_info["category"] == "enum":
3786                 enum = VkEnum.from_alias(t, self.types[alias]["data"])
3787                 type_info["data"] = enum
3788                 self.enums[enum.name] = enum
3790             if type_info["category"] == "handle":
3791                 handle = VkHandle.from_alias(t, self.types[alias]["data"])
3792                 handles.append(handle)
3793                 type_info["data"] = handle
3795             if type_info["category"] == "struct":
3796                 struct = VkStruct.from_alias(t, self.types[alias]["data"])
3797                 structs.append(struct)
3798                 type_info["data"] = struct
3800             self.types[type_info["name"]] = type_info
3802         # We need detailed type information during code generation
3803         # on structs for alignment reasons. Unfortunately structs
3804         # are parsed among other types, so there is no guarantee
3805         # that any types needed have been parsed already, so set
3806         # the data now.
3807         for struct in structs:
3808             struct.set_type_info(self.types)
3810             # Alias structures have enum values equivalent to those of the
3811             # structure which they are aliased against. we need to ignore alias
3812             # structs when populating the struct extensions list, otherwise we
3813             # will create duplicate case entries.
3814             if struct.alias:
3815                 continue
3817             for structextend in struct.structextends:
3818                 s = self.types[structextend]["data"]
3819                 s.struct_extensions.append(struct)
3821         # Guarantee everything is sorted, so code generation doesn't have
3822         # to deal with this.
3823         self.base_types = sorted(base_types, key=lambda base_type: base_type.name)
3824         self.bitmasks = sorted(bitmasks, key=lambda bitmask: bitmask.name)
3825         self.defines = defines
3826         self.enums = OrderedDict(sorted(self.enums.items()))
3827         self.funcpointers = sorted(funcpointers, key=lambda fp: fp.name)
3828         self.handles = sorted(handles, key=lambda handle: handle.name)
3829         self.structs = sorted(structs, key=lambda struct: struct.name)
3831 def generate_vulkan_json(f):
3832     f.write("{\n")
3833     f.write("    \"file_format_version\": \"1.0.0\",\n")
3834     f.write("    \"ICD\": {\n")
3835     f.write("        \"library_path\": \".\\\\winevulkan.dll\",\n")
3836     f.write("        \"api_version\": \"{0}\"\n".format(VK_XML_VERSION))
3837     f.write("    }\n")
3838     f.write("}\n")
3840 def set_working_directory():
3841     path = os.path.abspath(__file__)
3842     path = os.path.dirname(path)
3843     os.chdir(path)
3845 def download_vk_xml(filename):
3846     url = "https://raw.githubusercontent.com/KhronosGroup/Vulkan-Docs/v{0}/xml/vk.xml".format(VK_XML_VERSION)
3847     if not os.path.isfile(filename):
3848         urllib.request.urlretrieve(url, filename)
3850 def main():
3851     parser = argparse.ArgumentParser()
3852     parser.add_argument("-v", "--verbose", action="count", default=0, help="increase output verbosity")
3853     parser.add_argument("-x", "--xml", default=None, type=str, help="path to specification XML file")
3855     args = parser.parse_args()
3856     if args.verbose == 0:
3857         LOGGER.setLevel(logging.WARNING)
3858     elif args.verbose == 1:
3859         LOGGER.setLevel(logging.INFO)
3860     else: # > 1
3861         LOGGER.setLevel(logging.DEBUG)
3863     set_working_directory()
3865     if args.xml:
3866         vk_xml = args.xml
3867     else:
3868         vk_xml = "vk-{0}.xml".format(VK_XML_VERSION)
3869         download_vk_xml(vk_xml)
3871     registry = VkRegistry(vk_xml)
3872     generator = VkGenerator(registry)
3874     with open(WINE_VULKAN_H, "w") as f:
3875         generator.generate_vulkan_h(f)
3877     with open(WINE_VULKAN_THUNKS_H, "w") as f:
3878         generator.generate_thunks_h(f, "wine_")
3880     with open(WINE_VULKAN_THUNKS_C, "w") as f:
3881         generator.generate_thunks_c(f)
3883     with open(WINE_VULKAN_LOADER_THUNKS_H, "w") as f:
3884         generator.generate_loader_thunks_h(f)
3886     with open(WINE_VULKAN_LOADER_THUNKS_C, "w") as f:
3887         generator.generate_loader_thunks_c(f)
3889     with open(WINE_VULKAN_JSON, "w") as f:
3890         generate_vulkan_json(f)
3892     with open(WINE_VULKAN_SPEC, "w") as f:
3893         generator.generate_vulkan_spec(f)
3895     with open(WINE_VULKAN_LOADER_SPEC, "w") as f:
3896         generator.generate_vulkan_loader_spec(f)
3898 if __name__ == "__main__":
3899     main()