winevulkan: Use automatically-generated thunk for vkQueueSubmit.
[wine.git] / dlls / winevulkan / make_vulkan
blobcc79b0a58cde5f52d42f4b7889eb95a5139d4469
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.178"
68 WINE_VK_VERSION = (1, 2)
70 # Filenames to create.
71 WINE_VULKAN_H = "../../include/wine/vulkan.h"
72 WINE_VULKAN_DRIVER_H = "../../include/wine/vulkan_driver.h"
73 WINE_VULKAN_LOADER_SPEC = "../vulkan-1/vulkan-1.spec"
74 WINE_VULKAN_JSON = "winevulkan.json"
75 WINE_VULKAN_SPEC = "winevulkan.spec"
76 WINE_VULKAN_THUNKS_C = "vulkan_thunks.c"
77 WINE_VULKAN_THUNKS_H = "vulkan_thunks.h"
78 WINE_VULKAN_LOADER_THUNKS_C = "loader_thunks.c"
79 WINE_VULKAN_LOADER_THUNKS_H = "loader_thunks.h"
81 # Extension enum values start at a certain offset (EXT_BASE).
82 # Relative to the offset each extension has a block (EXT_BLOCK_SIZE)
83 # of values.
84 # Start for a given extension is:
85 # EXT_BASE + (extension_number-1) * EXT_BLOCK_SIZE
86 EXT_BASE = 1000000000
87 EXT_BLOCK_SIZE = 1000
89 UNSUPPORTED_EXTENSIONS = [
90     # Instance extensions
91     "VK_EXT_headless_surface", # Needs WSI work.
92     "VK_KHR_display", # Needs WSI work.
93     "VK_KHR_surface_protected_capabilities",
95     # Device extensions
96     "VK_AMD_display_native_hdr",
97     "VK_EXT_full_screen_exclusive",
98     "VK_EXT_hdr_metadata", # Needs WSI work.
99     "VK_EXT_pipeline_creation_feedback",
100     "VK_GOOGLE_display_timing",
101     "VK_KHR_external_fence_win32",
102     "VK_KHR_external_memory_win32",
103     "VK_KHR_external_semaphore_win32",
104     # Relates to external_semaphore and needs type conversions in bitflags.
105     "VK_KHR_shared_presentable_image", # Needs WSI work.
106     "VK_KHR_win32_keyed_mutex",
108     # Extensions for other platforms
109     "VK_EXT_external_memory_dma_buf",
110     "VK_EXT_image_drm_format_modifier",
111     "VK_KHR_external_fence_fd",
112     "VK_KHR_external_memory_fd",
113     "VK_KHR_external_semaphore_fd",
115     # Extensions which require callback handling
116     "VK_EXT_device_memory_report",
118     # Deprecated extensions
119     "VK_NV_external_memory_capabilities",
120     "VK_NV_external_memory_win32",
123 # The Vulkan loader provides entry-points for core functionality and important
124 # extensions. Based on vulkan-1.def this amounts to WSI extensions on 1.0.51.
125 CORE_EXTENSIONS = [
126     "VK_KHR_display",
127     "VK_KHR_display_swapchain",
128     "VK_KHR_get_surface_capabilities2",
129     "VK_KHR_surface",
130     "VK_KHR_swapchain",
131     "VK_KHR_win32_surface",
134 # Some experimental extensions are used by shipping applications so their API is extremely unlikely
135 # to change in a backwards-incompatible way. Allow translation of those extensions with WineVulkan.
136 ALLOWED_X_EXTENSIONS = [
137     "VK_NVX_binary_import",
138     "VK_NVX_image_view_handle",
141 # Functions part of our winevulkan graphics driver interface.
142 # DRIVER_VERSION should be bumped on any change to driver interface
143 # in FUNCTION_OVERRIDES
144 DRIVER_VERSION = 10
146 class ThunkType(Enum):
147     NONE = 1
148     PUBLIC = 2
149     PRIVATE = 3
151 # Table of functions for which we have a special implementation.
152 # These are regular device / instance functions for which we need
153 # to do more work compared to a regular thunk or because they are
154 # part of the driver interface.
155 # - dispatch set whether we need a function pointer in the device
156 #   / instance dispatch table.
157 # - driver sets whether the API is part of the driver interface.
158 # - thunk sets whether to create a thunk in vulkan_thunks.c.
159 #   - NONE means there's a fully custom implementation.
160 #   - PUBLIC means the implementation is fully auto generated.
161 #   - PRIVATE thunks can be used in custom implementations for
162 #     struct conversion.
163 # - loader_thunk sets whether to create a thunk for unix_funcs.
164 FUNCTION_OVERRIDES = {
165     # Global functions
166     "vkCreateInstance" : {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE},
167     "vkEnumerateInstanceExtensionProperties" : {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE},
168     "vkEnumerateInstanceLayerProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.NONE},
169     "vkEnumerateInstanceVersion": {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE},
170     "vkGetInstanceProcAddr": {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.NONE},
172     # Instance functions
173     "vkCreateDevice" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
174     "vkDestroyInstance" : {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE },
175     "vkEnumerateDeviceExtensionProperties" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
176     "vkEnumerateDeviceLayerProperties": {"dispatch": True, "driver": False, "thunk": ThunkType.NONE},
177     "vkEnumeratePhysicalDeviceGroups" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
178     "vkEnumeratePhysicalDevices" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
179     "vkGetPhysicalDeviceExternalBufferProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
180     "vkGetPhysicalDeviceExternalFenceProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
181     "vkGetPhysicalDeviceExternalSemaphoreProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
182     "vkGetPhysicalDeviceImageFormatProperties2" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE},
183     "vkGetPhysicalDeviceProperties2" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PUBLIC, "loader_thunk" : ThunkType.PRIVATE},
184     "vkGetPhysicalDeviceProperties2KHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PUBLIC, "loader_thunk" : ThunkType.PRIVATE},
186     # Device functions
187     "vkAllocateCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
188     "vkCreateCommandPool" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
189     "vkDestroyCommandPool" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
190     "vkDestroyDevice" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
191     "vkFreeCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
192     "vkGetDeviceProcAddr" : {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.NONE},
193     "vkGetDeviceQueue" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
194     "vkGetDeviceQueue2" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
196     # VK_KHR_surface
197     "vkDestroySurfaceKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.NONE},
198     "vkGetPhysicalDeviceSurfaceSupportKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
199     "vkGetPhysicalDeviceSurfaceCapabilitiesKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PRIVATE},
200     "vkGetPhysicalDeviceSurfaceFormatsKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
201     "vkGetPhysicalDeviceSurfacePresentModesKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
203     # VK_KHR_get_surface_capabilities2
204     "vkGetPhysicalDeviceSurfaceCapabilities2KHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PRIVATE},
205     "vkGetPhysicalDeviceSurfaceFormats2KHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
207     # VK_KHR_win32_surface
208     "vkCreateWin32SurfaceKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.NONE},
209     "vkGetPhysicalDeviceWin32PresentationSupportKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
211     # VK_KHR_swapchain
212     "vkCreateSwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
213     "vkDestroySwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
214     "vkGetSwapchainImagesKHR": {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
215     "vkQueuePresentKHR": {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
217     # VK_KHR_external_fence_capabilities
218     "vkGetPhysicalDeviceExternalFencePropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
220     # VK_KHR_external_memory_capabilities
221     "vkGetPhysicalDeviceExternalBufferPropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
222     "vkGetPhysicalDeviceImageFormatProperties2KHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE},
224     # VK_KHR_external_semaphore_capabilities
225     "vkGetPhysicalDeviceExternalSemaphorePropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
227     # VK_KHR_device_group_creation
228     "vkEnumeratePhysicalDeviceGroupsKHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
230     # VK_KHR_device_group
231     "vkGetDeviceGroupSurfacePresentModesKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
232     "vkGetPhysicalDevicePresentRectanglesKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
234     # VK_EXT_private_data
235     "vkGetPrivateDataEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
236     "vkSetPrivateDataEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
238     # VK_EXT_calibrated_timestamps
239     "vkGetPhysicalDeviceCalibrateableTimeDomainsEXT" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
240     "vkGetCalibratedTimestampsEXT" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
242     # VK_EXT_debug_utils
243     "vkCreateDebugUtilsMessengerEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
244     "vkDestroyDebugUtilsMessengerEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
245     "vkSubmitDebugUtilsMessageEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.PRIVATE},
246     "vkSetDebugUtilsObjectTagEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.PRIVATE},
247     "vkSetDebugUtilsObjectNameEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.PRIVATE},
249     # VK_EXT_debug_report
250     "vkCreateDebugReportCallbackEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
251     "vkDestroyDebugReportCallbackEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
252     "vkDebugReportMessageEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
254     # VK_EXT_debug_marker
255     "vkDebugMarkerSetObjectNameEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.PRIVATE},
256     "vkDebugMarkerSetObjectTagEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.PRIVATE},
259 STRUCT_CHAIN_CONVERSIONS = [
260     "VkDeviceCreateInfo",
261     "VkInstanceCreateInfo",
265 class Direction(Enum):
266     """ Parameter direction: input, output, input_output. """
267     INPUT = 1
268     OUTPUT = 2
269     INPUT_OUTPUT = 3
272 class VkBaseType(object):
273     def __init__(self, name, _type, alias=None, requires=None):
274         """ Vulkan base type class.
276         VkBaseType is mostly used by Vulkan to define its own
277         base types like VkFlags through typedef out of e.g. uint32_t.
279         Args:
280             name (:obj:'str'): Name of the base type.
281             _type (:obj:'str'): Underlying type
282             alias (bool): type is an alias or not.
283             requires (:obj:'str', optional): Other types required.
284                 Often bitmask values pull in a *FlagBits type.
285         """
286         self.name = name
287         self.type = _type
288         self.alias = alias
289         self.requires = requires
290         self.required = False
292     def definition(self):
293         # Definition is similar for alias or non-alias as type
294         # is already set to alias.
295         if not self.type is None:
296             return "typedef {0} {1};\n".format(self.type, self.name)
297         else:
298             return "struct {0};\n".format(self.name)
300     def is_alias(self):
301         return bool(self.alias)
304 class VkConstant(object):
305     def __init__(self, name, value):
306         self.name = name
307         self.value = value
309     def definition(self):
310         text = "#define {0} {1}\n".format(self.name, self.value)
311         return text
314 class VkDefine(object):
315     def __init__(self, name, value):
316         self.name = name
317         self.value = value
319     @staticmethod
320     def from_xml(define):
321         name_elem = define.find("name")
323         if name_elem is None:
324             # <type category="define" name="some_name">some_value</type>
325             name = define.attrib.get("name")
327             # We override behavior of VK_USE_64_BIT_PTR_DEFINES as the default non-dispatchable handle
328             # definition various between 64-bit (uses pointers) and 32-bit (uses uint64_t).
329             # This complicates TRACEs in the thunks, so just use uint64_t.
330             if name == "VK_USE_64_BIT_PTR_DEFINES":
331                 value = "#define VK_USE_64_BIT_PTR_DEFINES 0"
332             else:
333                 value = define.text
334             return VkDefine(name, value)
336         # With a name element the structure is like:
337         # <type category="define"><name>some_name</name>some_value</type>
338         name = name_elem.text
340         # Perform minimal parsing for Vulkan constants, which we don't need, but are referenced
341         # elsewhere in vk.xml.
342         # - VK_API_VERSION is a messy, deprecated constant and we don't want generate code for it.
343         # - AHardwareBuffer/ANativeWindow are forward declarations for Android types, which leaked
344         #   into the define region.
345         if name in ["VK_API_VERSION", "AHardwareBuffer", "ANativeWindow", "CAMetalLayer"]:
346             return VkDefine(name, None)
348         # The body of the define is basically unstructured C code. It is not meant for easy parsing.
349         # Some lines contain deprecated values or comments, which we try to filter out.
350         value = ""
351         for line in define.text.splitlines():
352             # Skip comments or deprecated values.
353             if "//" in line:
354                 continue
355             value += line
357         for child in define:
358             value += child.text
359             if child.tail is not None:
360                 # Split comments for VK_API_VERSION_1_0 / VK_API_VERSION_1_1
361                 if "//" in child.tail:
362                     value += child.tail.split("//")[0]
363                 else:
364                     value += child.tail
366         return VkDefine(name, value.rstrip(' '))
368     def definition(self):
369         if self.value is None:
370             return ""
372         # Nothing to do as the value was already put in the right form during parsing.
373         return "{0}\n".format(self.value)
376 class VkEnum(object):
377     def __init__(self, name, bitwidth, alias=None):
378         if not bitwidth in [32, 64]:
379             LOGGER.error("unknown bitwidth {0} for {1}".format(bitwidth, name))
380         self.name = name
381         self.bitwidth = bitwidth
382         self.values = [] if alias == None else alias.values
383         self.required = False
384         self.alias = alias
385         self.aliased_by = []
387     @staticmethod
388     def from_alias(enum, alias):
389         name = enum.attrib.get("name")
390         aliasee = VkEnum(name, alias.bitwidth, alias=alias)
392         alias.add_aliased_by(aliasee)
393         return aliasee
395     @staticmethod
396     def from_xml(enum):
397         name = enum.attrib.get("name")
398         bitwidth = int(enum.attrib.get("bitwidth", "32"))
399         result = VkEnum(name, bitwidth)
401         for v in enum.findall("enum"):
402             value_name = v.attrib.get("name")
403             # Value is either a value or a bitpos, only one can exist.
404             value = v.attrib.get("value")
405             alias_name = v.attrib.get("alias")
406             if alias_name:
407                 result.create_alias(value_name, alias_name)
408             elif value:
409                 result.create_value(value_name, value)
410             else:
411                 # bitmask
412                 result.create_bitpos(value_name, int(v.attrib.get("bitpos")))
414         if bitwidth == 32:
415             # vulkan.h contains a *_MAX_ENUM value set to 32-bit at the time of writing,
416             # which is to prepare for extensions as they can add values and hence affect
417             # the size definition.
418             max_name = re.sub(r'([0-9a-z_])([A-Z0-9])',r'\1_\2', name).upper() + "_MAX_ENUM"
419             result.create_value(max_name, "0x7fffffff")
421         return result
423     def create_alias(self, name, alias_name):
424         """ Create an aliased value for this enum """
425         # Older GCC versions need a literal to initialize a static const uint64_t
426         # which is what we use for 64bit bitmasks.
427         if self.bitwidth == 64:
428             alias = next(x for x in self.values if x.name == alias_name)
429             self.add(VkEnumValue(name, self.bitwidth, value=alias.value, hex=alias.hex, alias=alias_name))
430         else:
431             self.add(VkEnumValue(name, self.bitwidth, alias=alias_name))
433     def create_value(self, name, value):
434         """ Create a new value for this enum """
435         # Some values are in hex form. We want to preserve the hex representation
436         # at least when we convert back to a string. Internally we want to use int.
437         hex = "0x" in value
438         self.add(VkEnumValue(name, self.bitwidth, value=int(value, 0), hex=hex))
440     def create_bitpos(self, name, pos):
441         """ Create a new bitmask value for this enum """
442         self.add(VkEnumValue(name, self.bitwidth, value=(1 << pos), hex=True))
444     def add(self, value):
445         """ Add a value to enum. """
447         # Extensions can add new enum values. When an extension is promoted to Core
448         # the registry defines the value twice once for old extension and once for
449         # new Core features. Add the duplicate if it's explicitly marked as an
450         # alias, otherwise ignore it.
451         for v in self.values:
452             if not value.is_alias() and v.value == value.value:
453                 LOGGER.debug("Adding duplicate enum value {0} to {1}".format(v, self.name))
454                 return
455         # Avoid adding duplicate aliases multiple times
456         if not any(x.name == value.name for x in self.values):
457             self.values.append(value)
459     def definition(self):
460         if self.is_alias():
461             return ""
463         default_value = 0x7ffffffe if self.bitwidth == 32 else 0xfffffffffffffffe
465         # Print values sorted, values can have been added in a random order.
466         values = sorted(self.values, key=lambda value: value.value if value.value is not None else default_value)
468         if self.bitwidth == 32:
469             text = "typedef enum {0}\n{{\n".format(self.name)
470             for value in values:
471                 text += "    {0},\n".format(value.definition())
472             text += "}} {0};\n".format(self.name)
473         elif self.bitwidth == 64:
474             text = "typedef VkFlags64 {0};\n\n".format(self.name)
475             for value in values:
476                 text += "static const {0} {1};\n".format(self.name, value.definition())
478         for aliasee in self.aliased_by:
479             text += "typedef {0} {1};\n".format(self.name, aliasee.name)
481         text += "\n"
482         return text
484     def is_alias(self):
485         return bool(self.alias)
487     def add_aliased_by(self, aliasee):
488         self.aliased_by.append(aliasee)
491 class VkEnumValue(object):
492     def __init__(self, name, bitwidth, value=None, hex=False, alias=None):
493         self.name = name
494         self.bitwidth = bitwidth
495         self.value = value
496         self.hex = hex
497         self.alias = alias
499     def __repr__(self):
500         postfix = "ull" if self.bitwidth == 64 else ""
501         if self.is_alias() and self.value == None:
502             return "{0}={1}".format(self.name, self.alias)
503         return "{0}={1}{2}".format(self.name, self.value, postfix)
505     def definition(self):
506         """ Convert to text definition e.g. VK_FOO = 1 """
507         postfix = "ull" if self.bitwidth == 64 else ""
508         if self.is_alias() and self.value == None:
509             return "{0} = {1}".format(self.name, self.alias)
511         # Hex is commonly used for FlagBits and sometimes within
512         # a non-FlagBits enum for a bitmask value as well.
513         if self.hex:
514             return "{0} = 0x{1:08x}{2}".format(self.name, self.value, postfix)
515         else:
516             return "{0} = {1}{2}".format(self.name, self.value, postfix)
518     def is_alias(self):
519         return self.alias is not None
522 class VkFunction(object):
523     def __init__(self, _type=None, name=None, params=[], extensions=[], alias=None):
524         self.extensions = []
525         self.name = name
526         self.type = _type
527         self.params = params
528         self.alias = alias
530         # For some functions we need some extra metadata from FUNCTION_OVERRIDES.
531         func_info = FUNCTION_OVERRIDES.get(self.name, None)
532         self.dispatch = func_info["dispatch"] if func_info else True
533         self.driver = func_info["driver"] if func_info else False
534         self.thunk_type = func_info["thunk"] if func_info else ThunkType.PUBLIC
535         self.loader_thunk_type = func_info["loader_thunk"] if func_info and "loader_thunk" in func_info else ThunkType.PUBLIC
537         # Required is set while parsing which APIs and types are required
538         # and is used by the code generation.
539         self.required = True if func_info else False
541     @staticmethod
542     def from_alias(command, alias):
543         """ Create VkFunction from an alias command.
545         Args:
546             command: xml data for command
547             alias (VkFunction): function to use as a base for types / parameters.
549         Returns:
550             VkFunction
551         """
552         func_name = command.attrib.get("name")
553         func_type = alias.type
554         params = alias.params
556         return VkFunction(_type=func_type, name=func_name, params=params, alias=alias)
558     @staticmethod
559     def from_xml(command, types):
560         proto = command.find("proto")
561         func_name = proto.find("name").text
562         func_type = proto.find("type").text
564         params = []
565         for param in command.findall("param"):
566             vk_param = VkParam.from_xml(param, types)
567             params.append(vk_param)
569         return VkFunction(_type=func_type, name=func_name, params=params)
571     def get_conversions(self):
572         """ Get a list of conversion functions required for this function if any.
573         Parameters which are structures may require conversion between win32
574         and the host platform. This function returns a list of conversions
575         required.
576         """
578         conversions = []
579         for param in self.params:
580             convs = param.get_conversions()
581             if convs is not None:
582                 conversions.extend(convs)
584         return conversions
586     def is_alias(self):
587         return bool(self.alias)
589     def is_core_func(self):
590         """ Returns whether the function is a Vulkan core function.
591         Core functions are APIs defined by the Vulkan spec to be part of the
592         Core API as well as several KHR WSI extensions.
593         """
595         if not self.extensions:
596             return True
598         return any(ext in self.extensions for ext in CORE_EXTENSIONS)
600     def is_device_func(self):
601         # If none of the other, it must be a device function
602         return not self.is_global_func() and not self.is_instance_func() and not self.is_phys_dev_func()
604     def is_driver_func(self):
605         """ Returns if function is part of Wine driver interface. """
606         return self.driver
608     def is_global_func(self):
609         # Treat vkGetInstanceProcAddr as a global function as it
610         # can operate with NULL for vkInstance.
611         if self.name == "vkGetInstanceProcAddr":
612             return True
613         # Global functions are not passed a dispatchable object.
614         elif self.params[0].is_dispatchable():
615             return False
616         return True
618     def is_instance_func(self):
619         # Instance functions are passed VkInstance.
620         if self.params[0].type == "VkInstance":
621             return True
622         return False
624     def is_phys_dev_func(self):
625         # Physical device functions are passed VkPhysicalDevice.
626         if self.params[0].type == "VkPhysicalDevice":
627             return True
628         return False
630     def is_required(self):
631         return self.required
633     def needs_conversion(self):
634         """ Check if the function needs any input/output type conversion.
635         Functions need input/output conversion if struct parameters have
636         alignment differences between Win32 and Linux 32-bit.
637         """
639         for p in self.params:
640             if p.needs_conversion():
641                 LOGGER.debug("Parameter {0} to {1} requires conversion".format(p.name, self.name))
642                 return True
644         return False
646     def needs_unwrapping(self):
647         """ Check if the function needs any input/output type unwrapping.
648         Functions need input/output unwrapping if struct parameters have
649         wrapped handles.
650         """
652         for p in self.params:
653             if p.needs_unwrapping():
654                 return True
656         return False
658     def needs_dispatch(self):
659         return self.dispatch
661     def needs_thunk(self):
662         return self.thunk_type != ThunkType.NONE
664     def needs_private_thunk(self):
665         return self.thunk_type == ThunkType.PRIVATE
667     def pfn(self, prefix="p", call_conv=None, conv=False):
668         """ Create function pointer. """
670         if call_conv:
671             pfn = "{0} ({1} *{2}_{3})(".format(self.type, call_conv, prefix, self.name)
672         else:
673             pfn = "{0} (*{1}_{2})(".format(self.type, prefix, self.name)
675         for i, param in enumerate(self.params):
676             if param.const:
677                 pfn += param.const + " "
679             pfn += param.type
680             if conv and param.needs_conversion():
681                 pfn += "_host"
683             if param.is_pointer():
684                 pfn += " " + param.pointer
686             if param.array_len is not None:
687                 pfn += "[{0}]".format(param.array_len)
689             if i < len(self.params) - 1:
690                 pfn += ", "
691         pfn += ")"
692         return pfn
694     def prototype(self, call_conv=None, prefix=None, postfix=None):
695         """ Generate prototype for given function.
697         Args:
698             call_conv (str, optional): calling convention e.g. WINAPI
699             prefix (str, optional): prefix to append prior to function name e.g. vkFoo -> wine_vkFoo
700             postfix (str, optional): text to append after function name but prior to semicolon e.g. DECLSPEC_HIDDEN
701         """
703         proto = "{0}".format(self.type)
705         if call_conv is not None:
706             proto += " {0}".format(call_conv)
708         if prefix is not None:
709             proto += " {0}{1}(".format(prefix, self.name)
710         else:
711             proto += " {0}(".format(self.name)
713         # Add all the parameters.
714         proto += ", ".join([p.definition() for p in self.params])
716         if postfix is not None:
717             proto += ") {0}".format(postfix)
718         else:
719             proto += ")"
721         return proto
723     def body(self):
724         body = ""
726         if not self.needs_private_thunk():
727             body += "    {0}".format(self.trace())
729         params = ", ".join([p.variable(conv=False) for p in self.params])
731         # Call the native Vulkan function.
732         if self.type == "void":
733             body += "    {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
734         else:
735             body += "    return {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
737         return body
739     def loader_body(self):
740         body = ""
742         params = ", ".join([p.name for p in self.params])
744         # Call the function from unix_funcs.
745         if self.type == "void":
746             body += "    unix_funcs->p_{0}({1});\n".format(self.name, params)
747         else:
748             body += "    return unix_funcs->p_{0}({1});\n".format(self.name, params)
750         return body
752     def body_conversion(self, conv):
753         body = ""
755         # Declare a variable to hold the result for non-void functions.
756         if self.type != "void":
757             body += "    {0} result;\n".format(self.type)
759         # Declare any tmp parameters for conversion.
760         for p in self.params:
761             if p.needs_conversion() and conv:
762                 if p.is_dynamic_array():
763                     body += "    {0}_host *{1}_host;\n".format(p.type, p.name)
764                 else:
765                     body += "    {0}_host {1}_host;\n".format(p.type, p.name)
766             elif p.needs_unwrapping():
767                 if p.is_dynamic_array():
768                     body += "    {0} *{1}_host;\n".format(p.type, p.name)
769                 else:
770                     body += "    {0} {1}_host;\n".format(p.type, p.name)
772         if not self.needs_private_thunk():
773             body += "    {0}\n".format(self.trace())
775         # Call any win_to_host conversion calls.
776         for p in self.params:
777             if p.needs_input_conversion() and (p.needs_unwrapping() or conv):
778                 body += p.copy(Direction.INPUT)
780         # Build list of parameters containing converted and non-converted parameters.
781         # The param itself knows if conversion is needed and applies it when we set conv=True.
782         params = ", ".join([p.variable(conv=conv) for p in self.params])
784         # Call the native Vulkan function.
785         if self.type == "void":
786             body += "    {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
787         else:
788             body += "    result = {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
790         body += "\n"
792         # Call any host_to_win conversion calls.
793         for p in self.params:
794             if not p.needs_output_conversion():
795                 continue
797             body += p.copy(Direction.OUTPUT)
799         # Perform any required cleanups. Most of these are for array functions.
800         for p in self.params:
801             if p.needs_free() and (p.needs_unwrapping() or conv):
802                 body += p.free()
804         # Finally return the result.
805         if self.type != "void":
806             body += "    return result;\n"
808         return body
810     def spec(self, prefix=None, symbol=None):
811         """ Generate spec file entry for this function.
813         Args
814             prefix (str, optional): prefix to prepend to entry point name.
815             symbol (str, optional): allows overriding the name of the function implementing the entry point.
816         """
818         spec = ""
819         params = " ".join([p.spec() for p in self.params])
820         if prefix is not None:
821             spec += "@ stdcall -private {0}{1}({2})".format(prefix, self.name, params)
822         else:
823             spec += "@ stdcall {0}({1})".format(self.name, params)
825         if symbol is not None:
826             spec += " " + symbol
828         spec += "\n"
829         return spec
831     def stub(self, call_conv=None, prefix=None):
832         stub = self.prototype(call_conv=call_conv, prefix=prefix)
833         stub += "\n{\n"
834         stub += "    {0}".format(self.trace(message="stub: ", trace_func="FIXME"))
836         if self.type == "VkResult":
837             stub += "    return VK_ERROR_OUT_OF_HOST_MEMORY;\n"
838         elif self.type == "VkBool32":
839             stub += "    return VK_FALSE;\n"
840         elif self.type == "PFN_vkVoidFunction":
841             stub += "    return NULL;\n"
843         stub += "}\n\n"
844         return stub
846     def thunk(self, call_conv=None, prefix=None):
847         thunk = self.prototype(call_conv=call_conv, prefix=prefix)
848         thunk += "\n{\n"
850         if self.needs_conversion():
851             thunk += "#if defined(USE_STRUCT_CONVERSION)\n"
852             thunk += self.body_conversion(conv=True)
853             thunk += "#else\n"
854             if self.needs_unwrapping():
855                 thunk += self.body_conversion(conv=False)
856             else:
857                 thunk += self.body()
858             thunk += "#endif\n"
859         elif self.needs_unwrapping():
860             thunk += self.body_conversion(conv=False)
861         else:
862             thunk += self.body()
864         thunk += "}\n\n"
865         return thunk
867     def loader_thunk(self, prefix=None):
868         thunk = self.prototype(call_conv="WINAPI", prefix=prefix)
869         thunk += "\n{\n"
870         thunk += self.loader_body()
871         thunk += "}\n\n"
872         return thunk
874     def trace(self, message=None, trace_func=None):
875         """ Create a trace string including all parameters.
877         Args:
878             message (str, optional): text to print at start of trace message e.g. 'stub: '
879             trace_func (str, optional): used to override trace function e.g. FIXME, printf, etcetera.
880         """
881         if trace_func is not None:
882             trace = "{0}(\"".format(trace_func)
883         else:
884             trace = "TRACE(\""
886         if message is not None:
887             trace += message
889         # First loop is for all the format strings.
890         trace += ", ".join([p.format_string() for p in self.params])
891         trace += "\\n\""
893         # Second loop for parameter names and optional conversions.
894         for param in self.params:
895             if param.format_conv is not None:
896                 trace += ", " + param.format_conv.format(param.name)
897             else:
898                 trace += ", {0}".format(param.name)
899         trace += ");\n"
901         return trace
904 class VkFunctionPointer(object):
905     def __init__(self, _type, name, members, forward_decls):
906         self.name = name
907         self.members = members
908         self.type = _type
909         self.required = False
910         self.forward_decls = forward_decls
912     @staticmethod
913     def from_xml(funcpointer):
914         members = []
915         begin = None
917         for t in funcpointer.findall("type"):
918             # General form:
919             # <type>void</type>*       pUserData,
920             # Parsing of the tail (anything past </type>) is tricky since there
921             # can be other data on the next line like: const <type>int</type>..
923             const = True if begin and "const" in begin else False
924             _type = t.text
925             lines = t.tail.split(",\n")
926             if lines[0][0] == "*":
927                 pointer = "*"
928                 name = lines[0][1:].strip()
929             else:
930                 pointer = None
931                 name = lines[0].strip()
933             # Filter out ); if it is contained.
934             name = name.partition(");")[0]
936             # If tail encompasses multiple lines, assign the second line to begin
937             # for the next line.
938             try:
939                 begin = lines[1].strip()
940             except IndexError:
941                 begin = None
943             members.append(VkMember(const=const, _type=_type, pointer=pointer, name=name))
945         _type = funcpointer.text
946         name = funcpointer.find("name").text
947         if "requires" in funcpointer.attrib:
948             forward_decls = funcpointer.attrib.get("requires").split(",")
949         else:
950             forward_decls = []
951         return VkFunctionPointer(_type, name, members, forward_decls)
953     def definition(self):
954         text = ""
955         # forward declare required structs
956         for decl in self.forward_decls:
957             text += "typedef struct {0} {0};\n".format(decl)
959         text += "{0} {1})(\n".format(self.type, self.name)
961         first = True
962         if len(self.members) > 0:
963             for m in self.members:
964                 if first:
965                     text += "    " + m.definition()
966                     first = False
967                 else:
968                     text += ",\n    " + m.definition()
969         else:
970             # Just make the compiler happy by adding a void parameter.
971             text += "void"
972         text += ");\n"
973         return text
975     def is_alias(self):
976         return False
978 class VkHandle(object):
979     def __init__(self, name, _type, parent, alias=None):
980         self.name = name
981         self.type = _type
982         self.parent = parent
983         self.alias = alias
984         self.required = False
985         self.object_type = None
987     @staticmethod
988     def from_alias(handle, alias):
989         name = handle.attrib.get("name")
990         return VkHandle(name, alias.type, alias.parent, alias=alias)
992     @staticmethod
993     def from_xml(handle):
994         name = handle.find("name").text
995         _type = handle.find("type").text
996         parent = handle.attrib.get("parent") # Most objects have a parent e.g. VkQueue has VkDevice.
997         return VkHandle(name, _type, parent)
999     def dispatch_table(self):
1000         if not self.is_dispatchable():
1001             return None
1003         if self.parent is None:
1004             # Should only happen for VkInstance
1005             return "funcs"
1006         elif self.name == "VkDevice":
1007             # VkDevice has VkInstance as a parent, but has its own dispatch table.
1008             return "funcs"
1009         elif self.parent in ["VkInstance", "VkPhysicalDevice"]:
1010             return "instance->funcs"
1011         elif self.parent in ["VkDevice", "VkCommandPool"]:
1012             return "device->funcs"
1013         else:
1014             LOGGER.error("Unhandled dispatchable parent: {0}".format(self.parent))
1016     def definition(self):
1017         """ Generates handle definition e.g. VK_DEFINE_HANDLE(vkInstance) """
1019         # Legacy types are typedef'ed to the new type if they are aliases.
1020         if self.is_alias():
1021             return "typedef {0} {1};\n".format(self.alias.name, self.name)
1023         return "{0}({1})\n".format(self.type, self.name)
1025     def is_alias(self):
1026         return self.alias is not None
1028     def is_dispatchable(self):
1029         """ Some handles like VkInstance, VkDevice are dispatchable objects,
1030         which means they contain a dispatch table of function pointers.
1031         """
1032         return self.type == "VK_DEFINE_HANDLE"
1034     def is_required(self):
1035         return self.required
1037     def native_handle(self, name):
1038         """ Provide access to the native handle of a wrapped object. """
1040         if self.name == "VkCommandPool":
1041             return "wine_cmd_pool_from_handle({0})->command_pool".format(name)
1042         if self.name == "VkDebugUtilsMessengerEXT":
1043             return "wine_debug_utils_messenger_from_handle({0})->debug_messenger".format(name)
1044         if self.name == "VkDebugReportCallbackEXT":
1045             return "wine_debug_report_callback_from_handle({0})->debug_callback".format(name)
1046         if self.name == "VkSurfaceKHR":
1047             return "wine_surface_from_handle({0})->surface".format(name)
1049         native_handle_name = None
1051         if self.name == "VkCommandBuffer":
1052             native_handle_name = "command_buffer"
1053         if self.name == "VkDevice":
1054             native_handle_name = "device"
1055         if self.name == "VkInstance":
1056             native_handle_name = "instance"
1057         if self.name == "VkPhysicalDevice":
1058             native_handle_name = "phys_dev"
1059         if self.name == "VkQueue":
1060             native_handle_name = "queue"
1062         if native_handle_name:
1063             return "{0}->{1}".format(name, native_handle_name)
1065         if self.is_dispatchable():
1066             LOGGER.error("Unhandled native handle for: {0}".format(self.name))
1067         return None
1069     def driver_handle(self, name):
1070         """ Provide access to the handle that should be passed to the wine driver """
1072         if self.name == "VkSurfaceKHR":
1073             return "wine_surface_from_handle({0})->driver_surface".format(name)
1075         return self.native_handle(name)
1077     def is_wrapped(self):
1078         return self.native_handle("test") is not None
1080     def needs_conversion(self):
1081         return False
1083     def needs_unwrapping(self):
1084         return self.is_wrapped()
1086 class VkMember(object):
1087     def __init__(self, const=False, struct_fwd_decl=False,_type=None, pointer=None, name=None, array_len=None,
1088             dyn_array_len=None, optional=False, values=None):
1089         self.const = const
1090         self.struct_fwd_decl = struct_fwd_decl
1091         self.name = name
1092         self.pointer = pointer
1093         self.type = _type
1094         self.type_info = None
1095         self.array_len = array_len
1096         self.dyn_array_len = dyn_array_len
1097         self.optional = optional
1098         self.values = values
1100     def __eq__(self, other):
1101         """ Compare member based on name against a string.
1103         This method is for convenience by VkStruct, which holds a number of members and needs quick checking
1104         if certain members exist.
1105         """
1107         return self.name == other
1109     def __repr__(self):
1110         return "{0} {1} {2} {3} {4} {5} {6}".format(self.const, self.struct_fwd_decl, self.type, self.pointer,
1111                 self.name, self.array_len, self.dyn_array_len)
1113     @staticmethod
1114     def from_xml(member):
1115         """ Helper function for parsing a member tag within a struct or union. """
1117         name_elem = member.find("name")
1118         type_elem = member.find("type")
1120         const = False
1121         struct_fwd_decl = False
1122         member_type = None
1123         pointer = None
1124         array_len = None
1126         values = member.get("values")
1128         if member.text:
1129             if "const" in member.text:
1130                 const = True
1132             # Some members contain forward declarations:
1133             # - VkBaseInstructure has a member "const struct VkBaseInStructure *pNext"
1134             # - VkWaylandSurfaceCreateInfoKHR has a member "struct wl_display *display"
1135             if "struct" in member.text:
1136                 struct_fwd_decl = True
1138         if type_elem is not None:
1139             member_type = type_elem.text
1140             if type_elem.tail is not None:
1141                 pointer = type_elem.tail.strip() if type_elem.tail.strip() != "" else None
1143         # Name of other member within, which stores the number of
1144         # elements pointed to be by this member.
1145         dyn_array_len = member.get("len")
1147         # Some members are optional, which is important for conversion code e.g. not dereference NULL pointer.
1148         optional = True if member.get("optional") else False
1150         # Usually we need to allocate memory for dynamic arrays. We need to do the same in a few other cases
1151         # like for VkCommandBufferBeginInfo.pInheritanceInfo. Just threat such cases as dynamic arrays of
1152         # size 1 to simplify code generation.
1153         if dyn_array_len is None and pointer is not None:
1154             dyn_array_len = 1
1156         # Some members are arrays, attempt to parse these. Formats include:
1157         # <member><type>char</type><name>extensionName</name>[<enum>VK_MAX_EXTENSION_NAME_SIZE</enum>]</member>
1158         # <member><type>uint32_t</type><name>foo</name>[4]</member>
1159         if name_elem.tail and name_elem.tail[0] == '[':
1160             LOGGER.debug("Found array type")
1161             enum_elem = member.find("enum")
1162             if enum_elem is not None:
1163                 array_len = enum_elem.text
1164             else:
1165                 # Remove brackets around length
1166                 array_len = name_elem.tail.strip("[]")
1168         return VkMember(const=const, struct_fwd_decl=struct_fwd_decl, _type=member_type, pointer=pointer, name=name_elem.text,
1169                 array_len=array_len, dyn_array_len=dyn_array_len, optional=optional, values=values)
1171     def copy(self, input, output, direction, conv):
1172         """ Helper method for use by conversion logic to generate a C-code statement to copy this member.
1173             - `conv` indicates whether the statement is in a struct alignment conversion path. """
1175         if (conv and self.needs_conversion()) or self.needs_unwrapping():
1176             if self.is_dynamic_array():
1177                 if direction == Direction.OUTPUT:
1178                     LOGGER.warn("TODO: implement copying of returnedonly dynamic array for {0}.{1}".format(self.type, self.name))
1179                 else:
1180                     # Array length is either a variable name (string) or an int.
1181                     count = self.dyn_array_len if isinstance(self.dyn_array_len, int) else "{0}{1}".format(input, self.dyn_array_len)
1182                     return "{0}{1} = convert_{2}_array_win_to_host({3}{1}, {4});\n".format(output, self.name, self.type, input, count)
1183             elif self.is_static_array():
1184                 count = self.array_len
1185                 if direction == Direction.OUTPUT:
1186                     # Needed by VkMemoryHeap.memoryHeaps
1187                     return "convert_{0}_static_array_host_to_win({2}{1}, {3}{1}, {4});\n".format(self.type, self.name, input, output, count)
1188                 else:
1189                     # Nothing needed this yet.
1190                     LOGGER.warn("TODO: implement copying of static array for {0}.{1}".format(self.type, self.name))
1191             elif self.is_handle() and self.needs_unwrapping():
1192                 if direction == Direction.OUTPUT:
1193                     LOGGER.err("OUTPUT parameter {0}.{1} cannot be unwrapped".format(self.type, self.name))
1194                 else:
1195                     handle = self.type_info["data"]
1196                     return "{0}{1} = {2};\n".format(output, self.name, handle.driver_handle("{0}{1}".format(input, self.name)))
1197             else:
1198                 if direction == Direction.OUTPUT:
1199                     return "convert_{0}_host_to_win(&{2}{1}, &{3}{1});\n".format(self.type, self.name, input, output)
1200                 else:
1201                     return "convert_{0}_win_to_host(&{2}{1}, &{3}{1});\n".format(self.type, self.name, input, output)
1202         elif self.is_static_array():
1203             bytes_count = "{0} * sizeof({1})".format(self.array_len, self.type)
1204             return "memcpy({0}{1}, {2}{1}, {3});\n".format(output, self.name, input, bytes_count)
1205         else:
1206             return "{0}{1} = {2}{1};\n".format(output, self.name, input)
1208     def free(self, location, conv):
1209         """ Helper method for use by conversion logic to generate a C-code statement to free this member. """
1211         if not self.needs_unwrapping() and not conv:
1212             return ""
1214         # Add a cast to ignore const on conversion structs we allocated ourselves.
1215         # sample expected output: (VkSparseMemoryBind_host *)
1216         if self.is_const():
1217             cast = "(" + self.type
1218             if self.needs_conversion() and conv:
1219                 cast += "_host"
1220             cast += " *)"
1221         else:
1222             cast = ""
1224         if self.is_dynamic_array():
1225             count = self.dyn_array_len if isinstance(self.dyn_array_len, int) else "{0}{1}".format(location, self.dyn_array_len)
1226             if self.is_struct() and self.type_info["data"].returnedonly:
1227                 # For returnedonly, counts is stored in a pointer.
1228                 return "free_{0}_array({1}{2}{3}, *{4});\n".format(self.type, cast, location, self.name, count)
1229             else:
1230                 return "free_{0}_array({1}{2}{3}, {4});\n".format(self.type, cast, location, self.name, count)
1231         else:
1232             # We are operating on a single structure. Some structs (very rare) contain dynamic members,
1233             # which would need freeing.
1234             if self.needs_free():
1235                 return "free_{0}({1}&{2}{3});\n".format(self.type, cast, location, self.name)
1236         return ""
1238     def definition(self, align=False, conv=False):
1239         """ Generate prototype for given function.
1241         Args:
1242             align (bool, optional): Enable alignment if a type needs it. This adds WINE_VK_ALIGN(8) to a member.
1243             conv (bool, optional): Enable conversion if a type needs it. This appends '_host' to the name.
1244         """
1246         text = ""
1247         if self.is_const():
1248             text += "const "
1250         if self.is_struct_forward_declaration():
1251             text += "struct "
1253         if conv and self.is_struct():
1254             text += "{0}_host".format(self.type)
1255         else:
1256             text += self.type
1258         if self.is_pointer():
1259             text += " {0}{1}".format(self.pointer, self.name)
1260         else:
1261             if align and self.needs_alignment():
1262                 text += " WINE_VK_ALIGN(8) " + self.name
1263             else:
1264                 text += " " + self.name
1266         if self.is_static_array():
1267             text += "[{0}]".format(self.array_len)
1269         return text
1271     def get_conversions(self):
1272         """ Return any conversion description for this member and its children when conversion is needed. """
1274         # Check if we need conversion either for this member itself or for any child members
1275         # in case member represents a struct.
1276         if not self.needs_conversion() and not self.needs_unwrapping():
1277             return None
1279         conversions = []
1281         # Collect any conversion for any member structs.
1282         if self.is_struct():
1283             struct = self.type_info["data"]
1284             for m in struct:
1285                 m.needs_struct_extensions_conversion()
1286                 if m.needs_conversion() or m.needs_unwrapping():
1287                     conversions.extend(m.get_conversions())
1289             struct.needs_struct_extensions_conversion()
1290             direction = Direction.OUTPUT if struct.returnedonly else Direction.INPUT
1291         elif self.is_handle():
1292             direction = Direction.INPUT
1294         operand = self.type_info["data"]
1295         if self.is_dynamic_array():
1296             conversions.append(ConversionFunction(False, True, direction, operand))
1297         elif self.is_static_array():
1298             conversions.append(ConversionFunction(True, False, direction, operand))
1299         else:
1300             conversions.append(ConversionFunction(False, False, direction, operand))
1302         if self.needs_free():
1303             conversions.append(FreeFunction(self.is_dynamic_array(), operand))
1305         return conversions
1307     def is_const(self):
1308         return self.const
1310     def is_dynamic_array(self):
1311         """ Returns if the member is an array element.
1312         Vulkan uses this for dynamically sized arrays for which
1313         there is a 'count' parameter.
1314         """
1315         return self.dyn_array_len is not None
1317     def is_handle(self):
1318         return self.type_info["category"] == "handle"
1320     def is_pointer(self):
1321         return self.pointer is not None
1323     def is_static_array(self):
1324         """ Returns if the member is an array.
1325         Vulkan uses this often for fixed size arrays in which the
1326         length is part of the member.
1327         """
1328         return self.array_len is not None
1330     def is_struct(self):
1331         return self.type_info["category"] == "struct"
1333     def is_struct_forward_declaration(self):
1334         return self.struct_fwd_decl
1336     def is_union(self):
1337         return self.type_info["category"] == "union"
1339     def needs_alignment(self):
1340         """ Check if this member needs alignment for 64-bit data.
1341         Various structures need alignment on 64-bit variables due
1342         to compiler differences on 32-bit between Win32 and Linux.
1343         """
1345         if self.is_pointer():
1346             return False
1347         elif self.type == "size_t":
1348             return False
1349         elif self.type in ["uint64_t", "VkDeviceSize"]:
1350             return True
1351         elif self.is_struct():
1352             struct = self.type_info["data"]
1353             return struct.needs_alignment()
1354         elif self.is_handle():
1355             # Dispatchable handles are pointers to objects, while
1356             # non-dispatchable are uint64_t and hence need alignment.
1357             handle = self.type_info["data"]
1358             return False if handle.is_dispatchable() else True
1359         return False
1361     def needs_conversion(self):
1362         """ Structures requiring alignment, need conversion between win32 and host. """
1364         if not self.is_struct():
1365             return False
1367         struct = self.type_info["data"]
1368         return struct.needs_conversion()
1370     def needs_unwrapping(self):
1371         """ Structures with wrapped handles need unwrapping. """
1373         if self.is_struct():
1374             struct = self.type_info["data"]
1375             return struct.needs_unwrapping()
1377         if self.is_handle():
1378             handle = self.type_info["data"]
1379             return handle.is_wrapped()
1381         return False
1383     def needs_free(self):
1384         if not self.needs_conversion() and not self.needs_unwrapping():
1385             return False
1387         if self.is_dynamic_array():
1388             return True
1390         # TODO: some non-pointer structs and optional pointer structs may need freeing,
1391         # though none of this type have been encountered yet.
1392         return False
1394     def needs_struct_extensions_conversion(self):
1395         if not self.is_struct():
1396             return False
1398         struct = self.type_info["data"]
1399         return struct.needs_struct_extensions_conversion()
1401     def set_type_info(self, type_info):
1402         """ Helper function to set type information from the type registry.
1403         This is needed, because not all type data is available at time of
1404         parsing.
1405         """
1406         self.type_info = type_info
1409 class VkParam(object):
1410     """ Helper class which describes a parameter to a function call. """
1412     def __init__(self, type_info, const=None, pointer=None, name=None, array_len=None, dyn_array_len=None):
1413         self.const = const
1414         self.name = name
1415         self.array_len = array_len
1416         self.dyn_array_len = dyn_array_len
1417         self.pointer = pointer
1418         self.type_info = type_info
1419         self.type = type_info["name"] # For convenience
1420         self.handle = type_info["data"] if type_info["category"] == "handle" else None
1421         self.struct = type_info["data"] if type_info["category"] == "struct" else None
1423         self._set_direction()
1424         self._set_format_string()
1425         self._set_conversions()
1427     def __repr__(self):
1428         return "{0} {1} {2} {3} {4} {5}".format(self.const, self.type, self.pointer, self.name, self.array_len, self.dyn_array_len)
1430     @staticmethod
1431     def from_xml(param, types):
1432         """ Helper function to create VkParam from xml. """
1434         # Parameter parsing is slightly tricky. All the data is contained within
1435         # a param tag, but some data is within subtags while others are text
1436         # before or after the type tag.
1437         # Common structure:
1438         # <param>const <type>char</type>* <name>pLayerName</name></param>
1440         name_elem = param.find("name")
1441         array_len = None
1442         name = name_elem.text
1443         # Tail contains array length e.g. for blendConstants param of vkSetBlendConstants
1444         if name_elem.tail is not None:
1445             array_len = name_elem.tail.strip("[]")
1447         # Name of other parameter in function prototype, which stores the number of
1448         # elements pointed to be by this parameter.
1449         dyn_array_len = param.get("len", None)
1451         const = param.text.strip() if param.text else None
1452         type_elem = param.find("type")
1453         pointer = type_elem.tail.strip() if type_elem.tail.strip() != "" else None
1455         # Since we have parsed all types before hand, this should not happen.
1456         type_info = types.get(type_elem.text, None)
1457         if type_info is None:
1458             LOGGER.err("type info not found for: {0}".format(type_elem.text))
1460         return VkParam(type_info, const=const, pointer=pointer, name=name, array_len=array_len, dyn_array_len=dyn_array_len)
1462     def _set_conversions(self):
1463         """ Internal helper function to configure any needed conversion functions. """
1465         self.free_func = None
1466         self.input_conv = None
1467         self.output_conv = None
1468         if not self.needs_conversion() and not self.needs_unwrapping():
1469             return
1471         operand = self.struct if self.is_struct() else self.handle
1473         # Input functions require win to host conversion.
1474         if self._direction in [Direction.INPUT, Direction.INPUT_OUTPUT]:
1475             self.input_conv = ConversionFunction(False, self.is_dynamic_array(), Direction.INPUT, operand)
1477         # Output functions require host to win conversion.
1478         if self._direction in [Direction.INPUT_OUTPUT, Direction.OUTPUT]:
1479             self.output_conv = ConversionFunction(False, self.is_dynamic_array(), Direction.OUTPUT, operand)
1481         # Dynamic arrays, but also some normal structs (e.g. VkCommandBufferBeginInfo) need memory
1482         # allocation and thus some cleanup.
1483         if self.is_dynamic_array() or self.struct.needs_free():
1484             self.free_func = FreeFunction(self.is_dynamic_array(), operand)
1486     def _set_direction(self):
1487         """ Internal helper function to set parameter direction (input/output/input_output). """
1489         # The parameter direction needs to be determined from hints in vk.xml like returnedonly,
1490         # parameter constness and other heuristics.
1491         # For now we need to get this right for structures as we need to convert these, we may have
1492         # missed a few other edge cases (e.g. count variables).
1493         # See also https://github.com/KhronosGroup/Vulkan-Docs/issues/610
1495         if not self.is_pointer():
1496             self._direction = Direction.INPUT
1497         elif self.is_const() and self.is_pointer():
1498             self._direction = Direction.INPUT
1499         elif self.is_struct():
1500             if not self.struct.returnedonly:
1501                 self._direction = Direction.INPUT
1502                 return
1504             # Returnedonly hints towards output, however in some cases
1505             # it is inputoutput. In particular if pNext / sType exist,
1506             # which are used to link in other structures without having
1507             # to introduce new APIs. E.g. vkGetPhysicalDeviceProperties2KHR.
1508             if "pNext" in self.struct:
1509                 self._direction = Direction.INPUT_OUTPUT
1510                 return
1512             self._direction = Direction.OUTPUT
1513         else:
1514             # This should mostly be right. Count variables can be inout, but we don't care about these yet.
1515             self._direction = Direction.OUTPUT
1517     def _set_format_string(self):
1518         """ Internal helper function to be used by constructor to set format string. """
1520         # Determine a format string used by code generation for traces.
1521         # 64-bit types need a conversion function.
1522         self.format_conv = None
1523         if self.is_static_array() or self.is_pointer():
1524             self.format_str = "%p"
1525         else:
1526             if self.type_info["category"] in ["bitmask"]:
1527                 # Since 1.2.170 bitmasks can be 32 or 64-bit, check the basetype.
1528                 if self.type_info["data"].type == "VkFlags64":
1529                     self.format_str = "0x%s"
1530                     self.format_conv = "wine_dbgstr_longlong({0})"
1531                 else:
1532                     self.format_str = "%#x"
1533             elif self.type_info["category"] in ["enum"]:
1534                 self.format_str = "%#x"
1535             elif self.is_handle():
1536                 # We use uint64_t for non-dispatchable handles as opposed to pointers
1537                 # for dispatchable handles.
1538                 if self.handle.is_dispatchable():
1539                     self.format_str = "%p"
1540                 else:
1541                     self.format_str = "0x%s"
1542                     self.format_conv = "wine_dbgstr_longlong({0})"
1543             elif self.type == "float":
1544                 self.format_str = "%f"
1545             elif self.type == "int":
1546                 self.format_str = "%d"
1547             elif self.type == "int32_t":
1548                 self.format_str = "%d"
1549             elif self.type == "size_t":
1550                 self.format_str = "0x%s"
1551                 self.format_conv = "wine_dbgstr_longlong({0})"
1552             elif self.type in ["uint16_t", "uint32_t", "VkBool32"]:
1553                 self.format_str = "%u"
1554             elif self.type in ["uint64_t", "VkDeviceAddress", "VkDeviceSize"]:
1555                 self.format_str = "0x%s"
1556                 self.format_conv = "wine_dbgstr_longlong({0})"
1557             elif self.type == "HANDLE":
1558                 self.format_str = "%p"
1559             elif self.type in ["VisualID", "xcb_visualid_t", "RROutput", "zx_handle_t"]:
1560                 # Don't care about specific types for non-Windows platforms.
1561                 self.format_str = ""
1562             else:
1563                 LOGGER.warn("Unhandled type: {0}".format(self.type_info))
1565     def copy(self, direction):
1566         if direction == Direction.INPUT:
1567             if self.is_dynamic_array():
1568                 return "    {0}_host = convert_{1}_array_win_to_host({0}, {2});\n".format(self.name, self.type, self.dyn_array_len)
1569             else:
1570                 return "    convert_{0}_win_to_host({1}, &{1}_host);\n".format(self.type, self.name)
1571         else:
1572             if self.is_dynamic_array():
1573                 LOGGER.error("Unimplemented output conversion for: {0}".format(self.name))
1574             else:
1575                 return "    convert_{0}_host_to_win(&{1}_host, {1});\n".format(self.type, self.name)
1577     def definition(self, postfix=None):
1578         """ Return prototype for the parameter. E.g. 'const char *foo' """
1580         proto = ""
1581         if self.const:
1582             proto += self.const + " "
1584         proto += self.type
1586         if self.is_pointer():
1587             proto += " {0}{1}".format(self.pointer, self.name)
1588         else:
1589             proto += " " + self.name
1591         # Allows appending something to the variable name useful for
1592         # win32 to host conversion.
1593         if postfix is not None:
1594             proto += postfix
1596         if self.is_static_array():
1597             proto += "[{0}]".format(self.array_len)
1599         return proto
1601     def direction(self):
1602         """ Returns parameter direction: input, output, input_output.
1604         Parameter direction in Vulkan is not straight-forward, which this function determines.
1605         """
1607         return self._direction
1609     def dispatch_table(self):
1610         """ Return functions dispatch table pointer for dispatchable objects. """
1612         if not self.is_dispatchable():
1613             return None
1615         return "{0}->{1}".format(self.name, self.handle.dispatch_table())
1617     def format_string(self):
1618         return self.format_str
1620     def free(self):
1621         if self.is_dynamic_array():
1622             if self.is_struct() and self.struct.returnedonly:
1623                 # For returnedonly, counts is stored in a pointer.
1624                 return "    free_{0}_array({1}_host, *{2});\n".format(self.type, self.name, self.dyn_array_len)
1625             else:
1626                 return "    free_{0}_array({1}_host, {2});\n".format(self.type, self.name, self.dyn_array_len)
1627         else:
1628             # We are operating on a single structure. Some structs (very rare) contain dynamic members,
1629             # which would need freeing.
1630             if self.is_struct() and self.struct.needs_free():
1631                 return "    free_{0}(&{1}_host);\n".format(self.type, self.name)
1632         return ""
1634     def get_conversions(self):
1635         """ Get a list of conversions required for this parameter if any.
1636         Parameters which are structures may require conversion between win32
1637         and the host platform. This function returns a list of conversions
1638         required.
1639         """
1641         if self.is_struct():
1642             self.struct.needs_struct_extensions_conversion()
1643             for m in self.struct:
1644                 m.needs_struct_extensions_conversion()
1645         elif not self.is_handle():
1646             return None
1648         if not self.needs_conversion() and not self.needs_unwrapping():
1649             return None
1651         conversions = []
1653         # Collect any member conversions first, so we can guarantee
1654         # those functions will be defined prior to usage by the
1655         # 'parent' param requiring conversion.
1656         if self.is_struct():
1657             for m in self.struct:
1658                 if not m.is_struct():
1659                     continue
1661                 if not m.needs_conversion() and not m.needs_unwrapping():
1662                     continue
1664                 conversions.extend(m.get_conversions())
1666         # Conversion requirements for the 'parent' parameter.
1667         if self.input_conv is not None:
1668             conversions.append(self.input_conv)
1669         if self.output_conv is not None:
1670             conversions.append(self.output_conv)
1671         if self.free_func is not None:
1672             conversions.append(self.free_func)
1674         return conversions
1676     def is_const(self):
1677         return self.const is not None
1679     def is_dynamic_array(self):
1680         return self.dyn_array_len is not None
1682     def is_dispatchable(self):
1683         if not self.is_handle():
1684             return False
1686         return self.handle.is_dispatchable()
1688     def is_handle(self):
1689         return self.handle is not None
1691     def is_pointer(self):
1692         return self.pointer is not None
1694     def is_static_array(self):
1695         return self.array_len is not None
1697     def is_struct(self):
1698         return self.struct is not None
1700     def needs_conversion(self):
1701         """ Returns if parameter needs conversion between win32 and host. """
1703         if not self.is_struct():
1704             return False
1706         # VkSparseImageMemoryRequirements(2) is used by vkGetImageSparseMemoryRequirements(2).
1707         # This function is tricky to wrap, because how to wrap depends on whether
1708         # pSparseMemoryRequirements is NULL or not. Luckily for VkSparseImageMemoryRequirements(2)
1709         # the alignment works out in such a way that no conversion is needed between win32 and Linux.
1710         if self.type in ["VkSparseImageMemoryRequirements", "VkSparseImageMemoryRequirements2"]:
1711             return False
1713         # If a structure needs alignment changes, it means we need to
1714         # perform parameter conversion between win32 and host.
1715         if self.struct.needs_conversion():
1716             return True
1718         return False
1720     def needs_unwrapping(self):
1721         """ Returns if parameter needs unwrapping of handle. """
1723         # Wrapped handle parameters are handled seperately, only look for wrapped handles in structs
1724         if self.is_struct():
1725             return self.struct.needs_unwrapping()
1727         if self.is_handle() and self.is_dynamic_array():
1728             return self.handle.needs_unwrapping()
1730         return False
1732     def needs_free(self):
1733         return self.free_func is not None
1735     def needs_input_conversion(self):
1736         return self.input_conv is not None
1738     def needs_output_conversion(self):
1739         return self.output_conv is not None
1741     def spec(self):
1742         """ Generate spec file entry for this parameter. """
1744         if self.is_pointer() and self.type == "char":
1745             return "str"
1746         if self.is_dispatchable() or self.is_pointer() or self.is_static_array():
1747             return "ptr"
1748         if self.type_info["category"] in ["bitmask"]:
1749             # Since 1.2.170 bitmasks can be 32 or 64-bit, check the basetype.
1750             if self.type_info["data"].type == "VkFlags64":
1751                 return "int64"
1752             else:
1753                 return "long"
1754         if self.type_info["category"] in ["enum"]:
1755             return "long"
1756         if self.is_handle() and not self.is_dispatchable():
1757             return "int64"
1758         if self.type == "float":
1759             return "float"
1760         if self.type in ["int", "int32_t", "size_t", "uint16_t", "uint32_t", "VkBool32"]:
1761             return "long"
1762         if self.type in ["uint64_t", "VkDeviceSize"]:
1763             return "int64"
1765         LOGGER.error("Unhandled spec conversion for type: {0}".format(self.type))
1767     def variable(self, conv=False):
1768         """ Returns 'glue' code during generation of a function call on how to access the variable.
1769         This function handles various scenarios such as 'unwrapping' if dispatchable objects and
1770         renaming of parameters in case of win32 -> host conversion.
1772         Args:
1773             conv (bool, optional): Enable conversion if the param needs it. This appends '_host' to the name.
1774         """
1776         # Hack until we enable allocation callbacks from ICD to application. These are a joy
1777         # to enable one day, because of calling convention conversion.
1778         if "VkAllocationCallbacks" in self.type:
1779             LOGGER.debug("TODO: setting NULL VkAllocationCallbacks for {0}".format(self.name))
1780             return "NULL"
1782         if self.needs_unwrapping() or (conv and self.needs_conversion()):
1783             if self.is_dynamic_array():
1784                 return "{0}_host".format(self.name)
1785             else:
1786                 return "&{0}_host".format(self.name)
1787         else:
1788             # We need to pass the native handle to the native Vulkan calls and
1789             # the wine driver's handle to calls which are wrapped by the driver.
1790             driver_handle = self.handle.driver_handle(self.name) if self.is_handle() else None
1791             return driver_handle if driver_handle else self.name
1794 class VkStruct(Sequence):
1795     """ Class which represents the type union and struct. """
1797     def __init__(self, name, members, returnedonly, structextends, alias=None, union=False):
1798         self.name = name
1799         self.members = members
1800         self.returnedonly = returnedonly
1801         self.structextends = structextends
1802         self.required = False
1803         self.alias = alias
1804         self.union = union
1805         self.type_info = None # To be set later.
1806         self.struct_extensions = []
1807         self.aliased_by = []
1809     def __getitem__(self, i):
1810         return self.members[i]
1812     def __len__(self):
1813         return len(self.members)
1815     @staticmethod
1816     def from_alias(struct, alias):
1817         name = struct.attrib.get("name")
1818         aliasee = VkStruct(name, alias.members, alias.returnedonly, alias.structextends, alias=alias)
1820         alias.add_aliased_by(aliasee)
1821         return aliasee
1823     @staticmethod
1824     def from_xml(struct):
1825         # Unions and structs are the same parsing wise, but we need to
1826         # know which one we are dealing with later on for code generation.
1827         union = True if struct.attrib["category"] == "union" else False
1829         name = struct.attrib.get("name")
1831         # 'Output' structures for which data is filled in by the API are
1832         # marked as 'returnedonly'.
1833         returnedonly = True if struct.attrib.get("returnedonly") else False
1835         structextends = struct.attrib.get("structextends")
1836         structextends = structextends.split(",") if structextends else []
1838         members = []
1839         for member in struct.findall("member"):
1840             vk_member = VkMember.from_xml(member)
1841             members.append(vk_member)
1843         return VkStruct(name, members, returnedonly, structextends, union=union)
1845     @staticmethod
1846     def decouple_structs(structs):
1847         """ Helper function which decouples a list of structs.
1848         Structures often depend on other structures. To make the C compiler
1849         happy we need to define 'substructures' first. This function analyzes
1850         the list of structures and reorders them in such a way that they are
1851         decoupled.
1852         """
1854         tmp_structs = list(structs) # Don't modify the original structures.
1855         decoupled_structs = []
1857         while (len(tmp_structs) > 0):
1858             for struct in tmp_structs:
1859                 dependends = False
1861                 if not struct.required:
1862                     tmp_structs.remove(struct)
1863                     continue
1865                 for m in struct:
1866                     if not (m.is_struct() or m.is_union()):
1867                         continue
1869                     # VkBaseInstructure and VkBaseOutStructure reference themselves.
1870                     if m.type == struct.name:
1871                         break
1873                     found = False
1874                     # Check if a struct we depend on has already been defined.
1875                     for s in decoupled_structs:
1876                         if s.name == m.type:
1877                             found = True
1878                             break
1880                     if not found:
1881                         # Check if the struct we depend on is even in the list of structs.
1882                         # If found now, it means we haven't met all dependencies before we
1883                         # can operate on the current struct.
1884                         # When generating 'host' structs we may not be able to find a struct
1885                         # as the list would only contain the structs requiring conversion.
1886                         for s in tmp_structs:
1887                             if s.name == m.type:
1888                                 dependends = True
1889                                 break
1891                 if dependends == False:
1892                     decoupled_structs.append(struct)
1893                     tmp_structs.remove(struct)
1895         return decoupled_structs
1897     def definition(self, align=False, conv=False, postfix=None):
1898         """ Convert structure to textual definition.
1900         Args:
1901             align (bool, optional): enable alignment to 64-bit for win32 struct compatibility.
1902             conv (bool, optional): enable struct conversion if the struct needs it.
1903             postfix (str, optional): text to append to end of struct name, useful for struct renaming.
1904         """
1906         # Only define alias structs when doing conversions
1907         if self.is_alias() and not conv:
1908             return ""
1910         if self.union:
1911             text = "typedef union {0}".format(self.name)
1912         else:
1913             text = "typedef struct {0}".format(self.name)
1915         if postfix is not None:
1916             text += postfix
1918         text += "\n{\n"
1920         for m in self:
1921             if align and m.needs_alignment():
1922                 text += "    {0};\n".format(m.definition(align=align))
1923             elif conv and m.needs_conversion():
1924                 text += "    {0};\n".format(m.definition(conv=conv))
1925             else:
1926                 text += "    {0};\n".format(m.definition())
1928         if postfix is not None:
1929             text += "}} {0}{1};\n\n".format(self.name, postfix)
1930         else:
1931             text += "}} {0};\n".format(self.name)
1933         for aliasee in self.aliased_by:
1934             text += "typedef {0} {1};\n".format(self.name, aliasee.name)
1936         text += "\n"
1938         return text
1940     def is_alias(self):
1941         return bool(self.alias)
1943     def add_aliased_by(self, aliasee):
1944         self.aliased_by.append(aliasee)
1946     def needs_alignment(self):
1947         """ Check if structure needs alignment for 64-bit data.
1948         Various structures need alignment on 64-bit variables due
1949         to compiler differences on 32-bit between Win32 and Linux.
1950         """
1952         for m in self.members:
1953             if m.needs_alignment():
1954                 return True
1955         return False
1957     def needs_conversion(self):
1958         """ Returns if struct members needs conversion between win32 and host.
1959         Structures need conversion if they contain members requiring alignment
1960         or if they include other structures which need alignment.
1961         """
1963         if self.needs_alignment():
1964             return True
1966         for m in self.members:
1967             if m.needs_conversion():
1968                 return True
1969         return False
1971     def needs_unwrapping(self):
1972         """ Returns if struct members need unwrapping of handle. """
1974         for m in self.members:
1975             if m.needs_unwrapping():
1976                 return True
1977         return False
1979     def needs_free(self):
1980         """ Check if any struct member needs some memory freeing."""
1982         for m in self.members:
1983             if m.needs_free():
1984                 return True
1986             continue
1988         return False
1990     def needs_struct_extensions_conversion(self):
1991         """ Checks if structure extensions in pNext chain need conversion. """
1992         ret = False
1994         for e in self.struct_extensions:
1995             if e.required and e.needs_conversion():
1996                 LOGGER.error("Unhandled pNext chain alignment conversion for {0}".format(e.name))
1997                 ret = True
1998             if e.required and e.needs_unwrapping():
1999                 LOGGER.error("Unhandled pNext chain unwrapping conversion for {0}".format(e.name))
2000                 ret = True
2002         return ret
2004     def set_type_info(self, types):
2005         """ Helper function to set type information from the type registry.
2006         This is needed, because not all type data is available at time of
2007         parsing.
2008         """
2009         for m in self.members:
2010             type_info = types[m.type]
2011             m.set_type_info(type_info)
2014 class ConversionFunction(object):
2015     def __init__(self, array, dyn_array, direction, operand):
2016         self.array = array
2017         self.direction = direction
2018         self.dyn_array = dyn_array
2019         self.operand = operand
2020         self.type = operand.name
2022         self._set_name()
2024     def __eq__(self, other):
2025         return self.name == other.name
2027     def _generate_array_conversion_func(self):
2028         """ Helper function for generating a conversion function for array operands. """
2030         body = ""
2032         if self.operand.needs_conversion():
2033             body += "#if defined(USE_STRUCT_CONVERSION)\n"
2035             if self.direction == Direction.OUTPUT:
2036                 params = ["const {0}_host *in".format(self.type), "uint32_t count"]
2037                 return_type = self.type
2038             else:
2039                 params = ["const {0} *in".format(self.type), "uint32_t count"]
2040                 return_type = "{0}_host".format(self.type)
2042             # Generate function prototype.
2043             body += "static inline {0} *{1}(".format(return_type, self.name)
2044             body += ", ".join(p for p in params)
2045             body += ")\n{\n"
2047             body += "    {0} *out;\n".format(return_type)
2049         if self.operand.needs_unwrapping():
2050             if self.operand.needs_conversion():
2051                 body += "#else\n"
2053             params = ["const {0} *in".format(self.type), "uint32_t count"]
2054             return_type = "{0}".format(self.type)
2056             # Generate function prototype.
2057             body += "static inline {0} *{1}(".format(return_type, self.name)
2058             body += ", ".join(p for p in params)
2059             body += ")\n{\n"
2061             body += "    {0} *out;\n".format(return_type)
2063             if self.operand.needs_conversion():
2064                 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2066         body += "    unsigned int i;\n\n"
2067         body += "    if (!in) return NULL;\n\n"
2069         body += "    out = malloc(count * sizeof(*out));\n"
2071         body += "    for (i = 0; i < count; i++)\n"
2072         body += "    {\n"
2074         if isinstance(self.operand, VkStruct):
2075             for m in self.operand:
2076                 # TODO: support copying of pNext extension structures!
2077                 # Luckily though no extension struct at this point needs conversion.
2078                 convert = m.copy("in[i].", "out[i].", self.direction, conv=True)
2079                 if self.operand.needs_conversion() and not self.operand.needs_unwrapping():
2080                     body += "        " + convert
2081                 else:
2082                     unwrap = m.copy("in[i].", "out[i].", self.direction, conv=False)
2083                     if unwrap == convert:
2084                         body += "        " + unwrap
2085                     else:
2086                         body += "#if defined(USE_STRUCT_CONVERSION)\n"
2087                         body += "        " + convert
2088                         body += "#else\n"
2089                         body += "        " + unwrap
2090                         body += "#endif /* USE_STRUCT_CONVERSION */\n"
2092         elif isinstance(self.operand, VkHandle) and self.direction == Direction.INPUT:
2093             body += "        out[i] = " + self.operand.driver_handle("in[i]") + ";\n"
2094         else:
2095             LOGGER.warn("Unhandled conversion operand type")
2096             body += "        out[i] = in[i];\n"
2098         body += "    }\n\n"
2099         body += "    return out;\n"
2100         body += "}\n"
2102         if not self.operand.needs_unwrapping():
2103             body += "#endif /* USE_STRUCT_CONVERSION */\n"
2105         body += "\n"
2107         return body
2109     def _generate_conversion_func(self):
2110         """ Helper function for generating a conversion function for non-array operands. """
2112         # It doesn't make sense to generate conversion functions for non-struct variables
2113         # which aren't in arrays, as this should be handled by the copy() function
2114         if not isinstance(self.operand, VkStruct):
2115             return ""
2117         body = ""
2119         if self.operand.needs_conversion():
2120             body += "#if defined(USE_STRUCT_CONVERSION)\n"
2121             body += "static inline void {0}(".format(self.name)
2123             if self.direction == Direction.OUTPUT:
2124                 params = ["const {0}_host *in".format(self.type), "{0} *out".format(self.type)]
2125             else:
2126                 params = ["const {0} *in".format(self.type), "{0}_host *out".format(self.type)]
2128             # Generate parameter list
2129             body += ", ".join(p for p in params)
2130             body += ")\n"
2132         if self.operand.needs_unwrapping():
2133             if self.operand.needs_conversion():
2134                 body += "#else\n"
2136             body += "static inline void {0}(".format(self.name)
2138             params = ["const {0} *in".format(self.type), "{0} *out".format(self.type)]
2140             # Generate parameter list
2141             body += ", ".join(p for p in params)
2142             body += ")\n"
2144             if self.operand.needs_conversion():
2145                 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2147         body += "{\n    if (!in) return;\n\n"
2149         if self.direction == Direction.INPUT and "pNext" in self.operand and self.operand.returnedonly:
2150             # We are dealing with an input_output parameter. For these we only need to copy
2151             # pNext and sType as the other fields are filled in by the host. We do potentially
2152             # have to iterate over pNext and perform conversions based on switch(sType)!
2153             # Luckily though no extension structs at this point need conversion.
2154             # TODO: support copying of pNext extension structures!
2155             body += "    out->pNext = in->pNext;\n"
2156             body += "    out->sType = in->sType;\n"
2157         else:
2158             for m in self.operand:
2159                 # TODO: support copying of pNext extension structures!
2160                 convert = m.copy("in->", "out->", self.direction, conv=True)
2161                 if self.operand.needs_conversion() and not self.operand.needs_unwrapping():
2162                     body += "    " + convert
2163                 else:
2164                     unwrap = m.copy("in->", "out->", self.direction, conv=False)
2165                     if unwrap == convert:
2166                         body += "    " + unwrap
2167                     else:
2168                         body += "#if defined(USE_STRUCT_CONVERSION)\n"
2169                         body += "    " + convert
2170                         body += "#else\n"
2171                         body += "    " + unwrap
2172                         body += "#endif /* USE_STRUCT_CONVERSION */\n"
2174         body += "}\n"
2176         if not self.operand.needs_unwrapping():
2177             body += "#endif /* USE_STRUCT_CONVERSION */\n"
2179         body += "\n"
2181         return body
2183     def _generate_static_array_conversion_func(self):
2184         """ Helper function for generating a conversion function for array operands. """
2186         body = ""
2188         if self.operand.needs_conversion():
2189             body += "#if defined(USE_STRUCT_CONVERSION)\n"
2191             if self.direction == Direction.OUTPUT:
2192                 params = ["const {0}_host *in".format(self.type), "{0} *out".format(self.type), "uint32_t count"]
2193             else:
2194                 params = ["const {0} *in".format(self.type), "{0} *out_host".format(self.type), "uint32_t count"]
2196             # Generate function prototype.
2197             body += "static inline void {0}(".format(self.name)
2198             body += ", ".join(p for p in params)
2199             body += ")\n"
2201         if self.operand.needs_unwrapping():
2202             if self.operand.needs_conversion():
2203                 body += "#else\n"
2205             params = ["const {0} *in".format(self.type), "{0} *out".format(self.type), "uint32_t count"]
2207             # Generate function prototype.
2208             body += "static inline void {0}(".format(self.name)
2209             body += ", ".join(p for p in params)
2210             body += ")\n"
2212         body += "{\n"
2213         body += "    unsigned int i;\n\n"
2214         body += "    if (!in) return;\n\n"
2215         body += "    for (i = 0; i < count; i++)\n"
2216         body += "    {\n"
2218         if isinstance(self.operand, VkStruct):
2219             for m in self.operand:
2220                 # TODO: support copying of pNext extension structures!
2221                 convert = m.copy("in[i].", "out[i].", self.direction, conv=True)
2222                 if self.operand.needs_conversion() and not self.operand.needs_unwrapping():
2223                     body += "        " + convert
2224                 else:
2225                     unwrap = m.copy("in[i].", "out[i].", self.direction, conv=False)
2226                     if unwrap == convert:
2227                         body += "        " + unwrap
2228                     else:
2229                         body += "#if defined(USE_STRUCT_CONVERSION)\n"
2230                         body += "    " + convert
2231                         body += "#else\n"
2232                         body += "    " + unwrap
2233                         body += "#endif /* USE_STRUCT_CONVERSION */\n"
2234         elif isinstance(self.operand, VkHandle) and self.direction == Direction.INPUT:
2235             body += "        out[i] = " + self.operand.driver_handle("in[i]") + ";\n"
2236         else:
2237             LOGGER.warn("Unhandled conversion operand type")
2238             body += "        out[i] = in[i];\n"
2240         body += "    }\n"
2241         body += "}\n"
2243         if not self.operand.needs_unwrapping():
2244             body += "#endif /* USE_STRUCT_CONVERSION) */\n"
2246         body += "\n"
2248         return body
2250     def _set_name(self):
2251         if self.direction == Direction.INPUT:
2252             if self.array:
2253                 name = "convert_{0}_static_array_win_to_host".format(self.type)
2254             elif self.dyn_array:
2255                 name = "convert_{0}_array_win_to_host".format(self.type)
2256             else:
2257                 name = "convert_{0}_win_to_host".format(self.type)
2258         else: # Direction.OUTPUT
2259             if self.array:
2260                 name = "convert_{0}_static_array_host_to_win".format(self.type)
2261             elif self.dyn_array:
2262                 name = "convert_{0}_array_host_to_win".format(self.type)
2263             else:
2264                 name = "convert_{0}_host_to_win".format(self.type)
2266         self.name = name
2268     def definition(self):
2269         if self.array:
2270             return self._generate_static_array_conversion_func()
2271         elif self.dyn_array:
2272             return self._generate_array_conversion_func()
2273         else:
2274             return self._generate_conversion_func()
2277 class FreeFunction(object):
2278     def __init__(self, dyn_array, operand):
2279         self.dyn_array = dyn_array
2280         self.operand = operand
2281         self.type = operand.name
2283         if dyn_array:
2284             self.name = "free_{0}_array".format(self.type)
2285         else:
2286             self.name = "free_{0}".format(self.type)
2288     def __eq__(self, other):
2289         return self.name == other.name
2291     def _generate_array_free_func(self):
2292         """ Helper function for cleaning up temporary buffers required for array conversions. """
2294         body = ""
2296         if self.operand.needs_conversion():
2297             body += "#if defined(USE_STRUCT_CONVERSION)\n"
2298             # Generate function prototype.
2299             body += "static inline void {0}({1}_host *in, uint32_t count)\n".format(self.name, self.type)
2301         if self.operand.needs_unwrapping():
2302             if self.operand.needs_conversion():
2303                 body += "#else\n"
2305             # Generate function prototype.
2306             body += "static inline void {0}({1} *in, uint32_t count)\n".format(self.name, self.type)
2308             if self.operand.needs_conversion():
2309                 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2311         body += "{\n"
2313         # E.g. VkGraphicsPipelineCreateInfo_host needs freeing for pStages.
2314         if isinstance(self.operand, VkStruct) and self.operand.needs_free():
2315             body += "    unsigned int i;\n\n"
2316             body += "    if (!in) return;\n\n"
2317             body += "    for (i = 0; i < count; i++)\n"
2318             body += "    {\n"
2320             for m in self.operand:
2321                 if m.needs_free():
2322                     convert = m.free("in[i].", conv=True)
2323                     if self.operand.needs_conversion() and not self.operand.needs_unwrapping():
2324                         body += "        " + convert
2325                     else:
2326                         unwrap = m.free("in[i].", conv=False)
2327                         if convert == unwrap:
2328                             body += "        " + unwrap
2329                         elif unwrap == "":
2330                             body += "#if defined(USE_STRUCT_CONVERSION)\n"
2331                             body += "        " + convert
2332                             body += "#endif /* USE_STRUCT_CONVERSION */\n"
2333                         else:
2334                             body += "#if defined(USE_STRUCT_CONVERSION)\n"
2335                             body += "        " + convert
2336                             body += "#else\n"
2337                             body += "        " + unwrap
2338                             body += "#endif /* USE_STRUCT_CONVERSION */\n"
2339             body += "    }\n"
2340         else:
2341             body += "    if (!in) return;\n\n"
2343         body += "    free(in);\n"
2345         body += "}\n"
2347         if not self.operand.needs_unwrapping():
2348             body += "#endif /* USE_STRUCT_CONVERSION */\n"
2350         body += "\n"
2352         return body
2354     def _generate_free_func(self):
2355         # E.g. VkCommandBufferBeginInfo.pInheritanceInfo needs freeing.
2356         if not self.operand.needs_free():
2357             return ""
2359         if not isinstance(self.operand, VkStruct):
2360             return ""
2362         body = ""
2364         if self.operand.needs_conversion():
2365             body += "#if defined(USE_STRUCT_CONVERSION)\n"
2366             # Generate function prototype.
2367             body += "static inline void {0}({1}_host *in)\n".format(self.name, self.type)
2369         if self.operand.needs_unwrapping():
2370             if self.operand.needs_conversion():
2371                 body += "#else\n"
2373             # Generate function prototype.
2374             body += "static inline void {0}({1} *in)\n".format(self.name, self.type)
2376             if self.operand.needs_conversion():
2377                 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2379         body += "{\n"
2381         for m in self.operand:
2382             if m.needs_free():
2383                 convert = m.free("in->", conv=True)
2384                 if self.operand.needs_conversion() and not self.operand.needs_unwrapping():
2385                     body += "    " + convert
2386                 else:
2387                     unwrap = m.free("in->", conv=False)
2388                     if convert == unwrap:
2389                         body += "    " + unwrap
2390                     elif unwrap == "":
2391                         body += "#if defined(USE_STRUCT_CONVERSION)\n"
2392                         body += "    " + convert
2393                         body += "#endif /* USE_STRUCT_CONVERSION */\n"
2394                     else:
2395                         body += "#if defined(USE_STRUCT_CONVERSION)\n"
2396                         body += "    " + convert
2397                         body += "#else\n"
2398                         body += "    " + unwrap
2399                         body += "#endif /* USE_STRUCT_CONVERSION */\n"
2401         body += "}\n"
2403         if not self.operand.needs_unwrapping():
2404             body += "#endif /* USE_STRUCT_CONVERSION */\n"
2406         body += "\n"
2408         return body
2410     def definition(self):
2411         if self.dyn_array:
2412             return self._generate_array_free_func()
2413         else:
2414             # Some structures need freeing too if they contain dynamic arrays.
2415             # E.g. VkCommandBufferBeginInfo
2416             return self._generate_free_func()
2419 class StructChainConversionFunction(object):
2420     def __init__(self, direction, struct):
2421         self.direction = direction
2422         self.struct = struct
2423         self.type = struct.name
2425         self.name = "convert_{0}_struct_chain".format(self.type)
2427     def __eq__(self, other):
2428         return self.name == other.name
2430     def prototype(self, postfix=""):
2431         return "VkResult {0}(const void *pNext, {1} *out_struct) {2}".format(self.name, self.type, postfix).strip()
2433     def definition(self):
2434         body = self.prototype()
2435         body += "\n{\n"
2437         body += "    VkBaseOutStructure *out_header = (VkBaseOutStructure *)out_struct;\n";
2438         body += "    const VkBaseInStructure *in_header;\n\n";
2440         body += "    out_header->pNext = NULL;\n\n"
2442         body += "    for (in_header = pNext; in_header; in_header = in_header->pNext)\n"
2443         body += "    {\n"
2444         body += "        switch (in_header->sType)\n"
2445         body += "        {\n"
2447         # Ignore to not confuse host loader.
2448         body += "        case VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO:\n"
2449         body += "        case VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO:\n"
2450         body += "            break;\n\n"
2452         for e in self.struct.struct_extensions:
2453             if not e.required:
2454                 continue
2456             stype = next(x for x in e.members if x.name == "sType")
2458             body += "        case {0}:\n".format(stype.values)
2459             body += "        {\n"
2461             body += "            const {0} *in = (const {0} *)in_header;\n".format(e.name)
2462             body += "            {0} *out;\n\n".format(e.name)
2464             body += "            if (!(out = malloc(sizeof(*out)))) goto out_of_memory;\n\n"
2466             for m in e:
2467                 if m.name == "pNext":
2468                     body += "            out->pNext = NULL;\n"
2469                 else:
2470                     convert = m.copy("in->", "out->", self.direction, conv=True)
2471                     unwrap = m.copy("in->", "out->", self.direction, conv=False)
2472                     if unwrap == convert:
2473                         body += "            " + unwrap
2474                     else:
2475                         body += "#if defined(USE_STRUCT_CONVERSION)\n"
2476                         body += "            " + convert
2477                         body += "#else\n"
2478                         body += "            " + unwrap
2479                         body += "#endif /* USE_STRUCT_CONVERSION */\n"
2481             body += "\n            out_header->pNext = (VkBaseOutStructure *)out;\n"
2482             body += "            out_header = out_header->pNext;\n"
2483             body += "            break;\n"
2484             body += "        }\n\n"
2486         body += "        default:\n"
2487         body += "            FIXME(\"Application requested a linked structure of type %u.\\n\", in_header->sType);\n"
2489         body += "        }\n"
2490         body += "    }\n\n"
2492         body += "    return VK_SUCCESS;\n"
2494         if any(x for x in self.struct.struct_extensions if x.required):
2495             body += "\nout_of_memory:\n"
2496             body += "    free_{0}_struct_chain(out_struct);\n".format(self.type)
2497             body += "    return VK_ERROR_OUT_OF_HOST_MEMORY;\n"
2499         body += "}\n\n"
2500         return body
2502 class FreeStructChainFunction(object):
2503     def __init__(self, struct):
2504         self.struct = struct
2505         self.type = struct.name
2507         self.name = "free_{0}_struct_chain".format(self.type)
2509     def __eq__(self, other):
2510         return self.name == other.name
2512     def prototype(self, postfix=""):
2513         return "void {0}({1} *s) {2}".format(self.name, self.type, postfix).strip()
2515     def definition(self):
2516         body = self.prototype()
2517         body += "\n{\n"
2519         body += "    VkBaseOutStructure *header = (void *)s->pNext;\n\n";
2521         body += "    while (header)\n"
2522         body += "    {\n"
2523         body += "        void *prev = header;\n\n"
2524         body += "        switch (header->sType)\n"
2525         body += "        {\n"
2527         for e in self.struct.struct_extensions:
2528             if not e.required:
2529                 continue
2531             if not any(m.needs_free() for m in e):
2532                 continue
2534             stype = next(x for x in e.members if x.name == "sType")
2536             body += "            case {0}:\n".format(stype.values)
2537             body += "            {\n"
2538             body += "                {0} *structure = ({0} *) header;\n".format(e.name)
2540             for m in e:
2541                 if m.needs_free():
2542                     convert = m.free("structure->", conv=True)
2543                     unwrap = m.free("structure->", conv=False)
2544                     if convert == unwrap:
2545                         body += "                " + unwrap
2546                     elif unwrap == "":
2547                         body += "#if defined(USE_STRUCT_CONVERSION)\n"
2548                         body += "                " + convert
2549                         body += "#endif /* USE_STRUCT_CONVERSION */\n"
2550                     else:
2551                         body += "#if defined(USE_STRUCT_CONVERSION)\n"
2552                         body += "                " + convert
2553                         body += "#else\n"
2554                         body += "                " + unwrap
2555                         body += "#endif /* USE_STRUCT_CONVERSION */\n"
2557             body += "                break;\n"
2558             body += "            }\n"
2560         body += "            default:\n"
2561         body += "                break;\n"
2562         body += "        }\n"
2564         body += "        header = header->pNext;\n"
2565         body += "        free(prev);\n"
2566         body += "    }\n\n"
2568         body += "    s->pNext = NULL;\n"
2570         body += "}\n\n"
2571         return body
2574 class VkGenerator(object):
2575     def __init__(self, registry):
2576         self.registry = registry
2578         # Build a list conversion functions for struct conversion.
2579         self.conversions = []
2580         self.struct_chain_conversions = []
2581         self.host_structs = []
2582         for func in self.registry.funcs.values():
2583             if not func.is_required():
2584                 continue
2586             if not func.needs_conversion() and not func.needs_unwrapping():
2587                 continue
2589             conversions = func.get_conversions()
2590             for conv in conversions:
2591                 # Pull in any conversions for vulkan_thunks.c.
2592                 if func.needs_thunk():
2593                     # Append if we don't already have this conversion.
2594                     if not any(c == conv for c in self.conversions):
2595                         self.conversions.append(conv)
2597                 if not isinstance(conv.operand, VkStruct):
2598                     continue
2600                 # Structs can be used in different ways by different conversions
2601                 # e.g. array vs non-array. Just make sure we pull in each struct once.
2602                 if not any(s.name == conv.operand.name for s in self.host_structs):
2603                     self.host_structs.append(conv.operand)
2605         for struct in self.registry.structs:
2606             if struct.name in STRUCT_CHAIN_CONVERSIONS:
2607                 self.struct_chain_conversions.append(StructChainConversionFunction(Direction.INPUT, struct))
2608                 self.struct_chain_conversions.append(FreeStructChainFunction(struct))
2609                 # Once we decide to support pNext chains conversion everywhere, move this under get_conversions
2610                 for e in struct.struct_extensions:
2611                     for m in e:
2612                         if m.needs_conversion() or m.needs_unwrapping():
2613                             conversions = m.get_conversions()
2614                             for conv in conversions:
2615                                 if not any(c == conv for c in self.conversions):
2616                                     self.conversions.append(conv)
2618     def _generate_copyright(self, f, spec_file=False):
2619         f.write("# " if spec_file else "/* ")
2620         f.write("Automatically generated from Vulkan vk.xml; DO NOT EDIT!\n")
2621         lines = ["", "This file is generated from Vulkan vk.xml file covered",
2622             "by the following copyright and permission notice:"]
2623         lines.extend([l.rstrip(" ") for l in self.registry.copyright.splitlines()])
2624         for line in lines:
2625             f.write("{0}{1}".format("# " if spec_file else " * ", line).rstrip(" ") + "\n")
2626         f.write("\n" if spec_file else " */\n\n")
2628     def generate_thunks_c(self, f, prefix):
2629         self._generate_copyright(f)
2631         f.write("#if 0\n")
2632         f.write("#pragma makedep unix\n")
2633         f.write("#endif\n\n")
2635         f.write("#include \"config.h\"\n")
2636         f.write("#include \"wine/port.h\"\n\n")
2638         f.write("#include \"vulkan_private.h\"\n\n")
2640         f.write("WINE_DEFAULT_DEBUG_CHANNEL(vulkan);\n\n")
2642         # Generate any conversion helper functions.
2643         for conv in self.conversions:
2644             f.write(conv.definition())
2646         for conv in self.struct_chain_conversions:
2647             f.write(conv.definition())
2649         # Create thunks for instance and device functions.
2650         # Global functions don't go through the thunks.
2651         for vk_func in self.registry.funcs.values():
2652             if not vk_func.is_required():
2653                 continue
2655             if vk_func.is_global_func():
2656                 continue
2658             if not vk_func.needs_thunk():
2659                 continue
2661             # Exports symbols for Core functions.
2662             if not vk_func.is_core_func() and not vk_func.needs_private_thunk():
2663                 f.write("static ")
2665             if vk_func.needs_private_thunk():
2666                 f.write(vk_func.thunk(prefix="thunk_"))
2667             else:
2668                 f.write(vk_func.thunk(prefix=prefix, call_conv="WINAPI"))
2670         # Create array of device extensions.
2671         f.write("static const char * const vk_device_extensions[] =\n{\n")
2672         for ext in self.registry.extensions:
2673             if ext["type"] != "device":
2674                 continue
2676             f.write("    \"{0}\",\n".format(ext["name"]))
2677         f.write("};\n\n")
2679         # Create array of instance extensions.
2680         f.write("static const char * const vk_instance_extensions[] =\n{\n")
2681         for ext in self.registry.extensions:
2682             if ext["type"] != "instance":
2683                 continue
2685             f.write("    \"{0}\",\n".format(ext["name"]))
2686         f.write("};\n\n")
2688         f.write("BOOL wine_vk_device_extension_supported(const char *name)\n")
2689         f.write("{\n")
2690         f.write("    unsigned int i;\n")
2691         f.write("    for (i = 0; i < ARRAY_SIZE(vk_device_extensions); i++)\n")
2692         f.write("    {\n")
2693         f.write("        if (strcmp(vk_device_extensions[i], name) == 0)\n")
2694         f.write("            return TRUE;\n")
2695         f.write("    }\n")
2696         f.write("    return FALSE;\n")
2697         f.write("}\n\n")
2699         f.write("BOOL wine_vk_instance_extension_supported(const char *name)\n")
2700         f.write("{\n")
2701         f.write("    unsigned int i;\n")
2702         f.write("    for (i = 0; i < ARRAY_SIZE(vk_instance_extensions); i++)\n")
2703         f.write("    {\n")
2704         f.write("        if (strcmp(vk_instance_extensions[i], name) == 0)\n")
2705         f.write("            return TRUE;\n")
2706         f.write("    }\n")
2707         f.write("    return FALSE;\n")
2708         f.write("}\n\n")
2710         f.write("BOOL wine_vk_is_type_wrapped(VkObjectType type)\n")
2711         f.write("{\n")
2712         f.write("    return FALSE")
2713         for handle in self.registry.handles:
2714             if not handle.is_required() or not handle.is_wrapped() or handle.is_alias():
2715                 continue
2716             f.write(" ||\n        type == {}".format(handle.object_type))
2717         f.write(";\n")
2718         f.write("}\n\n")
2720         f.write("uint64_t wine_vk_unwrap_handle(VkObjectType type, uint64_t handle)\n")
2721         f.write("{\n")
2722         f.write("    switch(type)\n")
2723         f.write("    {\n")
2724         for handle in self.registry.handles:
2725             if not handle.is_required() or not handle.is_wrapped() or handle.is_alias():
2726                 continue
2727             f.write("    case {}:\n".format(handle.object_type))
2728             if handle.is_dispatchable():
2729                 f.write("        return (uint64_t) (uintptr_t) ")
2730                 f.write(handle.native_handle("(({}) (uintptr_t) handle)".format(handle.name)))
2731             else:
2732                 f.write("        return (uint64_t) ")
2733                 f.write(handle.native_handle("handle"))
2734             f.write(";\n");
2735         f.write("    default:\n")
2736         f.write("       return handle;\n")
2737         f.write("    }\n")
2738         f.write("}\n\n")
2740         f.write("const struct unix_funcs loader_funcs =\n")
2741         f.write("{\n")
2742         for vk_func in self.registry.funcs.values():
2743             if not vk_func.is_required():
2744                 continue
2745             if vk_func.loader_thunk_type == ThunkType.NONE:
2746                 continue
2748             f.write("    &{1}{0},\n".format(vk_func.name, prefix))
2749         f.write("};\n")
2751     def generate_thunks_h(self, f, prefix):
2752         self._generate_copyright(f)
2754         f.write("#ifndef __WINE_VULKAN_THUNKS_H\n")
2755         f.write("#define __WINE_VULKAN_THUNKS_H\n\n")
2757         f.write("#define WINE_VK_VERSION VK_API_VERSION_{0}_{1}\n\n".format(WINE_VK_VERSION[0], WINE_VK_VERSION[1]))
2759         # Generate prototypes for device and instance functions requiring a custom implementation.
2760         f.write("/* Functions for which we have custom implementations outside of the thunks. */\n")
2761         for vk_func in self.registry.funcs.values():
2762             if not vk_func.is_required():
2763                 continue
2764             if vk_func.needs_thunk() and not vk_func.needs_private_thunk():
2765                 continue
2767             if vk_func.is_core_func():
2768                 f.write("{0};\n".format(vk_func.prototype("WINAPI", prefix=prefix)))
2769             else:
2770                 f.write("{0};\n".format(vk_func.prototype("WINAPI", prefix=prefix, postfix="DECLSPEC_HIDDEN")))
2771         f.write("\n")
2773         f.write("/* Private thunks */\n")
2774         for vk_func in self.registry.funcs.values():
2775             if vk_func.needs_private_thunk():
2776                 f.write("{0};\n".format(vk_func.prototype(prefix="thunk_", postfix="DECLSPEC_HIDDEN")))
2777         f.write("\n")
2779         for struct in self.host_structs:
2780             f.write(struct.definition(align=False, conv=True, postfix="_host"))
2781         f.write("\n")
2783         for func in self.struct_chain_conversions:
2784             f.write(func.prototype(postfix="DECLSPEC_HIDDEN") + ";\n")
2785         f.write("\n")
2787         f.write("/* For use by vkDevice and children */\n")
2788         f.write("struct vulkan_device_funcs\n{\n")
2789         for vk_func in self.registry.device_funcs:
2790             if not vk_func.is_required():
2791                 continue
2793             if not vk_func.needs_dispatch():
2794                 LOGGER.debug("skipping {0} in vulkan_device_funcs".format(vk_func.name))
2795                 continue
2797             if vk_func.needs_conversion():
2798                 f.write("#if defined(USE_STRUCT_CONVERSION)\n")
2799                 f.write("    {0};\n".format(vk_func.pfn(conv=True)))
2800                 f.write("#else\n")
2801                 f.write("    {0};\n".format(vk_func.pfn(conv=False)))
2802                 f.write("#endif\n")
2803             else:
2804                 f.write("    {0};\n".format(vk_func.pfn(conv=False)))
2805         f.write("};\n\n")
2807         f.write("/* For use by vkInstance and children */\n")
2808         f.write("struct vulkan_instance_funcs\n{\n")
2809         for vk_func in self.registry.instance_funcs + self.registry.phys_dev_funcs:
2810             if not vk_func.is_required():
2811                 continue
2813             if not vk_func.needs_dispatch():
2814                 LOGGER.debug("skipping {0} in vulkan_instance_funcs".format(vk_func.name))
2815                 continue
2817             if vk_func.needs_conversion():
2818                 f.write("#if defined(USE_STRUCT_CONVERSION)\n")
2819                 f.write("    {0};\n".format(vk_func.pfn(conv=True)))
2820                 f.write("#else\n")
2821                 f.write("    {0};\n".format(vk_func.pfn(conv=False)))
2822                 f.write("#endif\n")
2823             else:
2824                 f.write("    {0};\n".format(vk_func.pfn(conv=False)))
2825         f.write("};\n\n")
2827         f.write("#define ALL_VK_DEVICE_FUNCS() \\\n")
2828         first = True
2829         for vk_func in self.registry.device_funcs:
2830             if not vk_func.is_required():
2831                 continue
2833             if not vk_func.needs_dispatch():
2834                 LOGGER.debug("skipping {0} in ALL_VK_DEVICE_FUNCS".format(vk_func.name))
2835                 continue
2837             if first:
2838                 f.write("    USE_VK_FUNC({0})".format(vk_func.name))
2839                 first = False
2840             else:
2841                 f.write(" \\\n    USE_VK_FUNC({0})".format(vk_func.name))
2842         f.write("\n\n")
2844         f.write("#define ALL_VK_INSTANCE_FUNCS() \\\n")
2845         first = True
2846         for vk_func in self.registry.instance_funcs + self.registry.phys_dev_funcs:
2847             if not vk_func.is_required():
2848                 continue
2850             if not vk_func.needs_dispatch():
2851                 LOGGER.debug("skipping {0} in ALL_VK_INSTANCE_FUNCS".format(vk_func.name))
2852                 continue
2854             if first:
2855                 f.write("    USE_VK_FUNC({0})".format(vk_func.name))
2856                 first = False
2857             else:
2858                 f.write(" \\\n    USE_VK_FUNC({0})".format(vk_func.name))
2859         f.write("\n\n")
2861         f.write("#endif /* __WINE_VULKAN_THUNKS_H */\n")
2863     def generate_loader_thunks_c(self, f):
2864         self._generate_copyright(f)
2866         f.write("#include \"vulkan_loader.h\"\n\n")
2868         f.write("WINE_DEFAULT_DEBUG_CHANNEL(vulkan);\n\n")
2870         for vk_func in self.registry.funcs.values():
2871             if not vk_func.is_required():
2872                 continue
2873             if vk_func.loader_thunk_type != ThunkType.PUBLIC:
2874                 continue
2876             f.write(vk_func.loader_thunk())
2878         f.write("static const struct vulkan_func vk_device_dispatch_table[] =\n{\n")
2879         for vk_func in self.registry.device_funcs:
2880             if not vk_func.is_required():
2881                 continue
2883             f.write("    {{\"{0}\", &{0}}},\n".format(vk_func.name))
2884         f.write("};\n\n")
2886         f.write("static const struct vulkan_func vk_phys_dev_dispatch_table[] =\n{\n")
2887         for vk_func in self.registry.phys_dev_funcs:
2888             if not vk_func.is_required():
2889                 continue
2891             f.write("    {{\"{0}\", &{0}}},\n".format(vk_func.name))
2892         f.write("};\n\n")
2894         f.write("static const struct vulkan_func vk_instance_dispatch_table[] =\n{\n")
2895         for vk_func in self.registry.instance_funcs:
2896             if not vk_func.is_required():
2897                 continue
2899             f.write("    {{\"{0}\", &{0}}},\n".format(vk_func.name))
2900         f.write("};\n\n")
2902         f.write("void *wine_vk_get_device_proc_addr(const char *name)\n")
2903         f.write("{\n")
2904         f.write("    unsigned int i;\n")
2905         f.write("    for (i = 0; i < ARRAY_SIZE(vk_device_dispatch_table); i++)\n")
2906         f.write("    {\n")
2907         f.write("        if (strcmp(vk_device_dispatch_table[i].name, name) == 0)\n")
2908         f.write("        {\n")
2909         f.write("            TRACE(\"Found name=%s in device table\\n\", debugstr_a(name));\n")
2910         f.write("            return vk_device_dispatch_table[i].func;\n")
2911         f.write("        }\n")
2912         f.write("    }\n")
2913         f.write("    return NULL;\n")
2914         f.write("}\n\n")
2916         f.write("void *wine_vk_get_phys_dev_proc_addr(const char *name)\n")
2917         f.write("{\n")
2918         f.write("    unsigned int i;\n")
2919         f.write("    for (i = 0; i < ARRAY_SIZE(vk_phys_dev_dispatch_table); i++)\n")
2920         f.write("    {\n")
2921         f.write("        if (strcmp(vk_phys_dev_dispatch_table[i].name, name) == 0)\n")
2922         f.write("        {\n")
2923         f.write("            TRACE(\"Found name=%s in physical device table\\n\", debugstr_a(name));\n")
2924         f.write("            return vk_phys_dev_dispatch_table[i].func;\n")
2925         f.write("        }\n")
2926         f.write("    }\n")
2927         f.write("    return NULL;\n")
2928         f.write("}\n\n")
2930         f.write("void *wine_vk_get_instance_proc_addr(const char *name)\n")
2931         f.write("{\n")
2932         f.write("    unsigned int i;\n")
2933         f.write("    for (i = 0; i < ARRAY_SIZE(vk_instance_dispatch_table); i++)\n")
2934         f.write("    {\n")
2935         f.write("        if (strcmp(vk_instance_dispatch_table[i].name, name) == 0)\n")
2936         f.write("        {\n")
2937         f.write("            TRACE(\"Found name=%s in instance table\\n\", debugstr_a(name));\n")
2938         f.write("            return vk_instance_dispatch_table[i].func;\n")
2939         f.write("        }\n")
2940         f.write("    }\n")
2941         f.write("    return NULL;\n")
2942         f.write("}\n")
2944     def generate_loader_thunks_h(self, f):
2945         self._generate_copyright(f)
2947         f.write("#ifndef __WINE_VULKAN_LOADER_THUNKS_H\n")
2948         f.write("#define __WINE_VULKAN_LOADER_THUNKS_H\n\n")
2950         f.write("struct unix_funcs\n")
2951         f.write("{\n")
2952         for vk_func in self.registry.funcs.values():
2953             if not vk_func.is_required():
2954                 continue
2955             if vk_func.loader_thunk_type == ThunkType.NONE:
2956                 continue
2958             f.write("    {0};\n".format(vk_func.pfn(conv=False, call_conv="WINAPI")))
2959         f.write("};\n\n")
2961         f.write("#endif /* __WINE_VULKAN_LOADER_THUNKS_H */\n")
2963     def generate_vulkan_h(self, f):
2964         self._generate_copyright(f)
2965         f.write("#ifndef __WINE_VULKAN_H\n")
2966         f.write("#define __WINE_VULKAN_H\n\n")
2968         f.write("#include <windef.h>\n")
2969         f.write("#include <stdint.h>\n\n")
2971         f.write("/* Define WINE_VK_HOST to get 'host' headers. */\n")
2972         f.write("#ifdef WINE_VK_HOST\n")
2973         f.write("#define VKAPI_CALL\n")
2974         f.write('#define WINE_VK_ALIGN(x)\n')
2975         f.write("#endif\n\n")
2977         f.write("#ifndef VKAPI_CALL\n")
2978         f.write("#define VKAPI_CALL __stdcall\n")
2979         f.write("#endif\n\n")
2981         f.write("#ifndef VKAPI_PTR\n")
2982         f.write("#define VKAPI_PTR VKAPI_CALL\n")
2983         f.write("#endif\n\n")
2985         f.write("#ifndef WINE_VK_ALIGN\n")
2986         f.write("#define WINE_VK_ALIGN DECLSPEC_ALIGN\n")
2987         f.write("#endif\n\n")
2989         # The overall strategy is to define independent constants and datatypes,
2990         # prior to complex structures and function calls to avoid forward declarations.
2991         for const in self.registry.consts:
2992             # For now just generate things we may not need. The amount of parsing needed
2993             # to get some of the info is tricky as you need to figure out which structure
2994             # references a certain constant.
2995             f.write(const.definition())
2996         f.write("\n")
2998         for define in self.registry.defines:
2999             f.write(define.definition())
3001         for handle in self.registry.handles:
3002             # For backward compatibility also create definitions for aliases.
3003             # These types normally don't get pulled in as we use the new types
3004             # even in legacy functions if they are aliases.
3005             if handle.is_required() or handle.is_alias():
3006                  f.write(handle.definition())
3007         f.write("\n")
3009         for base_type in self.registry.base_types:
3010             f.write(base_type.definition())
3011         f.write("\n")
3013         for bitmask in self.registry.bitmasks:
3014             f.write(bitmask.definition())
3015         f.write("\n")
3017         # Define enums, this includes values for some of the bitmask types as well.
3018         for enum in self.registry.enums.values():
3019             if enum.required:
3020                 f.write(enum.definition())
3022         for fp in self.registry.funcpointers:
3023             if fp.required:
3024                 f.write(fp.definition())
3025         f.write("\n")
3027         # This generates both structures and unions. Since structures
3028         # may depend on other structures/unions, we need a list of
3029         # decoupled structs.
3030         # Note: unions are stored in structs for dependency reasons,
3031         # see comment in parsing section.
3032         structs = VkStruct.decouple_structs(self.registry.structs)
3033         for struct in structs:
3034             LOGGER.debug("Generating struct: {0}".format(struct.name))
3035             f.write(struct.definition(align=True))
3037         for func in self.registry.funcs.values():
3038             if not func.is_required():
3039                 LOGGER.debug("Skipping PFN definition for: {0}".format(func.name))
3040                 continue
3042             f.write("typedef {0};\n".format(func.pfn(prefix="PFN", call_conv="VKAPI_PTR")))
3043         f.write("\n")
3045         f.write("#ifndef VK_NO_PROTOTYPES\n")
3046         for func in self.registry.funcs.values():
3047             if not func.is_required():
3048                 LOGGER.debug("Skipping API definition for: {0}".format(func.name))
3049                 continue
3051             LOGGER.debug("Generating API definition for: {0}".format(func.name))
3052             f.write("{0};\n".format(func.prototype(call_conv="VKAPI_CALL")))
3053         f.write("#endif /* VK_NO_PROTOTYPES */\n\n")
3055         f.write("#endif /* __WINE_VULKAN_H */\n")
3057     def generate_vulkan_driver_h(self, f):
3058         self._generate_copyright(f)
3059         f.write("#ifndef __WINE_VULKAN_DRIVER_H\n")
3060         f.write("#define __WINE_VULKAN_DRIVER_H\n\n")
3062         f.write("/* Wine internal vulkan driver version, needs to be bumped upon vulkan_funcs changes. */\n")
3063         f.write("#define WINE_VULKAN_DRIVER_VERSION {0}\n\n".format(DRIVER_VERSION))
3065         f.write("struct vulkan_funcs\n{\n")
3066         f.write("    /* Vulkan global functions. These are the only calls at this point a graphics driver\n")
3067         f.write("     * needs to provide. Other function calls will be provided indirectly by dispatch\n")
3068         f.write("     * tables part of dispatchable Vulkan objects such as VkInstance or vkDevice.\n")
3069         f.write("     */\n")
3071         for vk_func in self.registry.funcs.values():
3072             if not vk_func.is_driver_func():
3073                 continue
3075             pfn = vk_func.pfn()
3076             # Avoid PFN_vkVoidFunction in driver interface as Vulkan likes to put calling convention
3077             # stuff in there. For simplicity substitute with "void *".
3078             pfn = pfn.replace("PFN_vkVoidFunction", "void *")
3079             f.write("    {0};\n".format(pfn))
3081         f.write("\n")
3082         f.write("    /* winevulkan specific functions */\n")
3083         f.write("    VkSurfaceKHR (*p_wine_get_native_surface)(VkSurfaceKHR);\n")
3084         f.write("};\n\n")
3086         f.write("extern const struct vulkan_funcs * CDECL __wine_get_vulkan_driver(HDC hdc, UINT version);\n\n")
3088         f.write("static inline void *get_vulkan_driver_device_proc_addr(\n")
3089         f.write("        const struct vulkan_funcs *vulkan_funcs, const char *name)\n{\n")
3090         f.write("    if (!name || name[0] != 'v' || name[1] != 'k') return NULL;\n\n")
3091         f.write("    name += 2;\n\n")
3092         for vk_func in self.registry.funcs.values():
3093             if vk_func.is_driver_func() and vk_func.is_device_func():
3094                 f.write('    if (!strcmp(name, "{0}"))\n'.format(vk_func.name[2:]))
3095                 f.write('        return vulkan_funcs->p_{0};\n'.format(vk_func.name))
3096         f.write("\n")
3097         f.write("    return NULL;\n}\n\n")
3099         f.write("static inline void *get_vulkan_driver_instance_proc_addr(\n")
3100         f.write("        const struct vulkan_funcs *vulkan_funcs, VkInstance instance, const char *name)\n{\n")
3101         f.write("    if (!name || name[0] != 'v' || name[1] != 'k') return NULL;\n\n")
3102         f.write("    name += 2;\n\n")
3103         for vk_func in self.registry.funcs.values():
3104             if vk_func.is_driver_func() and vk_func.is_global_func() and vk_func.name != "vkGetInstanceProcAddr":
3105                 f.write('    if (!strcmp(name, "{0}"))\n'.format(vk_func.name[2:]))
3106                 f.write('        return vulkan_funcs->p_{0};\n'.format(vk_func.name))
3107         f.write("\n")
3108         f.write("    if (!instance) return NULL;\n\n")
3109         for vk_func in self.registry.funcs.values():
3110             if vk_func.is_driver_func() and (vk_func.is_instance_func() or vk_func.is_phys_dev_func()):
3111                 f.write('    if (!strcmp(name, "{0}"))\n'.format(vk_func.name[2:]))
3112                 f.write('        return vulkan_funcs->p_{0};\n'.format(vk_func.name))
3113         f.write("\n")
3114         f.write("    name -= 2;\n\n")
3115         f.write("    return get_vulkan_driver_device_proc_addr(vulkan_funcs, name);\n}\n\n")
3117         f.write("#endif /* __WINE_VULKAN_DRIVER_H */\n")
3119     def generate_vulkan_spec(self, f):
3120         self._generate_copyright(f, spec_file=True)
3121         f.write("@ stdcall -private vk_icdGetInstanceProcAddr(ptr str)\n")
3122         f.write("@ stdcall -private vk_icdGetPhysicalDeviceProcAddr(ptr str)\n")
3123         f.write("@ stdcall -private vk_icdNegotiateLoaderICDInterfaceVersion(ptr)\n")
3125         # Export symbols for all Vulkan Core functions.
3126         for func in self.registry.funcs.values():
3127             if not func.is_core_func():
3128                 continue
3130             # We support all Core functions except for VK_KHR_display* APIs.
3131             # Create stubs for unsupported Core functions.
3132             if func.is_required():
3133                 f.write(func.spec())
3134             else:
3135                 f.write("@ stub {0}\n".format(func.name))
3137         f.write("@ stdcall -private DllRegisterServer()\n")
3138         f.write("@ stdcall -private DllUnregisterServer()\n")
3140     def generate_vulkan_loader_spec(self, f):
3141         self._generate_copyright(f, spec_file=True)
3143         # Export symbols for all Vulkan Core functions.
3144         for func in self.registry.funcs.values():
3145             if not func.is_core_func():
3146                 continue
3148             # We support all Core functions except for VK_KHR_display* APIs.
3149             # Create stubs for unsupported Core functions.
3150             if func.is_required():
3151                 f.write(func.spec(symbol="winevulkan." + func.name))
3152             else:
3153                 f.write("@ stub {0}\n".format(func.name))
3156 class VkRegistry(object):
3157     def __init__(self, reg_filename):
3158         # Used for storage of type information.
3159         self.base_types = None
3160         self.bitmasks = None
3161         self.consts = None
3162         self.defines = None
3163         self.enums = None
3164         self.funcpointers = None
3165         self.handles = None
3166         self.structs = None
3168         # We aggregate all types in here for cross-referencing.
3169         self.funcs = {}
3170         self.types = {}
3172         self.version_regex = re.compile(
3173             r'^'
3174             r'VK_VERSION_'
3175             r'(?P<major>[0-9])'
3176             r'_'
3177             r'(?P<minor>[0-9])'
3178             r'$'
3179         )
3181         # Overall strategy for parsing the registry is to first
3182         # parse all type / function definitions. Then parse
3183         # features and extensions to decide which types / functions
3184         # to actually 'pull in' for code generation. For each type or
3185         # function call we want we set a member 'required' to True.
3186         tree = ET.parse(reg_filename)
3187         root = tree.getroot()
3188         self._parse_enums(root)
3189         self._parse_types(root)
3190         self._parse_commands(root)
3192         # Pull in any required types and functions.
3193         self._parse_features(root)
3194         self._parse_extensions(root)
3196         self._match_object_types()
3198         self.copyright = root.find('./comment').text
3200     def _is_feature_supported(self, feature):
3201         version = self.version_regex.match(feature)
3202         if not version:
3203             return True
3205         version = tuple(map(int, version.group('major', 'minor')))
3206         return version <= WINE_VK_VERSION
3208     def _is_extension_supported(self, extension):
3209         # We disable some extensions as either we haven't implemented
3210         # support yet or because they are for platforms other than win32.
3211         return extension not in UNSUPPORTED_EXTENSIONS
3213     def _mark_command_required(self, command):
3214         """ Helper function to mark a certain command and the datatypes it needs as required."""
3215         def mark_bitmask_dependencies(bitmask, types):
3216             if bitmask.requires is not None:
3217                 types[bitmask.requires]["data"].required = True
3219         def mark_funcpointer_dependencies(fp, types):
3220             for m in fp.members:
3221                 type_info = types[m.type]
3223                 # Complex types have a matching definition e.g. VkStruct.
3224                 # Not needed for base types such as uint32_t.
3225                 if "data" in type_info:
3226                     types[m.type]["data"].required = True
3228         def mark_struct_dependencies(struct, types):
3229              for m in struct:
3230                 type_info = types[m.type]
3232                 # Complex types have a matching definition e.g. VkStruct.
3233                 # Not needed for base types such as uint32_t.
3234                 if "data" in type_info:
3235                     types[m.type]["data"].required = True
3237                 if type_info["category"] == "struct":
3238                     # Yay, recurse
3239                     mark_struct_dependencies(type_info["data"], types)
3240                 elif type_info["category"] == "funcpointer":
3241                     mark_funcpointer_dependencies(type_info["data"], types)
3242                 elif type_info["category"] == "bitmask":
3243                     mark_bitmask_dependencies(type_info["data"], types)
3245         func = self.funcs[command]
3246         func.required = True
3248         # Pull in return type
3249         if func.type != "void":
3250             self.types[func.type]["data"].required = True
3252         # Analyze parameter dependencies and pull in any type needed.
3253         for p in func.params:
3254             type_info = self.types[p.type]
3256             # Check if we are dealing with a complex type e.g. VkEnum, VkStruct and others.
3257             if "data" not in type_info:
3258                 continue
3260             # Mark the complex type as required.
3261             type_info["data"].required = True
3262             if type_info["category"] == "struct":
3263                 struct = type_info["data"]
3264                 mark_struct_dependencies(struct, self.types)
3265             elif type_info["category"] == "bitmask":
3266                 mark_bitmask_dependencies(type_info["data"], self.types)
3268     def _match_object_types(self):
3269         """ Matches each handle with the correct object type. """
3270         # Use upper case comparison for simplicity.
3271         object_types = {}
3272         for value in self.enums["VkObjectType"].values:
3273             object_name = "VK" + value.name[len("VK_OBJECT_TYPE"):].replace("_", "")
3274             object_types[object_name] = value.name
3276         for handle in self.handles:
3277             if not handle.is_required():
3278                 continue
3279             handle.object_type = object_types.get(handle.name.upper())
3280             if not handle.object_type:
3281                 LOGGER.warning("No object type found for {}".format(handle.name))
3283     def _parse_commands(self, root):
3284         """ Parse command section containing the Vulkan function calls. """
3285         funcs = {}
3286         commands = root.findall("./commands/")
3288         # As of Vulkan 1.1, various extensions got promoted to Core.
3289         # The old commands (e.g. KHR) are available for backwards compatibility
3290         # and are marked in vk.xml as 'alias' to the non-extension type.
3291         # The registry likes to avoid data duplication, so parameters and other
3292         # metadata need to be looked up from the Core command.
3293         # We parse the alias commands in a second pass.
3294         alias_commands = []
3295         for command in commands:
3296             alias_name = command.attrib.get("alias")
3297             if alias_name:
3298                 alias_commands.append(command)
3299                 continue
3301             func = VkFunction.from_xml(command, self.types)
3302             funcs[func.name] = func
3304         for command in alias_commands:
3305             alias_name = command.attrib.get("alias")
3306             alias = funcs[alias_name]
3307             func = VkFunction.from_alias(command, alias)
3308             funcs[func.name] = func
3310         # To make life easy for the code generation, separate all function
3311         # calls out in the 4 types of Vulkan functions:
3312         # device, global, physical device and instance.
3313         device_funcs = []
3314         global_funcs = []
3315         phys_dev_funcs = []
3316         instance_funcs = []
3317         for func in funcs.values():
3318             if func.is_device_func():
3319                 device_funcs.append(func)
3320             elif func.is_global_func():
3321                 global_funcs.append(func)
3322             elif func.is_phys_dev_func():
3323                 phys_dev_funcs.append(func)
3324             else:
3325                 instance_funcs.append(func)
3327         # Sort function lists by name and store them.
3328         self.device_funcs = sorted(device_funcs, key=lambda func: func.name)
3329         self.global_funcs = sorted(global_funcs, key=lambda func: func.name)
3330         self.phys_dev_funcs = sorted(phys_dev_funcs, key=lambda func: func.name)
3331         self.instance_funcs = sorted(instance_funcs, key=lambda func: func.name)
3333         # The funcs dictionary is used as a convenient way to lookup function
3334         # calls when needed e.g. to adjust member variables.
3335         self.funcs = OrderedDict(sorted(funcs.items()))
3337     def _parse_enums(self, root):
3338         """ Parse enums section or better described as constants section. """
3339         enums = {}
3340         self.consts = []
3341         for enum in root.findall("./enums"):
3342             name = enum.attrib.get("name")
3343             _type = enum.attrib.get("type")
3345             if _type in ("enum", "bitmask"):
3346                 enums[name] = VkEnum.from_xml(enum)
3347             else:
3348                 # If no type is set, we are dealing with API constants.
3349                 for value in enum.findall("enum"):
3350                     # If enum is an alias, set the value to the alias name.
3351                     # E.g. VK_LUID_SIZE_KHR is an alias to VK_LUID_SIZE.
3352                     alias = value.attrib.get("alias")
3353                     if alias:
3354                         self.consts.append(VkConstant(value.attrib.get("name"), alias))
3355                     else:
3356                         self.consts.append(VkConstant(value.attrib.get("name"), value.attrib.get("value")))
3358         self.enums = OrderedDict(sorted(enums.items()))
3360     def _process_require_enum(self, enum_elem, ext=None, only_aliased=False):
3361         if "extends" in enum_elem.keys():
3362             enum = self.types[enum_elem.attrib["extends"]]["data"]
3364             # Need to define VkEnumValues which were aliased to by another value. This is necessary
3365             # from VK spec version 1.2.135 where the provisional VK_KHR_ray_tracing extension was
3366             # added which altered VK_NV_ray_tracing's VkEnumValues to alias to the provisional
3367             # extension.
3368             aliased = False
3369             for _, t in self.types.items():
3370                 if t["category"] != "enum":
3371                     continue
3372                 if not t["data"]:
3373                     continue
3374                 for value in t["data"].values:
3375                     if value.alias == enum_elem.attrib["name"]:
3376                         aliased = True
3378             if only_aliased and not aliased:
3379                 return
3381             if "bitpos" in enum_elem.keys():
3382                 # We need to add an extra value to an existing enum type.
3383                 # E.g. VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG to VkFormatFeatureFlagBits.
3384                 enum.create_bitpos(enum_elem.attrib["name"], int(enum_elem.attrib["bitpos"]))
3386             elif "offset" in enum_elem.keys():
3387                 # Extensions promoted to Core, have the extension number as part
3388                 # of the enum value. Else retrieve from the extension tag.
3389                 if enum_elem.attrib.get("extnumber"):
3390                     ext_number = int(enum_elem.attrib.get("extnumber"))
3391                 else:
3392                     ext_number = int(ext.attrib["number"])
3393                 offset = int(enum_elem.attrib["offset"])
3394                 value = EXT_BASE + (ext_number - 1) * EXT_BLOCK_SIZE + offset
3396                 # Deal with negative values.
3397                 direction = enum_elem.attrib.get("dir")
3398                 if direction is not None:
3399                     value = -value
3401                 enum.create_value(enum_elem.attrib["name"], str(value))
3403             elif "value" in enum_elem.keys():
3404                 enum.create_value(enum_elem.attrib["name"], enum_elem.attrib["value"])
3405             elif "alias" in enum_elem.keys():
3406                 enum.create_alias(enum_elem.attrib["name"], enum_elem.attrib["alias"])
3408         elif "value" in enum_elem.keys():
3409             # Constants are not aliased, no need to add them here, they'll get added later on.
3410             if only_aliased:
3411                 return
3413             self.consts.append(VkConstant(enum_elem.attrib["name"], enum_elem.attrib["value"]))
3415     @staticmethod
3416     def _require_type(type_info):
3417         if type_info.is_alias():
3418             type_info = type_info.alias
3419         type_info.required = True
3420         if type(type_info) == VkStruct:
3421             for member in type_info.members:
3422                 if "data" in member.type_info:
3423                   VkRegistry._require_type(member.type_info["data"])
3425     def _parse_extensions(self, root):
3426         """ Parse extensions section and pull in any types and commands for this extension. """
3427         extensions = []
3428         exts = root.findall("./extensions/extension")
3429         deferred_exts = []
3430         skipped_exts = UNSUPPORTED_EXTENSIONS.copy()
3432         def process_ext(ext, deferred=False):
3433             ext_name = ext.attrib["name"]
3435             # Set extension name on any functions calls part of this extension as we
3436             # were not aware of the name during initial parsing.
3437             commands = ext.findall("require/command")
3438             for command in commands:
3439                 cmd_name = command.attrib["name"]
3440                 # Need to verify that the command is defined, and otherwise skip it.
3441                 # vkCreateScreenSurfaceQNX is declared in <extensions> but not defined in
3442                 # <commands>. A command without a definition cannot be enabled, so it's valid for
3443                 # the XML file to handle this, but because of the manner in which we parse the XML
3444                 # file we pre-populate from <commands> before we check if a command is enabled.
3445                 if cmd_name in self.funcs:
3446                     self.funcs[cmd_name].extensions.append(ext_name)
3448             # Some extensions are not ready or have numbers reserved as a place holder.
3449             if ext.attrib["supported"] == "disabled":
3450                 LOGGER.debug("Skipping disabled extension: {0}".format(ext_name))
3451                 skipped_exts.append(ext_name)
3452                 return
3454             # Defer extensions with 'sortorder' as they are order-dependent for spec-parsing.
3455             if not deferred and "sortorder" in ext.attrib:
3456                 deferred_exts.append(ext)
3457                 return
3459             # Disable highly experimental extensions as the APIs are unstable and can
3460             # change between minor Vulkan revisions until API is final and becomes KHR
3461             # or NV.
3462             if ("KHX" in ext_name or "NVX" in ext_name) and ext_name not in ALLOWED_X_EXTENSIONS:
3463                 LOGGER.debug("Skipping experimental extension: {0}".format(ext_name))
3464                 skipped_exts.append(ext_name)
3465                 return
3467             # Extensions can define VkEnumValues which alias to provisional extensions. Pre-process
3468             # extensions to define any required VkEnumValues before the platform check below.
3469             for require in ext.findall("require"):
3470                 # Extensions can add enum values to Core / extension enums, so add these.
3471                 for enum_elem in require.findall("enum"):
3472                     self._process_require_enum(enum_elem, ext, only_aliased=True)
3474             platform = ext.attrib.get("platform")
3475             if platform and platform != "win32":
3476                 LOGGER.debug("Skipping extensions {0} for platform {1}".format(ext_name, platform))
3477                 skipped_exts.append(ext_name)
3478                 return
3480             if not self._is_extension_supported(ext_name):
3481                 LOGGER.debug("Skipping unsupported extension: {0}".format(ext_name))
3482                 skipped_exts.append(ext_name)
3483                 return
3484             elif "requires" in ext.attrib:
3485                 # Check if this extension builds on top of another unsupported extension.
3486                 requires = ext.attrib["requires"].split(",")
3487                 if len(set(requires).intersection(skipped_exts)) > 0:
3488                     skipped_exts.append(ext_name)
3489                     return
3491             LOGGER.debug("Loading extension: {0}".format(ext_name))
3493             # Extensions can define one or more require sections each requiring
3494             # different features (e.g. Vulkan 1.1). Parse each require section
3495             # separately, so we can skip sections we don't want.
3496             for require in ext.findall("require"):
3497                 # Extensions can add enum values to Core / extension enums, so add these.
3498                 for enum_elem in require.findall("enum"):
3499                     self._process_require_enum(enum_elem, ext)
3501                 for t in require.findall("type"):
3502                     type_info = self.types[t.attrib["name"]]["data"]
3503                     self._require_type(type_info)
3504                 feature = require.attrib.get("feature")
3505                 if feature and not self._is_feature_supported(feature):
3506                     continue
3508                 required_extension = require.attrib.get("extension")
3509                 if required_extension and not self._is_extension_supported(required_extension):
3510                     continue
3512                 # Pull in any commands we need. We infer types to pull in from the command
3513                 # as well.
3514                 for command in require.findall("command"):
3515                     cmd_name = command.attrib["name"]
3516                     self._mark_command_required(cmd_name)
3519             # Store a list with extensions.
3520             ext_info = {"name" : ext_name, "type" : ext.attrib["type"]}
3521             extensions.append(ext_info)
3524         # Process extensions, allowing for sortorder to defer extension processing
3525         for ext in exts:
3526             process_ext(ext)
3528         deferred_exts.sort(key=lambda ext: ext.attrib["sortorder"])
3530         # Respect sortorder
3531         for ext in deferred_exts:
3532             process_ext(ext, deferred=True)
3534         # Sort in alphabetical order.
3535         self.extensions = sorted(extensions, key=lambda ext: ext["name"])
3537     def _parse_features(self, root):
3538         """ Parse the feature section, which describes Core commands and types needed. """
3540         for feature in root.findall("./feature"):
3541             feature_name = feature.attrib["name"]
3542             for require in feature.findall("require"):
3543                 LOGGER.info("Including features for {0}".format(require.attrib.get("comment")))
3544                 for tag in require:
3545                     if tag.tag == "comment":
3546                         continue
3547                     elif tag.tag == "command":
3548                         if not self._is_feature_supported(feature_name):
3549                             continue
3550                         name = tag.attrib["name"]
3551                         self._mark_command_required(name)
3552                     elif tag.tag == "enum":
3553                         self._process_require_enum(tag)
3554                     elif tag.tag == "type":
3555                         name = tag.attrib["name"]
3557                         # Skip pull in for vk_platform.h for now.
3558                         if name == "vk_platform":
3559                             continue
3561                         type_info = self.types[name]
3562                         type_info["data"].required = True
3564     def _parse_types(self, root):
3565         """ Parse types section, which contains all data types e.g. structs, typedefs etcetera. """
3566         types = root.findall("./types/type")
3568         base_types = []
3569         bitmasks = []
3570         defines = []
3571         funcpointers = []
3572         handles = []
3573         structs = []
3575         alias_types = []
3576         for t in types:
3577             type_info = {}
3578             type_info["category"] = t.attrib.get("category", None)
3579             type_info["requires"] = t.attrib.get("requires", None)
3581             # We parse aliases in a second pass when we know more.
3582             alias = t.attrib.get("alias")
3583             if alias:
3584                 LOGGER.debug("Alias found: {0}".format(alias))
3585                 alias_types.append(t)
3586                 continue
3588             if type_info["category"] in ["include"]:
3589                 continue
3591             if type_info["category"] == "basetype":
3592                 name = t.find("name").text
3593                 _type = None
3594                 if not t.find("type") is None:
3595                     _type = t.find("type").text
3596                 basetype = VkBaseType(name, _type)
3597                 base_types.append(basetype)
3598                 type_info["data"] = basetype
3600             # Basic C types don't need us to define them, but we do need data for them
3601             if type_info["requires"] == "vk_platform":
3602                 requires = type_info["requires"]
3603                 basic_c = VkBaseType(name, _type, requires=requires)
3604                 type_info["data"] = basic_c
3606             if type_info["category"] == "bitmask":
3607                 name = t.find("name").text
3608                 _type = t.find("type").text
3610                 # Most bitmasks have a requires attribute used to pull in
3611                 # required '*FlagBits" enum.
3612                 requires = type_info["requires"]
3613                 bitmask = VkBaseType(name, _type, requires=requires)
3614                 bitmasks.append(bitmask)
3615                 type_info["data"] = bitmask
3617             if type_info["category"] == "define":
3618                 define = VkDefine.from_xml(t)
3619                 defines.append(define)
3620                 type_info["data"] = define
3622             if type_info["category"] == "enum":
3623                 name = t.attrib.get("name")
3624                 # The type section only contains enum names, not the actual definition.
3625                 # Since we already parsed the enum before, just link it in.
3626                 try:
3627                     type_info["data"] = self.enums[name]
3628                 except KeyError as e:
3629                     # Not all enums seem to be defined yet, typically that's for
3630                     # ones ending in 'FlagBits' where future extensions may add
3631                     # definitions.
3632                     type_info["data"] = None
3634             if type_info["category"] == "funcpointer":
3635                 funcpointer = VkFunctionPointer.from_xml(t)
3636                 funcpointers.append(funcpointer)
3637                 type_info["data"] = funcpointer
3639             if type_info["category"] == "handle":
3640                 handle = VkHandle.from_xml(t)
3641                 handles.append(handle)
3642                 type_info["data"] = handle
3644             if type_info["category"] in ["struct", "union"]:
3645                 # We store unions among structs as some structs depend
3646                 # on unions. The types are very similar in parsing and
3647                 # generation anyway. The official Vulkan scripts use
3648                 # a similar kind of hack.
3649                 struct = VkStruct.from_xml(t)
3650                 structs.append(struct)
3651                 type_info["data"] = struct
3653             # Name is in general within a name tag else it is an optional
3654             # attribute on the type tag.
3655             name_elem = t.find("name")
3656             if name_elem is not None:
3657                 type_info["name"] = name_elem.text
3658             else:
3659                 type_info["name"] = t.attrib.get("name", None)
3661             # Store all type data in a shared dictionary, so we can easily
3662             # look up information for a given type. There are no duplicate
3663             # names.
3664             self.types[type_info["name"]] = type_info
3666         # Second pass for alias types, so we can retrieve all data from
3667         # the aliased object.
3668         for t in alias_types:
3669             type_info = {}
3670             type_info["category"] = t.attrib.get("category")
3671             type_info["name"] = t.attrib.get("name")
3673             alias = t.attrib.get("alias")
3675             if type_info["category"] == "bitmask":
3676                 bitmask = VkBaseType(type_info["name"], alias, alias=self.types[alias]["data"])
3677                 bitmasks.append(bitmask)
3678                 type_info["data"] = bitmask
3680             if type_info["category"] == "enum":
3681                 enum = VkEnum.from_alias(t, self.types[alias]["data"])
3682                 type_info["data"] = enum
3683                 self.enums[enum.name] = enum
3685             if type_info["category"] == "handle":
3686                 handle = VkHandle.from_alias(t, self.types[alias]["data"])
3687                 handles.append(handle)
3688                 type_info["data"] = handle
3690             if type_info["category"] == "struct":
3691                 struct = VkStruct.from_alias(t, self.types[alias]["data"])
3692                 structs.append(struct)
3693                 type_info["data"] = struct
3695             self.types[type_info["name"]] = type_info
3697         # We need detailed type information during code generation
3698         # on structs for alignment reasons. Unfortunately structs
3699         # are parsed among other types, so there is no guarantee
3700         # that any types needed have been parsed already, so set
3701         # the data now.
3702         for struct in structs:
3703             struct.set_type_info(self.types)
3705             # Alias structures have enum values equivalent to those of the
3706             # structure which they are aliased against. we need to ignore alias
3707             # structs when populating the struct extensions list, otherwise we
3708             # will create duplicate case entries.
3709             if struct.alias:
3710                 continue
3712             for structextend in struct.structextends:
3713                 s = self.types[structextend]["data"]
3714                 s.struct_extensions.append(struct)
3716         # Guarantee everything is sorted, so code generation doesn't have
3717         # to deal with this.
3718         self.base_types = sorted(base_types, key=lambda base_type: base_type.name)
3719         self.bitmasks = sorted(bitmasks, key=lambda bitmask: bitmask.name)
3720         self.defines = defines
3721         self.enums = OrderedDict(sorted(self.enums.items()))
3722         self.funcpointers = sorted(funcpointers, key=lambda fp: fp.name)
3723         self.handles = sorted(handles, key=lambda handle: handle.name)
3724         self.structs = sorted(structs, key=lambda struct: struct.name)
3726 def generate_vulkan_json(f):
3727     f.write("{\n")
3728     f.write("    \"file_format_version\": \"1.0.0\",\n")
3729     f.write("    \"ICD\": {\n")
3730     f.write("        \"library_path\": \".\\\\winevulkan.dll\",\n")
3731     f.write("        \"api_version\": \"{0}\"\n".format(VK_XML_VERSION))
3732     f.write("    }\n")
3733     f.write("}\n")
3735 def set_working_directory():
3736     path = os.path.abspath(__file__)
3737     path = os.path.dirname(path)
3738     os.chdir(path)
3740 def download_vk_xml(filename):
3741     url = "https://raw.githubusercontent.com/KhronosGroup/Vulkan-Docs/v{0}/xml/vk.xml".format(VK_XML_VERSION)
3742     if not os.path.isfile(filename):
3743         urllib.request.urlretrieve(url, filename)
3745 def main():
3746     parser = argparse.ArgumentParser()
3747     parser.add_argument("-v", "--verbose", action="count", default=0, help="increase output verbosity")
3748     parser.add_argument("-x", "--xml", default=None, type=str, help="path to specification XML file")
3750     args = parser.parse_args()
3751     if args.verbose == 0:
3752         LOGGER.setLevel(logging.WARNING)
3753     elif args.verbose == 1:
3754         LOGGER.setLevel(logging.INFO)
3755     else: # > 1
3756         LOGGER.setLevel(logging.DEBUG)
3758     set_working_directory()
3760     if args.xml:
3761         vk_xml = args.xml
3762     else:
3763         vk_xml = "vk-{0}.xml".format(VK_XML_VERSION)
3764         download_vk_xml(vk_xml)
3766     registry = VkRegistry(vk_xml)
3767     generator = VkGenerator(registry)
3769     with open(WINE_VULKAN_H, "w") as f:
3770         generator.generate_vulkan_h(f)
3772     with open(WINE_VULKAN_DRIVER_H, "w") as f:
3773         generator.generate_vulkan_driver_h(f)
3775     with open(WINE_VULKAN_THUNKS_H, "w") as f:
3776         generator.generate_thunks_h(f, "wine_")
3778     with open(WINE_VULKAN_THUNKS_C, "w") as f:
3779         generator.generate_thunks_c(f, "wine_")
3781     with open(WINE_VULKAN_LOADER_THUNKS_H, "w") as f:
3782         generator.generate_loader_thunks_h(f)
3784     with open(WINE_VULKAN_LOADER_THUNKS_C, "w") as f:
3785         generator.generate_loader_thunks_c(f)
3787     with open(WINE_VULKAN_JSON, "w") as f:
3788         generate_vulkan_json(f)
3790     with open(WINE_VULKAN_SPEC, "w") as f:
3791         generator.generate_vulkan_spec(f)
3793     with open(WINE_VULKAN_LOADER_SPEC, "w") as f:
3794         generator.generate_vulkan_loader_spec(f)
3796 if __name__ == "__main__":
3797     main()