mfplat: Implement GetContiguousLength() for d3d11 buffer.
[wine/zf.git] / dlls / winevulkan / make_vulkan
bloba0e59a0370e792e976b4a164454fe787bf2f6c33
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()
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 or VkPhysicalDevice.
606         if self.params[0].type in ["VkInstance", "VkPhysicalDevice"]:
607             return True
608         return False
610     def is_required(self):
611         return self.required
613     def needs_conversion(self):
614         """ Check if the function needs any input/output type conversion.
615         Functions need input/output conversion if struct parameters have
616         alignment differences between Win32 and Linux 32-bit.
617         """
619         for p in self.params:
620             if p.needs_conversion():
621                 LOGGER.debug("Parameter {0} to {1} requires conversion".format(p.name, self.name))
622                 return True
624         return False
626     def needs_dispatch(self):
627         return self.dispatch
629     def needs_thunk(self):
630         return self.thunk_needed
632     def needs_private_thunk(self):
633         return self.private_thunk
635     def pfn(self, prefix="p", call_conv=None, conv=False):
636         """ Create function pointer. """
638         if call_conv:
639             pfn = "{0} ({1} *{2}_{3})(".format(self.type, call_conv, prefix, self.name)
640         else:
641             pfn = "{0} (*{1}_{2})(".format(self.type, prefix, self.name)
643         for i, param in enumerate(self.params):
644             if param.const:
645                 pfn += param.const + " "
647             pfn += param.type
648             if conv and param.needs_conversion():
649                 pfn += "_host"
651             if param.is_pointer():
652                 pfn += " " + param.pointer
654             if param.array_len is not None:
655                 pfn += "[{0}]".format(param.array_len)
657             if i < len(self.params) - 1:
658                 pfn += ", "
659         pfn += ")"
660         return pfn
662     def prototype(self, call_conv=None, prefix=None, postfix=None):
663         """ Generate prototype for given function.
665         Args:
666             call_conv (str, optional): calling convention e.g. WINAPI
667             prefix (str, optional): prefix to append prior to function name e.g. vkFoo -> wine_vkFoo
668             postfix (str, optional): text to append after function name but prior to semicolon e.g. DECLSPEC_HIDDEN
669         """
671         proto = "{0}".format(self.type)
673         if call_conv is not None:
674             proto += " {0}".format(call_conv)
676         if prefix is not None:
677             proto += " {0}{1}(".format(prefix, self.name)
678         else:
679             proto += " {0}(".format(self.name)
681         # Add all the parameters.
682         proto += ", ".join([p.definition() for p in self.params])
684         if postfix is not None:
685             proto += ") {0}".format(postfix)
686         else:
687             proto += ")"
689         return proto
691     def body(self):
692         body = ""
694         if not self.needs_private_thunk():
695             body += "    {0}".format(self.trace())
697         params = ", ".join([p.variable(conv=False) for p in self.params])
699         # Call the native Vulkan function.
700         if self.type == "void":
701             body += "    {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
702         else:
703             body += "    return {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
705         return body
707     def body_conversion(self):
708         body = ""
710         # Declare a variable to hold the result for non-void functions.
711         if self.type != "void":
712             body += "    {0} result;\n".format(self.type)
714         # Declare any tmp parameters for conversion.
715         for p in self.params:
716             if not p.needs_conversion():
717                 continue
719             if p.is_dynamic_array():
720                 body += "    {0}_host *{1}_host;\n".format(p.type, p.name)
721             else:
722                 body += "    {0}_host {1}_host;\n".format(p.type, p.name)
724         if not self.needs_private_thunk():
725             body += "    {0}\n".format(self.trace())
727         # Call any win_to_host conversion calls.
728         for p in self.params:
729             if not p.needs_input_conversion():
730                 continue
732             body += p.copy(Direction.INPUT)
734         # Build list of parameters containing converted and non-converted parameters.
735         # The param itself knows if conversion is needed and applies it when we set conv=True.
736         params = ", ".join([p.variable(conv=True) for p in self.params])
738         # Call the native Vulkan function.
739         if self.type == "void":
740             body += "    {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
741         else:
742             body += "    result = {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
744         body += "\n"
746         # Call any host_to_win conversion calls.
747         for p in self.params:
748             if not p.needs_output_conversion():
749                 continue
751             body += p.copy(Direction.OUTPUT)
753         # Perform any required cleanups. Most of these are for array functions.
754         for p in self.params:
755             if not p.needs_free():
756                 continue
758             body += p.free()
760         # Finally return the result.
761         if self.type != "void":
762             body += "    return result;\n"
764         return body
766     def spec(self, prefix=None, symbol=None):
767         """ Generate spec file entry for this function.
769         Args
770             prefix (str, optional): prefix to prepend to entry point name.
771             symbol (str, optional): allows overriding the name of the function implementing the entry point.
772         """
774         spec = ""
775         params = " ".join([p.spec() for p in self.params])
776         if prefix is not None:
777             spec += "@ stdcall -private {0}{1}({2})".format(prefix, self.name, params)
778         else:
779             spec += "@ stdcall {0}({1})".format(self.name, params)
781         if symbol is not None:
782             spec += " " + symbol
784         spec += "\n"
785         return spec
787     def stub(self, call_conv=None, prefix=None):
788         stub = self.prototype(call_conv=call_conv, prefix=prefix)
789         stub += "\n{\n"
790         stub += "    {0}".format(self.trace(message="stub: ", trace_func="FIXME"))
792         if self.type == "VkResult":
793             stub += "    return VK_ERROR_OUT_OF_HOST_MEMORY;\n"
794         elif self.type == "VkBool32":
795             stub += "    return VK_FALSE;\n"
796         elif self.type == "PFN_vkVoidFunction":
797             stub += "    return NULL;\n"
799         stub += "}\n\n"
800         return stub
802     def thunk(self, call_conv=None, prefix=None):
803         thunk = self.prototype(call_conv=call_conv, prefix=prefix)
804         thunk += "\n{\n"
806         if self.needs_conversion():
807             thunk += "#if defined(USE_STRUCT_CONVERSION)\n"
808             thunk += self.body_conversion()
809             thunk += "#else\n"
810             thunk += self.body()
811             thunk += "#endif\n"
812         else:
813             thunk += self.body()
815         thunk += "}\n\n"
816         return thunk
818     def trace(self, message=None, trace_func=None):
819         """ Create a trace string including all parameters.
821         Args:
822             message (str, optional): text to print at start of trace message e.g. 'stub: '
823             trace_func (str, optional): used to override trace function e.g. FIXME, printf, etcetera.
824         """
825         if trace_func is not None:
826             trace = "{0}(\"".format(trace_func)
827         else:
828             trace = "TRACE(\""
830         if message is not None:
831             trace += message
833         # First loop is for all the format strings.
834         trace += ", ".join([p.format_string() for p in self.params])
835         trace += "\\n\""
837         # Second loop for parameter names and optional conversions.
838         for param in self.params:
839             if param.format_conv is not None:
840                 trace += ", " + param.format_conv.format(param.name)
841             else:
842                 trace += ", {0}".format(param.name)
843         trace += ");\n"
845         return trace
848 class VkFunctionPointer(object):
849     def __init__(self, _type, name, members, forward_decls):
850         self.name = name
851         self.members = members
852         self.type = _type
853         self.required = False
854         self.forward_decls = forward_decls
856     @staticmethod
857     def from_xml(funcpointer):
858         members = []
859         begin = None
861         for t in funcpointer.findall("type"):
862             # General form:
863             # <type>void</type>*       pUserData,
864             # Parsing of the tail (anything past </type>) is tricky since there
865             # can be other data on the next line like: const <type>int</type>..
867             const = True if begin and "const" in begin else False
868             _type = t.text
869             lines = t.tail.split(",\n")
870             if lines[0][0] == "*":
871                 pointer = "*"
872                 name = lines[0][1:].strip()
873             else:
874                 pointer = None
875                 name = lines[0].strip()
877             # Filter out ); if it is contained.
878             name = name.partition(");")[0]
880             # If tail encompasses multiple lines, assign the second line to begin
881             # for the next line.
882             try:
883                 begin = lines[1].strip()
884             except IndexError:
885                 begin = None
887             members.append(VkMember(const=const, _type=_type, pointer=pointer, name=name))
889         _type = funcpointer.text
890         name = funcpointer.find("name").text
891         if "requires" in funcpointer.attrib:
892             forward_decls = funcpointer.attrib.get("requires").split(",")
893         else:
894             forward_decls = []
895         return VkFunctionPointer(_type, name, members, forward_decls)
897     def definition(self):
898         text = ""
899         # forward declare required structs
900         for decl in self.forward_decls:
901             text += "typedef struct {0} {0};\n".format(decl)
903         text += "{0} {1})(\n".format(self.type, self.name)
905         first = True
906         if len(self.members) > 0:
907             for m in self.members:
908                 if first:
909                     text += "    " + m.definition()
910                     first = False
911                 else:
912                     text += ",\n    " + m.definition()
913         else:
914             # Just make the compiler happy by adding a void parameter.
915             text += "void"
916         text += ");\n"
917         return text
919     def is_alias(self):
920         return False
922 class VkHandle(object):
923     def __init__(self, name, _type, parent, alias=None):
924         self.name = name
925         self.type = _type
926         self.parent = parent
927         self.alias = alias
928         self.required = False
929         self.object_type = None
931     @staticmethod
932     def from_alias(handle, alias):
933         name = handle.attrib.get("name")
934         return VkHandle(name, alias.type, alias.parent, alias=alias)
936     @staticmethod
937     def from_xml(handle):
938         name = handle.find("name").text
939         _type = handle.find("type").text
940         parent = handle.attrib.get("parent") # Most objects have a parent e.g. VkQueue has VkDevice.
941         return VkHandle(name, _type, parent)
943     def dispatch_table(self):
944         if not self.is_dispatchable():
945             return None
947         if self.parent is None:
948             # Should only happen for VkInstance
949             return "funcs"
950         elif self.name == "VkDevice":
951             # VkDevice has VkInstance as a parent, but has its own dispatch table.
952             return "funcs"
953         elif self.parent in ["VkInstance", "VkPhysicalDevice"]:
954             return "instance->funcs"
955         elif self.parent in ["VkDevice", "VkCommandPool"]:
956             return "device->funcs"
957         else:
958             LOGGER.error("Unhandled dispatchable parent: {0}".format(self.parent))
960     def definition(self):
961         """ Generates handle definition e.g. VK_DEFINE_HANDLE(vkInstance) """
963         # Legacy types are typedef'ed to the new type if they are aliases.
964         if self.is_alias():
965             return "typedef {0} {1};\n".format(self.alias.name, self.name)
967         return "{0}({1})\n".format(self.type, self.name)
969     def is_alias(self):
970         return self.alias is not None
972     def is_dispatchable(self):
973         """ Some handles like VkInstance, VkDevice are dispatchable objects,
974         which means they contain a dispatch table of function pointers.
975         """
976         return self.type == "VK_DEFINE_HANDLE"
978     def is_required(self):
979         return self.required
981     def native_handle(self, name):
982         """ Provide access to the native handle of a wrapped object. """
984         if self.name == "VkCommandPool":
985             return "wine_cmd_pool_from_handle({0})->command_pool".format(name)
986         if self.name == "VkDebugUtilsMessengerEXT":
987             return "wine_debug_utils_messenger_from_handle({0})->debug_messenger".format(name)
988         if self.name == "VkDebugReportCallbackEXT":
989             return "wine_debug_report_callback_from_handle({0})->debug_callback".format(name)
990         if self.name == "VkSurfaceKHR":
991             return "wine_surface_from_handle({0})->surface".format(name)
993         native_handle_name = None
995         if self.name == "VkCommandBuffer":
996             native_handle_name = "command_buffer"
997         if self.name == "VkDevice":
998             native_handle_name = "device"
999         if self.name == "VkInstance":
1000             native_handle_name = "instance"
1001         if self.name == "VkPhysicalDevice":
1002             native_handle_name = "phys_dev"
1003         if self.name == "VkQueue":
1004             native_handle_name = "queue"
1006         if native_handle_name:
1007             return "{0}->{1}".format(name, native_handle_name)
1009         if self.is_dispatchable():
1010             LOGGER.error("Unhandled native handle for: {0}".format(self.name))
1011         return None
1013     def driver_handle(self, name):
1014         """ Provide access to the handle that should be passed to the wine driver """
1016         if self.name == "VkSurfaceKHR":
1017             return "wine_surface_from_handle({0})->driver_surface".format(name)
1019         return self.native_handle(name)
1021     def is_wrapped(self):
1022         return self.native_handle("test") is not None
1024 class VkMember(object):
1025     def __init__(self, const=False, struct_fwd_decl=False,_type=None, pointer=None, name=None, array_len=None,
1026             dyn_array_len=None, optional=False, values=None):
1027         self.const = const
1028         self.struct_fwd_decl = struct_fwd_decl
1029         self.name = name
1030         self.pointer = pointer
1031         self.type = _type
1032         self.type_info = None
1033         self.array_len = array_len
1034         self.dyn_array_len = dyn_array_len
1035         self.optional = optional
1036         self.values = values
1038     def __eq__(self, other):
1039         """ Compare member based on name against a string.
1041         This method is for convenience by VkStruct, which holds a number of members and needs quick checking
1042         if certain members exist.
1043         """
1045         return self.name == other
1047     def __repr__(self):
1048         return "{0} {1} {2} {3} {4} {5} {6}".format(self.const, self.struct_fwd_decl, self.type, self.pointer,
1049                 self.name, self.array_len, self.dyn_array_len)
1051     @staticmethod
1052     def from_xml(member):
1053         """ Helper function for parsing a member tag within a struct or union. """
1055         name_elem = member.find("name")
1056         type_elem = member.find("type")
1058         const = False
1059         struct_fwd_decl = False
1060         member_type = None
1061         pointer = None
1062         array_len = None
1064         values = member.get("values")
1066         if member.text:
1067             if "const" in member.text:
1068                 const = True
1070             # Some members contain forward declarations:
1071             # - VkBaseInstructure has a member "const struct VkBaseInStructure *pNext"
1072             # - VkWaylandSurfaceCreateInfoKHR has a member "struct wl_display *display"
1073             if "struct" in member.text:
1074                 struct_fwd_decl = True
1076         if type_elem is not None:
1077             member_type = type_elem.text
1078             if type_elem.tail is not None:
1079                 pointer = type_elem.tail.strip() if type_elem.tail.strip() != "" else None
1081         # Name of other member within, which stores the number of
1082         # elements pointed to be by this member.
1083         dyn_array_len = member.get("len")
1085         # Some members are optional, which is important for conversion code e.g. not dereference NULL pointer.
1086         optional = True if member.get("optional") else False
1088         # Usually we need to allocate memory for dynamic arrays. We need to do the same in a few other cases
1089         # like for VkCommandBufferBeginInfo.pInheritanceInfo. Just threat such cases as dynamic arrays of
1090         # size 1 to simplify code generation.
1091         if dyn_array_len is None and pointer is not None:
1092             dyn_array_len = 1
1094         # Some members are arrays, attempt to parse these. Formats include:
1095         # <member><type>char</type><name>extensionName</name>[<enum>VK_MAX_EXTENSION_NAME_SIZE</enum>]</member>
1096         # <member><type>uint32_t</type><name>foo</name>[4]</member>
1097         if name_elem.tail and name_elem.tail[0] == '[':
1098             LOGGER.debug("Found array type")
1099             enum_elem = member.find("enum")
1100             if enum_elem is not None:
1101                 array_len = enum_elem.text
1102             else:
1103                 # Remove brackets around length
1104                 array_len = name_elem.tail.strip("[]")
1106         return VkMember(const=const, struct_fwd_decl=struct_fwd_decl, _type=member_type, pointer=pointer, name=name_elem.text,
1107                 array_len=array_len, dyn_array_len=dyn_array_len, optional=optional, values=values)
1109     def copy(self, input, output, direction):
1110         """ Helper method for use by conversion logic to generate a C-code statement to copy this member. """
1112         if self.needs_conversion():
1113             if self.is_dynamic_array():
1114                 if direction == Direction.OUTPUT:
1115                     LOGGER.warn("TODO: implement copying of returnedonly dynamic array for {0}.{1}".format(self.type, self.name))
1116                 else:
1117                     # Array length is either a variable name (string) or an int.
1118                     count = self.dyn_array_len if isinstance(self.dyn_array_len, int) else "{0}{1}".format(input, self.dyn_array_len)
1119                     return "{0}{1} = convert_{2}_array_win_to_host({3}{1}, {4});\n".format(output, self.name, self.type, input, count)
1120             elif self.is_static_array():
1121                 count = self.array_len
1122                 if direction == Direction.OUTPUT:
1123                     # Needed by VkMemoryHeap.memoryHeaps
1124                     return "convert_{0}_static_array_host_to_win({2}{1}, {3}{1}, {4});\n".format(self.type, self.name, input, output, count)
1125                 else:
1126                     # Nothing needed this yet.
1127                     LOGGER.warn("TODO: implement copying of static array for {0}.{1}".format(self.type, self.name))
1128             else:
1129                 if direction == Direction.OUTPUT:
1130                     return "convert_{0}_host_to_win(&{2}{1}, &{3}{1});\n".format(self.type, self.name, input, output)
1131                 else:
1132                     return "convert_{0}_win_to_host(&{2}{1}, &{3}{1});\n".format(self.type, self.name, input, output)
1133         elif self.is_static_array():
1134             bytes_count = "{0} * sizeof({1})".format(self.array_len, self.type)
1135             return "memcpy({0}{1}, {2}{1}, {3});\n".format(output, self.name, input, bytes_count)
1136         else:
1137             return "{0}{1} = {2}{1};\n".format(output, self.name, input)
1139     def definition(self, align=False, conv=False):
1140         """ Generate prototype for given function.
1142         Args:
1143             align (bool, optional): Enable alignment if a type needs it. This adds WINE_VK_ALIGN(8) to a member.
1144             conv (bool, optional): Enable conversion if a type needs it. This appends '_host' to the name.
1145         """
1147         text = ""
1148         if self.is_const():
1149             text += "const "
1151         if self.is_struct_forward_declaration():
1152             text += "struct "
1154         if conv and self.is_struct():
1155             text += "{0}_host".format(self.type)
1156         else:
1157             text += self.type
1159         if self.is_pointer():
1160             text += " {0}{1}".format(self.pointer, self.name)
1161         else:
1162             if align and self.needs_alignment():
1163                 text += " WINE_VK_ALIGN(8) " + self.name
1164             else:
1165                 text += " " + self.name
1167         if self.is_static_array():
1168             text += "[{0}]".format(self.array_len)
1170         return text
1172     def get_conversions(self):
1173         """ Return any conversion description for this member and its children when conversion is needed. """
1175         # Check if we need conversion either for this member itself or for any child members
1176         # in case member represents a struct.
1177         if not self.needs_conversion():
1178             return None
1180         conversions = []
1182         # Collect any conversion for any member structs.
1183         struct = self.type_info["data"]
1184         for m in struct:
1185             m.needs_struct_extensions_conversion()
1186             if m.needs_conversion():
1187                 conversions.extend(m.get_conversions())
1189         struct.needs_struct_extensions_conversion()
1191         struct = self.type_info["data"]
1192         direction = Direction.OUTPUT if struct.returnedonly else Direction.INPUT
1193         if self.is_dynamic_array():
1194             conversions.append(ConversionFunction(False, True, direction, struct))
1195         elif self.is_static_array():
1196             conversions.append(ConversionFunction(True, False, direction, struct))
1197         else:
1198             conversions.append(ConversionFunction(False, False, direction, struct))
1200         if self.needs_free():
1201             conversions.append(FreeFunction(self.is_dynamic_array(), struct))
1203         return conversions
1205     def is_const(self):
1206         return self.const
1208     def is_dynamic_array(self):
1209         """ Returns if the member is an array element.
1210         Vulkan uses this for dynamically sized arrays for which
1211         there is a 'count' parameter.
1212         """
1213         return self.dyn_array_len is not None
1215     def is_handle(self):
1216         return self.type_info["category"] == "handle"
1218     def is_pointer(self):
1219         return self.pointer is not None
1221     def is_static_array(self):
1222         """ Returns if the member is an array.
1223         Vulkan uses this often for fixed size arrays in which the
1224         length is part of the member.
1225         """
1226         return self.array_len is not None
1228     def is_struct(self):
1229         return self.type_info["category"] == "struct"
1231     def is_struct_forward_declaration(self):
1232         return self.struct_fwd_decl
1234     def is_union(self):
1235         return self.type_info["category"] == "union"
1237     def needs_alignment(self):
1238         """ Check if this member needs alignment for 64-bit data.
1239         Various structures need alignment on 64-bit variables due
1240         to compiler differences on 32-bit between Win32 and Linux.
1241         """
1243         if self.is_pointer():
1244             return False
1245         elif self.type == "size_t":
1246             return False
1247         elif self.type in ["uint64_t", "VkDeviceSize"]:
1248             return True
1249         elif self.is_struct():
1250             struct = self.type_info["data"]
1251             return struct.needs_alignment()
1252         elif self.is_handle():
1253             # Dispatchable handles are pointers to objects, while
1254             # non-dispatchable are uint64_t and hence need alignment.
1255             handle = self.type_info["data"]
1256             return False if handle.is_dispatchable() else True
1257         return False
1259     def needs_conversion(self):
1260         """ Structures requiring alignment, need conversion between win32 and host. """
1262         if not self.is_struct():
1263             return False
1265         struct = self.type_info["data"]
1266         return struct.needs_conversion()
1268     def needs_free(self):
1269         if not self.needs_conversion():
1270             return False
1272         if self.is_dynamic_array():
1273             return True
1275         # TODO: some non-pointer structs and optional pointer structs may need freeing,
1276         # though none of this type have been encountered yet.
1277         return False
1279     def needs_struct_extensions_conversion(self):
1280         if not self.is_struct():
1281             return False
1283         struct = self.type_info["data"]
1284         return struct.needs_struct_extensions_conversion()
1286     def set_type_info(self, type_info):
1287         """ Helper function to set type information from the type registry.
1288         This is needed, because not all type data is available at time of
1289         parsing.
1290         """
1291         self.type_info = type_info
1294 class VkParam(object):
1295     """ Helper class which describes a parameter to a function call. """
1297     def __init__(self, type_info, const=None, pointer=None, name=None, array_len=None, dyn_array_len=None):
1298         self.const = const
1299         self.name = name
1300         self.array_len = array_len
1301         self.dyn_array_len = dyn_array_len
1302         self.pointer = pointer
1303         self.type_info = type_info
1304         self.type = type_info["name"] # For convenience
1305         self.handle = type_info["data"] if type_info["category"] == "handle" else None
1306         self.struct = type_info["data"] if type_info["category"] == "struct" else None
1308         self._set_direction()
1309         self._set_format_string()
1310         self._set_conversions()
1312     def __repr__(self):
1313         return "{0} {1} {2} {3} {4} {5}".format(self.const, self.type, self.pointer, self.name, self.array_len, self.dyn_array_len)
1315     @staticmethod
1316     def from_xml(param, types):
1317         """ Helper function to create VkParam from xml. """
1319         # Parameter parsing is slightly tricky. All the data is contained within
1320         # a param tag, but some data is within subtags while others are text
1321         # before or after the type tag.
1322         # Common structure:
1323         # <param>const <type>char</type>* <name>pLayerName</name></param>
1325         name_elem = param.find("name")
1326         array_len = None
1327         name = name_elem.text
1328         # Tail contains array length e.g. for blendConstants param of vkSetBlendConstants
1329         if name_elem.tail is not None:
1330             array_len = name_elem.tail.strip("[]")
1332         # Name of other parameter in function prototype, which stores the number of
1333         # elements pointed to be by this parameter.
1334         dyn_array_len = param.get("len", None)
1336         const = param.text.strip() if param.text else None
1337         type_elem = param.find("type")
1338         pointer = type_elem.tail.strip() if type_elem.tail.strip() != "" else None
1340         # Since we have parsed all types before hand, this should not happen.
1341         type_info = types.get(type_elem.text, None)
1342         if type_info is None:
1343             LOGGER.err("type info not found for: {0}".format(type_elem.text))
1345         return VkParam(type_info, const=const, pointer=pointer, name=name, array_len=array_len, dyn_array_len=dyn_array_len)
1347     def _set_conversions(self):
1348         """ Internal helper function to configure any needed conversion functions. """
1350         self.free_func = None
1351         self.input_conv = None
1352         self.output_conv = None
1353         if not self.needs_conversion():
1354             return
1356         # Input functions require win to host conversion.
1357         if self._direction in [Direction.INPUT, Direction.INPUT_OUTPUT]:
1358             self.input_conv = ConversionFunction(False, self.is_dynamic_array(), Direction.INPUT, self.struct)
1360         # Output functions require host to win conversion.
1361         if self._direction in [Direction.INPUT_OUTPUT, Direction.OUTPUT]:
1362             self.output_conv = ConversionFunction(False, self.is_dynamic_array(), Direction.OUTPUT, self.struct)
1364         # Dynamic arrays, but also some normal structs (e.g. VkCommandBufferBeginInfo) need memory
1365         # allocation and thus some cleanup.
1366         if self.is_dynamic_array() or self.struct.needs_free():
1367             self.free_func = FreeFunction(self.is_dynamic_array(), self.struct)
1369     def _set_direction(self):
1370         """ Internal helper function to set parameter direction (input/output/input_output). """
1372         # The parameter direction needs to be determined from hints in vk.xml like returnedonly,
1373         # parameter constness and other heuristics.
1374         # For now we need to get this right for structures as we need to convert these, we may have
1375         # missed a few other edge cases (e.g. count variables).
1376         # See also https://github.com/KhronosGroup/Vulkan-Docs/issues/610
1378         if not self.is_pointer():
1379             self._direction = Direction.INPUT
1380         elif self.is_const() and self.is_pointer():
1381             self._direction = Direction.INPUT
1382         elif self.is_struct():
1383             if not self.struct.returnedonly:
1384                 self._direction = Direction.INPUT
1385                 return
1387             # Returnedonly hints towards output, however in some cases
1388             # it is inputoutput. In particular if pNext / sType exist,
1389             # which are used to link in other structures without having
1390             # to introduce new APIs. E.g. vkGetPhysicalDeviceProperties2KHR.
1391             if "pNext" in self.struct:
1392                 self._direction = Direction.INPUT_OUTPUT
1393                 return
1395             self._direction = Direction.OUTPUT
1396         else:
1397             # This should mostly be right. Count variables can be inout, but we don't care about these yet.
1398             self._direction = Direction.OUTPUT
1400     def _set_format_string(self):
1401         """ Internal helper function to be used by constructor to set format string. """
1403         # Determine a format string used by code generation for traces.
1404         # 64-bit types need a conversion function.
1405         self.format_conv = None
1406         if self.is_static_array() or self.is_pointer():
1407             self.format_str = "%p"
1408         else:
1409             if self.type_info["category"] in ["bitmask"]:
1410                 # Since 1.2.170 bitmasks can be 32 or 64-bit, check the basetype.
1411                 if self.type_info["data"].type == "VkFlags64":
1412                     self.format_str = "0x%s"
1413                     self.format_conv = "wine_dbgstr_longlong({0})"
1414                 else:
1415                     self.format_str = "%#x"
1416             elif self.type_info["category"] in ["enum"]:
1417                 self.format_str = "%#x"
1418             elif self.is_handle():
1419                 # We use uint64_t for non-dispatchable handles as opposed to pointers
1420                 # for dispatchable handles.
1421                 if self.handle.is_dispatchable():
1422                     self.format_str = "%p"
1423                 else:
1424                     self.format_str = "0x%s"
1425                     self.format_conv = "wine_dbgstr_longlong({0})"
1426             elif self.type == "float":
1427                 self.format_str = "%f"
1428             elif self.type == "int":
1429                 self.format_str = "%d"
1430             elif self.type == "int32_t":
1431                 self.format_str = "%d"
1432             elif self.type == "size_t":
1433                 self.format_str = "0x%s"
1434                 self.format_conv = "wine_dbgstr_longlong({0})"
1435             elif self.type in ["uint16_t", "uint32_t", "VkBool32"]:
1436                 self.format_str = "%u"
1437             elif self.type in ["uint64_t", "VkDeviceAddress", "VkDeviceSize"]:
1438                 self.format_str = "0x%s"
1439                 self.format_conv = "wine_dbgstr_longlong({0})"
1440             elif self.type == "HANDLE":
1441                 self.format_str = "%p"
1442             elif self.type in ["VisualID", "xcb_visualid_t", "RROutput"]:
1443                 # Don't care about Linux specific types.
1444                 self.format_str = ""
1445             else:
1446                 LOGGER.warn("Unhandled type: {0}".format(self.type_info))
1448     def copy(self, direction):
1449         if direction == Direction.INPUT:
1450             if self.is_dynamic_array():
1451                 return "    {0}_host = convert_{1}_array_win_to_host({0}, {2});\n".format(self.name, self.type, self.dyn_array_len)
1452             else:
1453                 return "    convert_{0}_win_to_host({1}, &{1}_host);\n".format(self.type, self.name)
1454         else:
1455             if self.is_dynamic_array():
1456                 LOGGER.error("Unimplemented output conversion for: {0}".format(self.name))
1457             else:
1458                 return "    convert_{0}_host_to_win(&{1}_host, {1});\n".format(self.type, self.name)
1460     def definition(self, postfix=None):
1461         """ Return prototype for the parameter. E.g. 'const char *foo' """
1463         proto = ""
1464         if self.const:
1465             proto += self.const + " "
1467         proto += self.type
1469         if self.is_pointer():
1470             proto += " {0}{1}".format(self.pointer, self.name)
1471         else:
1472             proto += " " + self.name
1474         # Allows appending something to the variable name useful for
1475         # win32 to host conversion.
1476         if postfix is not None:
1477             proto += postfix
1479         if self.is_static_array():
1480             proto += "[{0}]".format(self.array_len)
1482         return proto
1484     def direction(self):
1485         """ Returns parameter direction: input, output, input_output.
1487         Parameter direction in Vulkan is not straight-forward, which this function determines.
1488         """
1490         return self._direction
1492     def dispatch_table(self):
1493         """ Return functions dispatch table pointer for dispatchable objects. """
1495         if not self.is_dispatchable():
1496             return None
1498         return "{0}->{1}".format(self.name, self.handle.dispatch_table())
1500     def format_string(self):
1501         return self.format_str
1503     def free(self):
1504         if self.is_dynamic_array():
1505             if self.struct.returnedonly:
1506                 # For returnedonly, counts is stored in a pointer.
1507                 return "    free_{0}_array({1}_host, *{2});\n".format(self.type, self.name, self.dyn_array_len)
1508             else:
1509                 return "    free_{0}_array({1}_host, {2});\n".format(self.type, self.name, self.dyn_array_len)
1510         else:
1511             # We are operating on a single structure. Some structs (very rare) contain dynamic members,
1512             # which would need freeing.
1513             if self.struct.needs_free():
1514                 return "    free_{0}(&{1}_host);\n".format(self.type, self.name)
1515         return ""
1517     def get_conversions(self):
1518         """ Get a list of conversions required for this parameter if any.
1519         Parameters which are structures may require conversion between win32
1520         and the host platform. This function returns a list of conversions
1521         required.
1522         """
1524         if not self.is_struct():
1525             return None
1527         self.struct.needs_struct_extensions_conversion()
1528         for m in self.struct:
1529             m.needs_struct_extensions_conversion()
1531         if not self.needs_conversion():
1532             return None
1534         conversions = []
1536         # Collect any member conversions first, so we can guarantee
1537         # those functions will be defined prior to usage by the
1538         # 'parent' param requiring conversion.
1539         for m in self.struct:
1540             if not m.is_struct():
1541                 continue
1543             if not m.needs_conversion():
1544                 continue
1546             conversions.extend(m.get_conversions())
1548         # Conversion requirements for the 'parent' parameter.
1549         if self.input_conv is not None:
1550             conversions.append(self.input_conv)
1551         if self.output_conv is not None:
1552             conversions.append(self.output_conv)
1553         if self.free_func is not None:
1554             conversions.append(self.free_func)
1556         return conversions
1558     def is_const(self):
1559         return self.const is not None
1561     def is_dynamic_array(self):
1562         return self.dyn_array_len is not None
1564     def is_dispatchable(self):
1565         if not self.is_handle():
1566             return False
1568         return self.handle.is_dispatchable()
1570     def is_handle(self):
1571         return self.handle is not None
1573     def is_pointer(self):
1574         return self.pointer is not None
1576     def is_static_array(self):
1577         return self.array_len is not None
1579     def is_struct(self):
1580         return self.struct is not None
1582     def needs_conversion(self):
1583         """ Returns if parameter needs conversion between win32 and host. """
1585         if not self.is_struct():
1586             return False
1588         # VkSparseImageMemoryRequirements(2) is used by vkGetImageSparseMemoryRequirements(2).
1589         # This function is tricky to wrap, because how to wrap depends on whether
1590         # pSparseMemoryRequirements is NULL or not. Luckily for VkSparseImageMemoryRequirements(2)
1591         # the alignment works out in such a way that no conversion is needed between win32 and Linux.
1592         if self.type in ["VkSparseImageMemoryRequirements", "VkSparseImageMemoryRequirements2"]:
1593             return False
1595         # If a structure needs alignment changes, it means we need to
1596         # perform parameter conversion between win32 and host.
1597         if self.struct.needs_conversion():
1598             return True
1600         return False
1602     def needs_free(self):
1603         return self.free_func is not None
1605     def needs_input_conversion(self):
1606         return self.input_conv is not None
1608     def needs_output_conversion(self):
1609         return self.output_conv is not None
1611     def spec(self):
1612         """ Generate spec file entry for this parameter. """
1614         if self.is_pointer() and self.type == "char":
1615             return "str"
1616         if self.is_dispatchable() or self.is_pointer() or self.is_static_array():
1617             return "ptr"
1618         if self.type_info["category"] in ["bitmask"]:
1619             # Since 1.2.170 bitmasks can be 32 or 64-bit, check the basetype.
1620             if self.type_info["data"].type == "VkFlags64":
1621                 return "int64"
1622             else:
1623                 return "long"
1624         if self.type_info["category"] in ["enum"]:
1625             return "long"
1626         if self.is_handle() and not self.is_dispatchable():
1627             return "int64"
1628         if self.type == "float":
1629             return "float"
1630         if self.type in ["int", "int32_t", "size_t", "uint16_t", "uint32_t", "VkBool32"]:
1631             return "long"
1632         if self.type in ["uint64_t", "VkDeviceSize"]:
1633             return "int64"
1635         LOGGER.error("Unhandled spec conversion for type: {0}".format(self.type))
1637     def variable(self, conv=False):
1638         """ Returns 'glue' code during generation of a function call on how to access the variable.
1639         This function handles various scenarios such as 'unwrapping' if dispatchable objects and
1640         renaming of parameters in case of win32 -> host conversion.
1642         Args:
1643             conv (bool, optional): Enable conversion if the param needs it. This appends '_host' to the name.
1644         """
1646         # Hack until we enable allocation callbacks from ICD to application. These are a joy
1647         # to enable one day, because of calling convention conversion.
1648         if "VkAllocationCallbacks" in self.type:
1649             LOGGER.debug("TODO: setting NULL VkAllocationCallbacks for {0}".format(self.name))
1650             return "NULL"
1652         if conv and self.needs_conversion():
1653             if self.is_dynamic_array():
1654                 return "{0}_host".format(self.name)
1655             else:
1656                 return "&{0}_host".format(self.name)
1657         else:
1658             # We need to pass the native handle to the native Vulkan calls and
1659             # the wine driver's handle to calls which are wrapped by the driver.
1660             driver_handle = self.handle.driver_handle(self.name) if self.is_handle() else None
1661             return driver_handle if driver_handle else self.name
1664 class VkStruct(Sequence):
1665     """ Class which represents the type union and struct. """
1667     def __init__(self, name, members, returnedonly, structextends, alias=None, union=False):
1668         self.name = name
1669         self.members = members
1670         self.returnedonly = returnedonly
1671         self.structextends = structextends
1672         self.required = False
1673         self.alias = alias
1674         self.union = union
1675         self.type_info = None # To be set later.
1676         self.struct_extensions = []
1677         self.aliased_by = []
1679     def __getitem__(self, i):
1680         return self.members[i]
1682     def __len__(self):
1683         return len(self.members)
1685     @staticmethod
1686     def from_alias(struct, alias):
1687         name = struct.attrib.get("name")
1688         aliasee = VkStruct(name, alias.members, alias.returnedonly, alias.structextends, alias=alias)
1690         alias.add_aliased_by(aliasee)
1691         return aliasee
1693     @staticmethod
1694     def from_xml(struct):
1695         # Unions and structs are the same parsing wise, but we need to
1696         # know which one we are dealing with later on for code generation.
1697         union = True if struct.attrib["category"] == "union" else False
1699         name = struct.attrib.get("name")
1701         # 'Output' structures for which data is filled in by the API are
1702         # marked as 'returnedonly'.
1703         returnedonly = True if struct.attrib.get("returnedonly") else False
1705         structextends = struct.attrib.get("structextends")
1706         structextends = structextends.split(",") if structextends else []
1708         members = []
1709         for member in struct.findall("member"):
1710             vk_member = VkMember.from_xml(member)
1711             members.append(vk_member)
1713         return VkStruct(name, members, returnedonly, structextends, union=union)
1715     @staticmethod
1716     def decouple_structs(structs):
1717         """ Helper function which decouples a list of structs.
1718         Structures often depend on other structures. To make the C compiler
1719         happy we need to define 'substructures' first. This function analyzes
1720         the list of structures and reorders them in such a way that they are
1721         decoupled.
1722         """
1724         tmp_structs = list(structs) # Don't modify the original structures.
1725         decoupled_structs = []
1727         while (len(tmp_structs) > 0):
1728             for struct in tmp_structs:
1729                 dependends = False
1731                 if not struct.required:
1732                     tmp_structs.remove(struct)
1733                     continue
1735                 for m in struct:
1736                     if not (m.is_struct() or m.is_union()):
1737                         continue
1739                     # VkBaseInstructure and VkBaseOutStructure reference themselves.
1740                     if m.type == struct.name:
1741                         break
1743                     found = False
1744                     # Check if a struct we depend on has already been defined.
1745                     for s in decoupled_structs:
1746                         if s.name == m.type:
1747                             found = True
1748                             break
1750                     if not found:
1751                         # Check if the struct we depend on is even in the list of structs.
1752                         # If found now, it means we haven't met all dependencies before we
1753                         # can operate on the current struct.
1754                         # When generating 'host' structs we may not be able to find a struct
1755                         # as the list would only contain the structs requiring conversion.
1756                         for s in tmp_structs:
1757                             if s.name == m.type:
1758                                 dependends = True
1759                                 break
1761                 if dependends == False:
1762                     decoupled_structs.append(struct)
1763                     tmp_structs.remove(struct)
1765         return decoupled_structs
1767     def definition(self, align=False, conv=False, postfix=None):
1768         """ Convert structure to textual definition.
1770         Args:
1771             align (bool, optional): enable alignment to 64-bit for win32 struct compatibility.
1772             conv (bool, optional): enable struct conversion if the struct needs it.
1773             postfix (str, optional): text to append to end of struct name, useful for struct renaming.
1774         """
1776         # Only define alias structs when doing conversions
1777         if self.is_alias() and not conv:
1778             return ""
1780         if self.union:
1781             text = "typedef union {0}".format(self.name)
1782         else:
1783             text = "typedef struct {0}".format(self.name)
1785         if postfix is not None:
1786             text += postfix
1788         text += "\n{\n"
1790         for m in self:
1791             if align and m.needs_alignment():
1792                 text += "    {0};\n".format(m.definition(align=align))
1793             elif conv and m.needs_conversion():
1794                 text += "    {0};\n".format(m.definition(conv=conv))
1795             else:
1796                 text += "    {0};\n".format(m.definition())
1798         if postfix is not None:
1799             text += "}} {0}{1};\n\n".format(self.name, postfix)
1800         else:
1801             text += "}} {0};\n".format(self.name)
1803         for aliasee in self.aliased_by:
1804             text += "typedef {0} {1};\n".format(self.name, aliasee.name)
1806         text += "\n"
1808         return text
1810     def is_alias(self):
1811         return bool(self.alias)
1813     def add_aliased_by(self, aliasee):
1814         self.aliased_by.append(aliasee)
1816     def needs_alignment(self):
1817         """ Check if structure needs alignment for 64-bit data.
1818         Various structures need alignment on 64-bit variables due
1819         to compiler differences on 32-bit between Win32 and Linux.
1820         """
1822         for m in self.members:
1823             if m.needs_alignment():
1824                 return True
1825         return False
1827     def needs_conversion(self):
1828         """ Returns if struct members needs conversion between win32 and host.
1829         Structures need conversion if they contain members requiring alignment
1830         or if they include other structures which need alignment.
1831         """
1833         if self.needs_alignment():
1834             return True
1836         for m in self.members:
1837             if m.needs_conversion():
1838                 return True
1839         return False
1841     def needs_free(self):
1842         """ Check if any struct member needs some memory freeing."""
1844         for m in self.members:
1845             if m.needs_free():
1846                 return True
1848             continue
1850         return False
1852     def needs_struct_extensions_conversion(self):
1853         """ Checks if structure extensions in pNext chain need conversion. """
1854         ret = False
1856         for e in self.struct_extensions:
1857             if e.required and e.needs_conversion():
1858                 LOGGER.error("Unhandled pNext chain conversion for {0}".format(e.name))
1859                 ret = True
1861         return ret
1863     def set_type_info(self, types):
1864         """ Helper function to set type information from the type registry.
1865         This is needed, because not all type data is available at time of
1866         parsing.
1867         """
1868         for m in self.members:
1869             type_info = types[m.type]
1870             m.set_type_info(type_info)
1873 class ConversionFunction(object):
1874     def __init__(self, array, dyn_array, direction, struct):
1875         self.array = array
1876         self.direction = direction
1877         self.dyn_array = dyn_array
1878         self.struct = struct
1879         self.type = struct.name
1881         self._set_name()
1883     def __eq__(self, other):
1884         return self.name == other.name
1886     def _generate_array_conversion_func(self):
1887         """ Helper function for generating a conversion function for array structs. """
1889         if self.direction == Direction.OUTPUT:
1890             params = ["const {0}_host *in".format(self.type), "uint32_t count"]
1891             return_type = self.type
1892         else:
1893             params = ["const {0} *in".format(self.type), "uint32_t count"]
1894             return_type = "{0}_host".format(self.type)
1896         # Generate function prototype.
1897         body = "static inline {0} *{1}(".format(return_type, self.name)
1898         body += ", ".join(p for p in params)
1899         body += ")\n{\n"
1901         body += "    {0} *out;\n".format(return_type)
1902         body += "    unsigned int i;\n\n"
1903         body += "    if (!in) return NULL;\n\n"
1905         body += "    out = heap_alloc(count * sizeof(*out));\n"
1907         body += "    for (i = 0; i < count; i++)\n"
1908         body += "    {\n"
1910         for m in self.struct:
1911             # TODO: support copying of pNext extension structures!
1912             # Luckily though no extension struct at this point needs conversion.
1913             body += "        " + m.copy("in[i].", "out[i].", self.direction)
1915         body += "    }\n\n"
1916         body += "    return out;\n"
1917         body += "}\n\n"
1918         return body
1920     def _generate_conversion_func(self):
1921         """ Helper function for generating a conversion function for non-array structs. """
1923         if self.direction == Direction.OUTPUT:
1924             params = ["const {0}_host *in".format(self.type), "{0} *out".format(self.type)]
1925         else:
1926             params = ["const {0} *in".format(self.type), "{0}_host *out".format(self.type)]
1928         body = "static inline void {0}(".format(self.name)
1930         # Generate parameter list
1931         body += ", ".join(p for p in params)
1932         body += ")\n{\n"
1934         body += "    if (!in) return;\n\n"
1936         if self.direction == Direction.INPUT and "pNext" in self.struct and self.struct.returnedonly:
1937             # We are dealing with an input_output parameter. For these we only need to copy
1938             # pNext and sType as the other fields are filled in by the host. We do potentially
1939             # have to iterate over pNext and perform conversions based on switch(sType)!
1940             # Luckily though no extension structs at this point need conversion.
1941             # TODO: support copying of pNext extension structures!
1942             body += "    out->pNext = in->pNext;\n"
1943             body += "    out->sType = in->sType;\n"
1944         else:
1945             for m in self.struct:
1946                 # TODO: support copying of pNext extension structures!
1947                 body += "    " + m.copy("in->", "out->", self.direction)
1949         body += "}\n\n"
1950         return body
1952     def _generate_static_array_conversion_func(self):
1953         """ Helper function for generating a conversion function for array structs. """
1955         if self.direction == Direction.OUTPUT:
1956             params = ["const {0}_host *in".format(self.type), "{0} *out".format(self.type), "uint32_t count"]
1957         else:
1958             params = ["const {0} *in".format(self.type), "{0} *out_host".format(self.type), "uint32_t count"]
1960         # Generate function prototype.
1961         body = "static inline void {0}(".format(self.name)
1962         body += ", ".join(p for p in params)
1963         body += ")\n{\n"
1964         body += "    unsigned int i;\n\n"
1965         body += "    if (!in) return;\n\n"
1966         body += "    for (i = 0; i < count; i++)\n"
1967         body += "    {\n"
1969         for m in self.struct:
1970             # TODO: support copying of pNext extension structures!
1971             body += "        " + m.copy("in[i].", "out[i].", self.direction)
1973         body += "    }\n"
1974         body += "}\n\n"
1975         return body
1977     def _set_name(self):
1978         if self.direction == Direction.INPUT:
1979             if self.array:
1980                 name = "convert_{0}_static_array_win_to_host".format(self.type)
1981             elif self.dyn_array:
1982                 name = "convert_{0}_array_win_to_host".format(self.type)
1983             else:
1984                 name = "convert_{0}_win_to_host".format(self.type)
1985         else: # Direction.OUTPUT
1986             if self.array:
1987                 name = "convert_{0}_static_array_host_to_win".format(self.type)
1988             elif self.dyn_array:
1989                 name = "convert_{0}_array_host_to_win".format(self.type)
1990             else:
1991                 name = "convert_{0}_host_to_win".format(self.type)
1993         self.name = name
1995     def definition(self):
1996         if self.array:
1997             return self._generate_static_array_conversion_func()
1998         elif self.dyn_array:
1999             return self._generate_array_conversion_func()
2000         else:
2001             return self._generate_conversion_func()
2004 class FreeFunction(object):
2005     def __init__(self, dyn_array, struct):
2006         self.dyn_array = dyn_array
2007         self.struct = struct
2008         self.type = struct.name
2010         if dyn_array:
2011             self.name = "free_{0}_array".format(self.type)
2012         else:
2013             self.name = "free_{0}".format(self.type)
2015     def __eq__(self, other):
2016         return self.name == other.name
2018     def _generate_array_free_func(self):
2019         """ Helper function for cleaning up temporary buffers required for array conversions. """
2021         # Generate function prototype.
2022         body = "static inline void {0}({1}_host *in, uint32_t count)\n{{\n".format(self.name, self.type)
2024         # E.g. VkGraphicsPipelineCreateInfo_host needs freeing for pStages.
2025         if self.struct.needs_free():
2026             body += "    unsigned int i;\n\n"
2027             body += "    if (!in) return;\n\n"
2028             body += "    for (i = 0; i < count; i++)\n"
2029             body += "    {\n"
2031             for m in self.struct:
2032                 if m.needs_conversion() and m.is_dynamic_array():
2033                     if m.is_const():
2034                         # Add a cast to ignore const on conversion structs we allocated ourselves.
2035                         body += "        free_{0}_array(({0}_host *)in[i].{1}, in[i].{2});\n".format(m.type, m.name, m.dyn_array_len)
2036                     else:
2037                         body += "        free_{0}_array(in[i].{1}, in[i].{2});\n".format(m.type, m.name, m.dyn_array_len)
2038                 elif m.needs_conversion():
2039                     LOGGER.error("Unhandled conversion for {0}".format(m.name))
2040             body += "    }\n"
2041         else:
2042             body += "    if (!in) return;\n\n"
2044         body += "    heap_free(in);\n"
2046         body += "}\n\n"
2047         return body
2049     def _generate_free_func(self):
2050         # E.g. VkCommandBufferBeginInfo.pInheritanceInfo needs freeing.
2051         if not self.struct.needs_free():
2052             return ""
2054         # Generate function prototype.
2055         body = "static inline void {0}({1}_host *in)\n{{\n".format(self.name, self.type)
2057         for m in self.struct:
2058             if m.needs_conversion() and m.is_dynamic_array():
2059                 count = m.dyn_array_len if isinstance(m.dyn_array_len, int) else "in->{0}".format(m.dyn_array_len)
2060                 if m.is_const():
2061                     # Add a cast to ignore const on conversion structs we allocated ourselves.
2062                     body += "    free_{0}_array(({0}_host *)in->{1}, {2});\n".format(m.type, m.name, count)
2063                 else:
2064                     body += "    free_{0}_array(in->{1}, {2});\n".format(m.type, m.name, count)
2066         body += "}\n\n"
2067         return body
2069     def definition(self):
2070         if self.dyn_array:
2071             return self._generate_array_free_func()
2072         else:
2073             # Some structures need freeing too if they contain dynamic arrays.
2074             # E.g. VkCommandBufferBeginInfo
2075             return self._generate_free_func()
2078 class StructChainConversionFunction(object):
2079     def __init__(self, direction, struct):
2080         self.direction = direction
2081         self.struct = struct
2082         self.type = struct.name
2084         self.name = "convert_{0}_struct_chain".format(self.type)
2086     def __eq__(self, other):
2087         return self.name == other.name
2089     def prototype(self, postfix=""):
2090         return "VkResult {0}(const void *pNext, {1} *out_struct) {2}".format(self.name, self.type, postfix).strip()
2092     def definition(self):
2093         body = self.prototype()
2094         body += "\n{\n"
2096         body += "    VkBaseOutStructure *out_header = (VkBaseOutStructure *)out_struct;\n";
2097         body += "    const VkBaseInStructure *in_header;\n\n";
2099         body += "    out_header->pNext = NULL;\n\n"
2101         body += "    for (in_header = pNext; in_header; in_header = in_header->pNext)\n"
2102         body += "    {\n"
2103         body += "        switch (in_header->sType)\n"
2104         body += "        {\n"
2106         # Ignore to not confuse host loader.
2107         body += "        case VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO:\n"
2108         body += "        case VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO:\n"
2109         body += "            break;\n\n"
2111         for e in self.struct.struct_extensions:
2112             if not e.required:
2113                 continue
2115             stype = next(x for x in e.members if x.name == "sType")
2117             body += "        case {0}:\n".format(stype.values)
2118             body += "        {\n"
2120             body += "            const {0} *in = (const {0} *)in_header;\n".format(e.name)
2121             body += "            {0} *out;\n\n".format(e.name)
2123             body += "            if (!(out = heap_alloc(sizeof(*out)))) goto out_of_memory;\n\n"
2125             for m in e:
2126                 if m.name == "pNext":
2127                     body += "            out->pNext = NULL;\n"
2128                 else:
2129                     body += "            " + m.copy("in->", "out->", self.direction)
2131             body += "\n            out_header->pNext = (VkBaseOutStructure *)out;\n"
2132             body += "            out_header = out_header->pNext;\n"
2133             body += "            break;\n"
2134             body += "        }\n\n"
2136         body += "        default:\n"
2137         body += "            FIXME(\"Application requested a linked structure of type %u.\\n\", in_header->sType);\n"
2139         body += "        }\n"
2140         body += "    }\n\n"
2142         body += "    return VK_SUCCESS;\n"
2144         if any(x for x in self.struct.struct_extensions if x.required):
2145             body += "\nout_of_memory:\n"
2146             body += "    free_{0}_struct_chain(out_struct);\n".format(self.type)
2147             body += "    return VK_ERROR_OUT_OF_HOST_MEMORY;\n"
2149         body += "}\n\n"
2150         return body
2152 class FreeStructChainFunction(object):
2153     def __init__(self, struct):
2154         self.struct = struct
2155         self.type = struct.name
2157         self.name = "free_{0}_struct_chain".format(self.type)
2159     def __eq__(self, other):
2160         return self.name == other.name
2162     def prototype(self, postfix=""):
2163         return "void {0}({1} *s) {2}".format(self.name, self.type, postfix).strip()
2165     def definition(self):
2166         body = self.prototype()
2167         body += "\n{\n"
2169         body += "    VkBaseOutStructure *header = (void *)s->pNext;\n\n";
2171         body += "    while (header)\n"
2172         body += "    {\n"
2173         body += "        void *prev = header;\n"
2174         body += "        header = header->pNext;\n"
2175         body += "        heap_free(prev);\n"
2176         body += "    }\n\n"
2178         body += "    s->pNext = NULL;\n"
2180         body += "}\n\n"
2181         return body
2184 class VkGenerator(object):
2185     def __init__(self, registry):
2186         self.registry = registry
2188         # Build a list conversion functions for struct conversion.
2189         self.conversions = []
2190         self.struct_chain_conversions = []
2191         self.host_structs = []
2192         for func in self.registry.funcs.values():
2193             if not func.is_required():
2194                 continue
2196             if not func.needs_conversion():
2197                 continue
2199             conversions = func.get_conversions()
2200             for conv in conversions:
2201                 # Pull in any conversions for vulkan_thunks.c.
2202                 if func.needs_thunk():
2203                     # Append if we don't already have this conversion.
2204                     if not any(c == conv for c in self.conversions):
2205                         self.conversions.append(conv)
2207                 # Structs can be used in different ways by different conversions
2208                 # e.g. array vs non-array. Just make sure we pull in each struct once.
2209                 if not any(s.name == conv.struct.name for s in self.host_structs):
2210                     self.host_structs.append(conv.struct)
2212         for struct in self.registry.structs:
2213             if struct.name in STRUCT_CHAIN_CONVERSIONS:
2214                 self.struct_chain_conversions.append(StructChainConversionFunction(Direction.INPUT, struct))
2215                 self.struct_chain_conversions.append(FreeStructChainFunction(struct))
2217     def _generate_copyright(self, f, spec_file=False):
2218         f.write("# " if spec_file else "/* ")
2219         f.write("Automatically generated from Vulkan vk.xml; DO NOT EDIT!\n")
2220         lines = ["", "This file is generated from Vulkan vk.xml file covered",
2221             "by the following copyright and permission notice:"]
2222         lines.extend([l.rstrip(" ") for l in self.registry.copyright.splitlines()])
2223         for line in lines:
2224             f.write("{0}{1}".format("# " if spec_file else " * ", line).rstrip(" ") + "\n")
2225         f.write("\n" if spec_file else " */\n\n")
2227     def generate_thunks_c(self, f, prefix):
2228         self._generate_copyright(f)
2229         f.write("#include \"config.h\"\n")
2230         f.write("#include \"wine/port.h\"\n\n")
2232         f.write("#include \"vulkan_private.h\"\n\n")
2234         f.write("WINE_DEFAULT_DEBUG_CHANNEL(vulkan);\n\n")
2236         # Generate any conversion helper functions.
2237         f.write("#if defined(USE_STRUCT_CONVERSION)\n")
2238         for conv in self.conversions:
2239             f.write(conv.definition())
2240         f.write("#endif /* USE_STRUCT_CONVERSION */\n\n")
2242         for conv in self.struct_chain_conversions:
2243             f.write(conv.definition())
2245         # Create thunks for instance and device functions.
2246         # Global functions don't go through the thunks.
2247         for vk_func in self.registry.funcs.values():
2248             if not vk_func.is_required():
2249                 continue
2251             if vk_func.is_global_func():
2252                 continue
2254             if not vk_func.needs_thunk():
2255                 continue
2257             # Exports symbols for Core functions.
2258             if not vk_func.is_core_func() and not vk_func.needs_private_thunk():
2259                 f.write("static ")
2261             if vk_func.needs_private_thunk():
2262                 f.write(vk_func.thunk(prefix="thunk_"))
2263             else:
2264                 f.write(vk_func.thunk(prefix=prefix, call_conv="WINAPI"))
2266         f.write("static const struct vulkan_func vk_device_dispatch_table[] =\n{\n")
2267         for vk_func in self.registry.device_funcs:
2268             if not vk_func.is_required():
2269                 continue
2271             f.write("    {{\"{0}\", &{1}{0}}},\n".format(vk_func.name, prefix))
2272         f.write("};\n\n")
2274         f.write("static const struct vulkan_func vk_instance_dispatch_table[] =\n{\n")
2275         for vk_func in self.registry.instance_funcs:
2276             if not vk_func.is_required():
2277                 continue
2279             f.write("    {{\"{0}\", &{1}{0}}},\n".format(vk_func.name, prefix))
2280         f.write("};\n\n")
2282         f.write("void *wine_vk_get_device_proc_addr(const char *name)\n")
2283         f.write("{\n")
2284         f.write("    unsigned int i;\n")
2285         f.write("    for (i = 0; i < ARRAY_SIZE(vk_device_dispatch_table); i++)\n")
2286         f.write("    {\n")
2287         f.write("        if (strcmp(vk_device_dispatch_table[i].name, name) == 0)\n")
2288         f.write("        {\n")
2289         f.write("            TRACE(\"Found name=%s in device table\\n\", debugstr_a(name));\n")
2290         f.write("            return vk_device_dispatch_table[i].func;\n")
2291         f.write("        }\n")
2292         f.write("    }\n")
2293         f.write("    return NULL;\n")
2294         f.write("}\n\n")
2296         f.write("void *wine_vk_get_instance_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_instance_dispatch_table); i++)\n")
2300         f.write("    {\n")
2301         f.write("        if (strcmp(vk_instance_dispatch_table[i].name, name) == 0)\n")
2302         f.write("        {\n")
2303         f.write("            TRACE(\"Found name=%s in instance table\\n\", debugstr_a(name));\n")
2304         f.write("            return vk_instance_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         # Create array of device extensions.
2311         f.write("static const char * const vk_device_extensions[] =\n{\n")
2312         for ext in self.registry.extensions:
2313             if ext["type"] != "device":
2314                 continue
2316             f.write("    \"{0}\",\n".format(ext["name"]))
2317         f.write("};\n\n")
2319         # Create array of instance extensions.
2320         f.write("static const char * const vk_instance_extensions[] =\n{\n")
2321         for ext in self.registry.extensions:
2322             if ext["type"] != "instance":
2323                 continue
2325             f.write("    \"{0}\",\n".format(ext["name"]))
2326         f.write("};\n\n")
2328         f.write("BOOL wine_vk_device_extension_supported(const char *name)\n")
2329         f.write("{\n")
2330         f.write("    unsigned int i;\n")
2331         f.write("    for (i = 0; i < ARRAY_SIZE(vk_device_extensions); i++)\n")
2332         f.write("    {\n")
2333         f.write("        if (strcmp(vk_device_extensions[i], name) == 0)\n")
2334         f.write("            return TRUE;\n")
2335         f.write("    }\n")
2336         f.write("    return FALSE;\n")
2337         f.write("}\n\n")
2339         f.write("BOOL wine_vk_instance_extension_supported(const char *name)\n")
2340         f.write("{\n")
2341         f.write("    unsigned int i;\n")
2342         f.write("    for (i = 0; i < ARRAY_SIZE(vk_instance_extensions); i++)\n")
2343         f.write("    {\n")
2344         f.write("        if (strcmp(vk_instance_extensions[i], name) == 0)\n")
2345         f.write("            return TRUE;\n")
2346         f.write("    }\n")
2347         f.write("    return FALSE;\n")
2348         f.write("}\n\n")
2350         f.write("BOOL wine_vk_is_type_wrapped(VkObjectType type)\n")
2351         f.write("{\n")
2352         f.write("    return FALSE")
2353         for handle in self.registry.handles:
2354             if not handle.is_required() or not handle.is_wrapped() or handle.is_alias():
2355                 continue
2356             f.write(" ||\n        type == {}".format(handle.object_type))
2357         f.write(";\n")
2358         f.write("}\n\n")
2360         f.write("uint64_t wine_vk_unwrap_handle(VkObjectType type, uint64_t handle)\n")
2361         f.write("{\n")
2362         f.write("    switch(type)\n")
2363         f.write("    {\n")
2364         for handle in self.registry.handles:
2365             if not handle.is_required() or not handle.is_wrapped() or handle.is_alias():
2366                 continue
2367             f.write("    case {}:\n".format(handle.object_type))
2368             if handle.is_dispatchable():
2369                 f.write("        return (uint64_t) (uintptr_t) ")
2370                 f.write(handle.native_handle("(({}) (uintptr_t) handle)".format(handle.name)))
2371             else:
2372                 f.write("        return (uint64_t) ")
2373                 f.write(handle.native_handle("handle"))
2374             f.write(";\n");
2375         f.write("    default:\n")
2376         f.write("       return handle;\n")
2377         f.write("    }\n")
2378         f.write("}\n")
2380     def generate_thunks_h(self, f, prefix):
2381         self._generate_copyright(f)
2383         f.write("#ifndef __WINE_VULKAN_THUNKS_H\n")
2384         f.write("#define __WINE_VULKAN_THUNKS_H\n\n")
2386         f.write("#define WINE_VK_VERSION VK_API_VERSION_{0}_{1}\n\n".format(WINE_VK_VERSION[0], WINE_VK_VERSION[1]))
2388         # Generate prototypes for device and instance functions requiring a custom implementation.
2389         f.write("/* Functions for which we have custom implementations outside of the thunks. */\n")
2390         for vk_func in self.registry.funcs.values():
2391             if not vk_func.is_required() or vk_func.is_global_func():
2392                 continue
2393             if vk_func.needs_thunk() and not vk_func.needs_private_thunk():
2394                 continue
2396             if vk_func.is_core_func():
2397                 f.write("{0};\n".format(vk_func.prototype("WINAPI", prefix="wine_")))
2398             else:
2399                 f.write("{0};\n".format(vk_func.prototype("WINAPI", prefix="wine_", postfix="DECLSPEC_HIDDEN")))
2400         f.write("\n")
2402         f.write("/* Private thunks */\n")
2403         for vk_func in self.registry.funcs.values():
2404             if vk_func.needs_private_thunk():
2405                 f.write("{0};\n".format(vk_func.prototype(prefix="thunk_", postfix="DECLSPEC_HIDDEN")))
2406         f.write("\n")
2408         for struct in self.host_structs:
2409             f.write(struct.definition(align=False, conv=True, postfix="_host"))
2410         f.write("\n")
2412         for func in self.struct_chain_conversions:
2413             f.write(func.prototype(postfix="DECLSPEC_HIDDEN") + ";\n")
2414         f.write("\n")
2416         f.write("/* For use by vkDevice and children */\n")
2417         f.write("struct vulkan_device_funcs\n{\n")
2418         for vk_func in self.registry.device_funcs:
2419             if not vk_func.is_required():
2420                 continue
2422             if not vk_func.needs_dispatch():
2423                 LOGGER.debug("skipping {0} in vulkan_device_funcs".format(vk_func.name))
2424                 continue
2426             if vk_func.needs_conversion():
2427                 f.write("#if defined(USE_STRUCT_CONVERSION)\n")
2428                 f.write("    {0};\n".format(vk_func.pfn(conv=True)))
2429                 f.write("#else\n")
2430                 f.write("    {0};\n".format(vk_func.pfn(conv=False)))
2431                 f.write("#endif\n")
2432             else:
2433                 f.write("    {0};\n".format(vk_func.pfn(conv=False)))
2434         f.write("};\n\n")
2436         f.write("/* For use by vkInstance and children */\n")
2437         f.write("struct vulkan_instance_funcs\n{\n")
2438         for vk_func in self.registry.instance_funcs:
2439             if not vk_func.is_required():
2440                 continue
2442             if not vk_func.needs_dispatch():
2443                 LOGGER.debug("skipping {0} in vulkan_instance_funcs".format(vk_func.name))
2444                 continue
2446             if vk_func.needs_conversion():
2447                 f.write("#if defined(USE_STRUCT_CONVERSION)\n")
2448                 f.write("    {0};\n".format(vk_func.pfn(conv=True)))
2449                 f.write("#else\n")
2450                 f.write("    {0};\n".format(vk_func.pfn(conv=False)))
2451                 f.write("#endif\n")
2452             else:
2453                 f.write("    {0};\n".format(vk_func.pfn(conv=False)))
2454         f.write("};\n\n")
2456         f.write("#define ALL_VK_DEVICE_FUNCS() \\\n")
2457         first = True
2458         for vk_func in self.registry.device_funcs:
2459             if not vk_func.is_required():
2460                 continue
2462             if not vk_func.needs_dispatch():
2463                 LOGGER.debug("skipping {0} in ALL_VK_DEVICE_FUNCS".format(vk_func.name))
2464                 continue
2466             if first:
2467                 f.write("    USE_VK_FUNC({0})".format(vk_func.name))
2468                 first = False
2469             else:
2470                 f.write(" \\\n    USE_VK_FUNC({0})".format(vk_func.name))
2471         f.write("\n\n")
2473         f.write("#define ALL_VK_INSTANCE_FUNCS() \\\n")
2474         first = True
2475         for vk_func in self.registry.instance_funcs:
2476             if not vk_func.is_required():
2477                 continue
2479             if not vk_func.needs_dispatch():
2480                 LOGGER.debug("skipping {0} in ALL_VK_INSTANCE_FUNCS".format(vk_func.name))
2481                 continue
2483             if first:
2484                 f.write("    USE_VK_FUNC({0})".format(vk_func.name))
2485                 first = False
2486             else:
2487                 f.write(" \\\n    USE_VK_FUNC({0})".format(vk_func.name))
2488         f.write("\n\n")
2490         f.write("#endif /* __WINE_VULKAN_THUNKS_H */\n")
2492     def generate_vulkan_h(self, f):
2493         self._generate_copyright(f)
2494         f.write("#ifndef __WINE_VULKAN_H\n")
2495         f.write("#define __WINE_VULKAN_H\n\n")
2497         f.write("#include <windef.h>\n")
2498         f.write("#include <stdint.h>\n\n")
2500         f.write("/* Define WINE_VK_HOST to get 'host' headers. */\n")
2501         f.write("#ifdef WINE_VK_HOST\n")
2502         f.write("#define VKAPI_CALL\n")
2503         f.write('#define WINE_VK_ALIGN(x)\n')
2504         f.write("#endif\n\n")
2506         f.write("#ifndef VKAPI_CALL\n")
2507         f.write("#define VKAPI_CALL __stdcall\n")
2508         f.write("#endif\n\n")
2510         f.write("#ifndef VKAPI_PTR\n")
2511         f.write("#define VKAPI_PTR VKAPI_CALL\n")
2512         f.write("#endif\n\n")
2514         f.write("#ifndef WINE_VK_ALIGN\n")
2515         f.write("#define WINE_VK_ALIGN DECLSPEC_ALIGN\n")
2516         f.write("#endif\n\n")
2518         # The overall strategy is to define independent constants and datatypes,
2519         # prior to complex structures and function calls to avoid forward declarations.
2520         for const in self.registry.consts:
2521             # For now just generate things we may not need. The amount of parsing needed
2522             # to get some of the info is tricky as you need to figure out which structure
2523             # references a certain constant.
2524             f.write(const.definition())
2525         f.write("\n")
2527         for define in self.registry.defines:
2528             f.write(define.definition())
2530         for handle in self.registry.handles:
2531             # For backward compatibility also create definitions for aliases.
2532             # These types normally don't get pulled in as we use the new types
2533             # even in legacy functions if they are aliases.
2534             if handle.is_required() or handle.is_alias():
2535                  f.write(handle.definition())
2536         f.write("\n")
2538         for base_type in self.registry.base_types:
2539             f.write(base_type.definition())
2540         f.write("\n")
2542         for bitmask in self.registry.bitmasks:
2543             f.write(bitmask.definition())
2544         f.write("\n")
2546         # Define enums, this includes values for some of the bitmask types as well.
2547         for enum in self.registry.enums.values():
2548             if enum.required:
2549                 f.write(enum.definition())
2551         for fp in self.registry.funcpointers:
2552             if fp.required:
2553                 f.write(fp.definition())
2554         f.write("\n")
2556         # This generates both structures and unions. Since structures
2557         # may depend on other structures/unions, we need a list of
2558         # decoupled structs.
2559         # Note: unions are stored in structs for dependency reasons,
2560         # see comment in parsing section.
2561         structs = VkStruct.decouple_structs(self.registry.structs)
2562         for struct in structs:
2563             LOGGER.debug("Generating struct: {0}".format(struct.name))
2564             f.write(struct.definition(align=True))
2566         for func in self.registry.funcs.values():
2567             if not func.is_required():
2568                 LOGGER.debug("Skipping PFN definition for: {0}".format(func.name))
2569                 continue
2571             f.write("typedef {0};\n".format(func.pfn(prefix="PFN", call_conv="VKAPI_PTR")))
2572         f.write("\n")
2574         f.write("#ifndef VK_NO_PROTOTYPES\n")
2575         for func in self.registry.funcs.values():
2576             if not func.is_required():
2577                 LOGGER.debug("Skipping API definition for: {0}".format(func.name))
2578                 continue
2580             LOGGER.debug("Generating API definition for: {0}".format(func.name))
2581             f.write("{0};\n".format(func.prototype(call_conv="VKAPI_CALL")))
2582         f.write("#endif /* VK_NO_PROTOTYPES */\n\n")
2584         f.write("#endif /* __WINE_VULKAN_H */\n")
2586     def generate_vulkan_driver_h(self, f):
2587         self._generate_copyright(f)
2588         f.write("#ifndef __WINE_VULKAN_DRIVER_H\n")
2589         f.write("#define __WINE_VULKAN_DRIVER_H\n\n")
2591         f.write("/* Wine internal vulkan driver version, needs to be bumped upon vulkan_funcs changes. */\n")
2592         f.write("#define WINE_VULKAN_DRIVER_VERSION {0}\n\n".format(DRIVER_VERSION))
2594         f.write("struct vulkan_funcs\n{\n")
2595         f.write("    /* Vulkan global functions. These are the only calls at this point a graphics driver\n")
2596         f.write("     * needs to provide. Other function calls will be provided indirectly by dispatch\n")
2597         f.write("     * tables part of dispatchable Vulkan objects such as VkInstance or vkDevice.\n")
2598         f.write("     */\n")
2600         for vk_func in self.registry.funcs.values():
2601             if not vk_func.is_driver_func():
2602                 continue
2604             pfn = vk_func.pfn()
2605             # Avoid PFN_vkVoidFunction in driver interface as Vulkan likes to put calling convention
2606             # stuff in there. For simplicity substitute with "void *".
2607             pfn = pfn.replace("PFN_vkVoidFunction", "void *")
2608             f.write("    {0};\n".format(pfn))
2610         f.write("\n")
2611         f.write("    /* winevulkan specific functions */\n")
2612         f.write("    VkSurfaceKHR (*p_wine_get_native_surface)(VkSurfaceKHR);\n")
2613         f.write("};\n\n")
2615         f.write("extern const struct vulkan_funcs * CDECL __wine_get_vulkan_driver(HDC hdc, UINT version);\n\n")
2617         f.write("static inline void *get_vulkan_driver_device_proc_addr(\n")
2618         f.write("        const struct vulkan_funcs *vulkan_funcs, const char *name)\n{\n")
2619         f.write("    if (!name || name[0] != 'v' || name[1] != 'k') return NULL;\n\n")
2620         f.write("    name += 2;\n\n")
2621         for vk_func in self.registry.funcs.values():
2622             if vk_func.is_driver_func() and vk_func.is_device_func():
2623                 f.write('    if (!strcmp(name, "{0}"))\n'.format(vk_func.name[2:]))
2624                 f.write('        return vulkan_funcs->p_{0};\n'.format(vk_func.name))
2625         f.write("\n")
2626         f.write("    return NULL;\n}\n\n")
2628         f.write("static inline void *get_vulkan_driver_instance_proc_addr(\n")
2629         f.write("        const struct vulkan_funcs *vulkan_funcs, VkInstance instance, const char *name)\n{\n")
2630         f.write("    if (!name || name[0] != 'v' || name[1] != 'k') return NULL;\n\n")
2631         f.write("    name += 2;\n\n")
2632         for vk_func in self.registry.funcs.values():
2633             if vk_func.is_driver_func() and vk_func.is_global_func() and vk_func.name != "vkGetInstanceProcAddr":
2634                 f.write('    if (!strcmp(name, "{0}"))\n'.format(vk_func.name[2:]))
2635                 f.write('        return vulkan_funcs->p_{0};\n'.format(vk_func.name))
2636         f.write("\n")
2637         f.write("    if (!instance) return NULL;\n\n")
2638         for vk_func in self.registry.funcs.values():
2639             if vk_func.is_driver_func() and vk_func.is_instance_func():
2640                 f.write('    if (!strcmp(name, "{0}"))\n'.format(vk_func.name[2:]))
2641                 f.write('        return vulkan_funcs->p_{0};\n'.format(vk_func.name))
2642         f.write("\n")
2643         f.write("    name -= 2;\n\n")
2644         f.write("    return get_vulkan_driver_device_proc_addr(vulkan_funcs, name);\n}\n\n")
2646         f.write("#endif /* __WINE_VULKAN_DRIVER_H */\n")
2648     def generate_vulkan_spec(self, f):
2649         self._generate_copyright(f, spec_file=True)
2650         f.write("@ stdcall -private vk_icdGetInstanceProcAddr(ptr str) wine_vk_icdGetInstanceProcAddr\n")
2651         f.write("@ stdcall -private vk_icdNegotiateLoaderICDInterfaceVersion(ptr) wine_vk_icdNegotiateLoaderICDInterfaceVersion\n")
2652         f.write("@ cdecl -norelay native_vkGetInstanceProcAddrWINE(ptr str)\n")
2654         # Export symbols for all Vulkan Core functions.
2655         for func in self.registry.funcs.values():
2656             if not func.is_core_func():
2657                 continue
2659             # We support all Core functions except for VK_KHR_display* APIs.
2660             # Create stubs for unsupported Core functions.
2661             if func.is_required():
2662                 f.write(func.spec(prefix="wine_"))
2663             else:
2664                 f.write("@ stub {0}\n".format(func.name))
2666         f.write("@ stdcall -private DllRegisterServer()\n")
2667         f.write("@ stdcall -private DllUnregisterServer()\n")
2669     def generate_vulkan_loader_spec(self, f):
2670         self._generate_copyright(f, spec_file=True)
2672         # Export symbols for all Vulkan Core functions.
2673         for func in self.registry.funcs.values():
2674             if not func.is_core_func():
2675                 continue
2677             # We support all Core functions except for VK_KHR_display* APIs.
2678             # Create stubs for unsupported Core functions.
2679             if func.is_required():
2680                 f.write(func.spec(symbol="winevulkan.wine_" + func.name))
2681             else:
2682                 f.write("@ stub {0}\n".format(func.name))
2685 class VkRegistry(object):
2686     def __init__(self, reg_filename):
2687         # Used for storage of type information.
2688         self.base_types = None
2689         self.bitmasks = None
2690         self.consts = None
2691         self.defines = None
2692         self.enums = None
2693         self.funcpointers = None
2694         self.handles = None
2695         self.structs = None
2697         # We aggregate all types in here for cross-referencing.
2698         self.funcs = {}
2699         self.types = {}
2701         self.version_regex = re.compile(
2702             r'^'
2703             r'VK_VERSION_'
2704             r'(?P<major>[0-9])'
2705             r'_'
2706             r'(?P<minor>[0-9])'
2707             r'$'
2708         )
2710         # Overall strategy for parsing the registry is to first
2711         # parse all type / function definitions. Then parse
2712         # features and extensions to decide which types / functions
2713         # to actually 'pull in' for code generation. For each type or
2714         # function call we want we set a member 'required' to True.
2715         tree = ET.parse(reg_filename)
2716         root = tree.getroot()
2717         self._parse_enums(root)
2718         self._parse_types(root)
2719         self._parse_commands(root)
2721         # Pull in any required types and functions.
2722         self._parse_features(root)
2723         self._parse_extensions(root)
2725         self._match_object_types()
2727         self.copyright = root.find('./comment').text
2729     def _is_feature_supported(self, feature):
2730         version = self.version_regex.match(feature)
2731         if not version:
2732             return True
2734         version = tuple(map(int, version.group('major', 'minor')))
2735         return version <= WINE_VK_VERSION
2737     def _is_extension_supported(self, extension):
2738         # We disable some extensions as either we haven't implemented
2739         # support yet or because they are for platforms other than win32.
2740         return extension not in UNSUPPORTED_EXTENSIONS
2742     def _mark_command_required(self, command):
2743         """ Helper function to mark a certain command and the datatypes it needs as required."""
2744         def mark_bitmask_dependencies(bitmask, types):
2745             if bitmask.requires is not None:
2746                 types[bitmask.requires]["data"].required = True
2748         def mark_funcpointer_dependencies(fp, types):
2749             for m in fp.members:
2750                 type_info = types[m.type]
2752                 # Complex types have a matching definition e.g. VkStruct.
2753                 # Not needed for base types such as uint32_t.
2754                 if "data" in type_info:
2755                     types[m.type]["data"].required = True
2757         def mark_struct_dependencies(struct, types):
2758              for m in struct:
2759                 type_info = types[m.type]
2761                 # Complex types have a matching definition e.g. VkStruct.
2762                 # Not needed for base types such as uint32_t.
2763                 if "data" in type_info:
2764                     types[m.type]["data"].required = True
2766                 if type_info["category"] == "struct":
2767                     # Yay, recurse
2768                     mark_struct_dependencies(type_info["data"], types)
2769                 elif type_info["category"] == "funcpointer":
2770                     mark_funcpointer_dependencies(type_info["data"], types)
2771                 elif type_info["category"] == "bitmask":
2772                     mark_bitmask_dependencies(type_info["data"], types)
2774         func = self.funcs[command]
2775         func.required = True
2777         # Pull in return type
2778         if func.type != "void":
2779             self.types[func.type]["data"].required = True
2781         # Analyze parameter dependencies and pull in any type needed.
2782         for p in func.params:
2783             type_info = self.types[p.type]
2785             # Check if we are dealing with a complex type e.g. VkEnum, VkStruct and others.
2786             if "data" not in type_info:
2787                 continue
2789             # Mark the complex type as required.
2790             type_info["data"].required = True
2791             if type_info["category"] == "struct":
2792                 struct = type_info["data"]
2793                 mark_struct_dependencies(struct, self.types)
2794             elif type_info["category"] == "bitmask":
2795                 mark_bitmask_dependencies(type_info["data"], self.types)
2797     def _match_object_types(self):
2798         """ Matches each handle with the correct object type. """
2799         # Use upper case comparison for simplicity.
2800         object_types = {}
2801         for value in self.enums["VkObjectType"].values:
2802             object_name = "VK" + value.name[len("VK_OBJECT_TYPE"):].replace("_", "")
2803             object_types[object_name] = value.name
2805         for handle in self.handles:
2806             if not handle.is_required():
2807                 continue
2808             handle.object_type = object_types.get(handle.name.upper())
2809             if not handle.object_type:
2810                 LOGGER.warning("No object type found for {}".format(handle.name))
2812     def _parse_commands(self, root):
2813         """ Parse command section containing the Vulkan function calls. """
2814         funcs = {}
2815         commands = root.findall("./commands/")
2817         # As of Vulkan 1.1, various extensions got promoted to Core.
2818         # The old commands (e.g. KHR) are available for backwards compatibility
2819         # and are marked in vk.xml as 'alias' to the non-extension type.
2820         # The registry likes to avoid data duplication, so parameters and other
2821         # metadata need to be looked up from the Core command.
2822         # We parse the alias commands in a second pass.
2823         alias_commands = []
2824         for command in commands:
2825             alias_name = command.attrib.get("alias")
2826             if alias_name:
2827                 alias_commands.append(command)
2828                 continue
2830             func = VkFunction.from_xml(command, self.types)
2831             funcs[func.name] = func
2833         for command in alias_commands:
2834             alias_name = command.attrib.get("alias")
2835             alias = funcs[alias_name]
2836             func = VkFunction.from_alias(command, alias)
2837             funcs[func.name] = func
2839         # To make life easy for the code generation, separate all function
2840         # calls out in the 3 types of Vulkan functions: device, global and instance.
2841         device_funcs = []
2842         global_funcs = []
2843         instance_funcs = []
2844         for func in funcs.values():
2845             if func.is_device_func():
2846                 device_funcs.append(func)
2847             elif func.is_global_func():
2848                 global_funcs.append(func)
2849             else:
2850                 instance_funcs.append(func)
2852         # Sort function lists by name and store them.
2853         self.device_funcs = sorted(device_funcs, key=lambda func: func.name)
2854         self.global_funcs = sorted(global_funcs, key=lambda func: func.name)
2855         self.instance_funcs = sorted(instance_funcs, key=lambda func: func.name)
2857         # The funcs dictionary is used as a convenient way to lookup function
2858         # calls when needed e.g. to adjust member variables.
2859         self.funcs = OrderedDict(sorted(funcs.items()))
2861     def _parse_enums(self, root):
2862         """ Parse enums section or better described as constants section. """
2863         enums = {}
2864         self.consts = []
2865         for enum in root.findall("./enums"):
2866             name = enum.attrib.get("name")
2867             _type = enum.attrib.get("type")
2869             if _type in ("enum", "bitmask"):
2870                 enums[name] = VkEnum.from_xml(enum)
2871             else:
2872                 # If no type is set, we are dealing with API constants.
2873                 for value in enum.findall("enum"):
2874                     # If enum is an alias, set the value to the alias name.
2875                     # E.g. VK_LUID_SIZE_KHR is an alias to VK_LUID_SIZE.
2876                     alias = value.attrib.get("alias")
2877                     if alias:
2878                         self.consts.append(VkConstant(value.attrib.get("name"), alias))
2879                     else:
2880                         self.consts.append(VkConstant(value.attrib.get("name"), value.attrib.get("value")))
2882         self.enums = OrderedDict(sorted(enums.items()))
2884     def _process_require_enum(self, enum_elem, ext=None, only_aliased=False):
2885         if "extends" in enum_elem.keys():
2886             enum = self.types[enum_elem.attrib["extends"]]["data"]
2888             # Need to define VkEnumValues which were aliased to by another value. This is necessary
2889             # from VK spec version 1.2.135 where the provisional VK_KHR_ray_tracing extension was
2890             # added which altered VK_NV_ray_tracing's VkEnumValues to alias to the provisional
2891             # extension.
2892             aliased = False
2893             for _, t in self.types.items():
2894                 if t["category"] != "enum":
2895                     continue
2896                 if not t["data"]:
2897                     continue
2898                 for value in t["data"].values:
2899                     if value.alias == enum_elem.attrib["name"]:
2900                         aliased = True
2902             if only_aliased and not aliased:
2903                 return
2905             if "bitpos" in enum_elem.keys():
2906                 # We need to add an extra value to an existing enum type.
2907                 # E.g. VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG to VkFormatFeatureFlagBits.
2908                 enum.create_bitpos(enum_elem.attrib["name"], int(enum_elem.attrib["bitpos"]))
2910             elif "offset" in enum_elem.keys():
2911                 # Extensions promoted to Core, have the extension number as part
2912                 # of the enum value. Else retrieve from the extension tag.
2913                 if enum_elem.attrib.get("extnumber"):
2914                     ext_number = int(enum_elem.attrib.get("extnumber"))
2915                 else:
2916                     ext_number = int(ext.attrib["number"])
2917                 offset = int(enum_elem.attrib["offset"])
2918                 value = EXT_BASE + (ext_number - 1) * EXT_BLOCK_SIZE + offset
2920                 # Deal with negative values.
2921                 direction = enum_elem.attrib.get("dir")
2922                 if direction is not None:
2923                     value = -value
2925                 enum.create_value(enum_elem.attrib["name"], str(value))
2927             elif "value" in enum_elem.keys():
2928                 enum.create_value(enum_elem.attrib["name"], enum_elem.attrib["value"])
2929             elif "alias" in enum_elem.keys():
2930                 enum.create_alias(enum_elem.attrib["name"], enum_elem.attrib["alias"])
2932         elif "value" in enum_elem.keys():
2933             # Constants are not aliased, no need to add them here, they'll get added later on.
2934             if only_aliased:
2935                 return
2937             self.consts.append(VkConstant(enum_elem.attrib["name"], enum_elem.attrib["value"]))
2939     @staticmethod
2940     def _require_type(type_info):
2941         if type_info.is_alias():
2942             type_info = type_info.alias
2943         type_info.required = True
2944         if type(type_info) == VkStruct:
2945             for member in type_info.members:
2946                 if "data" in member.type_info:
2947                   VkRegistry._require_type(member.type_info["data"])
2949     def _parse_extensions(self, root):
2950         """ Parse extensions section and pull in any types and commands for this extension. """
2951         extensions = []
2952         exts = root.findall("./extensions/extension")
2953         deferred_exts = []
2954         skipped_exts = UNSUPPORTED_EXTENSIONS.copy()
2956         def process_ext(ext, deferred=False):
2957             ext_name = ext.attrib["name"]
2959             # Set extension name on any functions calls part of this extension as we
2960             # were not aware of the name during initial parsing.
2961             commands = ext.findall("require/command")
2962             for command in commands:
2963                 cmd_name = command.attrib["name"]
2964                 # Need to verify that the command is defined, and otherwise skip it.
2965                 # vkCreateScreenSurfaceQNX is declared in <extensions> but not defined in
2966                 # <commands>. A command without a definition cannot be enabled, so it's valid for
2967                 # the XML file to handle this, but because of the manner in which we parse the XML
2968                 # file we pre-populate from <commands> before we check if a command is enabled.
2969                 if cmd_name in self.funcs:
2970                     self.funcs[cmd_name].extensions.append(ext_name)
2972             # Some extensions are not ready or have numbers reserved as a place holder.
2973             if ext.attrib["supported"] == "disabled":
2974                 LOGGER.debug("Skipping disabled extension: {0}".format(ext_name))
2975                 skipped_exts.append(ext_name)
2976                 return
2978             # Defer extensions with 'sortorder' as they are order-dependent for spec-parsing.
2979             if not deferred and "sortorder" in ext.attrib:
2980                 deferred_exts.append(ext)
2981                 return
2983             # Disable highly experimental extensions as the APIs are unstable and can
2984             # change between minor Vulkan revisions until API is final and becomes KHR
2985             # or NV.
2986             if "KHX" in ext_name or "NVX" in ext_name:
2987                 LOGGER.debug("Skipping experimental extension: {0}".format(ext_name))
2988                 skipped_exts.append(ext_name)
2989                 return
2991             # Extensions can define VkEnumValues which alias to provisional extensions. Pre-process
2992             # extensions to define any required VkEnumValues before the platform check below.
2993             for require in ext.findall("require"):
2994                 # Extensions can add enum values to Core / extension enums, so add these.
2995                 for enum_elem in require.findall("enum"):
2996                     self._process_require_enum(enum_elem, ext, only_aliased=True)
2998             platform = ext.attrib.get("platform")
2999             if platform and platform != "win32":
3000                 LOGGER.debug("Skipping extensions {0} for platform {1}".format(ext_name, platform))
3001                 skipped_exts.append(ext_name)
3002                 return
3004             if not self._is_extension_supported(ext_name):
3005                 LOGGER.debug("Skipping unsupported extension: {0}".format(ext_name))
3006                 skipped_exts.append(ext_name)
3007                 return
3008             elif "requires" in ext.attrib:
3009                 # Check if this extension builds on top of another unsupported extension.
3010                 requires = ext.attrib["requires"].split(",")
3011                 if len(set(requires).intersection(skipped_exts)) > 0:
3012                     skipped_exts.append(ext_name)
3013                     return
3015             LOGGER.debug("Loading extension: {0}".format(ext_name))
3017             # Extensions can define one or more require sections each requiring
3018             # different features (e.g. Vulkan 1.1). Parse each require section
3019             # separately, so we can skip sections we don't want.
3020             for require in ext.findall("require"):
3021                 # Extensions can add enum values to Core / extension enums, so add these.
3022                 for enum_elem in require.findall("enum"):
3023                     self._process_require_enum(enum_elem, ext)
3025                 for t in require.findall("type"):
3026                     type_info = self.types[t.attrib["name"]]["data"]
3027                     self._require_type(type_info)
3028                 feature = require.attrib.get("feature")
3029                 if feature and not self._is_feature_supported(feature):
3030                     continue
3032                 required_extension = require.attrib.get("extension")
3033                 if required_extension and not self._is_extension_supported(required_extension):
3034                     continue
3036                 # Pull in any commands we need. We infer types to pull in from the command
3037                 # as well.
3038                 for command in require.findall("command"):
3039                     cmd_name = command.attrib["name"]
3040                     self._mark_command_required(cmd_name)
3043             # Store a list with extensions.
3044             ext_info = {"name" : ext_name, "type" : ext.attrib["type"]}
3045             extensions.append(ext_info)
3048         # Process extensions, allowing for sortorder to defer extension processing
3049         for ext in exts:
3050             process_ext(ext)
3052         deferred_exts.sort(key=lambda ext: ext.attrib["sortorder"])
3054         # Respect sortorder
3055         for ext in deferred_exts:
3056             process_ext(ext, deferred=True)
3058         # Sort in alphabetical order.
3059         self.extensions = sorted(extensions, key=lambda ext: ext["name"])
3061     def _parse_features(self, root):
3062         """ Parse the feature section, which describes Core commands and types needed. """
3064         for feature in root.findall("./feature"):
3065             feature_name = feature.attrib["name"]
3066             for require in feature.findall("require"):
3067                 LOGGER.info("Including features for {0}".format(require.attrib.get("comment")))
3068                 for tag in require:
3069                     if tag.tag == "comment":
3070                         continue
3071                     elif tag.tag == "command":
3072                         if not self._is_feature_supported(feature_name):
3073                             continue
3074                         name = tag.attrib["name"]
3075                         self._mark_command_required(name)
3076                     elif tag.tag == "enum":
3077                         self._process_require_enum(tag)
3078                     elif tag.tag == "type":
3079                         name = tag.attrib["name"]
3081                         # Skip pull in for vk_platform.h for now.
3082                         if name == "vk_platform":
3083                             continue
3085                         type_info = self.types[name]
3086                         type_info["data"].required = True
3088     def _parse_types(self, root):
3089         """ Parse types section, which contains all data types e.g. structs, typedefs etcetera. """
3090         types = root.findall("./types/type")
3092         base_types = []
3093         bitmasks = []
3094         defines = []
3095         funcpointers = []
3096         handles = []
3097         structs = []
3099         alias_types = []
3100         for t in types:
3101             type_info = {}
3102             type_info["category"] = t.attrib.get("category", None)
3103             type_info["requires"] = t.attrib.get("requires", None)
3105             # We parse aliases in a second pass when we know more.
3106             alias = t.attrib.get("alias")
3107             if alias:
3108                 LOGGER.debug("Alias found: {0}".format(alias))
3109                 alias_types.append(t)
3110                 continue
3112             if type_info["category"] in ["include"]:
3113                 continue
3115             if type_info["category"] == "basetype":
3116                 name = t.find("name").text
3117                 _type = None
3118                 if not t.find("type") is None:
3119                     _type = t.find("type").text
3120                 basetype = VkBaseType(name, _type)
3121                 base_types.append(basetype)
3122                 type_info["data"] = basetype
3124             # Basic C types don't need us to define them, but we do need data for them
3125             if type_info["requires"] == "vk_platform":
3126                 requires = type_info["requires"]
3127                 basic_c = VkBaseType(name, _type, requires=requires)
3128                 type_info["data"] = basic_c
3130             if type_info["category"] == "bitmask":
3131                 name = t.find("name").text
3132                 _type = t.find("type").text
3134                 # Most bitmasks have a requires attribute used to pull in
3135                 # required '*FlagBits" enum.
3136                 requires = type_info["requires"]
3137                 bitmask = VkBaseType(name, _type, requires=requires)
3138                 bitmasks.append(bitmask)
3139                 type_info["data"] = bitmask
3141             if type_info["category"] == "define":
3142                 define = VkDefine.from_xml(t)
3143                 defines.append(define)
3144                 type_info["data"] = define
3146             if type_info["category"] == "enum":
3147                 name = t.attrib.get("name")
3148                 # The type section only contains enum names, not the actual definition.
3149                 # Since we already parsed the enum before, just link it in.
3150                 try:
3151                     type_info["data"] = self.enums[name]
3152                 except KeyError as e:
3153                     # Not all enums seem to be defined yet, typically that's for
3154                     # ones ending in 'FlagBits' where future extensions may add
3155                     # definitions.
3156                     type_info["data"] = None
3158             if type_info["category"] == "funcpointer":
3159                 funcpointer = VkFunctionPointer.from_xml(t)
3160                 funcpointers.append(funcpointer)
3161                 type_info["data"] = funcpointer
3163             if type_info["category"] == "handle":
3164                 handle = VkHandle.from_xml(t)
3165                 handles.append(handle)
3166                 type_info["data"] = handle
3168             if type_info["category"] in ["struct", "union"]:
3169                 # We store unions among structs as some structs depend
3170                 # on unions. The types are very similar in parsing and
3171                 # generation anyway. The official Vulkan scripts use
3172                 # a similar kind of hack.
3173                 struct = VkStruct.from_xml(t)
3174                 structs.append(struct)
3175                 type_info["data"] = struct
3177             # Name is in general within a name tag else it is an optional
3178             # attribute on the type tag.
3179             name_elem = t.find("name")
3180             if name_elem is not None:
3181                 type_info["name"] = name_elem.text
3182             else:
3183                 type_info["name"] = t.attrib.get("name", None)
3185             # Store all type data in a shared dictionary, so we can easily
3186             # look up information for a given type. There are no duplicate
3187             # names.
3188             self.types[type_info["name"]] = type_info
3190         # Second pass for alias types, so we can retrieve all data from
3191         # the aliased object.
3192         for t in alias_types:
3193             type_info = {}
3194             type_info["category"] = t.attrib.get("category")
3195             type_info["name"] = t.attrib.get("name")
3197             alias = t.attrib.get("alias")
3199             if type_info["category"] == "bitmask":
3200                 bitmask = VkBaseType(type_info["name"], alias, alias=self.types[alias]["data"])
3201                 bitmasks.append(bitmask)
3202                 type_info["data"] = bitmask
3204             if type_info["category"] == "enum":
3205                 enum = VkEnum.from_alias(t, self.types[alias]["data"])
3206                 type_info["data"] = enum
3207                 self.enums[enum.name] = enum
3209             if type_info["category"] == "handle":
3210                 handle = VkHandle.from_alias(t, self.types[alias]["data"])
3211                 handles.append(handle)
3212                 type_info["data"] = handle
3214             if type_info["category"] == "struct":
3215                 struct = VkStruct.from_alias(t, self.types[alias]["data"])
3216                 structs.append(struct)
3217                 type_info["data"] = struct
3219             self.types[type_info["name"]] = type_info
3221         # We need detailed type information during code generation
3222         # on structs for alignment reasons. Unfortunately structs
3223         # are parsed among other types, so there is no guarantee
3224         # that any types needed have been parsed already, so set
3225         # the data now.
3226         for struct in structs:
3227             struct.set_type_info(self.types)
3229             # Alias structures have enum values equivalent to those of the
3230             # structure which they are aliased against. we need to ignore alias
3231             # structs when populating the struct extensions list, otherwise we
3232             # will create duplicate case entries.
3233             if struct.alias:
3234                 continue
3236             for structextend in struct.structextends:
3237                 s = self.types[structextend]["data"]
3238                 s.struct_extensions.append(struct)
3240         # Guarantee everything is sorted, so code generation doesn't have
3241         # to deal with this.
3242         self.base_types = sorted(base_types, key=lambda base_type: base_type.name)
3243         self.bitmasks = sorted(bitmasks, key=lambda bitmask: bitmask.name)
3244         self.defines = defines
3245         self.enums = OrderedDict(sorted(self.enums.items()))
3246         self.funcpointers = sorted(funcpointers, key=lambda fp: fp.name)
3247         self.handles = sorted(handles, key=lambda handle: handle.name)
3248         self.structs = sorted(structs, key=lambda struct: struct.name)
3250 def generate_vulkan_json(f):
3251     f.write("{\n")
3252     f.write("    \"file_format_version\": \"1.0.0\",\n")
3253     f.write("    \"ICD\": {\n")
3254     f.write("        \"library_path\": \".\\\\winevulkan.dll\",\n")
3255     f.write("        \"api_version\": \"{0}\"\n".format(VK_XML_VERSION))
3256     f.write("    }\n")
3257     f.write("}\n")
3259 def set_working_directory():
3260     path = os.path.abspath(__file__)
3261     path = os.path.dirname(path)
3262     os.chdir(path)
3264 def download_vk_xml(filename):
3265     url = "https://raw.githubusercontent.com/KhronosGroup/Vulkan-Docs/v{0}/xml/vk.xml".format(VK_XML_VERSION)
3266     if not os.path.isfile(filename):
3267         urllib.request.urlretrieve(url, filename)
3269 def main():
3270     parser = argparse.ArgumentParser()
3271     parser.add_argument("-v", "--verbose", action="count", default=0, help="increase output verbosity")
3272     parser.add_argument("-x", "--xml", default=None, type=str, help="path to specification XML file")
3274     args = parser.parse_args()
3275     if args.verbose == 0:
3276         LOGGER.setLevel(logging.WARNING)
3277     elif args.verbose == 1:
3278         LOGGER.setLevel(logging.INFO)
3279     else: # > 1
3280         LOGGER.setLevel(logging.DEBUG)
3282     set_working_directory()
3284     if args.xml:
3285         vk_xml = args.xml
3286     else:
3287         vk_xml = "vk-{0}.xml".format(VK_XML_VERSION)
3288         download_vk_xml(vk_xml)
3290     registry = VkRegistry(vk_xml)
3291     generator = VkGenerator(registry)
3293     with open(WINE_VULKAN_H, "w") as f:
3294         generator.generate_vulkan_h(f)
3296     with open(WINE_VULKAN_DRIVER_H, "w") as f:
3297         generator.generate_vulkan_driver_h(f)
3299     with open(WINE_VULKAN_THUNKS_H, "w") as f:
3300         generator.generate_thunks_h(f, "wine_")
3302     with open(WINE_VULKAN_THUNKS_C, "w") as f:
3303         generator.generate_thunks_c(f, "wine_")
3305     with open(WINE_VULKAN_JSON, "w") as f:
3306         generate_vulkan_json(f)
3308     with open(WINE_VULKAN_SPEC, "w") as f:
3309         generator.generate_vulkan_spec(f)
3311     with open(WINE_VULKAN_LOADER_SPEC, "w") as f:
3312         generator.generate_vulkan_loader_spec(f)
3314 if __name__ == "__main__":
3315     main()