winevulkan: Update to VK spec version 1.3.237.
[wine.git] / dlls / winevulkan / make_vulkan
blob7a883caceacb5e74885dec7c478dc6f1bb5a7077
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 sys
27 import urllib.request
28 import xml.etree.ElementTree as ET
29 from collections import OrderedDict
30 from collections.abc import Sequence
31 from enum import Enum
33 # This script generates code for a Wine Vulkan ICD driver from Vulkan's vk.xml.
34 # Generating the code is like 10x worse than OpenGL, which is mostly a calling
35 # convention passthrough.
37 # The script parses vk.xml and maps functions and types to helper objects. These
38 # helper objects simplify the xml parsing and map closely to the Vulkan types.
39 # The code generation utilizes the helper objects during code generation and
40 # most of the ugly work is carried out by these objects.
42 # Vulkan ICD challenges:
43 # - Vulkan ICD loader (vulkan-1.dll) relies on a section at the start of
44 #   'dispatchable handles' (e.g. VkDevice, VkInstance) for it to insert
45 #   its private data. It uses this area to stare its own dispatch tables
46 #   for loader internal use. This means any dispatchable objects need wrapping.
48 # - Vulkan structures have different alignment between win32 and 32-bit Linux.
49 #   This means structures with alignment differences need conversion logic.
50 #   Often structures are nested, so the parent structure may not need any
51 #   conversion, but some child may need some.
53 # vk.xml parsing challenges:
54 # - Contains type data for all platforms (generic Vulkan, Windows, Linux,..).
55 #   Parsing of extension information required to pull in types and functions
56 #   we really want to generate. Just tying all the data together is tricky.
58 # - Extensions can affect core types e.g. add new enum values, bitflags or
59 #   additional structure chaining through 'pNext' / 'sType'.
61 # - Arrays are used all over the place for parameters or for structure members.
62 #   Array length is often stored in a previous parameter or another structure
63 #   member and thus needs careful parsing.
65 LOGGER = logging.Logger("vulkan")
66 LOGGER.addHandler(logging.StreamHandler())
68 VK_XML_VERSION = "1.3.237"
69 WINE_VK_VERSION = (1, 3)
71 # Filenames to create.
72 WINE_VULKAN_H = "../../include/wine/vulkan.h"
73 WINE_VULKAN_DRIVER_H = "../../include/wine/vulkan_driver.h"
74 WINE_VULKAN_LOADER_SPEC = "../vulkan-1/vulkan-1.spec"
75 WINE_VULKAN_JSON = "winevulkan.json"
76 WINE_VULKAN_SPEC = "winevulkan.spec"
77 WINE_VULKAN_THUNKS_C = "vulkan_thunks.c"
78 WINE_VULKAN_THUNKS_H = "vulkan_thunks.h"
79 WINE_VULKAN_LOADER_THUNKS_C = "loader_thunks.c"
80 WINE_VULKAN_LOADER_THUNKS_H = "loader_thunks.h"
82 # Extension enum values start at a certain offset (EXT_BASE).
83 # Relative to the offset each extension has a block (EXT_BLOCK_SIZE)
84 # of values.
85 # Start for a given extension is:
86 # EXT_BASE + (extension_number-1) * EXT_BLOCK_SIZE
87 EXT_BASE = 1000000000
88 EXT_BLOCK_SIZE = 1000
90 UNSUPPORTED_EXTENSIONS = [
91     # Instance extensions
92     "VK_EXT_headless_surface", # Needs WSI work.
93     "VK_KHR_display", # Needs WSI work.
94     "VK_KHR_surface_protected_capabilities",
95     "VK_LUNARG_direct_driver_loading", # Implemented in the Vulkan loader
97     # Device extensions
98     "VK_AMD_display_native_hdr",
99     "VK_EXT_full_screen_exclusive",
100     "VK_EXT_hdr_metadata", # Needs WSI work.
101     "VK_GOOGLE_display_timing",
102     "VK_KHR_external_fence_win32",
103     "VK_KHR_external_semaphore_win32",
104     # Relates to external_semaphore and needs type conversions in bitflags.
105     "VK_KHR_shared_presentable_image", # Needs WSI work.
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_KHR_external_memory_win32",
135 # The Vulkan loader provides entry-points for core functionality and important
136 # extensions. Based on vulkan-1.def this amounts to WSI extensions on 1.0.51.
137 CORE_EXTENSIONS = [
138     "VK_KHR_display",
139     "VK_KHR_display_swapchain",
140     "VK_KHR_get_surface_capabilities2",
141     "VK_KHR_surface",
142     "VK_KHR_swapchain",
143     "VK_KHR_win32_surface",
146 # Some experimental extensions are used by shipping applications so their API is extremely unlikely
147 # to change in a backwards-incompatible way. Allow translation of those extensions with WineVulkan.
148 ALLOWED_X_EXTENSIONS = [
149     "VK_NVX_binary_import",
150     "VK_NVX_image_view_handle",
153 # Functions part of our winevulkan graphics driver interface.
154 # DRIVER_VERSION should be bumped on any change to driver interface
155 # in FUNCTION_OVERRIDES
156 DRIVER_VERSION = 11
158 class ThunkType(Enum):
159     NONE = 1
160     PUBLIC = 2
161     PRIVATE = 3
163 # Table of functions for which we have a special implementation.
164 # These are regular device / instance functions for which we need
165 # to do more work compared to a regular thunk or because they are
166 # part of the driver interface.
167 # - dispatch set whether we need a function pointer in the device
168 #   / instance dispatch table.
169 # - driver sets whether the API is part of the driver interface.
170 # - thunk sets whether to create a thunk in vulkan_thunks.c.
171 #   - NONE means there's a fully custom implementation.
172 #   - PUBLIC means the implementation is fully auto generated.
173 #   - PRIVATE thunks can be used in custom implementations for
174 #     struct conversion.
175 # - loader_thunk sets whether to create a thunk for unix funcs.
176 FUNCTION_OVERRIDES = {
177     # Global functions
178     "vkCreateInstance" : {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE, "extra_param" : "client_ptr"},
179     "vkEnumerateInstanceExtensionProperties" : {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE},
180     "vkEnumerateInstanceLayerProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.NONE},
181     "vkEnumerateInstanceVersion": {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE},
182     "vkGetInstanceProcAddr": {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.NONE},
184     # Instance functions
185     "vkCreateDevice" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE, "extra_param" : "client_ptr"},
186     "vkDestroyInstance" : {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE},
187     "vkEnumerateDeviceExtensionProperties" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
188     "vkEnumerateDeviceLayerProperties": {"dispatch": True, "driver": False, "thunk": ThunkType.NONE},
189     "vkEnumeratePhysicalDeviceGroups" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
190     "vkEnumeratePhysicalDevices" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
191     "vkGetPhysicalDeviceExternalBufferProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
192     "vkGetPhysicalDeviceExternalFenceProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
193     "vkGetPhysicalDeviceExternalSemaphoreProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
194     "vkGetPhysicalDeviceImageFormatProperties2" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE},
195     "vkGetPhysicalDeviceProperties2" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PUBLIC, "loader_thunk" : ThunkType.PRIVATE},
196     "vkGetPhysicalDeviceProperties2KHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PUBLIC, "loader_thunk" : ThunkType.PRIVATE},
198     # Device functions
199     "vkAllocateCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE},
200     "vkCreateCommandPool" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE, "extra_param" : "client_ptr"},
201     "vkDestroyCommandPool" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE},
202     "vkDestroyDevice" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE},
203     "vkFreeCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE},
204     "vkGetDeviceProcAddr" : {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.NONE},
205     "vkGetDeviceQueue" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
206     "vkGetDeviceQueue2" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
207     "vkAllocateMemory" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE},
208     "vkFreeMemory" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE},
209     "vkMapMemory" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE},
210     "vkUnmapMemory" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE},
211     "vkCreateBuffer" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE},
212     "vkCreateImage" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE},
214     # VK_KHR_surface
215     "vkDestroySurfaceKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.NONE},
216     "vkGetPhysicalDeviceSurfaceSupportKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
217     "vkGetPhysicalDeviceSurfaceCapabilitiesKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PRIVATE},
218     "vkGetPhysicalDeviceSurfaceFormatsKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
219     "vkGetPhysicalDeviceSurfacePresentModesKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
221     # VK_KHR_get_surface_capabilities2
222     "vkGetPhysicalDeviceSurfaceCapabilities2KHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PRIVATE},
223     "vkGetPhysicalDeviceSurfaceFormats2KHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
225     # VK_KHR_win32_surface
226     "vkCreateWin32SurfaceKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.NONE},
227     "vkGetPhysicalDeviceWin32PresentationSupportKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
229     # VK_KHR_swapchain
230     "vkCreateSwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
231     "vkDestroySwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
232     "vkGetSwapchainImagesKHR": {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
233     "vkQueuePresentKHR": {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
235     # VK_KHR_external_fence_capabilities
236     "vkGetPhysicalDeviceExternalFencePropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
238     # VK_KHR_external_memory_capabilities
239     "vkGetPhysicalDeviceExternalBufferPropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
240     "vkGetPhysicalDeviceImageFormatProperties2KHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE},
242     # VK_KHR_external_semaphore_capabilities
243     "vkGetPhysicalDeviceExternalSemaphorePropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
245     # VK_KHR_device_group_creation
246     "vkEnumeratePhysicalDeviceGroupsKHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
248     # VK_KHR_device_group
249     "vkGetDeviceGroupSurfacePresentModesKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
250     "vkGetPhysicalDevicePresentRectanglesKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
252     # VK_EXT_calibrated_timestamps
253     "vkGetPhysicalDeviceCalibrateableTimeDomainsEXT" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
254     "vkGetCalibratedTimestampsEXT" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
256     # VK_EXT_debug_utils
257     "vkCreateDebugUtilsMessengerEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
258     "vkDestroyDebugUtilsMessengerEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
260     # VK_EXT_debug_report
261     "vkCreateDebugReportCallbackEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
262     "vkDestroyDebugReportCallbackEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
265 STRUCT_CHAIN_CONVERSIONS = {
266     # Ignore to not confuse host loader.
267     "VkDeviceCreateInfo": ["VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO"],
268     "VkInstanceCreateInfo": ["VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO"],
271 # Some struct members are conditionally ignored and callers are free to leave them uninitialized.
272 # We can't deduce that from XML, so we allow expressing it here.
273 MEMBER_LENGTH_EXPRESSIONS = {
274     "VkWriteDescriptorSet": {
275         "pImageInfo":
276             "{struct}descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER || " +
277             "{struct}descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER || " +
278             "{struct}descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE || " +
279             "{struct}descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE || " +
280             "{struct}descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT || " +
281             "{struct}descriptorType == VK_DESCRIPTOR_TYPE_SAMPLE_WEIGHT_IMAGE_QCOM || " +
282             "{struct}descriptorType == VK_DESCRIPTOR_TYPE_BLOCK_MATCH_IMAGE_QCOM ? {len} : 0",
283         "pBufferInfo":
284             "{struct}descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER || " +
285             "{struct}descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER || " +
286             "{struct}descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC || " +
287             "{struct}descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC ? {len} : 0",
288     }
291 class Direction(Enum):
292     """ Parameter direction: input, output, input_output. """
293     INPUT = 1
294     OUTPUT = 2
297 class VkBaseType(object):
298     def __init__(self, name, _type, alias=None, requires=None):
299         """ Vulkan base type class.
301         VkBaseType is mostly used by Vulkan to define its own
302         base types like VkFlags through typedef out of e.g. uint32_t.
304         Args:
305             name (:obj:'str'): Name of the base type.
306             _type (:obj:'str'): Underlying type
307             alias (bool): type is an alias or not.
308             requires (:obj:'str', optional): Other types required.
309                 Often bitmask values pull in a *FlagBits type.
310         """
311         self.name = name
312         self.type = _type
313         self.alias = alias
314         self.requires = requires
315         self.required = False
317     def definition(self):
318         # Definition is similar for alias or non-alias as type
319         # is already set to alias.
320         if not self.type is None:
321             return "typedef {0} {1};\n".format(self.type, self.name)
322         else:
323             return "struct {0};\n".format(self.name)
325     def is_alias(self):
326         return bool(self.alias)
329 class VkConstant(object):
330     def __init__(self, name, value):
331         self.name = name
332         self.value = value
334     def definition(self):
335         text = "#define {0} {1}\n".format(self.name, self.value)
336         return text
339 class VkDefine(object):
340     def __init__(self, name, value):
341         self.name = name
342         self.value = value
344     @staticmethod
345     def from_xml(define):
346         name_elem = define.find("name")
348         if name_elem is None:
349             # <type category="define" name="some_name">some_value</type>
350             name = define.attrib.get("name")
352             # We override behavior of VK_USE_64_BIT_PTR_DEFINES as the default non-dispatchable handle
353             # definition various between 64-bit (uses pointers) and 32-bit (uses uint64_t).
354             # This complicates TRACEs in the thunks, so just use uint64_t.
355             if name == "VK_USE_64_BIT_PTR_DEFINES":
356                 value = "#define VK_USE_64_BIT_PTR_DEFINES 0"
357             else:
358                 value = define.text
359             return VkDefine(name, value)
361         # With a name element the structure is like:
362         # <type category="define"><name>some_name</name>some_value</type>
363         name = name_elem.text
365         # Perform minimal parsing for Vulkan constants, which we don't need, but are referenced
366         # elsewhere in vk.xml.
367         # - VK_API_VERSION is a messy, deprecated constant and we don't want generate code for it.
368         # - AHardwareBuffer/ANativeWindow are forward declarations for Android types, which leaked
369         #   into the define region.
370         if name in ["VK_API_VERSION", "AHardwareBuffer", "ANativeWindow", "CAMetalLayer"]:
371             return VkDefine(name, None)
373         # The body of the define is basically unstructured C code. It is not meant for easy parsing.
374         # Some lines contain deprecated values or comments, which we try to filter out.
375         value = ""
376         for line in define.text.splitlines():
377             # Skip comments or deprecated values.
378             if "//" in line:
379                 continue
380             value += line
382         for child in define:
383             value += child.text
384             if child.tail is not None:
385                 # Split comments for VK_API_VERSION_1_0 / VK_API_VERSION_1_1
386                 if "//" in child.tail:
387                     value += child.tail.split("//")[0]
388                 else:
389                     value += child.tail
391         return VkDefine(name, value.rstrip(' '))
393     def definition(self):
394         if self.value is None:
395             return ""
397         # Nothing to do as the value was already put in the right form during parsing.
398         return "{0}\n".format(self.value)
401 class VkEnum(object):
402     def __init__(self, name, bitwidth, alias=None):
403         if not bitwidth in [32, 64]:
404             LOGGER.error("unknown bitwidth {0} for {1}".format(bitwidth, name))
405         self.name = name
406         self.bitwidth = bitwidth
407         self.values = [] if alias == None else alias.values
408         self.required = False
409         self.alias = alias
410         self.aliased_by = []
412     @staticmethod
413     def from_alias(enum, alias):
414         name = enum.attrib.get("name")
415         aliasee = VkEnum(name, alias.bitwidth, alias=alias)
417         alias.add_aliased_by(aliasee)
418         return aliasee
420     @staticmethod
421     def from_xml(enum):
422         name = enum.attrib.get("name")
423         bitwidth = int(enum.attrib.get("bitwidth", "32"))
424         result = VkEnum(name, bitwidth)
426         for v in enum.findall("enum"):
427             value_name = v.attrib.get("name")
428             # Value is either a value or a bitpos, only one can exist.
429             value = v.attrib.get("value")
430             alias_name = v.attrib.get("alias")
431             if alias_name:
432                 result.create_alias(value_name, alias_name)
433             elif value:
434                 result.create_value(value_name, value)
435             else:
436                 # bitmask
437                 result.create_bitpos(value_name, int(v.attrib.get("bitpos")))
439         if bitwidth == 32:
440             # vulkan.h contains a *_MAX_ENUM value set to 32-bit at the time of writing,
441             # which is to prepare for extensions as they can add values and hence affect
442             # the size definition.
443             max_name = re.sub(r'([0-9a-z_])([A-Z0-9])',r'\1_\2', name).upper() + "_MAX_ENUM"
444             result.create_value(max_name, "0x7fffffff")
446         return result
448     def create_alias(self, name, alias_name):
449         """ Create an aliased value for this enum """
450         self.add(VkEnumValue(name, self.bitwidth, alias=alias_name))
452     def create_value(self, name, value):
453         """ Create a new value for this enum """
454         # Some values are in hex form. We want to preserve the hex representation
455         # at least when we convert back to a string. Internally we want to use int.
456         hex = "0x" in value
457         self.add(VkEnumValue(name, self.bitwidth, value=int(value, 0), hex=hex))
459     def create_bitpos(self, name, pos):
460         """ Create a new bitmask value for this enum """
461         self.add(VkEnumValue(name, self.bitwidth, value=(1 << pos), hex=True))
463     def add(self, value):
464         """ Add a value to enum. """
466         # Extensions can add new enum values. When an extension is promoted to Core
467         # the registry defines the value twice once for old extension and once for
468         # new Core features. Add the duplicate if it's explicitly marked as an
469         # alias, otherwise ignore it.
470         for v in self.values:
471             if not value.is_alias() and v.value == value.value:
472                 LOGGER.debug("Adding duplicate enum value {0} to {1}".format(v, self.name))
473                 return
474         # Avoid adding duplicate aliases multiple times
475         if not any(x.name == value.name for x in self.values):
476             self.values.append(value)
478     def fixup_64bit_aliases(self):
479         """ Replace 64bit aliases with literal values """
480         # Older GCC versions need a literal to initialize a static const uint64_t
481         # which is what we use for 64bit bitmasks.
482         if self.bitwidth != 64:
483             return
484         for value in self.values:
485             if not value.is_alias():
486                 continue
487             alias = next(x for x in self.values if x.name == value.alias)
488             value.hex = alias.hex
489             value.value = alias.value
491     def definition(self):
492         if self.is_alias():
493             return ""
495         default_value = 0x7ffffffe if self.bitwidth == 32 else 0xfffffffffffffffe
497         # Print values sorted, values can have been added in a random order.
498         values = sorted(self.values, key=lambda value: value.value if value.value is not None else default_value)
500         if self.bitwidth == 32:
501             text = "typedef enum {0}\n{{\n".format(self.name)
502             for value in values:
503                 text += "    {0},\n".format(value.definition())
504             text += "}} {0};\n".format(self.name)
505         elif self.bitwidth == 64:
506             text = "typedef VkFlags64 {0};\n\n".format(self.name)
507             for value in values:
508                 text += "static const {0} {1};\n".format(self.name, value.definition())
510         for aliasee in self.aliased_by:
511             text += "typedef {0} {1};\n".format(self.name, aliasee.name)
513         text += "\n"
514         return text
516     def is_alias(self):
517         return bool(self.alias)
519     def add_aliased_by(self, aliasee):
520         self.aliased_by.append(aliasee)
523 class VkEnumValue(object):
524     def __init__(self, name, bitwidth, value=None, hex=False, alias=None):
525         self.name = name
526         self.bitwidth = bitwidth
527         self.value = value
528         self.hex = hex
529         self.alias = alias
531     def __repr__(self):
532         postfix = "ull" if self.bitwidth == 64 else ""
533         if self.is_alias() and self.value == None:
534             return "{0}={1}".format(self.name, self.alias)
535         return "{0}={1}{2}".format(self.name, self.value, postfix)
537     def definition(self):
538         """ Convert to text definition e.g. VK_FOO = 1 """
539         postfix = "ull" if self.bitwidth == 64 else ""
540         if self.is_alias() and self.value == None:
541             return "{0} = {1}".format(self.name, self.alias)
543         # Hex is commonly used for FlagBits and sometimes within
544         # a non-FlagBits enum for a bitmask value as well.
545         if self.hex:
546             return "{0} = 0x{1:08x}{2}".format(self.name, self.value, postfix)
547         else:
548             return "{0} = {1}{2}".format(self.name, self.value, postfix)
550     def is_alias(self):
551         return self.alias is not None
554 class VkFunction(object):
555     def __init__(self, _type=None, name=None, params=[], alias=None):
556         self.extensions = set()
557         self.name = name
558         self.type = _type
559         self.params = params
560         self.alias = alias
562         # For some functions we need some extra metadata from FUNCTION_OVERRIDES.
563         func_info = FUNCTION_OVERRIDES.get(self.name, None)
564         self.dispatch = func_info["dispatch"] if func_info else True
565         self.driver = func_info["driver"] if func_info else False
566         self.thunk_type = func_info["thunk"] if func_info else ThunkType.PUBLIC
567         self.loader_thunk_type = func_info["loader_thunk"] if func_info and "loader_thunk" in func_info else ThunkType.PUBLIC
568         self.extra_param = func_info["extra_param"] if func_info and "extra_param" in func_info else None
570         # Required is set while parsing which APIs and types are required
571         # and is used by the code generation.
572         self.required = True if func_info else False
574     @staticmethod
575     def from_alias(command, alias):
576         """ Create VkFunction from an alias command.
578         Args:
579             command: xml data for command
580             alias (VkFunction): function to use as a base for types / parameters.
582         Returns:
583             VkFunction
584         """
585         func_name = command.attrib.get("name")
586         func_type = alias.type
587         params = alias.params
589         return VkFunction(_type=func_type, name=func_name, params=params, alias=alias)
591     @staticmethod
592     def from_xml(command, types):
593         proto = command.find("proto")
594         func_name = proto.find("name").text
595         func_type = proto.find("type").text
597         params = []
598         for param in command.findall("param"):
599             vk_param = VkParam.from_xml(param, types, params)
600             params.append(vk_param)
602         return VkFunction(_type=func_type, name=func_name, params=params)
604     def get_conversions(self):
605         """ Get a list of conversion functions required for this function if any.
606         Parameters which are structures may require conversion between win32
607         and the host platform. This function returns a list of conversions
608         required.
609         """
611         conversions = []
612         for param in self.params:
613             conversions.extend(param.get_conversions(self.thunk_type == ThunkType.PUBLIC))
614         return conversions
616     def is_alias(self):
617         return bool(self.alias)
619     def is_core_func(self):
620         """ Returns whether the function is a Vulkan core function.
621         Core functions are APIs defined by the Vulkan spec to be part of the
622         Core API as well as several KHR WSI extensions.
623         """
625         if not self.extensions:
626             return True
628         return any(ext in self.extensions for ext in CORE_EXTENSIONS)
630     def is_device_func(self):
631         # If none of the other, it must be a device function
632         return not self.is_global_func() and not self.is_instance_func() and not self.is_phys_dev_func()
634     def is_driver_func(self):
635         """ Returns if function is part of Wine driver interface. """
636         return self.driver
638     def is_global_func(self):
639         # Treat vkGetInstanceProcAddr as a global function as it
640         # can operate with NULL for vkInstance.
641         if self.name == "vkGetInstanceProcAddr":
642             return True
643         # Global functions are not passed a dispatchable object.
644         elif self.params[0].is_dispatchable():
645             return False
646         return True
648     def is_instance_func(self):
649         # Instance functions are passed VkInstance.
650         if self.params[0].type == "VkInstance":
651             return True
652         return False
654     def is_phys_dev_func(self):
655         # Physical device functions are passed VkPhysicalDevice.
656         if self.params[0].type == "VkPhysicalDevice":
657             return True
658         return False
660     def is_required(self):
661         return self.required
663     def returns_longlong(self):
664         return self.type in ["uint64_t", "VkDeviceAddress"]
666     def needs_dispatch(self):
667         return self.dispatch
669     def needs_private_thunk(self):
670         return self.needs_exposing() and self.loader_thunk_type != ThunkType.NONE and \
671             self.thunk_type != ThunkType.PUBLIC
673     def needs_exposing(self):
674         # The function needs exposed if at-least one extension isn't both UNSUPPORTED and UNEXPOSED
675         return self.is_required() and (not self.extensions or not self.extensions.issubset(UNEXPOSED_EXTENSIONS))
677     def pfn(self, prefix="p", call_conv=None):
678         """ Create function pointer. """
680         if call_conv:
681             pfn = "{0} ({1} *{2}_{3})(".format(self.type, call_conv, prefix, self.name)
682         else:
683             pfn = "{0} (*{1}_{2})(".format(self.type, prefix, self.name)
685         for i, param in enumerate(self.params):
686             if param.const:
687                 pfn += param.const + " "
689             pfn += param.type
691             if param.is_pointer():
692                 pfn += " " + param.pointer
694             if param.array_len is not None:
695                 pfn += "[{0}]".format(param.array_len)
697             if i < len(self.params) - 1:
698                 pfn += ", "
699         pfn += ")"
700         return pfn
702     def prototype(self, call_conv=None, prefix=None, postfix=None, is_thunk=False):
703         """ Generate prototype for given function.
705         Args:
706             call_conv (str, optional): calling convention e.g. WINAPI
707             prefix (str, optional): prefix to append prior to function name e.g. vkFoo -> wine_vkFoo
708             postfix (str, optional): text to append after function name but prior to semicolon e.g. DECLSPEC_HIDDEN
709         """
711         proto = "{0}".format(self.type)
713         if call_conv is not None:
714             proto += " {0}".format(call_conv)
716         if prefix is not None:
717             proto += " {0}{1}(".format(prefix, self.name)
718         else:
719             proto += " {0}(".format(self.name)
721         # Add all the parameters.
722         proto += ", ".join([p.definition() for p in self.params])
724         if is_thunk and self.extra_param:
725             proto += ", void *" + self.extra_param
727         if postfix is not None:
728             proto += ") {0}".format(postfix)
729         else:
730             proto += ")"
732         return proto
734     def loader_body(self):
735         body = "    struct {0}_params params;\n".format(self.name)
736         body += "    NTSTATUS status;\n"
737         for p in self.params:
738             body += "    params.{0} = {0};\n".format(p.name)
740         # Call the Unix function.
741         body += "    status = UNIX_CALL({0}, &params);\n".format(self.name)
742         body += "    assert(!status);\n"
743         if self.type != "void":
744             body += "    return params.result;\n"
745         return body
747     def body(self, conv, unwrap, params_prefix=""):
748         body = ""
749         needs_alloc = False
751         # Declare any tmp parameters for conversion.
752         for p in self.params:
753             if p.needs_variable(conv, unwrap):
754                 if p.is_dynamic_array():
755                     body += "    {2}{0} *{1}_host;\n".format(
756                         p.type, p.name, "const " if p.is_const() else "")
757                 elif p.optional:
758                     body += "    {0} *{1}_host = NULL;\n".format(p.type, p.name)
759                     needs_alloc = True
760                 else:
761                     body += "    {0} {1}_host;\n".format(p.type, p.name)
762             if p.needs_alloc(conv, unwrap):
763                 needs_alloc = True
765         if needs_alloc:
766             body += "    struct conversion_context ctx;\n"
767         body += "\n"
768         body += "    {0}\n".format(self.trace(params_prefix=params_prefix, conv=conv))
770         if self.params[0].optional and self.params[0].is_handle():
771             if self.type != "void":
772                 LOGGER.warning("return type {0} with optional handle not supported".format(self.type))
773             body += "    if (!{0}{1})\n".format(params_prefix, self.params[0].name)
774             body += "        return STATUS_SUCCESS;\n\n"
776         if needs_alloc:
777             body += "    init_conversion_context(&ctx);\n"
779         # Call any win_to_host conversion calls.
780         unwrap = self.thunk_type == ThunkType.PUBLIC
781         for p in self.params:
782             if p.needs_conversion(conv, unwrap, Direction.INPUT):
783                 body += p.copy(Direction.INPUT, conv, unwrap, prefix=params_prefix)
784             elif p.is_dynamic_array() and p.needs_conversion(conv, unwrap, Direction.OUTPUT):
785                 body += "    {0}_host = ({2}{0} && {1}) ? conversion_context_alloc(&ctx, sizeof(*{0}_host) * {1}) : NULL;\n".format(
786                     p.name, p.get_dyn_array_len(params_prefix, conv), params_prefix)
788         # Build list of parameters containing converted and non-converted parameters.
789         # The param itself knows if conversion is needed and applies it when we set conv=True.
790         params = ", ".join([p.variable(conv=conv, unwrap=unwrap, params_prefix=params_prefix) for p in self.params])
791         if self.extra_param:
792             if conv:
793                 params += ", UlongToPtr({0}{1})".format(params_prefix, self.extra_param)
794             else:
795                 params += ", {0}{1}".format(params_prefix, self.extra_param)
797         if unwrap or self.thunk_type == ThunkType.PUBLIC:
798             func_prefix = "{0}.p_".format(self.params[0].dispatch_table(params_prefix, conv))
799         else:
800             func_prefix = "wine_"
802         # Call the native Vulkan function.
803         if self.type == "void":
804             body += "    {0}{1}({2});\n".format(func_prefix, self.name, params)
805         else:
806             body += "    {0}result = {1}{2}({3});\n".format(params_prefix, func_prefix, self.name, params)
808         # Call any host_to_win conversion calls.
809         for p in self.params:
810             if p.needs_conversion(conv, unwrap, Direction.OUTPUT):
811                 body += p.copy(Direction.OUTPUT, conv, unwrap, prefix=params_prefix)
813         if needs_alloc:
814             body += "    free_conversion_context(&ctx);\n"
816         # Finally return the result.
817         body += "    return STATUS_SUCCESS;\n"
819         return body
821     def spec(self, prefix=None, symbol=None):
822         """ Generate spec file entry for this function.
824         Args
825             prefix (str, optional): prefix to prepend to entry point name.
826             symbol (str, optional): allows overriding the name of the function implementing the entry point.
827         """
829         spec = ""
830         params = " ".join([p.spec() for p in self.params])
831         if prefix is not None:
832             spec += "@ stdcall -private {0}{1}({2})".format(prefix, self.name, params)
833         else:
834             spec += "@ stdcall {0}({1})".format(self.name, params)
836         if symbol is not None:
837             spec += " " + symbol
839         spec += "\n"
840         return spec
842     def stub(self, call_conv=None, prefix=None):
843         stub = self.prototype(call_conv=call_conv, prefix=prefix)
844         stub += "\n{\n"
845         stub += "    {0}".format(self.trace(message="stub: ", trace_func="FIXME"))
847         if self.type == "VkResult":
848             stub += "    return VK_ERROR_OUT_OF_HOST_MEMORY;\n"
849         elif self.type == "VkBool32":
850             stub += "    return VK_FALSE;\n"
851         elif self.type == "PFN_vkVoidFunction":
852             stub += "    return NULL;\n"
854         stub += "}\n\n"
855         return stub
857     def thunk(self, prefix=None, conv=False):
858         thunk = ""
859         if not conv:
860             thunk += "#ifdef _WIN64\n"
861         thunk += "static NTSTATUS {0}{1}(void *args)\n".format(prefix, self.name)
862         thunk += "{\n"
863         if conv:
864             thunk += "    struct\n"
865             thunk += "    {\n"
866             for p in self.params:
867                 thunk += "        {0};\n".format(p.definition(conv=True, is_member=True))
868             if self.extra_param:
869                 thunk += "        PTR32 {0};\n".format(self.extra_param)
870             if self.type != "void":
871                 thunk += "        {0} result;\n".format(self.type)
872             thunk += "    } *params = args;\n"
873         else:
874             thunk += "    struct {0}_params *params = args;\n".format(self.name)
875         thunk += self.body(conv=conv, unwrap=self.thunk_type == ThunkType.PUBLIC, params_prefix="params->")
876         thunk += "}\n"
877         if not conv:
878             thunk += "#endif /* _WIN64 */\n"
879         thunk += "\n"
880         return thunk
882     def loader_thunk(self, prefix=None):
883         thunk = self.prototype(call_conv="WINAPI", prefix=prefix)
884         thunk += "\n{\n"
885         thunk += self.loader_body()
886         thunk += "}\n\n"
887         return thunk
889     def trace(self, message=None, trace_func=None, params_prefix="", conv=False):
890         """ Create a trace string including all parameters.
892         Args:
893             message (str, optional): text to print at start of trace message e.g. 'stub: '
894             trace_func (str, optional): used to override trace function e.g. FIXME, printf, etcetera.
895         """
896         if trace_func is not None:
897             trace = "{0}(\"".format(trace_func)
898         else:
899             trace = "TRACE(\""
901         if message is not None:
902             trace += message
904         # First loop is for all the format strings.
905         trace += ", ".join([p.format_string(conv) for p in self.params])
906         trace += "\\n\""
908         # Second loop for parameter names and optional conversions.
909         for param in self.params:
910             if param.format_conv is not None:
911                 trace += ", " + param.format_conv.format("{0}{1}".format(params_prefix, param.name))
912             else:
913                 trace += ", {0}{1}".format(params_prefix, param.name)
914         trace += ");\n"
916         return trace
919 class VkFunctionPointer(object):
920     def __init__(self, _type, name, members, forward_decls):
921         self.name = name
922         self.members = members
923         self.type = _type
924         self.required = False
925         self.forward_decls = forward_decls
927     @staticmethod
928     def from_xml(funcpointer):
929         members = []
930         begin = None
932         for t in funcpointer.findall("type"):
933             # General form:
934             # <type>void</type>*       pUserData,
935             # Parsing of the tail (anything past </type>) is tricky since there
936             # can be other data on the next line like: const <type>int</type>..
938             const = True if begin and "const" in begin else False
939             _type = t.text
940             lines = t.tail.split(",\n")
941             if lines[0][0] == "*":
942                 pointer = "*"
943                 name = lines[0][1:].strip()
944             else:
945                 pointer = None
946                 name = lines[0].strip()
948             # Filter out ); if it is contained.
949             name = name.partition(");")[0]
951             # If tail encompasses multiple lines, assign the second line to begin
952             # for the next line.
953             try:
954                 begin = lines[1].strip()
955             except IndexError:
956                 begin = None
958             members.append(VkMember(const=const, _type=_type, pointer=pointer, name=name))
960         _type = funcpointer.text
961         name = funcpointer.find("name").text
962         if "requires" in funcpointer.attrib:
963             forward_decls = funcpointer.attrib.get("requires").split(",")
964         else:
965             forward_decls = []
966         return VkFunctionPointer(_type, name, members, forward_decls)
968     def definition(self):
969         text = ""
970         # forward declare required structs
971         for decl in self.forward_decls:
972             text += "typedef struct {0} {0};\n".format(decl)
974         text += "{0} {1})(\n".format(self.type, self.name)
976         first = True
977         if len(self.members) > 0:
978             for m in self.members:
979                 if first:
980                     text += "    " + m.definition()
981                     first = False
982                 else:
983                     text += ",\n    " + m.definition()
984         else:
985             # Just make the compiler happy by adding a void parameter.
986             text += "void"
987         text += ");\n"
988         return text
990     def is_alias(self):
991         return False
993 class VkHandle(object):
994     def __init__(self, name, _type, parent, alias=None):
995         self.name = name
996         self.type = _type
997         self.parent = parent
998         self.alias = alias
999         self.required = False
1000         self.object_type = None
1002     @staticmethod
1003     def from_alias(handle, alias):
1004         name = handle.attrib.get("name")
1005         return VkHandle(name, alias.type, alias.parent, alias=alias)
1007     @staticmethod
1008     def from_xml(handle):
1009         name = handle.find("name").text
1010         _type = handle.find("type").text
1011         parent = handle.attrib.get("parent") # Most objects have a parent e.g. VkQueue has VkDevice.
1012         return VkHandle(name, _type, parent)
1014     def dispatch_table(self, param):
1015         if not self.is_dispatchable():
1016             return None
1018         if self.parent is None:
1019             # Should only happen for VkInstance
1020             return "wine_instance_from_handle({0})->funcs".format(param)
1021         elif self.name == "VkCommandBuffer":
1022             return "wine_cmd_buffer_from_handle({0})->device->funcs".format(param)
1023         elif self.name == "VkDevice":
1024             return "wine_device_from_handle({0})->funcs".format(param)
1025         elif self.name == "VkPhysicalDevice":
1026             return "wine_phys_dev_from_handle({0})->instance->funcs".format(param)
1027         elif self.name == "VkQueue":
1028             return "wine_queue_from_handle({0})->device->funcs".format(param)
1029         elif self.parent in ["VkInstance", "VkPhysicalDevice"]:
1030             return "{0}->instance->funcs".format(param)
1031         elif self.parent in ["VkDevice", "VkCommandPool"]:
1032             return "{0}->device->funcs".format(param)
1033         else:
1034             LOGGER.error("Unhandled dispatchable parent: {0}".format(self.parent))
1036     def definition(self):
1037         """ Generates handle definition e.g. VK_DEFINE_HANDLE(vkInstance) """
1039         # Legacy types are typedef'ed to the new type if they are aliases.
1040         if self.is_alias():
1041             return "typedef {0} {1};\n".format(self.alias.name, self.name)
1043         return "{0}({1})\n".format(self.type, self.name)
1045     def is_alias(self):
1046         return self.alias is not None
1048     def is_dispatchable(self):
1049         """ Some handles like VkInstance, VkDevice are dispatchable objects,
1050         which means they contain a dispatch table of function pointers.
1051         """
1052         return self.type == "VK_DEFINE_HANDLE"
1054     def is_required(self):
1055         return self.required
1057     def native_handle(self, name):
1058         """ Provide access to the native handle of a wrapped object. """
1060         if self.name == "VkCommandBuffer":
1061             return "wine_cmd_buffer_from_handle({0})->command_buffer".format(name)
1062         if self.name == "VkCommandPool":
1063             return "wine_cmd_pool_from_handle({0})->command_pool".format(name)
1064         if self.name == "VkDebugUtilsMessengerEXT":
1065             return "wine_debug_utils_messenger_from_handle({0})->debug_messenger".format(name)
1066         if self.name == "VkDebugReportCallbackEXT":
1067             return "wine_debug_report_callback_from_handle({0})->debug_callback".format(name)
1068         if self.name == "VkDevice":
1069             return "wine_device_from_handle({0})->device".format(name)
1070         if self.name == "VkInstance":
1071             return "wine_instance_from_handle({0})->instance".format(name)
1072         if self.name == "VkDeviceMemory":
1073             return "wine_device_memory_from_handle({0})->memory".format(name)
1074         if self.name == "VkPhysicalDevice":
1075             return "wine_phys_dev_from_handle({0})->phys_dev".format(name)
1076         if self.name == "VkQueue":
1077             return "wine_queue_from_handle({0})->queue".format(name)
1078         if self.name == "VkSurfaceKHR":
1079             return "wine_surface_from_handle({0})->surface".format(name)
1080         if self.is_dispatchable():
1081             LOGGER.error("Unhandled native handle for: {0}".format(self.name))
1082         return None
1084     def driver_handle(self, name):
1085         """ Provide access to the handle that should be passed to the wine driver """
1087         if self.name == "VkSurfaceKHR":
1088             return "wine_surface_from_handle({0})->driver_surface".format(name)
1090         return self.native_handle(name)
1092     def is_wrapped(self):
1093         return self.native_handle("test") is not None
1095     def needs_unwrapping(self):
1096         return self.is_wrapped()
1098 class VkVariable(object):
1099     def __init__(self, const=False, type_info=None, type=None, name=None, pointer=None, array_len=None,
1100                  dyn_array_len=None, object_type=None, optional=False, returnedonly=False, parent=None,
1101                  selection=None, selector=None):
1102         self.const = const
1103         self.type_info = type_info
1104         self.type = type
1105         self.name = name
1106         self.parent = parent
1107         self.object_type = object_type
1108         self.optional = optional
1109         self.returnedonly = returnedonly
1110         self.selection = selection
1111         self.selector = selector
1113         self.pointer = pointer
1114         self.array_len = array_len
1115         self.dyn_array_len = dyn_array_len
1116         self.pointer_array = False
1117         if isinstance(dyn_array_len, str):
1118             i = dyn_array_len.find(",")
1119             if i != -1:
1120                 self.dyn_array_len = dyn_array_len[0:i]
1121                 self.pointer_array = True
1123         if type_info:
1124             self.set_type_info(type_info)
1126     def __eq__(self, other):
1127         """ Compare member based on name against a string. """
1128         return self.name == other
1130     def set_type_info(self, type_info):
1131         """ Helper function to set type information from the type registry.
1132         This is needed, because not all type data is available at time of
1133         parsing.
1134         """
1135         self.type_info = type_info
1136         self.handle = type_info["data"] if type_info["category"] == "handle" else None
1137         self.struct = type_info["data"] if type_info["category"] == "struct" or type_info["category"] == "union" else None
1139     def get_dyn_array_len(self, prefix, conv):
1140         if isinstance(self.dyn_array_len, int):
1141             return self.dyn_array_len
1143         len_str = self.dyn_array_len
1144         parent = self.parent
1145         len = prefix
1147         # check if lenght is a member of another struct (for example pAllocateInfo->commandBufferCount)
1148         i = len_str.find("->")
1149         if i != -1:
1150             var = parent[parent.index(len_str[0:i])]
1151             len_str = len_str[i+2:]
1152             len = "({0})->".format(var.value(len, conv))
1153             parent = var.struct
1155         if len_str in parent:
1156             var = parent[parent.index(len_str)]
1157             len = var.value(len, conv);
1158             if var.is_pointer():
1159                 len = "*" + len
1160         else:
1161             len += len_str
1163         if isinstance(self.parent, VkStruct) and self.parent.name in MEMBER_LENGTH_EXPRESSIONS:
1164             exprs = MEMBER_LENGTH_EXPRESSIONS[self.parent.name]
1165             if self.name in exprs:
1166                 len = exprs[self.name].format(struct=prefix, len=len)
1168         return len
1170     def is_const(self):
1171         return self.const
1173     def is_pointer(self):
1174         return self.pointer is not None
1176     def is_pointer_size(self):
1177         if self.type in ["size_t", "HWND", "HINSTANCE"]:
1178             return True
1179         if self.is_handle() and self.handle.is_dispatchable():
1180             return True
1181         return False
1183     def is_handle(self):
1184         return self.handle is not None
1186     def is_struct(self):
1187         return self.type_info["category"] == "struct"
1189     def is_union(self):
1190         return self.type_info["category"] == "union"
1192     def is_bitmask(self):
1193         return self.type_info["category"] == "bitmask"
1195     def is_enum(self):
1196         return self.type_info["category"] == "enum"
1198     def is_dynamic_array(self):
1199         """ Returns if the member is an array element.
1200         Vulkan uses this for dynamically sized arrays for which
1201         there is a 'count' parameter.
1202         """
1203         return self.dyn_array_len is not None
1205     def is_static_array(self):
1206         """ Returns if the member is an array.
1207         Vulkan uses this often for fixed size arrays in which the
1208         length is part of the member.
1209         """
1210         return self.array_len is not None
1212     def is_generic_handle(self):
1213         """ Returns True if the member is a unit64_t containing
1214         a handle with a separate object type
1215         """
1216         return self.object_type != None and self.type == "uint64_t"
1218     def needs_alignment(self):
1219         """ Check if this member needs alignment for 64-bit data.
1220         Various structures need alignment on 64-bit variables due
1221         to compiler differences on 32-bit between Win32 and Linux.
1222         """
1224         if self.is_pointer():
1225             return False
1226         elif self.type == "size_t":
1227             return False
1228         elif self.type in ["uint64_t", "VkDeviceAddress", "VkDeviceSize"]:
1229             return True
1230         elif self.is_bitmask():
1231             return self.type_info["data"].type == "VkFlags64"
1232         elif self.is_enum():
1233             return self.type_info["data"].bitwidth == 64
1234         elif self.is_struct() or self.is_union():
1235             return self.type_info["data"].needs_alignment()
1236         elif self.is_handle():
1237             # Dispatchable handles are pointers to objects, while
1238             # non-dispatchable are uint64_t and hence need alignment.
1239             return not self.handle.is_dispatchable()
1240         return False
1242     def needs_unwrapping(self):
1243         """ Returns if variable needs unwrapping of handle. """
1245         if self.is_struct():
1246             return self.struct.needs_unwrapping()
1248         if self.is_handle():
1249             return self.handle.needs_unwrapping()
1251         if self.is_generic_handle():
1252             return True
1254         return False
1256     def needs_alloc(self, conv, unwrap):
1257         """ Returns True if conversion needs allocation """
1258         if self.is_dynamic_array():
1259             return self.needs_conversion(conv, unwrap, Direction.INPUT, False) \
1260                 or self.needs_conversion(conv, unwrap, Direction.OUTPUT, False)
1262         return (self.is_struct() or (self.is_union() and self.selector)) and self.struct.needs_alloc(conv, unwrap)
1264     def needs_win32_type(self):
1265         return (self.is_struct() or (self.is_union() and self.selector)) and self.struct.needs_win32_type()
1267     def get_conversions(self, unwrap, parent_const=False):
1268         """ Get a list of conversions required for this parameter if any.
1269         Parameters which are structures may require conversion between win32
1270         and the host platform. This function returns a list of conversions
1271         required.
1272         """
1274         conversions = []
1276         # Collect any member conversions first, so we can guarantee
1277         # those functions will be defined prior to usage by the
1278         # 'parent' param requiring conversion.
1279         if self.is_struct() or (self.is_union() and self.selector):
1280             struct = self.struct
1281             is_const = self.is_const() if self.is_pointer() else parent_const
1283             conversions.extend(struct.get_conversions(unwrap, is_const))
1285             for conv in [False, True]:
1286                 if struct.needs_conversion(conv, unwrap, Direction.INPUT, is_const):
1287                     conversions.append(StructConversionFunction(struct, Direction.INPUT, conv, unwrap, is_const))
1288                 if struct.needs_conversion(conv, unwrap, Direction.OUTPUT, is_const):
1289                     conversions.append(StructConversionFunction(struct, Direction.OUTPUT, conv, unwrap, is_const))
1291         if self.is_static_array() or self.is_dynamic_array():
1292             for conv in [False, True]:
1293                 if self.needs_conversion(conv, unwrap, Direction.INPUT, parent_const):
1294                     conversions.append(ArrayConversionFunction(self, Direction.INPUT, conv, unwrap))
1295                 if self.needs_conversion(conv, unwrap, Direction.OUTPUT, parent_const):
1296                     conversions.append(ArrayConversionFunction(self, Direction.OUTPUT, conv, unwrap))
1298         return conversions
1300     def needs_ptr32_type(self):
1301         """ Check if variable needs to use PTR32 type. """
1303         return self.is_pointer() or self.is_pointer_size() or self.is_static_array()
1305     def value(self, prefix, conv):
1306         """ Returns code accessing member value, casting 32-bit pointers when needed. """
1308         if not conv or not self.needs_ptr32_type() or (not self.is_pointer() and self.type == "size_t"):
1309             return prefix + self.name
1311         cast_type = ""
1312         if self.const:
1313             cast_type += "const "
1315         if self.pointer_array or ((self.is_pointer() or self.is_static_array()) and self.is_pointer_size()):
1316             cast_type += "PTR32 *"
1317         else:
1318             cast_type += self.type
1319             if self.needs_win32_type():
1320                 cast_type += "32"
1322             if self.is_pointer():
1323                 cast_type += " {0}".format(self.pointer)
1324             elif self.is_static_array():
1325                 cast_type += " *"
1327         return "({0})UlongToPtr({1}{2})".format(cast_type, prefix, self.name)
1330 class VkMember(VkVariable):
1331     def __init__(self, const=False, struct_fwd_decl=False,_type=None, pointer=None, name=None, array_len=None,
1332                  dyn_array_len=None, optional=False, values=None, object_type=None, bit_width=None,
1333                  returnedonly=False, parent=None, selection=None, selector=None):
1334         VkVariable.__init__(self, const=const, type=_type, name=name, pointer=pointer, array_len=array_len,
1335                             dyn_array_len=dyn_array_len, object_type=object_type, optional=optional,
1336                             returnedonly=returnedonly, parent=parent, selection=selection, selector=selector)
1337         self.struct_fwd_decl = struct_fwd_decl
1338         self.values = values
1339         self.bit_width = bit_width
1341     def __repr__(self):
1342         return "{0} {1} {2} {3} {4} {5} {6}".format(self.const, self.struct_fwd_decl, self.type, self.pointer,
1343                 self.name, self.array_len, self.dyn_array_len)
1345     @staticmethod
1346     def from_xml(member, returnedonly, parent):
1347         """ Helper function for parsing a member tag within a struct or union. """
1349         name_elem = member.find("name")
1350         type_elem = member.find("type")
1352         const = False
1353         struct_fwd_decl = False
1354         member_type = None
1355         pointer = None
1356         array_len = None
1357         bit_width = None
1359         values = member.get("values")
1361         if member.text:
1362             if "const" in member.text:
1363                 const = True
1365             # Some members contain forward declarations:
1366             # - VkBaseInstructure has a member "const struct VkBaseInStructure *pNext"
1367             # - VkWaylandSurfaceCreateInfoKHR has a member "struct wl_display *display"
1368             if "struct" in member.text:
1369                 struct_fwd_decl = True
1371         if type_elem is not None:
1372             member_type = type_elem.text
1373             if type_elem.tail is not None:
1374                 pointer = type_elem.tail.strip() if type_elem.tail.strip() != "" else None
1376         # Name of other member within, which stores the number of
1377         # elements pointed to be by this member.
1378         dyn_array_len = member.get("len")
1380         # Some members are optional, which is important for conversion code e.g. not dereference NULL pointer.
1381         optional = True if member.get("optional") else False
1383         # Usually we need to allocate memory for dynamic arrays. We need to do the same in a few other cases
1384         # like for VkCommandBufferBeginInfo.pInheritanceInfo. Just threat such cases as dynamic arrays of
1385         # size 1 to simplify code generation.
1386         if dyn_array_len is None and pointer is not None:
1387             dyn_array_len = 1
1389         # Some members are arrays, attempt to parse these. Formats include:
1390         # <member><type>char</type><name>extensionName</name>[<enum>VK_MAX_EXTENSION_NAME_SIZE</enum>]</member>
1391         # <member><type>uint32_t</type><name>foo</name>[4]</member>
1392         if name_elem.tail and name_elem.tail[0] == '[':
1393             LOGGER.debug("Found array type")
1394             enum_elem = member.find("enum")
1395             if enum_elem is not None:
1396                 array_len = enum_elem.text
1397             else:
1398                 # Remove brackets around length
1399                 array_len = name_elem.tail.strip("[]")
1401         object_type = member.get("objecttype", None)
1403         # Some members are bit field values:
1404         # <member><type>uint32_t</type> <name>mask</name>:8</member>
1405         if name_elem.tail and name_elem.tail[0] == ':':
1406             LOGGER.debug("Found bit field")
1407             bit_width = int(name_elem.tail[1:])
1409         selection = member.get("selection").split(',') if member.get("selection") else None
1410         selector = member.get("selector", None)
1412         return VkMember(const=const, struct_fwd_decl=struct_fwd_decl, _type=member_type, pointer=pointer,
1413                         name=name_elem.text, array_len=array_len, dyn_array_len=dyn_array_len, optional=optional,
1414                         values=values, object_type=object_type, bit_width=bit_width, returnedonly=returnedonly,
1415                         parent=parent, selection=selection, selector=selector)
1417     def copy(self, input, output, direction, conv, unwrap):
1418         """ Helper method for use by conversion logic to generate a C-code statement to copy this member.
1419             - `conv` indicates whether the statement is in a struct alignment conversion path. """
1421         win_type = "win32" if conv else "win64"
1422         if self.needs_conversion(conv, unwrap, direction, False):
1423             if self.is_dynamic_array():
1424                 # Array length is either a variable name (string) or an int.
1425                 count = self.get_dyn_array_len(input, conv)
1426                 host_part = "host" if unwrap else "unwrapped_host"
1427                 pointer_part = "pointer_" if self.pointer_array else ""
1428                 if direction == Direction.OUTPUT:
1429                     return "convert_{2}_{7}array_{6}_to_{5}({3}{1}, {0}, {4});\n".format(
1430                         self.value(output, conv), self.name, self.type, input, count, win_type,
1431                         host_part, pointer_part)
1432                 else:
1433                     return "{0}{1} = convert_{2}_{7}array_{5}_to_{6}(ctx, {3}, {4});\n".format(
1434                         output, self.name, self.type, self.value(input, conv), count, win_type,
1435                         host_part, pointer_part)
1436             elif self.is_static_array():
1437                 count = self.array_len
1438                 if direction == Direction.OUTPUT:
1439                     # Needed by VkMemoryHeap.memoryHeaps
1440                     host_part = "host" if unwrap else "unwrapped_host"
1441                     return "convert_{0}_array_{6}_to_{5}({2}{1}, {3}{1}, {4});\n".format(
1442                         self.type, self.name, input, output, count, win_type, host_part)
1443                 else:
1444                     # Nothing needed this yet.
1445                     LOGGER.warn("TODO: implement copying of static array for {0}.{1}".format(self.type, self.name))
1446             elif self.is_handle() and self.needs_unwrapping():
1447                 handle = self.type_info["data"]
1448                 if direction == Direction.OUTPUT:
1449                     LOGGER.err("OUTPUT parameter {0}.{1} cannot be unwrapped".format(self.type, self.name))
1450                 elif self.optional:
1451                     return "{0}{1} = {2} ? {3} : 0;\n".format(output, self.name,
1452                         self.value(input, conv), handle.driver_handle(self.value(input, conv)))
1453                 else:
1454                     return "{0}{1} = {2};\n".format(output, self.name, handle.driver_handle(self.value(input, conv)))
1455             elif self.is_generic_handle():
1456                 if direction == Direction.OUTPUT:
1457                     LOGGER.err("OUTPUT parameter {0}.{1} cannot be unwrapped".format(self.type, self.name))
1458                 else:
1459                     return "{0}{1} = wine_vk_unwrap_handle({2}{3}, {2}{1});\n".format(output, self.name, input, self.object_type)
1460             else:
1461                 selector_part = ", {0}{1}".format(input, self.selector) if self.selector else ""
1462                 if direction == Direction.OUTPUT:
1463                     return "convert_{0}_host_to_{4}(&{2}{1}, &{3}{1}{5});\n".format(self.type, self.name, input, output, win_type, selector_part)
1464                 else:
1465                     ctx_param = "ctx, " if self.needs_alloc(conv, unwrap) else ""
1466                     host_part = "host" if unwrap else "unwrapped_host"
1467                     return "convert_{0}_{4}_to_{6}({5}&{2}{1}, &{3}{1}{7});\n".format(self.type, self.name, input, output, win_type, ctx_param, host_part, selector_part)
1468         elif self.is_static_array():
1469             bytes_count = "{0} * sizeof({1})".format(self.array_len, self.type)
1470             return "memcpy({0}{1}, {2}{1}, {3});\n".format(output, self.name, input, bytes_count)
1471         elif direction == Direction.INPUT:
1472             return "{0}{1} = {2};\n".format(output, self.name, self.value(input, conv))
1473         elif conv and direction == Direction.OUTPUT and self.is_pointer():
1474             return "{0}{1} = PtrToUlong({2}{1});\n".format(output, self.name, input)
1475         else:
1476             return "{0}{1} = {2}{1};\n".format(output, self.name, input)
1478     def definition(self, align=False, conv=False):
1479         """ Generate prototype for given function.
1481         Args:
1482             align (bool, optional): Enable alignment if a type needs it. This adds WINE_VK_ALIGN(8) to a member.
1483             conv (bool, optional): Enable conversion if a type needs it. This appends '_host' to the name.
1484         """
1486         if conv and (self.is_pointer() or self.is_pointer_size()):
1487             text = "PTR32 " + self.name
1488             if self.is_static_array():
1489                 text += "[{0}]".format(self.array_len)
1490             return text
1492         text = ""
1493         if self.is_const():
1494             text += "const "
1496         if self.is_struct_forward_declaration():
1497             text += "struct "
1499         text += self.type
1500         if conv and self.needs_win32_type():
1501             text += "32"
1503         if self.is_pointer():
1504             text += " {0}{1}".format(self.pointer, self.name)
1505         else:
1506             if align and self.needs_alignment():
1507                 if conv:
1508                     text += " DECLSPEC_ALIGN(8) " + self.name
1509                 else:
1510                     text += " WINE_VK_ALIGN(8) " + self.name
1511             else:
1512                 text += " " + self.name
1514         if self.is_static_array():
1515             text += "[{0}]".format(self.array_len)
1517         if self.is_bit_field():
1518             text += ":{}".format(self.bit_width)
1520         return text
1522     def is_struct_forward_declaration(self):
1523         return self.struct_fwd_decl
1525     def is_bit_field(self):
1526         return self.bit_width is not None
1528     def needs_conversion(self, conv, unwrap, direction, struct_const):
1529         """ Check if member needs conversion. """
1531         # we can't convert unions if we don't have a selector
1532         if self.is_union() and not self.selector:
1533             return False
1535         is_const = self.is_const() if self.is_pointer() else struct_const
1537         # const members don't needs output conversion unless they are structs with non-const pointers
1538         if direction == Direction.OUTPUT and is_const and not self.is_struct():
1539             return False
1541         if direction == Direction.INPUT:
1542             # returnedonly members don't needs input conversions
1543             if not self.is_pointer() and self.returnedonly:
1544                 return False
1545             # pointer arrays always need input conversion
1546             if conv and self.is_dynamic_array() and self.pointer_array:
1547                 return True
1549         if self.is_handle():
1550             if unwrap and self.handle.is_wrapped():
1551                 return True
1552             if conv and self.handle.is_dispatchable():
1553                 return True
1554         elif self.is_generic_handle():
1555             if unwrap:
1556                 return True
1557         elif self.is_struct() or self.is_union():
1558             if self.struct.needs_conversion(conv, unwrap, direction, is_const):
1559                 return True
1561         # if pointer member needs output conversion, it also needs input conversion
1562         # to allocate the pointer
1563         if direction == Direction.INPUT and self.is_pointer() and \
1564            self.needs_conversion(conv, unwrap, Direction.OUTPUT, struct_const):
1565             return True
1567         return False
1569 class VkParam(VkVariable):
1570     """ Helper class which describes a parameter to a function call. """
1572     def __init__(self, type_info, const=None, pointer=None, name=None, parent=None, array_len=None,
1573                  dyn_array_len=None, object_type=None, optional=False):
1574         VkVariable.__init__(self, const=const, type_info=type_info, type=type_info["name"], name=name,
1575                             pointer=pointer, array_len=array_len, dyn_array_len=dyn_array_len,
1576                             object_type=object_type, optional=optional, parent=parent)
1578         self._set_format_string()
1580     def __repr__(self):
1581         return "{0} {1} {2} {3} {4} {5}".format(self.const, self.type, self.pointer, self.name, self.array_len, self.dyn_array_len)
1583     @staticmethod
1584     def from_xml(param, types, parent):
1585         """ Helper function to create VkParam from xml. """
1587         # Parameter parsing is slightly tricky. All the data is contained within
1588         # a param tag, but some data is within subtags while others are text
1589         # before or after the type tag.
1590         # Common structure:
1591         # <param>const <type>char</type>* <name>pLayerName</name></param>
1593         name_elem = param.find("name")
1594         array_len = None
1595         name = name_elem.text
1596         # Tail contains array length e.g. for blendConstants param of vkSetBlendConstants
1597         if name_elem.tail is not None:
1598             array_len = name_elem.tail.strip("[]")
1600         # Name of other parameter in function prototype, which stores the number of
1601         # elements pointed to be by this parameter.
1602         dyn_array_len = param.get("len", None)
1604         const = param.text.strip() if param.text else None
1605         type_elem = param.find("type")
1606         pointer = type_elem.tail.strip() if type_elem.tail.strip() != "" else None
1608         attr = param.get("optional")
1609         optional = attr and attr.startswith("true")
1611         # Some uint64_t are actually handles with a separate type param
1612         object_type = param.get("objecttype", None)
1614         # Since we have parsed all types before hand, this should not happen.
1615         type_info = types.get(type_elem.text, None)
1616         if type_info is None:
1617             LOGGER.err("type info not found for: {0}".format(type_elem.text))
1619         return VkParam(type_info, const=const, pointer=pointer, name=name, array_len=array_len,
1620                        dyn_array_len=dyn_array_len, object_type=object_type, optional=optional,
1621                        parent=parent)
1623     def _set_format_string(self):
1624         """ Internal helper function to be used by constructor to set format string. """
1626         # Determine a format string used by code generation for traces.
1627         # 64-bit types need a conversion function.
1628         self.format_conv = None
1629         if self.is_static_array() or self.is_pointer():
1630             self.format_str = "%p"
1631         else:
1632             if self.type_info["category"] in ["bitmask"]:
1633                 # Since 1.2.170 bitmasks can be 32 or 64-bit, check the basetype.
1634                 if self.type_info["data"].type == "VkFlags64":
1635                     self.format_str = "0x%s"
1636                     self.format_conv = "wine_dbgstr_longlong({0})"
1637                 else:
1638                     self.format_str = "%#x"
1639             elif self.type_info["category"] in ["enum"]:
1640                 self.format_str = "%#x"
1641             elif self.is_handle():
1642                 # We use uint64_t for non-dispatchable handles as opposed to pointers
1643                 # for dispatchable handles.
1644                 if self.handle.is_dispatchable():
1645                     self.format_str = "%p"
1646                 else:
1647                     self.format_str = "0x%s"
1648                     self.format_conv = "wine_dbgstr_longlong({0})"
1649             elif self.type == "float":
1650                 self.format_str = "%f"
1651             elif self.type == "int":
1652                 self.format_str = "%d"
1653             elif self.type == "int32_t":
1654                 self.format_str = "%d"
1655             elif self.type == "size_t":
1656                 self.format_str = "0x%s"
1657                 self.format_conv = "wine_dbgstr_longlong({0})"
1658             elif self.type in ["uint16_t", "uint32_t", "VkBool32"]:
1659                 self.format_str = "%u"
1660             elif self.type in ["uint64_t", "VkDeviceAddress", "VkDeviceSize"]:
1661                 self.format_str = "0x%s"
1662                 self.format_conv = "wine_dbgstr_longlong({0})"
1663             elif self.type == "HANDLE":
1664                 self.format_str = "%p"
1665             elif self.type in ["VisualID", "xcb_visualid_t", "RROutput", "zx_handle_t"]:
1666                 # Don't care about specific types for non-Windows platforms.
1667                 self.format_str = ""
1668             else:
1669                 LOGGER.warn("Unhandled type: {0}".format(self.type_info))
1671     def copy(self, direction, conv, unwrap, prefix=""):
1672         win_type = "win32" if conv else "win64"
1673         wrap_part = "" if unwrap or not self.needs_unwrapping() else "unwrapped_"
1674         if direction == Direction.INPUT:
1675             ctx_param = "&ctx, " if self.needs_alloc(conv, unwrap) else ""
1676             if self.is_dynamic_array():
1677                 return "    {0}_host = convert_{2}_array_{4}_to_{6}host({5}{1}, {3});\n".format(
1678                     self.name, self.value(prefix, conv), self.type, self.get_dyn_array_len(prefix, conv),
1679                     win_type, ctx_param, wrap_part)
1680             elif self.optional:
1681                 ret  = "    if ({0}{1})\n".format(prefix, self.name)
1682                 ret += "    {\n"
1683                 ret += "        {0}_host = conversion_context_alloc(&ctx, sizeof(*{0}_host));\n".format(self.name)
1684                 ret += "        convert_{0}_{3}_to_{5}host({4}{1}, {2}_host);\n".format(
1685                     self.type, self.value(prefix, conv), self.name, win_type, ctx_param, wrap_part)
1686                 ret += "    }\n"
1687                 return ret
1688             elif self.is_struct():
1689                 return "    convert_{0}_{3}_to_{5}host({4}{1}, &{2}_host);\n".format(
1690                     self.type, self.value(prefix, conv), self.name, win_type, ctx_param, wrap_part)
1691             elif self.is_pointer_size() and self.type != "size_t":
1692                 return "    {0}_host = UlongToPtr(*{1});\n".format(self.name, self.value(prefix, conv))
1693             else:
1694                 return "    {0}_host = *{1};\n".format(self.name, self.value(prefix, conv))
1695         else:
1696             if self.is_dynamic_array():
1697                 return "    convert_{0}_array_{1}host_to_{2}({3}_host, {4}, {5});\n".format(
1698                     self.type, wrap_part, win_type, self.name, self.value(prefix, conv),
1699                     self.get_dyn_array_len(prefix, conv))
1700             elif self.is_struct():
1701                 ref_part = "" if self.optional else "&"
1702                 return "    convert_{0}_host_to_{3}({4}{2}_host, {1});\n".format(
1703                     self.type, self.value(prefix, conv), self.name, win_type, ref_part)
1704             elif self.is_pointer_size() and self.type != "size_t":
1705                 return "    *{0} = PtrToUlong({1}_host);\n".format(self.value(prefix, conv), self.name)
1706             else:
1707                 return "    *{0} = {1}_host;\n".format(self.value(prefix, conv), self.name)
1709     def definition(self, postfix=None, is_member=False, conv=False):
1710         """ Return prototype for the parameter. E.g. 'const char *foo' """
1712         if is_member and conv and self.needs_ptr32_type():
1713             return "PTR32 {0}".format(self.name)
1715         proto = ""
1716         if self.const:
1717             proto += self.const + " "
1719         proto += self.type
1720         name = self.name
1721         if conv and self.needs_win32_type():
1722             proto += "32"
1724         if is_member and self.needs_alignment():
1725             proto += " DECLSPEC_ALIGN(8)"
1727         if self.is_pointer():
1728             proto += " {0}{1}".format(self.pointer, name)
1729         elif is_member and self.is_static_array():
1730             proto += " *" + name
1731         else:
1732             proto += " " + name
1734         # Allows appending something to the variable name useful for
1735         # win32 to host conversion.
1736         if postfix is not None:
1737             proto += postfix
1739         if not is_member and self.is_static_array():
1740             proto += "[{0}]".format(self.array_len)
1742         return proto
1744     def dispatch_table(self, params_prefix, conv):
1745         """ Return functions dispatch table pointer for dispatchable objects. """
1747         if not self.is_dispatchable():
1748             return None
1750         return self.handle.dispatch_table(self.value(params_prefix, conv))
1752     def format_string(self, conv):
1753         if conv and self.needs_ptr32_type() and (self.type != "size_t" or self.is_pointer()):
1754             return "%#x"
1755         return self.format_str
1757     def is_dispatchable(self):
1758         if not self.is_handle():
1759             return False
1761         return self.handle.is_dispatchable()
1763     def needs_conversion(self, conv, unwrap, direction, parent_const=False):
1764         """ Check if param needs conversion. """
1766         if self.is_struct():
1767             return self.struct.needs_conversion(conv, unwrap, direction, self.is_const())
1769         if self.is_handle():
1770             # non-pointer handles are handled inline in thunks
1771             if not self.is_dynamic_array() and not self.is_static_array():
1772                 return conv and self.is_pointer() and self.handle.is_dispatchable()
1774             # vkAllocateCommandBuffers is a special case, we use it in our private thunk as an input param
1775             param_direction = (Direction.INPUT if self.is_const() else Direction.OUTPUT)
1776             if self.name == "pCommandBuffers":
1777                 param_direction = Direction.INPUT
1778             if direction != param_direction:
1779                 return False
1781             if unwrap and self.handle.is_wrapped():
1782                 return True
1783             if conv and self.handle.is_dispatchable():
1784                 return True
1785         elif self.is_pointer() and self.is_pointer_size():
1786             return conv
1788         return False
1790     def needs_variable(self, conv, unwrap):
1791         if self.needs_conversion(conv, unwrap, Direction.INPUT):
1792             return True
1793         if self.needs_conversion(conv, unwrap, Direction.OUTPUT):
1794             return True
1795         return False
1797     def spec(self):
1798         """ Generate spec file entry for this parameter. """
1800         if self.is_pointer() and self.type == "char":
1801             return "str"
1802         if self.is_dispatchable() or self.is_pointer() or self.is_static_array():
1803             return "ptr"
1804         if self.type_info["category"] in ["bitmask"]:
1805             # Since 1.2.170 bitmasks can be 32 or 64-bit, check the basetype.
1806             if self.type_info["data"].type == "VkFlags64":
1807                 return "int64"
1808             else:
1809                 return "long"
1810         if self.type_info["category"] in ["enum"]:
1811             return "long"
1812         if self.is_handle() and not self.is_dispatchable():
1813             return "int64"
1814         if self.type == "float":
1815             return "float"
1816         if self.type in ["int", "int32_t", "size_t", "uint16_t", "uint32_t", "VkBool32"]:
1817             return "long"
1818         if self.type in ["uint64_t", "VkDeviceSize"]:
1819             return "int64"
1821         LOGGER.error("Unhandled spec conversion for type: {0}".format(self.type))
1823     def variable(self, conv, unwrap, params_prefix=""):
1824         """ Returns 'glue' code during generation of a function call on how to access the variable.
1825         This function handles various scenarios such as 'unwrapping' if dispatchable objects and
1826         renaming of parameters in case of win32 -> host conversion.
1828         Args:
1829             conv (bool, optional): Enable conversion if the param needs it. This appends '_host' to the name.
1830         """
1832         # Hack until we enable allocation callbacks from ICD to application. These are a joy
1833         # to enable one day, because of calling convention conversion.
1834         if unwrap and "VkAllocationCallbacks" in self.type:
1835             LOGGER.debug("TODO: setting NULL VkAllocationCallbacks for {0}".format(self.name))
1836             return "NULL"
1838         if self.needs_variable(conv, unwrap):
1839             if self.is_dynamic_array() or self.optional:
1840                 return "{0}_host".format(self.name)
1841             else:
1842                 return "&{0}_host".format(self.name)
1844         p = self.value(params_prefix, conv)
1846         if unwrap:
1847             unwrap_handle = None
1848             if self.object_type != None and self.type == "uint64_t":
1849                 unwrap_handle = "wine_vk_unwrap_handle({0}{1}, {0}{2})".format(
1850                     params_prefix, self.object_type, self.name)
1852             elif self.is_handle():
1853                 # We need to pass the native handle to the native Vulkan calls and
1854                 # the wine driver's handle to calls which are wrapped by the driver.
1855                 unwrap_handle = self.handle.driver_handle(p)
1856             if unwrap_handle:
1857                 if self.optional:
1858                     unwrap_handle = "{0}{1} ? {2} : 0".format(params_prefix, self.name, unwrap_handle)
1859                 return unwrap_handle
1861         return p
1864 class VkStruct(Sequence):
1865     """ Class which represents the type union and struct. """
1867     def __init__(self, name, members, returnedonly, structextends, alias=None, union=False):
1868         self.name = name
1869         self.members = members
1870         self.returnedonly = returnedonly
1871         self.structextends = structextends
1872         self.required = False
1873         self.alias = alias
1874         self.union = union
1875         self.type_info = None # To be set later.
1876         self.struct_extensions = []
1877         self.aliased_by = []
1879     def __getitem__(self, i):
1880         return self.members[i]
1882     def __len__(self):
1883         return len(self.members)
1885     @staticmethod
1886     def from_alias(struct, alias):
1887         name = struct.attrib.get("name")
1888         aliasee = VkStruct(name, alias.members, alias.returnedonly, alias.structextends, alias=alias)
1890         alias.add_aliased_by(aliasee)
1891         return aliasee
1893     @staticmethod
1894     def from_xml(struct):
1895         # Unions and structs are the same parsing wise, but we need to
1896         # know which one we are dealing with later on for code generation.
1897         union = True if struct.attrib["category"] == "union" else False
1899         name = struct.attrib.get("name")
1901         # 'Output' structures for which data is filled in by the API are
1902         # marked as 'returnedonly'.
1903         returnedonly = True if struct.attrib.get("returnedonly") else False
1905         # Those structs seem to be broken in spec, they are specified as
1906         # returned only, but documented as input structs.
1907         if name in ["VkSubpassShadingPipelineCreateInfoHUAWEI",
1908                     "VkPipelineShaderStageRequiredSubgroupSizeCreateInfo"]:
1909             returnedonly = False
1911         # Those structs don't have returnedonly in spec, but they could (should?).
1912         if name in ["VkSurfaceCapabilitiesPresentBarrierNV",
1913                     "VkCooperativeMatrixPropertiesNV",
1914                     "VkPerformanceValueINTEL"]:
1915             returnedonly = True
1917         structextends = struct.attrib.get("structextends")
1918         structextends = structextends.split(",") if structextends else []
1920         s = VkStruct(name, [], returnedonly, structextends, union=union)
1921         for member in struct.findall("member"):
1922             vk_member = VkMember.from_xml(member, returnedonly, s)
1923             s.members.append(vk_member)
1925         return s
1927     @staticmethod
1928     def decouple_structs(structs):
1929         """ Helper function which decouples a list of structs.
1930         Structures often depend on other structures. To make the C compiler
1931         happy we need to define 'substructures' first. This function analyzes
1932         the list of structures and reorders them in such a way that they are
1933         decoupled.
1934         """
1936         tmp_structs = list(structs) # Don't modify the original structures.
1937         decoupled_structs = []
1939         while (len(tmp_structs) > 0):
1940             # Iterate over a copy because we want to modify the list inside the loop.
1941             for struct in list(tmp_structs):
1942                 dependends = False
1944                 if not struct.required:
1945                     tmp_structs.remove(struct)
1946                     continue
1948                 for m in struct:
1949                     if not (m.is_struct() or m.is_union()):
1950                         continue
1952                     # VkBaseInstructure and VkBaseOutStructure reference themselves.
1953                     if m.type == struct.name:
1954                         break
1956                     found = False
1957                     # Check if a struct we depend on has already been defined.
1958                     for s in decoupled_structs:
1959                         if s.name == m.type:
1960                             found = True
1961                             break
1963                     if not found:
1964                         # Check if the struct we depend on is even in the list of structs.
1965                         # If found now, it means we haven't met all dependencies before we
1966                         # can operate on the current struct.
1967                         # When generating 'host' structs we may not be able to find a struct
1968                         # as the list would only contain the structs requiring conversion.
1969                         for s in tmp_structs:
1970                             if s.name == m.type:
1971                                 dependends = True
1972                                 break
1974                 if dependends == False:
1975                     decoupled_structs.append(struct)
1976                     tmp_structs.remove(struct)
1978         return decoupled_structs
1980     def definition(self, align=False, conv=False):
1981         """ Convert structure to textual definition.
1983         Args:
1984             align (bool, optional): enable alignment to 64-bit for win32 struct compatibility.
1985             conv (bool, optional): enable struct conversion if the struct needs it.
1986             postfix (str, optional): text to append to end of struct name, useful for struct renaming.
1987         """
1989         if self.is_alias():
1990             return ""
1992         suffix = "32" if conv else ""
1993         if self.union:
1994             text = "typedef union {0}".format(self.name)
1995         else:
1996             text = "typedef struct {0}".format(self.name)
1997         text += suffix
1999         text += "\n{\n"
2001         for m in self:
2002             if align and m.needs_alignment():
2003                 text += "    {0};\n".format(m.definition(align=align, conv=conv))
2004             else:
2005                 text += "    {0};\n".format(m.definition(conv=conv))
2007         text += "}} {0}{1};\n".format(self.name, suffix)
2009         for aliasee in self.aliased_by:
2010             text += "typedef {0}{2} {1}{2};\n".format(self.name, aliasee.name, suffix)
2012         return text
2014     def is_alias(self):
2015         return bool(self.alias)
2017     def add_aliased_by(self, aliasee):
2018         self.aliased_by.append(aliasee)
2020     def needs_alignment(self):
2021         """ Check if structure needs alignment for 64-bit data.
2022         Various structures need alignment on 64-bit variables due
2023         to compiler differences on 32-bit between Win32 and Linux.
2024         """
2026         for m in self.members:
2027             if self.name == m.type:
2028                 continue
2029             if m.needs_alignment():
2030                 return True
2031         return False
2033     def needs_unwrapping(self):
2034         """ Returns if struct members need unwrapping of handle. """
2036         for m in self.members:
2037             if self.name == m.type:
2038                 continue
2039             if m.needs_unwrapping():
2040                 return True
2041         return False
2043     def needs_extensions_conversion(self, conv, direction):
2044         """ Check if struct contains extensions chain that needs to be converted """
2046         if direction == Direction.INPUT and self.name in STRUCT_CHAIN_CONVERSIONS:
2047             return True
2049         if not "pNext" in self:
2050             return False
2051         is_const = self.members[self.members.index("pNext")].is_const()
2052         # VkOpticalFlowSessionCreateInfoNV is missing const in its pNext pointer
2053         if self.name in ["VkOpticalFlowSessionCreateInfoNV",
2054                          "VkDescriptorBufferBindingInfoEXT"]:
2055             is_const = True
2056         needs_output_copy = False
2058         for e in self.struct_extensions:
2059             if not e.required:
2060                 continue
2061             if e.needs_conversion(conv, True, direction, is_const, check_extensions=False):
2062                 return True
2063             if direction == Direction.INPUT:
2064                 # we need input conversion of structs containing struct chain even if it's returnedonly,
2065                 # so that we have a chance to allocate buffers
2066                 if e.needs_conversion(conv, True, Direction.OUTPUT, is_const, check_extensions=False):
2067                     return True
2069         return False
2071     def needs_conversion(self, conv, unwrap, direction, is_const, check_extensions=True):
2072         """ Check if struct needs conversion. """
2074         # VkAllocationCallbacks never needs conversion
2075         if self.name == "VkAllocationCallbacks":
2076             return False
2078         # pFixedRateFlags field is missing const, but it doesn't need output conversion
2079         if direction == Direction.OUTPUT and self.name == "VkImageCompressionControlEXT":
2080             return False
2082         needs_output_copy = False
2084         for m in self.members:
2085             if self.name == m.type:
2086                 continue
2088             if m.name == "pNext":
2089                 # pNext is a pointer, so it always needs conversion
2090                 if conv and direction == Direction.INPUT:
2091                     return True
2092                 # we need input conversion of structs containing struct chain even if it's returnedonly
2093                 if direction == Direction.INPUT and \
2094                    self.needs_conversion(conv, unwrap, Direction.OUTPUT, is_const):
2095                     return True
2096                 continue
2098             # for non-pointer members, check for returnedonly and const attributes
2099             if not m.is_pointer() or m.type == "void":
2100                 if direction == Direction.INPUT:
2101                     if self.returnedonly:
2102                         continue
2103                 else:
2104                     if is_const or m.is_const():
2105                         continue
2107             # check alignment and pointer-sized members for 32-bit conversions
2108             if conv and (direction == Direction.INPUT or not is_const):
2109                 if m.is_pointer() or m.is_pointer_size():
2110                     return True
2111                 # we don't check structs here, they will will be traversed by needs_conversion chain anyway
2112                 if not m.is_struct() and m.needs_alignment():
2113                     return True
2115             if m.needs_conversion(conv, unwrap, direction, is_const):
2116                 return True
2118             # pointers will be handled by needs_conversion, but if we have any other non-const
2119             # member, we may need to copy output
2120             if direction == Direction.OUTPUT and not m.is_pointer() and not is_const and not m.is_const():
2121                 needs_output_copy = True
2123         # if output needs any copy and we need input conversion, then we also need output conversion
2124         if needs_output_copy and self.needs_conversion(conv, unwrap, Direction.INPUT, check_extensions):
2125             return True
2127         return check_extensions and self.needs_extensions_conversion(conv, direction)
2129     def needs_alloc(self, conv, unwrap):
2130         """ Check if any struct member needs some memory allocation."""
2132         if self.needs_extensions_conversion(conv, Direction.INPUT):
2133             return True
2135         for m in self.members:
2136             if self.name == m.type:
2137                 continue
2138             if m.needs_alloc(conv, unwrap):
2139                 return True
2141         return False
2143     def needs_win32_type(self):
2144         # VkAllocationCallbacks never needs conversion
2145         if self.name == "VkAllocationCallbacks":
2146             return False
2148         for m in self.members:
2149             if self.name == m.type:
2150                 continue
2151             if m.is_pointer() or m.is_pointer_size():
2152                 return True
2153             if m.needs_alignment():
2154                 return True
2155             if (m.is_struct() or m.is_union()) and m.struct.needs_win32_type():
2156                 return True
2158     def set_type_info(self, types):
2159         """ Helper function to set type information from the type registry.
2160         This is needed, because not all type data is available at time of
2161         parsing.
2162         """
2163         for m in self.members:
2164             type_info = types[m.type]
2165             m.set_type_info(type_info)
2167     def get_conversions(self, unwrap, parent_const):
2168         conversions = []
2170         # Collect any conversion for any extension structs.
2171         for e in self.struct_extensions:
2172             if not e.required:
2173                 continue
2174             conversions.extend(e.get_conversions(True, parent_const))
2176         # Collect any conversion for any member structs.
2177         for m in self:
2178             if m.type == self.name:
2179                 continue
2180             conversions.extend(m.get_conversions(unwrap, parent_const))
2182         return conversions
2185 class StructConversionFunction(object):
2186     def __init__(self, struct, direction, conv, unwrap, const):
2187         self.direction = direction
2188         self.operand = struct
2189         self.type = struct.name
2190         self.conv = conv
2191         self.unwrap = unwrap or not self.operand.needs_unwrapping()
2192         self.const = const
2194         name = "convert_{0}_".format(self.type)
2195         win_type = "win32" if self.conv else "win64"
2196         host_part = "host" if self.unwrap else "unwrapped_host"
2197         if self.direction == Direction.INPUT:
2198             name += "{0}_to_{1}".format(win_type, host_part)
2199         else: # Direction.OUTPUT
2200             name += "{0}_to_{1}".format(host_part, win_type)
2201         self.name = name
2203     def __eq__(self, other):
2204         return self.name == other.name
2206     def member_needs_copy(self, struct, m):
2207         if self.direction == Direction.OUTPUT:
2208             if m.name in ["sType", "pNext"]:
2209                 return False
2210             if self.const and not m.is_pointer():
2211                 return False
2212             if m.is_const() and not m.needs_conversion(self.conv, self.unwrap, Direction.OUTPUT, self.const):
2213                 return False
2214         else:
2215             if m.name == "pNext":
2216                 return True
2217             if m.name != "sType" and struct.returnedonly and not m.needs_conversion(
2218                     self.conv, self.unwrap, Direction.INPUT, self.const):
2219                 return False
2220         return True
2222     def definition(self):
2223         """ Helper function for generating a struct conversion function. """
2225         # It doesn't make sense to generate conversion functions for non-struct variables
2226         # which aren't in arrays, as this should be handled by the copy() function
2227         if not isinstance(self.operand, VkStruct):
2228             return ""
2230         body = ""
2232         if not self.conv:
2233             body += "#ifdef _WIN64\n"
2235         needs_alloc = self.direction != Direction.OUTPUT and self.operand.needs_alloc(self.conv, self.unwrap)
2236         win_type = self.type
2237         if self.conv and self.operand.needs_win32_type():
2238             win_type += "32"
2239         if self.direction == Direction.OUTPUT and self.const:
2240             win_type = "const " + win_type
2242         if self.conv:
2243             body += "static inline void {0}(".format(self.name)
2245             if self.direction == Direction.OUTPUT:
2246                 params = ["const {0} *in".format(self.type), "{0} *out".format(win_type)]
2247             else:
2248                 params = ["const {0} *in".format(win_type), "{0} *out".format(self.type)]
2250             if self.operand.union:
2251                 params.append("VkFlags selector")
2253             # Generate parameter list
2254             if needs_alloc:
2255                 body += "struct conversion_context *ctx, "
2256             body += ", ".join(p for p in params)
2257             body += ")\n"
2259         else:
2260             body += "static inline void {0}(".format(self.name)
2262             params = ["const {0} *in".format(self.type), "{0} *out".format(self.type)]
2264             # Generate parameter list
2265             if needs_alloc:
2266                 body += "struct conversion_context *ctx, "
2267             body += ", ".join(p for p in params)
2268             body += ")\n"
2270         needs_extensions = self.operand.needs_extensions_conversion(self.conv, self.direction)
2272         body += "{\n"
2273         if needs_extensions:
2274             if self.direction == Direction.INPUT:
2275                 if self.conv:
2276                     body += "    const VkBaseInStructure32 *in_header;\n"
2277                 else:
2278                     body += "    const VkBaseInStructure *in_header;\n"
2279                 body += "    VkBaseOutStructure *out_header = (void *)out;\n\n"
2280             else:
2281                 body += "    const VkBaseInStructure *in_header;\n"
2282                 if self.conv:
2283                     body += "    VkBaseOutStructure32 *out_header = (void *)out;\n\n"
2284                 else:
2285                     body += "    VkBaseOutStructure *out_header = (void *)out;\n\n"
2287         body += "    if (!in) return;\n\n"
2289         for m in self.operand:
2290             if not self.member_needs_copy(self.operand, m):
2291                 continue
2292             if m.name == "pNext" and (needs_extensions or self.conv):
2293                 body += "    out->pNext = NULL;\n"
2294                 continue
2296             if m.selection:
2297                 body += "    if ("
2298                 body += " || ".join("selector == {}".format(s) for s in m.selection)
2299                 body += ")\n    "
2301             body += "    " + m.copy("in->", "out->", self.direction, self.conv, self.unwrap)
2303         if needs_extensions:
2304             if self.conv and self.direction == Direction.INPUT:
2305                 body += "\n    for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext))\n"
2306             else:
2307                 body += "\n    for (in_header = (void *)in->pNext; in_header; in_header = (void *)in_header->pNext)\n"
2308             body += "    {\n"
2309             body += "        switch (in_header->sType)\n"
2310             body += "        {\n"
2312             ident = "            "
2314             if self.direction == Direction.INPUT and self.type in STRUCT_CHAIN_CONVERSIONS:
2315                 for i in STRUCT_CHAIN_CONVERSIONS[self.type]:
2316                     body += "        case {0}:\n".format(i)
2317                 body += ident + "break;\n"
2319             for ext in self.operand.struct_extensions:
2320                 if not ext.required:
2321                     continue
2323                 if self.direction == Direction.OUTPUT and not any([self.member_needs_copy(ext, m) for m in ext]):
2324                     continue
2326                 stype = next(x for x in ext.members if x.name == "sType").values
2327                 win_type = ext.name + "32" if self.conv and ext.needs_win32_type() else ext.name
2328                 if self.direction == Direction.INPUT:
2329                     in_type = "const " + win_type
2330                     out_type = ext.name
2331                 else:
2332                     in_type = "const " + ext.name
2333                     out_type = win_type
2335                 body += "        case {0}:\n".format(stype)
2336                 body += "        {\n"
2337                 if self.direction == Direction.INPUT:
2338                     body += ident + "{0} *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));\n".format(out_type)
2339                 elif self.conv:
2340                     body += ident + "{0} *out_ext = find_next_struct32(out_header, {1});\n".format(out_type, stype)
2341                 else:
2342                     body += ident + "{0} *out_ext = find_next_struct(out_header, {1});\n".format(out_type, stype)
2344                 copy_body = ""
2346                 for m in ext:
2347                     if m.name == "sType":
2348                         copy_body += ident + "out_ext->sType = {0};\n".format(stype)
2349                         continue
2350                     if not self.member_needs_copy(ext, m):
2351                         continue
2352                     if m.name == "pNext":
2353                         copy_body += ident + "out_ext->pNext = NULL;\n"
2354                         continue
2356                     copy_body += ident + m.copy("in_ext->", "out_ext->", self.direction, self.conv, True)
2358                 # Generate the definition of "in_ext" if we need it
2359                 if "in_ext->" in copy_body:
2360                     body += ident + "{0} *in_ext = ({0} *)in_header;\n".format(in_type)
2361                 body += copy_body
2363                 if self.direction == Direction.INPUT:
2364                     body += ident + "out_header->pNext = (void *)out_ext;\n"
2365                 body += ident + "out_header = (void *)out_ext;\n"
2366                 body += ident + "break;\n"
2367                 body += "        }\n"
2369             body += "        default:\n"
2370             if self.direction == Direction.INPUT:
2371                 body += ident + "FIXME(\"Unhandled sType %u.\", in_header->sType);\n"
2372             body += "            break;\n"
2373             body += "        }\n"
2374             body += "    }\n"
2375         elif self.conv and self.direction == Direction.INPUT and "pNext" in self.operand:
2376             body += "    if (in->pNext)\n"
2377             body += "        FIXME(\"Unexpected pNext\\n\");\n"
2379         body += "}\n"
2380         if not self.conv:
2381             body += "#endif /* _WIN64 */\n"
2382         body += "\n"
2384         return body
2387 class ArrayConversionFunction(object):
2388     def __init__(self, array, direction, conv, unwrap):
2389         self.array = array
2390         self.direction = direction
2391         self.type = array.type
2392         self.conv = conv
2393         self.unwrap = unwrap or not array.needs_unwrapping()
2395         if array.is_static_array() and direction == Direction.INPUT:
2396             LOGGER.error("Static array input conversion is not supported")
2398         name = "convert_{0}_".format(array.type)
2399         if array.pointer_array:
2400             name += "pointer_"
2401         name += "array_"
2402         win_type = "win32" if self.conv else "win64"
2403         host_part = "host" if self.unwrap else "unwrapped_host"
2404         if self.direction == Direction.INPUT:
2405             name += "{0}_to_{1}".format(win_type, host_part)
2406         else: # Direction.OUTPUT
2407             name += "{0}_to_{1}".format(host_part, win_type)
2408         self.name = name
2410     def __eq__(self, other):
2411         return self.name == other.name
2413     def definition(self):
2414         """ Helper function for generating a conversion function for array operands. """
2416         body = ""
2418         if not self.conv:
2419             body += "#ifdef _WIN64\n"
2421         needs_alloc = self.direction != Direction.OUTPUT and self.array.needs_alloc(self.conv, self.unwrap)
2423         win_type = self.type
2424         if self.conv:
2425             if self.array.needs_win32_type():
2426                 win_type += "32"
2427             elif self.array.is_handle() and self.array.handle.is_dispatchable():
2428                 win_type = "PTR32"
2429         if self.direction == Direction.OUTPUT and self.array.is_const():
2430             win_type = "const " + win_type
2431         pointer_part = self.array.pointer if self.array.pointer else "*"
2433         if self.direction == Direction.OUTPUT:
2434             params = ["const {0} {1}in".format(self.type, pointer_part),
2435                       "{0} {1}out".format(win_type, pointer_part), "uint32_t count"]
2436             return_type = None
2437         elif self.conv and self.array.pointer_array:
2438             params = ["const PTR32 *in", "uint32_t count"]
2439             return_type = self.type
2440         else:
2441             params = ["const {0} {1}in".format(win_type, pointer_part), "uint32_t count"]
2442             return_type = self.type
2444         needs_copy = not self.array.is_struct() or self.direction != Direction.INPUT or \
2445             not self.array.struct.returnedonly or "pNext" in self.array.struct
2447         # Generate function prototype.
2448         if return_type:
2449             body += "static inline {0}{1} {2}{3}(".format(
2450                 "const " if self.array.is_const() else "", return_type, pointer_part, self.name)
2451         else:
2452             body += "static inline void {0}(".format(self.name)
2453         if needs_alloc:
2454             body += "struct conversion_context *ctx, "
2455         body += ", ".join(p for p in params)
2456         body += ")\n{\n"
2458         if return_type:
2459             body += "    {0} {1}out;\n".format(return_type, "**" if self.array.pointer_array else "*")
2460         if needs_copy:
2461             body += "    unsigned int i;\n\n"
2463         if return_type:
2464             body += "    if (!in || !count) return NULL;\n\n"
2465         else:
2466             body += "    if (!in) return;\n\n"
2468         if self.direction == Direction.INPUT:
2469             body += "    out = conversion_context_alloc(ctx, count * sizeof(*out));\n"
2471         if needs_copy:
2472             body += "    for (i = 0; i < count; i++)\n"
2473             body += "    {\n"
2475             if self.array.is_struct():
2476                 struct = self.array.struct
2477                 win_part = "win32" if self.conv else "win64"
2478                 host_part = "host" if self.unwrap else "unwrapped_host"
2479                 if self.direction == Direction.INPUT:
2480                     conv_suffix = "{0}_to_{1}".format(win_part, host_part)
2481                 else:
2482                     conv_suffix = "{0}_to_{1}".format(host_part, win_part)
2484                 ctx_part = ""
2485                 if self.direction == Direction.INPUT and struct.needs_alloc(self.conv, self.unwrap):
2486                     ctx_part = "ctx, "
2488                 if not self.array.pointer_array:
2489                     body += "        convert_{0}_{1}({2}&in[i], &out[i]);\n".format(
2490                         struct.name, conv_suffix, ctx_part)
2491                 else:
2492                     if struct.needs_conversion(self.conv, self.unwrap, self.direction, False):
2493                         body += "        if (in[i])\n"
2494                         body += "        {\n"
2495                         body += "            out[i] = conversion_context_alloc(ctx, sizeof(*out[i]));\n"
2496                         if self.conv:
2497                             in_param = "({0} *)UlongToPtr(in[i])".format(win_type)
2498                         else:
2499                             in_param = "in[i]"
2500                         body += "            convert_{0}_{1}({2}{3}, out[i]);\n".format(
2501                             struct.name, conv_suffix, ctx_part, in_param)
2502                         body += "        }\n"
2503                         body += "        else\n"
2504                         body += "            out[i] = NULL;\n"
2505                     else:
2506                         body += "        out[i] = UlongToPtr(in[i]);\n".format(win_type)
2507             elif self.array.is_handle():
2508                 if self.array.pointer_array:
2509                     LOGGER.error("Unhandled handle pointer arrays")
2510                 handle = self.array.handle
2511                 if not self.conv or not handle.is_dispatchable():
2512                     input = "in[i]"
2513                 elif self.direction == Direction.INPUT:
2514                     input = "UlongToPtr(in[i])"
2515                 else:
2516                     input = "PtrToUlong(in[i])"
2518                 if not self.unwrap or not handle.is_wrapped():
2519                     body += "        out[i] = {0};\n".format(input)
2520                 elif self.direction == Direction.INPUT:
2521                     body += "        out[i] = " + handle.driver_handle(input) + ";\n"
2522                 else:
2523                     LOGGER.warning("Unhandled handle output conversion")
2524             elif self.array.pointer_array:
2525                 body += "        out[i] = UlongToPtr(in[i]);\n"
2526             else:
2527                 body += "        out[i] = in[i];\n"
2529             body += "    }\n"
2531         if return_type:
2532             body += "\n    return {0}out;\n".format("(void *)" if self.array.pointer_array else "")
2533         body += "}\n"
2535         if not self.conv:
2536             body += "#endif /* _WIN64 */\n"
2538         body += "\n"
2540         return body
2543 class VkGenerator(object):
2544     def __init__(self, registry):
2545         self.registry = registry
2547         # Build a list conversion functions for struct conversion.
2548         self.conversions = []
2549         self.win32_structs = []
2550         for func in self.registry.funcs.values():
2551             if not func.needs_exposing():
2552                 continue
2554             conversions = func.get_conversions()
2555             for conv in conversions:
2556                 # Append if we don't already have this conversion.
2557                 if not any(c == conv for c in self.conversions):
2558                     self.conversions.append(conv)
2560                 if not isinstance(conv, StructConversionFunction):
2561                     continue
2563                 for e in conv.operand.struct_extensions:
2564                     if not e.required or not e.needs_win32_type():
2565                         continue
2566                     if not any(s.name == e.name for s in self.win32_structs):
2567                         self.win32_structs.append(e)
2569                 if not conv.operand.needs_win32_type():
2570                     continue
2572                 # Structs can be used in different ways by different conversions
2573                 # e.g. array vs non-array. Just make sure we pull in each struct once.
2574                 if not any(s.name == conv.operand.name for s in self.win32_structs):
2575                     self.win32_structs.append(conv.operand)
2577     def _generate_copyright(self, f, spec_file=False):
2578         f.write("# " if spec_file else "/* ")
2579         f.write("Automatically generated from Vulkan vk.xml; DO NOT EDIT!\n")
2580         lines = ["", "This file is generated from Vulkan vk.xml file covered",
2581             "by the following copyright and permission notice:"]
2582         lines.extend([l.rstrip(" ") for l in self.registry.copyright.splitlines()])
2583         for line in lines:
2584             f.write("{0}{1}".format("# " if spec_file else " * ", line).rstrip(" ") + "\n")
2585         f.write("\n" if spec_file else " */\n\n")
2587     def generate_thunks_c(self, f):
2588         self._generate_copyright(f)
2590         f.write("#if 0\n")
2591         f.write("#pragma makedep unix\n")
2592         f.write("#endif\n\n")
2594         f.write("#include \"config.h\"\n\n")
2596         f.write("#include <stdlib.h>\n\n")
2598         f.write("#include \"vulkan_private.h\"\n\n")
2600         f.write("WINE_DEFAULT_DEBUG_CHANNEL(vulkan);\n\n")
2602         for struct in self.win32_structs:
2603             f.write(struct.definition(conv=True, align=True))
2604             f.write("\n")
2606         f.write("static uint64_t wine_vk_unwrap_handle(uint32_t type, uint64_t handle)\n")
2607         f.write("{\n")
2608         f.write("    switch(type)\n")
2609         f.write("    {\n")
2610         for handle in self.registry.handles:
2611             if not handle.is_required() or not handle.is_wrapped() or handle.is_alias():
2612                 continue
2613             f.write("    case {}:\n".format(handle.object_type))
2614             if handle.is_dispatchable():
2615                 f.write("        return (uint64_t) (uintptr_t) ")
2616                 f.write(handle.native_handle("(({}) (uintptr_t) handle)".format(handle.name)))
2617             else:
2618                 f.write("        return (uint64_t) ")
2619                 f.write(handle.native_handle("handle"))
2620             f.write(";\n");
2621         f.write("    default:\n")
2622         f.write("       return handle;\n")
2623         f.write("    }\n")
2624         f.write("}\n\n")
2626         # Generate any conversion helper functions.
2627         for conv in self.conversions:
2628             f.write(conv.definition())
2630         # Create thunks for instance and device functions.
2631         # Global functions don't go through the thunks.
2632         for vk_func in self.registry.funcs.values():
2633             if not vk_func.needs_exposing():
2634                 continue
2635             if vk_func.loader_thunk_type == ThunkType.NONE:
2636                 continue
2638             f.write(vk_func.thunk(prefix="thunk64_"))
2639             f.write(vk_func.thunk(prefix="thunk32_", conv=True))
2641         # Create array of device extensions.
2642         f.write("static const char * const vk_device_extensions[] =\n{\n")
2643         for ext in self.registry.extensions:
2644             if ext["type"] != "device":
2645                 continue
2646             if ext["name"] in UNEXPOSED_EXTENSIONS:
2647                 continue
2649             f.write("    \"{0}\",\n".format(ext["name"]))
2650         f.write("};\n\n")
2652         # Create array of instance extensions.
2653         f.write("static const char * const vk_instance_extensions[] =\n{\n")
2654         for ext in self.registry.extensions:
2655             if ext["type"] != "instance":
2656                 continue
2657             if ext["name"] in UNEXPOSED_EXTENSIONS:
2658                 continue
2660             f.write("    \"{0}\",\n".format(ext["name"]))
2661         f.write("};\n\n")
2663         f.write("BOOL wine_vk_device_extension_supported(const char *name)\n")
2664         f.write("{\n")
2665         f.write("    unsigned int i;\n")
2666         f.write("    for (i = 0; i < ARRAY_SIZE(vk_device_extensions); i++)\n")
2667         f.write("    {\n")
2668         f.write("        if (strcmp(vk_device_extensions[i], name) == 0)\n")
2669         f.write("            return TRUE;\n")
2670         f.write("    }\n")
2671         f.write("    return FALSE;\n")
2672         f.write("}\n\n")
2674         f.write("BOOL wine_vk_instance_extension_supported(const char *name)\n")
2675         f.write("{\n")
2676         f.write("    unsigned int i;\n")
2677         f.write("    for (i = 0; i < ARRAY_SIZE(vk_instance_extensions); i++)\n")
2678         f.write("    {\n")
2679         f.write("        if (strcmp(vk_instance_extensions[i], name) == 0)\n")
2680         f.write("            return TRUE;\n")
2681         f.write("    }\n")
2682         f.write("    return FALSE;\n")
2683         f.write("}\n\n")
2685         f.write("BOOL wine_vk_is_type_wrapped(VkObjectType type)\n")
2686         f.write("{\n")
2687         f.write("    return FALSE")
2688         for handle in self.registry.handles:
2689             if not handle.is_required() or not handle.is_wrapped() or handle.is_alias():
2690                 continue
2691             f.write(" ||\n        type == {}".format(handle.object_type))
2692         f.write(";\n")
2693         f.write("}\n\n")
2696         f.write("#ifdef _WIN64\n\n")
2698         f.write("const unixlib_entry_t __wine_unix_call_funcs[] =\n")
2699         f.write("{\n")
2700         f.write("    init_vulkan,\n")
2701         f.write("    vk_is_available_instance_function,\n")
2702         f.write("    vk_is_available_device_function,\n")
2703         for vk_func in self.registry.funcs.values():
2704             if not vk_func.needs_exposing():
2705                 continue
2706             if vk_func.loader_thunk_type == ThunkType.NONE:
2707                 continue
2709             f.write("    {1}{0},\n".format(vk_func.name, "thunk64_"))
2710         f.write("};\n")
2711         f.write("C_ASSERT(ARRAYSIZE(__wine_unix_call_funcs) == unix_count);\n\n")
2713         f.write("#endif /* _WIN64 */\n\n")
2715         f.write("#ifdef _WIN64\n")
2716         f.write("const unixlib_entry_t __wine_unix_call_wow64_funcs[] =\n")
2717         f.write("#else\n")
2718         f.write("const unixlib_entry_t __wine_unix_call_funcs[] =\n")
2719         f.write("#endif\n")
2720         f.write("{\n")
2721         f.write("    init_vulkan,\n")
2722         f.write("    vk_is_available_instance_function32,\n")
2723         f.write("    vk_is_available_device_function32,\n")
2724         for vk_func in self.registry.funcs.values():
2725             if not vk_func.needs_exposing():
2726                 continue
2727             if vk_func.loader_thunk_type == ThunkType.NONE:
2728                 continue
2730             f.write("    {1}{0},\n".format(vk_func.name, "thunk32_"))
2731         f.write("};\n")
2732         f.write("C_ASSERT(ARRAYSIZE(__wine_unix_call_funcs) == unix_count);\n")
2734     def generate_thunks_h(self, f, prefix):
2735         self._generate_copyright(f)
2737         f.write("#ifndef __WINE_VULKAN_THUNKS_H\n")
2738         f.write("#define __WINE_VULKAN_THUNKS_H\n\n")
2740         f.write("#define WINE_VK_VERSION VK_API_VERSION_{0}_{1}\n\n".format(WINE_VK_VERSION[0], WINE_VK_VERSION[1]))
2742         # Generate prototypes for device and instance functions requiring a custom implementation.
2743         f.write("/* Functions for which we have custom implementations outside of the thunks. */\n")
2744         for vk_func in self.registry.funcs.values():
2745             if not vk_func.needs_private_thunk():
2746                 continue
2748             f.write("{0};\n".format(vk_func.prototype(prefix=prefix, postfix="DECLSPEC_HIDDEN", is_thunk=True)))
2749         f.write("\n")
2751         f.write("/* For use by vkDevice and children */\n")
2752         f.write("struct vulkan_device_funcs\n{\n")
2753         for vk_func in self.registry.device_funcs:
2754             if not vk_func.needs_exposing():
2755                 continue
2757             if not vk_func.needs_dispatch():
2758                 LOGGER.debug("skipping {0} in vulkan_device_funcs".format(vk_func.name))
2759                 continue
2761             f.write("    {0};\n".format(vk_func.pfn()))
2762         f.write("};\n\n")
2764         f.write("/* For use by vkInstance and children */\n")
2765         f.write("struct vulkan_instance_funcs\n{\n")
2766         for vk_func in self.registry.instance_funcs + self.registry.phys_dev_funcs:
2767             if not vk_func.needs_exposing():
2768                 continue
2770             if not vk_func.needs_dispatch():
2771                 LOGGER.debug("skipping {0} in vulkan_instance_funcs".format(vk_func.name))
2772                 continue
2774             f.write("    {0};\n".format(vk_func.pfn()))
2775         f.write("};\n\n")
2777         f.write("#define ALL_VK_DEVICE_FUNCS() \\\n")
2778         first = True
2779         for vk_func in self.registry.device_funcs:
2780             if not vk_func.needs_exposing():
2781                 continue
2783             if not vk_func.needs_dispatch():
2784                 LOGGER.debug("skipping {0} in ALL_VK_DEVICE_FUNCS".format(vk_func.name))
2785                 continue
2787             if first:
2788                 f.write("    USE_VK_FUNC({0})".format(vk_func.name))
2789                 first = False
2790             else:
2791                 f.write(" \\\n    USE_VK_FUNC({0})".format(vk_func.name))
2792         f.write("\n\n")
2794         f.write("#define ALL_VK_INSTANCE_FUNCS() \\\n")
2795         first = True
2796         for vk_func in self.registry.instance_funcs + self.registry.phys_dev_funcs:
2797             if not vk_func.needs_exposing():
2798                 continue
2800             if not vk_func.needs_dispatch():
2801                 LOGGER.debug("skipping {0} in ALL_VK_INSTANCE_FUNCS".format(vk_func.name))
2802                 continue
2804             if first:
2805                 f.write("    USE_VK_FUNC({0})".format(vk_func.name))
2806                 first = False
2807             else:
2808                 f.write(" \\\n    USE_VK_FUNC({0})".format(vk_func.name))
2809         f.write("\n\n")
2811         f.write("#endif /* __WINE_VULKAN_THUNKS_H */\n")
2813     def generate_loader_thunks_c(self, f):
2814         self._generate_copyright(f)
2816         f.write("#include \"vulkan_loader.h\"\n\n")
2818         f.write("WINE_DEFAULT_DEBUG_CHANNEL(vulkan);\n\n")
2820         for vk_func in self.registry.funcs.values():
2821             if not vk_func.needs_exposing():
2822                 continue
2823             if vk_func.loader_thunk_type != ThunkType.PUBLIC:
2824                 continue
2826             f.write(vk_func.loader_thunk())
2828         f.write("static const struct vulkan_func vk_device_dispatch_table[] =\n{\n")
2829         for vk_func in self.registry.device_funcs:
2830             if not vk_func.needs_exposing():
2831                 continue
2833             f.write("    {{\"{0}\", {0}}},\n".format(vk_func.name))
2834         f.write("};\n\n")
2836         f.write("static const struct vulkan_func vk_phys_dev_dispatch_table[] =\n{\n")
2837         for vk_func in self.registry.phys_dev_funcs:
2838             if not vk_func.needs_exposing():
2839                 continue
2841             f.write("    {{\"{0}\", {0}}},\n".format(vk_func.name))
2842         f.write("};\n\n")
2844         f.write("static const struct vulkan_func vk_instance_dispatch_table[] =\n{\n")
2845         for vk_func in self.registry.instance_funcs:
2846             if not vk_func.needs_exposing():
2847                 continue
2849             f.write("    {{\"{0}\", {0}}},\n".format(vk_func.name))
2850         f.write("};\n\n")
2852         f.write("void *wine_vk_get_device_proc_addr(const char *name)\n")
2853         f.write("{\n")
2854         f.write("    unsigned int i;\n")
2855         f.write("    for (i = 0; i < ARRAY_SIZE(vk_device_dispatch_table); i++)\n")
2856         f.write("    {\n")
2857         f.write("        if (strcmp(vk_device_dispatch_table[i].name, name) == 0)\n")
2858         f.write("        {\n")
2859         f.write("            TRACE(\"Found name=%s in device table\\n\", debugstr_a(name));\n")
2860         f.write("            return vk_device_dispatch_table[i].func;\n")
2861         f.write("        }\n")
2862         f.write("    }\n")
2863         f.write("    return NULL;\n")
2864         f.write("}\n\n")
2866         f.write("void *wine_vk_get_phys_dev_proc_addr(const char *name)\n")
2867         f.write("{\n")
2868         f.write("    unsigned int i;\n")
2869         f.write("    for (i = 0; i < ARRAY_SIZE(vk_phys_dev_dispatch_table); i++)\n")
2870         f.write("    {\n")
2871         f.write("        if (strcmp(vk_phys_dev_dispatch_table[i].name, name) == 0)\n")
2872         f.write("        {\n")
2873         f.write("            TRACE(\"Found name=%s in physical device table\\n\", debugstr_a(name));\n")
2874         f.write("            return vk_phys_dev_dispatch_table[i].func;\n")
2875         f.write("        }\n")
2876         f.write("    }\n")
2877         f.write("    return NULL;\n")
2878         f.write("}\n\n")
2880         f.write("void *wine_vk_get_instance_proc_addr(const char *name)\n")
2881         f.write("{\n")
2882         f.write("    unsigned int i;\n")
2883         f.write("    for (i = 0; i < ARRAY_SIZE(vk_instance_dispatch_table); i++)\n")
2884         f.write("    {\n")
2885         f.write("        if (strcmp(vk_instance_dispatch_table[i].name, name) == 0)\n")
2886         f.write("        {\n")
2887         f.write("            TRACE(\"Found name=%s in instance table\\n\", debugstr_a(name));\n")
2888         f.write("            return vk_instance_dispatch_table[i].func;\n")
2889         f.write("        }\n")
2890         f.write("    }\n")
2891         f.write("    return NULL;\n")
2892         f.write("}\n")
2894     def generate_loader_thunks_h(self, f):
2895         self._generate_copyright(f)
2897         f.write("#ifndef __WINE_VULKAN_LOADER_THUNKS_H\n")
2898         f.write("#define __WINE_VULKAN_LOADER_THUNKS_H\n\n")
2900         f.write("enum unix_call\n")
2901         f.write("{\n")
2902         f.write("    unix_init,\n")
2903         f.write("    unix_is_available_instance_function,\n")
2904         f.write("    unix_is_available_device_function,\n")
2905         for vk_func in self.registry.funcs.values():
2906             if not vk_func.needs_exposing():
2907                 continue
2908             if vk_func.loader_thunk_type == ThunkType.NONE:
2909                 continue
2911             f.write("    unix_{0},\n".format(vk_func.name))
2912         f.write("    unix_count,\n")
2913         f.write("};\n\n")
2915         for vk_func in self.registry.funcs.values():
2916             if not vk_func.needs_exposing():
2917                 continue
2918             if vk_func.loader_thunk_type == ThunkType.NONE:
2919                 continue
2921             f.write("struct {0}_params\n".format(vk_func.name))
2922             f.write("{\n");
2923             for p in vk_func.params:
2924                 f.write("    {0};\n".format(p.definition(is_member=True)))
2925             if vk_func.extra_param:
2926                 f.write("    void *{0};\n".format(vk_func.extra_param))
2927             if vk_func.type != "void":
2928                 f.write("    {0} result;\n".format(vk_func.type))
2929             f.write("};\n\n");
2931         f.write("#endif /* __WINE_VULKAN_LOADER_THUNKS_H */\n")
2933     def generate_vulkan_h(self, f):
2934         self._generate_copyright(f)
2935         f.write("#ifndef __WINE_VULKAN_H\n")
2936         f.write("#define __WINE_VULKAN_H\n\n")
2938         f.write("#include <windef.h>\n")
2939         f.write("#include <stdint.h>\n\n")
2941         f.write("/* Define WINE_VK_HOST to get 'host' headers. */\n")
2942         f.write("#ifdef WINE_VK_HOST\n")
2943         f.write("#define VKAPI_CALL\n")
2944         f.write('#define WINE_VK_ALIGN(x)\n')
2945         f.write("#endif\n\n")
2947         f.write("#ifndef VKAPI_CALL\n")
2948         f.write("#define VKAPI_CALL __stdcall\n")
2949         f.write("#endif\n\n")
2951         f.write("#ifndef VKAPI_PTR\n")
2952         f.write("#define VKAPI_PTR VKAPI_CALL\n")
2953         f.write("#endif\n\n")
2955         f.write("#ifndef WINE_VK_ALIGN\n")
2956         f.write("#define WINE_VK_ALIGN DECLSPEC_ALIGN\n")
2957         f.write("#endif\n\n")
2959         # The overall strategy is to define independent constants and datatypes,
2960         # prior to complex structures and function calls to avoid forward declarations.
2961         for const in self.registry.consts:
2962             # For now just generate things we may not need. The amount of parsing needed
2963             # to get some of the info is tricky as you need to figure out which structure
2964             # references a certain constant.
2965             f.write(const.definition())
2966         f.write("\n")
2968         for define in self.registry.defines:
2969             f.write(define.definition())
2971         for handle in self.registry.handles:
2972             # For backward compatibility also create definitions for aliases.
2973             # These types normally don't get pulled in as we use the new types
2974             # even in legacy functions if they are aliases.
2975             if handle.is_required() or handle.is_alias():
2976                  f.write(handle.definition())
2977         f.write("\n")
2979         for base_type in self.registry.base_types:
2980             f.write(base_type.definition())
2981         f.write("\n")
2983         for bitmask in self.registry.bitmasks:
2984             f.write(bitmask.definition())
2985         f.write("\n")
2987         # Define enums, this includes values for some of the bitmask types as well.
2988         for enum in self.registry.enums.values():
2989             if enum.required:
2990                 f.write(enum.definition())
2992         for fp in self.registry.funcpointers:
2993             if fp.required:
2994                 f.write(fp.definition())
2995         f.write("\n")
2997         # This generates both structures and unions. Since structures
2998         # may depend on other structures/unions, we need a list of
2999         # decoupled structs.
3000         # Note: unions are stored in structs for dependency reasons,
3001         # see comment in parsing section.
3002         structs = VkStruct.decouple_structs(self.registry.structs)
3003         for struct in structs:
3004             LOGGER.debug("Generating struct: {0}".format(struct.name))
3005             f.write(struct.definition(align=True))
3006             f.write("\n")
3008         for func in self.registry.funcs.values():
3009             if not func.is_required():
3010                 LOGGER.debug("Skipping PFN definition for: {0}".format(func.name))
3011                 continue
3013             f.write("typedef {0};\n".format(func.pfn(prefix="PFN", call_conv="VKAPI_PTR")))
3014         f.write("\n")
3016         f.write("#ifndef VK_NO_PROTOTYPES\n")
3017         for func in self.registry.funcs.values():
3018             if not func.is_required():
3019                 LOGGER.debug("Skipping API definition for: {0}".format(func.name))
3020                 continue
3022             LOGGER.debug("Generating API definition for: {0}".format(func.name))
3023             f.write("{0};\n".format(func.prototype(call_conv="VKAPI_CALL")))
3024         f.write("#endif /* VK_NO_PROTOTYPES */\n\n")
3026         f.write("#endif /* __WINE_VULKAN_H */\n")
3028     def generate_vulkan_driver_h(self, f):
3029         self._generate_copyright(f)
3030         f.write("#ifndef __WINE_VULKAN_DRIVER_H\n")
3031         f.write("#define __WINE_VULKAN_DRIVER_H\n\n")
3033         f.write("/* Wine internal vulkan driver version, needs to be bumped upon vulkan_funcs changes. */\n")
3034         f.write("#define WINE_VULKAN_DRIVER_VERSION {0}\n\n".format(DRIVER_VERSION))
3036         f.write("struct vulkan_funcs\n{\n")
3037         f.write("    /* Vulkan global functions. These are the only calls at this point a graphics driver\n")
3038         f.write("     * needs to provide. Other function calls will be provided indirectly by dispatch\n")
3039         f.write("     * tables part of dispatchable Vulkan objects such as VkInstance or vkDevice.\n")
3040         f.write("     */\n")
3042         for vk_func in self.registry.funcs.values():
3043             if not vk_func.is_driver_func():
3044                 continue
3046             pfn = vk_func.pfn()
3047             # Avoid PFN_vkVoidFunction in driver interface as Vulkan likes to put calling convention
3048             # stuff in there. For simplicity substitute with "void *".
3049             pfn = pfn.replace("PFN_vkVoidFunction", "void *")
3050             f.write("    {0};\n".format(pfn))
3052         f.write("\n")
3053         f.write("    /* winevulkan specific functions */\n")
3054         f.write("    VkSurfaceKHR (*p_wine_get_native_surface)(VkSurfaceKHR);\n")
3055         f.write("};\n\n")
3057         f.write("extern const struct vulkan_funcs * __wine_get_vulkan_driver(UINT version);\n\n")
3059         f.write("static inline void *get_vulkan_driver_device_proc_addr(\n")
3060         f.write("        const struct vulkan_funcs *vulkan_funcs, const char *name)\n{\n")
3061         f.write("    if (!name || name[0] != 'v' || name[1] != 'k') return NULL;\n\n")
3062         f.write("    name += 2;\n\n")
3063         for vk_func in self.registry.funcs.values():
3064             if vk_func.is_driver_func() and vk_func.is_device_func():
3065                 f.write('    if (!strcmp(name, "{0}"))\n'.format(vk_func.name[2:]))
3066                 f.write('        return vulkan_funcs->p_{0};\n'.format(vk_func.name))
3067         f.write("\n")
3068         f.write("    return NULL;\n}\n\n")
3070         f.write("static inline void *get_vulkan_driver_instance_proc_addr(\n")
3071         f.write("        const struct vulkan_funcs *vulkan_funcs, VkInstance instance, const char *name)\n{\n")
3072         f.write("    if (!name || name[0] != 'v' || name[1] != 'k') return NULL;\n\n")
3073         f.write("    name += 2;\n\n")
3074         for vk_func in self.registry.funcs.values():
3075             if vk_func.is_driver_func() and vk_func.is_global_func() and vk_func.name != "vkGetInstanceProcAddr":
3076                 f.write('    if (!strcmp(name, "{0}"))\n'.format(vk_func.name[2:]))
3077                 f.write('        return vulkan_funcs->p_{0};\n'.format(vk_func.name))
3078         f.write("\n")
3079         f.write("    if (!instance) return NULL;\n\n")
3080         for vk_func in self.registry.funcs.values():
3081             if vk_func.is_driver_func() and (vk_func.is_instance_func() or vk_func.is_phys_dev_func()):
3082                 f.write('    if (!strcmp(name, "{0}"))\n'.format(vk_func.name[2:]))
3083                 f.write('        return vulkan_funcs->p_{0};\n'.format(vk_func.name))
3084         f.write("\n")
3085         f.write("    name -= 2;\n\n")
3086         f.write("    return get_vulkan_driver_device_proc_addr(vulkan_funcs, name);\n}\n\n")
3088         f.write("#endif /* __WINE_VULKAN_DRIVER_H */\n")
3090     def generate_vulkan_spec(self, f):
3091         self._generate_copyright(f, spec_file=True)
3092         f.write("@ stdcall -private vk_icdGetInstanceProcAddr(ptr str)\n")
3093         f.write("@ stdcall -private vk_icdGetPhysicalDeviceProcAddr(ptr str)\n")
3094         f.write("@ stdcall -private vk_icdNegotiateLoaderICDInterfaceVersion(ptr)\n")
3096         # Export symbols for all Vulkan Core functions.
3097         for func in self.registry.funcs.values():
3098             if not func.is_core_func():
3099                 continue
3101             # We support all Core functions except for VK_KHR_display* APIs.
3102             # Create stubs for unsupported Core functions.
3103             if func.is_required():
3104                 f.write(func.spec())
3105             else:
3106                 f.write("@ stub {0}\n".format(func.name))
3108         f.write("@ stdcall -private DllRegisterServer()\n")
3109         f.write("@ stdcall -private DllUnregisterServer()\n")
3111     def generate_vulkan_loader_spec(self, f):
3112         self._generate_copyright(f, spec_file=True)
3114         # Export symbols for all Vulkan Core functions.
3115         for func in self.registry.funcs.values():
3116             if not func.is_core_func():
3117                 continue
3119             # We support all Core functions except for VK_KHR_display* APIs.
3120             # Create stubs for unsupported Core functions.
3121             if func.is_required():
3122                 f.write(func.spec(symbol="winevulkan." + func.name))
3123             else:
3124                 f.write("@ stub {0}\n".format(func.name))
3127 class VkRegistry(object):
3128     def __init__(self, reg_filename):
3129         # Used for storage of type information.
3130         self.base_types = None
3131         self.bitmasks = None
3132         self.consts = None
3133         self.defines = None
3134         self.enums = None
3135         self.funcpointers = None
3136         self.handles = None
3137         self.structs = None
3139         # We aggregate all types in here for cross-referencing.
3140         self.funcs = {}
3141         self.types = {}
3143         self.version_regex = re.compile(
3144             r'^'
3145             r'VK_VERSION_'
3146             r'(?P<major>[0-9])'
3147             r'_'
3148             r'(?P<minor>[0-9])'
3149             r'$'
3150         )
3152         # Overall strategy for parsing the registry is to first
3153         # parse all type / function definitions. Then parse
3154         # features and extensions to decide which types / functions
3155         # to actually 'pull in' for code generation. For each type or
3156         # function call we want we set a member 'required' to True.
3157         tree = ET.parse(reg_filename)
3158         root = tree.getroot()
3159         self._parse_enums(root)
3160         self._parse_types(root)
3161         self._parse_commands(root)
3163         # Pull in any required types and functions.
3164         self._parse_features(root)
3165         self._parse_extensions(root)
3167         for enum in self.enums.values():
3168             enum.fixup_64bit_aliases()
3170         self._match_object_types()
3172         self.copyright = root.find('./comment').text
3174     def _is_feature_supported(self, feature):
3175         version = self.version_regex.match(feature)
3176         if not version:
3177             return True
3179         version = tuple(map(int, version.group('major', 'minor')))
3180         return version <= WINE_VK_VERSION
3182     def _is_extension_supported(self, extension):
3183         # We disable some extensions as either we haven't implemented
3184         # support yet or because they are for platforms other than win32.
3185         return extension not in UNSUPPORTED_EXTENSIONS
3187     def _mark_command_required(self, command):
3188         """ Helper function to mark a certain command and the datatypes it needs as required."""
3189         def mark_bitmask_dependencies(bitmask, types):
3190             if bitmask.requires is not None:
3191                 types[bitmask.requires]["data"].required = True
3193         def mark_funcpointer_dependencies(fp, types):
3194             for m in fp.members:
3195                 type_info = types[m.type]
3197                 # Complex types have a matching definition e.g. VkStruct.
3198                 # Not needed for base types such as uint32_t.
3199                 if "data" in type_info:
3200                     types[m.type]["data"].required = True
3202         def mark_struct_dependencies(struct, types):
3203              for m in struct:
3204                 type_info = types[m.type]
3206                 # Complex types have a matching definition e.g. VkStruct.
3207                 # Not needed for base types such as uint32_t.
3208                 if "data" in type_info:
3209                     types[m.type]["data"].required = True
3211                 if type_info["category"] == "struct" and struct.name != m.type:
3212                     # Yay, recurse
3213                     mark_struct_dependencies(type_info["data"], types)
3214                 elif type_info["category"] == "funcpointer":
3215                     mark_funcpointer_dependencies(type_info["data"], types)
3216                 elif type_info["category"] == "bitmask":
3217                     mark_bitmask_dependencies(type_info["data"], types)
3219         func = self.funcs[command]
3220         func.required = True
3222         # Pull in return type
3223         if func.type != "void":
3224             self.types[func.type]["data"].required = True
3226         # Analyze parameter dependencies and pull in any type needed.
3227         for p in func.params:
3228             type_info = self.types[p.type]
3230             # Check if we are dealing with a complex type e.g. VkEnum, VkStruct and others.
3231             if "data" not in type_info:
3232                 continue
3234             # Mark the complex type as required.
3235             type_info["data"].required = True
3236             if type_info["category"] == "struct":
3237                 struct = type_info["data"]
3238                 mark_struct_dependencies(struct, self.types)
3239             elif type_info["category"] == "bitmask":
3240                 mark_bitmask_dependencies(type_info["data"], self.types)
3242     def _match_object_types(self):
3243         """ Matches each handle with the correct object type. """
3244         # Use upper case comparison for simplicity.
3245         object_types = {}
3246         for value in self.enums["VkObjectType"].values:
3247             object_name = "VK" + value.name[len("VK_OBJECT_TYPE"):].replace("_", "")
3248             object_types[object_name] = value.name
3250         for handle in self.handles:
3251             if not handle.is_required():
3252                 continue
3253             handle.object_type = object_types.get(handle.name.upper())
3254             if not handle.object_type:
3255                 LOGGER.warning("No object type found for {}".format(handle.name))
3257     def _parse_commands(self, root):
3258         """ Parse command section containing the Vulkan function calls. """
3259         funcs = {}
3260         commands = root.findall("./commands/")
3262         # As of Vulkan 1.1, various extensions got promoted to Core.
3263         # The old commands (e.g. KHR) are available for backwards compatibility
3264         # and are marked in vk.xml as 'alias' to the non-extension type.
3265         # The registry likes to avoid data duplication, so parameters and other
3266         # metadata need to be looked up from the Core command.
3267         # We parse the alias commands in a second pass.
3268         alias_commands = []
3269         for command in commands:
3270             alias_name = command.attrib.get("alias")
3271             if alias_name:
3272                 alias_commands.append(command)
3273                 continue
3275             func = VkFunction.from_xml(command, self.types)
3276             funcs[func.name] = func
3278         for command in alias_commands:
3279             alias_name = command.attrib.get("alias")
3280             alias = funcs[alias_name]
3281             func = VkFunction.from_alias(command, alias)
3282             funcs[func.name] = func
3284         # To make life easy for the code generation, separate all function
3285         # calls out in the 4 types of Vulkan functions:
3286         # device, global, physical device and instance.
3287         device_funcs = []
3288         global_funcs = []
3289         phys_dev_funcs = []
3290         instance_funcs = []
3291         for func in funcs.values():
3292             if func.is_device_func():
3293                 device_funcs.append(func)
3294             elif func.is_global_func():
3295                 global_funcs.append(func)
3296             elif func.is_phys_dev_func():
3297                 phys_dev_funcs.append(func)
3298             else:
3299                 instance_funcs.append(func)
3301         # Sort function lists by name and store them.
3302         self.device_funcs = sorted(device_funcs, key=lambda func: func.name)
3303         self.global_funcs = sorted(global_funcs, key=lambda func: func.name)
3304         self.phys_dev_funcs = sorted(phys_dev_funcs, key=lambda func: func.name)
3305         self.instance_funcs = sorted(instance_funcs, key=lambda func: func.name)
3307         # The funcs dictionary is used as a convenient way to lookup function
3308         # calls when needed e.g. to adjust member variables.
3309         self.funcs = OrderedDict(sorted(funcs.items()))
3311     def _parse_enums(self, root):
3312         """ Parse enums section or better described as constants section. """
3313         enums = {}
3314         self.consts = []
3315         for enum in root.findall("./enums"):
3316             name = enum.attrib.get("name")
3317             _type = enum.attrib.get("type")
3319             if _type in ("enum", "bitmask"):
3320                 enums[name] = VkEnum.from_xml(enum)
3321             else:
3322                 # If no type is set, we are dealing with API constants.
3323                 for value in enum.findall("enum"):
3324                     # If enum is an alias, set the value to the alias name.
3325                     # E.g. VK_LUID_SIZE_KHR is an alias to VK_LUID_SIZE.
3326                     alias = value.attrib.get("alias")
3327                     if alias:
3328                         self.consts.append(VkConstant(value.attrib.get("name"), alias))
3329                     else:
3330                         self.consts.append(VkConstant(value.attrib.get("name"), value.attrib.get("value")))
3332         self.enums = OrderedDict(sorted(enums.items()))
3334     def _process_require_enum(self, enum_elem, ext=None, only_aliased=False):
3335         if "extends" in enum_elem.keys():
3336             enum = self.types[enum_elem.attrib["extends"]]["data"]
3338             # Need to define VkEnumValues which were aliased to by another value. This is necessary
3339             # from VK spec version 1.2.135 where the provisional VK_KHR_ray_tracing extension was
3340             # added which altered VK_NV_ray_tracing's VkEnumValues to alias to the provisional
3341             # extension.
3342             aliased = False
3343             for _, t in self.types.items():
3344                 if t["category"] != "enum":
3345                     continue
3346                 if not t["data"]:
3347                     continue
3348                 for value in t["data"].values:
3349                     if value.alias == enum_elem.attrib["name"]:
3350                         aliased = True
3352             if only_aliased and not aliased:
3353                 return
3355             if "bitpos" in enum_elem.keys():
3356                 # We need to add an extra value to an existing enum type.
3357                 # E.g. VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG to VkFormatFeatureFlagBits.
3358                 enum.create_bitpos(enum_elem.attrib["name"], int(enum_elem.attrib["bitpos"]))
3360             elif "offset" in enum_elem.keys():
3361                 # Extensions promoted to Core, have the extension number as part
3362                 # of the enum value. Else retrieve from the extension tag.
3363                 if enum_elem.attrib.get("extnumber"):
3364                     ext_number = int(enum_elem.attrib.get("extnumber"))
3365                 else:
3366                     ext_number = int(ext.attrib["number"])
3367                 offset = int(enum_elem.attrib["offset"])
3368                 value = EXT_BASE + (ext_number - 1) * EXT_BLOCK_SIZE + offset
3370                 # Deal with negative values.
3371                 direction = enum_elem.attrib.get("dir")
3372                 if direction is not None:
3373                     value = -value
3375                 enum.create_value(enum_elem.attrib["name"], str(value))
3377             elif "value" in enum_elem.keys():
3378                 enum.create_value(enum_elem.attrib["name"], enum_elem.attrib["value"])
3379             elif "alias" in enum_elem.keys():
3380                 enum.create_alias(enum_elem.attrib["name"], enum_elem.attrib["alias"])
3382         elif "value" in enum_elem.keys():
3383             # Constant with an explicit value
3384             if only_aliased:
3385                 return
3387             self.consts.append(VkConstant(enum_elem.attrib["name"], enum_elem.attrib["value"]))
3388         elif "alias" in enum_elem.keys():
3389             # Aliased constant
3390             if not only_aliased:
3391                 return
3393             self.consts.append(VkConstant(enum_elem.attrib["name"], enum_elem.attrib["alias"]))
3395     @staticmethod
3396     def _require_type(type_info):
3397         if type_info.is_alias():
3398             type_info = type_info.alias
3399         type_info.required = True
3400         if type(type_info) == VkStruct:
3401             for member in type_info.members:
3402                 if "data" in member.type_info:
3403                   VkRegistry._require_type(member.type_info["data"])
3405     def _parse_extensions(self, root):
3406         """ Parse extensions section and pull in any types and commands for this extension. """
3407         extensions = []
3408         exts = root.findall("./extensions/extension")
3409         deferred_exts = []
3410         skipped_exts = UNSUPPORTED_EXTENSIONS.copy()
3412         def process_ext(ext, deferred=False):
3413             ext_name = ext.attrib["name"]
3415             # Set extension name on any functions calls part of this extension as we
3416             # were not aware of the name during initial parsing.
3417             commands = ext.findall("require/command")
3418             for command in commands:
3419                 cmd_name = command.attrib["name"]
3420                 # Need to verify that the command is defined, and otherwise skip it.
3421                 # vkCreateScreenSurfaceQNX is declared in <extensions> but not defined in
3422                 # <commands>. A command without a definition cannot be enabled, so it's valid for
3423                 # the XML file to handle this, but because of the manner in which we parse the XML
3424                 # file we pre-populate from <commands> before we check if a command is enabled.
3425                 if cmd_name in self.funcs:
3426                     self.funcs[cmd_name].extensions.add(ext_name)
3428             # Some extensions are not ready or have numbers reserved as a place holder.
3429             if ext.attrib["supported"] == "disabled":
3430                 LOGGER.debug("Skipping disabled extension: {0}".format(ext_name))
3431                 skipped_exts.append(ext_name)
3432                 return
3434             # Defer extensions with 'sortorder' as they are order-dependent for spec-parsing.
3435             if not deferred and "sortorder" in ext.attrib:
3436                 deferred_exts.append(ext)
3437                 return
3439             # Disable highly experimental extensions as the APIs are unstable and can
3440             # change between minor Vulkan revisions until API is final and becomes KHR
3441             # or NV.
3442             if ("KHX" in ext_name or "NVX" in ext_name) and ext_name not in ALLOWED_X_EXTENSIONS:
3443                 LOGGER.debug("Skipping experimental extension: {0}".format(ext_name))
3444                 skipped_exts.append(ext_name)
3445                 return
3447             # Extensions can define VkEnumValues which alias to provisional extensions. Pre-process
3448             # extensions to define any required VkEnumValues before the platform check below.
3449             for require in ext.findall("require"):
3450                 # Extensions can add enum values to Core / extension enums, so add these.
3451                 for enum_elem in require.findall("enum"):
3452                     self._process_require_enum(enum_elem, ext, only_aliased=True)
3454             platform = ext.attrib.get("platform")
3455             if platform and platform != "win32":
3456                 LOGGER.debug("Skipping extensions {0} for platform {1}".format(ext_name, platform))
3457                 skipped_exts.append(ext_name)
3458                 return
3460             if not self._is_extension_supported(ext_name):
3461                 LOGGER.debug("Skipping unsupported extension: {0}".format(ext_name))
3462                 skipped_exts.append(ext_name)
3463                 return
3464             elif "requires" in ext.attrib:
3465                 # Check if this extension builds on top of another unsupported extension.
3466                 requires = ext.attrib["requires"].split(",")
3467                 if len(set(requires).intersection(skipped_exts)) > 0:
3468                     skipped_exts.append(ext_name)
3469                     return
3471             LOGGER.debug("Loading extension: {0}".format(ext_name))
3473             # Extensions can define one or more require sections each requiring
3474             # different features (e.g. Vulkan 1.1). Parse each require section
3475             # separately, so we can skip sections we don't want.
3476             for require in ext.findall("require"):
3477                 # Extensions can add enum values to Core / extension enums, so add these.
3478                 for enum_elem in require.findall("enum"):
3479                     self._process_require_enum(enum_elem, ext)
3481                 for t in require.findall("type"):
3482                     type_info = self.types[t.attrib["name"]]["data"]
3483                     self._require_type(type_info)
3484                 feature = require.attrib.get("feature")
3485                 if feature and not self._is_feature_supported(feature):
3486                     continue
3488                 required_extension = require.attrib.get("extension")
3489                 if required_extension and not self._is_extension_supported(required_extension):
3490                     continue
3492                 # Pull in any commands we need. We infer types to pull in from the command
3493                 # as well.
3494                 for command in require.findall("command"):
3495                     cmd_name = command.attrib["name"]
3496                     self._mark_command_required(cmd_name)
3499             # Store a list with extensions.
3500             ext_info = {"name" : ext_name, "type" : ext.attrib["type"]}
3501             extensions.append(ext_info)
3504         # Process extensions, allowing for sortorder to defer extension processing
3505         for ext in exts:
3506             process_ext(ext)
3508         deferred_exts.sort(key=lambda ext: ext.attrib["sortorder"])
3510         # Respect sortorder
3511         for ext in deferred_exts:
3512             process_ext(ext, deferred=True)
3514         # Sort in alphabetical order.
3515         self.extensions = sorted(extensions, key=lambda ext: ext["name"])
3517     def _parse_features(self, root):
3518         """ Parse the feature section, which describes Core commands and types needed. """
3520         for feature in root.findall("./feature"):
3521             feature_name = feature.attrib["name"]
3522             for require in feature.findall("require"):
3523                 LOGGER.info("Including features for {0}".format(require.attrib.get("comment")))
3524                 for tag in require:
3525                     if tag.tag == "comment":
3526                         continue
3527                     elif tag.tag == "command":
3528                         if not self._is_feature_supported(feature_name):
3529                             continue
3530                         name = tag.attrib["name"]
3531                         self._mark_command_required(name)
3532                     elif tag.tag == "enum":
3533                         self._process_require_enum(tag)
3534                     elif tag.tag == "type":
3535                         name = tag.attrib["name"]
3537                         # Skip pull in for vk_platform.h for now.
3538                         if name == "vk_platform":
3539                             continue
3541                         type_info = self.types[name]
3542                         type_info["data"].required = True
3544     def _parse_types(self, root):
3545         """ Parse types section, which contains all data types e.g. structs, typedefs etcetera. """
3546         types = root.findall("./types/type")
3548         base_types = []
3549         bitmasks = []
3550         defines = []
3551         funcpointers = []
3552         handles = []
3553         structs = []
3555         alias_types = []
3556         for t in types:
3557             type_info = {}
3558             type_info["category"] = t.attrib.get("category", None)
3559             type_info["requires"] = t.attrib.get("requires", None)
3561             # We parse aliases in a second pass when we know more.
3562             alias = t.attrib.get("alias")
3563             if alias:
3564                 LOGGER.debug("Alias found: {0}".format(alias))
3565                 alias_types.append(t)
3566                 continue
3568             if type_info["category"] in ["include"]:
3569                 continue
3571             if type_info["category"] == "basetype":
3572                 name = t.find("name").text
3573                 _type = None
3574                 if not t.find("type") is None:
3575                     _type = t.find("type").text
3576                     tail = t.find("type").tail
3577                     if tail is not None:
3578                         _type += tail.strip()
3579                 basetype = VkBaseType(name, _type)
3580                 base_types.append(basetype)
3581                 type_info["data"] = basetype
3583             # Basic C types don't need us to define them, but we do need data for them
3584             if type_info["requires"] == "vk_platform":
3585                 requires = type_info["requires"]
3586                 basic_c = VkBaseType(name, _type, requires=requires)
3587                 type_info["data"] = basic_c
3589             if type_info["category"] == "bitmask":
3590                 name = t.find("name").text
3591                 _type = t.find("type").text
3593                 # Most bitmasks have a requires attribute used to pull in
3594                 # required '*FlagBits" enum.
3595                 requires = type_info["requires"]
3596                 bitmask = VkBaseType(name, _type, requires=requires)
3597                 bitmasks.append(bitmask)
3598                 type_info["data"] = bitmask
3600             if type_info["category"] == "define":
3601                 define = VkDefine.from_xml(t)
3602                 defines.append(define)
3603                 type_info["data"] = define
3605             if type_info["category"] == "enum":
3606                 name = t.attrib.get("name")
3607                 # The type section only contains enum names, not the actual definition.
3608                 # Since we already parsed the enum before, just link it in.
3609                 try:
3610                     type_info["data"] = self.enums[name]
3611                 except KeyError as e:
3612                     # Not all enums seem to be defined yet, typically that's for
3613                     # ones ending in 'FlagBits' where future extensions may add
3614                     # definitions.
3615                     type_info["data"] = None
3617             if type_info["category"] == "funcpointer":
3618                 funcpointer = VkFunctionPointer.from_xml(t)
3619                 funcpointers.append(funcpointer)
3620                 type_info["data"] = funcpointer
3622             if type_info["category"] == "handle":
3623                 handle = VkHandle.from_xml(t)
3624                 handles.append(handle)
3625                 type_info["data"] = handle
3627             if type_info["category"] in ["struct", "union"]:
3628                 # We store unions among structs as some structs depend
3629                 # on unions. The types are very similar in parsing and
3630                 # generation anyway. The official Vulkan scripts use
3631                 # a similar kind of hack.
3632                 struct = VkStruct.from_xml(t)
3633                 structs.append(struct)
3634                 type_info["data"] = struct
3636             # Name is in general within a name tag else it is an optional
3637             # attribute on the type tag.
3638             name_elem = t.find("name")
3639             if name_elem is not None:
3640                 type_info["name"] = name_elem.text
3641             else:
3642                 type_info["name"] = t.attrib.get("name", None)
3644             # Store all type data in a shared dictionary, so we can easily
3645             # look up information for a given type. There are no duplicate
3646             # names.
3647             self.types[type_info["name"]] = type_info
3649         # Second pass for alias types, so we can retrieve all data from
3650         # the aliased object.
3651         for t in alias_types:
3652             type_info = {}
3653             type_info["category"] = t.attrib.get("category")
3654             type_info["name"] = t.attrib.get("name")
3656             alias = t.attrib.get("alias")
3658             if type_info["category"] == "bitmask":
3659                 bitmask = VkBaseType(type_info["name"], alias, alias=self.types[alias]["data"])
3660                 bitmasks.append(bitmask)
3661                 type_info["data"] = bitmask
3663             if type_info["category"] == "enum":
3664                 enum = VkEnum.from_alias(t, self.types[alias]["data"])
3665                 type_info["data"] = enum
3666                 self.enums[enum.name] = enum
3668             if type_info["category"] == "handle":
3669                 handle = VkHandle.from_alias(t, self.types[alias]["data"])
3670                 handles.append(handle)
3671                 type_info["data"] = handle
3673             if type_info["category"] == "struct":
3674                 struct = VkStruct.from_alias(t, self.types[alias]["data"])
3675                 structs.append(struct)
3676                 type_info["data"] = struct
3678             self.types[type_info["name"]] = type_info
3680         # We need detailed type information during code generation
3681         # on structs for alignment reasons. Unfortunately structs
3682         # are parsed among other types, so there is no guarantee
3683         # that any types needed have been parsed already, so set
3684         # the data now.
3685         for struct in structs:
3686             struct.set_type_info(self.types)
3688             # Alias structures have enum values equivalent to those of the
3689             # structure which they are aliased against. we need to ignore alias
3690             # structs when populating the struct extensions list, otherwise we
3691             # will create duplicate case entries.
3692             if struct.alias:
3693                 continue
3695             for structextend in struct.structextends:
3696                 s = self.types[structextend]["data"]
3697                 s.struct_extensions.append(struct)
3699         # Guarantee everything is sorted, so code generation doesn't have
3700         # to deal with this.
3701         self.base_types = sorted(base_types, key=lambda base_type: base_type.name)
3702         self.bitmasks = sorted(bitmasks, key=lambda bitmask: bitmask.name)
3703         self.defines = defines
3704         self.enums = OrderedDict(sorted(self.enums.items()))
3705         self.funcpointers = sorted(funcpointers, key=lambda fp: fp.name)
3706         self.handles = sorted(handles, key=lambda handle: handle.name)
3707         self.structs = sorted(structs, key=lambda struct: struct.name)
3709 def generate_vulkan_json(f):
3710     f.write("{\n")
3711     f.write("    \"file_format_version\": \"1.0.0\",\n")
3712     f.write("    \"ICD\": {\n")
3713     f.write("        \"library_path\": \".\\\\winevulkan.dll\",\n")
3714     f.write("        \"api_version\": \"{0}\"\n".format(VK_XML_VERSION))
3715     f.write("    }\n")
3716     f.write("}\n")
3718 def set_working_directory():
3719     path = os.path.abspath(__file__)
3720     path = os.path.dirname(path)
3721     os.chdir(path)
3723 def download_vk_xml(filename):
3724     url = "https://raw.githubusercontent.com/KhronosGroup/Vulkan-Docs/v{0}/xml/vk.xml".format(VK_XML_VERSION)
3725     if not os.path.isfile(filename):
3726         urllib.request.urlretrieve(url, filename)
3728 def main():
3729     parser = argparse.ArgumentParser()
3730     parser.add_argument("-v", "--verbose", action="count", default=0, help="increase output verbosity")
3731     parser.add_argument("-x", "--xml", default=None, type=str, help="path to specification XML file")
3733     args = parser.parse_args()
3734     if args.verbose == 0:
3735         LOGGER.setLevel(logging.WARNING)
3736     elif args.verbose == 1:
3737         LOGGER.setLevel(logging.INFO)
3738     else: # > 1
3739         LOGGER.setLevel(logging.DEBUG)
3741     set_working_directory()
3743     if args.xml:
3744         vk_xml = args.xml
3745     else:
3746         vk_xml = "vk-{0}.xml".format(VK_XML_VERSION)
3747         download_vk_xml(vk_xml)
3749     registry = VkRegistry(vk_xml)
3750     generator = VkGenerator(registry)
3752     with open(WINE_VULKAN_H, "w") as f:
3753         generator.generate_vulkan_h(f)
3755     with open(WINE_VULKAN_DRIVER_H, "w") as f:
3756         generator.generate_vulkan_driver_h(f)
3758     with open(WINE_VULKAN_THUNKS_H, "w") as f:
3759         generator.generate_thunks_h(f, "wine_")
3761     with open(WINE_VULKAN_THUNKS_C, "w") as f:
3762         generator.generate_thunks_c(f)
3764     with open(WINE_VULKAN_LOADER_THUNKS_H, "w") as f:
3765         generator.generate_loader_thunks_h(f)
3767     with open(WINE_VULKAN_LOADER_THUNKS_C, "w") as f:
3768         generator.generate_loader_thunks_c(f)
3770     with open(WINE_VULKAN_JSON, "w") as f:
3771         generate_vulkan_json(f)
3773     with open(WINE_VULKAN_SPEC, "w") as f:
3774         generator.generate_vulkan_spec(f)
3776     with open(WINE_VULKAN_LOADER_SPEC, "w") as f:
3777         generator.generate_vulkan_loader_spec(f)
3779 if __name__ == "__main__":
3780     main()