winevulkan: Unwrap params with objecttype.
[wine.git] / dlls / winevulkan / make_vulkan
blob662f1c8144edcd48c95c3708e19ab43b11fb0b29
1 #!/usr/bin/env python3
2 # Wine Vulkan generator
4 # Copyright 2017-2018 Roderick Colenbrander
6 # This library is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU Lesser General Public
8 #  License as published by the Free Software Foundation; either
9 # version 2.1 of the License, or (at your option) any later version.
11 # This library is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 # Lesser General Public License for more details.
16 # You should have received a copy of the GNU Lesser General Public
17 # License along with this library; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 import argparse
22 import logging
23 import os
24 import re
25 import sys
26 import urllib.request
27 import xml.etree.ElementTree as ET
28 from collections import OrderedDict
29 from collections.abc import Sequence
30 from enum import Enum
32 # This script generates code for a Wine Vulkan ICD driver from Vulkan's vk.xml.
33 # Generating the code is like 10x worse than OpenGL, which is mostly a calling
34 # convention passthrough.
36 # The script parses vk.xml and maps functions and types to helper objects. These
37 # helper objects simplify the xml parsing and map closely to the Vulkan types.
38 # The code generation utilizes the helper objects during code generation and
39 # most of the ugly work is carried out by these objects.
41 # Vulkan ICD challenges:
42 # - Vulkan ICD loader (vulkan-1.dll) relies on a section at the start of
43 #   'dispatchable handles' (e.g. VkDevice, VkInstance) for it to insert
44 #   its private data. It uses this area to stare its own dispatch tables
45 #   for loader internal use. This means any dispatchable objects need wrapping.
47 # - Vulkan structures have different alignment between win32 and 32-bit Linux.
48 #   This means structures with alignment differences need conversion logic.
49 #   Often structures are nested, so the parent structure may not need any
50 #   conversion, but some child may need some.
52 # vk.xml parsing challenges:
53 # - Contains type data for all platforms (generic Vulkan, Windows, Linux,..).
54 #   Parsing of extension information required to pull in types and functions
55 #   we really want to generate. Just tying all the data together is tricky.
57 # - Extensions can affect core types e.g. add new enum values, bitflags or
58 #   additional structure chaining through 'pNext' / 'sType'.
60 # - Arrays are used all over the place for parameters or for structure members.
61 #   Array length is often stored in a previous parameter or another structure
62 #   member and thus needs careful parsing.
64 LOGGER = logging.Logger("vulkan")
65 LOGGER.addHandler(logging.StreamHandler())
67 VK_XML_VERSION = "1.2.182"
68 WINE_VK_VERSION = (1, 2)
70 # Filenames to create.
71 WINE_VULKAN_H = "../../include/wine/vulkan.h"
72 WINE_VULKAN_DRIVER_H = "../../include/wine/vulkan_driver.h"
73 WINE_VULKAN_LOADER_SPEC = "../vulkan-1/vulkan-1.spec"
74 WINE_VULKAN_JSON = "winevulkan.json"
75 WINE_VULKAN_SPEC = "winevulkan.spec"
76 WINE_VULKAN_THUNKS_C = "vulkan_thunks.c"
77 WINE_VULKAN_THUNKS_H = "vulkan_thunks.h"
78 WINE_VULKAN_LOADER_THUNKS_C = "loader_thunks.c"
79 WINE_VULKAN_LOADER_THUNKS_H = "loader_thunks.h"
81 # Extension enum values start at a certain offset (EXT_BASE).
82 # Relative to the offset each extension has a block (EXT_BLOCK_SIZE)
83 # of values.
84 # Start for a given extension is:
85 # EXT_BASE + (extension_number-1) * EXT_BLOCK_SIZE
86 EXT_BASE = 1000000000
87 EXT_BLOCK_SIZE = 1000
89 UNSUPPORTED_EXTENSIONS = [
90     # Instance extensions
91     "VK_EXT_headless_surface", # Needs WSI work.
92     "VK_KHR_display", # Needs WSI work.
93     "VK_KHR_surface_protected_capabilities",
95     # Device extensions
96     "VK_AMD_display_native_hdr",
97     "VK_EXT_full_screen_exclusive",
98     "VK_EXT_hdr_metadata", # Needs WSI work.
99     "VK_EXT_pipeline_creation_feedback",
100     "VK_GOOGLE_display_timing",
101     "VK_KHR_external_fence_win32",
102     "VK_KHR_external_memory_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",
108     # Extensions for other platforms
109     "VK_EXT_external_memory_dma_buf",
110     "VK_EXT_image_drm_format_modifier",
111     "VK_EXT_physical_device_drm",
112     "VK_KHR_external_fence_fd",
113     "VK_KHR_external_memory_fd",
114     "VK_KHR_external_semaphore_fd",
116     # Extensions which require callback handling
117     "VK_EXT_device_memory_report",
119     # Extensions which are broken
120     "VK_HUAWEI_subpass_shading", # https://github.com/KhronosGroup/Vulkan-Docs/issues/1564
122     # Deprecated extensions
123     "VK_NV_external_memory_capabilities",
124     "VK_NV_external_memory_win32",
127 # The Vulkan loader provides entry-points for core functionality and important
128 # extensions. Based on vulkan-1.def this amounts to WSI extensions on 1.0.51.
129 CORE_EXTENSIONS = [
130     "VK_KHR_display",
131     "VK_KHR_display_swapchain",
132     "VK_KHR_get_surface_capabilities2",
133     "VK_KHR_surface",
134     "VK_KHR_swapchain",
135     "VK_KHR_win32_surface",
138 # Some experimental extensions are used by shipping applications so their API is extremely unlikely
139 # to change in a backwards-incompatible way. Allow translation of those extensions with WineVulkan.
140 ALLOWED_X_EXTENSIONS = [
141     "VK_NVX_binary_import",
142     "VK_NVX_image_view_handle",
145 # Functions part of our winevulkan graphics driver interface.
146 # DRIVER_VERSION should be bumped on any change to driver interface
147 # in FUNCTION_OVERRIDES
148 DRIVER_VERSION = 10
150 class ThunkType(Enum):
151     NONE = 1
152     PUBLIC = 2
153     PRIVATE = 3
155 # Table of functions for which we have a special implementation.
156 # These are regular device / instance functions for which we need
157 # to do more work compared to a regular thunk or because they are
158 # part of the driver interface.
159 # - dispatch set whether we need a function pointer in the device
160 #   / instance dispatch table.
161 # - driver sets whether the API is part of the driver interface.
162 # - thunk sets whether to create a thunk in vulkan_thunks.c.
163 #   - NONE means there's a fully custom implementation.
164 #   - PUBLIC means the implementation is fully auto generated.
165 #   - PRIVATE thunks can be used in custom implementations for
166 #     struct conversion.
167 # - loader_thunk sets whether to create a thunk for unix_funcs.
168 FUNCTION_OVERRIDES = {
169     # Global functions
170     "vkCreateInstance" : {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE},
171     "vkEnumerateInstanceExtensionProperties" : {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE},
172     "vkEnumerateInstanceLayerProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.NONE},
173     "vkEnumerateInstanceVersion": {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE},
174     "vkGetInstanceProcAddr": {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.NONE},
176     # Instance functions
177     "vkCreateDevice" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
178     "vkDestroyInstance" : {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE },
179     "vkEnumerateDeviceExtensionProperties" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
180     "vkEnumerateDeviceLayerProperties": {"dispatch": True, "driver": False, "thunk": ThunkType.NONE},
181     "vkEnumeratePhysicalDeviceGroups" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
182     "vkEnumeratePhysicalDevices" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
183     "vkGetPhysicalDeviceExternalBufferProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
184     "vkGetPhysicalDeviceExternalFenceProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
185     "vkGetPhysicalDeviceExternalSemaphoreProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
186     "vkGetPhysicalDeviceImageFormatProperties2" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE},
187     "vkGetPhysicalDeviceProperties2" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PUBLIC, "loader_thunk" : ThunkType.PRIVATE},
188     "vkGetPhysicalDeviceProperties2KHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PUBLIC, "loader_thunk" : ThunkType.PRIVATE},
190     # Device functions
191     "vkAllocateCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
192     "vkCreateCommandPool" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
193     "vkDestroyCommandPool" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
194     "vkDestroyDevice" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
195     "vkFreeCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
196     "vkGetDeviceProcAddr" : {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.NONE},
197     "vkGetDeviceQueue" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
198     "vkGetDeviceQueue2" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
200     # VK_KHR_surface
201     "vkDestroySurfaceKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.NONE},
202     "vkGetPhysicalDeviceSurfaceSupportKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
203     "vkGetPhysicalDeviceSurfaceCapabilitiesKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PRIVATE},
204     "vkGetPhysicalDeviceSurfaceFormatsKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
205     "vkGetPhysicalDeviceSurfacePresentModesKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
207     # VK_KHR_get_surface_capabilities2
208     "vkGetPhysicalDeviceSurfaceCapabilities2KHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PRIVATE},
209     "vkGetPhysicalDeviceSurfaceFormats2KHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
211     # VK_KHR_win32_surface
212     "vkCreateWin32SurfaceKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.NONE},
213     "vkGetPhysicalDeviceWin32PresentationSupportKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
215     # VK_KHR_swapchain
216     "vkCreateSwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
217     "vkDestroySwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
218     "vkGetSwapchainImagesKHR": {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
219     "vkQueuePresentKHR": {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
221     # VK_KHR_external_fence_capabilities
222     "vkGetPhysicalDeviceExternalFencePropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
224     # VK_KHR_external_memory_capabilities
225     "vkGetPhysicalDeviceExternalBufferPropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
226     "vkGetPhysicalDeviceImageFormatProperties2KHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE},
228     # VK_KHR_external_semaphore_capabilities
229     "vkGetPhysicalDeviceExternalSemaphorePropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
231     # VK_KHR_device_group_creation
232     "vkEnumeratePhysicalDeviceGroupsKHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
234     # VK_KHR_device_group
235     "vkGetDeviceGroupSurfacePresentModesKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
236     "vkGetPhysicalDevicePresentRectanglesKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
238     # VK_EXT_private_data
239     "vkGetPrivateDataEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
240     "vkSetPrivateDataEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
242     # VK_EXT_calibrated_timestamps
243     "vkGetPhysicalDeviceCalibrateableTimeDomainsEXT" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
244     "vkGetCalibratedTimestampsEXT" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
246     # VK_EXT_debug_utils
247     "vkCreateDebugUtilsMessengerEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
248     "vkDestroyDebugUtilsMessengerEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
249     "vkSubmitDebugUtilsMessageEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.PRIVATE},
250     "vkSetDebugUtilsObjectTagEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.PRIVATE},
251     "vkSetDebugUtilsObjectNameEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.PRIVATE},
253     # VK_EXT_debug_report
254     "vkCreateDebugReportCallbackEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
255     "vkDestroyDebugReportCallbackEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
256     "vkDebugReportMessageEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
258     # VK_EXT_debug_marker
259     "vkDebugMarkerSetObjectNameEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.PRIVATE},
260     "vkDebugMarkerSetObjectTagEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.PRIVATE},
263 STRUCT_CHAIN_CONVERSIONS = {
264     # Ignore to not confuse host loader.
265     "VkDeviceCreateInfo": ["VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO"],
266     "VkInstanceCreateInfo": ["VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO"],
270 class Direction(Enum):
271     """ Parameter direction: input, output, input_output. """
272     INPUT = 1
273     OUTPUT = 2
274     INPUT_OUTPUT = 3
277 class VkBaseType(object):
278     def __init__(self, name, _type, alias=None, requires=None):
279         """ Vulkan base type class.
281         VkBaseType is mostly used by Vulkan to define its own
282         base types like VkFlags through typedef out of e.g. uint32_t.
284         Args:
285             name (:obj:'str'): Name of the base type.
286             _type (:obj:'str'): Underlying type
287             alias (bool): type is an alias or not.
288             requires (:obj:'str', optional): Other types required.
289                 Often bitmask values pull in a *FlagBits type.
290         """
291         self.name = name
292         self.type = _type
293         self.alias = alias
294         self.requires = requires
295         self.required = False
297     def definition(self):
298         # Definition is similar for alias or non-alias as type
299         # is already set to alias.
300         if not self.type is None:
301             return "typedef {0} {1};\n".format(self.type, self.name)
302         else:
303             return "struct {0};\n".format(self.name)
305     def is_alias(self):
306         return bool(self.alias)
309 class VkConstant(object):
310     def __init__(self, name, value):
311         self.name = name
312         self.value = value
314     def definition(self):
315         text = "#define {0} {1}\n".format(self.name, self.value)
316         return text
319 class VkDefine(object):
320     def __init__(self, name, value):
321         self.name = name
322         self.value = value
324     @staticmethod
325     def from_xml(define):
326         name_elem = define.find("name")
328         if name_elem is None:
329             # <type category="define" name="some_name">some_value</type>
330             name = define.attrib.get("name")
332             # We override behavior of VK_USE_64_BIT_PTR_DEFINES as the default non-dispatchable handle
333             # definition various between 64-bit (uses pointers) and 32-bit (uses uint64_t).
334             # This complicates TRACEs in the thunks, so just use uint64_t.
335             if name == "VK_USE_64_BIT_PTR_DEFINES":
336                 value = "#define VK_USE_64_BIT_PTR_DEFINES 0"
337             else:
338                 value = define.text
339             return VkDefine(name, value)
341         # With a name element the structure is like:
342         # <type category="define"><name>some_name</name>some_value</type>
343         name = name_elem.text
345         # Perform minimal parsing for Vulkan constants, which we don't need, but are referenced
346         # elsewhere in vk.xml.
347         # - VK_API_VERSION is a messy, deprecated constant and we don't want generate code for it.
348         # - AHardwareBuffer/ANativeWindow are forward declarations for Android types, which leaked
349         #   into the define region.
350         if name in ["VK_API_VERSION", "AHardwareBuffer", "ANativeWindow", "CAMetalLayer"]:
351             return VkDefine(name, None)
353         # The body of the define is basically unstructured C code. It is not meant for easy parsing.
354         # Some lines contain deprecated values or comments, which we try to filter out.
355         value = ""
356         for line in define.text.splitlines():
357             # Skip comments or deprecated values.
358             if "//" in line:
359                 continue
360             value += line
362         for child in define:
363             value += child.text
364             if child.tail is not None:
365                 # Split comments for VK_API_VERSION_1_0 / VK_API_VERSION_1_1
366                 if "//" in child.tail:
367                     value += child.tail.split("//")[0]
368                 else:
369                     value += child.tail
371         return VkDefine(name, value.rstrip(' '))
373     def definition(self):
374         if self.value is None:
375             return ""
377         # Nothing to do as the value was already put in the right form during parsing.
378         return "{0}\n".format(self.value)
381 class VkEnum(object):
382     def __init__(self, name, bitwidth, alias=None):
383         if not bitwidth in [32, 64]:
384             LOGGER.error("unknown bitwidth {0} for {1}".format(bitwidth, name))
385         self.name = name
386         self.bitwidth = bitwidth
387         self.values = [] if alias == None else alias.values
388         self.required = False
389         self.alias = alias
390         self.aliased_by = []
392     @staticmethod
393     def from_alias(enum, alias):
394         name = enum.attrib.get("name")
395         aliasee = VkEnum(name, alias.bitwidth, alias=alias)
397         alias.add_aliased_by(aliasee)
398         return aliasee
400     @staticmethod
401     def from_xml(enum):
402         name = enum.attrib.get("name")
403         bitwidth = int(enum.attrib.get("bitwidth", "32"))
404         result = VkEnum(name, bitwidth)
406         for v in enum.findall("enum"):
407             value_name = v.attrib.get("name")
408             # Value is either a value or a bitpos, only one can exist.
409             value = v.attrib.get("value")
410             alias_name = v.attrib.get("alias")
411             if alias_name:
412                 result.create_alias(value_name, alias_name)
413             elif value:
414                 result.create_value(value_name, value)
415             else:
416                 # bitmask
417                 result.create_bitpos(value_name, int(v.attrib.get("bitpos")))
419         if bitwidth == 32:
420             # vulkan.h contains a *_MAX_ENUM value set to 32-bit at the time of writing,
421             # which is to prepare for extensions as they can add values and hence affect
422             # the size definition.
423             max_name = re.sub(r'([0-9a-z_])([A-Z0-9])',r'\1_\2', name).upper() + "_MAX_ENUM"
424             result.create_value(max_name, "0x7fffffff")
426         return result
428     def create_alias(self, name, alias_name):
429         """ Create an aliased value for this enum """
430         # Older GCC versions need a literal to initialize a static const uint64_t
431         # which is what we use for 64bit bitmasks.
432         if self.bitwidth == 64:
433             alias = next(x for x in self.values if x.name == alias_name)
434             self.add(VkEnumValue(name, self.bitwidth, value=alias.value, hex=alias.hex, alias=alias_name))
435         else:
436             self.add(VkEnumValue(name, self.bitwidth, alias=alias_name))
438     def create_value(self, name, value):
439         """ Create a new value for this enum """
440         # Some values are in hex form. We want to preserve the hex representation
441         # at least when we convert back to a string. Internally we want to use int.
442         hex = "0x" in value
443         self.add(VkEnumValue(name, self.bitwidth, value=int(value, 0), hex=hex))
445     def create_bitpos(self, name, pos):
446         """ Create a new bitmask value for this enum """
447         self.add(VkEnumValue(name, self.bitwidth, value=(1 << pos), hex=True))
449     def add(self, value):
450         """ Add a value to enum. """
452         # Extensions can add new enum values. When an extension is promoted to Core
453         # the registry defines the value twice once for old extension and once for
454         # new Core features. Add the duplicate if it's explicitly marked as an
455         # alias, otherwise ignore it.
456         for v in self.values:
457             if not value.is_alias() and v.value == value.value:
458                 LOGGER.debug("Adding duplicate enum value {0} to {1}".format(v, self.name))
459                 return
460         # Avoid adding duplicate aliases multiple times
461         if not any(x.name == value.name for x in self.values):
462             self.values.append(value)
464     def definition(self):
465         if self.is_alias():
466             return ""
468         default_value = 0x7ffffffe if self.bitwidth == 32 else 0xfffffffffffffffe
470         # Print values sorted, values can have been added in a random order.
471         values = sorted(self.values, key=lambda value: value.value if value.value is not None else default_value)
473         if self.bitwidth == 32:
474             text = "typedef enum {0}\n{{\n".format(self.name)
475             for value in values:
476                 text += "    {0},\n".format(value.definition())
477             text += "}} {0};\n".format(self.name)
478         elif self.bitwidth == 64:
479             text = "typedef VkFlags64 {0};\n\n".format(self.name)
480             for value in values:
481                 text += "static const {0} {1};\n".format(self.name, value.definition())
483         for aliasee in self.aliased_by:
484             text += "typedef {0} {1};\n".format(self.name, aliasee.name)
486         text += "\n"
487         return text
489     def is_alias(self):
490         return bool(self.alias)
492     def add_aliased_by(self, aliasee):
493         self.aliased_by.append(aliasee)
496 class VkEnumValue(object):
497     def __init__(self, name, bitwidth, value=None, hex=False, alias=None):
498         self.name = name
499         self.bitwidth = bitwidth
500         self.value = value
501         self.hex = hex
502         self.alias = alias
504     def __repr__(self):
505         postfix = "ull" if self.bitwidth == 64 else ""
506         if self.is_alias() and self.value == None:
507             return "{0}={1}".format(self.name, self.alias)
508         return "{0}={1}{2}".format(self.name, self.value, postfix)
510     def definition(self):
511         """ Convert to text definition e.g. VK_FOO = 1 """
512         postfix = "ull" if self.bitwidth == 64 else ""
513         if self.is_alias() and self.value == None:
514             return "{0} = {1}".format(self.name, self.alias)
516         # Hex is commonly used for FlagBits and sometimes within
517         # a non-FlagBits enum for a bitmask value as well.
518         if self.hex:
519             return "{0} = 0x{1:08x}{2}".format(self.name, self.value, postfix)
520         else:
521             return "{0} = {1}{2}".format(self.name, self.value, postfix)
523     def is_alias(self):
524         return self.alias is not None
527 class VkFunction(object):
528     def __init__(self, _type=None, name=None, params=[], extensions=[], alias=None):
529         self.extensions = []
530         self.name = name
531         self.type = _type
532         self.params = params
533         self.alias = alias
535         # For some functions we need some extra metadata from FUNCTION_OVERRIDES.
536         func_info = FUNCTION_OVERRIDES.get(self.name, None)
537         self.dispatch = func_info["dispatch"] if func_info else True
538         self.driver = func_info["driver"] if func_info else False
539         self.thunk_type = func_info["thunk"] if func_info else ThunkType.PUBLIC
540         self.loader_thunk_type = func_info["loader_thunk"] if func_info and "loader_thunk" in func_info else ThunkType.PUBLIC
542         # Required is set while parsing which APIs and types are required
543         # and is used by the code generation.
544         self.required = True if func_info else False
546     @staticmethod
547     def from_alias(command, alias):
548         """ Create VkFunction from an alias command.
550         Args:
551             command: xml data for command
552             alias (VkFunction): function to use as a base for types / parameters.
554         Returns:
555             VkFunction
556         """
557         func_name = command.attrib.get("name")
558         func_type = alias.type
559         params = alias.params
561         return VkFunction(_type=func_type, name=func_name, params=params, alias=alias)
563     @staticmethod
564     def from_xml(command, types):
565         proto = command.find("proto")
566         func_name = proto.find("name").text
567         func_type = proto.find("type").text
569         params = []
570         for param in command.findall("param"):
571             vk_param = VkParam.from_xml(param, types)
572             params.append(vk_param)
574         return VkFunction(_type=func_type, name=func_name, params=params)
576     def get_conversions(self):
577         """ Get a list of conversion functions required for this function if any.
578         Parameters which are structures may require conversion between win32
579         and the host platform. This function returns a list of conversions
580         required.
581         """
583         conversions = []
584         for param in self.params:
585             convs = param.get_conversions()
586             if convs is not None:
587                 conversions.extend(convs)
589         return conversions
591     def is_alias(self):
592         return bool(self.alias)
594     def is_core_func(self):
595         """ Returns whether the function is a Vulkan core function.
596         Core functions are APIs defined by the Vulkan spec to be part of the
597         Core API as well as several KHR WSI extensions.
598         """
600         if not self.extensions:
601             return True
603         return any(ext in self.extensions for ext in CORE_EXTENSIONS)
605     def is_device_func(self):
606         # If none of the other, it must be a device function
607         return not self.is_global_func() and not self.is_instance_func() and not self.is_phys_dev_func()
609     def is_driver_func(self):
610         """ Returns if function is part of Wine driver interface. """
611         return self.driver
613     def is_global_func(self):
614         # Treat vkGetInstanceProcAddr as a global function as it
615         # can operate with NULL for vkInstance.
616         if self.name == "vkGetInstanceProcAddr":
617             return True
618         # Global functions are not passed a dispatchable object.
619         elif self.params[0].is_dispatchable():
620             return False
621         return True
623     def is_instance_func(self):
624         # Instance functions are passed VkInstance.
625         if self.params[0].type == "VkInstance":
626             return True
627         return False
629     def is_phys_dev_func(self):
630         # Physical device functions are passed VkPhysicalDevice.
631         if self.params[0].type == "VkPhysicalDevice":
632             return True
633         return False
635     def is_required(self):
636         return self.required
638     def needs_conversion(self):
639         """ Check if the function needs any input/output type conversion.
640         Functions need input/output conversion if struct parameters have
641         alignment differences between Win32 and Linux 32-bit.
642         """
644         for p in self.params:
645             if p.needs_conversion():
646                 LOGGER.debug("Parameter {0} to {1} requires conversion".format(p.name, self.name))
647                 return True
649         return False
651     def needs_unwrapping(self):
652         """ Check if the function needs any input/output type unwrapping.
653         Functions need input/output unwrapping if struct parameters have
654         wrapped handles.
655         """
657         for p in self.params:
658             if p.needs_unwrapping():
659                 return True
661         return False
663     def needs_dispatch(self):
664         return self.dispatch
666     def needs_thunk(self):
667         return self.thunk_type != ThunkType.NONE
669     def needs_private_thunk(self):
670         return self.thunk_type == ThunkType.PRIVATE
672     def pfn(self, prefix="p", call_conv=None, conv=False):
673         """ Create function pointer. """
675         if call_conv:
676             pfn = "{0} ({1} *{2}_{3})(".format(self.type, call_conv, prefix, self.name)
677         else:
678             pfn = "{0} (*{1}_{2})(".format(self.type, prefix, self.name)
680         for i, param in enumerate(self.params):
681             if param.const:
682                 pfn += param.const + " "
684             pfn += param.type
685             if conv and param.needs_conversion():
686                 pfn += "_host"
688             if param.is_pointer():
689                 pfn += " " + param.pointer
691             if param.array_len is not None:
692                 pfn += "[{0}]".format(param.array_len)
694             if i < len(self.params) - 1:
695                 pfn += ", "
696         pfn += ")"
697         return pfn
699     def prototype(self, call_conv=None, prefix=None, postfix=None):
700         """ Generate prototype for given function.
702         Args:
703             call_conv (str, optional): calling convention e.g. WINAPI
704             prefix (str, optional): prefix to append prior to function name e.g. vkFoo -> wine_vkFoo
705             postfix (str, optional): text to append after function name but prior to semicolon e.g. DECLSPEC_HIDDEN
706         """
708         proto = "{0}".format(self.type)
710         if call_conv is not None:
711             proto += " {0}".format(call_conv)
713         if prefix is not None:
714             proto += " {0}{1}(".format(prefix, self.name)
715         else:
716             proto += " {0}(".format(self.name)
718         # Add all the parameters.
719         proto += ", ".join([p.definition() for p in self.params])
721         if postfix is not None:
722             proto += ") {0}".format(postfix)
723         else:
724             proto += ")"
726         return proto
728     def body(self):
729         body = ""
731         if not self.needs_private_thunk():
732             body += "    {0}".format(self.trace())
734         params = ", ".join([p.variable(conv=False) for p in self.params])
736         # Call the native Vulkan function.
737         if self.type == "void":
738             body += "    {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
739         else:
740             body += "    return {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
742         return body
744     def loader_body(self):
745         body = ""
747         params = ", ".join([p.name for p in self.params])
749         # Call the function from unix_funcs.
750         if self.type == "void":
751             body += "    unix_funcs->p_{0}({1});\n".format(self.name, params)
752         else:
753             body += "    return unix_funcs->p_{0}({1});\n".format(self.name, params)
755         return body
757     def body_conversion(self, conv):
758         body = ""
760         # Declare a variable to hold the result for non-void functions.
761         if self.type != "void":
762             body += "    {0} result;\n".format(self.type)
764         # Declare any tmp parameters for conversion.
765         for p in self.params:
766             if p.needs_conversion() and conv:
767                 if p.is_dynamic_array():
768                     body += "    {0}_host *{1}_host;\n".format(p.type, p.name)
769                 else:
770                     body += "    {0}_host {1}_host;\n".format(p.type, p.name)
771             elif p.needs_unwrapping():
772                 if p.is_dynamic_array():
773                     body += "    {0} *{1}_host;\n".format(p.type, p.name)
774                 else:
775                     body += "    {0} {1}_host;\n".format(p.type, p.name)
777         if not self.needs_private_thunk():
778             body += "    {0}\n".format(self.trace())
780         # Call any win_to_host conversion calls.
781         for p in self.params:
782             if p.needs_input_conversion() and (p.needs_unwrapping() or conv):
783                 body += p.copy(Direction.INPUT)
785         # Build list of parameters containing converted and non-converted parameters.
786         # The param itself knows if conversion is needed and applies it when we set conv=True.
787         params = ", ".join([p.variable(conv=conv) for p in self.params])
789         # Call the native Vulkan function.
790         if self.type == "void":
791             body += "    {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
792         else:
793             body += "    result = {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
795         body += "\n"
797         # Call any host_to_win conversion calls.
798         for p in self.params:
799             if not p.needs_output_conversion():
800                 continue
802             body += p.copy(Direction.OUTPUT)
804         # Perform any required cleanups. Most of these are for array functions.
805         for p in self.params:
806             if p.needs_free() and (p.needs_unwrapping() or conv):
807                 body += p.free()
809         # Finally return the result.
810         if self.type != "void":
811             body += "    return result;\n"
813         return body
815     def spec(self, prefix=None, symbol=None):
816         """ Generate spec file entry for this function.
818         Args
819             prefix (str, optional): prefix to prepend to entry point name.
820             symbol (str, optional): allows overriding the name of the function implementing the entry point.
821         """
823         spec = ""
824         params = " ".join([p.spec() for p in self.params])
825         if prefix is not None:
826             spec += "@ stdcall -private {0}{1}({2})".format(prefix, self.name, params)
827         else:
828             spec += "@ stdcall {0}({1})".format(self.name, params)
830         if symbol is not None:
831             spec += " " + symbol
833         spec += "\n"
834         return spec
836     def stub(self, call_conv=None, prefix=None):
837         stub = self.prototype(call_conv=call_conv, prefix=prefix)
838         stub += "\n{\n"
839         stub += "    {0}".format(self.trace(message="stub: ", trace_func="FIXME"))
841         if self.type == "VkResult":
842             stub += "    return VK_ERROR_OUT_OF_HOST_MEMORY;\n"
843         elif self.type == "VkBool32":
844             stub += "    return VK_FALSE;\n"
845         elif self.type == "PFN_vkVoidFunction":
846             stub += "    return NULL;\n"
848         stub += "}\n\n"
849         return stub
851     def thunk(self, call_conv=None, prefix=None):
852         thunk = self.prototype(call_conv=call_conv, prefix=prefix)
853         thunk += "\n{\n"
855         if self.needs_conversion():
856             thunk += "#if defined(USE_STRUCT_CONVERSION)\n"
857             thunk += self.body_conversion(conv=True)
858             thunk += "#else\n"
859             if self.needs_unwrapping():
860                 thunk += self.body_conversion(conv=False)
861             else:
862                 thunk += self.body()
863             thunk += "#endif\n"
864         elif self.needs_unwrapping():
865             thunk += self.body_conversion(conv=False)
866         else:
867             thunk += self.body()
869         thunk += "}\n\n"
870         return thunk
872     def loader_thunk(self, prefix=None):
873         thunk = self.prototype(call_conv="WINAPI", prefix=prefix)
874         thunk += "\n{\n"
875         thunk += self.loader_body()
876         thunk += "}\n\n"
877         return thunk
879     def trace(self, message=None, trace_func=None):
880         """ Create a trace string including all parameters.
882         Args:
883             message (str, optional): text to print at start of trace message e.g. 'stub: '
884             trace_func (str, optional): used to override trace function e.g. FIXME, printf, etcetera.
885         """
886         if trace_func is not None:
887             trace = "{0}(\"".format(trace_func)
888         else:
889             trace = "TRACE(\""
891         if message is not None:
892             trace += message
894         # First loop is for all the format strings.
895         trace += ", ".join([p.format_string() for p in self.params])
896         trace += "\\n\""
898         # Second loop for parameter names and optional conversions.
899         for param in self.params:
900             if param.format_conv is not None:
901                 trace += ", " + param.format_conv.format(param.name)
902             else:
903                 trace += ", {0}".format(param.name)
904         trace += ");\n"
906         return trace
909 class VkFunctionPointer(object):
910     def __init__(self, _type, name, members, forward_decls):
911         self.name = name
912         self.members = members
913         self.type = _type
914         self.required = False
915         self.forward_decls = forward_decls
917     @staticmethod
918     def from_xml(funcpointer):
919         members = []
920         begin = None
922         for t in funcpointer.findall("type"):
923             # General form:
924             # <type>void</type>*       pUserData,
925             # Parsing of the tail (anything past </type>) is tricky since there
926             # can be other data on the next line like: const <type>int</type>..
928             const = True if begin and "const" in begin else False
929             _type = t.text
930             lines = t.tail.split(",\n")
931             if lines[0][0] == "*":
932                 pointer = "*"
933                 name = lines[0][1:].strip()
934             else:
935                 pointer = None
936                 name = lines[0].strip()
938             # Filter out ); if it is contained.
939             name = name.partition(");")[0]
941             # If tail encompasses multiple lines, assign the second line to begin
942             # for the next line.
943             try:
944                 begin = lines[1].strip()
945             except IndexError:
946                 begin = None
948             members.append(VkMember(const=const, _type=_type, pointer=pointer, name=name))
950         _type = funcpointer.text
951         name = funcpointer.find("name").text
952         if "requires" in funcpointer.attrib:
953             forward_decls = funcpointer.attrib.get("requires").split(",")
954         else:
955             forward_decls = []
956         return VkFunctionPointer(_type, name, members, forward_decls)
958     def definition(self):
959         text = ""
960         # forward declare required structs
961         for decl in self.forward_decls:
962             text += "typedef struct {0} {0};\n".format(decl)
964         text += "{0} {1})(\n".format(self.type, self.name)
966         first = True
967         if len(self.members) > 0:
968             for m in self.members:
969                 if first:
970                     text += "    " + m.definition()
971                     first = False
972                 else:
973                     text += ",\n    " + m.definition()
974         else:
975             # Just make the compiler happy by adding a void parameter.
976             text += "void"
977         text += ");\n"
978         return text
980     def is_alias(self):
981         return False
983 class VkHandle(object):
984     def __init__(self, name, _type, parent, alias=None):
985         self.name = name
986         self.type = _type
987         self.parent = parent
988         self.alias = alias
989         self.required = False
990         self.object_type = None
992     @staticmethod
993     def from_alias(handle, alias):
994         name = handle.attrib.get("name")
995         return VkHandle(name, alias.type, alias.parent, alias=alias)
997     @staticmethod
998     def from_xml(handle):
999         name = handle.find("name").text
1000         _type = handle.find("type").text
1001         parent = handle.attrib.get("parent") # Most objects have a parent e.g. VkQueue has VkDevice.
1002         return VkHandle(name, _type, parent)
1004     def dispatch_table(self):
1005         if not self.is_dispatchable():
1006             return None
1008         if self.parent is None:
1009             # Should only happen for VkInstance
1010             return "funcs"
1011         elif self.name == "VkDevice":
1012             # VkDevice has VkInstance as a parent, but has its own dispatch table.
1013             return "funcs"
1014         elif self.parent in ["VkInstance", "VkPhysicalDevice"]:
1015             return "instance->funcs"
1016         elif self.parent in ["VkDevice", "VkCommandPool"]:
1017             return "device->funcs"
1018         else:
1019             LOGGER.error("Unhandled dispatchable parent: {0}".format(self.parent))
1021     def definition(self):
1022         """ Generates handle definition e.g. VK_DEFINE_HANDLE(vkInstance) """
1024         # Legacy types are typedef'ed to the new type if they are aliases.
1025         if self.is_alias():
1026             return "typedef {0} {1};\n".format(self.alias.name, self.name)
1028         return "{0}({1})\n".format(self.type, self.name)
1030     def is_alias(self):
1031         return self.alias is not None
1033     def is_dispatchable(self):
1034         """ Some handles like VkInstance, VkDevice are dispatchable objects,
1035         which means they contain a dispatch table of function pointers.
1036         """
1037         return self.type == "VK_DEFINE_HANDLE"
1039     def is_required(self):
1040         return self.required
1042     def native_handle(self, name):
1043         """ Provide access to the native handle of a wrapped object. """
1045         if self.name == "VkCommandPool":
1046             return "wine_cmd_pool_from_handle({0})->command_pool".format(name)
1047         if self.name == "VkDebugUtilsMessengerEXT":
1048             return "wine_debug_utils_messenger_from_handle({0})->debug_messenger".format(name)
1049         if self.name == "VkDebugReportCallbackEXT":
1050             return "wine_debug_report_callback_from_handle({0})->debug_callback".format(name)
1051         if self.name == "VkSurfaceKHR":
1052             return "wine_surface_from_handle({0})->surface".format(name)
1054         native_handle_name = None
1056         if self.name == "VkCommandBuffer":
1057             native_handle_name = "command_buffer"
1058         if self.name == "VkDevice":
1059             native_handle_name = "device"
1060         if self.name == "VkInstance":
1061             native_handle_name = "instance"
1062         if self.name == "VkPhysicalDevice":
1063             native_handle_name = "phys_dev"
1064         if self.name == "VkQueue":
1065             native_handle_name = "queue"
1067         if native_handle_name:
1068             return "{0}->{1}".format(name, native_handle_name)
1070         if self.is_dispatchable():
1071             LOGGER.error("Unhandled native handle for: {0}".format(self.name))
1072         return None
1074     def driver_handle(self, name):
1075         """ Provide access to the handle that should be passed to the wine driver """
1077         if self.name == "VkSurfaceKHR":
1078             return "wine_surface_from_handle({0})->driver_surface".format(name)
1080         return self.native_handle(name)
1082     def is_wrapped(self):
1083         return self.native_handle("test") is not None
1085     def needs_conversion(self):
1086         return False
1088     def needs_unwrapping(self):
1089         return self.is_wrapped()
1091 class VkMember(object):
1092     def __init__(self, const=False, struct_fwd_decl=False,_type=None, pointer=None, name=None, array_len=None,
1093             dyn_array_len=None, optional=False, values=None):
1094         self.const = const
1095         self.struct_fwd_decl = struct_fwd_decl
1096         self.name = name
1097         self.pointer = pointer
1098         self.type = _type
1099         self.type_info = None
1100         self.array_len = array_len
1101         self.dyn_array_len = dyn_array_len
1102         self.optional = optional
1103         self.values = values
1105     def __eq__(self, other):
1106         """ Compare member based on name against a string.
1108         This method is for convenience by VkStruct, which holds a number of members and needs quick checking
1109         if certain members exist.
1110         """
1112         return self.name == other
1114     def __repr__(self):
1115         return "{0} {1} {2} {3} {4} {5} {6}".format(self.const, self.struct_fwd_decl, self.type, self.pointer,
1116                 self.name, self.array_len, self.dyn_array_len)
1118     @staticmethod
1119     def from_xml(member):
1120         """ Helper function for parsing a member tag within a struct or union. """
1122         name_elem = member.find("name")
1123         type_elem = member.find("type")
1125         const = False
1126         struct_fwd_decl = False
1127         member_type = None
1128         pointer = None
1129         array_len = None
1131         values = member.get("values")
1133         if member.text:
1134             if "const" in member.text:
1135                 const = True
1137             # Some members contain forward declarations:
1138             # - VkBaseInstructure has a member "const struct VkBaseInStructure *pNext"
1139             # - VkWaylandSurfaceCreateInfoKHR has a member "struct wl_display *display"
1140             if "struct" in member.text:
1141                 struct_fwd_decl = True
1143         if type_elem is not None:
1144             member_type = type_elem.text
1145             if type_elem.tail is not None:
1146                 pointer = type_elem.tail.strip() if type_elem.tail.strip() != "" else None
1148         # Name of other member within, which stores the number of
1149         # elements pointed to be by this member.
1150         dyn_array_len = member.get("len")
1152         # Some members are optional, which is important for conversion code e.g. not dereference NULL pointer.
1153         optional = True if member.get("optional") else False
1155         # Usually we need to allocate memory for dynamic arrays. We need to do the same in a few other cases
1156         # like for VkCommandBufferBeginInfo.pInheritanceInfo. Just threat such cases as dynamic arrays of
1157         # size 1 to simplify code generation.
1158         if dyn_array_len is None and pointer is not None:
1159             dyn_array_len = 1
1161         # Some members are arrays, attempt to parse these. Formats include:
1162         # <member><type>char</type><name>extensionName</name>[<enum>VK_MAX_EXTENSION_NAME_SIZE</enum>]</member>
1163         # <member><type>uint32_t</type><name>foo</name>[4]</member>
1164         if name_elem.tail and name_elem.tail[0] == '[':
1165             LOGGER.debug("Found array type")
1166             enum_elem = member.find("enum")
1167             if enum_elem is not None:
1168                 array_len = enum_elem.text
1169             else:
1170                 # Remove brackets around length
1171                 array_len = name_elem.tail.strip("[]")
1173         return VkMember(const=const, struct_fwd_decl=struct_fwd_decl, _type=member_type, pointer=pointer, name=name_elem.text,
1174                 array_len=array_len, dyn_array_len=dyn_array_len, optional=optional, values=values)
1176     def copy(self, input, output, direction, conv):
1177         """ Helper method for use by conversion logic to generate a C-code statement to copy this member.
1178             - `conv` indicates whether the statement is in a struct alignment conversion path. """
1180         if (conv and self.needs_conversion()) or self.needs_unwrapping():
1181             if self.is_dynamic_array():
1182                 if direction == Direction.OUTPUT:
1183                     LOGGER.warn("TODO: implement copying of returnedonly dynamic array for {0}.{1}".format(self.type, self.name))
1184                 else:
1185                     # Array length is either a variable name (string) or an int.
1186                     count = self.dyn_array_len if isinstance(self.dyn_array_len, int) else "{0}{1}".format(input, self.dyn_array_len)
1187                     return "{0}{1} = convert_{2}_array_win_to_host({3}{1}, {4});\n".format(output, self.name, self.type, input, count)
1188             elif self.is_static_array():
1189                 count = self.array_len
1190                 if direction == Direction.OUTPUT:
1191                     # Needed by VkMemoryHeap.memoryHeaps
1192                     return "convert_{0}_static_array_host_to_win({2}{1}, {3}{1}, {4});\n".format(self.type, self.name, input, output, count)
1193                 else:
1194                     # Nothing needed this yet.
1195                     LOGGER.warn("TODO: implement copying of static array for {0}.{1}".format(self.type, self.name))
1196             elif self.is_handle() and self.needs_unwrapping():
1197                 if direction == Direction.OUTPUT:
1198                     LOGGER.err("OUTPUT parameter {0}.{1} cannot be unwrapped".format(self.type, self.name))
1199                 else:
1200                     handle = self.type_info["data"]
1201                     return "{0}{1} = {2};\n".format(output, self.name, handle.driver_handle("{0}{1}".format(input, self.name)))
1202             else:
1203                 if direction == Direction.OUTPUT:
1204                     return "convert_{0}_host_to_win(&{2}{1}, &{3}{1});\n".format(self.type, self.name, input, output)
1205                 else:
1206                     return "convert_{0}_win_to_host(&{2}{1}, &{3}{1});\n".format(self.type, self.name, input, output)
1207         elif self.is_static_array():
1208             bytes_count = "{0} * sizeof({1})".format(self.array_len, self.type)
1209             return "memcpy({0}{1}, {2}{1}, {3});\n".format(output, self.name, input, bytes_count)
1210         else:
1211             return "{0}{1} = {2}{1};\n".format(output, self.name, input)
1213     def free(self, location, conv):
1214         """ Helper method for use by conversion logic to generate a C-code statement to free this member. """
1216         if not self.needs_unwrapping() and not conv:
1217             return ""
1219         # Add a cast to ignore const on conversion structs we allocated ourselves.
1220         # sample expected output: (VkSparseMemoryBind_host *)
1221         if self.is_const():
1222             cast = "(" + self.type
1223             if self.needs_conversion() and conv:
1224                 cast += "_host"
1225             cast += " *)"
1226         else:
1227             cast = ""
1229         if self.is_dynamic_array():
1230             count = self.dyn_array_len if isinstance(self.dyn_array_len, int) else "{0}{1}".format(location, self.dyn_array_len)
1231             if self.is_struct() and self.type_info["data"].returnedonly:
1232                 # For returnedonly, counts is stored in a pointer.
1233                 return "free_{0}_array({1}{2}{3}, *{4});\n".format(self.type, cast, location, self.name, count)
1234             else:
1235                 return "free_{0}_array({1}{2}{3}, {4});\n".format(self.type, cast, location, self.name, count)
1236         else:
1237             # We are operating on a single structure. Some structs (very rare) contain dynamic members,
1238             # which would need freeing.
1239             if self.needs_free():
1240                 return "free_{0}({1}&{2}{3});\n".format(self.type, cast, location, self.name)
1241         return ""
1243     def definition(self, align=False, conv=False):
1244         """ Generate prototype for given function.
1246         Args:
1247             align (bool, optional): Enable alignment if a type needs it. This adds WINE_VK_ALIGN(8) to a member.
1248             conv (bool, optional): Enable conversion if a type needs it. This appends '_host' to the name.
1249         """
1251         text = ""
1252         if self.is_const():
1253             text += "const "
1255         if self.is_struct_forward_declaration():
1256             text += "struct "
1258         if conv and self.is_struct():
1259             text += "{0}_host".format(self.type)
1260         else:
1261             text += self.type
1263         if self.is_pointer():
1264             text += " {0}{1}".format(self.pointer, self.name)
1265         else:
1266             if align and self.needs_alignment():
1267                 text += " WINE_VK_ALIGN(8) " + self.name
1268             else:
1269                 text += " " + self.name
1271         if self.is_static_array():
1272             text += "[{0}]".format(self.array_len)
1274         return text
1276     def get_conversions(self):
1277         """ Return any conversion description for this member and its children when conversion is needed. """
1279         # Check if we need conversion either for this member itself or for any child members
1280         # in case member represents a struct.
1281         if not self.needs_conversion() and not self.needs_unwrapping():
1282             return None
1284         conversions = []
1286         # Collect any conversion for any member structs.
1287         if self.is_struct():
1288             struct = self.type_info["data"]
1289             for m in struct:
1290                 m.needs_struct_extensions_conversion()
1291                 if m.needs_conversion() or m.needs_unwrapping():
1292                     conversions.extend(m.get_conversions())
1294             struct.needs_struct_extensions_conversion()
1295             direction = Direction.OUTPUT if struct.returnedonly else Direction.INPUT
1296         elif self.is_handle():
1297             direction = Direction.INPUT
1299         operand = self.type_info["data"]
1300         if self.is_dynamic_array():
1301             conversions.append(ConversionFunction(False, True, direction, operand))
1302         elif self.is_static_array():
1303             conversions.append(ConversionFunction(True, False, direction, operand))
1304         else:
1305             conversions.append(ConversionFunction(False, False, direction, operand))
1307         if self.needs_free():
1308             conversions.append(FreeFunction(self.is_dynamic_array(), operand))
1310         return conversions
1312     def is_const(self):
1313         return self.const
1315     def is_dynamic_array(self):
1316         """ Returns if the member is an array element.
1317         Vulkan uses this for dynamically sized arrays for which
1318         there is a 'count' parameter.
1319         """
1320         return self.dyn_array_len is not None
1322     def is_handle(self):
1323         return self.type_info["category"] == "handle"
1325     def is_pointer(self):
1326         return self.pointer is not None
1328     def is_static_array(self):
1329         """ Returns if the member is an array.
1330         Vulkan uses this often for fixed size arrays in which the
1331         length is part of the member.
1332         """
1333         return self.array_len is not None
1335     def is_struct(self):
1336         return self.type_info["category"] == "struct"
1338     def is_struct_forward_declaration(self):
1339         return self.struct_fwd_decl
1341     def is_union(self):
1342         return self.type_info["category"] == "union"
1344     def needs_alignment(self):
1345         """ Check if this member needs alignment for 64-bit data.
1346         Various structures need alignment on 64-bit variables due
1347         to compiler differences on 32-bit between Win32 and Linux.
1348         """
1350         if self.is_pointer():
1351             return False
1352         elif self.type == "size_t":
1353             return False
1354         elif self.type in ["uint64_t", "VkDeviceSize"]:
1355             return True
1356         elif self.is_struct():
1357             struct = self.type_info["data"]
1358             return struct.needs_alignment()
1359         elif self.is_handle():
1360             # Dispatchable handles are pointers to objects, while
1361             # non-dispatchable are uint64_t and hence need alignment.
1362             handle = self.type_info["data"]
1363             return False if handle.is_dispatchable() else True
1364         return False
1366     def needs_conversion(self):
1367         """ Structures requiring alignment, need conversion between win32 and host. """
1369         if not self.is_struct():
1370             return False
1372         struct = self.type_info["data"]
1373         return struct.needs_conversion()
1375     def needs_unwrapping(self):
1376         """ Structures with wrapped handles need unwrapping. """
1378         if self.is_struct():
1379             struct = self.type_info["data"]
1380             return struct.needs_unwrapping()
1382         if self.is_handle():
1383             handle = self.type_info["data"]
1384             return handle.is_wrapped()
1386         return False
1388     def needs_free(self):
1389         if not self.needs_conversion() and not self.needs_unwrapping():
1390             return False
1392         if self.is_dynamic_array():
1393             return True
1395         # TODO: some non-pointer structs and optional pointer structs may need freeing,
1396         # though none of this type have been encountered yet.
1397         return False
1399     def needs_struct_extensions_conversion(self):
1400         if not self.is_struct():
1401             return False
1403         struct = self.type_info["data"]
1404         return struct.needs_struct_extensions_conversion()
1406     def set_type_info(self, type_info):
1407         """ Helper function to set type information from the type registry.
1408         This is needed, because not all type data is available at time of
1409         parsing.
1410         """
1411         self.type_info = type_info
1414 class VkParam(object):
1415     """ Helper class which describes a parameter to a function call. """
1417     def __init__(self, type_info, const=None, pointer=None, name=None, array_len=None, dyn_array_len=None, object_type=None):
1418         self.const = const
1419         self.name = name
1420         self.array_len = array_len
1421         self.dyn_array_len = dyn_array_len
1422         self.pointer = pointer
1423         self.object_type = object_type
1424         self.type_info = type_info
1425         self.type = type_info["name"] # For convenience
1426         self.handle = type_info["data"] if type_info["category"] == "handle" else None
1427         self.struct = type_info["data"] if type_info["category"] == "struct" else None
1429         self._set_direction()
1430         self._set_format_string()
1431         self._set_conversions()
1433     def __repr__(self):
1434         return "{0} {1} {2} {3} {4} {5}".format(self.const, self.type, self.pointer, self.name, self.array_len, self.dyn_array_len)
1436     @staticmethod
1437     def from_xml(param, types):
1438         """ Helper function to create VkParam from xml. """
1440         # Parameter parsing is slightly tricky. All the data is contained within
1441         # a param tag, but some data is within subtags while others are text
1442         # before or after the type tag.
1443         # Common structure:
1444         # <param>const <type>char</type>* <name>pLayerName</name></param>
1446         name_elem = param.find("name")
1447         array_len = None
1448         name = name_elem.text
1449         # Tail contains array length e.g. for blendConstants param of vkSetBlendConstants
1450         if name_elem.tail is not None:
1451             array_len = name_elem.tail.strip("[]")
1453         # Name of other parameter in function prototype, which stores the number of
1454         # elements pointed to be by this parameter.
1455         dyn_array_len = param.get("len", None)
1457         const = param.text.strip() if param.text else None
1458         type_elem = param.find("type")
1459         pointer = type_elem.tail.strip() if type_elem.tail.strip() != "" else None
1461         # Some uint64_t are actually handles with a separate type param
1462         object_type = param.get("objecttype", None)
1464         # Since we have parsed all types before hand, this should not happen.
1465         type_info = types.get(type_elem.text, None)
1466         if type_info is None:
1467             LOGGER.err("type info not found for: {0}".format(type_elem.text))
1469         return VkParam(type_info, const=const, pointer=pointer, name=name, array_len=array_len, dyn_array_len=dyn_array_len, object_type=object_type)
1471     def _set_conversions(self):
1472         """ Internal helper function to configure any needed conversion functions. """
1474         self.free_func = None
1475         self.input_conv = None
1476         self.output_conv = None
1477         if not self.needs_conversion() and not self.needs_unwrapping():
1478             return
1480         operand = self.struct if self.is_struct() else self.handle
1482         # Input functions require win to host conversion.
1483         if self._direction in [Direction.INPUT, Direction.INPUT_OUTPUT]:
1484             self.input_conv = ConversionFunction(False, self.is_dynamic_array(), Direction.INPUT, operand)
1486         # Output functions require host to win conversion.
1487         if self._direction in [Direction.INPUT_OUTPUT, Direction.OUTPUT]:
1488             self.output_conv = ConversionFunction(False, self.is_dynamic_array(), Direction.OUTPUT, operand)
1490         # Dynamic arrays, but also some normal structs (e.g. VkCommandBufferBeginInfo) need memory
1491         # allocation and thus some cleanup.
1492         if self.is_dynamic_array() or self.struct.needs_free():
1493             self.free_func = FreeFunction(self.is_dynamic_array(), operand)
1495     def _set_direction(self):
1496         """ Internal helper function to set parameter direction (input/output/input_output). """
1498         # The parameter direction needs to be determined from hints in vk.xml like returnedonly,
1499         # parameter constness and other heuristics.
1500         # For now we need to get this right for structures as we need to convert these, we may have
1501         # missed a few other edge cases (e.g. count variables).
1502         # See also https://github.com/KhronosGroup/Vulkan-Docs/issues/610
1504         if not self.is_pointer():
1505             self._direction = Direction.INPUT
1506         elif self.is_const() and self.is_pointer():
1507             self._direction = Direction.INPUT
1508         elif self.is_struct():
1509             if not self.struct.returnedonly:
1510                 self._direction = Direction.INPUT
1511                 return
1513             # Returnedonly hints towards output, however in some cases
1514             # it is inputoutput. In particular if pNext / sType exist,
1515             # which are used to link in other structures without having
1516             # to introduce new APIs. E.g. vkGetPhysicalDeviceProperties2KHR.
1517             if "pNext" in self.struct:
1518                 self._direction = Direction.INPUT_OUTPUT
1519                 return
1521             self._direction = Direction.OUTPUT
1522         else:
1523             # This should mostly be right. Count variables can be inout, but we don't care about these yet.
1524             self._direction = Direction.OUTPUT
1526     def _set_format_string(self):
1527         """ Internal helper function to be used by constructor to set format string. """
1529         # Determine a format string used by code generation for traces.
1530         # 64-bit types need a conversion function.
1531         self.format_conv = None
1532         if self.is_static_array() or self.is_pointer():
1533             self.format_str = "%p"
1534         else:
1535             if self.type_info["category"] in ["bitmask"]:
1536                 # Since 1.2.170 bitmasks can be 32 or 64-bit, check the basetype.
1537                 if self.type_info["data"].type == "VkFlags64":
1538                     self.format_str = "0x%s"
1539                     self.format_conv = "wine_dbgstr_longlong({0})"
1540                 else:
1541                     self.format_str = "%#x"
1542             elif self.type_info["category"] in ["enum"]:
1543                 self.format_str = "%#x"
1544             elif self.is_handle():
1545                 # We use uint64_t for non-dispatchable handles as opposed to pointers
1546                 # for dispatchable handles.
1547                 if self.handle.is_dispatchable():
1548                     self.format_str = "%p"
1549                 else:
1550                     self.format_str = "0x%s"
1551                     self.format_conv = "wine_dbgstr_longlong({0})"
1552             elif self.type == "float":
1553                 self.format_str = "%f"
1554             elif self.type == "int":
1555                 self.format_str = "%d"
1556             elif self.type == "int32_t":
1557                 self.format_str = "%d"
1558             elif self.type == "size_t":
1559                 self.format_str = "0x%s"
1560                 self.format_conv = "wine_dbgstr_longlong({0})"
1561             elif self.type in ["uint16_t", "uint32_t", "VkBool32"]:
1562                 self.format_str = "%u"
1563             elif self.type in ["uint64_t", "VkDeviceAddress", "VkDeviceSize"]:
1564                 self.format_str = "0x%s"
1565                 self.format_conv = "wine_dbgstr_longlong({0})"
1566             elif self.type == "HANDLE":
1567                 self.format_str = "%p"
1568             elif self.type in ["VisualID", "xcb_visualid_t", "RROutput", "zx_handle_t"]:
1569                 # Don't care about specific types for non-Windows platforms.
1570                 self.format_str = ""
1571             else:
1572                 LOGGER.warn("Unhandled type: {0}".format(self.type_info))
1574     def copy(self, direction):
1575         if direction == Direction.INPUT:
1576             if self.is_dynamic_array():
1577                 return "    {0}_host = convert_{1}_array_win_to_host({0}, {2});\n".format(self.name, self.type, self.dyn_array_len)
1578             else:
1579                 return "    convert_{0}_win_to_host({1}, &{1}_host);\n".format(self.type, self.name)
1580         else:
1581             if self.is_dynamic_array():
1582                 LOGGER.error("Unimplemented output conversion for: {0}".format(self.name))
1583             else:
1584                 return "    convert_{0}_host_to_win(&{1}_host, {1});\n".format(self.type, self.name)
1586     def definition(self, postfix=None):
1587         """ Return prototype for the parameter. E.g. 'const char *foo' """
1589         proto = ""
1590         if self.const:
1591             proto += self.const + " "
1593         proto += self.type
1595         if self.is_pointer():
1596             proto += " {0}{1}".format(self.pointer, self.name)
1597         else:
1598             proto += " " + self.name
1600         # Allows appending something to the variable name useful for
1601         # win32 to host conversion.
1602         if postfix is not None:
1603             proto += postfix
1605         if self.is_static_array():
1606             proto += "[{0}]".format(self.array_len)
1608         return proto
1610     def direction(self):
1611         """ Returns parameter direction: input, output, input_output.
1613         Parameter direction in Vulkan is not straight-forward, which this function determines.
1614         """
1616         return self._direction
1618     def dispatch_table(self):
1619         """ Return functions dispatch table pointer for dispatchable objects. """
1621         if not self.is_dispatchable():
1622             return None
1624         return "{0}->{1}".format(self.name, self.handle.dispatch_table())
1626     def format_string(self):
1627         return self.format_str
1629     def free(self):
1630         if self.is_dynamic_array():
1631             if self.is_struct() and self.struct.returnedonly:
1632                 # For returnedonly, counts is stored in a pointer.
1633                 return "    free_{0}_array({1}_host, *{2});\n".format(self.type, self.name, self.dyn_array_len)
1634             else:
1635                 return "    free_{0}_array({1}_host, {2});\n".format(self.type, self.name, self.dyn_array_len)
1636         else:
1637             # We are operating on a single structure. Some structs (very rare) contain dynamic members,
1638             # which would need freeing.
1639             if self.is_struct() and self.struct.needs_free():
1640                 return "    free_{0}(&{1}_host);\n".format(self.type, self.name)
1641         return ""
1643     def get_conversions(self):
1644         """ Get a list of conversions required for this parameter if any.
1645         Parameters which are structures may require conversion between win32
1646         and the host platform. This function returns a list of conversions
1647         required.
1648         """
1650         if self.is_struct():
1651             self.struct.needs_struct_extensions_conversion()
1652             for m in self.struct:
1653                 m.needs_struct_extensions_conversion()
1654         elif not self.is_handle():
1655             return None
1657         if not self.needs_conversion() and not self.needs_unwrapping():
1658             return None
1660         conversions = []
1662         # Collect any member conversions first, so we can guarantee
1663         # those functions will be defined prior to usage by the
1664         # 'parent' param requiring conversion.
1665         if self.is_struct():
1666             for m in self.struct:
1667                 if not m.is_struct():
1668                     continue
1670                 if not m.needs_conversion() and not m.needs_unwrapping():
1671                     continue
1673                 conversions.extend(m.get_conversions())
1675         # Conversion requirements for the 'parent' parameter.
1676         if self.input_conv is not None:
1677             conversions.append(self.input_conv)
1678         if self.output_conv is not None:
1679             conversions.append(self.output_conv)
1680         if self.free_func is not None:
1681             conversions.append(self.free_func)
1683         return conversions
1685     def is_const(self):
1686         return self.const is not None
1688     def is_dynamic_array(self):
1689         return self.dyn_array_len is not None
1691     def is_dispatchable(self):
1692         if not self.is_handle():
1693             return False
1695         return self.handle.is_dispatchable()
1697     def is_handle(self):
1698         return self.handle is not None
1700     def is_pointer(self):
1701         return self.pointer is not None
1703     def is_static_array(self):
1704         return self.array_len is not None
1706     def is_struct(self):
1707         return self.struct is not None
1709     def needs_conversion(self):
1710         """ Returns if parameter needs conversion between win32 and host. """
1712         if not self.is_struct():
1713             return False
1715         # VkSparseImageMemoryRequirements(2) is used by vkGetImageSparseMemoryRequirements(2).
1716         # This function is tricky to wrap, because how to wrap depends on whether
1717         # pSparseMemoryRequirements is NULL or not. Luckily for VkSparseImageMemoryRequirements(2)
1718         # the alignment works out in such a way that no conversion is needed between win32 and Linux.
1719         if self.type in ["VkSparseImageMemoryRequirements", "VkSparseImageMemoryRequirements2"]:
1720             return False
1722         # If a structure needs alignment changes, it means we need to
1723         # perform parameter conversion between win32 and host.
1724         if self.struct.needs_conversion():
1725             return True
1727         return False
1729     def needs_unwrapping(self):
1730         """ Returns if parameter needs unwrapping of handle. """
1732         # Wrapped handle parameters are handled separately, only look for wrapped handles in structs
1733         if self.is_struct():
1734             return self.struct.needs_unwrapping()
1736         if self.is_handle() and self.is_dynamic_array():
1737             return self.handle.needs_unwrapping()
1739         return False
1741     def needs_free(self):
1742         return self.free_func is not None
1744     def needs_input_conversion(self):
1745         return self.input_conv is not None
1747     def needs_output_conversion(self):
1748         return self.output_conv is not None
1750     def spec(self):
1751         """ Generate spec file entry for this parameter. """
1753         if self.is_pointer() and self.type == "char":
1754             return "str"
1755         if self.is_dispatchable() or self.is_pointer() or self.is_static_array():
1756             return "ptr"
1757         if self.type_info["category"] in ["bitmask"]:
1758             # Since 1.2.170 bitmasks can be 32 or 64-bit, check the basetype.
1759             if self.type_info["data"].type == "VkFlags64":
1760                 return "int64"
1761             else:
1762                 return "long"
1763         if self.type_info["category"] in ["enum"]:
1764             return "long"
1765         if self.is_handle() and not self.is_dispatchable():
1766             return "int64"
1767         if self.type == "float":
1768             return "float"
1769         if self.type in ["int", "int32_t", "size_t", "uint16_t", "uint32_t", "VkBool32"]:
1770             return "long"
1771         if self.type in ["uint64_t", "VkDeviceSize"]:
1772             return "int64"
1774         LOGGER.error("Unhandled spec conversion for type: {0}".format(self.type))
1776     def variable(self, conv=False):
1777         """ Returns 'glue' code during generation of a function call on how to access the variable.
1778         This function handles various scenarios such as 'unwrapping' if dispatchable objects and
1779         renaming of parameters in case of win32 -> host conversion.
1781         Args:
1782             conv (bool, optional): Enable conversion if the param needs it. This appends '_host' to the name.
1783         """
1785         # Hack until we enable allocation callbacks from ICD to application. These are a joy
1786         # to enable one day, because of calling convention conversion.
1787         if "VkAllocationCallbacks" in self.type:
1788             LOGGER.debug("TODO: setting NULL VkAllocationCallbacks for {0}".format(self.name))
1789             return "NULL"
1791         if self.needs_unwrapping() or (conv and self.needs_conversion()):
1792             if self.is_dynamic_array():
1793                 return "{0}_host".format(self.name)
1794             else:
1795                 return "&{0}_host".format(self.name)
1796         else:
1797             if self.object_type != None and self.type == "uint64_t":
1798                 return "wine_vk_unwrap_handle({0}, {1})".format(self.object_type, self.name)
1800             # We need to pass the native handle to the native Vulkan calls and
1801             # the wine driver's handle to calls which are wrapped by the driver.
1802             driver_handle = self.handle.driver_handle(self.name) if self.is_handle() else None
1803             return driver_handle if driver_handle else self.name
1806 class VkStruct(Sequence):
1807     """ Class which represents the type union and struct. """
1809     def __init__(self, name, members, returnedonly, structextends, alias=None, union=False):
1810         self.name = name
1811         self.members = members
1812         self.returnedonly = returnedonly
1813         self.structextends = structextends
1814         self.required = False
1815         self.alias = alias
1816         self.union = union
1817         self.type_info = None # To be set later.
1818         self.struct_extensions = []
1819         self.aliased_by = []
1821     def __getitem__(self, i):
1822         return self.members[i]
1824     def __len__(self):
1825         return len(self.members)
1827     @staticmethod
1828     def from_alias(struct, alias):
1829         name = struct.attrib.get("name")
1830         aliasee = VkStruct(name, alias.members, alias.returnedonly, alias.structextends, alias=alias)
1832         alias.add_aliased_by(aliasee)
1833         return aliasee
1835     @staticmethod
1836     def from_xml(struct):
1837         # Unions and structs are the same parsing wise, but we need to
1838         # know which one we are dealing with later on for code generation.
1839         union = True if struct.attrib["category"] == "union" else False
1841         name = struct.attrib.get("name")
1843         # 'Output' structures for which data is filled in by the API are
1844         # marked as 'returnedonly'.
1845         returnedonly = True if struct.attrib.get("returnedonly") else False
1847         structextends = struct.attrib.get("structextends")
1848         structextends = structextends.split(",") if structextends else []
1850         members = []
1851         for member in struct.findall("member"):
1852             vk_member = VkMember.from_xml(member)
1853             members.append(vk_member)
1855         return VkStruct(name, members, returnedonly, structextends, union=union)
1857     @staticmethod
1858     def decouple_structs(structs):
1859         """ Helper function which decouples a list of structs.
1860         Structures often depend on other structures. To make the C compiler
1861         happy we need to define 'substructures' first. This function analyzes
1862         the list of structures and reorders them in such a way that they are
1863         decoupled.
1864         """
1866         tmp_structs = list(structs) # Don't modify the original structures.
1867         decoupled_structs = []
1869         while (len(tmp_structs) > 0):
1870             for struct in tmp_structs:
1871                 dependends = False
1873                 if not struct.required:
1874                     tmp_structs.remove(struct)
1875                     continue
1877                 for m in struct:
1878                     if not (m.is_struct() or m.is_union()):
1879                         continue
1881                     # VkBaseInstructure and VkBaseOutStructure reference themselves.
1882                     if m.type == struct.name:
1883                         break
1885                     found = False
1886                     # Check if a struct we depend on has already been defined.
1887                     for s in decoupled_structs:
1888                         if s.name == m.type:
1889                             found = True
1890                             break
1892                     if not found:
1893                         # Check if the struct we depend on is even in the list of structs.
1894                         # If found now, it means we haven't met all dependencies before we
1895                         # can operate on the current struct.
1896                         # When generating 'host' structs we may not be able to find a struct
1897                         # as the list would only contain the structs requiring conversion.
1898                         for s in tmp_structs:
1899                             if s.name == m.type:
1900                                 dependends = True
1901                                 break
1903                 if dependends == False:
1904                     decoupled_structs.append(struct)
1905                     tmp_structs.remove(struct)
1907         return decoupled_structs
1909     def definition(self, align=False, conv=False, postfix=None):
1910         """ Convert structure to textual definition.
1912         Args:
1913             align (bool, optional): enable alignment to 64-bit for win32 struct compatibility.
1914             conv (bool, optional): enable struct conversion if the struct needs it.
1915             postfix (str, optional): text to append to end of struct name, useful for struct renaming.
1916         """
1918         # Only define alias structs when doing conversions
1919         if self.is_alias() and not conv:
1920             return ""
1922         if self.union:
1923             text = "typedef union {0}".format(self.name)
1924         else:
1925             text = "typedef struct {0}".format(self.name)
1927         if postfix is not None:
1928             text += postfix
1930         text += "\n{\n"
1932         for m in self:
1933             if align and m.needs_alignment():
1934                 text += "    {0};\n".format(m.definition(align=align))
1935             elif conv and m.needs_conversion():
1936                 text += "    {0};\n".format(m.definition(conv=conv))
1937             else:
1938                 text += "    {0};\n".format(m.definition())
1940         if postfix is not None:
1941             text += "}} {0}{1};\n".format(self.name, postfix)
1942         else:
1943             text += "}} {0};\n".format(self.name)
1945         for aliasee in self.aliased_by:
1946             text += "typedef {0} {1};\n".format(self.name, aliasee.name)
1948         return text
1950     def is_alias(self):
1951         return bool(self.alias)
1953     def add_aliased_by(self, aliasee):
1954         self.aliased_by.append(aliasee)
1956     def needs_alignment(self):
1957         """ Check if structure needs alignment for 64-bit data.
1958         Various structures need alignment on 64-bit variables due
1959         to compiler differences on 32-bit between Win32 and Linux.
1960         """
1962         for m in self.members:
1963             if m.needs_alignment():
1964                 return True
1965         return False
1967     def needs_conversion(self):
1968         """ Returns if struct members needs conversion between win32 and host.
1969         Structures need conversion if they contain members requiring alignment
1970         or if they include other structures which need alignment.
1971         """
1973         if self.needs_alignment():
1974             return True
1976         for m in self.members:
1977             if m.needs_conversion():
1978                 return True
1979         return False
1981     def needs_unwrapping(self):
1982         """ Returns if struct members need unwrapping of handle. """
1984         for m in self.members:
1985             if m.needs_unwrapping():
1986                 return True
1987         return False
1989     def needs_free(self):
1990         """ Check if any struct member needs some memory freeing."""
1992         for m in self.members:
1993             if m.needs_free():
1994                 return True
1996             continue
1998         return False
2000     def needs_struct_extensions_conversion(self):
2001         """ Checks if structure extensions in pNext chain need conversion. """
2002         ret = False
2004         for e in self.struct_extensions:
2005             if e.required and e.needs_conversion():
2006                 LOGGER.error("Unhandled pNext chain alignment conversion for {0}".format(e.name))
2007                 ret = True
2008             if e.required and e.needs_unwrapping():
2009                 LOGGER.error("Unhandled pNext chain unwrapping conversion for {0}".format(e.name))
2010                 ret = True
2012         return ret
2014     def set_type_info(self, types):
2015         """ Helper function to set type information from the type registry.
2016         This is needed, because not all type data is available at time of
2017         parsing.
2018         """
2019         for m in self.members:
2020             type_info = types[m.type]
2021             m.set_type_info(type_info)
2024 class ConversionFunction(object):
2025     def __init__(self, array, dyn_array, direction, operand):
2026         self.array = array
2027         self.direction = direction
2028         self.dyn_array = dyn_array
2029         self.operand = operand
2030         self.type = operand.name
2032         self._set_name()
2034     def __eq__(self, other):
2035         return self.name == other.name
2037     def _generate_array_conversion_func(self):
2038         """ Helper function for generating a conversion function for array operands. """
2040         body = ""
2042         if self.operand.needs_conversion():
2043             body += "#if defined(USE_STRUCT_CONVERSION)\n"
2045             if self.direction == Direction.OUTPUT:
2046                 params = ["const {0}_host *in".format(self.type), "uint32_t count"]
2047                 return_type = self.type
2048             else:
2049                 params = ["const {0} *in".format(self.type), "uint32_t count"]
2050                 return_type = "{0}_host".format(self.type)
2052             # Generate function prototype.
2053             body += "static inline {0} *{1}(".format(return_type, self.name)
2054             body += ", ".join(p for p in params)
2055             body += ")\n{\n"
2057             body += "    {0} *out;\n".format(return_type)
2059         if self.operand.needs_unwrapping():
2060             if self.operand.needs_conversion():
2061                 body += "#else\n"
2063             params = ["const {0} *in".format(self.type), "uint32_t count"]
2064             return_type = "{0}".format(self.type)
2066             # Generate function prototype.
2067             body += "static inline {0} *{1}(".format(return_type, self.name)
2068             body += ", ".join(p for p in params)
2069             body += ")\n{\n"
2071             body += "    {0} *out;\n".format(return_type)
2073             if self.operand.needs_conversion():
2074                 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2076         body += "    unsigned int i;\n\n"
2077         body += "    if (!in) return NULL;\n\n"
2079         body += "    out = malloc(count * sizeof(*out));\n"
2081         body += "    for (i = 0; i < count; i++)\n"
2082         body += "    {\n"
2084         if isinstance(self.operand, VkStruct):
2085             for m in self.operand:
2086                 # TODO: support copying of pNext extension structures!
2087                 # Luckily though no extension struct at this point needs conversion.
2088                 convert = m.copy("in[i].", "out[i].", self.direction, conv=True)
2089                 if self.operand.needs_conversion() and not self.operand.needs_unwrapping():
2090                     body += "        " + convert
2091                 else:
2092                     unwrap = m.copy("in[i].", "out[i].", self.direction, conv=False)
2093                     if unwrap == convert:
2094                         body += "        " + unwrap
2095                     else:
2096                         body += "#if defined(USE_STRUCT_CONVERSION)\n"
2097                         body += "        " + convert
2098                         body += "#else\n"
2099                         body += "        " + unwrap
2100                         body += "#endif /* USE_STRUCT_CONVERSION */\n"
2102         elif isinstance(self.operand, VkHandle) and self.direction == Direction.INPUT:
2103             body += "        out[i] = " + self.operand.driver_handle("in[i]") + ";\n"
2104         else:
2105             LOGGER.warn("Unhandled conversion operand type")
2106             body += "        out[i] = in[i];\n"
2108         body += "    }\n\n"
2109         body += "    return out;\n"
2110         body += "}\n"
2112         if not self.operand.needs_unwrapping():
2113             body += "#endif /* USE_STRUCT_CONVERSION */\n"
2115         body += "\n"
2117         return body
2119     def _generate_conversion_func(self):
2120         """ Helper function for generating a conversion function for non-array operands. """
2122         # It doesn't make sense to generate conversion functions for non-struct variables
2123         # which aren't in arrays, as this should be handled by the copy() function
2124         if not isinstance(self.operand, VkStruct):
2125             return ""
2127         body = ""
2129         if self.operand.needs_conversion():
2130             body += "#if defined(USE_STRUCT_CONVERSION)\n"
2131             body += "static inline void {0}(".format(self.name)
2133             if self.direction == Direction.OUTPUT:
2134                 params = ["const {0}_host *in".format(self.type), "{0} *out".format(self.type)]
2135             else:
2136                 params = ["const {0} *in".format(self.type), "{0}_host *out".format(self.type)]
2138             # Generate parameter list
2139             body += ", ".join(p for p in params)
2140             body += ")\n"
2142         if self.operand.needs_unwrapping():
2143             if self.operand.needs_conversion():
2144                 body += "#else\n"
2146             body += "static inline void {0}(".format(self.name)
2148             params = ["const {0} *in".format(self.type), "{0} *out".format(self.type)]
2150             # Generate parameter list
2151             body += ", ".join(p for p in params)
2152             body += ")\n"
2154             if self.operand.needs_conversion():
2155                 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2157         body += "{\n    if (!in) return;\n\n"
2159         if self.direction == Direction.INPUT and "pNext" in self.operand and self.operand.returnedonly:
2160             # We are dealing with an input_output parameter. For these we only need to copy
2161             # pNext and sType as the other fields are filled in by the host. We do potentially
2162             # have to iterate over pNext and perform conversions based on switch(sType)!
2163             # Luckily though no extension structs at this point need conversion.
2164             # TODO: support copying of pNext extension structures!
2165             body += "    out->pNext = in->pNext;\n"
2166             body += "    out->sType = in->sType;\n"
2167         else:
2168             for m in self.operand:
2169                 # TODO: support copying of pNext extension structures!
2170                 convert = m.copy("in->", "out->", self.direction, conv=True)
2171                 if self.operand.needs_conversion() and not self.operand.needs_unwrapping():
2172                     body += "    " + convert
2173                 else:
2174                     unwrap = m.copy("in->", "out->", self.direction, conv=False)
2175                     if unwrap == convert:
2176                         body += "    " + unwrap
2177                     else:
2178                         body += "#if defined(USE_STRUCT_CONVERSION)\n"
2179                         body += "    " + convert
2180                         body += "#else\n"
2181                         body += "    " + unwrap
2182                         body += "#endif /* USE_STRUCT_CONVERSION */\n"
2184         body += "}\n"
2186         if not self.operand.needs_unwrapping():
2187             body += "#endif /* USE_STRUCT_CONVERSION */\n"
2189         body += "\n"
2191         return body
2193     def _generate_static_array_conversion_func(self):
2194         """ Helper function for generating a conversion function for array operands. """
2196         body = ""
2198         if self.operand.needs_conversion():
2199             body += "#if defined(USE_STRUCT_CONVERSION)\n"
2201             if self.direction == Direction.OUTPUT:
2202                 params = ["const {0}_host *in".format(self.type), "{0} *out".format(self.type), "uint32_t count"]
2203             else:
2204                 params = ["const {0} *in".format(self.type), "{0} *out_host".format(self.type), "uint32_t count"]
2206             # Generate function prototype.
2207             body += "static inline void {0}(".format(self.name)
2208             body += ", ".join(p for p in params)
2209             body += ")\n"
2211         if self.operand.needs_unwrapping():
2212             if self.operand.needs_conversion():
2213                 body += "#else\n"
2215             params = ["const {0} *in".format(self.type), "{0} *out".format(self.type), "uint32_t count"]
2217             # Generate function prototype.
2218             body += "static inline void {0}(".format(self.name)
2219             body += ", ".join(p for p in params)
2220             body += ")\n"
2222         body += "{\n"
2223         body += "    unsigned int i;\n\n"
2224         body += "    if (!in) return;\n\n"
2225         body += "    for (i = 0; i < count; i++)\n"
2226         body += "    {\n"
2228         if isinstance(self.operand, VkStruct):
2229             for m in self.operand:
2230                 # TODO: support copying of pNext extension structures!
2231                 convert = m.copy("in[i].", "out[i].", self.direction, conv=True)
2232                 if self.operand.needs_conversion() and not self.operand.needs_unwrapping():
2233                     body += "        " + convert
2234                 else:
2235                     unwrap = m.copy("in[i].", "out[i].", self.direction, conv=False)
2236                     if unwrap == convert:
2237                         body += "        " + unwrap
2238                     else:
2239                         body += "#if defined(USE_STRUCT_CONVERSION)\n"
2240                         body += "    " + convert
2241                         body += "#else\n"
2242                         body += "    " + unwrap
2243                         body += "#endif /* USE_STRUCT_CONVERSION */\n"
2244         elif isinstance(self.operand, VkHandle) and self.direction == Direction.INPUT:
2245             body += "        out[i] = " + self.operand.driver_handle("in[i]") + ";\n"
2246         else:
2247             LOGGER.warn("Unhandled conversion operand type")
2248             body += "        out[i] = in[i];\n"
2250         body += "    }\n"
2251         body += "}\n"
2253         if not self.operand.needs_unwrapping():
2254             body += "#endif /* USE_STRUCT_CONVERSION) */\n"
2256         body += "\n"
2258         return body
2260     def _set_name(self):
2261         if self.direction == Direction.INPUT:
2262             if self.array:
2263                 name = "convert_{0}_static_array_win_to_host".format(self.type)
2264             elif self.dyn_array:
2265                 name = "convert_{0}_array_win_to_host".format(self.type)
2266             else:
2267                 name = "convert_{0}_win_to_host".format(self.type)
2268         else: # Direction.OUTPUT
2269             if self.array:
2270                 name = "convert_{0}_static_array_host_to_win".format(self.type)
2271             elif self.dyn_array:
2272                 name = "convert_{0}_array_host_to_win".format(self.type)
2273             else:
2274                 name = "convert_{0}_host_to_win".format(self.type)
2276         self.name = name
2278     def definition(self):
2279         if self.array:
2280             return self._generate_static_array_conversion_func()
2281         elif self.dyn_array:
2282             return self._generate_array_conversion_func()
2283         else:
2284             return self._generate_conversion_func()
2287 class FreeFunction(object):
2288     def __init__(self, dyn_array, operand):
2289         self.dyn_array = dyn_array
2290         self.operand = operand
2291         self.type = operand.name
2293         if dyn_array:
2294             self.name = "free_{0}_array".format(self.type)
2295         else:
2296             self.name = "free_{0}".format(self.type)
2298     def __eq__(self, other):
2299         return self.name == other.name
2301     def _generate_array_free_func(self):
2302         """ Helper function for cleaning up temporary buffers required for array conversions. """
2304         body = ""
2306         if self.operand.needs_conversion():
2307             body += "#if defined(USE_STRUCT_CONVERSION)\n"
2308             # Generate function prototype.
2309             body += "static inline void {0}({1}_host *in, uint32_t count)\n".format(self.name, self.type)
2311         if self.operand.needs_unwrapping():
2312             if self.operand.needs_conversion():
2313                 body += "#else\n"
2315             # Generate function prototype.
2316             body += "static inline void {0}({1} *in, uint32_t count)\n".format(self.name, self.type)
2318             if self.operand.needs_conversion():
2319                 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2321         body += "{\n"
2323         # E.g. VkGraphicsPipelineCreateInfo_host needs freeing for pStages.
2324         if isinstance(self.operand, VkStruct) and self.operand.needs_free():
2325             body += "    unsigned int i;\n\n"
2326             body += "    if (!in) return;\n\n"
2327             body += "    for (i = 0; i < count; i++)\n"
2328             body += "    {\n"
2330             for m in self.operand:
2331                 if m.needs_free():
2332                     convert = m.free("in[i].", conv=True)
2333                     if self.operand.needs_conversion() and not self.operand.needs_unwrapping():
2334                         body += "        " + convert
2335                     else:
2336                         unwrap = m.free("in[i].", conv=False)
2337                         if convert == unwrap:
2338                             body += "        " + unwrap
2339                         elif unwrap == "":
2340                             body += "#if defined(USE_STRUCT_CONVERSION)\n"
2341                             body += "        " + convert
2342                             body += "#endif /* USE_STRUCT_CONVERSION */\n"
2343                         else:
2344                             body += "#if defined(USE_STRUCT_CONVERSION)\n"
2345                             body += "        " + convert
2346                             body += "#else\n"
2347                             body += "        " + unwrap
2348                             body += "#endif /* USE_STRUCT_CONVERSION */\n"
2349             body += "    }\n"
2350         else:
2351             body += "    if (!in) return;\n\n"
2353         body += "    free(in);\n"
2355         body += "}\n"
2357         if not self.operand.needs_unwrapping():
2358             body += "#endif /* USE_STRUCT_CONVERSION */\n"
2360         body += "\n"
2362         return body
2364     def _generate_free_func(self):
2365         # E.g. VkCommandBufferBeginInfo.pInheritanceInfo needs freeing.
2366         if not self.operand.needs_free():
2367             return ""
2369         if not isinstance(self.operand, VkStruct):
2370             return ""
2372         body = ""
2374         if self.operand.needs_conversion():
2375             body += "#if defined(USE_STRUCT_CONVERSION)\n"
2376             # Generate function prototype.
2377             body += "static inline void {0}({1}_host *in)\n".format(self.name, self.type)
2379         if self.operand.needs_unwrapping():
2380             if self.operand.needs_conversion():
2381                 body += "#else\n"
2383             # Generate function prototype.
2384             body += "static inline void {0}({1} *in)\n".format(self.name, self.type)
2386             if self.operand.needs_conversion():
2387                 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2389         body += "{\n"
2391         for m in self.operand:
2392             if m.needs_free():
2393                 convert = m.free("in->", conv=True)
2394                 if self.operand.needs_conversion() and not self.operand.needs_unwrapping():
2395                     body += "    " + convert
2396                 else:
2397                     unwrap = m.free("in->", conv=False)
2398                     if convert == unwrap:
2399                         body += "    " + unwrap
2400                     elif unwrap == "":
2401                         body += "#if defined(USE_STRUCT_CONVERSION)\n"
2402                         body += "    " + convert
2403                         body += "#endif /* USE_STRUCT_CONVERSION */\n"
2404                     else:
2405                         body += "#if defined(USE_STRUCT_CONVERSION)\n"
2406                         body += "    " + convert
2407                         body += "#else\n"
2408                         body += "    " + unwrap
2409                         body += "#endif /* USE_STRUCT_CONVERSION */\n"
2411         body += "}\n"
2413         if not self.operand.needs_unwrapping():
2414             body += "#endif /* USE_STRUCT_CONVERSION */\n"
2416         body += "\n"
2418         return body
2420     def definition(self):
2421         if self.dyn_array:
2422             return self._generate_array_free_func()
2423         else:
2424             # Some structures need freeing too if they contain dynamic arrays.
2425             # E.g. VkCommandBufferBeginInfo
2426             return self._generate_free_func()
2429 class StructChainConversionFunction(object):
2430     def __init__(self, direction, struct, ignores):
2431         self.direction = direction
2432         self.struct = struct
2433         self.ignores = ignores
2434         self.type = struct.name
2436         self.name = "convert_{0}_struct_chain".format(self.type)
2438     def __eq__(self, other):
2439         return self.name == other.name
2441     def prototype(self, postfix=""):
2442         return "VkResult {0}(const void *pNext, {1} *out_struct) {2}".format(self.name, self.type, postfix).strip()
2444     def definition(self):
2445         body = self.prototype()
2446         body += "\n{\n"
2448         body += "    VkBaseOutStructure *out_header = (VkBaseOutStructure *)out_struct;\n";
2449         body += "    const VkBaseInStructure *in_header;\n\n";
2451         body += "    out_header->pNext = NULL;\n\n"
2453         body += "    for (in_header = pNext; in_header; in_header = in_header->pNext)\n"
2454         body += "    {\n"
2455         body += "        switch (in_header->sType)\n"
2456         body += "        {\n"
2458         for i in self.ignores:
2459             body += "        case {0}:\n".format(i)
2460         body += "            break;\n\n"
2462         for e in self.struct.struct_extensions:
2463             if not e.required:
2464                 continue
2466             stype = next(x for x in e.members if x.name == "sType")
2468             if stype.values in self.ignores:
2469                 continue
2471             body += "        case {0}:\n".format(stype.values)
2472             body += "        {\n"
2474             body += "            const {0} *in = (const {0} *)in_header;\n".format(e.name)
2475             body += "            {0} *out;\n\n".format(e.name)
2477             body += "            if (!(out = malloc(sizeof(*out)))) goto out_of_memory;\n\n"
2479             for m in e:
2480                 if m.name == "pNext":
2481                     body += "            out->pNext = NULL;\n"
2482                 else:
2483                     convert = m.copy("in->", "out->", self.direction, conv=True)
2484                     unwrap = m.copy("in->", "out->", self.direction, conv=False)
2485                     if unwrap == convert:
2486                         body += "            " + unwrap
2487                     else:
2488                         body += "#if defined(USE_STRUCT_CONVERSION)\n"
2489                         body += "            " + convert
2490                         body += "#else\n"
2491                         body += "            " + unwrap
2492                         body += "#endif /* USE_STRUCT_CONVERSION */\n"
2494             body += "\n            out_header->pNext = (VkBaseOutStructure *)out;\n"
2495             body += "            out_header = out_header->pNext;\n"
2496             body += "            break;\n"
2497             body += "        }\n\n"
2499         body += "        default:\n"
2500         body += "            FIXME(\"Application requested a linked structure of type %u.\\n\", in_header->sType);\n"
2502         body += "        }\n"
2503         body += "    }\n\n"
2505         body += "    return VK_SUCCESS;\n"
2507         if any(x for x in self.struct.struct_extensions if x.required):
2508             body += "\nout_of_memory:\n"
2509             body += "    free_{0}_struct_chain(out_struct);\n".format(self.type)
2510             body += "    return VK_ERROR_OUT_OF_HOST_MEMORY;\n"
2512         body += "}\n\n"
2513         return body
2515 class FreeStructChainFunction(object):
2516     def __init__(self, struct):
2517         self.struct = struct
2518         self.type = struct.name
2520         self.name = "free_{0}_struct_chain".format(self.type)
2522     def __eq__(self, other):
2523         return self.name == other.name
2525     def prototype(self, postfix=""):
2526         return "void {0}({1} *s) {2}".format(self.name, self.type, postfix).strip()
2528     def definition(self):
2529         body = self.prototype()
2530         body += "\n{\n"
2532         body += "    VkBaseOutStructure *header = (void *)s->pNext;\n\n";
2534         body += "    while (header)\n"
2535         body += "    {\n"
2536         body += "        void *prev = header;\n\n"
2537         body += "        switch (header->sType)\n"
2538         body += "        {\n"
2540         for e in self.struct.struct_extensions:
2541             if not e.required:
2542                 continue
2544             if not any(m.needs_free() for m in e):
2545                 continue
2547             stype = next(x for x in e.members if x.name == "sType")
2549             body += "            case {0}:\n".format(stype.values)
2550             body += "            {\n"
2551             body += "                {0} *structure = ({0} *) header;\n".format(e.name)
2553             for m in e:
2554                 if m.needs_free():
2555                     convert = m.free("structure->", conv=True)
2556                     unwrap = m.free("structure->", conv=False)
2557                     if convert == unwrap:
2558                         body += "                " + unwrap
2559                     elif unwrap == "":
2560                         body += "#if defined(USE_STRUCT_CONVERSION)\n"
2561                         body += "                " + convert
2562                         body += "#endif /* USE_STRUCT_CONVERSION */\n"
2563                     else:
2564                         body += "#if defined(USE_STRUCT_CONVERSION)\n"
2565                         body += "                " + convert
2566                         body += "#else\n"
2567                         body += "                " + unwrap
2568                         body += "#endif /* USE_STRUCT_CONVERSION */\n"
2570             body += "                break;\n"
2571             body += "            }\n"
2573         body += "            default:\n"
2574         body += "                break;\n"
2575         body += "        }\n"
2577         body += "        header = header->pNext;\n"
2578         body += "        free(prev);\n"
2579         body += "    }\n\n"
2581         body += "    s->pNext = NULL;\n"
2583         body += "}\n\n"
2584         return body
2587 class VkGenerator(object):
2588     def __init__(self, registry):
2589         self.registry = registry
2591         # Build a list conversion functions for struct conversion.
2592         self.conversions = []
2593         self.struct_chain_conversions = []
2594         self.host_structs = []
2595         for func in self.registry.funcs.values():
2596             if not func.is_required():
2597                 continue
2599             if not func.needs_conversion() and not func.needs_unwrapping():
2600                 continue
2602             conversions = func.get_conversions()
2603             for conv in conversions:
2604                 # Pull in any conversions for vulkan_thunks.c.
2605                 if func.needs_thunk():
2606                     # Append if we don't already have this conversion.
2607                     if not any(c == conv for c in self.conversions):
2608                         self.conversions.append(conv)
2610                 if not isinstance(conv.operand, VkStruct):
2611                     continue
2613                 # Structs can be used in different ways by different conversions
2614                 # e.g. array vs non-array. Just make sure we pull in each struct once.
2615                 if not any(s.name == conv.operand.name for s in self.host_structs):
2616                     self.host_structs.append(conv.operand)
2618         for struct in self.registry.structs:
2619             if struct.name in STRUCT_CHAIN_CONVERSIONS:
2620                 self.struct_chain_conversions.append(StructChainConversionFunction(Direction.INPUT, struct, STRUCT_CHAIN_CONVERSIONS[struct.name]))
2621                 self.struct_chain_conversions.append(FreeStructChainFunction(struct))
2622                 # Once we decide to support pNext chains conversion everywhere, move this under get_conversions
2623                 for e in struct.struct_extensions:
2624                     for m in e:
2625                         if m.needs_conversion() or m.needs_unwrapping():
2626                             conversions = m.get_conversions()
2627                             for conv in conversions:
2628                                 if not any(c == conv for c in self.conversions):
2629                                     self.conversions.append(conv)
2631     def _generate_copyright(self, f, spec_file=False):
2632         f.write("# " if spec_file else "/* ")
2633         f.write("Automatically generated from Vulkan vk.xml; DO NOT EDIT!\n")
2634         lines = ["", "This file is generated from Vulkan vk.xml file covered",
2635             "by the following copyright and permission notice:"]
2636         lines.extend([l.rstrip(" ") for l in self.registry.copyright.splitlines()])
2637         for line in lines:
2638             f.write("{0}{1}".format("# " if spec_file else " * ", line).rstrip(" ") + "\n")
2639         f.write("\n" if spec_file else " */\n\n")
2641     def generate_thunks_c(self, f, prefix):
2642         self._generate_copyright(f)
2644         f.write("#if 0\n")
2645         f.write("#pragma makedep unix\n")
2646         f.write("#endif\n\n")
2648         f.write("#include \"config.h\"\n")
2649         f.write("#include \"wine/port.h\"\n\n")
2651         f.write("#include \"vulkan_private.h\"\n\n")
2653         f.write("WINE_DEFAULT_DEBUG_CHANNEL(vulkan);\n\n")
2655         # Generate any conversion helper functions.
2656         for conv in self.conversions:
2657             f.write(conv.definition())
2659         for conv in self.struct_chain_conversions:
2660             f.write(conv.definition())
2662         # Create thunks for instance and device functions.
2663         # Global functions don't go through the thunks.
2664         for vk_func in self.registry.funcs.values():
2665             if not vk_func.is_required():
2666                 continue
2668             if vk_func.is_global_func():
2669                 continue
2671             if not vk_func.needs_thunk():
2672                 continue
2674             if vk_func.needs_private_thunk():
2675                 f.write(vk_func.thunk(prefix="thunk_"))
2676             else:
2677                 f.write("static ")
2678                 f.write(vk_func.thunk(prefix=prefix, call_conv="WINAPI"))
2680         # Create array of device extensions.
2681         f.write("static const char * const vk_device_extensions[] =\n{\n")
2682         for ext in self.registry.extensions:
2683             if ext["type"] != "device":
2684                 continue
2686             f.write("    \"{0}\",\n".format(ext["name"]))
2687         f.write("};\n\n")
2689         # Create array of instance extensions.
2690         f.write("static const char * const vk_instance_extensions[] =\n{\n")
2691         for ext in self.registry.extensions:
2692             if ext["type"] != "instance":
2693                 continue
2695             f.write("    \"{0}\",\n".format(ext["name"]))
2696         f.write("};\n\n")
2698         f.write("BOOL wine_vk_device_extension_supported(const char *name)\n")
2699         f.write("{\n")
2700         f.write("    unsigned int i;\n")
2701         f.write("    for (i = 0; i < ARRAY_SIZE(vk_device_extensions); i++)\n")
2702         f.write("    {\n")
2703         f.write("        if (strcmp(vk_device_extensions[i], name) == 0)\n")
2704         f.write("            return TRUE;\n")
2705         f.write("    }\n")
2706         f.write("    return FALSE;\n")
2707         f.write("}\n\n")
2709         f.write("BOOL wine_vk_instance_extension_supported(const char *name)\n")
2710         f.write("{\n")
2711         f.write("    unsigned int i;\n")
2712         f.write("    for (i = 0; i < ARRAY_SIZE(vk_instance_extensions); i++)\n")
2713         f.write("    {\n")
2714         f.write("        if (strcmp(vk_instance_extensions[i], name) == 0)\n")
2715         f.write("            return TRUE;\n")
2716         f.write("    }\n")
2717         f.write("    return FALSE;\n")
2718         f.write("}\n\n")
2720         f.write("BOOL wine_vk_is_type_wrapped(VkObjectType type)\n")
2721         f.write("{\n")
2722         f.write("    return FALSE")
2723         for handle in self.registry.handles:
2724             if not handle.is_required() or not handle.is_wrapped() or handle.is_alias():
2725                 continue
2726             f.write(" ||\n        type == {}".format(handle.object_type))
2727         f.write(";\n")
2728         f.write("}\n\n")
2730         f.write("uint64_t wine_vk_unwrap_handle(VkObjectType type, uint64_t handle)\n")
2731         f.write("{\n")
2732         f.write("    switch(type)\n")
2733         f.write("    {\n")
2734         for handle in self.registry.handles:
2735             if not handle.is_required() or not handle.is_wrapped() or handle.is_alias():
2736                 continue
2737             f.write("    case {}:\n".format(handle.object_type))
2738             if handle.is_dispatchable():
2739                 f.write("        return (uint64_t) (uintptr_t) ")
2740                 f.write(handle.native_handle("(({}) (uintptr_t) handle)".format(handle.name)))
2741             else:
2742                 f.write("        return (uint64_t) ")
2743                 f.write(handle.native_handle("handle"))
2744             f.write(";\n");
2745         f.write("    default:\n")
2746         f.write("       return handle;\n")
2747         f.write("    }\n")
2748         f.write("}\n\n")
2750         f.write("const struct unix_funcs loader_funcs =\n")
2751         f.write("{\n")
2752         for vk_func in self.registry.funcs.values():
2753             if not vk_func.is_required():
2754                 continue
2755             if vk_func.loader_thunk_type == ThunkType.NONE:
2756                 continue
2758             f.write("    &{1}{0},\n".format(vk_func.name, prefix))
2759         f.write("};\n")
2761     def generate_thunks_h(self, f, prefix):
2762         self._generate_copyright(f)
2764         f.write("#ifndef __WINE_VULKAN_THUNKS_H\n")
2765         f.write("#define __WINE_VULKAN_THUNKS_H\n\n")
2767         f.write("#define WINE_VK_VERSION VK_API_VERSION_{0}_{1}\n\n".format(WINE_VK_VERSION[0], WINE_VK_VERSION[1]))
2769         # Generate prototypes for device and instance functions requiring a custom implementation.
2770         f.write("/* Functions for which we have custom implementations outside of the thunks. */\n")
2771         for vk_func in self.registry.funcs.values():
2772             if not vk_func.is_required():
2773                 continue
2774             if vk_func.needs_thunk() and not vk_func.needs_private_thunk():
2775                 continue
2777             if vk_func.is_core_func():
2778                 f.write("{0};\n".format(vk_func.prototype("WINAPI", prefix=prefix)))
2779             else:
2780                 f.write("{0};\n".format(vk_func.prototype("WINAPI", prefix=prefix, postfix="DECLSPEC_HIDDEN")))
2781         f.write("\n")
2783         f.write("/* Private thunks */\n")
2784         for vk_func in self.registry.funcs.values():
2785             if vk_func.needs_private_thunk():
2786                 f.write("{0};\n".format(vk_func.prototype(prefix="thunk_", postfix="DECLSPEC_HIDDEN")))
2787         f.write("\n")
2789         for struct in self.host_structs:
2790             f.write("#if defined(USE_STRUCT_CONVERSION)\n")
2791             f.write(struct.definition(align=False, conv=True, postfix="_host"))
2792             f.write("#else\n")
2793             f.write("typedef {0} {0}_host;\n".format(struct.name))
2794             f.write("#endif\n\n")
2795         f.write("\n")
2797         for func in self.struct_chain_conversions:
2798             f.write(func.prototype(postfix="DECLSPEC_HIDDEN") + ";\n")
2799         f.write("\n")
2801         f.write("/* For use by vkDevice and children */\n")
2802         f.write("struct vulkan_device_funcs\n{\n")
2803         for vk_func in self.registry.device_funcs:
2804             if not vk_func.is_required():
2805                 continue
2807             if not vk_func.needs_dispatch():
2808                 LOGGER.debug("skipping {0} in vulkan_device_funcs".format(vk_func.name))
2809                 continue
2811             f.write("    {0};\n".format(vk_func.pfn(conv=vk_func.needs_conversion())))
2812         f.write("};\n\n")
2814         f.write("/* For use by vkInstance and children */\n")
2815         f.write("struct vulkan_instance_funcs\n{\n")
2816         for vk_func in self.registry.instance_funcs + self.registry.phys_dev_funcs:
2817             if not vk_func.is_required():
2818                 continue
2820             if not vk_func.needs_dispatch():
2821                 LOGGER.debug("skipping {0} in vulkan_instance_funcs".format(vk_func.name))
2822                 continue
2824             f.write("    {0};\n".format(vk_func.pfn(conv=vk_func.needs_conversion())))
2825         f.write("};\n\n")
2827         f.write("#define ALL_VK_DEVICE_FUNCS() \\\n")
2828         first = True
2829         for vk_func in self.registry.device_funcs:
2830             if not vk_func.is_required():
2831                 continue
2833             if not vk_func.needs_dispatch():
2834                 LOGGER.debug("skipping {0} in ALL_VK_DEVICE_FUNCS".format(vk_func.name))
2835                 continue
2837             if first:
2838                 f.write("    USE_VK_FUNC({0})".format(vk_func.name))
2839                 first = False
2840             else:
2841                 f.write(" \\\n    USE_VK_FUNC({0})".format(vk_func.name))
2842         f.write("\n\n")
2844         f.write("#define ALL_VK_INSTANCE_FUNCS() \\\n")
2845         first = True
2846         for vk_func in self.registry.instance_funcs + self.registry.phys_dev_funcs:
2847             if not vk_func.is_required():
2848                 continue
2850             if not vk_func.needs_dispatch():
2851                 LOGGER.debug("skipping {0} in ALL_VK_INSTANCE_FUNCS".format(vk_func.name))
2852                 continue
2854             if first:
2855                 f.write("    USE_VK_FUNC({0})".format(vk_func.name))
2856                 first = False
2857             else:
2858                 f.write(" \\\n    USE_VK_FUNC({0})".format(vk_func.name))
2859         f.write("\n\n")
2861         f.write("#endif /* __WINE_VULKAN_THUNKS_H */\n")
2863     def generate_loader_thunks_c(self, f):
2864         self._generate_copyright(f)
2866         f.write("#include \"vulkan_loader.h\"\n\n")
2868         f.write("WINE_DEFAULT_DEBUG_CHANNEL(vulkan);\n\n")
2870         for vk_func in self.registry.funcs.values():
2871             if not vk_func.is_required():
2872                 continue
2873             if vk_func.loader_thunk_type != ThunkType.PUBLIC:
2874                 continue
2876             f.write(vk_func.loader_thunk())
2878         f.write("static const struct vulkan_func vk_device_dispatch_table[] =\n{\n")
2879         for vk_func in self.registry.device_funcs:
2880             if not vk_func.is_required():
2881                 continue
2883             f.write("    {{\"{0}\", &{0}}},\n".format(vk_func.name))
2884         f.write("};\n\n")
2886         f.write("static const struct vulkan_func vk_phys_dev_dispatch_table[] =\n{\n")
2887         for vk_func in self.registry.phys_dev_funcs:
2888             if not vk_func.is_required():
2889                 continue
2891             f.write("    {{\"{0}\", &{0}}},\n".format(vk_func.name))
2892         f.write("};\n\n")
2894         f.write("static const struct vulkan_func vk_instance_dispatch_table[] =\n{\n")
2895         for vk_func in self.registry.instance_funcs:
2896             if not vk_func.is_required():
2897                 continue
2899             f.write("    {{\"{0}\", &{0}}},\n".format(vk_func.name))
2900         f.write("};\n\n")
2902         f.write("void *wine_vk_get_device_proc_addr(const char *name)\n")
2903         f.write("{\n")
2904         f.write("    unsigned int i;\n")
2905         f.write("    for (i = 0; i < ARRAY_SIZE(vk_device_dispatch_table); i++)\n")
2906         f.write("    {\n")
2907         f.write("        if (strcmp(vk_device_dispatch_table[i].name, name) == 0)\n")
2908         f.write("        {\n")
2909         f.write("            TRACE(\"Found name=%s in device table\\n\", debugstr_a(name));\n")
2910         f.write("            return vk_device_dispatch_table[i].func;\n")
2911         f.write("        }\n")
2912         f.write("    }\n")
2913         f.write("    return NULL;\n")
2914         f.write("}\n\n")
2916         f.write("void *wine_vk_get_phys_dev_proc_addr(const char *name)\n")
2917         f.write("{\n")
2918         f.write("    unsigned int i;\n")
2919         f.write("    for (i = 0; i < ARRAY_SIZE(vk_phys_dev_dispatch_table); i++)\n")
2920         f.write("    {\n")
2921         f.write("        if (strcmp(vk_phys_dev_dispatch_table[i].name, name) == 0)\n")
2922         f.write("        {\n")
2923         f.write("            TRACE(\"Found name=%s in physical device table\\n\", debugstr_a(name));\n")
2924         f.write("            return vk_phys_dev_dispatch_table[i].func;\n")
2925         f.write("        }\n")
2926         f.write("    }\n")
2927         f.write("    return NULL;\n")
2928         f.write("}\n\n")
2930         f.write("void *wine_vk_get_instance_proc_addr(const char *name)\n")
2931         f.write("{\n")
2932         f.write("    unsigned int i;\n")
2933         f.write("    for (i = 0; i < ARRAY_SIZE(vk_instance_dispatch_table); i++)\n")
2934         f.write("    {\n")
2935         f.write("        if (strcmp(vk_instance_dispatch_table[i].name, name) == 0)\n")
2936         f.write("        {\n")
2937         f.write("            TRACE(\"Found name=%s in instance table\\n\", debugstr_a(name));\n")
2938         f.write("            return vk_instance_dispatch_table[i].func;\n")
2939         f.write("        }\n")
2940         f.write("    }\n")
2941         f.write("    return NULL;\n")
2942         f.write("}\n")
2944     def generate_loader_thunks_h(self, f):
2945         self._generate_copyright(f)
2947         f.write("#ifndef __WINE_VULKAN_LOADER_THUNKS_H\n")
2948         f.write("#define __WINE_VULKAN_LOADER_THUNKS_H\n\n")
2950         f.write("struct unix_funcs\n")
2951         f.write("{\n")
2952         for vk_func in self.registry.funcs.values():
2953             if not vk_func.is_required():
2954                 continue
2955             if vk_func.loader_thunk_type == ThunkType.NONE:
2956                 continue
2958             f.write("    {0};\n".format(vk_func.pfn(conv=False, call_conv="WINAPI")))
2959         f.write("};\n\n")
2961         f.write("#endif /* __WINE_VULKAN_LOADER_THUNKS_H */\n")
2963     def generate_vulkan_h(self, f):
2964         self._generate_copyright(f)
2965         f.write("#ifndef __WINE_VULKAN_H\n")
2966         f.write("#define __WINE_VULKAN_H\n\n")
2968         f.write("#include <windef.h>\n")
2969         f.write("#include <stdint.h>\n\n")
2971         f.write("/* Define WINE_VK_HOST to get 'host' headers. */\n")
2972         f.write("#ifdef WINE_VK_HOST\n")
2973         f.write("#define VKAPI_CALL\n")
2974         f.write('#define WINE_VK_ALIGN(x)\n')
2975         f.write("#endif\n\n")
2977         f.write("#ifndef VKAPI_CALL\n")
2978         f.write("#define VKAPI_CALL __stdcall\n")
2979         f.write("#endif\n\n")
2981         f.write("#ifndef VKAPI_PTR\n")
2982         f.write("#define VKAPI_PTR VKAPI_CALL\n")
2983         f.write("#endif\n\n")
2985         f.write("#ifndef WINE_VK_ALIGN\n")
2986         f.write("#define WINE_VK_ALIGN DECLSPEC_ALIGN\n")
2987         f.write("#endif\n\n")
2989         # The overall strategy is to define independent constants and datatypes,
2990         # prior to complex structures and function calls to avoid forward declarations.
2991         for const in self.registry.consts:
2992             # For now just generate things we may not need. The amount of parsing needed
2993             # to get some of the info is tricky as you need to figure out which structure
2994             # references a certain constant.
2995             f.write(const.definition())
2996         f.write("\n")
2998         for define in self.registry.defines:
2999             f.write(define.definition())
3001         for handle in self.registry.handles:
3002             # For backward compatibility also create definitions for aliases.
3003             # These types normally don't get pulled in as we use the new types
3004             # even in legacy functions if they are aliases.
3005             if handle.is_required() or handle.is_alias():
3006                  f.write(handle.definition())
3007         f.write("\n")
3009         for base_type in self.registry.base_types:
3010             f.write(base_type.definition())
3011         f.write("\n")
3013         for bitmask in self.registry.bitmasks:
3014             f.write(bitmask.definition())
3015         f.write("\n")
3017         # Define enums, this includes values for some of the bitmask types as well.
3018         for enum in self.registry.enums.values():
3019             if enum.required:
3020                 f.write(enum.definition())
3022         for fp in self.registry.funcpointers:
3023             if fp.required:
3024                 f.write(fp.definition())
3025         f.write("\n")
3027         # This generates both structures and unions. Since structures
3028         # may depend on other structures/unions, we need a list of
3029         # decoupled structs.
3030         # Note: unions are stored in structs for dependency reasons,
3031         # see comment in parsing section.
3032         structs = VkStruct.decouple_structs(self.registry.structs)
3033         for struct in structs:
3034             LOGGER.debug("Generating struct: {0}".format(struct.name))
3035             f.write(struct.definition(align=True))
3036             f.write("\n")
3038         for func in self.registry.funcs.values():
3039             if not func.is_required():
3040                 LOGGER.debug("Skipping PFN definition for: {0}".format(func.name))
3041                 continue
3043             f.write("typedef {0};\n".format(func.pfn(prefix="PFN", call_conv="VKAPI_PTR")))
3044         f.write("\n")
3046         f.write("#ifndef VK_NO_PROTOTYPES\n")
3047         for func in self.registry.funcs.values():
3048             if not func.is_required():
3049                 LOGGER.debug("Skipping API definition for: {0}".format(func.name))
3050                 continue
3052             LOGGER.debug("Generating API definition for: {0}".format(func.name))
3053             f.write("{0};\n".format(func.prototype(call_conv="VKAPI_CALL")))
3054         f.write("#endif /* VK_NO_PROTOTYPES */\n\n")
3056         f.write("#endif /* __WINE_VULKAN_H */\n")
3058     def generate_vulkan_driver_h(self, f):
3059         self._generate_copyright(f)
3060         f.write("#ifndef __WINE_VULKAN_DRIVER_H\n")
3061         f.write("#define __WINE_VULKAN_DRIVER_H\n\n")
3063         f.write("/* Wine internal vulkan driver version, needs to be bumped upon vulkan_funcs changes. */\n")
3064         f.write("#define WINE_VULKAN_DRIVER_VERSION {0}\n\n".format(DRIVER_VERSION))
3066         f.write("struct vulkan_funcs\n{\n")
3067         f.write("    /* Vulkan global functions. These are the only calls at this point a graphics driver\n")
3068         f.write("     * needs to provide. Other function calls will be provided indirectly by dispatch\n")
3069         f.write("     * tables part of dispatchable Vulkan objects such as VkInstance or vkDevice.\n")
3070         f.write("     */\n")
3072         for vk_func in self.registry.funcs.values():
3073             if not vk_func.is_driver_func():
3074                 continue
3076             pfn = vk_func.pfn()
3077             # Avoid PFN_vkVoidFunction in driver interface as Vulkan likes to put calling convention
3078             # stuff in there. For simplicity substitute with "void *".
3079             pfn = pfn.replace("PFN_vkVoidFunction", "void *")
3080             f.write("    {0};\n".format(pfn))
3082         f.write("\n")
3083         f.write("    /* winevulkan specific functions */\n")
3084         f.write("    VkSurfaceKHR (*p_wine_get_native_surface)(VkSurfaceKHR);\n")
3085         f.write("};\n\n")
3087         f.write("extern const struct vulkan_funcs * CDECL __wine_get_vulkan_driver(HDC hdc, UINT version);\n\n")
3089         f.write("static inline void *get_vulkan_driver_device_proc_addr(\n")
3090         f.write("        const struct vulkan_funcs *vulkan_funcs, const char *name)\n{\n")
3091         f.write("    if (!name || name[0] != 'v' || name[1] != 'k') return NULL;\n\n")
3092         f.write("    name += 2;\n\n")
3093         for vk_func in self.registry.funcs.values():
3094             if vk_func.is_driver_func() and vk_func.is_device_func():
3095                 f.write('    if (!strcmp(name, "{0}"))\n'.format(vk_func.name[2:]))
3096                 f.write('        return vulkan_funcs->p_{0};\n'.format(vk_func.name))
3097         f.write("\n")
3098         f.write("    return NULL;\n}\n\n")
3100         f.write("static inline void *get_vulkan_driver_instance_proc_addr(\n")
3101         f.write("        const struct vulkan_funcs *vulkan_funcs, VkInstance instance, const char *name)\n{\n")
3102         f.write("    if (!name || name[0] != 'v' || name[1] != 'k') return NULL;\n\n")
3103         f.write("    name += 2;\n\n")
3104         for vk_func in self.registry.funcs.values():
3105             if vk_func.is_driver_func() and vk_func.is_global_func() and vk_func.name != "vkGetInstanceProcAddr":
3106                 f.write('    if (!strcmp(name, "{0}"))\n'.format(vk_func.name[2:]))
3107                 f.write('        return vulkan_funcs->p_{0};\n'.format(vk_func.name))
3108         f.write("\n")
3109         f.write("    if (!instance) return NULL;\n\n")
3110         for vk_func in self.registry.funcs.values():
3111             if vk_func.is_driver_func() and (vk_func.is_instance_func() or vk_func.is_phys_dev_func()):
3112                 f.write('    if (!strcmp(name, "{0}"))\n'.format(vk_func.name[2:]))
3113                 f.write('        return vulkan_funcs->p_{0};\n'.format(vk_func.name))
3114         f.write("\n")
3115         f.write("    name -= 2;\n\n")
3116         f.write("    return get_vulkan_driver_device_proc_addr(vulkan_funcs, name);\n}\n\n")
3118         f.write("#endif /* __WINE_VULKAN_DRIVER_H */\n")
3120     def generate_vulkan_spec(self, f):
3121         self._generate_copyright(f, spec_file=True)
3122         f.write("@ stdcall -private vk_icdGetInstanceProcAddr(ptr str)\n")
3123         f.write("@ stdcall -private vk_icdGetPhysicalDeviceProcAddr(ptr str)\n")
3124         f.write("@ stdcall -private vk_icdNegotiateLoaderICDInterfaceVersion(ptr)\n")
3126         # Export symbols for all Vulkan Core functions.
3127         for func in self.registry.funcs.values():
3128             if not func.is_core_func():
3129                 continue
3131             # We support all Core functions except for VK_KHR_display* APIs.
3132             # Create stubs for unsupported Core functions.
3133             if func.is_required():
3134                 f.write(func.spec())
3135             else:
3136                 f.write("@ stub {0}\n".format(func.name))
3138         f.write("@ stdcall -private DllRegisterServer()\n")
3139         f.write("@ stdcall -private DllUnregisterServer()\n")
3141     def generate_vulkan_loader_spec(self, f):
3142         self._generate_copyright(f, spec_file=True)
3144         # Export symbols for all Vulkan Core functions.
3145         for func in self.registry.funcs.values():
3146             if not func.is_core_func():
3147                 continue
3149             # We support all Core functions except for VK_KHR_display* APIs.
3150             # Create stubs for unsupported Core functions.
3151             if func.is_required():
3152                 f.write(func.spec(symbol="winevulkan." + func.name))
3153             else:
3154                 f.write("@ stub {0}\n".format(func.name))
3157 class VkRegistry(object):
3158     def __init__(self, reg_filename):
3159         # Used for storage of type information.
3160         self.base_types = None
3161         self.bitmasks = None
3162         self.consts = None
3163         self.defines = None
3164         self.enums = None
3165         self.funcpointers = None
3166         self.handles = None
3167         self.structs = None
3169         # We aggregate all types in here for cross-referencing.
3170         self.funcs = {}
3171         self.types = {}
3173         self.version_regex = re.compile(
3174             r'^'
3175             r'VK_VERSION_'
3176             r'(?P<major>[0-9])'
3177             r'_'
3178             r'(?P<minor>[0-9])'
3179             r'$'
3180         )
3182         # Overall strategy for parsing the registry is to first
3183         # parse all type / function definitions. Then parse
3184         # features and extensions to decide which types / functions
3185         # to actually 'pull in' for code generation. For each type or
3186         # function call we want we set a member 'required' to True.
3187         tree = ET.parse(reg_filename)
3188         root = tree.getroot()
3189         self._parse_enums(root)
3190         self._parse_types(root)
3191         self._parse_commands(root)
3193         # Pull in any required types and functions.
3194         self._parse_features(root)
3195         self._parse_extensions(root)
3197         self._match_object_types()
3199         self.copyright = root.find('./comment').text
3201     def _is_feature_supported(self, feature):
3202         version = self.version_regex.match(feature)
3203         if not version:
3204             return True
3206         version = tuple(map(int, version.group('major', 'minor')))
3207         return version <= WINE_VK_VERSION
3209     def _is_extension_supported(self, extension):
3210         # We disable some extensions as either we haven't implemented
3211         # support yet or because they are for platforms other than win32.
3212         return extension not in UNSUPPORTED_EXTENSIONS
3214     def _mark_command_required(self, command):
3215         """ Helper function to mark a certain command and the datatypes it needs as required."""
3216         def mark_bitmask_dependencies(bitmask, types):
3217             if bitmask.requires is not None:
3218                 types[bitmask.requires]["data"].required = True
3220         def mark_funcpointer_dependencies(fp, types):
3221             for m in fp.members:
3222                 type_info = types[m.type]
3224                 # Complex types have a matching definition e.g. VkStruct.
3225                 # Not needed for base types such as uint32_t.
3226                 if "data" in type_info:
3227                     types[m.type]["data"].required = True
3229         def mark_struct_dependencies(struct, types):
3230              for m in struct:
3231                 type_info = types[m.type]
3233                 # Complex types have a matching definition e.g. VkStruct.
3234                 # Not needed for base types such as uint32_t.
3235                 if "data" in type_info:
3236                     types[m.type]["data"].required = True
3238                 if type_info["category"] == "struct":
3239                     # Yay, recurse
3240                     mark_struct_dependencies(type_info["data"], types)
3241                 elif type_info["category"] == "funcpointer":
3242                     mark_funcpointer_dependencies(type_info["data"], types)
3243                 elif type_info["category"] == "bitmask":
3244                     mark_bitmask_dependencies(type_info["data"], types)
3246         func = self.funcs[command]
3247         func.required = True
3249         # Pull in return type
3250         if func.type != "void":
3251             self.types[func.type]["data"].required = True
3253         # Analyze parameter dependencies and pull in any type needed.
3254         for p in func.params:
3255             type_info = self.types[p.type]
3257             # Check if we are dealing with a complex type e.g. VkEnum, VkStruct and others.
3258             if "data" not in type_info:
3259                 continue
3261             # Mark the complex type as required.
3262             type_info["data"].required = True
3263             if type_info["category"] == "struct":
3264                 struct = type_info["data"]
3265                 mark_struct_dependencies(struct, self.types)
3266             elif type_info["category"] == "bitmask":
3267                 mark_bitmask_dependencies(type_info["data"], self.types)
3269     def _match_object_types(self):
3270         """ Matches each handle with the correct object type. """
3271         # Use upper case comparison for simplicity.
3272         object_types = {}
3273         for value in self.enums["VkObjectType"].values:
3274             object_name = "VK" + value.name[len("VK_OBJECT_TYPE"):].replace("_", "")
3275             object_types[object_name] = value.name
3277         for handle in self.handles:
3278             if not handle.is_required():
3279                 continue
3280             handle.object_type = object_types.get(handle.name.upper())
3281             if not handle.object_type:
3282                 LOGGER.warning("No object type found for {}".format(handle.name))
3284     def _parse_commands(self, root):
3285         """ Parse command section containing the Vulkan function calls. """
3286         funcs = {}
3287         commands = root.findall("./commands/")
3289         # As of Vulkan 1.1, various extensions got promoted to Core.
3290         # The old commands (e.g. KHR) are available for backwards compatibility
3291         # and are marked in vk.xml as 'alias' to the non-extension type.
3292         # The registry likes to avoid data duplication, so parameters and other
3293         # metadata need to be looked up from the Core command.
3294         # We parse the alias commands in a second pass.
3295         alias_commands = []
3296         for command in commands:
3297             alias_name = command.attrib.get("alias")
3298             if alias_name:
3299                 alias_commands.append(command)
3300                 continue
3302             func = VkFunction.from_xml(command, self.types)
3303             funcs[func.name] = func
3305         for command in alias_commands:
3306             alias_name = command.attrib.get("alias")
3307             alias = funcs[alias_name]
3308             func = VkFunction.from_alias(command, alias)
3309             funcs[func.name] = func
3311         # To make life easy for the code generation, separate all function
3312         # calls out in the 4 types of Vulkan functions:
3313         # device, global, physical device and instance.
3314         device_funcs = []
3315         global_funcs = []
3316         phys_dev_funcs = []
3317         instance_funcs = []
3318         for func in funcs.values():
3319             if func.is_device_func():
3320                 device_funcs.append(func)
3321             elif func.is_global_func():
3322                 global_funcs.append(func)
3323             elif func.is_phys_dev_func():
3324                 phys_dev_funcs.append(func)
3325             else:
3326                 instance_funcs.append(func)
3328         # Sort function lists by name and store them.
3329         self.device_funcs = sorted(device_funcs, key=lambda func: func.name)
3330         self.global_funcs = sorted(global_funcs, key=lambda func: func.name)
3331         self.phys_dev_funcs = sorted(phys_dev_funcs, key=lambda func: func.name)
3332         self.instance_funcs = sorted(instance_funcs, key=lambda func: func.name)
3334         # The funcs dictionary is used as a convenient way to lookup function
3335         # calls when needed e.g. to adjust member variables.
3336         self.funcs = OrderedDict(sorted(funcs.items()))
3338     def _parse_enums(self, root):
3339         """ Parse enums section or better described as constants section. """
3340         enums = {}
3341         self.consts = []
3342         for enum in root.findall("./enums"):
3343             name = enum.attrib.get("name")
3344             _type = enum.attrib.get("type")
3346             if _type in ("enum", "bitmask"):
3347                 enums[name] = VkEnum.from_xml(enum)
3348             else:
3349                 # If no type is set, we are dealing with API constants.
3350                 for value in enum.findall("enum"):
3351                     # If enum is an alias, set the value to the alias name.
3352                     # E.g. VK_LUID_SIZE_KHR is an alias to VK_LUID_SIZE.
3353                     alias = value.attrib.get("alias")
3354                     if alias:
3355                         self.consts.append(VkConstant(value.attrib.get("name"), alias))
3356                     else:
3357                         self.consts.append(VkConstant(value.attrib.get("name"), value.attrib.get("value")))
3359         self.enums = OrderedDict(sorted(enums.items()))
3361     def _process_require_enum(self, enum_elem, ext=None, only_aliased=False):
3362         if "extends" in enum_elem.keys():
3363             enum = self.types[enum_elem.attrib["extends"]]["data"]
3365             # Need to define VkEnumValues which were aliased to by another value. This is necessary
3366             # from VK spec version 1.2.135 where the provisional VK_KHR_ray_tracing extension was
3367             # added which altered VK_NV_ray_tracing's VkEnumValues to alias to the provisional
3368             # extension.
3369             aliased = False
3370             for _, t in self.types.items():
3371                 if t["category"] != "enum":
3372                     continue
3373                 if not t["data"]:
3374                     continue
3375                 for value in t["data"].values:
3376                     if value.alias == enum_elem.attrib["name"]:
3377                         aliased = True
3379             if only_aliased and not aliased:
3380                 return
3382             if "bitpos" in enum_elem.keys():
3383                 # We need to add an extra value to an existing enum type.
3384                 # E.g. VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG to VkFormatFeatureFlagBits.
3385                 enum.create_bitpos(enum_elem.attrib["name"], int(enum_elem.attrib["bitpos"]))
3387             elif "offset" in enum_elem.keys():
3388                 # Extensions promoted to Core, have the extension number as part
3389                 # of the enum value. Else retrieve from the extension tag.
3390                 if enum_elem.attrib.get("extnumber"):
3391                     ext_number = int(enum_elem.attrib.get("extnumber"))
3392                 else:
3393                     ext_number = int(ext.attrib["number"])
3394                 offset = int(enum_elem.attrib["offset"])
3395                 value = EXT_BASE + (ext_number - 1) * EXT_BLOCK_SIZE + offset
3397                 # Deal with negative values.
3398                 direction = enum_elem.attrib.get("dir")
3399                 if direction is not None:
3400                     value = -value
3402                 enum.create_value(enum_elem.attrib["name"], str(value))
3404             elif "value" in enum_elem.keys():
3405                 enum.create_value(enum_elem.attrib["name"], enum_elem.attrib["value"])
3406             elif "alias" in enum_elem.keys():
3407                 enum.create_alias(enum_elem.attrib["name"], enum_elem.attrib["alias"])
3409         elif "value" in enum_elem.keys():
3410             # Constants are not aliased, no need to add them here, they'll get added later on.
3411             if only_aliased:
3412                 return
3414             self.consts.append(VkConstant(enum_elem.attrib["name"], enum_elem.attrib["value"]))
3416     @staticmethod
3417     def _require_type(type_info):
3418         if type_info.is_alias():
3419             type_info = type_info.alias
3420         type_info.required = True
3421         if type(type_info) == VkStruct:
3422             for member in type_info.members:
3423                 if "data" in member.type_info:
3424                   VkRegistry._require_type(member.type_info["data"])
3426     def _parse_extensions(self, root):
3427         """ Parse extensions section and pull in any types and commands for this extension. """
3428         extensions = []
3429         exts = root.findall("./extensions/extension")
3430         deferred_exts = []
3431         skipped_exts = UNSUPPORTED_EXTENSIONS.copy()
3433         def process_ext(ext, deferred=False):
3434             ext_name = ext.attrib["name"]
3436             # Set extension name on any functions calls part of this extension as we
3437             # were not aware of the name during initial parsing.
3438             commands = ext.findall("require/command")
3439             for command in commands:
3440                 cmd_name = command.attrib["name"]
3441                 # Need to verify that the command is defined, and otherwise skip it.
3442                 # vkCreateScreenSurfaceQNX is declared in <extensions> but not defined in
3443                 # <commands>. A command without a definition cannot be enabled, so it's valid for
3444                 # the XML file to handle this, but because of the manner in which we parse the XML
3445                 # file we pre-populate from <commands> before we check if a command is enabled.
3446                 if cmd_name in self.funcs:
3447                     self.funcs[cmd_name].extensions.append(ext_name)
3449             # Some extensions are not ready or have numbers reserved as a place holder.
3450             if ext.attrib["supported"] == "disabled":
3451                 LOGGER.debug("Skipping disabled extension: {0}".format(ext_name))
3452                 skipped_exts.append(ext_name)
3453                 return
3455             # Defer extensions with 'sortorder' as they are order-dependent for spec-parsing.
3456             if not deferred and "sortorder" in ext.attrib:
3457                 deferred_exts.append(ext)
3458                 return
3460             # Disable highly experimental extensions as the APIs are unstable and can
3461             # change between minor Vulkan revisions until API is final and becomes KHR
3462             # or NV.
3463             if ("KHX" in ext_name or "NVX" in ext_name) and ext_name not in ALLOWED_X_EXTENSIONS:
3464                 LOGGER.debug("Skipping experimental extension: {0}".format(ext_name))
3465                 skipped_exts.append(ext_name)
3466                 return
3468             # Extensions can define VkEnumValues which alias to provisional extensions. Pre-process
3469             # extensions to define any required VkEnumValues before the platform check below.
3470             for require in ext.findall("require"):
3471                 # Extensions can add enum values to Core / extension enums, so add these.
3472                 for enum_elem in require.findall("enum"):
3473                     self._process_require_enum(enum_elem, ext, only_aliased=True)
3475             platform = ext.attrib.get("platform")
3476             if platform and platform != "win32":
3477                 LOGGER.debug("Skipping extensions {0} for platform {1}".format(ext_name, platform))
3478                 skipped_exts.append(ext_name)
3479                 return
3481             if not self._is_extension_supported(ext_name):
3482                 LOGGER.debug("Skipping unsupported extension: {0}".format(ext_name))
3483                 skipped_exts.append(ext_name)
3484                 return
3485             elif "requires" in ext.attrib:
3486                 # Check if this extension builds on top of another unsupported extension.
3487                 requires = ext.attrib["requires"].split(",")
3488                 if len(set(requires).intersection(skipped_exts)) > 0:
3489                     skipped_exts.append(ext_name)
3490                     return
3492             LOGGER.debug("Loading extension: {0}".format(ext_name))
3494             # Extensions can define one or more require sections each requiring
3495             # different features (e.g. Vulkan 1.1). Parse each require section
3496             # separately, so we can skip sections we don't want.
3497             for require in ext.findall("require"):
3498                 # Extensions can add enum values to Core / extension enums, so add these.
3499                 for enum_elem in require.findall("enum"):
3500                     self._process_require_enum(enum_elem, ext)
3502                 for t in require.findall("type"):
3503                     type_info = self.types[t.attrib["name"]]["data"]
3504                     self._require_type(type_info)
3505                 feature = require.attrib.get("feature")
3506                 if feature and not self._is_feature_supported(feature):
3507                     continue
3509                 required_extension = require.attrib.get("extension")
3510                 if required_extension and not self._is_extension_supported(required_extension):
3511                     continue
3513                 # Pull in any commands we need. We infer types to pull in from the command
3514                 # as well.
3515                 for command in require.findall("command"):
3516                     cmd_name = command.attrib["name"]
3517                     self._mark_command_required(cmd_name)
3520             # Store a list with extensions.
3521             ext_info = {"name" : ext_name, "type" : ext.attrib["type"]}
3522             extensions.append(ext_info)
3525         # Process extensions, allowing for sortorder to defer extension processing
3526         for ext in exts:
3527             process_ext(ext)
3529         deferred_exts.sort(key=lambda ext: ext.attrib["sortorder"])
3531         # Respect sortorder
3532         for ext in deferred_exts:
3533             process_ext(ext, deferred=True)
3535         # Sort in alphabetical order.
3536         self.extensions = sorted(extensions, key=lambda ext: ext["name"])
3538     def _parse_features(self, root):
3539         """ Parse the feature section, which describes Core commands and types needed. """
3541         for feature in root.findall("./feature"):
3542             feature_name = feature.attrib["name"]
3543             for require in feature.findall("require"):
3544                 LOGGER.info("Including features for {0}".format(require.attrib.get("comment")))
3545                 for tag in require:
3546                     if tag.tag == "comment":
3547                         continue
3548                     elif tag.tag == "command":
3549                         if not self._is_feature_supported(feature_name):
3550                             continue
3551                         name = tag.attrib["name"]
3552                         self._mark_command_required(name)
3553                     elif tag.tag == "enum":
3554                         self._process_require_enum(tag)
3555                     elif tag.tag == "type":
3556                         name = tag.attrib["name"]
3558                         # Skip pull in for vk_platform.h for now.
3559                         if name == "vk_platform":
3560                             continue
3562                         type_info = self.types[name]
3563                         type_info["data"].required = True
3565     def _parse_types(self, root):
3566         """ Parse types section, which contains all data types e.g. structs, typedefs etcetera. """
3567         types = root.findall("./types/type")
3569         base_types = []
3570         bitmasks = []
3571         defines = []
3572         funcpointers = []
3573         handles = []
3574         structs = []
3576         alias_types = []
3577         for t in types:
3578             type_info = {}
3579             type_info["category"] = t.attrib.get("category", None)
3580             type_info["requires"] = t.attrib.get("requires", None)
3582             # We parse aliases in a second pass when we know more.
3583             alias = t.attrib.get("alias")
3584             if alias:
3585                 LOGGER.debug("Alias found: {0}".format(alias))
3586                 alias_types.append(t)
3587                 continue
3589             if type_info["category"] in ["include"]:
3590                 continue
3592             if type_info["category"] == "basetype":
3593                 name = t.find("name").text
3594                 _type = None
3595                 if not t.find("type") is None:
3596                     _type = t.find("type").text
3597                 basetype = VkBaseType(name, _type)
3598                 base_types.append(basetype)
3599                 type_info["data"] = basetype
3601             # Basic C types don't need us to define them, but we do need data for them
3602             if type_info["requires"] == "vk_platform":
3603                 requires = type_info["requires"]
3604                 basic_c = VkBaseType(name, _type, requires=requires)
3605                 type_info["data"] = basic_c
3607             if type_info["category"] == "bitmask":
3608                 name = t.find("name").text
3609                 _type = t.find("type").text
3611                 # Most bitmasks have a requires attribute used to pull in
3612                 # required '*FlagBits" enum.
3613                 requires = type_info["requires"]
3614                 bitmask = VkBaseType(name, _type, requires=requires)
3615                 bitmasks.append(bitmask)
3616                 type_info["data"] = bitmask
3618             if type_info["category"] == "define":
3619                 define = VkDefine.from_xml(t)
3620                 defines.append(define)
3621                 type_info["data"] = define
3623             if type_info["category"] == "enum":
3624                 name = t.attrib.get("name")
3625                 # The type section only contains enum names, not the actual definition.
3626                 # Since we already parsed the enum before, just link it in.
3627                 try:
3628                     type_info["data"] = self.enums[name]
3629                 except KeyError as e:
3630                     # Not all enums seem to be defined yet, typically that's for
3631                     # ones ending in 'FlagBits' where future extensions may add
3632                     # definitions.
3633                     type_info["data"] = None
3635             if type_info["category"] == "funcpointer":
3636                 funcpointer = VkFunctionPointer.from_xml(t)
3637                 funcpointers.append(funcpointer)
3638                 type_info["data"] = funcpointer
3640             if type_info["category"] == "handle":
3641                 handle = VkHandle.from_xml(t)
3642                 handles.append(handle)
3643                 type_info["data"] = handle
3645             if type_info["category"] in ["struct", "union"]:
3646                 # We store unions among structs as some structs depend
3647                 # on unions. The types are very similar in parsing and
3648                 # generation anyway. The official Vulkan scripts use
3649                 # a similar kind of hack.
3650                 struct = VkStruct.from_xml(t)
3651                 structs.append(struct)
3652                 type_info["data"] = struct
3654             # Name is in general within a name tag else it is an optional
3655             # attribute on the type tag.
3656             name_elem = t.find("name")
3657             if name_elem is not None:
3658                 type_info["name"] = name_elem.text
3659             else:
3660                 type_info["name"] = t.attrib.get("name", None)
3662             # Store all type data in a shared dictionary, so we can easily
3663             # look up information for a given type. There are no duplicate
3664             # names.
3665             self.types[type_info["name"]] = type_info
3667         # Second pass for alias types, so we can retrieve all data from
3668         # the aliased object.
3669         for t in alias_types:
3670             type_info = {}
3671             type_info["category"] = t.attrib.get("category")
3672             type_info["name"] = t.attrib.get("name")
3674             alias = t.attrib.get("alias")
3676             if type_info["category"] == "bitmask":
3677                 bitmask = VkBaseType(type_info["name"], alias, alias=self.types[alias]["data"])
3678                 bitmasks.append(bitmask)
3679                 type_info["data"] = bitmask
3681             if type_info["category"] == "enum":
3682                 enum = VkEnum.from_alias(t, self.types[alias]["data"])
3683                 type_info["data"] = enum
3684                 self.enums[enum.name] = enum
3686             if type_info["category"] == "handle":
3687                 handle = VkHandle.from_alias(t, self.types[alias]["data"])
3688                 handles.append(handle)
3689                 type_info["data"] = handle
3691             if type_info["category"] == "struct":
3692                 struct = VkStruct.from_alias(t, self.types[alias]["data"])
3693                 structs.append(struct)
3694                 type_info["data"] = struct
3696             self.types[type_info["name"]] = type_info
3698         # We need detailed type information during code generation
3699         # on structs for alignment reasons. Unfortunately structs
3700         # are parsed among other types, so there is no guarantee
3701         # that any types needed have been parsed already, so set
3702         # the data now.
3703         for struct in structs:
3704             struct.set_type_info(self.types)
3706             # Alias structures have enum values equivalent to those of the
3707             # structure which they are aliased against. we need to ignore alias
3708             # structs when populating the struct extensions list, otherwise we
3709             # will create duplicate case entries.
3710             if struct.alias:
3711                 continue
3713             for structextend in struct.structextends:
3714                 s = self.types[structextend]["data"]
3715                 s.struct_extensions.append(struct)
3717         # Guarantee everything is sorted, so code generation doesn't have
3718         # to deal with this.
3719         self.base_types = sorted(base_types, key=lambda base_type: base_type.name)
3720         self.bitmasks = sorted(bitmasks, key=lambda bitmask: bitmask.name)
3721         self.defines = defines
3722         self.enums = OrderedDict(sorted(self.enums.items()))
3723         self.funcpointers = sorted(funcpointers, key=lambda fp: fp.name)
3724         self.handles = sorted(handles, key=lambda handle: handle.name)
3725         self.structs = sorted(structs, key=lambda struct: struct.name)
3727 def generate_vulkan_json(f):
3728     f.write("{\n")
3729     f.write("    \"file_format_version\": \"1.0.0\",\n")
3730     f.write("    \"ICD\": {\n")
3731     f.write("        \"library_path\": \".\\\\winevulkan.dll\",\n")
3732     f.write("        \"api_version\": \"{0}\"\n".format(VK_XML_VERSION))
3733     f.write("    }\n")
3734     f.write("}\n")
3736 def set_working_directory():
3737     path = os.path.abspath(__file__)
3738     path = os.path.dirname(path)
3739     os.chdir(path)
3741 def download_vk_xml(filename):
3742     url = "https://raw.githubusercontent.com/KhronosGroup/Vulkan-Docs/v{0}/xml/vk.xml".format(VK_XML_VERSION)
3743     if not os.path.isfile(filename):
3744         urllib.request.urlretrieve(url, filename)
3746 def main():
3747     parser = argparse.ArgumentParser()
3748     parser.add_argument("-v", "--verbose", action="count", default=0, help="increase output verbosity")
3749     parser.add_argument("-x", "--xml", default=None, type=str, help="path to specification XML file")
3751     args = parser.parse_args()
3752     if args.verbose == 0:
3753         LOGGER.setLevel(logging.WARNING)
3754     elif args.verbose == 1:
3755         LOGGER.setLevel(logging.INFO)
3756     else: # > 1
3757         LOGGER.setLevel(logging.DEBUG)
3759     set_working_directory()
3761     if args.xml:
3762         vk_xml = args.xml
3763     else:
3764         vk_xml = "vk-{0}.xml".format(VK_XML_VERSION)
3765         download_vk_xml(vk_xml)
3767     registry = VkRegistry(vk_xml)
3768     generator = VkGenerator(registry)
3770     with open(WINE_VULKAN_H, "w") as f:
3771         generator.generate_vulkan_h(f)
3773     with open(WINE_VULKAN_DRIVER_H, "w") as f:
3774         generator.generate_vulkan_driver_h(f)
3776     with open(WINE_VULKAN_THUNKS_H, "w") as f:
3777         generator.generate_thunks_h(f, "wine_")
3779     with open(WINE_VULKAN_THUNKS_C, "w") as f:
3780         generator.generate_thunks_c(f, "wine_")
3782     with open(WINE_VULKAN_LOADER_THUNKS_H, "w") as f:
3783         generator.generate_loader_thunks_h(f)
3785     with open(WINE_VULKAN_LOADER_THUNKS_C, "w") as f:
3786         generator.generate_loader_thunks_c(f)
3788     with open(WINE_VULKAN_JSON, "w") as f:
3789         generate_vulkan_json(f)
3791     with open(WINE_VULKAN_SPEC, "w") as f:
3792         generator.generate_vulkan_spec(f)
3794     with open(WINE_VULKAN_LOADER_SPEC, "w") as f:
3795         generator.generate_vulkan_loader_spec(f)
3797 if __name__ == "__main__":
3798     main()