wined3d: Pass a wined3d_device_context to wined3d_cs_emit_blt_sub_resource().
[wine/zf.git] / dlls / winevulkan / make_vulkan
blobc30beee981d93e6d273a2798796d40c3e84f79a1
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.170"
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"
79 # Extension enum values start at a certain offset (EXT_BASE).
80 # Relative to the offset each extension has a block (EXT_BLOCK_SIZE)
81 # of values.
82 # Start for a given extension is:
83 # EXT_BASE + (extension_number-1) * EXT_BLOCK_SIZE
84 EXT_BASE = 1000000000
85 EXT_BLOCK_SIZE = 1000
87 UNSUPPORTED_EXTENSIONS = [
88     # Instance extensions
89     "VK_EXT_headless_surface", # Needs WSI work.
90     "VK_KHR_display", # Needs WSI work.
91     "VK_KHR_surface_protected_capabilities",
93     # Device extensions
94     "VK_AMD_display_native_hdr",
95     "VK_EXT_full_screen_exclusive",
96     "VK_EXT_hdr_metadata", # Needs WSI work.
97     "VK_EXT_pipeline_creation_feedback",
98     "VK_GOOGLE_display_timing",
99     "VK_KHR_external_fence_win32",
100     "VK_KHR_external_memory_win32",
101     "VK_KHR_external_semaphore_win32",
102     # Relates to external_semaphore and needs type conversions in bitflags.
103     "VK_KHR_shared_presentable_image", # Needs WSI work.
104     "VK_KHR_win32_keyed_mutex",
106     # Extensions for other platforms
107     "VK_EXT_external_memory_dma_buf",
108     "VK_EXT_image_drm_format_modifier",
109     "VK_KHR_external_fence_fd",
110     "VK_KHR_external_memory_fd",
111     "VK_KHR_external_semaphore_fd",
113     # Extensions which require callback handling
114     "VK_EXT_device_memory_report",
116     # Deprecated extensions
117     "VK_NV_external_memory_capabilities",
118     "VK_NV_external_memory_win32",
121 # The Vulkan loader provides entry-points for core functionality and important
122 # extensions. Based on vulkan-1.def this amounts to WSI extensions on 1.0.51.
123 CORE_EXTENSIONS = [
124     "VK_KHR_display",
125     "VK_KHR_display_swapchain",
126     "VK_KHR_get_surface_capabilities2",
127     "VK_KHR_surface",
128     "VK_KHR_swapchain",
129     "VK_KHR_win32_surface",
132 # Functions part of our winevulkan graphics driver interface.
133 # DRIVER_VERSION should be bumped on any change to driver interface
134 # in FUNCTION_OVERRIDES
135 DRIVER_VERSION = 10
137 # Table of functions for which we have a special implementation.
138 # These are regular device / instance functions for which we need
139 # to do more work compared to a regular thunk or because they are
140 # part of the driver interface.
141 # - dispatch set whether we need a function pointer in the device
142 #   / instance dispatch table.
143 # - driver sets whether the API is part of the driver interface.
144 # - thunk sets whether to create a thunk in vulkan_thunks.c.
145 FUNCTION_OVERRIDES = {
146     # Global functions
147     "vkCreateInstance" : {"dispatch" : False, "driver" : True, "thunk" : False},
148     "vkEnumerateInstanceExtensionProperties" : {"dispatch" : False, "driver" : True, "thunk" : False},
149     "vkEnumerateInstanceVersion": {"dispatch" : False, "driver" : False, "thunk" : False},
150     "vkGetInstanceProcAddr": {"dispatch" : False, "driver" : True, "thunk" : False},
152     # Instance functions
153     "vkCreateDevice" : {"dispatch" : True, "driver" : False, "thunk" : False},
154     "vkDestroyInstance" : {"dispatch" : False, "driver" : True, "thunk" : False },
155     "vkEnumerateDeviceExtensionProperties" : {"dispatch" : True, "driver" : False, "thunk" : False},
156     "vkEnumerateDeviceLayerProperties": {"dispatch": True, "driver": False, "thunk": False},
157     "vkEnumeratePhysicalDeviceGroups" : {"dispatch" : True, "driver" : False, "thunk" : False},
158     "vkEnumeratePhysicalDevices" : {"dispatch" : True, "driver" : False, "thunk" : False},
159     "vkGetPhysicalDeviceExternalBufferProperties" : {"dispatch" : False, "driver" : False, "thunk" : False},
160     "vkGetPhysicalDeviceExternalFenceProperties" : {"dispatch" : False, "driver" : False, "thunk" : False},
161     "vkGetPhysicalDeviceExternalSemaphoreProperties" : {"dispatch" : False, "driver" : False, "thunk" : False},
162     "vkGetPhysicalDeviceImageFormatProperties2" : {"dispatch" : True, "driver" : False, "thunk" : True, "private_thunk" : True},
163     "vkGetPhysicalDeviceProperties2" : {"dispatch" : True, "driver" : False, "thunk" : True, "private_thunk" : True},
164     "vkGetPhysicalDeviceProperties2KHR" : {"dispatch" : True, "driver" : False, "thunk" : True, "private_thunk" : True},
166     # Device functions
167     "vkAllocateCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : False},
168     "vkCmdExecuteCommands" : {"dispatch" : True, "driver" : False, "thunk" : False},
169     "vkCreateCommandPool" : {"dispatch": True, "driver" : False, "thunk" : False},
170     "vkDestroyCommandPool" : {"dispatch": True, "driver" : False, "thunk" : False},
171     "vkDestroyDevice" : {"dispatch" : True, "driver" : False, "thunk" : False},
172     "vkFreeCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : False},
173     "vkGetDeviceProcAddr" : {"dispatch" : False, "driver" : True, "thunk" : False},
174     "vkGetDeviceQueue" : {"dispatch": True, "driver" : False, "thunk" : False},
175     "vkGetDeviceQueue2" : {"dispatch": True, "driver" : False, "thunk" : False},
176     "vkQueueSubmit" : {"dispatch": True, "driver" : False, "thunk" : False},
178     # VK_KHR_surface
179     "vkDestroySurfaceKHR" : {"dispatch" : True, "driver" : True, "thunk" : False},
180     "vkGetPhysicalDeviceSurfaceSupportKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
181     "vkGetPhysicalDeviceSurfaceCapabilitiesKHR" : {"dispatch" : True, "driver" : True, "thunk" : False, "private_thunk" : True},
182     "vkGetPhysicalDeviceSurfaceFormatsKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
183     "vkGetPhysicalDeviceSurfacePresentModesKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
185     # VK_KHR_get_surface_capabilities2
186     "vkGetPhysicalDeviceSurfaceCapabilities2KHR" : {"dispatch" : True, "driver" : True, "thunk" : False, "private_thunk" : True},
187     "vkGetPhysicalDeviceSurfaceFormats2KHR" : {"dispatch" : True, "driver" : True, "thunk" : False, "private_thunk" : True},
189     # VK_KHR_win32_surface
190     "vkCreateWin32SurfaceKHR" : {"dispatch" : True, "driver" : True, "thunk" : False},
191     "vkGetPhysicalDeviceWin32PresentationSupportKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
193     # VK_KHR_swapchain
194     "vkCreateSwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : False, "private_thunk" : True},
195     "vkDestroySwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
196     "vkGetSwapchainImagesKHR": {"dispatch" : True, "driver" : True, "thunk" : True},
197     "vkQueuePresentKHR": {"dispatch" : True, "driver" : True, "thunk" : True},
199     # VK_KHR_external_fence_capabilities
200     "vkGetPhysicalDeviceExternalFencePropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : False},
202     # VK_KHR_external_memory_capabilities
203     "vkGetPhysicalDeviceExternalBufferPropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : False},
204     "vkGetPhysicalDeviceImageFormatProperties2KHR" : {"dispatch" : True, "driver" : False, "thunk" : True, "private_thunk" : True},
206     # VK_KHR_external_semaphore_capabilities
207     "vkGetPhysicalDeviceExternalSemaphorePropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : False},
209     # VK_KHR_device_group_creation
210     "vkEnumeratePhysicalDeviceGroupsKHR" : {"dispatch" : True, "driver" : False, "thunk" : False},
212     # VK_KHR_device_group
213     "vkGetDeviceGroupSurfacePresentModesKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
214     "vkGetPhysicalDevicePresentRectanglesKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
216     # VK_EXT_private_data
217     "vkGetPrivateDataEXT" : {"dispatch": True, "driver" : False, "thunk" : False},
218     "vkSetPrivateDataEXT" : {"dispatch": True, "driver" : False, "thunk" : False},
220     # VK_EXT_calibrated_timestamps
221     "vkGetPhysicalDeviceCalibrateableTimeDomainsEXT" : {"dispatch" : True, "driver" : False, "thunk" : False},
222     "vkGetCalibratedTimestampsEXT" : {"dispatch" : True, "driver" : False, "thunk" : False},
224     # VK_EXT_debug_utils
225     "vkCreateDebugUtilsMessengerEXT" : {"dispatch": True, "driver" : False, "thunk" : False},
226     "vkDestroyDebugUtilsMessengerEXT" : {"dispatch": True, "driver" : False, "thunk" : False},
227     "vkSubmitDebugUtilsMessageEXT" : {"dispatch": True, "driver" : False, "thunk" : True, "private_thunk" : True},
228     "vkSetDebugUtilsObjectTagEXT" : {"dispatch": True, "driver" : False, "thunk" : True, "private_thunk" : True},
229     "vkSetDebugUtilsObjectNameEXT" : {"dispatch": True, "driver" : False, "thunk" : True, "private_thunk" : True},
231     # VK_EXT_debug_report
232     "vkCreateDebugReportCallbackEXT" : {"dispatch": True, "driver" : False, "thunk" : False},
233     "vkDestroyDebugReportCallbackEXT" : {"dispatch": True, "driver" : False, "thunk" : False},
234     "vkDebugReportMessageEXT" : {"dispatch": True, "driver" : False, "thunk" : False},
236     # VK_EXT_debug_marker
237     "vkDebugMarkerSetObjectNameEXT" : {"dispatch": True, "driver" : False, "thunk" : True, "private_thunk" : True},
238     "vkDebugMarkerSetObjectTagEXT" : {"dispatch": True, "driver" : False, "thunk" : True, "private_thunk" : True},
241 STRUCT_CHAIN_CONVERSIONS = [
242     "VkDeviceCreateInfo",
243     "VkInstanceCreateInfo",
247 class Direction(Enum):
248     """ Parameter direction: input, output, input_output. """
249     INPUT = 1
250     OUTPUT = 2
251     INPUT_OUTPUT = 3
254 class VkBaseType(object):
255     def __init__(self, name, _type, alias=None, requires=None):
256         """ Vulkan base type class.
258         VkBaseType is mostly used by Vulkan to define its own
259         base types like VkFlags through typedef out of e.g. uint32_t.
261         Args:
262             name (:obj:'str'): Name of the base type.
263             _type (:obj:'str'): Underlying type
264             alias (bool): type is an alias or not.
265             requires (:obj:'str', optional): Other types required.
266                 Often bitmask values pull in a *FlagBits type.
267         """
268         self.name = name
269         self.type = _type
270         self.alias = alias
271         self.requires = requires
272         self.required = False
274     def definition(self):
275         # Definition is similar for alias or non-alias as type
276         # is already set to alias.
277         if not self.type is None:
278             return "typedef {0} {1};\n".format(self.type, self.name)
279         else:
280             return "struct {0};\n".format(self.name)
282     def is_alias(self):
283         return bool(self.alias)
286 class VkConstant(object):
287     def __init__(self, name, value):
288         self.name = name
289         self.value = value
291     def definition(self):
292         text = "#define {0} {1}\n".format(self.name, self.value)
293         return text
296 class VkDefine(object):
297     def __init__(self, name, value):
298         self.name = name
299         self.value = value
301     @staticmethod
302     def from_xml(define):
303         name_elem = define.find("name")
305         if name_elem is None:
306             # <type category="define" name="some_name">some_value</type>
307             # At the time of writing there is only 1 define of this category
308             # 'VK_DEFINE_NON_DISPATCHABLE_HANDLE'.
309             name = define.attrib.get("name")
311             # We override behavior of VK_DEFINE_NON_DISPATCHABLE handle as the default
312             # definition various between 64-bit (uses pointers) and 32-bit (uses uint64_t).
313             # This complicates TRACEs in the thunks, so just use uint64_t.
314             if name == "VK_DEFINE_NON_DISPATCHABLE_HANDLE":
315                 value = "#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object;"
316             else:
317                 value = define.text
318             return VkDefine(name, value)
320         # With a name element the structure is like:
321         # <type category="define"><name>some_name</name>some_value</type>
322         name = name_elem.text
324         # Perform minimal parsing for Vulkan constants, which we don't need, but are referenced
325         # elsewhere in vk.xml.
326         # - VK_API_VERSION is a messy, deprecated constant and we don't want generate code for it.
327         # - AHardwareBuffer/ANativeWindow are forward declarations for Android types, which leaked
328         #   into the define region.
329         if name in ["VK_API_VERSION", "AHardwareBuffer", "ANativeWindow", "CAMetalLayer"]:
330             return VkDefine(name, None)
332         # The body of the define is basically unstructured C code. It is not meant for easy parsing.
333         # Some lines contain deprecated values or comments, which we try to filter out.
334         value = ""
335         for line in define.text.splitlines():
336             # Skip comments or deprecated values.
337             if "//" in line:
338                 continue
339             value += line
341         for child in define:
342             value += child.text
343             if child.tail is not None:
344                 # Split comments for VK_API_VERSION_1_0 / VK_API_VERSION_1_1
345                 if "//" in child.tail:
346                     value += child.tail.split("//")[0]
347                 else:
348                     value += child.tail
350         return VkDefine(name, value.rstrip(' '))
352     def definition(self):
353         if self.value is None:
354             return ""
356         # Nothing to do as the value was already put in the right form during parsing.
357         return "{0}\n".format(self.value)
360 class VkEnum(object):
361     def __init__(self, name, bitwidth, alias=None):
362         if not bitwidth in [32, 64]:
363             LOGGER.error("unknown bitwidth {0} for {1}".format(bitwidth, name))
364         self.name = name
365         self.bitwidth = bitwidth
366         self.values = [] if alias == None else alias.values
367         self.required = False
368         self.alias = alias
369         self.aliased_by = []
371     @staticmethod
372     def from_alias(enum, alias):
373         name = enum.attrib.get("name")
374         aliasee = VkEnum(name, alias.bitwidth, alias=alias)
376         alias.add_aliased_by(aliasee)
377         return aliasee
379     @staticmethod
380     def from_xml(enum):
381         name = enum.attrib.get("name")
382         bitwidth = int(enum.attrib.get("bitwidth", "32"))
383         result = VkEnum(name, bitwidth)
385         for v in enum.findall("enum"):
386             value_name = v.attrib.get("name")
387             # Value is either a value or a bitpos, only one can exist.
388             value = v.attrib.get("value")
389             alias_name = v.attrib.get("alias")
390             if alias_name:
391                 result.create_alias(value_name, alias_name)
392             elif value:
393                 result.create_value(value_name, value)
394             else:
395                 # bitmask
396                 result.create_bitpos(value_name, int(v.attrib.get("bitpos")))
398         if bitwidth == 32:
399             # vulkan.h contains a *_MAX_ENUM value set to 32-bit at the time of writing,
400             # which is to prepare for extensions as they can add values and hence affect
401             # the size definition.
402             max_name = re.sub(r'([0-9a-z_])([A-Z0-9])',r'\1_\2', name).upper() + "_MAX_ENUM"
403             result.create_value(max_name, "0x7fffffff")
405         return result
407     def create_alias(self, name, alias_name):
408         """ Create an aliased value for this enum """
409         # Older GCC versions need a literal to initialize a static const uint64_t
410         # which is what we use for 64bit bitmasks.
411         if self.bitwidth == 64:
412             alias = next(x for x in self.values if x.name == alias_name)
413             self.add(VkEnumValue(name, self.bitwidth, value=alias.value, hex=alias.hex, alias=alias_name))
414         else:
415             self.add(VkEnumValue(name, self.bitwidth, alias=alias_name))
417     def create_value(self, name, value):
418         """ Create a new value for this enum """
419         # Some values are in hex form. We want to preserve the hex representation
420         # at least when we convert back to a string. Internally we want to use int.
421         hex = "0x" in value
422         self.add(VkEnumValue(name, self.bitwidth, value=int(value, 0), hex=hex))
424     def create_bitpos(self, name, pos):
425         """ Create a new bitmask value for this enum """
426         self.add(VkEnumValue(name, self.bitwidth, value=(1 << pos), hex=True))
428     def add(self, value):
429         """ Add a value to enum. """
431         # Extensions can add new enum values. When an extension is promoted to Core
432         # the registry defines the value twice once for old extension and once for
433         # new Core features. Add the duplicate if it's explicitly marked as an
434         # alias, otherwise ignore it.
435         for v in self.values:
436             if not value.is_alias() and v.value == value.value:
437                 LOGGER.debug("Adding duplicate enum value {0} to {1}".format(v, self.name))
438                 return
439         # Avoid adding duplicate aliases multiple times
440         if not any(x.name == value.name for x in self.values):
441             self.values.append(value)
443     def definition(self):
444         if self.is_alias():
445             return ""
447         default_value = 0x7ffffffe if self.bitwidth == 32 else 0xfffffffffffffffe
449         # Print values sorted, values can have been added in a random order.
450         values = sorted(self.values, key=lambda value: value.value if value.value is not None else default_value)
452         if self.bitwidth == 32:
453             text = "typedef enum {0}\n{{\n".format(self.name)
454             for value in values:
455                 text += "    {0},\n".format(value.definition())
456             text += "}} {0};\n".format(self.name)
457         elif self.bitwidth == 64:
458             text = "typedef VkFlags64 {0};\n\n".format(self.name)
459             for value in values:
460                 text += "static const {0} {1};\n".format(self.name, value.definition())
462         for aliasee in self.aliased_by:
463             text += "typedef {0} {1};\n".format(self.name, aliasee.name)
465         text += "\n"
466         return text
468     def is_alias(self):
469         return bool(self.alias)
471     def add_aliased_by(self, aliasee):
472         self.aliased_by.append(aliasee)
475 class VkEnumValue(object):
476     def __init__(self, name, bitwidth, value=None, hex=False, alias=None):
477         self.name = name
478         self.bitwidth = bitwidth
479         self.value = value
480         self.hex = hex
481         self.alias = alias
483     def __repr__(self):
484         postfix = "ull" if self.bitwidth == 64 else ""
485         if self.is_alias() and self.value == None:
486             return "{0}={1}".format(self.name, self.alias)
487         return "{0}={1}{2}".format(self.name, self.value, postfix)
489     def definition(self):
490         """ Convert to text definition e.g. VK_FOO = 1 """
491         postfix = "ull" if self.bitwidth == 64 else ""
492         if self.is_alias() and self.value == None:
493             return "{0} = {1}".format(self.name, self.alias)
495         # Hex is commonly used for FlagBits and sometimes within
496         # a non-FlagBits enum for a bitmask value as well.
497         if self.hex:
498             return "{0} = 0x{1:08x}{2}".format(self.name, self.value, postfix)
499         else:
500             return "{0} = {1}{2}".format(self.name, self.value, postfix)
502     def is_alias(self):
503         return self.alias is not None
506 class VkFunction(object):
507     def __init__(self, _type=None, name=None, params=[], extensions=[], alias=None):
508         self.extensions = []
509         self.name = name
510         self.type = _type
511         self.params = params
512         self.alias = alias
514         # For some functions we need some extra metadata from FUNCTION_OVERRIDES.
515         func_info = FUNCTION_OVERRIDES.get(self.name, None)
516         self.dispatch = func_info["dispatch"] if func_info else True
517         self.driver = func_info["driver"] if func_info else False
518         self.thunk_needed = func_info["thunk"] if func_info else True
519         self.private_thunk = func_info["private_thunk"] if func_info and "private_thunk" in func_info else False
520         if self.private_thunk:
521             self.thunk_needed = True
523         # Required is set while parsing which APIs and types are required
524         # and is used by the code generation.
525         self.required = True if func_info else False
527     @staticmethod
528     def from_alias(command, alias):
529         """ Create VkFunction from an alias command.
531         Args:
532             command: xml data for command
533             alias (VkFunction): function to use as a base for types / parameters.
535         Returns:
536             VkFunction
537         """
538         func_name = command.attrib.get("name")
539         func_type = alias.type
540         params = alias.params
542         return VkFunction(_type=func_type, name=func_name, params=params, alias=alias)
544     @staticmethod
545     def from_xml(command, types):
546         proto = command.find("proto")
547         func_name = proto.find("name").text
548         func_type = proto.find("type").text
550         params = []
551         for param in command.findall("param"):
552             vk_param = VkParam.from_xml(param, types)
553             params.append(vk_param)
555         return VkFunction(_type=func_type, name=func_name, params=params)
557     def get_conversions(self):
558         """ Get a list of conversion functions required for this function if any.
559         Parameters which are structures may require conversion between win32
560         and the host platform. This function returns a list of conversions
561         required.
562         """
564         conversions = []
565         for param in self.params:
566             convs = param.get_conversions()
567             if convs is not None:
568                 conversions.extend(convs)
570         return conversions
572     def is_alias(self):
573         return bool(self.alias)
575     def is_core_func(self):
576         """ Returns whether the function is a Vulkan core function.
577         Core functions are APIs defined by the Vulkan spec to be part of the
578         Core API as well as several KHR WSI extensions.
579         """
581         if not self.extensions:
582             return True
584         return any(ext in self.extensions for ext in CORE_EXTENSIONS)
586     def is_device_func(self):
587         # If none of the other, it must be a device function
588         return not self.is_global_func() and not self.is_instance_func() and not self.is_phys_dev_func()
590     def is_driver_func(self):
591         """ Returns if function is part of Wine driver interface. """
592         return self.driver
594     def is_global_func(self):
595         # Treat vkGetInstanceProcAddr as a global function as it
596         # can operate with NULL for vkInstance.
597         if self.name == "vkGetInstanceProcAddr":
598             return True
599         # Global functions are not passed a dispatchable object.
600         elif self.params[0].is_dispatchable():
601             return False
602         return True
604     def is_instance_func(self):
605         # Instance functions are passed VkInstance.
606         if self.params[0].type == "VkInstance":
607             return True
608         return False
610     def is_phys_dev_func(self):
611         # Physical device functions are passed VkPhysicalDevice.
612         if self.params[0].type == "VkPhysicalDevice":
613             return True
614         return False
616     def is_required(self):
617         return self.required
619     def needs_conversion(self):
620         """ Check if the function needs any input/output type conversion.
621         Functions need input/output conversion if struct parameters have
622         alignment differences between Win32 and Linux 32-bit.
623         """
625         for p in self.params:
626             if p.needs_conversion():
627                 LOGGER.debug("Parameter {0} to {1} requires conversion".format(p.name, self.name))
628                 return True
630         return False
632     def needs_dispatch(self):
633         return self.dispatch
635     def needs_thunk(self):
636         return self.thunk_needed
638     def needs_private_thunk(self):
639         return self.private_thunk
641     def pfn(self, prefix="p", call_conv=None, conv=False):
642         """ Create function pointer. """
644         if call_conv:
645             pfn = "{0} ({1} *{2}_{3})(".format(self.type, call_conv, prefix, self.name)
646         else:
647             pfn = "{0} (*{1}_{2})(".format(self.type, prefix, self.name)
649         for i, param in enumerate(self.params):
650             if param.const:
651                 pfn += param.const + " "
653             pfn += param.type
654             if conv and param.needs_conversion():
655                 pfn += "_host"
657             if param.is_pointer():
658                 pfn += " " + param.pointer
660             if param.array_len is not None:
661                 pfn += "[{0}]".format(param.array_len)
663             if i < len(self.params) - 1:
664                 pfn += ", "
665         pfn += ")"
666         return pfn
668     def prototype(self, call_conv=None, prefix=None, postfix=None):
669         """ Generate prototype for given function.
671         Args:
672             call_conv (str, optional): calling convention e.g. WINAPI
673             prefix (str, optional): prefix to append prior to function name e.g. vkFoo -> wine_vkFoo
674             postfix (str, optional): text to append after function name but prior to semicolon e.g. DECLSPEC_HIDDEN
675         """
677         proto = "{0}".format(self.type)
679         if call_conv is not None:
680             proto += " {0}".format(call_conv)
682         if prefix is not None:
683             proto += " {0}{1}(".format(prefix, self.name)
684         else:
685             proto += " {0}(".format(self.name)
687         # Add all the parameters.
688         proto += ", ".join([p.definition() for p in self.params])
690         if postfix is not None:
691             proto += ") {0}".format(postfix)
692         else:
693             proto += ")"
695         return proto
697     def body(self):
698         body = ""
700         if not self.needs_private_thunk():
701             body += "    {0}".format(self.trace())
703         params = ", ".join([p.variable(conv=False) for p in self.params])
705         # Call the native Vulkan function.
706         if self.type == "void":
707             body += "    {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
708         else:
709             body += "    return {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
711         return body
713     def body_conversion(self):
714         body = ""
716         # Declare a variable to hold the result for non-void functions.
717         if self.type != "void":
718             body += "    {0} result;\n".format(self.type)
720         # Declare any tmp parameters for conversion.
721         for p in self.params:
722             if not p.needs_conversion():
723                 continue
725             if p.is_dynamic_array():
726                 body += "    {0}_host *{1}_host;\n".format(p.type, p.name)
727             else:
728                 body += "    {0}_host {1}_host;\n".format(p.type, p.name)
730         if not self.needs_private_thunk():
731             body += "    {0}\n".format(self.trace())
733         # Call any win_to_host conversion calls.
734         for p in self.params:
735             if not p.needs_input_conversion():
736                 continue
738             body += p.copy(Direction.INPUT)
740         # Build list of parameters containing converted and non-converted parameters.
741         # The param itself knows if conversion is needed and applies it when we set conv=True.
742         params = ", ".join([p.variable(conv=True) for p in self.params])
744         # Call the native Vulkan function.
745         if self.type == "void":
746             body += "    {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
747         else:
748             body += "    result = {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
750         body += "\n"
752         # Call any host_to_win conversion calls.
753         for p in self.params:
754             if not p.needs_output_conversion():
755                 continue
757             body += p.copy(Direction.OUTPUT)
759         # Perform any required cleanups. Most of these are for array functions.
760         for p in self.params:
761             if not p.needs_free():
762                 continue
764             body += p.free()
766         # Finally return the result.
767         if self.type != "void":
768             body += "    return result;\n"
770         return body
772     def spec(self, prefix=None, symbol=None):
773         """ Generate spec file entry for this function.
775         Args
776             prefix (str, optional): prefix to prepend to entry point name.
777             symbol (str, optional): allows overriding the name of the function implementing the entry point.
778         """
780         spec = ""
781         params = " ".join([p.spec() for p in self.params])
782         if prefix is not None:
783             spec += "@ stdcall -private {0}{1}({2})".format(prefix, self.name, params)
784         else:
785             spec += "@ stdcall {0}({1})".format(self.name, params)
787         if symbol is not None:
788             spec += " " + symbol
790         spec += "\n"
791         return spec
793     def stub(self, call_conv=None, prefix=None):
794         stub = self.prototype(call_conv=call_conv, prefix=prefix)
795         stub += "\n{\n"
796         stub += "    {0}".format(self.trace(message="stub: ", trace_func="FIXME"))
798         if self.type == "VkResult":
799             stub += "    return VK_ERROR_OUT_OF_HOST_MEMORY;\n"
800         elif self.type == "VkBool32":
801             stub += "    return VK_FALSE;\n"
802         elif self.type == "PFN_vkVoidFunction":
803             stub += "    return NULL;\n"
805         stub += "}\n\n"
806         return stub
808     def thunk(self, call_conv=None, prefix=None):
809         thunk = self.prototype(call_conv=call_conv, prefix=prefix)
810         thunk += "\n{\n"
812         if self.needs_conversion():
813             thunk += "#if defined(USE_STRUCT_CONVERSION)\n"
814             thunk += self.body_conversion()
815             thunk += "#else\n"
816             thunk += self.body()
817             thunk += "#endif\n"
818         else:
819             thunk += self.body()
821         thunk += "}\n\n"
822         return thunk
824     def trace(self, message=None, trace_func=None):
825         """ Create a trace string including all parameters.
827         Args:
828             message (str, optional): text to print at start of trace message e.g. 'stub: '
829             trace_func (str, optional): used to override trace function e.g. FIXME, printf, etcetera.
830         """
831         if trace_func is not None:
832             trace = "{0}(\"".format(trace_func)
833         else:
834             trace = "TRACE(\""
836         if message is not None:
837             trace += message
839         # First loop is for all the format strings.
840         trace += ", ".join([p.format_string() for p in self.params])
841         trace += "\\n\""
843         # Second loop for parameter names and optional conversions.
844         for param in self.params:
845             if param.format_conv is not None:
846                 trace += ", " + param.format_conv.format(param.name)
847             else:
848                 trace += ", {0}".format(param.name)
849         trace += ");\n"
851         return trace
854 class VkFunctionPointer(object):
855     def __init__(self, _type, name, members, forward_decls):
856         self.name = name
857         self.members = members
858         self.type = _type
859         self.required = False
860         self.forward_decls = forward_decls
862     @staticmethod
863     def from_xml(funcpointer):
864         members = []
865         begin = None
867         for t in funcpointer.findall("type"):
868             # General form:
869             # <type>void</type>*       pUserData,
870             # Parsing of the tail (anything past </type>) is tricky since there
871             # can be other data on the next line like: const <type>int</type>..
873             const = True if begin and "const" in begin else False
874             _type = t.text
875             lines = t.tail.split(",\n")
876             if lines[0][0] == "*":
877                 pointer = "*"
878                 name = lines[0][1:].strip()
879             else:
880                 pointer = None
881                 name = lines[0].strip()
883             # Filter out ); if it is contained.
884             name = name.partition(");")[0]
886             # If tail encompasses multiple lines, assign the second line to begin
887             # for the next line.
888             try:
889                 begin = lines[1].strip()
890             except IndexError:
891                 begin = None
893             members.append(VkMember(const=const, _type=_type, pointer=pointer, name=name))
895         _type = funcpointer.text
896         name = funcpointer.find("name").text
897         if "requires" in funcpointer.attrib:
898             forward_decls = funcpointer.attrib.get("requires").split(",")
899         else:
900             forward_decls = []
901         return VkFunctionPointer(_type, name, members, forward_decls)
903     def definition(self):
904         text = ""
905         # forward declare required structs
906         for decl in self.forward_decls:
907             text += "typedef struct {0} {0};\n".format(decl)
909         text += "{0} {1})(\n".format(self.type, self.name)
911         first = True
912         if len(self.members) > 0:
913             for m in self.members:
914                 if first:
915                     text += "    " + m.definition()
916                     first = False
917                 else:
918                     text += ",\n    " + m.definition()
919         else:
920             # Just make the compiler happy by adding a void parameter.
921             text += "void"
922         text += ");\n"
923         return text
925     def is_alias(self):
926         return False
928 class VkHandle(object):
929     def __init__(self, name, _type, parent, alias=None):
930         self.name = name
931         self.type = _type
932         self.parent = parent
933         self.alias = alias
934         self.required = False
935         self.object_type = None
937     @staticmethod
938     def from_alias(handle, alias):
939         name = handle.attrib.get("name")
940         return VkHandle(name, alias.type, alias.parent, alias=alias)
942     @staticmethod
943     def from_xml(handle):
944         name = handle.find("name").text
945         _type = handle.find("type").text
946         parent = handle.attrib.get("parent") # Most objects have a parent e.g. VkQueue has VkDevice.
947         return VkHandle(name, _type, parent)
949     def dispatch_table(self):
950         if not self.is_dispatchable():
951             return None
953         if self.parent is None:
954             # Should only happen for VkInstance
955             return "funcs"
956         elif self.name == "VkDevice":
957             # VkDevice has VkInstance as a parent, but has its own dispatch table.
958             return "funcs"
959         elif self.parent in ["VkInstance", "VkPhysicalDevice"]:
960             return "instance->funcs"
961         elif self.parent in ["VkDevice", "VkCommandPool"]:
962             return "device->funcs"
963         else:
964             LOGGER.error("Unhandled dispatchable parent: {0}".format(self.parent))
966     def definition(self):
967         """ Generates handle definition e.g. VK_DEFINE_HANDLE(vkInstance) """
969         # Legacy types are typedef'ed to the new type if they are aliases.
970         if self.is_alias():
971             return "typedef {0} {1};\n".format(self.alias.name, self.name)
973         return "{0}({1})\n".format(self.type, self.name)
975     def is_alias(self):
976         return self.alias is not None
978     def is_dispatchable(self):
979         """ Some handles like VkInstance, VkDevice are dispatchable objects,
980         which means they contain a dispatch table of function pointers.
981         """
982         return self.type == "VK_DEFINE_HANDLE"
984     def is_required(self):
985         return self.required
987     def native_handle(self, name):
988         """ Provide access to the native handle of a wrapped object. """
990         if self.name == "VkCommandPool":
991             return "wine_cmd_pool_from_handle({0})->command_pool".format(name)
992         if self.name == "VkDebugUtilsMessengerEXT":
993             return "wine_debug_utils_messenger_from_handle({0})->debug_messenger".format(name)
994         if self.name == "VkDebugReportCallbackEXT":
995             return "wine_debug_report_callback_from_handle({0})->debug_callback".format(name)
996         if self.name == "VkSurfaceKHR":
997             return "wine_surface_from_handle({0})->surface".format(name)
999         native_handle_name = None
1001         if self.name == "VkCommandBuffer":
1002             native_handle_name = "command_buffer"
1003         if self.name == "VkDevice":
1004             native_handle_name = "device"
1005         if self.name == "VkInstance":
1006             native_handle_name = "instance"
1007         if self.name == "VkPhysicalDevice":
1008             native_handle_name = "phys_dev"
1009         if self.name == "VkQueue":
1010             native_handle_name = "queue"
1012         if native_handle_name:
1013             return "{0}->{1}".format(name, native_handle_name)
1015         if self.is_dispatchable():
1016             LOGGER.error("Unhandled native handle for: {0}".format(self.name))
1017         return None
1019     def driver_handle(self, name):
1020         """ Provide access to the handle that should be passed to the wine driver """
1022         if self.name == "VkSurfaceKHR":
1023             return "wine_surface_from_handle({0})->driver_surface".format(name)
1025         return self.native_handle(name)
1027     def is_wrapped(self):
1028         return self.native_handle("test") is not None
1030 class VkMember(object):
1031     def __init__(self, const=False, struct_fwd_decl=False,_type=None, pointer=None, name=None, array_len=None,
1032             dyn_array_len=None, optional=False, values=None):
1033         self.const = const
1034         self.struct_fwd_decl = struct_fwd_decl
1035         self.name = name
1036         self.pointer = pointer
1037         self.type = _type
1038         self.type_info = None
1039         self.array_len = array_len
1040         self.dyn_array_len = dyn_array_len
1041         self.optional = optional
1042         self.values = values
1044     def __eq__(self, other):
1045         """ Compare member based on name against a string.
1047         This method is for convenience by VkStruct, which holds a number of members and needs quick checking
1048         if certain members exist.
1049         """
1051         return self.name == other
1053     def __repr__(self):
1054         return "{0} {1} {2} {3} {4} {5} {6}".format(self.const, self.struct_fwd_decl, self.type, self.pointer,
1055                 self.name, self.array_len, self.dyn_array_len)
1057     @staticmethod
1058     def from_xml(member):
1059         """ Helper function for parsing a member tag within a struct or union. """
1061         name_elem = member.find("name")
1062         type_elem = member.find("type")
1064         const = False
1065         struct_fwd_decl = False
1066         member_type = None
1067         pointer = None
1068         array_len = None
1070         values = member.get("values")
1072         if member.text:
1073             if "const" in member.text:
1074                 const = True
1076             # Some members contain forward declarations:
1077             # - VkBaseInstructure has a member "const struct VkBaseInStructure *pNext"
1078             # - VkWaylandSurfaceCreateInfoKHR has a member "struct wl_display *display"
1079             if "struct" in member.text:
1080                 struct_fwd_decl = True
1082         if type_elem is not None:
1083             member_type = type_elem.text
1084             if type_elem.tail is not None:
1085                 pointer = type_elem.tail.strip() if type_elem.tail.strip() != "" else None
1087         # Name of other member within, which stores the number of
1088         # elements pointed to be by this member.
1089         dyn_array_len = member.get("len")
1091         # Some members are optional, which is important for conversion code e.g. not dereference NULL pointer.
1092         optional = True if member.get("optional") else False
1094         # Usually we need to allocate memory for dynamic arrays. We need to do the same in a few other cases
1095         # like for VkCommandBufferBeginInfo.pInheritanceInfo. Just threat such cases as dynamic arrays of
1096         # size 1 to simplify code generation.
1097         if dyn_array_len is None and pointer is not None:
1098             dyn_array_len = 1
1100         # Some members are arrays, attempt to parse these. Formats include:
1101         # <member><type>char</type><name>extensionName</name>[<enum>VK_MAX_EXTENSION_NAME_SIZE</enum>]</member>
1102         # <member><type>uint32_t</type><name>foo</name>[4]</member>
1103         if name_elem.tail and name_elem.tail[0] == '[':
1104             LOGGER.debug("Found array type")
1105             enum_elem = member.find("enum")
1106             if enum_elem is not None:
1107                 array_len = enum_elem.text
1108             else:
1109                 # Remove brackets around length
1110                 array_len = name_elem.tail.strip("[]")
1112         return VkMember(const=const, struct_fwd_decl=struct_fwd_decl, _type=member_type, pointer=pointer, name=name_elem.text,
1113                 array_len=array_len, dyn_array_len=dyn_array_len, optional=optional, values=values)
1115     def copy(self, input, output, direction):
1116         """ Helper method for use by conversion logic to generate a C-code statement to copy this member. """
1118         if self.needs_conversion():
1119             if self.is_dynamic_array():
1120                 if direction == Direction.OUTPUT:
1121                     LOGGER.warn("TODO: implement copying of returnedonly dynamic array for {0}.{1}".format(self.type, self.name))
1122                 else:
1123                     # Array length is either a variable name (string) or an int.
1124                     count = self.dyn_array_len if isinstance(self.dyn_array_len, int) else "{0}{1}".format(input, self.dyn_array_len)
1125                     return "{0}{1} = convert_{2}_array_win_to_host({3}{1}, {4});\n".format(output, self.name, self.type, input, count)
1126             elif self.is_static_array():
1127                 count = self.array_len
1128                 if direction == Direction.OUTPUT:
1129                     # Needed by VkMemoryHeap.memoryHeaps
1130                     return "convert_{0}_static_array_host_to_win({2}{1}, {3}{1}, {4});\n".format(self.type, self.name, input, output, count)
1131                 else:
1132                     # Nothing needed this yet.
1133                     LOGGER.warn("TODO: implement copying of static array for {0}.{1}".format(self.type, self.name))
1134             else:
1135                 if direction == Direction.OUTPUT:
1136                     return "convert_{0}_host_to_win(&{2}{1}, &{3}{1});\n".format(self.type, self.name, input, output)
1137                 else:
1138                     return "convert_{0}_win_to_host(&{2}{1}, &{3}{1});\n".format(self.type, self.name, input, output)
1139         elif self.is_static_array():
1140             bytes_count = "{0} * sizeof({1})".format(self.array_len, self.type)
1141             return "memcpy({0}{1}, {2}{1}, {3});\n".format(output, self.name, input, bytes_count)
1142         else:
1143             return "{0}{1} = {2}{1};\n".format(output, self.name, input)
1145     def definition(self, align=False, conv=False):
1146         """ Generate prototype for given function.
1148         Args:
1149             align (bool, optional): Enable alignment if a type needs it. This adds WINE_VK_ALIGN(8) to a member.
1150             conv (bool, optional): Enable conversion if a type needs it. This appends '_host' to the name.
1151         """
1153         text = ""
1154         if self.is_const():
1155             text += "const "
1157         if self.is_struct_forward_declaration():
1158             text += "struct "
1160         if conv and self.is_struct():
1161             text += "{0}_host".format(self.type)
1162         else:
1163             text += self.type
1165         if self.is_pointer():
1166             text += " {0}{1}".format(self.pointer, self.name)
1167         else:
1168             if align and self.needs_alignment():
1169                 text += " WINE_VK_ALIGN(8) " + self.name
1170             else:
1171                 text += " " + self.name
1173         if self.is_static_array():
1174             text += "[{0}]".format(self.array_len)
1176         return text
1178     def get_conversions(self):
1179         """ Return any conversion description for this member and its children when conversion is needed. """
1181         # Check if we need conversion either for this member itself or for any child members
1182         # in case member represents a struct.
1183         if not self.needs_conversion():
1184             return None
1186         conversions = []
1188         # Collect any conversion for any member structs.
1189         struct = self.type_info["data"]
1190         for m in struct:
1191             m.needs_struct_extensions_conversion()
1192             if m.needs_conversion():
1193                 conversions.extend(m.get_conversions())
1195         struct.needs_struct_extensions_conversion()
1197         struct = self.type_info["data"]
1198         direction = Direction.OUTPUT if struct.returnedonly else Direction.INPUT
1199         if self.is_dynamic_array():
1200             conversions.append(ConversionFunction(False, True, direction, struct))
1201         elif self.is_static_array():
1202             conversions.append(ConversionFunction(True, False, direction, struct))
1203         else:
1204             conversions.append(ConversionFunction(False, False, direction, struct))
1206         if self.needs_free():
1207             conversions.append(FreeFunction(self.is_dynamic_array(), struct))
1209         return conversions
1211     def is_const(self):
1212         return self.const
1214     def is_dynamic_array(self):
1215         """ Returns if the member is an array element.
1216         Vulkan uses this for dynamically sized arrays for which
1217         there is a 'count' parameter.
1218         """
1219         return self.dyn_array_len is not None
1221     def is_handle(self):
1222         return self.type_info["category"] == "handle"
1224     def is_pointer(self):
1225         return self.pointer is not None
1227     def is_static_array(self):
1228         """ Returns if the member is an array.
1229         Vulkan uses this often for fixed size arrays in which the
1230         length is part of the member.
1231         """
1232         return self.array_len is not None
1234     def is_struct(self):
1235         return self.type_info["category"] == "struct"
1237     def is_struct_forward_declaration(self):
1238         return self.struct_fwd_decl
1240     def is_union(self):
1241         return self.type_info["category"] == "union"
1243     def needs_alignment(self):
1244         """ Check if this member needs alignment for 64-bit data.
1245         Various structures need alignment on 64-bit variables due
1246         to compiler differences on 32-bit between Win32 and Linux.
1247         """
1249         if self.is_pointer():
1250             return False
1251         elif self.type == "size_t":
1252             return False
1253         elif self.type in ["uint64_t", "VkDeviceSize"]:
1254             return True
1255         elif self.is_struct():
1256             struct = self.type_info["data"]
1257             return struct.needs_alignment()
1258         elif self.is_handle():
1259             # Dispatchable handles are pointers to objects, while
1260             # non-dispatchable are uint64_t and hence need alignment.
1261             handle = self.type_info["data"]
1262             return False if handle.is_dispatchable() else True
1263         return False
1265     def needs_conversion(self):
1266         """ Structures requiring alignment, need conversion between win32 and host. """
1268         if not self.is_struct():
1269             return False
1271         struct = self.type_info["data"]
1272         return struct.needs_conversion()
1274     def needs_free(self):
1275         if not self.needs_conversion():
1276             return False
1278         if self.is_dynamic_array():
1279             return True
1281         # TODO: some non-pointer structs and optional pointer structs may need freeing,
1282         # though none of this type have been encountered yet.
1283         return False
1285     def needs_struct_extensions_conversion(self):
1286         if not self.is_struct():
1287             return False
1289         struct = self.type_info["data"]
1290         return struct.needs_struct_extensions_conversion()
1292     def set_type_info(self, type_info):
1293         """ Helper function to set type information from the type registry.
1294         This is needed, because not all type data is available at time of
1295         parsing.
1296         """
1297         self.type_info = type_info
1300 class VkParam(object):
1301     """ Helper class which describes a parameter to a function call. """
1303     def __init__(self, type_info, const=None, pointer=None, name=None, array_len=None, dyn_array_len=None):
1304         self.const = const
1305         self.name = name
1306         self.array_len = array_len
1307         self.dyn_array_len = dyn_array_len
1308         self.pointer = pointer
1309         self.type_info = type_info
1310         self.type = type_info["name"] # For convenience
1311         self.handle = type_info["data"] if type_info["category"] == "handle" else None
1312         self.struct = type_info["data"] if type_info["category"] == "struct" else None
1314         self._set_direction()
1315         self._set_format_string()
1316         self._set_conversions()
1318     def __repr__(self):
1319         return "{0} {1} {2} {3} {4} {5}".format(self.const, self.type, self.pointer, self.name, self.array_len, self.dyn_array_len)
1321     @staticmethod
1322     def from_xml(param, types):
1323         """ Helper function to create VkParam from xml. """
1325         # Parameter parsing is slightly tricky. All the data is contained within
1326         # a param tag, but some data is within subtags while others are text
1327         # before or after the type tag.
1328         # Common structure:
1329         # <param>const <type>char</type>* <name>pLayerName</name></param>
1331         name_elem = param.find("name")
1332         array_len = None
1333         name = name_elem.text
1334         # Tail contains array length e.g. for blendConstants param of vkSetBlendConstants
1335         if name_elem.tail is not None:
1336             array_len = name_elem.tail.strip("[]")
1338         # Name of other parameter in function prototype, which stores the number of
1339         # elements pointed to be by this parameter.
1340         dyn_array_len = param.get("len", None)
1342         const = param.text.strip() if param.text else None
1343         type_elem = param.find("type")
1344         pointer = type_elem.tail.strip() if type_elem.tail.strip() != "" else None
1346         # Since we have parsed all types before hand, this should not happen.
1347         type_info = types.get(type_elem.text, None)
1348         if type_info is None:
1349             LOGGER.err("type info not found for: {0}".format(type_elem.text))
1351         return VkParam(type_info, const=const, pointer=pointer, name=name, array_len=array_len, dyn_array_len=dyn_array_len)
1353     def _set_conversions(self):
1354         """ Internal helper function to configure any needed conversion functions. """
1356         self.free_func = None
1357         self.input_conv = None
1358         self.output_conv = None
1359         if not self.needs_conversion():
1360             return
1362         # Input functions require win to host conversion.
1363         if self._direction in [Direction.INPUT, Direction.INPUT_OUTPUT]:
1364             self.input_conv = ConversionFunction(False, self.is_dynamic_array(), Direction.INPUT, self.struct)
1366         # Output functions require host to win conversion.
1367         if self._direction in [Direction.INPUT_OUTPUT, Direction.OUTPUT]:
1368             self.output_conv = ConversionFunction(False, self.is_dynamic_array(), Direction.OUTPUT, self.struct)
1370         # Dynamic arrays, but also some normal structs (e.g. VkCommandBufferBeginInfo) need memory
1371         # allocation and thus some cleanup.
1372         if self.is_dynamic_array() or self.struct.needs_free():
1373             self.free_func = FreeFunction(self.is_dynamic_array(), self.struct)
1375     def _set_direction(self):
1376         """ Internal helper function to set parameter direction (input/output/input_output). """
1378         # The parameter direction needs to be determined from hints in vk.xml like returnedonly,
1379         # parameter constness and other heuristics.
1380         # For now we need to get this right for structures as we need to convert these, we may have
1381         # missed a few other edge cases (e.g. count variables).
1382         # See also https://github.com/KhronosGroup/Vulkan-Docs/issues/610
1384         if not self.is_pointer():
1385             self._direction = Direction.INPUT
1386         elif self.is_const() and self.is_pointer():
1387             self._direction = Direction.INPUT
1388         elif self.is_struct():
1389             if not self.struct.returnedonly:
1390                 self._direction = Direction.INPUT
1391                 return
1393             # Returnedonly hints towards output, however in some cases
1394             # it is inputoutput. In particular if pNext / sType exist,
1395             # which are used to link in other structures without having
1396             # to introduce new APIs. E.g. vkGetPhysicalDeviceProperties2KHR.
1397             if "pNext" in self.struct:
1398                 self._direction = Direction.INPUT_OUTPUT
1399                 return
1401             self._direction = Direction.OUTPUT
1402         else:
1403             # This should mostly be right. Count variables can be inout, but we don't care about these yet.
1404             self._direction = Direction.OUTPUT
1406     def _set_format_string(self):
1407         """ Internal helper function to be used by constructor to set format string. """
1409         # Determine a format string used by code generation for traces.
1410         # 64-bit types need a conversion function.
1411         self.format_conv = None
1412         if self.is_static_array() or self.is_pointer():
1413             self.format_str = "%p"
1414         else:
1415             if self.type_info["category"] in ["bitmask"]:
1416                 # Since 1.2.170 bitmasks can be 32 or 64-bit, check the basetype.
1417                 if self.type_info["data"].type == "VkFlags64":
1418                     self.format_str = "0x%s"
1419                     self.format_conv = "wine_dbgstr_longlong({0})"
1420                 else:
1421                     self.format_str = "%#x"
1422             elif self.type_info["category"] in ["enum"]:
1423                 self.format_str = "%#x"
1424             elif self.is_handle():
1425                 # We use uint64_t for non-dispatchable handles as opposed to pointers
1426                 # for dispatchable handles.
1427                 if self.handle.is_dispatchable():
1428                     self.format_str = "%p"
1429                 else:
1430                     self.format_str = "0x%s"
1431                     self.format_conv = "wine_dbgstr_longlong({0})"
1432             elif self.type == "float":
1433                 self.format_str = "%f"
1434             elif self.type == "int":
1435                 self.format_str = "%d"
1436             elif self.type == "int32_t":
1437                 self.format_str = "%d"
1438             elif self.type == "size_t":
1439                 self.format_str = "0x%s"
1440                 self.format_conv = "wine_dbgstr_longlong({0})"
1441             elif self.type in ["uint16_t", "uint32_t", "VkBool32"]:
1442                 self.format_str = "%u"
1443             elif self.type in ["uint64_t", "VkDeviceAddress", "VkDeviceSize"]:
1444                 self.format_str = "0x%s"
1445                 self.format_conv = "wine_dbgstr_longlong({0})"
1446             elif self.type == "HANDLE":
1447                 self.format_str = "%p"
1448             elif self.type in ["VisualID", "xcb_visualid_t", "RROutput"]:
1449                 # Don't care about Linux specific types.
1450                 self.format_str = ""
1451             else:
1452                 LOGGER.warn("Unhandled type: {0}".format(self.type_info))
1454     def copy(self, direction):
1455         if direction == Direction.INPUT:
1456             if self.is_dynamic_array():
1457                 return "    {0}_host = convert_{1}_array_win_to_host({0}, {2});\n".format(self.name, self.type, self.dyn_array_len)
1458             else:
1459                 return "    convert_{0}_win_to_host({1}, &{1}_host);\n".format(self.type, self.name)
1460         else:
1461             if self.is_dynamic_array():
1462                 LOGGER.error("Unimplemented output conversion for: {0}".format(self.name))
1463             else:
1464                 return "    convert_{0}_host_to_win(&{1}_host, {1});\n".format(self.type, self.name)
1466     def definition(self, postfix=None):
1467         """ Return prototype for the parameter. E.g. 'const char *foo' """
1469         proto = ""
1470         if self.const:
1471             proto += self.const + " "
1473         proto += self.type
1475         if self.is_pointer():
1476             proto += " {0}{1}".format(self.pointer, self.name)
1477         else:
1478             proto += " " + self.name
1480         # Allows appending something to the variable name useful for
1481         # win32 to host conversion.
1482         if postfix is not None:
1483             proto += postfix
1485         if self.is_static_array():
1486             proto += "[{0}]".format(self.array_len)
1488         return proto
1490     def direction(self):
1491         """ Returns parameter direction: input, output, input_output.
1493         Parameter direction in Vulkan is not straight-forward, which this function determines.
1494         """
1496         return self._direction
1498     def dispatch_table(self):
1499         """ Return functions dispatch table pointer for dispatchable objects. """
1501         if not self.is_dispatchable():
1502             return None
1504         return "{0}->{1}".format(self.name, self.handle.dispatch_table())
1506     def format_string(self):
1507         return self.format_str
1509     def free(self):
1510         if self.is_dynamic_array():
1511             if self.struct.returnedonly:
1512                 # For returnedonly, counts is stored in a pointer.
1513                 return "    free_{0}_array({1}_host, *{2});\n".format(self.type, self.name, self.dyn_array_len)
1514             else:
1515                 return "    free_{0}_array({1}_host, {2});\n".format(self.type, self.name, self.dyn_array_len)
1516         else:
1517             # We are operating on a single structure. Some structs (very rare) contain dynamic members,
1518             # which would need freeing.
1519             if self.struct.needs_free():
1520                 return "    free_{0}(&{1}_host);\n".format(self.type, self.name)
1521         return ""
1523     def get_conversions(self):
1524         """ Get a list of conversions required for this parameter if any.
1525         Parameters which are structures may require conversion between win32
1526         and the host platform. This function returns a list of conversions
1527         required.
1528         """
1530         if not self.is_struct():
1531             return None
1533         self.struct.needs_struct_extensions_conversion()
1534         for m in self.struct:
1535             m.needs_struct_extensions_conversion()
1537         if not self.needs_conversion():
1538             return None
1540         conversions = []
1542         # Collect any member conversions first, so we can guarantee
1543         # those functions will be defined prior to usage by the
1544         # 'parent' param requiring conversion.
1545         for m in self.struct:
1546             if not m.is_struct():
1547                 continue
1549             if not m.needs_conversion():
1550                 continue
1552             conversions.extend(m.get_conversions())
1554         # Conversion requirements for the 'parent' parameter.
1555         if self.input_conv is not None:
1556             conversions.append(self.input_conv)
1557         if self.output_conv is not None:
1558             conversions.append(self.output_conv)
1559         if self.free_func is not None:
1560             conversions.append(self.free_func)
1562         return conversions
1564     def is_const(self):
1565         return self.const is not None
1567     def is_dynamic_array(self):
1568         return self.dyn_array_len is not None
1570     def is_dispatchable(self):
1571         if not self.is_handle():
1572             return False
1574         return self.handle.is_dispatchable()
1576     def is_handle(self):
1577         return self.handle is not None
1579     def is_pointer(self):
1580         return self.pointer is not None
1582     def is_static_array(self):
1583         return self.array_len is not None
1585     def is_struct(self):
1586         return self.struct is not None
1588     def needs_conversion(self):
1589         """ Returns if parameter needs conversion between win32 and host. """
1591         if not self.is_struct():
1592             return False
1594         # VkSparseImageMemoryRequirements(2) is used by vkGetImageSparseMemoryRequirements(2).
1595         # This function is tricky to wrap, because how to wrap depends on whether
1596         # pSparseMemoryRequirements is NULL or not. Luckily for VkSparseImageMemoryRequirements(2)
1597         # the alignment works out in such a way that no conversion is needed between win32 and Linux.
1598         if self.type in ["VkSparseImageMemoryRequirements", "VkSparseImageMemoryRequirements2"]:
1599             return False
1601         # If a structure needs alignment changes, it means we need to
1602         # perform parameter conversion between win32 and host.
1603         if self.struct.needs_conversion():
1604             return True
1606         return False
1608     def needs_free(self):
1609         return self.free_func is not None
1611     def needs_input_conversion(self):
1612         return self.input_conv is not None
1614     def needs_output_conversion(self):
1615         return self.output_conv is not None
1617     def spec(self):
1618         """ Generate spec file entry for this parameter. """
1620         if self.is_pointer() and self.type == "char":
1621             return "str"
1622         if self.is_dispatchable() or self.is_pointer() or self.is_static_array():
1623             return "ptr"
1624         if self.type_info["category"] in ["bitmask"]:
1625             # Since 1.2.170 bitmasks can be 32 or 64-bit, check the basetype.
1626             if self.type_info["data"].type == "VkFlags64":
1627                 return "int64"
1628             else:
1629                 return "long"
1630         if self.type_info["category"] in ["enum"]:
1631             return "long"
1632         if self.is_handle() and not self.is_dispatchable():
1633             return "int64"
1634         if self.type == "float":
1635             return "float"
1636         if self.type in ["int", "int32_t", "size_t", "uint16_t", "uint32_t", "VkBool32"]:
1637             return "long"
1638         if self.type in ["uint64_t", "VkDeviceSize"]:
1639             return "int64"
1641         LOGGER.error("Unhandled spec conversion for type: {0}".format(self.type))
1643     def variable(self, conv=False):
1644         """ Returns 'glue' code during generation of a function call on how to access the variable.
1645         This function handles various scenarios such as 'unwrapping' if dispatchable objects and
1646         renaming of parameters in case of win32 -> host conversion.
1648         Args:
1649             conv (bool, optional): Enable conversion if the param needs it. This appends '_host' to the name.
1650         """
1652         # Hack until we enable allocation callbacks from ICD to application. These are a joy
1653         # to enable one day, because of calling convention conversion.
1654         if "VkAllocationCallbacks" in self.type:
1655             LOGGER.debug("TODO: setting NULL VkAllocationCallbacks for {0}".format(self.name))
1656             return "NULL"
1658         if conv and self.needs_conversion():
1659             if self.is_dynamic_array():
1660                 return "{0}_host".format(self.name)
1661             else:
1662                 return "&{0}_host".format(self.name)
1663         else:
1664             # We need to pass the native handle to the native Vulkan calls and
1665             # the wine driver's handle to calls which are wrapped by the driver.
1666             driver_handle = self.handle.driver_handle(self.name) if self.is_handle() else None
1667             return driver_handle if driver_handle else self.name
1670 class VkStruct(Sequence):
1671     """ Class which represents the type union and struct. """
1673     def __init__(self, name, members, returnedonly, structextends, alias=None, union=False):
1674         self.name = name
1675         self.members = members
1676         self.returnedonly = returnedonly
1677         self.structextends = structextends
1678         self.required = False
1679         self.alias = alias
1680         self.union = union
1681         self.type_info = None # To be set later.
1682         self.struct_extensions = []
1683         self.aliased_by = []
1685     def __getitem__(self, i):
1686         return self.members[i]
1688     def __len__(self):
1689         return len(self.members)
1691     @staticmethod
1692     def from_alias(struct, alias):
1693         name = struct.attrib.get("name")
1694         aliasee = VkStruct(name, alias.members, alias.returnedonly, alias.structextends, alias=alias)
1696         alias.add_aliased_by(aliasee)
1697         return aliasee
1699     @staticmethod
1700     def from_xml(struct):
1701         # Unions and structs are the same parsing wise, but we need to
1702         # know which one we are dealing with later on for code generation.
1703         union = True if struct.attrib["category"] == "union" else False
1705         name = struct.attrib.get("name")
1707         # 'Output' structures for which data is filled in by the API are
1708         # marked as 'returnedonly'.
1709         returnedonly = True if struct.attrib.get("returnedonly") else False
1711         structextends = struct.attrib.get("structextends")
1712         structextends = structextends.split(",") if structextends else []
1714         members = []
1715         for member in struct.findall("member"):
1716             vk_member = VkMember.from_xml(member)
1717             members.append(vk_member)
1719         return VkStruct(name, members, returnedonly, structextends, union=union)
1721     @staticmethod
1722     def decouple_structs(structs):
1723         """ Helper function which decouples a list of structs.
1724         Structures often depend on other structures. To make the C compiler
1725         happy we need to define 'substructures' first. This function analyzes
1726         the list of structures and reorders them in such a way that they are
1727         decoupled.
1728         """
1730         tmp_structs = list(structs) # Don't modify the original structures.
1731         decoupled_structs = []
1733         while (len(tmp_structs) > 0):
1734             for struct in tmp_structs:
1735                 dependends = False
1737                 if not struct.required:
1738                     tmp_structs.remove(struct)
1739                     continue
1741                 for m in struct:
1742                     if not (m.is_struct() or m.is_union()):
1743                         continue
1745                     # VkBaseInstructure and VkBaseOutStructure reference themselves.
1746                     if m.type == struct.name:
1747                         break
1749                     found = False
1750                     # Check if a struct we depend on has already been defined.
1751                     for s in decoupled_structs:
1752                         if s.name == m.type:
1753                             found = True
1754                             break
1756                     if not found:
1757                         # Check if the struct we depend on is even in the list of structs.
1758                         # If found now, it means we haven't met all dependencies before we
1759                         # can operate on the current struct.
1760                         # When generating 'host' structs we may not be able to find a struct
1761                         # as the list would only contain the structs requiring conversion.
1762                         for s in tmp_structs:
1763                             if s.name == m.type:
1764                                 dependends = True
1765                                 break
1767                 if dependends == False:
1768                     decoupled_structs.append(struct)
1769                     tmp_structs.remove(struct)
1771         return decoupled_structs
1773     def definition(self, align=False, conv=False, postfix=None):
1774         """ Convert structure to textual definition.
1776         Args:
1777             align (bool, optional): enable alignment to 64-bit for win32 struct compatibility.
1778             conv (bool, optional): enable struct conversion if the struct needs it.
1779             postfix (str, optional): text to append to end of struct name, useful for struct renaming.
1780         """
1782         # Only define alias structs when doing conversions
1783         if self.is_alias() and not conv:
1784             return ""
1786         if self.union:
1787             text = "typedef union {0}".format(self.name)
1788         else:
1789             text = "typedef struct {0}".format(self.name)
1791         if postfix is not None:
1792             text += postfix
1794         text += "\n{\n"
1796         for m in self:
1797             if align and m.needs_alignment():
1798                 text += "    {0};\n".format(m.definition(align=align))
1799             elif conv and m.needs_conversion():
1800                 text += "    {0};\n".format(m.definition(conv=conv))
1801             else:
1802                 text += "    {0};\n".format(m.definition())
1804         if postfix is not None:
1805             text += "}} {0}{1};\n\n".format(self.name, postfix)
1806         else:
1807             text += "}} {0};\n".format(self.name)
1809         for aliasee in self.aliased_by:
1810             text += "typedef {0} {1};\n".format(self.name, aliasee.name)
1812         text += "\n"
1814         return text
1816     def is_alias(self):
1817         return bool(self.alias)
1819     def add_aliased_by(self, aliasee):
1820         self.aliased_by.append(aliasee)
1822     def needs_alignment(self):
1823         """ Check if structure needs alignment for 64-bit data.
1824         Various structures need alignment on 64-bit variables due
1825         to compiler differences on 32-bit between Win32 and Linux.
1826         """
1828         for m in self.members:
1829             if m.needs_alignment():
1830                 return True
1831         return False
1833     def needs_conversion(self):
1834         """ Returns if struct members needs conversion between win32 and host.
1835         Structures need conversion if they contain members requiring alignment
1836         or if they include other structures which need alignment.
1837         """
1839         if self.needs_alignment():
1840             return True
1842         for m in self.members:
1843             if m.needs_conversion():
1844                 return True
1845         return False
1847     def needs_free(self):
1848         """ Check if any struct member needs some memory freeing."""
1850         for m in self.members:
1851             if m.needs_free():
1852                 return True
1854             continue
1856         return False
1858     def needs_struct_extensions_conversion(self):
1859         """ Checks if structure extensions in pNext chain need conversion. """
1860         ret = False
1862         for e in self.struct_extensions:
1863             if e.required and e.needs_conversion():
1864                 LOGGER.error("Unhandled pNext chain conversion for {0}".format(e.name))
1865                 ret = True
1867         return ret
1869     def set_type_info(self, types):
1870         """ Helper function to set type information from the type registry.
1871         This is needed, because not all type data is available at time of
1872         parsing.
1873         """
1874         for m in self.members:
1875             type_info = types[m.type]
1876             m.set_type_info(type_info)
1879 class ConversionFunction(object):
1880     def __init__(self, array, dyn_array, direction, struct):
1881         self.array = array
1882         self.direction = direction
1883         self.dyn_array = dyn_array
1884         self.struct = struct
1885         self.type = struct.name
1887         self._set_name()
1889     def __eq__(self, other):
1890         return self.name == other.name
1892     def _generate_array_conversion_func(self):
1893         """ Helper function for generating a conversion function for array structs. """
1895         if self.direction == Direction.OUTPUT:
1896             params = ["const {0}_host *in".format(self.type), "uint32_t count"]
1897             return_type = self.type
1898         else:
1899             params = ["const {0} *in".format(self.type), "uint32_t count"]
1900             return_type = "{0}_host".format(self.type)
1902         # Generate function prototype.
1903         body = "static inline {0} *{1}(".format(return_type, self.name)
1904         body += ", ".join(p for p in params)
1905         body += ")\n{\n"
1907         body += "    {0} *out;\n".format(return_type)
1908         body += "    unsigned int i;\n\n"
1909         body += "    if (!in) return NULL;\n\n"
1911         body += "    out = heap_alloc(count * sizeof(*out));\n"
1913         body += "    for (i = 0; i < count; i++)\n"
1914         body += "    {\n"
1916         for m in self.struct:
1917             # TODO: support copying of pNext extension structures!
1918             # Luckily though no extension struct at this point needs conversion.
1919             body += "        " + m.copy("in[i].", "out[i].", self.direction)
1921         body += "    }\n\n"
1922         body += "    return out;\n"
1923         body += "}\n\n"
1924         return body
1926     def _generate_conversion_func(self):
1927         """ Helper function for generating a conversion function for non-array structs. """
1929         if self.direction == Direction.OUTPUT:
1930             params = ["const {0}_host *in".format(self.type), "{0} *out".format(self.type)]
1931         else:
1932             params = ["const {0} *in".format(self.type), "{0}_host *out".format(self.type)]
1934         body = "static inline void {0}(".format(self.name)
1936         # Generate parameter list
1937         body += ", ".join(p for p in params)
1938         body += ")\n{\n"
1940         body += "    if (!in) return;\n\n"
1942         if self.direction == Direction.INPUT and "pNext" in self.struct and self.struct.returnedonly:
1943             # We are dealing with an input_output parameter. For these we only need to copy
1944             # pNext and sType as the other fields are filled in by the host. We do potentially
1945             # have to iterate over pNext and perform conversions based on switch(sType)!
1946             # Luckily though no extension structs at this point need conversion.
1947             # TODO: support copying of pNext extension structures!
1948             body += "    out->pNext = in->pNext;\n"
1949             body += "    out->sType = in->sType;\n"
1950         else:
1951             for m in self.struct:
1952                 # TODO: support copying of pNext extension structures!
1953                 body += "    " + m.copy("in->", "out->", self.direction)
1955         body += "}\n\n"
1956         return body
1958     def _generate_static_array_conversion_func(self):
1959         """ Helper function for generating a conversion function for array structs. """
1961         if self.direction == Direction.OUTPUT:
1962             params = ["const {0}_host *in".format(self.type), "{0} *out".format(self.type), "uint32_t count"]
1963         else:
1964             params = ["const {0} *in".format(self.type), "{0} *out_host".format(self.type), "uint32_t count"]
1966         # Generate function prototype.
1967         body = "static inline void {0}(".format(self.name)
1968         body += ", ".join(p for p in params)
1969         body += ")\n{\n"
1970         body += "    unsigned int i;\n\n"
1971         body += "    if (!in) return;\n\n"
1972         body += "    for (i = 0; i < count; i++)\n"
1973         body += "    {\n"
1975         for m in self.struct:
1976             # TODO: support copying of pNext extension structures!
1977             body += "        " + m.copy("in[i].", "out[i].", self.direction)
1979         body += "    }\n"
1980         body += "}\n\n"
1981         return body
1983     def _set_name(self):
1984         if self.direction == Direction.INPUT:
1985             if self.array:
1986                 name = "convert_{0}_static_array_win_to_host".format(self.type)
1987             elif self.dyn_array:
1988                 name = "convert_{0}_array_win_to_host".format(self.type)
1989             else:
1990                 name = "convert_{0}_win_to_host".format(self.type)
1991         else: # Direction.OUTPUT
1992             if self.array:
1993                 name = "convert_{0}_static_array_host_to_win".format(self.type)
1994             elif self.dyn_array:
1995                 name = "convert_{0}_array_host_to_win".format(self.type)
1996             else:
1997                 name = "convert_{0}_host_to_win".format(self.type)
1999         self.name = name
2001     def definition(self):
2002         if self.array:
2003             return self._generate_static_array_conversion_func()
2004         elif self.dyn_array:
2005             return self._generate_array_conversion_func()
2006         else:
2007             return self._generate_conversion_func()
2010 class FreeFunction(object):
2011     def __init__(self, dyn_array, struct):
2012         self.dyn_array = dyn_array
2013         self.struct = struct
2014         self.type = struct.name
2016         if dyn_array:
2017             self.name = "free_{0}_array".format(self.type)
2018         else:
2019             self.name = "free_{0}".format(self.type)
2021     def __eq__(self, other):
2022         return self.name == other.name
2024     def _generate_array_free_func(self):
2025         """ Helper function for cleaning up temporary buffers required for array conversions. """
2027         # Generate function prototype.
2028         body = "static inline void {0}({1}_host *in, uint32_t count)\n{{\n".format(self.name, self.type)
2030         # E.g. VkGraphicsPipelineCreateInfo_host needs freeing for pStages.
2031         if self.struct.needs_free():
2032             body += "    unsigned int i;\n\n"
2033             body += "    if (!in) return;\n\n"
2034             body += "    for (i = 0; i < count; i++)\n"
2035             body += "    {\n"
2037             for m in self.struct:
2038                 if m.needs_conversion() and m.is_dynamic_array():
2039                     if m.is_const():
2040                         # Add a cast to ignore const on conversion structs we allocated ourselves.
2041                         body += "        free_{0}_array(({0}_host *)in[i].{1}, in[i].{2});\n".format(m.type, m.name, m.dyn_array_len)
2042                     else:
2043                         body += "        free_{0}_array(in[i].{1}, in[i].{2});\n".format(m.type, m.name, m.dyn_array_len)
2044                 elif m.needs_conversion():
2045                     LOGGER.error("Unhandled conversion for {0}".format(m.name))
2046             body += "    }\n"
2047         else:
2048             body += "    if (!in) return;\n\n"
2050         body += "    heap_free(in);\n"
2052         body += "}\n\n"
2053         return body
2055     def _generate_free_func(self):
2056         # E.g. VkCommandBufferBeginInfo.pInheritanceInfo needs freeing.
2057         if not self.struct.needs_free():
2058             return ""
2060         # Generate function prototype.
2061         body = "static inline void {0}({1}_host *in)\n{{\n".format(self.name, self.type)
2063         for m in self.struct:
2064             if m.needs_conversion() and m.is_dynamic_array():
2065                 count = m.dyn_array_len if isinstance(m.dyn_array_len, int) else "in->{0}".format(m.dyn_array_len)
2066                 if m.is_const():
2067                     # Add a cast to ignore const on conversion structs we allocated ourselves.
2068                     body += "    free_{0}_array(({0}_host *)in->{1}, {2});\n".format(m.type, m.name, count)
2069                 else:
2070                     body += "    free_{0}_array(in->{1}, {2});\n".format(m.type, m.name, count)
2072         body += "}\n\n"
2073         return body
2075     def definition(self):
2076         if self.dyn_array:
2077             return self._generate_array_free_func()
2078         else:
2079             # Some structures need freeing too if they contain dynamic arrays.
2080             # E.g. VkCommandBufferBeginInfo
2081             return self._generate_free_func()
2084 class StructChainConversionFunction(object):
2085     def __init__(self, direction, struct):
2086         self.direction = direction
2087         self.struct = struct
2088         self.type = struct.name
2090         self.name = "convert_{0}_struct_chain".format(self.type)
2092     def __eq__(self, other):
2093         return self.name == other.name
2095     def prototype(self, postfix=""):
2096         return "VkResult {0}(const void *pNext, {1} *out_struct) {2}".format(self.name, self.type, postfix).strip()
2098     def definition(self):
2099         body = self.prototype()
2100         body += "\n{\n"
2102         body += "    VkBaseOutStructure *out_header = (VkBaseOutStructure *)out_struct;\n";
2103         body += "    const VkBaseInStructure *in_header;\n\n";
2105         body += "    out_header->pNext = NULL;\n\n"
2107         body += "    for (in_header = pNext; in_header; in_header = in_header->pNext)\n"
2108         body += "    {\n"
2109         body += "        switch (in_header->sType)\n"
2110         body += "        {\n"
2112         # Ignore to not confuse host loader.
2113         body += "        case VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO:\n"
2114         body += "        case VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO:\n"
2115         body += "            break;\n\n"
2117         for e in self.struct.struct_extensions:
2118             if not e.required:
2119                 continue
2121             stype = next(x for x in e.members if x.name == "sType")
2123             body += "        case {0}:\n".format(stype.values)
2124             body += "        {\n"
2126             body += "            const {0} *in = (const {0} *)in_header;\n".format(e.name)
2127             body += "            {0} *out;\n\n".format(e.name)
2129             body += "            if (!(out = heap_alloc(sizeof(*out)))) goto out_of_memory;\n\n"
2131             for m in e:
2132                 if m.name == "pNext":
2133                     body += "            out->pNext = NULL;\n"
2134                 else:
2135                     body += "            " + m.copy("in->", "out->", self.direction)
2137             body += "\n            out_header->pNext = (VkBaseOutStructure *)out;\n"
2138             body += "            out_header = out_header->pNext;\n"
2139             body += "            break;\n"
2140             body += "        }\n\n"
2142         body += "        default:\n"
2143         body += "            FIXME(\"Application requested a linked structure of type %u.\\n\", in_header->sType);\n"
2145         body += "        }\n"
2146         body += "    }\n\n"
2148         body += "    return VK_SUCCESS;\n"
2150         if any(x for x in self.struct.struct_extensions if x.required):
2151             body += "\nout_of_memory:\n"
2152             body += "    free_{0}_struct_chain(out_struct);\n".format(self.type)
2153             body += "    return VK_ERROR_OUT_OF_HOST_MEMORY;\n"
2155         body += "}\n\n"
2156         return body
2158 class FreeStructChainFunction(object):
2159     def __init__(self, struct):
2160         self.struct = struct
2161         self.type = struct.name
2163         self.name = "free_{0}_struct_chain".format(self.type)
2165     def __eq__(self, other):
2166         return self.name == other.name
2168     def prototype(self, postfix=""):
2169         return "void {0}({1} *s) {2}".format(self.name, self.type, postfix).strip()
2171     def definition(self):
2172         body = self.prototype()
2173         body += "\n{\n"
2175         body += "    VkBaseOutStructure *header = (void *)s->pNext;\n\n";
2177         body += "    while (header)\n"
2178         body += "    {\n"
2179         body += "        void *prev = header;\n"
2180         body += "        header = header->pNext;\n"
2181         body += "        heap_free(prev);\n"
2182         body += "    }\n\n"
2184         body += "    s->pNext = NULL;\n"
2186         body += "}\n\n"
2187         return body
2190 class VkGenerator(object):
2191     def __init__(self, registry):
2192         self.registry = registry
2194         # Build a list conversion functions for struct conversion.
2195         self.conversions = []
2196         self.struct_chain_conversions = []
2197         self.host_structs = []
2198         for func in self.registry.funcs.values():
2199             if not func.is_required():
2200                 continue
2202             if not func.needs_conversion():
2203                 continue
2205             conversions = func.get_conversions()
2206             for conv in conversions:
2207                 # Pull in any conversions for vulkan_thunks.c.
2208                 if func.needs_thunk():
2209                     # Append if we don't already have this conversion.
2210                     if not any(c == conv for c in self.conversions):
2211                         self.conversions.append(conv)
2213                 # Structs can be used in different ways by different conversions
2214                 # e.g. array vs non-array. Just make sure we pull in each struct once.
2215                 if not any(s.name == conv.struct.name for s in self.host_structs):
2216                     self.host_structs.append(conv.struct)
2218         for struct in self.registry.structs:
2219             if struct.name in STRUCT_CHAIN_CONVERSIONS:
2220                 self.struct_chain_conversions.append(StructChainConversionFunction(Direction.INPUT, struct))
2221                 self.struct_chain_conversions.append(FreeStructChainFunction(struct))
2223     def _generate_copyright(self, f, spec_file=False):
2224         f.write("# " if spec_file else "/* ")
2225         f.write("Automatically generated from Vulkan vk.xml; DO NOT EDIT!\n")
2226         lines = ["", "This file is generated from Vulkan vk.xml file covered",
2227             "by the following copyright and permission notice:"]
2228         lines.extend([l.rstrip(" ") for l in self.registry.copyright.splitlines()])
2229         for line in lines:
2230             f.write("{0}{1}".format("# " if spec_file else " * ", line).rstrip(" ") + "\n")
2231         f.write("\n" if spec_file else " */\n\n")
2233     def generate_thunks_c(self, f, prefix):
2234         self._generate_copyright(f)
2235         f.write("#include \"config.h\"\n")
2236         f.write("#include \"wine/port.h\"\n\n")
2238         f.write("#include \"vulkan_private.h\"\n\n")
2240         f.write("WINE_DEFAULT_DEBUG_CHANNEL(vulkan);\n\n")
2242         # Generate any conversion helper functions.
2243         f.write("#if defined(USE_STRUCT_CONVERSION)\n")
2244         for conv in self.conversions:
2245             f.write(conv.definition())
2246         f.write("#endif /* USE_STRUCT_CONVERSION */\n\n")
2248         for conv in self.struct_chain_conversions:
2249             f.write(conv.definition())
2251         # Create thunks for instance and device functions.
2252         # Global functions don't go through the thunks.
2253         for vk_func in self.registry.funcs.values():
2254             if not vk_func.is_required():
2255                 continue
2257             if vk_func.is_global_func():
2258                 continue
2260             if not vk_func.needs_thunk():
2261                 continue
2263             # Exports symbols for Core functions.
2264             if not vk_func.is_core_func() and not vk_func.needs_private_thunk():
2265                 f.write("static ")
2267             if vk_func.needs_private_thunk():
2268                 f.write(vk_func.thunk(prefix="thunk_"))
2269             else:
2270                 f.write(vk_func.thunk(prefix=prefix, call_conv="WINAPI"))
2272         f.write("static const struct vulkan_func vk_device_dispatch_table[] =\n{\n")
2273         for vk_func in self.registry.device_funcs:
2274             if not vk_func.is_required():
2275                 continue
2277             f.write("    {{\"{0}\", &{1}{0}}},\n".format(vk_func.name, prefix))
2278         f.write("};\n\n")
2280         f.write("static const struct vulkan_func vk_phys_dev_dispatch_table[] =\n{\n")
2281         for vk_func in self.registry.phys_dev_funcs:
2282             if not vk_func.is_required():
2283                 continue
2285             f.write("    {{\"{0}\", &{1}{0}}},\n".format(vk_func.name, prefix))
2286         f.write("};\n\n")
2288         f.write("static const struct vulkan_func vk_instance_dispatch_table[] =\n{\n")
2289         for vk_func in self.registry.instance_funcs:
2290             if not vk_func.is_required():
2291                 continue
2293             f.write("    {{\"{0}\", &{1}{0}}},\n".format(vk_func.name, prefix))
2294         f.write("};\n\n")
2296         f.write("void *wine_vk_get_device_proc_addr(const char *name)\n")
2297         f.write("{\n")
2298         f.write("    unsigned int i;\n")
2299         f.write("    for (i = 0; i < ARRAY_SIZE(vk_device_dispatch_table); i++)\n")
2300         f.write("    {\n")
2301         f.write("        if (strcmp(vk_device_dispatch_table[i].name, name) == 0)\n")
2302         f.write("        {\n")
2303         f.write("            TRACE(\"Found name=%s in device table\\n\", debugstr_a(name));\n")
2304         f.write("            return vk_device_dispatch_table[i].func;\n")
2305         f.write("        }\n")
2306         f.write("    }\n")
2307         f.write("    return NULL;\n")
2308         f.write("}\n\n")
2310         f.write("void *wine_vk_get_phys_dev_proc_addr(const char *name)\n")
2311         f.write("{\n")
2312         f.write("    unsigned int i;\n")
2313         f.write("    for (i = 0; i < ARRAY_SIZE(vk_phys_dev_dispatch_table); i++)\n")
2314         f.write("    {\n")
2315         f.write("        if (strcmp(vk_phys_dev_dispatch_table[i].name, name) == 0)\n")
2316         f.write("        {\n")
2317         f.write("            TRACE(\"Found name=%s in physical device table\\n\", debugstr_a(name));\n")
2318         f.write("            return vk_phys_dev_dispatch_table[i].func;\n")
2319         f.write("        }\n")
2320         f.write("    }\n")
2321         f.write("    return NULL;\n")
2322         f.write("}\n\n")
2324         f.write("void *wine_vk_get_instance_proc_addr(const char *name)\n")
2325         f.write("{\n")
2326         f.write("    unsigned int i;\n")
2327         f.write("    for (i = 0; i < ARRAY_SIZE(vk_instance_dispatch_table); i++)\n")
2328         f.write("    {\n")
2329         f.write("        if (strcmp(vk_instance_dispatch_table[i].name, name) == 0)\n")
2330         f.write("        {\n")
2331         f.write("            TRACE(\"Found name=%s in instance table\\n\", debugstr_a(name));\n")
2332         f.write("            return vk_instance_dispatch_table[i].func;\n")
2333         f.write("        }\n")
2334         f.write("    }\n")
2335         f.write("    return NULL;\n")
2336         f.write("}\n\n")
2338         # Create array of device extensions.
2339         f.write("static const char * const vk_device_extensions[] =\n{\n")
2340         for ext in self.registry.extensions:
2341             if ext["type"] != "device":
2342                 continue
2344             f.write("    \"{0}\",\n".format(ext["name"]))
2345         f.write("};\n\n")
2347         # Create array of instance extensions.
2348         f.write("static const char * const vk_instance_extensions[] =\n{\n")
2349         for ext in self.registry.extensions:
2350             if ext["type"] != "instance":
2351                 continue
2353             f.write("    \"{0}\",\n".format(ext["name"]))
2354         f.write("};\n\n")
2356         f.write("BOOL wine_vk_device_extension_supported(const char *name)\n")
2357         f.write("{\n")
2358         f.write("    unsigned int i;\n")
2359         f.write("    for (i = 0; i < ARRAY_SIZE(vk_device_extensions); i++)\n")
2360         f.write("    {\n")
2361         f.write("        if (strcmp(vk_device_extensions[i], name) == 0)\n")
2362         f.write("            return TRUE;\n")
2363         f.write("    }\n")
2364         f.write("    return FALSE;\n")
2365         f.write("}\n\n")
2367         f.write("BOOL wine_vk_instance_extension_supported(const char *name)\n")
2368         f.write("{\n")
2369         f.write("    unsigned int i;\n")
2370         f.write("    for (i = 0; i < ARRAY_SIZE(vk_instance_extensions); i++)\n")
2371         f.write("    {\n")
2372         f.write("        if (strcmp(vk_instance_extensions[i], name) == 0)\n")
2373         f.write("            return TRUE;\n")
2374         f.write("    }\n")
2375         f.write("    return FALSE;\n")
2376         f.write("}\n\n")
2378         f.write("BOOL wine_vk_is_type_wrapped(VkObjectType type)\n")
2379         f.write("{\n")
2380         f.write("    return FALSE")
2381         for handle in self.registry.handles:
2382             if not handle.is_required() or not handle.is_wrapped() or handle.is_alias():
2383                 continue
2384             f.write(" ||\n        type == {}".format(handle.object_type))
2385         f.write(";\n")
2386         f.write("}\n\n")
2388         f.write("uint64_t wine_vk_unwrap_handle(VkObjectType type, uint64_t handle)\n")
2389         f.write("{\n")
2390         f.write("    switch(type)\n")
2391         f.write("    {\n")
2392         for handle in self.registry.handles:
2393             if not handle.is_required() or not handle.is_wrapped() or handle.is_alias():
2394                 continue
2395             f.write("    case {}:\n".format(handle.object_type))
2396             if handle.is_dispatchable():
2397                 f.write("        return (uint64_t) (uintptr_t) ")
2398                 f.write(handle.native_handle("(({}) (uintptr_t) handle)".format(handle.name)))
2399             else:
2400                 f.write("        return (uint64_t) ")
2401                 f.write(handle.native_handle("handle"))
2402             f.write(";\n");
2403         f.write("    default:\n")
2404         f.write("       return handle;\n")
2405         f.write("    }\n")
2406         f.write("}\n")
2408     def generate_thunks_h(self, f, prefix):
2409         self._generate_copyright(f)
2411         f.write("#ifndef __WINE_VULKAN_THUNKS_H\n")
2412         f.write("#define __WINE_VULKAN_THUNKS_H\n\n")
2414         f.write("#define WINE_VK_VERSION VK_API_VERSION_{0}_{1}\n\n".format(WINE_VK_VERSION[0], WINE_VK_VERSION[1]))
2416         # Generate prototypes for device and instance functions requiring a custom implementation.
2417         f.write("/* Functions for which we have custom implementations outside of the thunks. */\n")
2418         for vk_func in self.registry.funcs.values():
2419             if not vk_func.is_required() or vk_func.is_global_func():
2420                 continue
2421             if vk_func.needs_thunk() and not vk_func.needs_private_thunk():
2422                 continue
2424             if vk_func.is_core_func():
2425                 f.write("{0};\n".format(vk_func.prototype("WINAPI", prefix="wine_")))
2426             else:
2427                 f.write("{0};\n".format(vk_func.prototype("WINAPI", prefix="wine_", postfix="DECLSPEC_HIDDEN")))
2428         f.write("\n")
2430         f.write("/* Private thunks */\n")
2431         for vk_func in self.registry.funcs.values():
2432             if vk_func.needs_private_thunk():
2433                 f.write("{0};\n".format(vk_func.prototype(prefix="thunk_", postfix="DECLSPEC_HIDDEN")))
2434         f.write("\n")
2436         for struct in self.host_structs:
2437             f.write(struct.definition(align=False, conv=True, postfix="_host"))
2438         f.write("\n")
2440         for func in self.struct_chain_conversions:
2441             f.write(func.prototype(postfix="DECLSPEC_HIDDEN") + ";\n")
2442         f.write("\n")
2444         f.write("/* For use by vkDevice and children */\n")
2445         f.write("struct vulkan_device_funcs\n{\n")
2446         for vk_func in self.registry.device_funcs:
2447             if not vk_func.is_required():
2448                 continue
2450             if not vk_func.needs_dispatch():
2451                 LOGGER.debug("skipping {0} in vulkan_device_funcs".format(vk_func.name))
2452                 continue
2454             if vk_func.needs_conversion():
2455                 f.write("#if defined(USE_STRUCT_CONVERSION)\n")
2456                 f.write("    {0};\n".format(vk_func.pfn(conv=True)))
2457                 f.write("#else\n")
2458                 f.write("    {0};\n".format(vk_func.pfn(conv=False)))
2459                 f.write("#endif\n")
2460             else:
2461                 f.write("    {0};\n".format(vk_func.pfn(conv=False)))
2462         f.write("};\n\n")
2464         f.write("/* For use by vkInstance and children */\n")
2465         f.write("struct vulkan_instance_funcs\n{\n")
2466         for vk_func in self.registry.instance_funcs + self.registry.phys_dev_funcs:
2467             if not vk_func.is_required():
2468                 continue
2470             if not vk_func.needs_dispatch():
2471                 LOGGER.debug("skipping {0} in vulkan_instance_funcs".format(vk_func.name))
2472                 continue
2474             if vk_func.needs_conversion():
2475                 f.write("#if defined(USE_STRUCT_CONVERSION)\n")
2476                 f.write("    {0};\n".format(vk_func.pfn(conv=True)))
2477                 f.write("#else\n")
2478                 f.write("    {0};\n".format(vk_func.pfn(conv=False)))
2479                 f.write("#endif\n")
2480             else:
2481                 f.write("    {0};\n".format(vk_func.pfn(conv=False)))
2482         f.write("};\n\n")
2484         f.write("#define ALL_VK_DEVICE_FUNCS() \\\n")
2485         first = True
2486         for vk_func in self.registry.device_funcs:
2487             if not vk_func.is_required():
2488                 continue
2490             if not vk_func.needs_dispatch():
2491                 LOGGER.debug("skipping {0} in ALL_VK_DEVICE_FUNCS".format(vk_func.name))
2492                 continue
2494             if first:
2495                 f.write("    USE_VK_FUNC({0})".format(vk_func.name))
2496                 first = False
2497             else:
2498                 f.write(" \\\n    USE_VK_FUNC({0})".format(vk_func.name))
2499         f.write("\n\n")
2501         f.write("#define ALL_VK_INSTANCE_FUNCS() \\\n")
2502         first = True
2503         for vk_func in self.registry.instance_funcs + self.registry.phys_dev_funcs:
2504             if not vk_func.is_required():
2505                 continue
2507             if not vk_func.needs_dispatch():
2508                 LOGGER.debug("skipping {0} in ALL_VK_INSTANCE_FUNCS".format(vk_func.name))
2509                 continue
2511             if first:
2512                 f.write("    USE_VK_FUNC({0})".format(vk_func.name))
2513                 first = False
2514             else:
2515                 f.write(" \\\n    USE_VK_FUNC({0})".format(vk_func.name))
2516         f.write("\n\n")
2518         f.write("#endif /* __WINE_VULKAN_THUNKS_H */\n")
2520     def generate_vulkan_h(self, f):
2521         self._generate_copyright(f)
2522         f.write("#ifndef __WINE_VULKAN_H\n")
2523         f.write("#define __WINE_VULKAN_H\n\n")
2525         f.write("#include <windef.h>\n")
2526         f.write("#include <stdint.h>\n\n")
2528         f.write("/* Define WINE_VK_HOST to get 'host' headers. */\n")
2529         f.write("#ifdef WINE_VK_HOST\n")
2530         f.write("#define VKAPI_CALL\n")
2531         f.write('#define WINE_VK_ALIGN(x)\n')
2532         f.write("#endif\n\n")
2534         f.write("#ifndef VKAPI_CALL\n")
2535         f.write("#define VKAPI_CALL __stdcall\n")
2536         f.write("#endif\n\n")
2538         f.write("#ifndef VKAPI_PTR\n")
2539         f.write("#define VKAPI_PTR VKAPI_CALL\n")
2540         f.write("#endif\n\n")
2542         f.write("#ifndef WINE_VK_ALIGN\n")
2543         f.write("#define WINE_VK_ALIGN DECLSPEC_ALIGN\n")
2544         f.write("#endif\n\n")
2546         # The overall strategy is to define independent constants and datatypes,
2547         # prior to complex structures and function calls to avoid forward declarations.
2548         for const in self.registry.consts:
2549             # For now just generate things we may not need. The amount of parsing needed
2550             # to get some of the info is tricky as you need to figure out which structure
2551             # references a certain constant.
2552             f.write(const.definition())
2553         f.write("\n")
2555         for define in self.registry.defines:
2556             f.write(define.definition())
2558         for handle in self.registry.handles:
2559             # For backward compatibility also create definitions for aliases.
2560             # These types normally don't get pulled in as we use the new types
2561             # even in legacy functions if they are aliases.
2562             if handle.is_required() or handle.is_alias():
2563                  f.write(handle.definition())
2564         f.write("\n")
2566         for base_type in self.registry.base_types:
2567             f.write(base_type.definition())
2568         f.write("\n")
2570         for bitmask in self.registry.bitmasks:
2571             f.write(bitmask.definition())
2572         f.write("\n")
2574         # Define enums, this includes values for some of the bitmask types as well.
2575         for enum in self.registry.enums.values():
2576             if enum.required:
2577                 f.write(enum.definition())
2579         for fp in self.registry.funcpointers:
2580             if fp.required:
2581                 f.write(fp.definition())
2582         f.write("\n")
2584         # This generates both structures and unions. Since structures
2585         # may depend on other structures/unions, we need a list of
2586         # decoupled structs.
2587         # Note: unions are stored in structs for dependency reasons,
2588         # see comment in parsing section.
2589         structs = VkStruct.decouple_structs(self.registry.structs)
2590         for struct in structs:
2591             LOGGER.debug("Generating struct: {0}".format(struct.name))
2592             f.write(struct.definition(align=True))
2594         for func in self.registry.funcs.values():
2595             if not func.is_required():
2596                 LOGGER.debug("Skipping PFN definition for: {0}".format(func.name))
2597                 continue
2599             f.write("typedef {0};\n".format(func.pfn(prefix="PFN", call_conv="VKAPI_PTR")))
2600         f.write("\n")
2602         f.write("#ifndef VK_NO_PROTOTYPES\n")
2603         for func in self.registry.funcs.values():
2604             if not func.is_required():
2605                 LOGGER.debug("Skipping API definition for: {0}".format(func.name))
2606                 continue
2608             LOGGER.debug("Generating API definition for: {0}".format(func.name))
2609             f.write("{0};\n".format(func.prototype(call_conv="VKAPI_CALL")))
2610         f.write("#endif /* VK_NO_PROTOTYPES */\n\n")
2612         f.write("#endif /* __WINE_VULKAN_H */\n")
2614     def generate_vulkan_driver_h(self, f):
2615         self._generate_copyright(f)
2616         f.write("#ifndef __WINE_VULKAN_DRIVER_H\n")
2617         f.write("#define __WINE_VULKAN_DRIVER_H\n\n")
2619         f.write("/* Wine internal vulkan driver version, needs to be bumped upon vulkan_funcs changes. */\n")
2620         f.write("#define WINE_VULKAN_DRIVER_VERSION {0}\n\n".format(DRIVER_VERSION))
2622         f.write("struct vulkan_funcs\n{\n")
2623         f.write("    /* Vulkan global functions. These are the only calls at this point a graphics driver\n")
2624         f.write("     * needs to provide. Other function calls will be provided indirectly by dispatch\n")
2625         f.write("     * tables part of dispatchable Vulkan objects such as VkInstance or vkDevice.\n")
2626         f.write("     */\n")
2628         for vk_func in self.registry.funcs.values():
2629             if not vk_func.is_driver_func():
2630                 continue
2632             pfn = vk_func.pfn()
2633             # Avoid PFN_vkVoidFunction in driver interface as Vulkan likes to put calling convention
2634             # stuff in there. For simplicity substitute with "void *".
2635             pfn = pfn.replace("PFN_vkVoidFunction", "void *")
2636             f.write("    {0};\n".format(pfn))
2638         f.write("\n")
2639         f.write("    /* winevulkan specific functions */\n")
2640         f.write("    VkSurfaceKHR (*p_wine_get_native_surface)(VkSurfaceKHR);\n")
2641         f.write("};\n\n")
2643         f.write("extern const struct vulkan_funcs * CDECL __wine_get_vulkan_driver(HDC hdc, UINT version);\n\n")
2645         f.write("static inline void *get_vulkan_driver_device_proc_addr(\n")
2646         f.write("        const struct vulkan_funcs *vulkan_funcs, const char *name)\n{\n")
2647         f.write("    if (!name || name[0] != 'v' || name[1] != 'k') return NULL;\n\n")
2648         f.write("    name += 2;\n\n")
2649         for vk_func in self.registry.funcs.values():
2650             if vk_func.is_driver_func() and vk_func.is_device_func():
2651                 f.write('    if (!strcmp(name, "{0}"))\n'.format(vk_func.name[2:]))
2652                 f.write('        return vulkan_funcs->p_{0};\n'.format(vk_func.name))
2653         f.write("\n")
2654         f.write("    return NULL;\n}\n\n")
2656         f.write("static inline void *get_vulkan_driver_instance_proc_addr(\n")
2657         f.write("        const struct vulkan_funcs *vulkan_funcs, VkInstance instance, const char *name)\n{\n")
2658         f.write("    if (!name || name[0] != 'v' || name[1] != 'k') return NULL;\n\n")
2659         f.write("    name += 2;\n\n")
2660         for vk_func in self.registry.funcs.values():
2661             if vk_func.is_driver_func() and vk_func.is_global_func() and vk_func.name != "vkGetInstanceProcAddr":
2662                 f.write('    if (!strcmp(name, "{0}"))\n'.format(vk_func.name[2:]))
2663                 f.write('        return vulkan_funcs->p_{0};\n'.format(vk_func.name))
2664         f.write("\n")
2665         f.write("    if (!instance) return NULL;\n\n")
2666         for vk_func in self.registry.funcs.values():
2667             if vk_func.is_driver_func() and (vk_func.is_instance_func() or vk_func.is_phys_dev_func()):
2668                 f.write('    if (!strcmp(name, "{0}"))\n'.format(vk_func.name[2:]))
2669                 f.write('        return vulkan_funcs->p_{0};\n'.format(vk_func.name))
2670         f.write("\n")
2671         f.write("    name -= 2;\n\n")
2672         f.write("    return get_vulkan_driver_device_proc_addr(vulkan_funcs, name);\n}\n\n")
2674         f.write("#endif /* __WINE_VULKAN_DRIVER_H */\n")
2676     def generate_vulkan_spec(self, f):
2677         self._generate_copyright(f, spec_file=True)
2678         f.write("@ stdcall -private vk_icdGetInstanceProcAddr(ptr str) wine_vk_icdGetInstanceProcAddr\n")
2679         f.write("@ stdcall -private vk_icdGetPhysicalDeviceProcAddr(ptr str) wine_vk_icdGetPhysicalDeviceProcAddr\n")
2680         f.write("@ stdcall -private vk_icdNegotiateLoaderICDInterfaceVersion(ptr) wine_vk_icdNegotiateLoaderICDInterfaceVersion\n")
2681         f.write("@ cdecl -norelay native_vkGetInstanceProcAddrWINE(ptr str)\n")
2683         # Export symbols for all Vulkan Core functions.
2684         for func in self.registry.funcs.values():
2685             if not func.is_core_func():
2686                 continue
2688             # We support all Core functions except for VK_KHR_display* APIs.
2689             # Create stubs for unsupported Core functions.
2690             if func.is_required():
2691                 f.write(func.spec(prefix="wine_"))
2692             else:
2693                 f.write("@ stub {0}\n".format(func.name))
2695         f.write("@ stdcall -private DllRegisterServer()\n")
2696         f.write("@ stdcall -private DllUnregisterServer()\n")
2698     def generate_vulkan_loader_spec(self, f):
2699         self._generate_copyright(f, spec_file=True)
2701         # Export symbols for all Vulkan Core functions.
2702         for func in self.registry.funcs.values():
2703             if not func.is_core_func():
2704                 continue
2706             # We support all Core functions except for VK_KHR_display* APIs.
2707             # Create stubs for unsupported Core functions.
2708             if func.is_required():
2709                 f.write(func.spec(symbol="winevulkan.wine_" + func.name))
2710             else:
2711                 f.write("@ stub {0}\n".format(func.name))
2714 class VkRegistry(object):
2715     def __init__(self, reg_filename):
2716         # Used for storage of type information.
2717         self.base_types = None
2718         self.bitmasks = None
2719         self.consts = None
2720         self.defines = None
2721         self.enums = None
2722         self.funcpointers = None
2723         self.handles = None
2724         self.structs = None
2726         # We aggregate all types in here for cross-referencing.
2727         self.funcs = {}
2728         self.types = {}
2730         self.version_regex = re.compile(
2731             r'^'
2732             r'VK_VERSION_'
2733             r'(?P<major>[0-9])'
2734             r'_'
2735             r'(?P<minor>[0-9])'
2736             r'$'
2737         )
2739         # Overall strategy for parsing the registry is to first
2740         # parse all type / function definitions. Then parse
2741         # features and extensions to decide which types / functions
2742         # to actually 'pull in' for code generation. For each type or
2743         # function call we want we set a member 'required' to True.
2744         tree = ET.parse(reg_filename)
2745         root = tree.getroot()
2746         self._parse_enums(root)
2747         self._parse_types(root)
2748         self._parse_commands(root)
2750         # Pull in any required types and functions.
2751         self._parse_features(root)
2752         self._parse_extensions(root)
2754         self._match_object_types()
2756         self.copyright = root.find('./comment').text
2758     def _is_feature_supported(self, feature):
2759         version = self.version_regex.match(feature)
2760         if not version:
2761             return True
2763         version = tuple(map(int, version.group('major', 'minor')))
2764         return version <= WINE_VK_VERSION
2766     def _is_extension_supported(self, extension):
2767         # We disable some extensions as either we haven't implemented
2768         # support yet or because they are for platforms other than win32.
2769         return extension not in UNSUPPORTED_EXTENSIONS
2771     def _mark_command_required(self, command):
2772         """ Helper function to mark a certain command and the datatypes it needs as required."""
2773         def mark_bitmask_dependencies(bitmask, types):
2774             if bitmask.requires is not None:
2775                 types[bitmask.requires]["data"].required = True
2777         def mark_funcpointer_dependencies(fp, types):
2778             for m in fp.members:
2779                 type_info = types[m.type]
2781                 # Complex types have a matching definition e.g. VkStruct.
2782                 # Not needed for base types such as uint32_t.
2783                 if "data" in type_info:
2784                     types[m.type]["data"].required = True
2786         def mark_struct_dependencies(struct, types):
2787              for m in struct:
2788                 type_info = types[m.type]
2790                 # Complex types have a matching definition e.g. VkStruct.
2791                 # Not needed for base types such as uint32_t.
2792                 if "data" in type_info:
2793                     types[m.type]["data"].required = True
2795                 if type_info["category"] == "struct":
2796                     # Yay, recurse
2797                     mark_struct_dependencies(type_info["data"], types)
2798                 elif type_info["category"] == "funcpointer":
2799                     mark_funcpointer_dependencies(type_info["data"], types)
2800                 elif type_info["category"] == "bitmask":
2801                     mark_bitmask_dependencies(type_info["data"], types)
2803         func = self.funcs[command]
2804         func.required = True
2806         # Pull in return type
2807         if func.type != "void":
2808             self.types[func.type]["data"].required = True
2810         # Analyze parameter dependencies and pull in any type needed.
2811         for p in func.params:
2812             type_info = self.types[p.type]
2814             # Check if we are dealing with a complex type e.g. VkEnum, VkStruct and others.
2815             if "data" not in type_info:
2816                 continue
2818             # Mark the complex type as required.
2819             type_info["data"].required = True
2820             if type_info["category"] == "struct":
2821                 struct = type_info["data"]
2822                 mark_struct_dependencies(struct, self.types)
2823             elif type_info["category"] == "bitmask":
2824                 mark_bitmask_dependencies(type_info["data"], self.types)
2826     def _match_object_types(self):
2827         """ Matches each handle with the correct object type. """
2828         # Use upper case comparison for simplicity.
2829         object_types = {}
2830         for value in self.enums["VkObjectType"].values:
2831             object_name = "VK" + value.name[len("VK_OBJECT_TYPE"):].replace("_", "")
2832             object_types[object_name] = value.name
2834         for handle in self.handles:
2835             if not handle.is_required():
2836                 continue
2837             handle.object_type = object_types.get(handle.name.upper())
2838             if not handle.object_type:
2839                 LOGGER.warning("No object type found for {}".format(handle.name))
2841     def _parse_commands(self, root):
2842         """ Parse command section containing the Vulkan function calls. """
2843         funcs = {}
2844         commands = root.findall("./commands/")
2846         # As of Vulkan 1.1, various extensions got promoted to Core.
2847         # The old commands (e.g. KHR) are available for backwards compatibility
2848         # and are marked in vk.xml as 'alias' to the non-extension type.
2849         # The registry likes to avoid data duplication, so parameters and other
2850         # metadata need to be looked up from the Core command.
2851         # We parse the alias commands in a second pass.
2852         alias_commands = []
2853         for command in commands:
2854             alias_name = command.attrib.get("alias")
2855             if alias_name:
2856                 alias_commands.append(command)
2857                 continue
2859             func = VkFunction.from_xml(command, self.types)
2860             funcs[func.name] = func
2862         for command in alias_commands:
2863             alias_name = command.attrib.get("alias")
2864             alias = funcs[alias_name]
2865             func = VkFunction.from_alias(command, alias)
2866             funcs[func.name] = func
2868         # To make life easy for the code generation, separate all function
2869         # calls out in the 4 types of Vulkan functions:
2870         # device, global, physical device and instance.
2871         device_funcs = []
2872         global_funcs = []
2873         phys_dev_funcs = []
2874         instance_funcs = []
2875         for func in funcs.values():
2876             if func.is_device_func():
2877                 device_funcs.append(func)
2878             elif func.is_global_func():
2879                 global_funcs.append(func)
2880             elif func.is_phys_dev_func():
2881                 phys_dev_funcs.append(func)
2882             else:
2883                 instance_funcs.append(func)
2885         # Sort function lists by name and store them.
2886         self.device_funcs = sorted(device_funcs, key=lambda func: func.name)
2887         self.global_funcs = sorted(global_funcs, key=lambda func: func.name)
2888         self.phys_dev_funcs = sorted(phys_dev_funcs, key=lambda func: func.name)
2889         self.instance_funcs = sorted(instance_funcs, key=lambda func: func.name)
2891         # The funcs dictionary is used as a convenient way to lookup function
2892         # calls when needed e.g. to adjust member variables.
2893         self.funcs = OrderedDict(sorted(funcs.items()))
2895     def _parse_enums(self, root):
2896         """ Parse enums section or better described as constants section. """
2897         enums = {}
2898         self.consts = []
2899         for enum in root.findall("./enums"):
2900             name = enum.attrib.get("name")
2901             _type = enum.attrib.get("type")
2903             if _type in ("enum", "bitmask"):
2904                 enums[name] = VkEnum.from_xml(enum)
2905             else:
2906                 # If no type is set, we are dealing with API constants.
2907                 for value in enum.findall("enum"):
2908                     # If enum is an alias, set the value to the alias name.
2909                     # E.g. VK_LUID_SIZE_KHR is an alias to VK_LUID_SIZE.
2910                     alias = value.attrib.get("alias")
2911                     if alias:
2912                         self.consts.append(VkConstant(value.attrib.get("name"), alias))
2913                     else:
2914                         self.consts.append(VkConstant(value.attrib.get("name"), value.attrib.get("value")))
2916         self.enums = OrderedDict(sorted(enums.items()))
2918     def _process_require_enum(self, enum_elem, ext=None, only_aliased=False):
2919         if "extends" in enum_elem.keys():
2920             enum = self.types[enum_elem.attrib["extends"]]["data"]
2922             # Need to define VkEnumValues which were aliased to by another value. This is necessary
2923             # from VK spec version 1.2.135 where the provisional VK_KHR_ray_tracing extension was
2924             # added which altered VK_NV_ray_tracing's VkEnumValues to alias to the provisional
2925             # extension.
2926             aliased = False
2927             for _, t in self.types.items():
2928                 if t["category"] != "enum":
2929                     continue
2930                 if not t["data"]:
2931                     continue
2932                 for value in t["data"].values:
2933                     if value.alias == enum_elem.attrib["name"]:
2934                         aliased = True
2936             if only_aliased and not aliased:
2937                 return
2939             if "bitpos" in enum_elem.keys():
2940                 # We need to add an extra value to an existing enum type.
2941                 # E.g. VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG to VkFormatFeatureFlagBits.
2942                 enum.create_bitpos(enum_elem.attrib["name"], int(enum_elem.attrib["bitpos"]))
2944             elif "offset" in enum_elem.keys():
2945                 # Extensions promoted to Core, have the extension number as part
2946                 # of the enum value. Else retrieve from the extension tag.
2947                 if enum_elem.attrib.get("extnumber"):
2948                     ext_number = int(enum_elem.attrib.get("extnumber"))
2949                 else:
2950                     ext_number = int(ext.attrib["number"])
2951                 offset = int(enum_elem.attrib["offset"])
2952                 value = EXT_BASE + (ext_number - 1) * EXT_BLOCK_SIZE + offset
2954                 # Deal with negative values.
2955                 direction = enum_elem.attrib.get("dir")
2956                 if direction is not None:
2957                     value = -value
2959                 enum.create_value(enum_elem.attrib["name"], str(value))
2961             elif "value" in enum_elem.keys():
2962                 enum.create_value(enum_elem.attrib["name"], enum_elem.attrib["value"])
2963             elif "alias" in enum_elem.keys():
2964                 enum.create_alias(enum_elem.attrib["name"], enum_elem.attrib["alias"])
2966         elif "value" in enum_elem.keys():
2967             # Constants are not aliased, no need to add them here, they'll get added later on.
2968             if only_aliased:
2969                 return
2971             self.consts.append(VkConstant(enum_elem.attrib["name"], enum_elem.attrib["value"]))
2973     @staticmethod
2974     def _require_type(type_info):
2975         if type_info.is_alias():
2976             type_info = type_info.alias
2977         type_info.required = True
2978         if type(type_info) == VkStruct:
2979             for member in type_info.members:
2980                 if "data" in member.type_info:
2981                   VkRegistry._require_type(member.type_info["data"])
2983     def _parse_extensions(self, root):
2984         """ Parse extensions section and pull in any types and commands for this extension. """
2985         extensions = []
2986         exts = root.findall("./extensions/extension")
2987         deferred_exts = []
2988         skipped_exts = UNSUPPORTED_EXTENSIONS.copy()
2990         def process_ext(ext, deferred=False):
2991             ext_name = ext.attrib["name"]
2993             # Set extension name on any functions calls part of this extension as we
2994             # were not aware of the name during initial parsing.
2995             commands = ext.findall("require/command")
2996             for command in commands:
2997                 cmd_name = command.attrib["name"]
2998                 # Need to verify that the command is defined, and otherwise skip it.
2999                 # vkCreateScreenSurfaceQNX is declared in <extensions> but not defined in
3000                 # <commands>. A command without a definition cannot be enabled, so it's valid for
3001                 # the XML file to handle this, but because of the manner in which we parse the XML
3002                 # file we pre-populate from <commands> before we check if a command is enabled.
3003                 if cmd_name in self.funcs:
3004                     self.funcs[cmd_name].extensions.append(ext_name)
3006             # Some extensions are not ready or have numbers reserved as a place holder.
3007             if ext.attrib["supported"] == "disabled":
3008                 LOGGER.debug("Skipping disabled extension: {0}".format(ext_name))
3009                 skipped_exts.append(ext_name)
3010                 return
3012             # Defer extensions with 'sortorder' as they are order-dependent for spec-parsing.
3013             if not deferred and "sortorder" in ext.attrib:
3014                 deferred_exts.append(ext)
3015                 return
3017             # Disable highly experimental extensions as the APIs are unstable and can
3018             # change between minor Vulkan revisions until API is final and becomes KHR
3019             # or NV.
3020             if "KHX" in ext_name or "NVX" in ext_name:
3021                 LOGGER.debug("Skipping experimental extension: {0}".format(ext_name))
3022                 skipped_exts.append(ext_name)
3023                 return
3025             # Extensions can define VkEnumValues which alias to provisional extensions. Pre-process
3026             # extensions to define any required VkEnumValues before the platform check below.
3027             for require in ext.findall("require"):
3028                 # Extensions can add enum values to Core / extension enums, so add these.
3029                 for enum_elem in require.findall("enum"):
3030                     self._process_require_enum(enum_elem, ext, only_aliased=True)
3032             platform = ext.attrib.get("platform")
3033             if platform and platform != "win32":
3034                 LOGGER.debug("Skipping extensions {0} for platform {1}".format(ext_name, platform))
3035                 skipped_exts.append(ext_name)
3036                 return
3038             if not self._is_extension_supported(ext_name):
3039                 LOGGER.debug("Skipping unsupported extension: {0}".format(ext_name))
3040                 skipped_exts.append(ext_name)
3041                 return
3042             elif "requires" in ext.attrib:
3043                 # Check if this extension builds on top of another unsupported extension.
3044                 requires = ext.attrib["requires"].split(",")
3045                 if len(set(requires).intersection(skipped_exts)) > 0:
3046                     skipped_exts.append(ext_name)
3047                     return
3049             LOGGER.debug("Loading extension: {0}".format(ext_name))
3051             # Extensions can define one or more require sections each requiring
3052             # different features (e.g. Vulkan 1.1). Parse each require section
3053             # separately, so we can skip sections we don't want.
3054             for require in ext.findall("require"):
3055                 # Extensions can add enum values to Core / extension enums, so add these.
3056                 for enum_elem in require.findall("enum"):
3057                     self._process_require_enum(enum_elem, ext)
3059                 for t in require.findall("type"):
3060                     type_info = self.types[t.attrib["name"]]["data"]
3061                     self._require_type(type_info)
3062                 feature = require.attrib.get("feature")
3063                 if feature and not self._is_feature_supported(feature):
3064                     continue
3066                 required_extension = require.attrib.get("extension")
3067                 if required_extension and not self._is_extension_supported(required_extension):
3068                     continue
3070                 # Pull in any commands we need. We infer types to pull in from the command
3071                 # as well.
3072                 for command in require.findall("command"):
3073                     cmd_name = command.attrib["name"]
3074                     self._mark_command_required(cmd_name)
3077             # Store a list with extensions.
3078             ext_info = {"name" : ext_name, "type" : ext.attrib["type"]}
3079             extensions.append(ext_info)
3082         # Process extensions, allowing for sortorder to defer extension processing
3083         for ext in exts:
3084             process_ext(ext)
3086         deferred_exts.sort(key=lambda ext: ext.attrib["sortorder"])
3088         # Respect sortorder
3089         for ext in deferred_exts:
3090             process_ext(ext, deferred=True)
3092         # Sort in alphabetical order.
3093         self.extensions = sorted(extensions, key=lambda ext: ext["name"])
3095     def _parse_features(self, root):
3096         """ Parse the feature section, which describes Core commands and types needed. """
3098         for feature in root.findall("./feature"):
3099             feature_name = feature.attrib["name"]
3100             for require in feature.findall("require"):
3101                 LOGGER.info("Including features for {0}".format(require.attrib.get("comment")))
3102                 for tag in require:
3103                     if tag.tag == "comment":
3104                         continue
3105                     elif tag.tag == "command":
3106                         if not self._is_feature_supported(feature_name):
3107                             continue
3108                         name = tag.attrib["name"]
3109                         self._mark_command_required(name)
3110                     elif tag.tag == "enum":
3111                         self._process_require_enum(tag)
3112                     elif tag.tag == "type":
3113                         name = tag.attrib["name"]
3115                         # Skip pull in for vk_platform.h for now.
3116                         if name == "vk_platform":
3117                             continue
3119                         type_info = self.types[name]
3120                         type_info["data"].required = True
3122     def _parse_types(self, root):
3123         """ Parse types section, which contains all data types e.g. structs, typedefs etcetera. """
3124         types = root.findall("./types/type")
3126         base_types = []
3127         bitmasks = []
3128         defines = []
3129         funcpointers = []
3130         handles = []
3131         structs = []
3133         alias_types = []
3134         for t in types:
3135             type_info = {}
3136             type_info["category"] = t.attrib.get("category", None)
3137             type_info["requires"] = t.attrib.get("requires", None)
3139             # We parse aliases in a second pass when we know more.
3140             alias = t.attrib.get("alias")
3141             if alias:
3142                 LOGGER.debug("Alias found: {0}".format(alias))
3143                 alias_types.append(t)
3144                 continue
3146             if type_info["category"] in ["include"]:
3147                 continue
3149             if type_info["category"] == "basetype":
3150                 name = t.find("name").text
3151                 _type = None
3152                 if not t.find("type") is None:
3153                     _type = t.find("type").text
3154                 basetype = VkBaseType(name, _type)
3155                 base_types.append(basetype)
3156                 type_info["data"] = basetype
3158             # Basic C types don't need us to define them, but we do need data for them
3159             if type_info["requires"] == "vk_platform":
3160                 requires = type_info["requires"]
3161                 basic_c = VkBaseType(name, _type, requires=requires)
3162                 type_info["data"] = basic_c
3164             if type_info["category"] == "bitmask":
3165                 name = t.find("name").text
3166                 _type = t.find("type").text
3168                 # Most bitmasks have a requires attribute used to pull in
3169                 # required '*FlagBits" enum.
3170                 requires = type_info["requires"]
3171                 bitmask = VkBaseType(name, _type, requires=requires)
3172                 bitmasks.append(bitmask)
3173                 type_info["data"] = bitmask
3175             if type_info["category"] == "define":
3176                 define = VkDefine.from_xml(t)
3177                 defines.append(define)
3178                 type_info["data"] = define
3180             if type_info["category"] == "enum":
3181                 name = t.attrib.get("name")
3182                 # The type section only contains enum names, not the actual definition.
3183                 # Since we already parsed the enum before, just link it in.
3184                 try:
3185                     type_info["data"] = self.enums[name]
3186                 except KeyError as e:
3187                     # Not all enums seem to be defined yet, typically that's for
3188                     # ones ending in 'FlagBits' where future extensions may add
3189                     # definitions.
3190                     type_info["data"] = None
3192             if type_info["category"] == "funcpointer":
3193                 funcpointer = VkFunctionPointer.from_xml(t)
3194                 funcpointers.append(funcpointer)
3195                 type_info["data"] = funcpointer
3197             if type_info["category"] == "handle":
3198                 handle = VkHandle.from_xml(t)
3199                 handles.append(handle)
3200                 type_info["data"] = handle
3202             if type_info["category"] in ["struct", "union"]:
3203                 # We store unions among structs as some structs depend
3204                 # on unions. The types are very similar in parsing and
3205                 # generation anyway. The official Vulkan scripts use
3206                 # a similar kind of hack.
3207                 struct = VkStruct.from_xml(t)
3208                 structs.append(struct)
3209                 type_info["data"] = struct
3211             # Name is in general within a name tag else it is an optional
3212             # attribute on the type tag.
3213             name_elem = t.find("name")
3214             if name_elem is not None:
3215                 type_info["name"] = name_elem.text
3216             else:
3217                 type_info["name"] = t.attrib.get("name", None)
3219             # Store all type data in a shared dictionary, so we can easily
3220             # look up information for a given type. There are no duplicate
3221             # names.
3222             self.types[type_info["name"]] = type_info
3224         # Second pass for alias types, so we can retrieve all data from
3225         # the aliased object.
3226         for t in alias_types:
3227             type_info = {}
3228             type_info["category"] = t.attrib.get("category")
3229             type_info["name"] = t.attrib.get("name")
3231             alias = t.attrib.get("alias")
3233             if type_info["category"] == "bitmask":
3234                 bitmask = VkBaseType(type_info["name"], alias, alias=self.types[alias]["data"])
3235                 bitmasks.append(bitmask)
3236                 type_info["data"] = bitmask
3238             if type_info["category"] == "enum":
3239                 enum = VkEnum.from_alias(t, self.types[alias]["data"])
3240                 type_info["data"] = enum
3241                 self.enums[enum.name] = enum
3243             if type_info["category"] == "handle":
3244                 handle = VkHandle.from_alias(t, self.types[alias]["data"])
3245                 handles.append(handle)
3246                 type_info["data"] = handle
3248             if type_info["category"] == "struct":
3249                 struct = VkStruct.from_alias(t, self.types[alias]["data"])
3250                 structs.append(struct)
3251                 type_info["data"] = struct
3253             self.types[type_info["name"]] = type_info
3255         # We need detailed type information during code generation
3256         # on structs for alignment reasons. Unfortunately structs
3257         # are parsed among other types, so there is no guarantee
3258         # that any types needed have been parsed already, so set
3259         # the data now.
3260         for struct in structs:
3261             struct.set_type_info(self.types)
3263             # Alias structures have enum values equivalent to those of the
3264             # structure which they are aliased against. we need to ignore alias
3265             # structs when populating the struct extensions list, otherwise we
3266             # will create duplicate case entries.
3267             if struct.alias:
3268                 continue
3270             for structextend in struct.structextends:
3271                 s = self.types[structextend]["data"]
3272                 s.struct_extensions.append(struct)
3274         # Guarantee everything is sorted, so code generation doesn't have
3275         # to deal with this.
3276         self.base_types = sorted(base_types, key=lambda base_type: base_type.name)
3277         self.bitmasks = sorted(bitmasks, key=lambda bitmask: bitmask.name)
3278         self.defines = defines
3279         self.enums = OrderedDict(sorted(self.enums.items()))
3280         self.funcpointers = sorted(funcpointers, key=lambda fp: fp.name)
3281         self.handles = sorted(handles, key=lambda handle: handle.name)
3282         self.structs = sorted(structs, key=lambda struct: struct.name)
3284 def generate_vulkan_json(f):
3285     f.write("{\n")
3286     f.write("    \"file_format_version\": \"1.0.0\",\n")
3287     f.write("    \"ICD\": {\n")
3288     f.write("        \"library_path\": \".\\\\winevulkan.dll\",\n")
3289     f.write("        \"api_version\": \"{0}\"\n".format(VK_XML_VERSION))
3290     f.write("    }\n")
3291     f.write("}\n")
3293 def set_working_directory():
3294     path = os.path.abspath(__file__)
3295     path = os.path.dirname(path)
3296     os.chdir(path)
3298 def download_vk_xml(filename):
3299     url = "https://raw.githubusercontent.com/KhronosGroup/Vulkan-Docs/v{0}/xml/vk.xml".format(VK_XML_VERSION)
3300     if not os.path.isfile(filename):
3301         urllib.request.urlretrieve(url, filename)
3303 def main():
3304     parser = argparse.ArgumentParser()
3305     parser.add_argument("-v", "--verbose", action="count", default=0, help="increase output verbosity")
3306     parser.add_argument("-x", "--xml", default=None, type=str, help="path to specification XML file")
3308     args = parser.parse_args()
3309     if args.verbose == 0:
3310         LOGGER.setLevel(logging.WARNING)
3311     elif args.verbose == 1:
3312         LOGGER.setLevel(logging.INFO)
3313     else: # > 1
3314         LOGGER.setLevel(logging.DEBUG)
3316     set_working_directory()
3318     if args.xml:
3319         vk_xml = args.xml
3320     else:
3321         vk_xml = "vk-{0}.xml".format(VK_XML_VERSION)
3322         download_vk_xml(vk_xml)
3324     registry = VkRegistry(vk_xml)
3325     generator = VkGenerator(registry)
3327     with open(WINE_VULKAN_H, "w") as f:
3328         generator.generate_vulkan_h(f)
3330     with open(WINE_VULKAN_DRIVER_H, "w") as f:
3331         generator.generate_vulkan_driver_h(f)
3333     with open(WINE_VULKAN_THUNKS_H, "w") as f:
3334         generator.generate_thunks_h(f, "wine_")
3336     with open(WINE_VULKAN_THUNKS_C, "w") as f:
3337         generator.generate_thunks_c(f, "wine_")
3339     with open(WINE_VULKAN_JSON, "w") as f:
3340         generate_vulkan_json(f)
3342     with open(WINE_VULKAN_SPEC, "w") as f:
3343         generator.generate_vulkan_spec(f)
3345     with open(WINE_VULKAN_LOADER_SPEC, "w") as f:
3346         generator.generate_vulkan_loader_spec(f)
3348 if __name__ == "__main__":
3349     main()