ntdll: Make wine_build a hidden symbol.
[wine.git] / dlls / winevulkan / make_vulkan
blob55b5b71691e776461fcdcc673b3e2c2e81af9a2b
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.188"
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_semaphore_win32",
103     # Relates to external_semaphore and needs type conversions in bitflags.
104     "VK_KHR_shared_presentable_image", # Needs WSI work.
105     "VK_KHR_win32_keyed_mutex",
106     "VK_NV_external_memory_rdma", # Needs shared resources work.
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     # Deprecated extensions
120     "VK_NV_external_memory_capabilities",
121     "VK_NV_external_memory_win32",
124 # Either internal extensions which aren't present on the win32 platform which
125 # winevulkan may nonetheless use, or extensions we want to generate headers for
126 # but not expose to applications (useful for test commits)
127 UNEXPOSED_EXTENSIONS = {
128     "VK_KHR_external_memory_win32",
131 # The Vulkan loader provides entry-points for core functionality and important
132 # extensions. Based on vulkan-1.def this amounts to WSI extensions on 1.0.51.
133 CORE_EXTENSIONS = [
134     "VK_KHR_display",
135     "VK_KHR_display_swapchain",
136     "VK_KHR_get_surface_capabilities2",
137     "VK_KHR_surface",
138     "VK_KHR_swapchain",
139     "VK_KHR_win32_surface",
142 # Some experimental extensions are used by shipping applications so their API is extremely unlikely
143 # to change in a backwards-incompatible way. Allow translation of those extensions with WineVulkan.
144 ALLOWED_X_EXTENSIONS = [
145     "VK_NVX_binary_import",
146     "VK_NVX_image_view_handle",
149 # Functions part of our winevulkan graphics driver interface.
150 # DRIVER_VERSION should be bumped on any change to driver interface
151 # in FUNCTION_OVERRIDES
152 DRIVER_VERSION = 10
154 class ThunkType(Enum):
155     NONE = 1
156     PUBLIC = 2
157     PRIVATE = 3
159 # Table of functions for which we have a special implementation.
160 # These are regular device / instance functions for which we need
161 # to do more work compared to a regular thunk or because they are
162 # part of the driver interface.
163 # - dispatch set whether we need a function pointer in the device
164 #   / instance dispatch table.
165 # - driver sets whether the API is part of the driver interface.
166 # - thunk sets whether to create a thunk in vulkan_thunks.c.
167 #   - NONE means there's a fully custom implementation.
168 #   - PUBLIC means the implementation is fully auto generated.
169 #   - PRIVATE thunks can be used in custom implementations for
170 #     struct conversion.
171 # - loader_thunk sets whether to create a thunk for unix_funcs.
172 FUNCTION_OVERRIDES = {
173     # Global functions
174     "vkCreateInstance" : {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE},
175     "vkEnumerateInstanceExtensionProperties" : {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE},
176     "vkEnumerateInstanceLayerProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.NONE},
177     "vkEnumerateInstanceVersion": {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE},
178     "vkGetInstanceProcAddr": {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.NONE},
180     # Instance functions
181     "vkCreateDevice" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
182     "vkDestroyInstance" : {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE },
183     "vkEnumerateDeviceExtensionProperties" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
184     "vkEnumerateDeviceLayerProperties": {"dispatch": True, "driver": False, "thunk": ThunkType.NONE},
185     "vkEnumeratePhysicalDeviceGroups" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
186     "vkEnumeratePhysicalDevices" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
187     "vkGetPhysicalDeviceExternalBufferProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
188     "vkGetPhysicalDeviceExternalFenceProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
189     "vkGetPhysicalDeviceExternalSemaphoreProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
190     "vkGetPhysicalDeviceImageFormatProperties2" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE},
191     "vkGetPhysicalDeviceProperties2" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PUBLIC, "loader_thunk" : ThunkType.PRIVATE},
192     "vkGetPhysicalDeviceProperties2KHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PUBLIC, "loader_thunk" : ThunkType.PRIVATE},
194     # Device functions
195     "vkAllocateCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
196     "vkCreateCommandPool" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
197     "vkDestroyCommandPool" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
198     "vkDestroyDevice" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
199     "vkFreeCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
200     "vkGetDeviceProcAddr" : {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.NONE},
201     "vkGetDeviceQueue" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
202     "vkGetDeviceQueue2" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
204     # VK_KHR_surface
205     "vkDestroySurfaceKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.NONE},
206     "vkGetPhysicalDeviceSurfaceSupportKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
207     "vkGetPhysicalDeviceSurfaceCapabilitiesKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PRIVATE},
208     "vkGetPhysicalDeviceSurfaceFormatsKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
209     "vkGetPhysicalDeviceSurfacePresentModesKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
211     # VK_KHR_get_surface_capabilities2
212     "vkGetPhysicalDeviceSurfaceCapabilities2KHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PRIVATE},
213     "vkGetPhysicalDeviceSurfaceFormats2KHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
215     # VK_KHR_win32_surface
216     "vkCreateWin32SurfaceKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.NONE},
217     "vkGetPhysicalDeviceWin32PresentationSupportKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
219     # VK_KHR_swapchain
220     "vkCreateSwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
221     "vkDestroySwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
222     "vkGetSwapchainImagesKHR": {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
223     "vkQueuePresentKHR": {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
225     # VK_KHR_external_fence_capabilities
226     "vkGetPhysicalDeviceExternalFencePropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
228     # VK_KHR_external_memory_capabilities
229     "vkGetPhysicalDeviceExternalBufferPropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
230     "vkGetPhysicalDeviceImageFormatProperties2KHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE},
232     # VK_KHR_external_semaphore_capabilities
233     "vkGetPhysicalDeviceExternalSemaphorePropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
235     # VK_KHR_device_group_creation
236     "vkEnumeratePhysicalDeviceGroupsKHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
238     # VK_KHR_device_group
239     "vkGetDeviceGroupSurfacePresentModesKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
240     "vkGetPhysicalDevicePresentRectanglesKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
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},
250     # VK_EXT_debug_report
251     "vkCreateDebugReportCallbackEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
252     "vkDestroyDebugReportCallbackEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
255 STRUCT_CHAIN_CONVERSIONS = {
256     # Ignore to not confuse host loader.
257     "VkDeviceCreateInfo": ["VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO"],
258     "VkInstanceCreateInfo": ["VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO"],
262 class Direction(Enum):
263     """ Parameter direction: input, output, input_output. """
264     INPUT = 1
265     OUTPUT = 2
266     INPUT_OUTPUT = 3
269 class VkBaseType(object):
270     def __init__(self, name, _type, alias=None, requires=None):
271         """ Vulkan base type class.
273         VkBaseType is mostly used by Vulkan to define its own
274         base types like VkFlags through typedef out of e.g. uint32_t.
276         Args:
277             name (:obj:'str'): Name of the base type.
278             _type (:obj:'str'): Underlying type
279             alias (bool): type is an alias or not.
280             requires (:obj:'str', optional): Other types required.
281                 Often bitmask values pull in a *FlagBits type.
282         """
283         self.name = name
284         self.type = _type
285         self.alias = alias
286         self.requires = requires
287         self.required = False
289     def definition(self):
290         # Definition is similar for alias or non-alias as type
291         # is already set to alias.
292         if not self.type is None:
293             return "typedef {0} {1};\n".format(self.type, self.name)
294         else:
295             return "struct {0};\n".format(self.name)
297     def is_alias(self):
298         return bool(self.alias)
301 class VkConstant(object):
302     def __init__(self, name, value):
303         self.name = name
304         self.value = value
306     def definition(self):
307         text = "#define {0} {1}\n".format(self.name, self.value)
308         return text
311 class VkDefine(object):
312     def __init__(self, name, value):
313         self.name = name
314         self.value = value
316     @staticmethod
317     def from_xml(define):
318         name_elem = define.find("name")
320         if name_elem is None:
321             # <type category="define" name="some_name">some_value</type>
322             name = define.attrib.get("name")
324             # We override behavior of VK_USE_64_BIT_PTR_DEFINES as the default non-dispatchable handle
325             # definition various between 64-bit (uses pointers) and 32-bit (uses uint64_t).
326             # This complicates TRACEs in the thunks, so just use uint64_t.
327             if name == "VK_USE_64_BIT_PTR_DEFINES":
328                 value = "#define VK_USE_64_BIT_PTR_DEFINES 0"
329             else:
330                 value = define.text
331             return VkDefine(name, value)
333         # With a name element the structure is like:
334         # <type category="define"><name>some_name</name>some_value</type>
335         name = name_elem.text
337         # Perform minimal parsing for Vulkan constants, which we don't need, but are referenced
338         # elsewhere in vk.xml.
339         # - VK_API_VERSION is a messy, deprecated constant and we don't want generate code for it.
340         # - AHardwareBuffer/ANativeWindow are forward declarations for Android types, which leaked
341         #   into the define region.
342         if name in ["VK_API_VERSION", "AHardwareBuffer", "ANativeWindow", "CAMetalLayer"]:
343             return VkDefine(name, None)
345         # The body of the define is basically unstructured C code. It is not meant for easy parsing.
346         # Some lines contain deprecated values or comments, which we try to filter out.
347         value = ""
348         for line in define.text.splitlines():
349             # Skip comments or deprecated values.
350             if "//" in line:
351                 continue
352             value += line
354         for child in define:
355             value += child.text
356             if child.tail is not None:
357                 # Split comments for VK_API_VERSION_1_0 / VK_API_VERSION_1_1
358                 if "//" in child.tail:
359                     value += child.tail.split("//")[0]
360                 else:
361                     value += child.tail
363         return VkDefine(name, value.rstrip(' '))
365     def definition(self):
366         if self.value is None:
367             return ""
369         # Nothing to do as the value was already put in the right form during parsing.
370         return "{0}\n".format(self.value)
373 class VkEnum(object):
374     def __init__(self, name, bitwidth, alias=None):
375         if not bitwidth in [32, 64]:
376             LOGGER.error("unknown bitwidth {0} for {1}".format(bitwidth, name))
377         self.name = name
378         self.bitwidth = bitwidth
379         self.values = [] if alias == None else alias.values
380         self.required = False
381         self.alias = alias
382         self.aliased_by = []
384     @staticmethod
385     def from_alias(enum, alias):
386         name = enum.attrib.get("name")
387         aliasee = VkEnum(name, alias.bitwidth, alias=alias)
389         alias.add_aliased_by(aliasee)
390         return aliasee
392     @staticmethod
393     def from_xml(enum):
394         name = enum.attrib.get("name")
395         bitwidth = int(enum.attrib.get("bitwidth", "32"))
396         result = VkEnum(name, bitwidth)
398         for v in enum.findall("enum"):
399             value_name = v.attrib.get("name")
400             # Value is either a value or a bitpos, only one can exist.
401             value = v.attrib.get("value")
402             alias_name = v.attrib.get("alias")
403             if alias_name:
404                 result.create_alias(value_name, alias_name)
405             elif value:
406                 result.create_value(value_name, value)
407             else:
408                 # bitmask
409                 result.create_bitpos(value_name, int(v.attrib.get("bitpos")))
411         if bitwidth == 32:
412             # vulkan.h contains a *_MAX_ENUM value set to 32-bit at the time of writing,
413             # which is to prepare for extensions as they can add values and hence affect
414             # the size definition.
415             max_name = re.sub(r'([0-9a-z_])([A-Z0-9])',r'\1_\2', name).upper() + "_MAX_ENUM"
416             result.create_value(max_name, "0x7fffffff")
418         return result
420     def create_alias(self, name, alias_name):
421         """ Create an aliased value for this enum """
422         # Older GCC versions need a literal to initialize a static const uint64_t
423         # which is what we use for 64bit bitmasks.
424         if self.bitwidth == 64:
425             alias = next(x for x in self.values if x.name == alias_name)
426             self.add(VkEnumValue(name, self.bitwidth, value=alias.value, hex=alias.hex, alias=alias_name))
427         else:
428             self.add(VkEnumValue(name, self.bitwidth, alias=alias_name))
430     def create_value(self, name, value):
431         """ Create a new value for this enum """
432         # Some values are in hex form. We want to preserve the hex representation
433         # at least when we convert back to a string. Internally we want to use int.
434         hex = "0x" in value
435         self.add(VkEnumValue(name, self.bitwidth, value=int(value, 0), hex=hex))
437     def create_bitpos(self, name, pos):
438         """ Create a new bitmask value for this enum """
439         self.add(VkEnumValue(name, self.bitwidth, value=(1 << pos), hex=True))
441     def add(self, value):
442         """ Add a value to enum. """
444         # Extensions can add new enum values. When an extension is promoted to Core
445         # the registry defines the value twice once for old extension and once for
446         # new Core features. Add the duplicate if it's explicitly marked as an
447         # alias, otherwise ignore it.
448         for v in self.values:
449             if not value.is_alias() and v.value == value.value:
450                 LOGGER.debug("Adding duplicate enum value {0} to {1}".format(v, self.name))
451                 return
452         # Avoid adding duplicate aliases multiple times
453         if not any(x.name == value.name for x in self.values):
454             self.values.append(value)
456     def definition(self):
457         if self.is_alias():
458             return ""
460         default_value = 0x7ffffffe if self.bitwidth == 32 else 0xfffffffffffffffe
462         # Print values sorted, values can have been added in a random order.
463         values = sorted(self.values, key=lambda value: value.value if value.value is not None else default_value)
465         if self.bitwidth == 32:
466             text = "typedef enum {0}\n{{\n".format(self.name)
467             for value in values:
468                 text += "    {0},\n".format(value.definition())
469             text += "}} {0};\n".format(self.name)
470         elif self.bitwidth == 64:
471             text = "typedef VkFlags64 {0};\n\n".format(self.name)
472             for value in values:
473                 text += "static const {0} {1};\n".format(self.name, value.definition())
475         for aliasee in self.aliased_by:
476             text += "typedef {0} {1};\n".format(self.name, aliasee.name)
478         text += "\n"
479         return text
481     def is_alias(self):
482         return bool(self.alias)
484     def add_aliased_by(self, aliasee):
485         self.aliased_by.append(aliasee)
488 class VkEnumValue(object):
489     def __init__(self, name, bitwidth, value=None, hex=False, alias=None):
490         self.name = name
491         self.bitwidth = bitwidth
492         self.value = value
493         self.hex = hex
494         self.alias = alias
496     def __repr__(self):
497         postfix = "ull" if self.bitwidth == 64 else ""
498         if self.is_alias() and self.value == None:
499             return "{0}={1}".format(self.name, self.alias)
500         return "{0}={1}{2}".format(self.name, self.value, postfix)
502     def definition(self):
503         """ Convert to text definition e.g. VK_FOO = 1 """
504         postfix = "ull" if self.bitwidth == 64 else ""
505         if self.is_alias() and self.value == None:
506             return "{0} = {1}".format(self.name, self.alias)
508         # Hex is commonly used for FlagBits and sometimes within
509         # a non-FlagBits enum for a bitmask value as well.
510         if self.hex:
511             return "{0} = 0x{1:08x}{2}".format(self.name, self.value, postfix)
512         else:
513             return "{0} = {1}{2}".format(self.name, self.value, postfix)
515     def is_alias(self):
516         return self.alias is not None
519 class VkFunction(object):
520     def __init__(self, _type=None, name=None, params=[], alias=None):
521         self.extensions = set()
522         self.name = name
523         self.type = _type
524         self.params = params
525         self.alias = alias
527         # For some functions we need some extra metadata from FUNCTION_OVERRIDES.
528         func_info = FUNCTION_OVERRIDES.get(self.name, None)
529         self.dispatch = func_info["dispatch"] if func_info else True
530         self.driver = func_info["driver"] if func_info else False
531         self.thunk_type = func_info["thunk"] if func_info else ThunkType.PUBLIC
532         self.loader_thunk_type = func_info["loader_thunk"] if func_info and "loader_thunk" in func_info else ThunkType.PUBLIC
534         # Required is set while parsing which APIs and types are required
535         # and is used by the code generation.
536         self.required = True if func_info else False
538     @staticmethod
539     def from_alias(command, alias):
540         """ Create VkFunction from an alias command.
542         Args:
543             command: xml data for command
544             alias (VkFunction): function to use as a base for types / parameters.
546         Returns:
547             VkFunction
548         """
549         func_name = command.attrib.get("name")
550         func_type = alias.type
551         params = alias.params
553         return VkFunction(_type=func_type, name=func_name, params=params, alias=alias)
555     @staticmethod
556     def from_xml(command, types):
557         proto = command.find("proto")
558         func_name = proto.find("name").text
559         func_type = proto.find("type").text
561         params = []
562         for param in command.findall("param"):
563             vk_param = VkParam.from_xml(param, types)
564             params.append(vk_param)
566         return VkFunction(_type=func_type, name=func_name, params=params)
568     def get_conversions(self):
569         """ Get a list of conversion functions required for this function if any.
570         Parameters which are structures may require conversion between win32
571         and the host platform. This function returns a list of conversions
572         required.
573         """
575         conversions = []
576         for param in self.params:
577             convs = param.get_conversions()
578             if convs is not None:
579                 conversions.extend(convs)
581         return conversions
583     def is_alias(self):
584         return bool(self.alias)
586     def is_core_func(self):
587         """ Returns whether the function is a Vulkan core function.
588         Core functions are APIs defined by the Vulkan spec to be part of the
589         Core API as well as several KHR WSI extensions.
590         """
592         if not self.extensions:
593             return True
595         return any(ext in self.extensions for ext in CORE_EXTENSIONS)
597     def is_device_func(self):
598         # If none of the other, it must be a device function
599         return not self.is_global_func() and not self.is_instance_func() and not self.is_phys_dev_func()
601     def is_driver_func(self):
602         """ Returns if function is part of Wine driver interface. """
603         return self.driver
605     def is_global_func(self):
606         # Treat vkGetInstanceProcAddr as a global function as it
607         # can operate with NULL for vkInstance.
608         if self.name == "vkGetInstanceProcAddr":
609             return True
610         # Global functions are not passed a dispatchable object.
611         elif self.params[0].is_dispatchable():
612             return False
613         return True
615     def is_instance_func(self):
616         # Instance functions are passed VkInstance.
617         if self.params[0].type == "VkInstance":
618             return True
619         return False
621     def is_phys_dev_func(self):
622         # Physical device functions are passed VkPhysicalDevice.
623         if self.params[0].type == "VkPhysicalDevice":
624             return True
625         return False
627     def is_required(self):
628         return self.required
630     def needs_conversion(self):
631         """ Check if the function needs any input/output type conversion.
632         Functions need input/output conversion if struct parameters have
633         alignment differences between Win32 and Linux 32-bit.
634         """
636         for p in self.params:
637             if p.needs_conversion():
638                 LOGGER.debug("Parameter {0} to {1} requires conversion".format(p.name, self.name))
639                 return True
641         return False
643     def needs_unwrapping(self):
644         """ Check if the function needs any input/output type unwrapping.
645         Functions need input/output unwrapping if struct parameters have
646         wrapped handles.
647         """
649         for p in self.params:
650             if p.needs_unwrapping():
651                 return True
653         return False
655     def needs_dispatch(self):
656         return self.dispatch
658     def needs_thunk(self):
659         return self.thunk_type != ThunkType.NONE
661     def needs_private_thunk(self):
662         return self.thunk_type == ThunkType.PRIVATE
664     def needs_exposing(self):
665         # The function needs exposed if at-least one extension isn't both UNSUPPORTED and UNEXPOSED
666         return self.is_required() and (not self.extensions or not self.extensions.issubset(UNEXPOSED_EXTENSIONS))
668     def pfn(self, prefix="p", call_conv=None, conv=False):
669         """ Create function pointer. """
671         if call_conv:
672             pfn = "{0} ({1} *{2}_{3})(".format(self.type, call_conv, prefix, self.name)
673         else:
674             pfn = "{0} (*{1}_{2})(".format(self.type, prefix, self.name)
676         for i, param in enumerate(self.params):
677             if param.const:
678                 pfn += param.const + " "
680             pfn += param.type
681             if conv and param.needs_conversion():
682                 pfn += "_host"
684             if param.is_pointer():
685                 pfn += " " + param.pointer
687             if param.array_len is not None:
688                 pfn += "[{0}]".format(param.array_len)
690             if i < len(self.params) - 1:
691                 pfn += ", "
692         pfn += ")"
693         return pfn
695     def prototype(self, call_conv=None, prefix=None, postfix=None):
696         """ Generate prototype for given function.
698         Args:
699             call_conv (str, optional): calling convention e.g. WINAPI
700             prefix (str, optional): prefix to append prior to function name e.g. vkFoo -> wine_vkFoo
701             postfix (str, optional): text to append after function name but prior to semicolon e.g. DECLSPEC_HIDDEN
702         """
704         proto = "{0}".format(self.type)
706         if call_conv is not None:
707             proto += " {0}".format(call_conv)
709         if prefix is not None:
710             proto += " {0}{1}(".format(prefix, self.name)
711         else:
712             proto += " {0}(".format(self.name)
714         # Add all the parameters.
715         proto += ", ".join([p.definition() for p in self.params])
717         if postfix is not None:
718             proto += ") {0}".format(postfix)
719         else:
720             proto += ")"
722         return proto
724     def body(self):
725         body = ""
727         if not self.needs_private_thunk():
728             body += "    {0}".format(self.trace())
730         params = ", ".join([p.variable(conv=False) for p in self.params])
732         # Call the native Vulkan function.
733         if self.type == "void":
734             body += "    {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
735         else:
736             body += "    return {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
738         return body
740     def loader_body(self):
741         body = ""
743         params = ", ".join([p.name for p in self.params])
745         # Call the function from unix_funcs.
746         if self.type == "void":
747             body += "    unix_funcs->p_{0}({1});\n".format(self.name, params)
748         else:
749             body += "    return unix_funcs->p_{0}({1});\n".format(self.name, params)
751         return body
753     def body_conversion(self, conv):
754         body = ""
756         # Declare a variable to hold the result for non-void functions.
757         if self.type != "void":
758             body += "    {0} result;\n".format(self.type)
760         # Declare any tmp parameters for conversion.
761         for p in self.params:
762             if p.needs_conversion() and conv:
763                 if p.is_dynamic_array():
764                     body += "    {0}_host *{1}_host;\n".format(p.type, p.name)
765                 else:
766                     body += "    {0}_host {1}_host;\n".format(p.type, p.name)
767             elif p.needs_unwrapping():
768                 if p.is_dynamic_array():
769                     body += "    {0} *{1}_host;\n".format(p.type, p.name)
770                 else:
771                     body += "    {0} {1}_host;\n".format(p.type, p.name)
773         if not self.needs_private_thunk():
774             body += "    {0}\n".format(self.trace())
776         # Call any win_to_host conversion calls.
777         for p in self.params:
778             if p.needs_input_conversion() and (p.needs_unwrapping() or conv):
779                 body += p.copy(Direction.INPUT)
781         # Build list of parameters containing converted and non-converted parameters.
782         # The param itself knows if conversion is needed and applies it when we set conv=True.
783         params = ", ".join([p.variable(conv=conv) for p in self.params])
785         # Call the native Vulkan function.
786         if self.type == "void":
787             body += "    {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
788         else:
789             body += "    result = {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
791         body += "\n"
793         # Call any host_to_win conversion calls.
794         for p in self.params:
795             if not p.needs_output_conversion():
796                 continue
798             body += p.copy(Direction.OUTPUT)
800         # Perform any required cleanups. Most of these are for array functions.
801         for p in self.params:
802             if p.needs_free() and (p.needs_unwrapping() or conv):
803                 body += p.free()
805         # Finally return the result.
806         if self.type != "void":
807             body += "    return result;\n"
809         return body
811     def spec(self, prefix=None, symbol=None):
812         """ Generate spec file entry for this function.
814         Args
815             prefix (str, optional): prefix to prepend to entry point name.
816             symbol (str, optional): allows overriding the name of the function implementing the entry point.
817         """
819         spec = ""
820         params = " ".join([p.spec() for p in self.params])
821         if prefix is not None:
822             spec += "@ stdcall -private {0}{1}({2})".format(prefix, self.name, params)
823         else:
824             spec += "@ stdcall {0}({1})".format(self.name, params)
826         if symbol is not None:
827             spec += " " + symbol
829         spec += "\n"
830         return spec
832     def stub(self, call_conv=None, prefix=None):
833         stub = self.prototype(call_conv=call_conv, prefix=prefix)
834         stub += "\n{\n"
835         stub += "    {0}".format(self.trace(message="stub: ", trace_func="FIXME"))
837         if self.type == "VkResult":
838             stub += "    return VK_ERROR_OUT_OF_HOST_MEMORY;\n"
839         elif self.type == "VkBool32":
840             stub += "    return VK_FALSE;\n"
841         elif self.type == "PFN_vkVoidFunction":
842             stub += "    return NULL;\n"
844         stub += "}\n\n"
845         return stub
847     def thunk(self, call_conv=None, prefix=None):
848         thunk = self.prototype(call_conv=call_conv, prefix=prefix)
849         thunk += "\n{\n"
851         if self.needs_conversion():
852             thunk += "#if defined(USE_STRUCT_CONVERSION)\n"
853             thunk += self.body_conversion(conv=True)
854             thunk += "#else\n"
855             if self.needs_unwrapping():
856                 thunk += self.body_conversion(conv=False)
857             else:
858                 thunk += self.body()
859             thunk += "#endif\n"
860         elif self.needs_unwrapping():
861             thunk += self.body_conversion(conv=False)
862         else:
863             thunk += self.body()
865         thunk += "}\n\n"
866         return thunk
868     def loader_thunk(self, prefix=None):
869         thunk = self.prototype(call_conv="WINAPI", prefix=prefix)
870         thunk += "\n{\n"
871         thunk += self.loader_body()
872         thunk += "}\n\n"
873         return thunk
875     def trace(self, message=None, trace_func=None):
876         """ Create a trace string including all parameters.
878         Args:
879             message (str, optional): text to print at start of trace message e.g. 'stub: '
880             trace_func (str, optional): used to override trace function e.g. FIXME, printf, etcetera.
881         """
882         if trace_func is not None:
883             trace = "{0}(\"".format(trace_func)
884         else:
885             trace = "TRACE(\""
887         if message is not None:
888             trace += message
890         # First loop is for all the format strings.
891         trace += ", ".join([p.format_string() for p in self.params])
892         trace += "\\n\""
894         # Second loop for parameter names and optional conversions.
895         for param in self.params:
896             if param.format_conv is not None:
897                 trace += ", " + param.format_conv.format(param.name)
898             else:
899                 trace += ", {0}".format(param.name)
900         trace += ");\n"
902         return trace
905 class VkFunctionPointer(object):
906     def __init__(self, _type, name, members, forward_decls):
907         self.name = name
908         self.members = members
909         self.type = _type
910         self.required = False
911         self.forward_decls = forward_decls
913     @staticmethod
914     def from_xml(funcpointer):
915         members = []
916         begin = None
918         for t in funcpointer.findall("type"):
919             # General form:
920             # <type>void</type>*       pUserData,
921             # Parsing of the tail (anything past </type>) is tricky since there
922             # can be other data on the next line like: const <type>int</type>..
924             const = True if begin and "const" in begin else False
925             _type = t.text
926             lines = t.tail.split(",\n")
927             if lines[0][0] == "*":
928                 pointer = "*"
929                 name = lines[0][1:].strip()
930             else:
931                 pointer = None
932                 name = lines[0].strip()
934             # Filter out ); if it is contained.
935             name = name.partition(");")[0]
937             # If tail encompasses multiple lines, assign the second line to begin
938             # for the next line.
939             try:
940                 begin = lines[1].strip()
941             except IndexError:
942                 begin = None
944             members.append(VkMember(const=const, _type=_type, pointer=pointer, name=name))
946         _type = funcpointer.text
947         name = funcpointer.find("name").text
948         if "requires" in funcpointer.attrib:
949             forward_decls = funcpointer.attrib.get("requires").split(",")
950         else:
951             forward_decls = []
952         return VkFunctionPointer(_type, name, members, forward_decls)
954     def definition(self):
955         text = ""
956         # forward declare required structs
957         for decl in self.forward_decls:
958             text += "typedef struct {0} {0};\n".format(decl)
960         text += "{0} {1})(\n".format(self.type, self.name)
962         first = True
963         if len(self.members) > 0:
964             for m in self.members:
965                 if first:
966                     text += "    " + m.definition()
967                     first = False
968                 else:
969                     text += ",\n    " + m.definition()
970         else:
971             # Just make the compiler happy by adding a void parameter.
972             text += "void"
973         text += ");\n"
974         return text
976     def is_alias(self):
977         return False
979 class VkHandle(object):
980     def __init__(self, name, _type, parent, alias=None):
981         self.name = name
982         self.type = _type
983         self.parent = parent
984         self.alias = alias
985         self.required = False
986         self.object_type = None
988     @staticmethod
989     def from_alias(handle, alias):
990         name = handle.attrib.get("name")
991         return VkHandle(name, alias.type, alias.parent, alias=alias)
993     @staticmethod
994     def from_xml(handle):
995         name = handle.find("name").text
996         _type = handle.find("type").text
997         parent = handle.attrib.get("parent") # Most objects have a parent e.g. VkQueue has VkDevice.
998         return VkHandle(name, _type, parent)
1000     def dispatch_table(self):
1001         if not self.is_dispatchable():
1002             return None
1004         if self.parent is None:
1005             # Should only happen for VkInstance
1006             return "funcs"
1007         elif self.name == "VkDevice":
1008             # VkDevice has VkInstance as a parent, but has its own dispatch table.
1009             return "funcs"
1010         elif self.parent in ["VkInstance", "VkPhysicalDevice"]:
1011             return "instance->funcs"
1012         elif self.parent in ["VkDevice", "VkCommandPool"]:
1013             return "device->funcs"
1014         else:
1015             LOGGER.error("Unhandled dispatchable parent: {0}".format(self.parent))
1017     def definition(self):
1018         """ Generates handle definition e.g. VK_DEFINE_HANDLE(vkInstance) """
1020         # Legacy types are typedef'ed to the new type if they are aliases.
1021         if self.is_alias():
1022             return "typedef {0} {1};\n".format(self.alias.name, self.name)
1024         return "{0}({1})\n".format(self.type, self.name)
1026     def is_alias(self):
1027         return self.alias is not None
1029     def is_dispatchable(self):
1030         """ Some handles like VkInstance, VkDevice are dispatchable objects,
1031         which means they contain a dispatch table of function pointers.
1032         """
1033         return self.type == "VK_DEFINE_HANDLE"
1035     def is_required(self):
1036         return self.required
1038     def native_handle(self, name):
1039         """ Provide access to the native handle of a wrapped object. """
1041         if self.name == "VkCommandPool":
1042             return "wine_cmd_pool_from_handle({0})->command_pool".format(name)
1043         if self.name == "VkDebugUtilsMessengerEXT":
1044             return "wine_debug_utils_messenger_from_handle({0})->debug_messenger".format(name)
1045         if self.name == "VkDebugReportCallbackEXT":
1046             return "wine_debug_report_callback_from_handle({0})->debug_callback".format(name)
1047         if self.name == "VkSurfaceKHR":
1048             return "wine_surface_from_handle({0})->surface".format(name)
1050         native_handle_name = None
1052         if self.name == "VkCommandBuffer":
1053             native_handle_name = "command_buffer"
1054         if self.name == "VkDevice":
1055             native_handle_name = "device"
1056         if self.name == "VkInstance":
1057             native_handle_name = "instance"
1058         if self.name == "VkPhysicalDevice":
1059             native_handle_name = "phys_dev"
1060         if self.name == "VkQueue":
1061             native_handle_name = "queue"
1063         if native_handle_name:
1064             return "{0}->{1}".format(name, native_handle_name)
1066         if self.is_dispatchable():
1067             LOGGER.error("Unhandled native handle for: {0}".format(self.name))
1068         return None
1070     def driver_handle(self, name):
1071         """ Provide access to the handle that should be passed to the wine driver """
1073         if self.name == "VkSurfaceKHR":
1074             return "wine_surface_from_handle({0})->driver_surface".format(name)
1076         return self.native_handle(name)
1078     def is_wrapped(self):
1079         return self.native_handle("test") is not None
1081     def needs_conversion(self):
1082         return False
1084     def needs_unwrapping(self):
1085         return self.is_wrapped()
1087 class VkMember(object):
1088     def __init__(self, const=False, struct_fwd_decl=False,_type=None, pointer=None, name=None, array_len=None,
1089             dyn_array_len=None, optional=False, values=None, object_type=None, bit_width=None):
1090         self.const = const
1091         self.struct_fwd_decl = struct_fwd_decl
1092         self.name = name
1093         self.pointer = pointer
1094         self.type = _type
1095         self.type_info = None
1096         self.array_len = array_len
1097         self.dyn_array_len = dyn_array_len
1098         self.optional = optional
1099         self.values = values
1100         self.object_type = object_type
1101         self.bit_width = bit_width
1103     def __eq__(self, other):
1104         """ Compare member based on name against a string.
1106         This method is for convenience by VkStruct, which holds a number of members and needs quick checking
1107         if certain members exist.
1108         """
1110         return self.name == other
1112     def __repr__(self):
1113         return "{0} {1} {2} {3} {4} {5} {6}".format(self.const, self.struct_fwd_decl, self.type, self.pointer,
1114                 self.name, self.array_len, self.dyn_array_len)
1116     @staticmethod
1117     def from_xml(member):
1118         """ Helper function for parsing a member tag within a struct or union. """
1120         name_elem = member.find("name")
1121         type_elem = member.find("type")
1123         const = False
1124         struct_fwd_decl = False
1125         member_type = None
1126         pointer = None
1127         array_len = None
1128         bit_width = None
1130         values = member.get("values")
1132         if member.text:
1133             if "const" in member.text:
1134                 const = True
1136             # Some members contain forward declarations:
1137             # - VkBaseInstructure has a member "const struct VkBaseInStructure *pNext"
1138             # - VkWaylandSurfaceCreateInfoKHR has a member "struct wl_display *display"
1139             if "struct" in member.text:
1140                 struct_fwd_decl = True
1142         if type_elem is not None:
1143             member_type = type_elem.text
1144             if type_elem.tail is not None:
1145                 pointer = type_elem.tail.strip() if type_elem.tail.strip() != "" else None
1147         # Name of other member within, which stores the number of
1148         # elements pointed to be by this member.
1149         dyn_array_len = member.get("len")
1151         # Some members are optional, which is important for conversion code e.g. not dereference NULL pointer.
1152         optional = True if member.get("optional") else False
1154         # Usually we need to allocate memory for dynamic arrays. We need to do the same in a few other cases
1155         # like for VkCommandBufferBeginInfo.pInheritanceInfo. Just threat such cases as dynamic arrays of
1156         # size 1 to simplify code generation.
1157         if dyn_array_len is None and pointer is not None:
1158             dyn_array_len = 1
1160         # Some members are arrays, attempt to parse these. Formats include:
1161         # <member><type>char</type><name>extensionName</name>[<enum>VK_MAX_EXTENSION_NAME_SIZE</enum>]</member>
1162         # <member><type>uint32_t</type><name>foo</name>[4]</member>
1163         if name_elem.tail and name_elem.tail[0] == '[':
1164             LOGGER.debug("Found array type")
1165             enum_elem = member.find("enum")
1166             if enum_elem is not None:
1167                 array_len = enum_elem.text
1168             else:
1169                 # Remove brackets around length
1170                 array_len = name_elem.tail.strip("[]")
1172         object_type = member.get("objecttype", None)
1174         # Some members are bit field values:
1175         # <member><type>uint32_t</type> <name>mask</name>:8</member>
1176         if name_elem.tail and name_elem.tail[0] == ':':
1177             LOGGER.debug("Found bit field")
1178             bit_width = int(name_elem.tail[1:])
1180         return VkMember(const=const, struct_fwd_decl=struct_fwd_decl, _type=member_type, pointer=pointer, name=name_elem.text,
1181                 array_len=array_len, dyn_array_len=dyn_array_len, optional=optional, values=values, object_type=object_type, bit_width=bit_width)
1183     def copy(self, input, output, direction, conv):
1184         """ Helper method for use by conversion logic to generate a C-code statement to copy this member.
1185             - `conv` indicates whether the statement is in a struct alignment conversion path. """
1187         if (conv and self.needs_conversion()) or self.needs_unwrapping():
1188             if self.is_dynamic_array():
1189                 if direction == Direction.OUTPUT:
1190                     LOGGER.warn("TODO: implement copying of returnedonly dynamic array for {0}.{1}".format(self.type, self.name))
1191                 else:
1192                     # Array length is either a variable name (string) or an int.
1193                     count = self.dyn_array_len if isinstance(self.dyn_array_len, int) else "{0}{1}".format(input, self.dyn_array_len)
1194                     return "{0}{1} = convert_{2}_array_win_to_host({3}{1}, {4});\n".format(output, self.name, self.type, input, count)
1195             elif self.is_static_array():
1196                 count = self.array_len
1197                 if direction == Direction.OUTPUT:
1198                     # Needed by VkMemoryHeap.memoryHeaps
1199                     return "convert_{0}_static_array_host_to_win({2}{1}, {3}{1}, {4});\n".format(self.type, self.name, input, output, count)
1200                 else:
1201                     # Nothing needed this yet.
1202                     LOGGER.warn("TODO: implement copying of static array for {0}.{1}".format(self.type, self.name))
1203             elif self.is_handle() and self.needs_unwrapping():
1204                 if direction == Direction.OUTPUT:
1205                     LOGGER.err("OUTPUT parameter {0}.{1} cannot be unwrapped".format(self.type, self.name))
1206                 else:
1207                     handle = self.type_info["data"]
1208                     return "{0}{1} = {2};\n".format(output, self.name, handle.driver_handle("{0}{1}".format(input, self.name)))
1209             elif self.is_generic_handle():
1210                 if direction == Direction.OUTPUT:
1211                     LOGGER.err("OUTPUT parameter {0}.{1} cannot be unwrapped".format(self.type, self.name))
1212                 else:
1213                     return "{0}{1} = wine_vk_unwrap_handle({2}{3}, {2}{1});\n".format(output, self.name, input, self.object_type)
1214             else:
1215                 if direction == Direction.OUTPUT:
1216                     return "convert_{0}_host_to_win(&{2}{1}, &{3}{1});\n".format(self.type, self.name, input, output)
1217                 else:
1218                     return "convert_{0}_win_to_host(&{2}{1}, &{3}{1});\n".format(self.type, self.name, input, output)
1219         elif self.is_static_array():
1220             bytes_count = "{0} * sizeof({1})".format(self.array_len, self.type)
1221             return "memcpy({0}{1}, {2}{1}, {3});\n".format(output, self.name, input, bytes_count)
1222         else:
1223             return "{0}{1} = {2}{1};\n".format(output, self.name, input)
1225     def free(self, location, conv):
1226         """ Helper method for use by conversion logic to generate a C-code statement to free this member. """
1228         if not self.needs_unwrapping() and not conv:
1229             return ""
1231         # Add a cast to ignore const on conversion structs we allocated ourselves.
1232         # sample expected output: (VkSparseMemoryBind_host *)
1233         if self.is_const():
1234             cast = "(" + self.type
1235             if self.needs_conversion() and conv:
1236                 cast += "_host"
1237             cast += " *)"
1238         else:
1239             cast = ""
1241         if self.is_dynamic_array():
1242             count = self.dyn_array_len if isinstance(self.dyn_array_len, int) else "{0}{1}".format(location, self.dyn_array_len)
1243             if self.is_struct() and self.type_info["data"].returnedonly:
1244                 # For returnedonly, counts is stored in a pointer.
1245                 return "free_{0}_array({1}{2}{3}, *{4});\n".format(self.type, cast, location, self.name, count)
1246             else:
1247                 return "free_{0}_array({1}{2}{3}, {4});\n".format(self.type, cast, location, self.name, count)
1248         else:
1249             # We are operating on a single structure. Some structs (very rare) contain dynamic members,
1250             # which would need freeing.
1251             if self.needs_free():
1252                 return "free_{0}({1}&{2}{3});\n".format(self.type, cast, location, self.name)
1253         return ""
1255     def definition(self, align=False, conv=False):
1256         """ Generate prototype for given function.
1258         Args:
1259             align (bool, optional): Enable alignment if a type needs it. This adds WINE_VK_ALIGN(8) to a member.
1260             conv (bool, optional): Enable conversion if a type needs it. This appends '_host' to the name.
1261         """
1263         text = ""
1264         if self.is_const():
1265             text += "const "
1267         if self.is_struct_forward_declaration():
1268             text += "struct "
1270         if conv and self.is_struct():
1271             text += "{0}_host".format(self.type)
1272         else:
1273             text += self.type
1275         if self.is_pointer():
1276             text += " {0}{1}".format(self.pointer, self.name)
1277         else:
1278             if align and self.needs_alignment():
1279                 text += " WINE_VK_ALIGN(8) " + self.name
1280             else:
1281                 text += " " + self.name
1283         if self.is_static_array():
1284             text += "[{0}]".format(self.array_len)
1286         if self.is_bit_field():
1287             text += ":{}".format(self.bit_width)
1289         return text
1291     def get_conversions(self):
1292         """ Return any conversion description for this member and its children when conversion is needed. """
1294         # Check if we need conversion either for this member itself or for any child members
1295         # in case member represents a struct.
1296         if not self.needs_conversion() and not self.needs_unwrapping():
1297             return None
1299         conversions = []
1301         # Collect any conversion for any member structs.
1302         if self.is_struct():
1303             struct = self.type_info["data"]
1304             for m in struct:
1305                 m.needs_struct_extensions_conversion()
1306                 if m.needs_conversion() or m.needs_unwrapping():
1307                     conversions.extend(m.get_conversions())
1309             struct.needs_struct_extensions_conversion()
1310             direction = Direction.OUTPUT if struct.returnedonly else Direction.INPUT
1311         elif self.is_handle() or self.is_generic_handle():
1312             direction = Direction.INPUT
1314         operand = self.type_info["data"]
1315         if self.is_dynamic_array():
1316             conversions.append(ConversionFunction(False, True, direction, operand))
1317         elif self.is_static_array():
1318             conversions.append(ConversionFunction(True, False, direction, operand))
1319         else:
1320             conversions.append(ConversionFunction(False, False, direction, operand))
1322         if self.needs_free():
1323             conversions.append(FreeFunction(self.is_dynamic_array(), operand))
1325         return conversions
1327     def is_const(self):
1328         return self.const
1330     def is_dynamic_array(self):
1331         """ Returns if the member is an array element.
1332         Vulkan uses this for dynamically sized arrays for which
1333         there is a 'count' parameter.
1334         """
1335         return self.dyn_array_len is not None
1337     def is_handle(self):
1338         return self.type_info["category"] == "handle"
1340     def is_pointer(self):
1341         return self.pointer is not None
1343     def is_static_array(self):
1344         """ Returns if the member is an array.
1345         Vulkan uses this often for fixed size arrays in which the
1346         length is part of the member.
1347         """
1348         return self.array_len is not None
1350     def is_struct(self):
1351         return self.type_info["category"] == "struct"
1353     def is_struct_forward_declaration(self):
1354         return self.struct_fwd_decl
1356     def is_union(self):
1357         return self.type_info["category"] == "union"
1359     def is_generic_handle(self):
1360         """ Returns True if the member is a unit64_t containing
1361         a handle with a separate object type
1362         """
1364         return self.object_type != None and self.type == "uint64_t"
1366     def is_bit_field(self):
1367         return self.bit_width is not None
1369     def needs_alignment(self):
1370         """ Check if this member needs alignment for 64-bit data.
1371         Various structures need alignment on 64-bit variables due
1372         to compiler differences on 32-bit between Win32 and Linux.
1373         """
1375         if self.is_pointer():
1376             return False
1377         elif self.type == "size_t":
1378             return False
1379         elif self.type in ["uint64_t", "VkDeviceSize"]:
1380             return True
1381         elif self.is_struct():
1382             struct = self.type_info["data"]
1383             return struct.needs_alignment()
1384         elif self.is_handle():
1385             # Dispatchable handles are pointers to objects, while
1386             # non-dispatchable are uint64_t and hence need alignment.
1387             handle = self.type_info["data"]
1388             return False if handle.is_dispatchable() else True
1389         return False
1391     def needs_conversion(self):
1392         """ Structures requiring alignment, need conversion between win32 and host. """
1394         if not self.is_struct():
1395             return False
1397         struct = self.type_info["data"]
1398         return struct.needs_conversion()
1400     def needs_unwrapping(self):
1401         """ Structures with wrapped handles need unwrapping. """
1403         if self.is_struct():
1404             struct = self.type_info["data"]
1405             return struct.needs_unwrapping()
1407         if self.is_handle():
1408             handle = self.type_info["data"]
1409             return handle.is_wrapped()
1411         if self.is_generic_handle():
1412             return True
1414         return False
1416     def needs_free(self):
1417         if not self.needs_conversion() and not self.needs_unwrapping():
1418             return False
1420         if self.is_dynamic_array():
1421             return True
1423         # TODO: some non-pointer structs and optional pointer structs may need freeing,
1424         # though none of this type have been encountered yet.
1425         return False
1427     def needs_struct_extensions_conversion(self):
1428         if not self.is_struct():
1429             return False
1431         struct = self.type_info["data"]
1432         return struct.needs_struct_extensions_conversion()
1434     def set_type_info(self, type_info):
1435         """ Helper function to set type information from the type registry.
1436         This is needed, because not all type data is available at time of
1437         parsing.
1438         """
1439         self.type_info = type_info
1442 class VkParam(object):
1443     """ Helper class which describes a parameter to a function call. """
1445     def __init__(self, type_info, const=None, pointer=None, name=None, array_len=None, dyn_array_len=None, object_type=None):
1446         self.const = const
1447         self.name = name
1448         self.array_len = array_len
1449         self.dyn_array_len = dyn_array_len
1450         self.pointer = pointer
1451         self.object_type = object_type
1452         self.type_info = type_info
1453         self.type = type_info["name"] # For convenience
1454         self.handle = type_info["data"] if type_info["category"] == "handle" else None
1455         self.struct = type_info["data"] if type_info["category"] == "struct" else None
1457         self._set_direction()
1458         self._set_format_string()
1459         self._set_conversions()
1461     def __repr__(self):
1462         return "{0} {1} {2} {3} {4} {5}".format(self.const, self.type, self.pointer, self.name, self.array_len, self.dyn_array_len)
1464     @staticmethod
1465     def from_xml(param, types):
1466         """ Helper function to create VkParam from xml. """
1468         # Parameter parsing is slightly tricky. All the data is contained within
1469         # a param tag, but some data is within subtags while others are text
1470         # before or after the type tag.
1471         # Common structure:
1472         # <param>const <type>char</type>* <name>pLayerName</name></param>
1474         name_elem = param.find("name")
1475         array_len = None
1476         name = name_elem.text
1477         # Tail contains array length e.g. for blendConstants param of vkSetBlendConstants
1478         if name_elem.tail is not None:
1479             array_len = name_elem.tail.strip("[]")
1481         # Name of other parameter in function prototype, which stores the number of
1482         # elements pointed to be by this parameter.
1483         dyn_array_len = param.get("len", None)
1485         const = param.text.strip() if param.text else None
1486         type_elem = param.find("type")
1487         pointer = type_elem.tail.strip() if type_elem.tail.strip() != "" else None
1489         # Some uint64_t are actually handles with a separate type param
1490         object_type = param.get("objecttype", None)
1492         # Since we have parsed all types before hand, this should not happen.
1493         type_info = types.get(type_elem.text, None)
1494         if type_info is None:
1495             LOGGER.err("type info not found for: {0}".format(type_elem.text))
1497         return VkParam(type_info, const=const, pointer=pointer, name=name, array_len=array_len, dyn_array_len=dyn_array_len, object_type=object_type)
1499     def _set_conversions(self):
1500         """ Internal helper function to configure any needed conversion functions. """
1502         self.free_func = None
1503         self.input_conv = None
1504         self.output_conv = None
1505         if not self.needs_conversion() and not self.needs_unwrapping():
1506             return
1508         operand = self.struct if self.is_struct() else self.handle
1510         # Input functions require win to host conversion.
1511         if self._direction in [Direction.INPUT, Direction.INPUT_OUTPUT]:
1512             self.input_conv = ConversionFunction(False, self.is_dynamic_array(), Direction.INPUT, operand)
1514         # Output functions require host to win conversion.
1515         if self._direction in [Direction.INPUT_OUTPUT, Direction.OUTPUT]:
1516             self.output_conv = ConversionFunction(False, self.is_dynamic_array(), Direction.OUTPUT, operand)
1518         # Dynamic arrays, but also some normal structs (e.g. VkCommandBufferBeginInfo) need memory
1519         # allocation and thus some cleanup.
1520         if self.is_dynamic_array() or self.struct.needs_free():
1521             self.free_func = FreeFunction(self.is_dynamic_array(), operand)
1523     def _set_direction(self):
1524         """ Internal helper function to set parameter direction (input/output/input_output). """
1526         # The parameter direction needs to be determined from hints in vk.xml like returnedonly,
1527         # parameter constness and other heuristics.
1528         # For now we need to get this right for structures as we need to convert these, we may have
1529         # missed a few other edge cases (e.g. count variables).
1530         # See also https://github.com/KhronosGroup/Vulkan-Docs/issues/610
1532         if not self.is_pointer():
1533             self._direction = Direction.INPUT
1534         elif self.is_const() and self.is_pointer():
1535             self._direction = Direction.INPUT
1536         elif self.is_struct():
1537             if not self.struct.returnedonly:
1538                 self._direction = Direction.INPUT
1539                 return
1541             # Returnedonly hints towards output, however in some cases
1542             # it is inputoutput. In particular if pNext / sType exist,
1543             # which are used to link in other structures without having
1544             # to introduce new APIs. E.g. vkGetPhysicalDeviceProperties2KHR.
1545             if "pNext" in self.struct:
1546                 self._direction = Direction.INPUT_OUTPUT
1547                 return
1549             self._direction = Direction.OUTPUT
1550         else:
1551             # This should mostly be right. Count variables can be inout, but we don't care about these yet.
1552             self._direction = Direction.OUTPUT
1554     def _set_format_string(self):
1555         """ Internal helper function to be used by constructor to set format string. """
1557         # Determine a format string used by code generation for traces.
1558         # 64-bit types need a conversion function.
1559         self.format_conv = None
1560         if self.is_static_array() or self.is_pointer():
1561             self.format_str = "%p"
1562         else:
1563             if self.type_info["category"] in ["bitmask"]:
1564                 # Since 1.2.170 bitmasks can be 32 or 64-bit, check the basetype.
1565                 if self.type_info["data"].type == "VkFlags64":
1566                     self.format_str = "0x%s"
1567                     self.format_conv = "wine_dbgstr_longlong({0})"
1568                 else:
1569                     self.format_str = "%#x"
1570             elif self.type_info["category"] in ["enum"]:
1571                 self.format_str = "%#x"
1572             elif self.is_handle():
1573                 # We use uint64_t for non-dispatchable handles as opposed to pointers
1574                 # for dispatchable handles.
1575                 if self.handle.is_dispatchable():
1576                     self.format_str = "%p"
1577                 else:
1578                     self.format_str = "0x%s"
1579                     self.format_conv = "wine_dbgstr_longlong({0})"
1580             elif self.type == "float":
1581                 self.format_str = "%f"
1582             elif self.type == "int":
1583                 self.format_str = "%d"
1584             elif self.type == "int32_t":
1585                 self.format_str = "%d"
1586             elif self.type == "size_t":
1587                 self.format_str = "0x%s"
1588                 self.format_conv = "wine_dbgstr_longlong({0})"
1589             elif self.type in ["uint16_t", "uint32_t", "VkBool32"]:
1590                 self.format_str = "%u"
1591             elif self.type in ["uint64_t", "VkDeviceAddress", "VkDeviceSize"]:
1592                 self.format_str = "0x%s"
1593                 self.format_conv = "wine_dbgstr_longlong({0})"
1594             elif self.type == "HANDLE":
1595                 self.format_str = "%p"
1596             elif self.type in ["VisualID", "xcb_visualid_t", "RROutput", "zx_handle_t"]:
1597                 # Don't care about specific types for non-Windows platforms.
1598                 self.format_str = ""
1599             else:
1600                 LOGGER.warn("Unhandled type: {0}".format(self.type_info))
1602     def copy(self, direction):
1603         if direction == Direction.INPUT:
1604             if self.is_dynamic_array():
1605                 return "    {0}_host = convert_{1}_array_win_to_host({0}, {2});\n".format(self.name, self.type, self.dyn_array_len)
1606             else:
1607                 return "    convert_{0}_win_to_host({1}, &{1}_host);\n".format(self.type, self.name)
1608         else:
1609             if self.is_dynamic_array():
1610                 LOGGER.error("Unimplemented output conversion for: {0}".format(self.name))
1611             else:
1612                 return "    convert_{0}_host_to_win(&{1}_host, {1});\n".format(self.type, self.name)
1614     def definition(self, postfix=None):
1615         """ Return prototype for the parameter. E.g. 'const char *foo' """
1617         proto = ""
1618         if self.const:
1619             proto += self.const + " "
1621         proto += self.type
1623         if self.is_pointer():
1624             proto += " {0}{1}".format(self.pointer, self.name)
1625         else:
1626             proto += " " + self.name
1628         # Allows appending something to the variable name useful for
1629         # win32 to host conversion.
1630         if postfix is not None:
1631             proto += postfix
1633         if self.is_static_array():
1634             proto += "[{0}]".format(self.array_len)
1636         return proto
1638     def direction(self):
1639         """ Returns parameter direction: input, output, input_output.
1641         Parameter direction in Vulkan is not straight-forward, which this function determines.
1642         """
1644         return self._direction
1646     def dispatch_table(self):
1647         """ Return functions dispatch table pointer for dispatchable objects. """
1649         if not self.is_dispatchable():
1650             return None
1652         return "{0}->{1}".format(self.name, self.handle.dispatch_table())
1654     def format_string(self):
1655         return self.format_str
1657     def free(self):
1658         if self.is_dynamic_array():
1659             if self.is_struct() and self.struct.returnedonly:
1660                 # For returnedonly, counts is stored in a pointer.
1661                 return "    free_{0}_array({1}_host, *{2});\n".format(self.type, self.name, self.dyn_array_len)
1662             else:
1663                 return "    free_{0}_array({1}_host, {2});\n".format(self.type, self.name, self.dyn_array_len)
1664         else:
1665             # We are operating on a single structure. Some structs (very rare) contain dynamic members,
1666             # which would need freeing.
1667             if self.is_struct() and self.struct.needs_free():
1668                 return "    free_{0}(&{1}_host);\n".format(self.type, self.name)
1669         return ""
1671     def get_conversions(self):
1672         """ Get a list of conversions required for this parameter if any.
1673         Parameters which are structures may require conversion between win32
1674         and the host platform. This function returns a list of conversions
1675         required.
1676         """
1678         if self.is_struct():
1679             self.struct.needs_struct_extensions_conversion()
1680             for m in self.struct:
1681                 m.needs_struct_extensions_conversion()
1682         elif not self.is_handle():
1683             return None
1685         if not self.needs_conversion() and not self.needs_unwrapping():
1686             return None
1688         conversions = []
1690         # Collect any member conversions first, so we can guarantee
1691         # those functions will be defined prior to usage by the
1692         # 'parent' param requiring conversion.
1693         if self.is_struct():
1694             for m in self.struct:
1695                 if not m.is_struct():
1696                     continue
1698                 if not m.needs_conversion() and not m.needs_unwrapping():
1699                     continue
1701                 conversions.extend(m.get_conversions())
1703         # Conversion requirements for the 'parent' parameter.
1704         if self.input_conv is not None:
1705             conversions.append(self.input_conv)
1706         if self.output_conv is not None:
1707             conversions.append(self.output_conv)
1708         if self.free_func is not None:
1709             conversions.append(self.free_func)
1711         return conversions
1713     def is_const(self):
1714         return self.const is not None
1716     def is_dynamic_array(self):
1717         return self.dyn_array_len is not None
1719     def is_dispatchable(self):
1720         if not self.is_handle():
1721             return False
1723         return self.handle.is_dispatchable()
1725     def is_handle(self):
1726         return self.handle is not None
1728     def is_pointer(self):
1729         return self.pointer is not None
1731     def is_static_array(self):
1732         return self.array_len is not None
1734     def is_struct(self):
1735         return self.struct is not None
1737     def needs_conversion(self):
1738         """ Returns if parameter needs conversion between win32 and host. """
1740         if not self.is_struct():
1741             return False
1743         # VkSparseImageMemoryRequirements(2) is used by vkGetImageSparseMemoryRequirements(2).
1744         # This function is tricky to wrap, because how to wrap depends on whether
1745         # pSparseMemoryRequirements is NULL or not. Luckily for VkSparseImageMemoryRequirements(2)
1746         # the alignment works out in such a way that no conversion is needed between win32 and Linux.
1747         if self.type in ["VkSparseImageMemoryRequirements", "VkSparseImageMemoryRequirements2"]:
1748             return False
1750         # If a structure needs alignment changes, it means we need to
1751         # perform parameter conversion between win32 and host.
1752         if self.struct.needs_conversion():
1753             return True
1755         return False
1757     def needs_unwrapping(self):
1758         """ Returns if parameter needs unwrapping of handle. """
1760         # Wrapped handle parameters are handled separately, only look for wrapped handles in structs
1761         if self.is_struct():
1762             return self.struct.needs_unwrapping()
1764         if self.is_handle() and self.is_dynamic_array():
1765             return self.handle.needs_unwrapping()
1767         return False
1769     def needs_free(self):
1770         return self.free_func is not None
1772     def needs_input_conversion(self):
1773         return self.input_conv is not None
1775     def needs_output_conversion(self):
1776         return self.output_conv is not None
1778     def spec(self):
1779         """ Generate spec file entry for this parameter. """
1781         if self.is_pointer() and self.type == "char":
1782             return "str"
1783         if self.is_dispatchable() or self.is_pointer() or self.is_static_array():
1784             return "ptr"
1785         if self.type_info["category"] in ["bitmask"]:
1786             # Since 1.2.170 bitmasks can be 32 or 64-bit, check the basetype.
1787             if self.type_info["data"].type == "VkFlags64":
1788                 return "int64"
1789             else:
1790                 return "long"
1791         if self.type_info["category"] in ["enum"]:
1792             return "long"
1793         if self.is_handle() and not self.is_dispatchable():
1794             return "int64"
1795         if self.type == "float":
1796             return "float"
1797         if self.type in ["int", "int32_t", "size_t", "uint16_t", "uint32_t", "VkBool32"]:
1798             return "long"
1799         if self.type in ["uint64_t", "VkDeviceSize"]:
1800             return "int64"
1802         LOGGER.error("Unhandled spec conversion for type: {0}".format(self.type))
1804     def variable(self, conv=False):
1805         """ Returns 'glue' code during generation of a function call on how to access the variable.
1806         This function handles various scenarios such as 'unwrapping' if dispatchable objects and
1807         renaming of parameters in case of win32 -> host conversion.
1809         Args:
1810             conv (bool, optional): Enable conversion if the param needs it. This appends '_host' to the name.
1811         """
1813         # Hack until we enable allocation callbacks from ICD to application. These are a joy
1814         # to enable one day, because of calling convention conversion.
1815         if "VkAllocationCallbacks" in self.type:
1816             LOGGER.debug("TODO: setting NULL VkAllocationCallbacks for {0}".format(self.name))
1817             return "NULL"
1819         if self.needs_unwrapping() or (conv and self.needs_conversion()):
1820             if self.is_dynamic_array():
1821                 return "{0}_host".format(self.name)
1822             else:
1823                 return "&{0}_host".format(self.name)
1824         else:
1825             if self.object_type != None and self.type == "uint64_t":
1826                 return "wine_vk_unwrap_handle({0}, {1})".format(self.object_type, self.name)
1828             # We need to pass the native handle to the native Vulkan calls and
1829             # the wine driver's handle to calls which are wrapped by the driver.
1830             driver_handle = self.handle.driver_handle(self.name) if self.is_handle() else None
1831             return driver_handle if driver_handle else self.name
1834 class VkStruct(Sequence):
1835     """ Class which represents the type union and struct. """
1837     def __init__(self, name, members, returnedonly, structextends, alias=None, union=False):
1838         self.name = name
1839         self.members = members
1840         self.returnedonly = returnedonly
1841         self.structextends = structextends
1842         self.required = False
1843         self.alias = alias
1844         self.union = union
1845         self.type_info = None # To be set later.
1846         self.struct_extensions = []
1847         self.aliased_by = []
1849     def __getitem__(self, i):
1850         return self.members[i]
1852     def __len__(self):
1853         return len(self.members)
1855     @staticmethod
1856     def from_alias(struct, alias):
1857         name = struct.attrib.get("name")
1858         aliasee = VkStruct(name, alias.members, alias.returnedonly, alias.structextends, alias=alias)
1860         alias.add_aliased_by(aliasee)
1861         return aliasee
1863     @staticmethod
1864     def from_xml(struct):
1865         # Unions and structs are the same parsing wise, but we need to
1866         # know which one we are dealing with later on for code generation.
1867         union = True if struct.attrib["category"] == "union" else False
1869         name = struct.attrib.get("name")
1871         # 'Output' structures for which data is filled in by the API are
1872         # marked as 'returnedonly'.
1873         returnedonly = True if struct.attrib.get("returnedonly") else False
1875         structextends = struct.attrib.get("structextends")
1876         structextends = structextends.split(",") if structextends else []
1878         members = []
1879         for member in struct.findall("member"):
1880             vk_member = VkMember.from_xml(member)
1881             members.append(vk_member)
1883         return VkStruct(name, members, returnedonly, structextends, union=union)
1885     @staticmethod
1886     def decouple_structs(structs):
1887         """ Helper function which decouples a list of structs.
1888         Structures often depend on other structures. To make the C compiler
1889         happy we need to define 'substructures' first. This function analyzes
1890         the list of structures and reorders them in such a way that they are
1891         decoupled.
1892         """
1894         tmp_structs = list(structs) # Don't modify the original structures.
1895         decoupled_structs = []
1897         while (len(tmp_structs) > 0):
1898             for struct in tmp_structs:
1899                 dependends = False
1901                 if not struct.required:
1902                     tmp_structs.remove(struct)
1903                     continue
1905                 for m in struct:
1906                     if not (m.is_struct() or m.is_union()):
1907                         continue
1909                     # VkBaseInstructure and VkBaseOutStructure reference themselves.
1910                     if m.type == struct.name:
1911                         break
1913                     found = False
1914                     # Check if a struct we depend on has already been defined.
1915                     for s in decoupled_structs:
1916                         if s.name == m.type:
1917                             found = True
1918                             break
1920                     if not found:
1921                         # Check if the struct we depend on is even in the list of structs.
1922                         # If found now, it means we haven't met all dependencies before we
1923                         # can operate on the current struct.
1924                         # When generating 'host' structs we may not be able to find a struct
1925                         # as the list would only contain the structs requiring conversion.
1926                         for s in tmp_structs:
1927                             if s.name == m.type:
1928                                 dependends = True
1929                                 break
1931                 if dependends == False:
1932                     decoupled_structs.append(struct)
1933                     tmp_structs.remove(struct)
1935         return decoupled_structs
1937     def definition(self, align=False, conv=False, postfix=None):
1938         """ Convert structure to textual definition.
1940         Args:
1941             align (bool, optional): enable alignment to 64-bit for win32 struct compatibility.
1942             conv (bool, optional): enable struct conversion if the struct needs it.
1943             postfix (str, optional): text to append to end of struct name, useful for struct renaming.
1944         """
1946         # Only define alias structs when doing conversions
1947         if self.is_alias() and not conv:
1948             return ""
1950         if self.union:
1951             text = "typedef union {0}".format(self.name)
1952         else:
1953             text = "typedef struct {0}".format(self.name)
1955         if postfix is not None:
1956             text += postfix
1958         text += "\n{\n"
1960         for m in self:
1961             if align and m.needs_alignment():
1962                 text += "    {0};\n".format(m.definition(align=align))
1963             elif conv and m.needs_conversion():
1964                 text += "    {0};\n".format(m.definition(conv=conv))
1965             else:
1966                 text += "    {0};\n".format(m.definition())
1968         if postfix is not None:
1969             text += "}} {0}{1};\n".format(self.name, postfix)
1970         else:
1971             text += "}} {0};\n".format(self.name)
1973         for aliasee in self.aliased_by:
1974             text += "typedef {0} {1};\n".format(self.name, aliasee.name)
1976         return text
1978     def is_alias(self):
1979         return bool(self.alias)
1981     def add_aliased_by(self, aliasee):
1982         self.aliased_by.append(aliasee)
1984     def needs_alignment(self):
1985         """ Check if structure needs alignment for 64-bit data.
1986         Various structures need alignment on 64-bit variables due
1987         to compiler differences on 32-bit between Win32 and Linux.
1988         """
1990         for m in self.members:
1991             if m.needs_alignment():
1992                 return True
1993         return False
1995     def needs_conversion(self):
1996         """ Returns if struct members needs conversion between win32 and host.
1997         Structures need conversion if they contain members requiring alignment
1998         or if they include other structures which need alignment.
1999         """
2001         if self.needs_alignment():
2002             return True
2004         for m in self.members:
2005             if m.needs_conversion():
2006                 return True
2007         return False
2009     def needs_unwrapping(self):
2010         """ Returns if struct members need unwrapping of handle. """
2012         for m in self.members:
2013             if m.needs_unwrapping():
2014                 return True
2015         return False
2017     def needs_free(self):
2018         """ Check if any struct member needs some memory freeing."""
2020         for m in self.members:
2021             if m.needs_free():
2022                 return True
2024             continue
2026         return False
2028     def needs_struct_extensions_conversion(self):
2029         """ Checks if structure extensions in pNext chain need conversion. """
2030         ret = False
2032         for e in self.struct_extensions:
2033             if e.required and e.needs_conversion():
2034                 LOGGER.error("Unhandled pNext chain alignment conversion for {0}".format(e.name))
2035                 ret = True
2036             if e.required and e.needs_unwrapping():
2037                 LOGGER.error("Unhandled pNext chain unwrapping conversion for {0}".format(e.name))
2038                 ret = True
2040         return ret
2042     def set_type_info(self, types):
2043         """ Helper function to set type information from the type registry.
2044         This is needed, because not all type data is available at time of
2045         parsing.
2046         """
2047         for m in self.members:
2048             type_info = types[m.type]
2049             m.set_type_info(type_info)
2052 class ConversionFunction(object):
2053     def __init__(self, array, dyn_array, direction, operand):
2054         self.array = array
2055         self.direction = direction
2056         self.dyn_array = dyn_array
2057         self.operand = operand
2058         self.type = operand.name
2060         self._set_name()
2062     def __eq__(self, other):
2063         return self.name == other.name
2065     def _generate_array_conversion_func(self):
2066         """ Helper function for generating a conversion function for array operands. """
2068         body = ""
2070         if self.operand.needs_conversion():
2071             body += "#if defined(USE_STRUCT_CONVERSION)\n"
2073             if self.direction == Direction.OUTPUT:
2074                 params = ["const {0}_host *in".format(self.type), "uint32_t count"]
2075                 return_type = self.type
2076             else:
2077                 params = ["const {0} *in".format(self.type), "uint32_t count"]
2078                 return_type = "{0}_host".format(self.type)
2080             # Generate function prototype.
2081             body += "static inline {0} *{1}(".format(return_type, self.name)
2082             body += ", ".join(p for p in params)
2083             body += ")\n{\n"
2085             body += "    {0} *out;\n".format(return_type)
2087         if self.operand.needs_unwrapping():
2088             if self.operand.needs_conversion():
2089                 body += "#else\n"
2091             params = ["const {0} *in".format(self.type), "uint32_t count"]
2092             return_type = "{0}".format(self.type)
2094             # Generate function prototype.
2095             body += "static inline {0} *{1}(".format(return_type, self.name)
2096             body += ", ".join(p for p in params)
2097             body += ")\n{\n"
2099             body += "    {0} *out;\n".format(return_type)
2101             if self.operand.needs_conversion():
2102                 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2104         body += "    unsigned int i;\n\n"
2105         body += "    if (!in) return NULL;\n\n"
2107         body += "    out = malloc(count * sizeof(*out));\n"
2109         body += "    for (i = 0; i < count; i++)\n"
2110         body += "    {\n"
2112         if isinstance(self.operand, VkStruct):
2113             for m in self.operand:
2114                 # TODO: support copying of pNext extension structures!
2115                 # Luckily though no extension struct at this point needs conversion.
2116                 convert = m.copy("in[i].", "out[i].", self.direction, conv=True)
2117                 if self.operand.needs_conversion() and not self.operand.needs_unwrapping():
2118                     body += "        " + convert
2119                 else:
2120                     unwrap = m.copy("in[i].", "out[i].", self.direction, conv=False)
2121                     if unwrap == convert:
2122                         body += "        " + unwrap
2123                     else:
2124                         body += "#if defined(USE_STRUCT_CONVERSION)\n"
2125                         body += "        " + convert
2126                         body += "#else\n"
2127                         body += "        " + unwrap
2128                         body += "#endif /* USE_STRUCT_CONVERSION */\n"
2130         elif isinstance(self.operand, VkHandle) and self.direction == Direction.INPUT:
2131             body += "        out[i] = " + self.operand.driver_handle("in[i]") + ";\n"
2132         else:
2133             LOGGER.warn("Unhandled conversion operand type")
2134             body += "        out[i] = in[i];\n"
2136         body += "    }\n\n"
2137         body += "    return out;\n"
2138         body += "}\n"
2140         if not self.operand.needs_unwrapping():
2141             body += "#endif /* USE_STRUCT_CONVERSION */\n"
2143         body += "\n"
2145         return body
2147     def _generate_conversion_func(self):
2148         """ Helper function for generating a conversion function for non-array operands. """
2150         # It doesn't make sense to generate conversion functions for non-struct variables
2151         # which aren't in arrays, as this should be handled by the copy() function
2152         if not isinstance(self.operand, VkStruct):
2153             return ""
2155         body = ""
2157         if self.operand.needs_conversion():
2158             body += "#if defined(USE_STRUCT_CONVERSION)\n"
2159             body += "static inline void {0}(".format(self.name)
2161             if self.direction == Direction.OUTPUT:
2162                 params = ["const {0}_host *in".format(self.type), "{0} *out".format(self.type)]
2163             else:
2164                 params = ["const {0} *in".format(self.type), "{0}_host *out".format(self.type)]
2166             # Generate parameter list
2167             body += ", ".join(p for p in params)
2168             body += ")\n"
2170         if self.operand.needs_unwrapping():
2171             if self.operand.needs_conversion():
2172                 body += "#else\n"
2174             body += "static inline void {0}(".format(self.name)
2176             params = ["const {0} *in".format(self.type), "{0} *out".format(self.type)]
2178             # Generate parameter list
2179             body += ", ".join(p for p in params)
2180             body += ")\n"
2182             if self.operand.needs_conversion():
2183                 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2185         body += "{\n    if (!in) return;\n\n"
2187         if self.direction == Direction.INPUT and "pNext" in self.operand and self.operand.returnedonly:
2188             # We are dealing with an input_output parameter. For these we only need to copy
2189             # pNext and sType as the other fields are filled in by the host. We do potentially
2190             # have to iterate over pNext and perform conversions based on switch(sType)!
2191             # Luckily though no extension structs at this point need conversion.
2192             # TODO: support copying of pNext extension structures!
2193             body += "    out->pNext = in->pNext;\n"
2194             body += "    out->sType = in->sType;\n"
2195         else:
2196             for m in self.operand:
2197                 # TODO: support copying of pNext extension structures!
2198                 convert = m.copy("in->", "out->", self.direction, conv=True)
2199                 if self.operand.needs_conversion() and not self.operand.needs_unwrapping():
2200                     body += "    " + convert
2201                 else:
2202                     unwrap = m.copy("in->", "out->", self.direction, conv=False)
2203                     if unwrap == convert:
2204                         body += "    " + unwrap
2205                     else:
2206                         body += "#if defined(USE_STRUCT_CONVERSION)\n"
2207                         body += "    " + convert
2208                         body += "#else\n"
2209                         body += "    " + unwrap
2210                         body += "#endif /* USE_STRUCT_CONVERSION */\n"
2212         body += "}\n"
2214         if not self.operand.needs_unwrapping():
2215             body += "#endif /* USE_STRUCT_CONVERSION */\n"
2217         body += "\n"
2219         return body
2221     def _generate_static_array_conversion_func(self):
2222         """ Helper function for generating a conversion function for array operands. """
2224         body = ""
2226         if self.operand.needs_conversion():
2227             body += "#if defined(USE_STRUCT_CONVERSION)\n"
2229             if self.direction == Direction.OUTPUT:
2230                 params = ["const {0}_host *in".format(self.type), "{0} *out".format(self.type), "uint32_t count"]
2231             else:
2232                 params = ["const {0} *in".format(self.type), "{0} *out_host".format(self.type), "uint32_t count"]
2234             # Generate function prototype.
2235             body += "static inline void {0}(".format(self.name)
2236             body += ", ".join(p for p in params)
2237             body += ")\n"
2239         if self.operand.needs_unwrapping():
2240             if self.operand.needs_conversion():
2241                 body += "#else\n"
2243             params = ["const {0} *in".format(self.type), "{0} *out".format(self.type), "uint32_t count"]
2245             # Generate function prototype.
2246             body += "static inline void {0}(".format(self.name)
2247             body += ", ".join(p for p in params)
2248             body += ")\n"
2250         body += "{\n"
2251         body += "    unsigned int i;\n\n"
2252         body += "    if (!in) return;\n\n"
2253         body += "    for (i = 0; i < count; i++)\n"
2254         body += "    {\n"
2256         if isinstance(self.operand, VkStruct):
2257             for m in self.operand:
2258                 # TODO: support copying of pNext extension structures!
2259                 convert = m.copy("in[i].", "out[i].", self.direction, conv=True)
2260                 if self.operand.needs_conversion() and not self.operand.needs_unwrapping():
2261                     body += "        " + convert
2262                 else:
2263                     unwrap = m.copy("in[i].", "out[i].", self.direction, conv=False)
2264                     if unwrap == convert:
2265                         body += "        " + unwrap
2266                     else:
2267                         body += "#if defined(USE_STRUCT_CONVERSION)\n"
2268                         body += "    " + convert
2269                         body += "#else\n"
2270                         body += "    " + unwrap
2271                         body += "#endif /* USE_STRUCT_CONVERSION */\n"
2272         elif isinstance(self.operand, VkHandle) and self.direction == Direction.INPUT:
2273             body += "        out[i] = " + self.operand.driver_handle("in[i]") + ";\n"
2274         else:
2275             LOGGER.warn("Unhandled conversion operand type")
2276             body += "        out[i] = in[i];\n"
2278         body += "    }\n"
2279         body += "}\n"
2281         if not self.operand.needs_unwrapping():
2282             body += "#endif /* USE_STRUCT_CONVERSION) */\n"
2284         body += "\n"
2286         return body
2288     def _set_name(self):
2289         if self.direction == Direction.INPUT:
2290             if self.array:
2291                 name = "convert_{0}_static_array_win_to_host".format(self.type)
2292             elif self.dyn_array:
2293                 name = "convert_{0}_array_win_to_host".format(self.type)
2294             else:
2295                 name = "convert_{0}_win_to_host".format(self.type)
2296         else: # Direction.OUTPUT
2297             if self.array:
2298                 name = "convert_{0}_static_array_host_to_win".format(self.type)
2299             elif self.dyn_array:
2300                 name = "convert_{0}_array_host_to_win".format(self.type)
2301             else:
2302                 name = "convert_{0}_host_to_win".format(self.type)
2304         self.name = name
2306     def definition(self):
2307         if self.array:
2308             return self._generate_static_array_conversion_func()
2309         elif self.dyn_array:
2310             return self._generate_array_conversion_func()
2311         else:
2312             return self._generate_conversion_func()
2315 class FreeFunction(object):
2316     def __init__(self, dyn_array, operand):
2317         self.dyn_array = dyn_array
2318         self.operand = operand
2319         self.type = operand.name
2321         if dyn_array:
2322             self.name = "free_{0}_array".format(self.type)
2323         else:
2324             self.name = "free_{0}".format(self.type)
2326     def __eq__(self, other):
2327         return self.name == other.name
2329     def _generate_array_free_func(self):
2330         """ Helper function for cleaning up temporary buffers required for array conversions. """
2332         body = ""
2334         if self.operand.needs_conversion():
2335             body += "#if defined(USE_STRUCT_CONVERSION)\n"
2336             # Generate function prototype.
2337             body += "static inline void {0}({1}_host *in, uint32_t count)\n".format(self.name, self.type)
2339         if self.operand.needs_unwrapping():
2340             if self.operand.needs_conversion():
2341                 body += "#else\n"
2343             # Generate function prototype.
2344             body += "static inline void {0}({1} *in, uint32_t count)\n".format(self.name, self.type)
2346             if self.operand.needs_conversion():
2347                 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2349         body += "{\n"
2351         # E.g. VkGraphicsPipelineCreateInfo_host needs freeing for pStages.
2352         if isinstance(self.operand, VkStruct) and self.operand.needs_free():
2353             body += "    unsigned int i;\n\n"
2354             body += "    if (!in) return;\n\n"
2355             body += "    for (i = 0; i < count; i++)\n"
2356             body += "    {\n"
2358             for m in self.operand:
2359                 if m.needs_free():
2360                     convert = m.free("in[i].", conv=True)
2361                     if self.operand.needs_conversion() and not self.operand.needs_unwrapping():
2362                         body += "        " + convert
2363                     else:
2364                         unwrap = m.free("in[i].", conv=False)
2365                         if convert == unwrap:
2366                             body += "        " + unwrap
2367                         elif unwrap == "":
2368                             body += "#if defined(USE_STRUCT_CONVERSION)\n"
2369                             body += "        " + convert
2370                             body += "#endif /* USE_STRUCT_CONVERSION */\n"
2371                         else:
2372                             body += "#if defined(USE_STRUCT_CONVERSION)\n"
2373                             body += "        " + convert
2374                             body += "#else\n"
2375                             body += "        " + unwrap
2376                             body += "#endif /* USE_STRUCT_CONVERSION */\n"
2377             body += "    }\n"
2378         else:
2379             body += "    if (!in) return;\n\n"
2381         body += "    free(in);\n"
2383         body += "}\n"
2385         if not self.operand.needs_unwrapping():
2386             body += "#endif /* USE_STRUCT_CONVERSION */\n"
2388         body += "\n"
2390         return body
2392     def _generate_free_func(self):
2393         # E.g. VkCommandBufferBeginInfo.pInheritanceInfo needs freeing.
2394         if not self.operand.needs_free():
2395             return ""
2397         if not isinstance(self.operand, VkStruct):
2398             return ""
2400         body = ""
2402         if self.operand.needs_conversion():
2403             body += "#if defined(USE_STRUCT_CONVERSION)\n"
2404             # Generate function prototype.
2405             body += "static inline void {0}({1}_host *in)\n".format(self.name, self.type)
2407         if self.operand.needs_unwrapping():
2408             if self.operand.needs_conversion():
2409                 body += "#else\n"
2411             # Generate function prototype.
2412             body += "static inline void {0}({1} *in)\n".format(self.name, self.type)
2414             if self.operand.needs_conversion():
2415                 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2417         body += "{\n"
2419         for m in self.operand:
2420             if m.needs_free():
2421                 convert = m.free("in->", conv=True)
2422                 if self.operand.needs_conversion() and not self.operand.needs_unwrapping():
2423                     body += "    " + convert
2424                 else:
2425                     unwrap = m.free("in->", conv=False)
2426                     if convert == unwrap:
2427                         body += "    " + unwrap
2428                     elif unwrap == "":
2429                         body += "#if defined(USE_STRUCT_CONVERSION)\n"
2430                         body += "    " + convert
2431                         body += "#endif /* USE_STRUCT_CONVERSION */\n"
2432                     else:
2433                         body += "#if defined(USE_STRUCT_CONVERSION)\n"
2434                         body += "    " + convert
2435                         body += "#else\n"
2436                         body += "    " + unwrap
2437                         body += "#endif /* USE_STRUCT_CONVERSION */\n"
2439         body += "}\n"
2441         if not self.operand.needs_unwrapping():
2442             body += "#endif /* USE_STRUCT_CONVERSION */\n"
2444         body += "\n"
2446         return body
2448     def definition(self):
2449         if self.dyn_array:
2450             return self._generate_array_free_func()
2451         else:
2452             # Some structures need freeing too if they contain dynamic arrays.
2453             # E.g. VkCommandBufferBeginInfo
2454             return self._generate_free_func()
2457 class StructChainConversionFunction(object):
2458     def __init__(self, direction, struct, ignores):
2459         self.direction = direction
2460         self.struct = struct
2461         self.ignores = ignores
2462         self.type = struct.name
2464         self.name = "convert_{0}_struct_chain".format(self.type)
2466     def __eq__(self, other):
2467         return self.name == other.name
2469     def prototype(self, postfix=""):
2470         return "VkResult {0}(const void *pNext, {1} *out_struct) {2}".format(self.name, self.type, postfix).strip()
2472     def definition(self):
2473         body = self.prototype()
2474         body += "\n{\n"
2476         body += "    VkBaseOutStructure *out_header = (VkBaseOutStructure *)out_struct;\n";
2477         body += "    const VkBaseInStructure *in_header;\n\n";
2479         body += "    out_header->pNext = NULL;\n\n"
2481         body += "    for (in_header = pNext; in_header; in_header = in_header->pNext)\n"
2482         body += "    {\n"
2483         body += "        switch (in_header->sType)\n"
2484         body += "        {\n"
2486         for i in self.ignores:
2487             body += "        case {0}:\n".format(i)
2488         body += "            break;\n\n"
2490         for e in self.struct.struct_extensions:
2491             if not e.required:
2492                 continue
2494             stype = next(x for x in e.members if x.name == "sType")
2496             if stype.values in self.ignores:
2497                 continue
2499             body += "        case {0}:\n".format(stype.values)
2500             body += "        {\n"
2502             body += "            const {0} *in = (const {0} *)in_header;\n".format(e.name)
2503             body += "            {0} *out;\n\n".format(e.name)
2505             body += "            if (!(out = malloc(sizeof(*out)))) goto out_of_memory;\n\n"
2507             for m in e:
2508                 if m.name == "pNext":
2509                     body += "            out->pNext = NULL;\n"
2510                 else:
2511                     convert = m.copy("in->", "out->", self.direction, conv=True)
2512                     unwrap = m.copy("in->", "out->", self.direction, conv=False)
2513                     if unwrap == convert:
2514                         body += "            " + unwrap
2515                     else:
2516                         body += "#if defined(USE_STRUCT_CONVERSION)\n"
2517                         body += "            " + convert
2518                         body += "#else\n"
2519                         body += "            " + unwrap
2520                         body += "#endif /* USE_STRUCT_CONVERSION */\n"
2522             body += "\n            out_header->pNext = (VkBaseOutStructure *)out;\n"
2523             body += "            out_header = out_header->pNext;\n"
2524             body += "            break;\n"
2525             body += "        }\n\n"
2527         body += "        default:\n"
2528         body += "            FIXME(\"Application requested a linked structure of type %u.\\n\", in_header->sType);\n"
2530         body += "        }\n"
2531         body += "    }\n\n"
2533         body += "    return VK_SUCCESS;\n"
2535         if any(x for x in self.struct.struct_extensions if x.required):
2536             body += "\nout_of_memory:\n"
2537             body += "    free_{0}_struct_chain(out_struct);\n".format(self.type)
2538             body += "    return VK_ERROR_OUT_OF_HOST_MEMORY;\n"
2540         body += "}\n\n"
2541         return body
2543 class FreeStructChainFunction(object):
2544     def __init__(self, struct):
2545         self.struct = struct
2546         self.type = struct.name
2548         self.name = "free_{0}_struct_chain".format(self.type)
2550     def __eq__(self, other):
2551         return self.name == other.name
2553     def prototype(self, postfix=""):
2554         return "void {0}({1} *s) {2}".format(self.name, self.type, postfix).strip()
2556     def definition(self):
2557         body = self.prototype()
2558         body += "\n{\n"
2560         body += "    VkBaseOutStructure *header = (void *)s->pNext;\n\n";
2562         body += "    while (header)\n"
2563         body += "    {\n"
2564         body += "        void *prev = header;\n\n"
2565         body += "        switch (header->sType)\n"
2566         body += "        {\n"
2568         for e in self.struct.struct_extensions:
2569             if not e.required:
2570                 continue
2572             if not any(m.needs_free() for m in e):
2573                 continue
2575             stype = next(x for x in e.members if x.name == "sType")
2577             body += "            case {0}:\n".format(stype.values)
2578             body += "            {\n"
2579             body += "                {0} *structure = ({0} *) header;\n".format(e.name)
2581             for m in e:
2582                 if m.needs_free():
2583                     convert = m.free("structure->", conv=True)
2584                     unwrap = m.free("structure->", conv=False)
2585                     if convert == unwrap:
2586                         body += "                " + unwrap
2587                     elif unwrap == "":
2588                         body += "#if defined(USE_STRUCT_CONVERSION)\n"
2589                         body += "                " + convert
2590                         body += "#endif /* USE_STRUCT_CONVERSION */\n"
2591                     else:
2592                         body += "#if defined(USE_STRUCT_CONVERSION)\n"
2593                         body += "                " + convert
2594                         body += "#else\n"
2595                         body += "                " + unwrap
2596                         body += "#endif /* USE_STRUCT_CONVERSION */\n"
2598             body += "                break;\n"
2599             body += "            }\n"
2601         body += "            default:\n"
2602         body += "                break;\n"
2603         body += "        }\n"
2605         body += "        header = header->pNext;\n"
2606         body += "        free(prev);\n"
2607         body += "    }\n\n"
2609         body += "    s->pNext = NULL;\n"
2611         body += "}\n\n"
2612         return body
2615 class VkGenerator(object):
2616     def __init__(self, registry):
2617         self.registry = registry
2619         # Build a list conversion functions for struct conversion.
2620         self.conversions = []
2621         self.struct_chain_conversions = []
2622         self.host_structs = []
2623         for func in self.registry.funcs.values():
2624             if not func.is_required():
2625                 continue
2627             if not func.needs_conversion() and not func.needs_unwrapping():
2628                 continue
2630             conversions = func.get_conversions()
2631             for conv in conversions:
2632                 # Pull in any conversions for vulkan_thunks.c.
2633                 if func.needs_thunk():
2634                     # Append if we don't already have this conversion.
2635                     if not any(c == conv for c in self.conversions):
2636                         self.conversions.append(conv)
2638                 if not isinstance(conv.operand, VkStruct):
2639                     continue
2641                 # Structs can be used in different ways by different conversions
2642                 # e.g. array vs non-array. Just make sure we pull in each struct once.
2643                 if not any(s.name == conv.operand.name for s in self.host_structs):
2644                     self.host_structs.append(conv.operand)
2646         for struct in self.registry.structs:
2647             if struct.name in STRUCT_CHAIN_CONVERSIONS:
2648                 self.struct_chain_conversions.append(StructChainConversionFunction(Direction.INPUT, struct, STRUCT_CHAIN_CONVERSIONS[struct.name]))
2649                 self.struct_chain_conversions.append(FreeStructChainFunction(struct))
2650                 # Once we decide to support pNext chains conversion everywhere, move this under get_conversions
2651                 for e in struct.struct_extensions:
2652                     for m in e:
2653                         if m.needs_conversion() or m.needs_unwrapping():
2654                             conversions = m.get_conversions()
2655                             for conv in conversions:
2656                                 if not any(c == conv for c in self.conversions):
2657                                     self.conversions.append(conv)
2659     def _generate_copyright(self, f, spec_file=False):
2660         f.write("# " if spec_file else "/* ")
2661         f.write("Automatically generated from Vulkan vk.xml; DO NOT EDIT!\n")
2662         lines = ["", "This file is generated from Vulkan vk.xml file covered",
2663             "by the following copyright and permission notice:"]
2664         lines.extend([l.rstrip(" ") for l in self.registry.copyright.splitlines()])
2665         for line in lines:
2666             f.write("{0}{1}".format("# " if spec_file else " * ", line).rstrip(" ") + "\n")
2667         f.write("\n" if spec_file else " */\n\n")
2669     def generate_thunks_c(self, f, prefix):
2670         self._generate_copyright(f)
2672         f.write("#if 0\n")
2673         f.write("#pragma makedep unix\n")
2674         f.write("#endif\n\n")
2676         f.write("#include \"config.h\"\n")
2677         f.write("#include \"wine/port.h\"\n\n")
2679         f.write("#include \"vulkan_private.h\"\n\n")
2681         f.write("WINE_DEFAULT_DEBUG_CHANNEL(vulkan);\n\n")
2683         # Generate any conversion helper functions.
2684         for conv in self.conversions:
2685             f.write(conv.definition())
2687         for conv in self.struct_chain_conversions:
2688             f.write(conv.definition())
2690         # Create thunks for instance and device functions.
2691         # Global functions don't go through the thunks.
2692         for vk_func in self.registry.funcs.values():
2693             if not vk_func.needs_exposing():
2694                 continue
2696             if vk_func.is_global_func():
2697                 continue
2699             if not vk_func.needs_thunk():
2700                 continue
2702             if vk_func.needs_private_thunk():
2703                 f.write(vk_func.thunk(prefix="thunk_"))
2704             else:
2705                 f.write("static ")
2706                 f.write(vk_func.thunk(prefix=prefix, call_conv="WINAPI"))
2708         # Create array of device extensions.
2709         f.write("static const char * const vk_device_extensions[] =\n{\n")
2710         for ext in self.registry.extensions:
2711             if ext["type"] != "device":
2712                 continue
2713             if ext["name"] in UNEXPOSED_EXTENSIONS:
2714                 continue
2716             f.write("    \"{0}\",\n".format(ext["name"]))
2717         f.write("};\n\n")
2719         # Create array of instance extensions.
2720         f.write("static const char * const vk_instance_extensions[] =\n{\n")
2721         for ext in self.registry.extensions:
2722             if ext["type"] != "instance":
2723                 continue
2724             if ext["name"] in UNEXPOSED_EXTENSIONS:
2725                 continue
2727             f.write("    \"{0}\",\n".format(ext["name"]))
2728         f.write("};\n\n")
2730         f.write("BOOL wine_vk_device_extension_supported(const char *name)\n")
2731         f.write("{\n")
2732         f.write("    unsigned int i;\n")
2733         f.write("    for (i = 0; i < ARRAY_SIZE(vk_device_extensions); i++)\n")
2734         f.write("    {\n")
2735         f.write("        if (strcmp(vk_device_extensions[i], name) == 0)\n")
2736         f.write("            return TRUE;\n")
2737         f.write("    }\n")
2738         f.write("    return FALSE;\n")
2739         f.write("}\n\n")
2741         f.write("BOOL wine_vk_instance_extension_supported(const char *name)\n")
2742         f.write("{\n")
2743         f.write("    unsigned int i;\n")
2744         f.write("    for (i = 0; i < ARRAY_SIZE(vk_instance_extensions); i++)\n")
2745         f.write("    {\n")
2746         f.write("        if (strcmp(vk_instance_extensions[i], name) == 0)\n")
2747         f.write("            return TRUE;\n")
2748         f.write("    }\n")
2749         f.write("    return FALSE;\n")
2750         f.write("}\n\n")
2752         f.write("BOOL wine_vk_is_type_wrapped(VkObjectType type)\n")
2753         f.write("{\n")
2754         f.write("    return FALSE")
2755         for handle in self.registry.handles:
2756             if not handle.is_required() or not handle.is_wrapped() or handle.is_alias():
2757                 continue
2758             f.write(" ||\n        type == {}".format(handle.object_type))
2759         f.write(";\n")
2760         f.write("}\n\n")
2762         f.write("uint64_t wine_vk_unwrap_handle(VkObjectType type, uint64_t handle)\n")
2763         f.write("{\n")
2764         f.write("    switch(type)\n")
2765         f.write("    {\n")
2766         for handle in self.registry.handles:
2767             if not handle.is_required() or not handle.is_wrapped() or handle.is_alias():
2768                 continue
2769             f.write("    case {}:\n".format(handle.object_type))
2770             if handle.is_dispatchable():
2771                 f.write("        return (uint64_t) (uintptr_t) ")
2772                 f.write(handle.native_handle("(({}) (uintptr_t) handle)".format(handle.name)))
2773             else:
2774                 f.write("        return (uint64_t) ")
2775                 f.write(handle.native_handle("handle"))
2776             f.write(";\n");
2777         f.write("    default:\n")
2778         f.write("       return handle;\n")
2779         f.write("    }\n")
2780         f.write("}\n\n")
2782         f.write("const struct unix_funcs loader_funcs =\n")
2783         f.write("{\n")
2784         for vk_func in self.registry.funcs.values():
2785             if not vk_func.needs_exposing():
2786                 continue
2787             if vk_func.loader_thunk_type == ThunkType.NONE:
2788                 continue
2790             f.write("    &{1}{0},\n".format(vk_func.name, prefix))
2791         f.write("};\n")
2793     def generate_thunks_h(self, f, prefix):
2794         self._generate_copyright(f)
2796         f.write("#ifndef __WINE_VULKAN_THUNKS_H\n")
2797         f.write("#define __WINE_VULKAN_THUNKS_H\n\n")
2799         f.write("#define WINE_VK_VERSION VK_API_VERSION_{0}_{1}\n\n".format(WINE_VK_VERSION[0], WINE_VK_VERSION[1]))
2801         # Generate prototypes for device and instance functions requiring a custom implementation.
2802         f.write("/* Functions for which we have custom implementations outside of the thunks. */\n")
2803         for vk_func in self.registry.funcs.values():
2804             if not vk_func.needs_exposing():
2805                 continue
2806             if vk_func.needs_thunk() and not vk_func.needs_private_thunk():
2807                 continue
2809             if vk_func.is_core_func():
2810                 f.write("{0};\n".format(vk_func.prototype("WINAPI", prefix=prefix)))
2811             else:
2812                 f.write("{0};\n".format(vk_func.prototype("WINAPI", prefix=prefix, postfix="DECLSPEC_HIDDEN")))
2813         f.write("\n")
2815         f.write("/* Private thunks */\n")
2816         for vk_func in self.registry.funcs.values():
2817             if vk_func.needs_private_thunk():
2818                 f.write("{0};\n".format(vk_func.prototype(prefix="thunk_", postfix="DECLSPEC_HIDDEN")))
2819         f.write("\n")
2821         for struct in self.host_structs:
2822             f.write("#if defined(USE_STRUCT_CONVERSION)\n")
2823             f.write(struct.definition(align=False, conv=True, postfix="_host"))
2824             f.write("#else\n")
2825             f.write("typedef {0} {0}_host;\n".format(struct.name))
2826             f.write("#endif\n\n")
2827         f.write("\n")
2829         for func in self.struct_chain_conversions:
2830             f.write(func.prototype(postfix="DECLSPEC_HIDDEN") + ";\n")
2831         f.write("\n")
2833         f.write("/* For use by vkDevice and children */\n")
2834         f.write("struct vulkan_device_funcs\n{\n")
2835         for vk_func in self.registry.device_funcs:
2836             if not vk_func.is_required():
2837                 continue
2839             if not vk_func.needs_dispatch():
2840                 LOGGER.debug("skipping {0} in vulkan_device_funcs".format(vk_func.name))
2841                 continue
2843             f.write("    {0};\n".format(vk_func.pfn(conv=vk_func.needs_conversion())))
2844         f.write("};\n\n")
2846         f.write("/* For use by vkInstance and children */\n")
2847         f.write("struct vulkan_instance_funcs\n{\n")
2848         for vk_func in self.registry.instance_funcs + self.registry.phys_dev_funcs:
2849             if not vk_func.is_required():
2850                 continue
2852             if not vk_func.needs_dispatch():
2853                 LOGGER.debug("skipping {0} in vulkan_instance_funcs".format(vk_func.name))
2854                 continue
2856             f.write("    {0};\n".format(vk_func.pfn(conv=vk_func.needs_conversion())))
2857         f.write("};\n\n")
2859         f.write("#define ALL_VK_DEVICE_FUNCS() \\\n")
2860         first = True
2861         for vk_func in self.registry.device_funcs:
2862             if not vk_func.is_required():
2863                 continue
2865             if not vk_func.needs_dispatch():
2866                 LOGGER.debug("skipping {0} in ALL_VK_DEVICE_FUNCS".format(vk_func.name))
2867                 continue
2869             if first:
2870                 f.write("    USE_VK_FUNC({0})".format(vk_func.name))
2871                 first = False
2872             else:
2873                 f.write(" \\\n    USE_VK_FUNC({0})".format(vk_func.name))
2874         f.write("\n\n")
2876         f.write("#define ALL_VK_INSTANCE_FUNCS() \\\n")
2877         first = True
2878         for vk_func in self.registry.instance_funcs + self.registry.phys_dev_funcs:
2879             if not vk_func.is_required():
2880                 continue
2882             if not vk_func.needs_dispatch():
2883                 LOGGER.debug("skipping {0} in ALL_VK_INSTANCE_FUNCS".format(vk_func.name))
2884                 continue
2886             if first:
2887                 f.write("    USE_VK_FUNC({0})".format(vk_func.name))
2888                 first = False
2889             else:
2890                 f.write(" \\\n    USE_VK_FUNC({0})".format(vk_func.name))
2891         f.write("\n\n")
2893         f.write("#endif /* __WINE_VULKAN_THUNKS_H */\n")
2895     def generate_loader_thunks_c(self, f):
2896         self._generate_copyright(f)
2898         f.write("#include \"vulkan_loader.h\"\n\n")
2900         f.write("WINE_DEFAULT_DEBUG_CHANNEL(vulkan);\n\n")
2902         for vk_func in self.registry.funcs.values():
2903             if not vk_func.needs_exposing():
2904                 continue
2905             if vk_func.loader_thunk_type != ThunkType.PUBLIC:
2906                 continue
2908             f.write(vk_func.loader_thunk())
2910         f.write("static const struct vulkan_func vk_device_dispatch_table[] =\n{\n")
2911         for vk_func in self.registry.device_funcs:
2912             if not vk_func.needs_exposing():
2913                 continue
2915             f.write("    {{\"{0}\", &{0}}},\n".format(vk_func.name))
2916         f.write("};\n\n")
2918         f.write("static const struct vulkan_func vk_phys_dev_dispatch_table[] =\n{\n")
2919         for vk_func in self.registry.phys_dev_funcs:
2920             if not vk_func.needs_exposing():
2921                 continue
2923             f.write("    {{\"{0}\", &{0}}},\n".format(vk_func.name))
2924         f.write("};\n\n")
2926         f.write("static const struct vulkan_func vk_instance_dispatch_table[] =\n{\n")
2927         for vk_func in self.registry.instance_funcs:
2928             if not vk_func.needs_exposing():
2929                 continue
2931             f.write("    {{\"{0}\", &{0}}},\n".format(vk_func.name))
2932         f.write("};\n\n")
2934         f.write("void *wine_vk_get_device_proc_addr(const char *name)\n")
2935         f.write("{\n")
2936         f.write("    unsigned int i;\n")
2937         f.write("    for (i = 0; i < ARRAY_SIZE(vk_device_dispatch_table); i++)\n")
2938         f.write("    {\n")
2939         f.write("        if (strcmp(vk_device_dispatch_table[i].name, name) == 0)\n")
2940         f.write("        {\n")
2941         f.write("            TRACE(\"Found name=%s in device table\\n\", debugstr_a(name));\n")
2942         f.write("            return vk_device_dispatch_table[i].func;\n")
2943         f.write("        }\n")
2944         f.write("    }\n")
2945         f.write("    return NULL;\n")
2946         f.write("}\n\n")
2948         f.write("void *wine_vk_get_phys_dev_proc_addr(const char *name)\n")
2949         f.write("{\n")
2950         f.write("    unsigned int i;\n")
2951         f.write("    for (i = 0; i < ARRAY_SIZE(vk_phys_dev_dispatch_table); i++)\n")
2952         f.write("    {\n")
2953         f.write("        if (strcmp(vk_phys_dev_dispatch_table[i].name, name) == 0)\n")
2954         f.write("        {\n")
2955         f.write("            TRACE(\"Found name=%s in physical device table\\n\", debugstr_a(name));\n")
2956         f.write("            return vk_phys_dev_dispatch_table[i].func;\n")
2957         f.write("        }\n")
2958         f.write("    }\n")
2959         f.write("    return NULL;\n")
2960         f.write("}\n\n")
2962         f.write("void *wine_vk_get_instance_proc_addr(const char *name)\n")
2963         f.write("{\n")
2964         f.write("    unsigned int i;\n")
2965         f.write("    for (i = 0; i < ARRAY_SIZE(vk_instance_dispatch_table); i++)\n")
2966         f.write("    {\n")
2967         f.write("        if (strcmp(vk_instance_dispatch_table[i].name, name) == 0)\n")
2968         f.write("        {\n")
2969         f.write("            TRACE(\"Found name=%s in instance table\\n\", debugstr_a(name));\n")
2970         f.write("            return vk_instance_dispatch_table[i].func;\n")
2971         f.write("        }\n")
2972         f.write("    }\n")
2973         f.write("    return NULL;\n")
2974         f.write("}\n")
2976     def generate_loader_thunks_h(self, f):
2977         self._generate_copyright(f)
2979         f.write("#ifndef __WINE_VULKAN_LOADER_THUNKS_H\n")
2980         f.write("#define __WINE_VULKAN_LOADER_THUNKS_H\n\n")
2982         f.write("struct unix_funcs\n")
2983         f.write("{\n")
2984         for vk_func in self.registry.funcs.values():
2985             if not vk_func.needs_exposing():
2986                 continue
2987             if vk_func.loader_thunk_type == ThunkType.NONE:
2988                 continue
2990             f.write("    {0};\n".format(vk_func.pfn(conv=False, call_conv="WINAPI")))
2991         f.write("};\n\n")
2993         f.write("#endif /* __WINE_VULKAN_LOADER_THUNKS_H */\n")
2995     def generate_vulkan_h(self, f):
2996         self._generate_copyright(f)
2997         f.write("#ifndef __WINE_VULKAN_H\n")
2998         f.write("#define __WINE_VULKAN_H\n\n")
3000         f.write("#include <windef.h>\n")
3001         f.write("#include <stdint.h>\n\n")
3003         f.write("/* Define WINE_VK_HOST to get 'host' headers. */\n")
3004         f.write("#ifdef WINE_VK_HOST\n")
3005         f.write("#define VKAPI_CALL\n")
3006         f.write('#define WINE_VK_ALIGN(x)\n')
3007         f.write("#endif\n\n")
3009         f.write("#ifndef VKAPI_CALL\n")
3010         f.write("#define VKAPI_CALL __stdcall\n")
3011         f.write("#endif\n\n")
3013         f.write("#ifndef VKAPI_PTR\n")
3014         f.write("#define VKAPI_PTR VKAPI_CALL\n")
3015         f.write("#endif\n\n")
3017         f.write("#ifndef WINE_VK_ALIGN\n")
3018         f.write("#define WINE_VK_ALIGN DECLSPEC_ALIGN\n")
3019         f.write("#endif\n\n")
3021         # The overall strategy is to define independent constants and datatypes,
3022         # prior to complex structures and function calls to avoid forward declarations.
3023         for const in self.registry.consts:
3024             # For now just generate things we may not need. The amount of parsing needed
3025             # to get some of the info is tricky as you need to figure out which structure
3026             # references a certain constant.
3027             f.write(const.definition())
3028         f.write("\n")
3030         for define in self.registry.defines:
3031             f.write(define.definition())
3033         for handle in self.registry.handles:
3034             # For backward compatibility also create definitions for aliases.
3035             # These types normally don't get pulled in as we use the new types
3036             # even in legacy functions if they are aliases.
3037             if handle.is_required() or handle.is_alias():
3038                  f.write(handle.definition())
3039         f.write("\n")
3041         for base_type in self.registry.base_types:
3042             f.write(base_type.definition())
3043         f.write("\n")
3045         for bitmask in self.registry.bitmasks:
3046             f.write(bitmask.definition())
3047         f.write("\n")
3049         # Define enums, this includes values for some of the bitmask types as well.
3050         for enum in self.registry.enums.values():
3051             if enum.required:
3052                 f.write(enum.definition())
3054         for fp in self.registry.funcpointers:
3055             if fp.required:
3056                 f.write(fp.definition())
3057         f.write("\n")
3059         # This generates both structures and unions. Since structures
3060         # may depend on other structures/unions, we need a list of
3061         # decoupled structs.
3062         # Note: unions are stored in structs for dependency reasons,
3063         # see comment in parsing section.
3064         structs = VkStruct.decouple_structs(self.registry.structs)
3065         for struct in structs:
3066             LOGGER.debug("Generating struct: {0}".format(struct.name))
3067             f.write(struct.definition(align=True))
3068             f.write("\n")
3070         for func in self.registry.funcs.values():
3071             if not func.is_required():
3072                 LOGGER.debug("Skipping PFN definition for: {0}".format(func.name))
3073                 continue
3075             f.write("typedef {0};\n".format(func.pfn(prefix="PFN", call_conv="VKAPI_PTR")))
3076         f.write("\n")
3078         f.write("#ifndef VK_NO_PROTOTYPES\n")
3079         for func in self.registry.funcs.values():
3080             if not func.is_required():
3081                 LOGGER.debug("Skipping API definition for: {0}".format(func.name))
3082                 continue
3084             LOGGER.debug("Generating API definition for: {0}".format(func.name))
3085             f.write("{0};\n".format(func.prototype(call_conv="VKAPI_CALL")))
3086         f.write("#endif /* VK_NO_PROTOTYPES */\n\n")
3088         f.write("#endif /* __WINE_VULKAN_H */\n")
3090     def generate_vulkan_driver_h(self, f):
3091         self._generate_copyright(f)
3092         f.write("#ifndef __WINE_VULKAN_DRIVER_H\n")
3093         f.write("#define __WINE_VULKAN_DRIVER_H\n\n")
3095         f.write("/* Wine internal vulkan driver version, needs to be bumped upon vulkan_funcs changes. */\n")
3096         f.write("#define WINE_VULKAN_DRIVER_VERSION {0}\n\n".format(DRIVER_VERSION))
3098         f.write("struct vulkan_funcs\n{\n")
3099         f.write("    /* Vulkan global functions. These are the only calls at this point a graphics driver\n")
3100         f.write("     * needs to provide. Other function calls will be provided indirectly by dispatch\n")
3101         f.write("     * tables part of dispatchable Vulkan objects such as VkInstance or vkDevice.\n")
3102         f.write("     */\n")
3104         for vk_func in self.registry.funcs.values():
3105             if not vk_func.is_driver_func():
3106                 continue
3108             pfn = vk_func.pfn()
3109             # Avoid PFN_vkVoidFunction in driver interface as Vulkan likes to put calling convention
3110             # stuff in there. For simplicity substitute with "void *".
3111             pfn = pfn.replace("PFN_vkVoidFunction", "void *")
3112             f.write("    {0};\n".format(pfn))
3114         f.write("\n")
3115         f.write("    /* winevulkan specific functions */\n")
3116         f.write("    VkSurfaceKHR (*p_wine_get_native_surface)(VkSurfaceKHR);\n")
3117         f.write("};\n\n")
3119         f.write("extern const struct vulkan_funcs * CDECL __wine_get_vulkan_driver(HDC hdc, UINT version);\n\n")
3121         f.write("static inline void *get_vulkan_driver_device_proc_addr(\n")
3122         f.write("        const struct vulkan_funcs *vulkan_funcs, const char *name)\n{\n")
3123         f.write("    if (!name || name[0] != 'v' || name[1] != 'k') return NULL;\n\n")
3124         f.write("    name += 2;\n\n")
3125         for vk_func in self.registry.funcs.values():
3126             if vk_func.is_driver_func() and vk_func.is_device_func():
3127                 f.write('    if (!strcmp(name, "{0}"))\n'.format(vk_func.name[2:]))
3128                 f.write('        return vulkan_funcs->p_{0};\n'.format(vk_func.name))
3129         f.write("\n")
3130         f.write("    return NULL;\n}\n\n")
3132         f.write("static inline void *get_vulkan_driver_instance_proc_addr(\n")
3133         f.write("        const struct vulkan_funcs *vulkan_funcs, VkInstance instance, const char *name)\n{\n")
3134         f.write("    if (!name || name[0] != 'v' || name[1] != 'k') return NULL;\n\n")
3135         f.write("    name += 2;\n\n")
3136         for vk_func in self.registry.funcs.values():
3137             if vk_func.is_driver_func() and vk_func.is_global_func() and vk_func.name != "vkGetInstanceProcAddr":
3138                 f.write('    if (!strcmp(name, "{0}"))\n'.format(vk_func.name[2:]))
3139                 f.write('        return vulkan_funcs->p_{0};\n'.format(vk_func.name))
3140         f.write("\n")
3141         f.write("    if (!instance) return NULL;\n\n")
3142         for vk_func in self.registry.funcs.values():
3143             if vk_func.is_driver_func() and (vk_func.is_instance_func() or vk_func.is_phys_dev_func()):
3144                 f.write('    if (!strcmp(name, "{0}"))\n'.format(vk_func.name[2:]))
3145                 f.write('        return vulkan_funcs->p_{0};\n'.format(vk_func.name))
3146         f.write("\n")
3147         f.write("    name -= 2;\n\n")
3148         f.write("    return get_vulkan_driver_device_proc_addr(vulkan_funcs, name);\n}\n\n")
3150         f.write("#endif /* __WINE_VULKAN_DRIVER_H */\n")
3152     def generate_vulkan_spec(self, f):
3153         self._generate_copyright(f, spec_file=True)
3154         f.write("@ stdcall -private vk_icdGetInstanceProcAddr(ptr str)\n")
3155         f.write("@ stdcall -private vk_icdGetPhysicalDeviceProcAddr(ptr str)\n")
3156         f.write("@ stdcall -private vk_icdNegotiateLoaderICDInterfaceVersion(ptr)\n")
3158         # Export symbols for all Vulkan Core functions.
3159         for func in self.registry.funcs.values():
3160             if not func.is_core_func():
3161                 continue
3163             # We support all Core functions except for VK_KHR_display* APIs.
3164             # Create stubs for unsupported Core functions.
3165             if func.is_required():
3166                 f.write(func.spec())
3167             else:
3168                 f.write("@ stub {0}\n".format(func.name))
3170         f.write("@ stdcall -private DllRegisterServer()\n")
3171         f.write("@ stdcall -private DllUnregisterServer()\n")
3173     def generate_vulkan_loader_spec(self, f):
3174         self._generate_copyright(f, spec_file=True)
3176         # Export symbols for all Vulkan Core functions.
3177         for func in self.registry.funcs.values():
3178             if not func.is_core_func():
3179                 continue
3181             # We support all Core functions except for VK_KHR_display* APIs.
3182             # Create stubs for unsupported Core functions.
3183             if func.is_required():
3184                 f.write(func.spec(symbol="winevulkan." + func.name))
3185             else:
3186                 f.write("@ stub {0}\n".format(func.name))
3189 class VkRegistry(object):
3190     def __init__(self, reg_filename):
3191         # Used for storage of type information.
3192         self.base_types = None
3193         self.bitmasks = None
3194         self.consts = None
3195         self.defines = None
3196         self.enums = None
3197         self.funcpointers = None
3198         self.handles = None
3199         self.structs = None
3201         # We aggregate all types in here for cross-referencing.
3202         self.funcs = {}
3203         self.types = {}
3205         self.version_regex = re.compile(
3206             r'^'
3207             r'VK_VERSION_'
3208             r'(?P<major>[0-9])'
3209             r'_'
3210             r'(?P<minor>[0-9])'
3211             r'$'
3212         )
3214         # Overall strategy for parsing the registry is to first
3215         # parse all type / function definitions. Then parse
3216         # features and extensions to decide which types / functions
3217         # to actually 'pull in' for code generation. For each type or
3218         # function call we want we set a member 'required' to True.
3219         tree = ET.parse(reg_filename)
3220         root = tree.getroot()
3221         self._parse_enums(root)
3222         self._parse_types(root)
3223         self._parse_commands(root)
3225         # Pull in any required types and functions.
3226         self._parse_features(root)
3227         self._parse_extensions(root)
3229         self._match_object_types()
3231         self.copyright = root.find('./comment').text
3233     def _is_feature_supported(self, feature):
3234         version = self.version_regex.match(feature)
3235         if not version:
3236             return True
3238         version = tuple(map(int, version.group('major', 'minor')))
3239         return version <= WINE_VK_VERSION
3241     def _is_extension_supported(self, extension):
3242         # We disable some extensions as either we haven't implemented
3243         # support yet or because they are for platforms other than win32.
3244         return extension not in UNSUPPORTED_EXTENSIONS
3246     def _mark_command_required(self, command):
3247         """ Helper function to mark a certain command and the datatypes it needs as required."""
3248         def mark_bitmask_dependencies(bitmask, types):
3249             if bitmask.requires is not None:
3250                 types[bitmask.requires]["data"].required = True
3252         def mark_funcpointer_dependencies(fp, types):
3253             for m in fp.members:
3254                 type_info = types[m.type]
3256                 # Complex types have a matching definition e.g. VkStruct.
3257                 # Not needed for base types such as uint32_t.
3258                 if "data" in type_info:
3259                     types[m.type]["data"].required = True
3261         def mark_struct_dependencies(struct, types):
3262              for m in struct:
3263                 type_info = types[m.type]
3265                 # Complex types have a matching definition e.g. VkStruct.
3266                 # Not needed for base types such as uint32_t.
3267                 if "data" in type_info:
3268                     types[m.type]["data"].required = True
3270                 if type_info["category"] == "struct":
3271                     # Yay, recurse
3272                     mark_struct_dependencies(type_info["data"], types)
3273                 elif type_info["category"] == "funcpointer":
3274                     mark_funcpointer_dependencies(type_info["data"], types)
3275                 elif type_info["category"] == "bitmask":
3276                     mark_bitmask_dependencies(type_info["data"], types)
3278         func = self.funcs[command]
3279         func.required = True
3281         # Pull in return type
3282         if func.type != "void":
3283             self.types[func.type]["data"].required = True
3285         # Analyze parameter dependencies and pull in any type needed.
3286         for p in func.params:
3287             type_info = self.types[p.type]
3289             # Check if we are dealing with a complex type e.g. VkEnum, VkStruct and others.
3290             if "data" not in type_info:
3291                 continue
3293             # Mark the complex type as required.
3294             type_info["data"].required = True
3295             if type_info["category"] == "struct":
3296                 struct = type_info["data"]
3297                 mark_struct_dependencies(struct, self.types)
3298             elif type_info["category"] == "bitmask":
3299                 mark_bitmask_dependencies(type_info["data"], self.types)
3301     def _match_object_types(self):
3302         """ Matches each handle with the correct object type. """
3303         # Use upper case comparison for simplicity.
3304         object_types = {}
3305         for value in self.enums["VkObjectType"].values:
3306             object_name = "VK" + value.name[len("VK_OBJECT_TYPE"):].replace("_", "")
3307             object_types[object_name] = value.name
3309         for handle in self.handles:
3310             if not handle.is_required():
3311                 continue
3312             handle.object_type = object_types.get(handle.name.upper())
3313             if not handle.object_type:
3314                 LOGGER.warning("No object type found for {}".format(handle.name))
3316     def _parse_commands(self, root):
3317         """ Parse command section containing the Vulkan function calls. """
3318         funcs = {}
3319         commands = root.findall("./commands/")
3321         # As of Vulkan 1.1, various extensions got promoted to Core.
3322         # The old commands (e.g. KHR) are available for backwards compatibility
3323         # and are marked in vk.xml as 'alias' to the non-extension type.
3324         # The registry likes to avoid data duplication, so parameters and other
3325         # metadata need to be looked up from the Core command.
3326         # We parse the alias commands in a second pass.
3327         alias_commands = []
3328         for command in commands:
3329             alias_name = command.attrib.get("alias")
3330             if alias_name:
3331                 alias_commands.append(command)
3332                 continue
3334             func = VkFunction.from_xml(command, self.types)
3335             funcs[func.name] = func
3337         for command in alias_commands:
3338             alias_name = command.attrib.get("alias")
3339             alias = funcs[alias_name]
3340             func = VkFunction.from_alias(command, alias)
3341             funcs[func.name] = func
3343         # To make life easy for the code generation, separate all function
3344         # calls out in the 4 types of Vulkan functions:
3345         # device, global, physical device and instance.
3346         device_funcs = []
3347         global_funcs = []
3348         phys_dev_funcs = []
3349         instance_funcs = []
3350         for func in funcs.values():
3351             if func.is_device_func():
3352                 device_funcs.append(func)
3353             elif func.is_global_func():
3354                 global_funcs.append(func)
3355             elif func.is_phys_dev_func():
3356                 phys_dev_funcs.append(func)
3357             else:
3358                 instance_funcs.append(func)
3360         # Sort function lists by name and store them.
3361         self.device_funcs = sorted(device_funcs, key=lambda func: func.name)
3362         self.global_funcs = sorted(global_funcs, key=lambda func: func.name)
3363         self.phys_dev_funcs = sorted(phys_dev_funcs, key=lambda func: func.name)
3364         self.instance_funcs = sorted(instance_funcs, key=lambda func: func.name)
3366         # The funcs dictionary is used as a convenient way to lookup function
3367         # calls when needed e.g. to adjust member variables.
3368         self.funcs = OrderedDict(sorted(funcs.items()))
3370     def _parse_enums(self, root):
3371         """ Parse enums section or better described as constants section. """
3372         enums = {}
3373         self.consts = []
3374         for enum in root.findall("./enums"):
3375             name = enum.attrib.get("name")
3376             _type = enum.attrib.get("type")
3378             if _type in ("enum", "bitmask"):
3379                 enums[name] = VkEnum.from_xml(enum)
3380             else:
3381                 # If no type is set, we are dealing with API constants.
3382                 for value in enum.findall("enum"):
3383                     # If enum is an alias, set the value to the alias name.
3384                     # E.g. VK_LUID_SIZE_KHR is an alias to VK_LUID_SIZE.
3385                     alias = value.attrib.get("alias")
3386                     if alias:
3387                         self.consts.append(VkConstant(value.attrib.get("name"), alias))
3388                     else:
3389                         self.consts.append(VkConstant(value.attrib.get("name"), value.attrib.get("value")))
3391         self.enums = OrderedDict(sorted(enums.items()))
3393     def _process_require_enum(self, enum_elem, ext=None, only_aliased=False):
3394         if "extends" in enum_elem.keys():
3395             enum = self.types[enum_elem.attrib["extends"]]["data"]
3397             # Need to define VkEnumValues which were aliased to by another value. This is necessary
3398             # from VK spec version 1.2.135 where the provisional VK_KHR_ray_tracing extension was
3399             # added which altered VK_NV_ray_tracing's VkEnumValues to alias to the provisional
3400             # extension.
3401             aliased = False
3402             for _, t in self.types.items():
3403                 if t["category"] != "enum":
3404                     continue
3405                 if not t["data"]:
3406                     continue
3407                 for value in t["data"].values:
3408                     if value.alias == enum_elem.attrib["name"]:
3409                         aliased = True
3411             if only_aliased and not aliased:
3412                 return
3414             if "bitpos" in enum_elem.keys():
3415                 # We need to add an extra value to an existing enum type.
3416                 # E.g. VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG to VkFormatFeatureFlagBits.
3417                 enum.create_bitpos(enum_elem.attrib["name"], int(enum_elem.attrib["bitpos"]))
3419             elif "offset" in enum_elem.keys():
3420                 # Extensions promoted to Core, have the extension number as part
3421                 # of the enum value. Else retrieve from the extension tag.
3422                 if enum_elem.attrib.get("extnumber"):
3423                     ext_number = int(enum_elem.attrib.get("extnumber"))
3424                 else:
3425                     ext_number = int(ext.attrib["number"])
3426                 offset = int(enum_elem.attrib["offset"])
3427                 value = EXT_BASE + (ext_number - 1) * EXT_BLOCK_SIZE + offset
3429                 # Deal with negative values.
3430                 direction = enum_elem.attrib.get("dir")
3431                 if direction is not None:
3432                     value = -value
3434                 enum.create_value(enum_elem.attrib["name"], str(value))
3436             elif "value" in enum_elem.keys():
3437                 enum.create_value(enum_elem.attrib["name"], enum_elem.attrib["value"])
3438             elif "alias" in enum_elem.keys():
3439                 enum.create_alias(enum_elem.attrib["name"], enum_elem.attrib["alias"])
3441         elif "value" in enum_elem.keys():
3442             # Constants are not aliased, no need to add them here, they'll get added later on.
3443             if only_aliased:
3444                 return
3446             self.consts.append(VkConstant(enum_elem.attrib["name"], enum_elem.attrib["value"]))
3448     @staticmethod
3449     def _require_type(type_info):
3450         if type_info.is_alias():
3451             type_info = type_info.alias
3452         type_info.required = True
3453         if type(type_info) == VkStruct:
3454             for member in type_info.members:
3455                 if "data" in member.type_info:
3456                   VkRegistry._require_type(member.type_info["data"])
3458     def _parse_extensions(self, root):
3459         """ Parse extensions section and pull in any types and commands for this extension. """
3460         extensions = []
3461         exts = root.findall("./extensions/extension")
3462         deferred_exts = []
3463         skipped_exts = UNSUPPORTED_EXTENSIONS.copy()
3465         def process_ext(ext, deferred=False):
3466             ext_name = ext.attrib["name"]
3468             # Set extension name on any functions calls part of this extension as we
3469             # were not aware of the name during initial parsing.
3470             commands = ext.findall("require/command")
3471             for command in commands:
3472                 cmd_name = command.attrib["name"]
3473                 # Need to verify that the command is defined, and otherwise skip it.
3474                 # vkCreateScreenSurfaceQNX is declared in <extensions> but not defined in
3475                 # <commands>. A command without a definition cannot be enabled, so it's valid for
3476                 # the XML file to handle this, but because of the manner in which we parse the XML
3477                 # file we pre-populate from <commands> before we check if a command is enabled.
3478                 if cmd_name in self.funcs:
3479                     self.funcs[cmd_name].extensions.add(ext_name)
3481             # Some extensions are not ready or have numbers reserved as a place holder.
3482             if ext.attrib["supported"] == "disabled":
3483                 LOGGER.debug("Skipping disabled extension: {0}".format(ext_name))
3484                 skipped_exts.append(ext_name)
3485                 return
3487             # Defer extensions with 'sortorder' as they are order-dependent for spec-parsing.
3488             if not deferred and "sortorder" in ext.attrib:
3489                 deferred_exts.append(ext)
3490                 return
3492             # Disable highly experimental extensions as the APIs are unstable and can
3493             # change between minor Vulkan revisions until API is final and becomes KHR
3494             # or NV.
3495             if ("KHX" in ext_name or "NVX" in ext_name) and ext_name not in ALLOWED_X_EXTENSIONS:
3496                 LOGGER.debug("Skipping experimental extension: {0}".format(ext_name))
3497                 skipped_exts.append(ext_name)
3498                 return
3500             # Extensions can define VkEnumValues which alias to provisional extensions. Pre-process
3501             # extensions to define any required VkEnumValues before the platform check below.
3502             for require in ext.findall("require"):
3503                 # Extensions can add enum values to Core / extension enums, so add these.
3504                 for enum_elem in require.findall("enum"):
3505                     self._process_require_enum(enum_elem, ext, only_aliased=True)
3507             platform = ext.attrib.get("platform")
3508             if platform and platform != "win32":
3509                 LOGGER.debug("Skipping extensions {0} for platform {1}".format(ext_name, platform))
3510                 skipped_exts.append(ext_name)
3511                 return
3513             if not self._is_extension_supported(ext_name):
3514                 LOGGER.debug("Skipping unsupported extension: {0}".format(ext_name))
3515                 skipped_exts.append(ext_name)
3516                 return
3517             elif "requires" in ext.attrib:
3518                 # Check if this extension builds on top of another unsupported extension.
3519                 requires = ext.attrib["requires"].split(",")
3520                 if len(set(requires).intersection(skipped_exts)) > 0:
3521                     skipped_exts.append(ext_name)
3522                     return
3524             LOGGER.debug("Loading extension: {0}".format(ext_name))
3526             # Extensions can define one or more require sections each requiring
3527             # different features (e.g. Vulkan 1.1). Parse each require section
3528             # separately, so we can skip sections we don't want.
3529             for require in ext.findall("require"):
3530                 # Extensions can add enum values to Core / extension enums, so add these.
3531                 for enum_elem in require.findall("enum"):
3532                     self._process_require_enum(enum_elem, ext)
3534                 for t in require.findall("type"):
3535                     type_info = self.types[t.attrib["name"]]["data"]
3536                     self._require_type(type_info)
3537                 feature = require.attrib.get("feature")
3538                 if feature and not self._is_feature_supported(feature):
3539                     continue
3541                 required_extension = require.attrib.get("extension")
3542                 if required_extension and not self._is_extension_supported(required_extension):
3543                     continue
3545                 # Pull in any commands we need. We infer types to pull in from the command
3546                 # as well.
3547                 for command in require.findall("command"):
3548                     cmd_name = command.attrib["name"]
3549                     self._mark_command_required(cmd_name)
3552             # Store a list with extensions.
3553             ext_info = {"name" : ext_name, "type" : ext.attrib["type"]}
3554             extensions.append(ext_info)
3557         # Process extensions, allowing for sortorder to defer extension processing
3558         for ext in exts:
3559             process_ext(ext)
3561         deferred_exts.sort(key=lambda ext: ext.attrib["sortorder"])
3563         # Respect sortorder
3564         for ext in deferred_exts:
3565             process_ext(ext, deferred=True)
3567         # Sort in alphabetical order.
3568         self.extensions = sorted(extensions, key=lambda ext: ext["name"])
3570     def _parse_features(self, root):
3571         """ Parse the feature section, which describes Core commands and types needed. """
3573         for feature in root.findall("./feature"):
3574             feature_name = feature.attrib["name"]
3575             for require in feature.findall("require"):
3576                 LOGGER.info("Including features for {0}".format(require.attrib.get("comment")))
3577                 for tag in require:
3578                     if tag.tag == "comment":
3579                         continue
3580                     elif tag.tag == "command":
3581                         if not self._is_feature_supported(feature_name):
3582                             continue
3583                         name = tag.attrib["name"]
3584                         self._mark_command_required(name)
3585                     elif tag.tag == "enum":
3586                         self._process_require_enum(tag)
3587                     elif tag.tag == "type":
3588                         name = tag.attrib["name"]
3590                         # Skip pull in for vk_platform.h for now.
3591                         if name == "vk_platform":
3592                             continue
3594                         type_info = self.types[name]
3595                         type_info["data"].required = True
3597     def _parse_types(self, root):
3598         """ Parse types section, which contains all data types e.g. structs, typedefs etcetera. """
3599         types = root.findall("./types/type")
3601         base_types = []
3602         bitmasks = []
3603         defines = []
3604         funcpointers = []
3605         handles = []
3606         structs = []
3608         alias_types = []
3609         for t in types:
3610             type_info = {}
3611             type_info["category"] = t.attrib.get("category", None)
3612             type_info["requires"] = t.attrib.get("requires", None)
3614             # We parse aliases in a second pass when we know more.
3615             alias = t.attrib.get("alias")
3616             if alias:
3617                 LOGGER.debug("Alias found: {0}".format(alias))
3618                 alias_types.append(t)
3619                 continue
3621             if type_info["category"] in ["include"]:
3622                 continue
3624             if type_info["category"] == "basetype":
3625                 name = t.find("name").text
3626                 _type = None
3627                 if not t.find("type") is None:
3628                     _type = t.find("type").text
3629                     tail = t.find("type").tail
3630                     if tail is not None:
3631                         _type += tail.strip()
3632                 basetype = VkBaseType(name, _type)
3633                 base_types.append(basetype)
3634                 type_info["data"] = basetype
3636             # Basic C types don't need us to define them, but we do need data for them
3637             if type_info["requires"] == "vk_platform":
3638                 requires = type_info["requires"]
3639                 basic_c = VkBaseType(name, _type, requires=requires)
3640                 type_info["data"] = basic_c
3642             if type_info["category"] == "bitmask":
3643                 name = t.find("name").text
3644                 _type = t.find("type").text
3646                 # Most bitmasks have a requires attribute used to pull in
3647                 # required '*FlagBits" enum.
3648                 requires = type_info["requires"]
3649                 bitmask = VkBaseType(name, _type, requires=requires)
3650                 bitmasks.append(bitmask)
3651                 type_info["data"] = bitmask
3653             if type_info["category"] == "define":
3654                 define = VkDefine.from_xml(t)
3655                 defines.append(define)
3656                 type_info["data"] = define
3658             if type_info["category"] == "enum":
3659                 name = t.attrib.get("name")
3660                 # The type section only contains enum names, not the actual definition.
3661                 # Since we already parsed the enum before, just link it in.
3662                 try:
3663                     type_info["data"] = self.enums[name]
3664                 except KeyError as e:
3665                     # Not all enums seem to be defined yet, typically that's for
3666                     # ones ending in 'FlagBits' where future extensions may add
3667                     # definitions.
3668                     type_info["data"] = None
3670             if type_info["category"] == "funcpointer":
3671                 funcpointer = VkFunctionPointer.from_xml(t)
3672                 funcpointers.append(funcpointer)
3673                 type_info["data"] = funcpointer
3675             if type_info["category"] == "handle":
3676                 handle = VkHandle.from_xml(t)
3677                 handles.append(handle)
3678                 type_info["data"] = handle
3680             if type_info["category"] in ["struct", "union"]:
3681                 # We store unions among structs as some structs depend
3682                 # on unions. The types are very similar in parsing and
3683                 # generation anyway. The official Vulkan scripts use
3684                 # a similar kind of hack.
3685                 struct = VkStruct.from_xml(t)
3686                 structs.append(struct)
3687                 type_info["data"] = struct
3689             # Name is in general within a name tag else it is an optional
3690             # attribute on the type tag.
3691             name_elem = t.find("name")
3692             if name_elem is not None:
3693                 type_info["name"] = name_elem.text
3694             else:
3695                 type_info["name"] = t.attrib.get("name", None)
3697             # Store all type data in a shared dictionary, so we can easily
3698             # look up information for a given type. There are no duplicate
3699             # names.
3700             self.types[type_info["name"]] = type_info
3702         # Second pass for alias types, so we can retrieve all data from
3703         # the aliased object.
3704         for t in alias_types:
3705             type_info = {}
3706             type_info["category"] = t.attrib.get("category")
3707             type_info["name"] = t.attrib.get("name")
3709             alias = t.attrib.get("alias")
3711             if type_info["category"] == "bitmask":
3712                 bitmask = VkBaseType(type_info["name"], alias, alias=self.types[alias]["data"])
3713                 bitmasks.append(bitmask)
3714                 type_info["data"] = bitmask
3716             if type_info["category"] == "enum":
3717                 enum = VkEnum.from_alias(t, self.types[alias]["data"])
3718                 type_info["data"] = enum
3719                 self.enums[enum.name] = enum
3721             if type_info["category"] == "handle":
3722                 handle = VkHandle.from_alias(t, self.types[alias]["data"])
3723                 handles.append(handle)
3724                 type_info["data"] = handle
3726             if type_info["category"] == "struct":
3727                 struct = VkStruct.from_alias(t, self.types[alias]["data"])
3728                 structs.append(struct)
3729                 type_info["data"] = struct
3731             self.types[type_info["name"]] = type_info
3733         # We need detailed type information during code generation
3734         # on structs for alignment reasons. Unfortunately structs
3735         # are parsed among other types, so there is no guarantee
3736         # that any types needed have been parsed already, so set
3737         # the data now.
3738         for struct in structs:
3739             struct.set_type_info(self.types)
3741             # Alias structures have enum values equivalent to those of the
3742             # structure which they are aliased against. we need to ignore alias
3743             # structs when populating the struct extensions list, otherwise we
3744             # will create duplicate case entries.
3745             if struct.alias:
3746                 continue
3748             for structextend in struct.structextends:
3749                 s = self.types[structextend]["data"]
3750                 s.struct_extensions.append(struct)
3752         # Guarantee everything is sorted, so code generation doesn't have
3753         # to deal with this.
3754         self.base_types = sorted(base_types, key=lambda base_type: base_type.name)
3755         self.bitmasks = sorted(bitmasks, key=lambda bitmask: bitmask.name)
3756         self.defines = defines
3757         self.enums = OrderedDict(sorted(self.enums.items()))
3758         self.funcpointers = sorted(funcpointers, key=lambda fp: fp.name)
3759         self.handles = sorted(handles, key=lambda handle: handle.name)
3760         self.structs = sorted(structs, key=lambda struct: struct.name)
3762 def generate_vulkan_json(f):
3763     f.write("{\n")
3764     f.write("    \"file_format_version\": \"1.0.0\",\n")
3765     f.write("    \"ICD\": {\n")
3766     f.write("        \"library_path\": \".\\\\winevulkan.dll\",\n")
3767     f.write("        \"api_version\": \"{0}\"\n".format(VK_XML_VERSION))
3768     f.write("    }\n")
3769     f.write("}\n")
3771 def set_working_directory():
3772     path = os.path.abspath(__file__)
3773     path = os.path.dirname(path)
3774     os.chdir(path)
3776 def download_vk_xml(filename):
3777     url = "https://raw.githubusercontent.com/KhronosGroup/Vulkan-Docs/v{0}/xml/vk.xml".format(VK_XML_VERSION)
3778     if not os.path.isfile(filename):
3779         urllib.request.urlretrieve(url, filename)
3781 def main():
3782     parser = argparse.ArgumentParser()
3783     parser.add_argument("-v", "--verbose", action="count", default=0, help="increase output verbosity")
3784     parser.add_argument("-x", "--xml", default=None, type=str, help="path to specification XML file")
3786     args = parser.parse_args()
3787     if args.verbose == 0:
3788         LOGGER.setLevel(logging.WARNING)
3789     elif args.verbose == 1:
3790         LOGGER.setLevel(logging.INFO)
3791     else: # > 1
3792         LOGGER.setLevel(logging.DEBUG)
3794     set_working_directory()
3796     if args.xml:
3797         vk_xml = args.xml
3798     else:
3799         vk_xml = "vk-{0}.xml".format(VK_XML_VERSION)
3800         download_vk_xml(vk_xml)
3802     registry = VkRegistry(vk_xml)
3803     generator = VkGenerator(registry)
3805     with open(WINE_VULKAN_H, "w") as f:
3806         generator.generate_vulkan_h(f)
3808     with open(WINE_VULKAN_DRIVER_H, "w") as f:
3809         generator.generate_vulkan_driver_h(f)
3811     with open(WINE_VULKAN_THUNKS_H, "w") as f:
3812         generator.generate_thunks_h(f, "wine_")
3814     with open(WINE_VULKAN_THUNKS_C, "w") as f:
3815         generator.generate_thunks_c(f, "wine_")
3817     with open(WINE_VULKAN_LOADER_THUNKS_H, "w") as f:
3818         generator.generate_loader_thunks_h(f)
3820     with open(WINE_VULKAN_LOADER_THUNKS_C, "w") as f:
3821         generator.generate_loader_thunks_c(f)
3823     with open(WINE_VULKAN_JSON, "w") as f:
3824         generate_vulkan_json(f)
3826     with open(WINE_VULKAN_SPEC, "w") as f:
3827         generator.generate_vulkan_spec(f)
3829     with open(WINE_VULKAN_LOADER_SPEC, "w") as f:
3830         generator.generate_vulkan_loader_spec(f)
3832 if __name__ == "__main__":
3833     main()