winevulkan: Implement VK_KHR_external_memory_capabilities.
[wine.git] / dlls / winevulkan / make_vulkan
blob7a4aa4d8d675989e50568462e2ccaee59f131993
1 #!/usr/bin/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.1.104"
68 WINE_VK_VERSION = (1, 0)
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_SPEC = "winevulkan.spec"
75 WINE_VULKAN_THUNKS_C = "vulkan_thunks.c"
76 WINE_VULKAN_THUNKS_H = "vulkan_thunks.h"
78 # Extension enum values start at a certain offset (EXT_BASE).
79 # Relative to the offset each extension has a block (EXT_BLOCK_SIZE)
80 # of values.
81 # Start for a given extension is:
82 # EXT_BASE + (extension_number-1) * EXT_BLOCK_SIZE
83 EXT_BASE = 1000000000
84 EXT_BLOCK_SIZE = 1000
86 BLACKLISTED_EXTENSIONS = [
87     # Instance extensions
88     "VK_EXT_debug_utils",
89     "VK_EXT_validation_features",
90     "VK_EXT_validation_flags",
91     "VK_KHR_display",
92     "VK_KHR_get_surface_capabilities2",
93     "VK_KHR_surface_protected_capabilities",
94     "VK_NV_external_memory_capabilities",
96     # Device extensions
97     "VK_AMD_display_native_hdr",
98     "VK_AMD_memory_overallocation_behavior",
99     # Handling of VK_EXT_debug_report requires some consideration. The win32
100     # loader already provides it for us and it is somewhat usable. If we add
101     # plumbing down to the native layer, we will get each message twice as we
102     # use 2 loaders (win32+native), but we may get output from the driver.
103     # In any case callback conversion is required.
104     "VK_EXT_calibrated_timestamps",
105     "VK_EXT_debug_report",
106     "VK_EXT_display_control", # Requires VK_EXT_display_surface_counter
107     "VK_EXT_external_memory_dma_buf", # Linux specific
108     "VK_EXT_full_screen_exclusive",
109     "VK_EXT_hdr_metadata", # Needs WSI work.
110     "VK_EXT_image_drm_format_modifier",
111     "VK_EXT_memory_priority",
112     "VK_EXT_pipeline_creation_feedback",
113     "VK_EXT_ycbcr_image_arrays",
114     "VK_GOOGLE_display_timing",
115     "VK_KHR_display", # Needs WSI work.
116     "VK_KHR_external_fence",
117     "VK_KHR_external_fence_fd",
118     "VK_KHR_external_fence_win32",
119     "VK_KHR_external_memory",
120     "VK_KHR_external_semaphore",
121     "VK_KHR_shader_float16_int8",
122     # Relates to external_semaphore and needs type conversions in bitflags.
123     "VK_KHR_external_semaphore_capabilities",
124     "VK_KHR_shared_presentable_image", # Needs WSI work.
125     "VK_KHR_win32_keyed_mutex",
126     "VK_NV_cooperative_matrix",
127     "VK_NV_dedicated_allocation_image_aliasing",
128     "VK_NV_external_memory_win32",
131 # The Vulkan loader provides entry-points for core functionality and important
132 # extensions. Based on vulkan-1.def this amounts to WSI extensions on 1.0.51.
133 CORE_EXTENSIONS = [
134     "VK_KHR_display",
135     "VK_KHR_display_swapchain",
136     "VK_KHR_surface",
137     "VK_KHR_swapchain",
138     "VK_KHR_win32_surface",
141 # Functions part of our winevulkan graphics driver interface.
142 # DRIVER_VERSION should be bumped on any change to driver interface
143 # in FUNCTION_OVERRIDES
144 DRIVER_VERSION = 7
146 # Table of functions for which we have a special implementation.
147 # These are regular device / instance functions for which we need
148 # to do more work compared to a regular thunk or because they are
149 # part of the driver interface.
150 # - dispatch set whether we need a function pointer in the device
151 #   / instance dispatch table.
152 # - driver sets whether the API is part of the driver interface.
153 # - thunk sets whether to create a thunk in vulkan_thunks.c.
154 FUNCTION_OVERRIDES = {
155     # Global functions
156     "vkCreateInstance" : {"dispatch" : False, "driver" : True, "thunk" : False},
157     "vkEnumerateInstanceExtensionProperties" : {"dispatch" : False, "driver" : True, "thunk" : False},
158     "vkEnumerateInstanceVersion": {"dispatch" : False, "driver" : False, "thunk" : False},
159     "vkGetInstanceProcAddr": {"dispatch" : False, "driver" : True, "thunk" : False},
161     # Instance functions
162     "vkCreateDevice" : {"dispatch" : True, "driver" : False, "thunk" : False},
163     "vkDestroyInstance" : {"dispatch" : False, "driver" : True, "thunk" : False },
164     "vkEnumerateDeviceExtensionProperties" : {"dispatch" : True, "driver" : False, "thunk" : False},
165     "vkEnumeratePhysicalDeviceGroups" : {"dispatch" : True, "driver" : False, "thunk" : False},
166     "vkEnumeratePhysicalDevices" : {"dispatch" : True, "driver" : False, "thunk" : False},
167     "vkGetPhysicalDeviceExternalBufferProperties" : {"dispatch" : False, "driver" : False, "thunk" : False},
168     "vkGetPhysicalDeviceExternalFenceProperties" : {"dispatch" : False, "driver" : False, "thunk" : False},
169     "vkGetPhysicalDeviceImageFormatProperties2" : {"dispatch" : True, "driver" : False, "thunk" : True, "private_thunk" : True},
171     # Device functions
172     "vkAllocateCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : False},
173     "vkCmdExecuteCommands" : {"dispatch" : True, "driver" : False, "thunk" : False},
174     "vkCreateCommandPool" : {"dispatch": True, "driver" : False, "thunk" : False},
175     "vkDestroyCommandPool" : {"dispatch": True, "driver" : False, "thunk" : False},
176     "vkDestroyDevice" : {"dispatch" : True, "driver" : False, "thunk" : False},
177     "vkFreeCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : False},
178     "vkGetDeviceProcAddr" : {"dispatch" : False, "driver" : True, "thunk" : False},
179     "vkGetDeviceQueue" : {"dispatch": True, "driver" : False, "thunk" : False},
180     "vkGetDeviceQueue2" : {"dispatch": True, "driver" : False, "thunk" : False},
181     "vkQueueSubmit" : {"dispatch": True, "driver" : False, "thunk" : False},
183     # VK_KHR_surface
184     "vkDestroySurfaceKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
185     "vkGetPhysicalDeviceSurfaceSupportKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
186     "vkGetPhysicalDeviceSurfaceCapabilitiesKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
187     "vkGetPhysicalDeviceSurfaceFormatsKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
188     "vkGetPhysicalDeviceSurfacePresentModesKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
190     # VK_KHR_win32_surface
191     "vkCreateWin32SurfaceKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
192     "vkGetPhysicalDeviceWin32PresentationSupportKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
194     # VK_KHR_swapchain
195     "vkCreateSwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
196     "vkDestroySwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
197     "vkGetSwapchainImagesKHR": {"dispatch" : True, "driver" : True, "thunk" : True},
198     "vkQueuePresentKHR": {"dispatch" : True, "driver" : True, "thunk" : True},
200     # VK_KHR_external_fence_capabilities
201     "vkGetPhysicalDeviceExternalFencePropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : False},
203     # VK_KHR_external_memory_capabilities
204     "vkGetPhysicalDeviceExternalBufferPropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : False},
205     "vkGetPhysicalDeviceImageFormatProperties2KHR" : {"dispatch" : True, "driver" : False, "thunk" : True, "private_thunk" : True},
207     # VK_KHR_device_group_creation
208     "vkEnumeratePhysicalDeviceGroupsKHR" : {"dispatch" : True, "driver" : False, "thunk" : False},
210     # VK_KHR_device_group
211     "vkGetDeviceGroupSurfacePresentModesKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
212     "vkGetPhysicalDevicePresentRectanglesKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
216 class Direction(Enum):
217     """ Parameter direction: input, output, input_output. """
218     INPUT = 1
219     OUTPUT = 2
220     INPUT_OUTPUT = 3
223 class VkBaseType(object):
224     def __init__(self, name, _type, alias=None, requires=None):
225         """ Vulkan base type class.
227         VkBaseType is mostly used by Vulkan to define its own
228         base types like VkFlags through typedef out of e.g. uint32_t.
230         Args:
231             name (:obj:'str'): Name of the base type.
232             _type (:obj:'str'): Underlaying type
233             alias (bool): type is an alias or not.
234             requires (:obj:'str', optional): Other types required.
235                 Often bitmask values pull in a *FlagBits type.
236         """
237         self.name = name
238         self.type = _type
239         self.alias = alias
240         self.requires = requires
241         self.required = False
243     def definition(self):
244         # Definition is similar for alias or non-alias as type
245         # is already set to alias.
246         return "typedef {0} {1};\n".format(self.type, self.name)
248     def is_alias(self):
249         return bool(self.alias)
252 class VkConstant(object):
253     def __init__(self, name, value):
254         self.name = name
255         self.value = value
257     def definition(self):
258         text = "#define {0} {1}\n".format(self.name, self.value)
259         return text
262 class VkDefine(object):
263     def __init__(self, name, value):
264         self.name = name
265         self.value = value
267     @staticmethod
268     def from_xml(define):
269         name_elem = define.find("name")
271         if name_elem is None:
272             # <type category="define" name="some_name">some_value</type>
273             # At the time of writing there is only 1 define of this category
274             # 'VK_DEFINE_NON_DISPATCHABLE_HANDLE'.
275             name = define.attrib.get("name")
277             # We override behavior of VK_DEFINE_NON_DISPATCHABLE handle as the default
278             # definition various between 64-bit (uses pointers) and 32-bit (uses uint64_t).
279             # This complicates TRACEs in the thunks, so just use uint64_t.
280             if name == "VK_DEFINE_NON_DISPATCHABLE_HANDLE":
281                 value = "#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object;"
282             else:
283                 value = define.text
284             return VkDefine(name, value)
286         # With a name element the structure is like:
287         # <type category="define"><name>some_name</name>some_value</type>
288         name = name_elem.text
290         # Perform minimal parsing for Vulkan constants, which we don't need, but are referenced
291         # elsewhere in vk.xml.
292         # - VK_API_VERSION is a messy, deprecated constant and we don't want generate code for it.
293         # - AHardwareBuffer/ANativeWindow are forard declarations for Android types, which leaked
294         #   into the define region.
295         if name in ["VK_API_VERSION", "AHardwareBuffer", "ANativeWindow", "CAMetalLayer"]:
296             return VkDefine(name, None)
298         # The body of the define is basically unstructured C code. It is not meant for easy parsing.
299         # Some lines contain deprecated values or comments, which we try to filter out.
300         value = ""
301         for line in define.text.splitlines():
302             # Skip comments or deprecated values.
303             if "//" in line:
304                 continue
305             value += line
307         for child in define:
308             value += child.text
309             if child.tail is not None:
310                 # Split comments for VK_API_VERSION_1_0 / VK_API_VERSION_1_1
311                 if "//" in child.tail:
312                     value += child.tail.split("//")[0]
313                 else:
314                     value += child.tail
316         return VkDefine(name, value.rstrip(' '))
318     def definition(self):
319         if self.value is None:
320             return ""
322         # Nothing to do as the value was already put in the right form during parsing.
323         return "{0}\n".format(self.value)
326 class VkEnum(object):
327     def __init__(self, name, values, alias=None):
328         self.name = name
329         self.values = values
330         self.required = False
331         self.alias = alias
333     @staticmethod
334     def from_alias(enum, alias):
335         name = enum.attrib.get("name")
336         return VkEnum(name, alias.values, alias=alias)
338     @staticmethod
339     def from_xml(enum):
340         name = enum.attrib.get("name")
341         values = []
343         for v in enum.findall("enum"):
344             # Value is either a value or a bitpos, only one can exist.
345             value = v.attrib.get("value")
346             alias_name = v.attrib.get("alias")
347             if alias_name:
348                 alias = next(x for x in values if x.name == alias_name)
349                 values.append(VkEnumValue(v.attrib.get("name"), alias.value, alias.hex))
350             elif value:
351                 # Some values are in hex form. We want to preserve the hex representation
352                 # at least when we convert back to a string. Internally we want to use int.
353                 if "0x" in value:
354                     values.append(VkEnumValue(v.attrib.get("name"), int(value, 0), hex=True))
355                 else:
356                     values.append(VkEnumValue(v.attrib.get("name"), int(value, 0)))
357             else:
358                 # bitmask
359                 value = 1 << int(v.attrib.get("bitpos"))
360                 values.append(VkEnumValue(v.attrib.get("name"), value, hex=True))
362         # vulkan.h contains a *_MAX_ENUM value set to 32-bit at the time of writing,
363         # which is to prepare for extensions as they can add values and hence affect
364         # the size definition.
365         max_name = re.sub(r'([0-9a-z_])([A-Z0-9])',r'\1_\2', name).upper() + "_MAX_ENUM"
366         values.append(VkEnumValue(max_name, 0x7fffffff, hex=True))
368         return VkEnum(name, values)
370     def add(self, value):
371         """ Add a value to enum. """
373         # Extensions can add new enum values. When an extension is promoted to Core
374         # the registry defines the value twice once for old extension and once for
375         # new Core features. Ignore the duplicate entry.
376         for v in self.values:
377             if v.value == value.value:
378                 LOGGER.debug("Adding duplicate enum value {0} to {1}".format(v, self.name))
379                 return
380         self.values.append(value)
382     def definition(self):
383         text = "typedef enum {0}\n{{\n".format(self.name)
385         # Print values sorted, values can have been added in a random order.
386         values = sorted(self.values, key=lambda value: value.value)
387         for value in values:
388             text += "    {0},\n".format(value.definition())
389         text += "}} {0};\n\n".format(self.name)
390         return text
392     def is_alias(self):
393         return bool(self.alias)
396 class VkEnumValue(object):
397     def __init__(self, name, value, hex=False):
398         self.name = name
399         self.value = value
400         self.hex = hex
402     def __repr__(self):
403         return "{0}={1}".format(self.name, self.value)
405     def definition(self):
406         """ Convert to text definition e.g. VK_FOO = 1 """
408         # Hex is commonly used for FlagBits and sometimes within
409         # a non-FlagBits enum for a bitmask value as well.
410         if self.hex:
411             return "{0} = 0x{1:08x}".format(self.name, self.value)
412         else:
413             return "{0} = {1}".format(self.name, self.value)
416 class VkFunction(object):
417     def __init__(self, _type=None, name=None, params=[], extensions=[], alias=None):
418         self.extensions = []
419         self.name = name
420         self.type = _type
421         self.params = params
422         self.alias = alias
424         # For some functions we need some extra metadata from FUNCTION_OVERRIDES.
425         func_info = FUNCTION_OVERRIDES.get(self.name, None)
426         self.dispatch = func_info["dispatch"] if func_info else True
427         self.driver = func_info["driver"] if func_info else False
428         self.thunk_needed = func_info["thunk"] if func_info else True
429         self.private_thunk = func_info["private_thunk"] if func_info and "private_thunk" in func_info else False
430         if self.private_thunk:
431             self.thunk_needed = True
433         # Required is set while parsing which APIs and types are required
434         # and is used by the code generation.
435         self.required = True if func_info else False
437     @staticmethod
438     def from_alias(command, alias):
439         """ Create VkFunction from an alias command.
441         Args:
442             command: xml data for command
443             alias (VkFunction): function to use as a base for types / parameters.
445         Returns:
446             VkFunction
447         """
448         func_name = command.attrib.get("name")
449         func_type = alias.type
450         params = alias.params
452         return VkFunction(_type=func_type, name=func_name, params=params, alias=alias)
454     @staticmethod
455     def from_xml(command, types):
456         proto = command.find("proto")
457         func_name = proto.find("name").text
458         func_type = proto.find("type").text
460         params = []
461         for param in command.findall("param"):
462             vk_param = VkParam.from_xml(param, types)
463             params.append(vk_param)
465         return VkFunction(_type=func_type, name=func_name, params=params)
467     def get_conversions(self):
468         """ Get a list of conversion functions required for this function if any.
469         Parameters which are structures may require conversion between win32
470         and the host platform. This function returns a list of conversions
471         required.
472         """
474         conversions = []
475         for param in self.params:
476             convs = param.get_conversions()
477             if convs is not None:
478                 conversions.extend(convs)
480         return conversions
482     def is_alias(self):
483         return bool(self.alias)
485     def is_core_func(self):
486         """ Returns whether the function is a Vulkan core function.
487         Core functions are APIs defined by the Vulkan spec to be part of the
488         Core API as well as several KHR WSI extensions.
489         """
491         if not self.extensions:
492             return True
494         return any(ext in self.extensions for ext in CORE_EXTENSIONS)
496     def is_device_func(self):
497         # If none of the other, it must be a device function
498         return not self.is_global_func() and not self.is_instance_func()
500     def is_driver_func(self):
501         """ Returns if function is part of Wine driver interface. """
502         return self.driver
504     def is_global_func(self):
505         # Treat vkGetInstanceProcAddr as a global function as it
506         # can operate with NULL for vkInstance.
507         if self.name == "vkGetInstanceProcAddr":
508             return True
509         # Global functions are not passed a dispatchable object.
510         elif self.params[0].is_dispatchable():
511             return False
512         return True
514     def is_instance_func(self):
515         # Instance functions are passed VkInstance or VkPhysicalDevice.
516         if self.params[0].type in ["VkInstance", "VkPhysicalDevice"]:
517             return True
518         return False
520     def is_required(self):
521         return self.required
523     def needs_conversion(self):
524         """ Check if the function needs any input/output type conversion.
525         Functions need input/output conversion if struct parameters have
526         alignment differences between Win32 and Linux 32-bit.
527         """
529         for p in self.params:
530             if p.needs_conversion():
531                 LOGGER.debug("Parameter {0} to {1} requires conversion".format(p.name, self.name))
532                 return True
534         return False
536     def needs_dispatch(self):
537         return self.dispatch
539     def needs_thunk(self):
540         return self.thunk_needed
542     def needs_private_thunk(self):
543         return self.private_thunk
545     def pfn(self, prefix="p", call_conv=None, conv=False):
546         """ Create function pointer. """
548         if call_conv:
549             pfn = "{0} ({1} *{2}_{3})(".format(self.type, call_conv, prefix, self.name)
550         else:
551             pfn = "{0} (*{1}_{2})(".format(self.type, prefix, self.name)
553         for i, param in enumerate(self.params):
554             if param.const:
555                 pfn += param.const + " "
557             pfn += param.type
558             if conv and param.needs_conversion():
559                 pfn += "_host"
561             if param.is_pointer():
562                 pfn += " " + param.pointer
564             if param.array_len is not None:
565                 pfn += "[{0}]".format(param.array_len)
567             if i < len(self.params) - 1:
568                 pfn += ", "
569         pfn += ")"
570         return pfn
572     def prototype(self, call_conv=None, prefix=None, postfix=None):
573         """ Generate prototype for given function.
575         Args:
576             call_conv (str, optional): calling convention e.g. WINAPI
577             prefix (str, optional): prefix to append prior to function name e.g. vkFoo -> wine_vkFoo
578             postfix (str, optional): text to append after function name but prior to semicolon e.g. DECLSPEC_HIDDEN
579         """
581         proto = "{0}".format(self.type)
583         if call_conv is not None:
584             proto += " {0}".format(call_conv)
586         if prefix is not None:
587             proto += " {0}{1}(".format(prefix, self.name)
588         else:
589             proto += " {0}(".format(self.name)
591         # Add all the parameters.
592         proto += ", ".join([p.definition() for p in self.params])
594         if postfix is not None:
595             proto += ") {0}".format(postfix)
596         else:
597             proto += ")"
599         return proto
601     def body(self):
602         body = ""
604         if not self.needs_private_thunk():
605             body += "    {0}".format(self.trace())
607         params = ", ".join([p.variable(conv=False) for p in self.params])
609         # Call the native Vulkan function.
610         if self.type == "void":
611             body += "    {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
612         else:
613             body += "    return {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
615         return body
617     def body_conversion(self):
618         body = ""
620         # Declare a variable to hold the result for non-void functions.
621         if self.type != "void":
622             body += "    {0} result;\n".format(self.type)
624         # Declare any tmp parameters for conversion.
625         for p in self.params:
626             if not p.needs_conversion():
627                 continue
629             if p.is_dynamic_array():
630                 body += "    {0}_host *{1}_host;\n".format(p.type, p.name)
631             else:
632                 body += "    {0}_host {1}_host;\n".format(p.type, p.name)
634         if not self.needs_private_thunk():
635             body += "    {0}\n".format(self.trace())
637         # Call any win_to_host conversion calls.
638         for p in self.params:
639             if not p.needs_input_conversion():
640                 continue
642             body += p.copy(Direction.INPUT)
644         # Build list of parameters containing converted and non-converted parameters.
645         # The param itself knows if conversion is needed and applies it when we set conv=True.
646         params = ", ".join([p.variable(conv=True) for p in self.params])
648         # Call the native Vulkan function.
649         if self.type == "void":
650             body += "    {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
651         else:
652             body += "    result = {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
654         body += "\n"
656         # Call any host_to_win conversion calls.
657         for p in self.params:
658             if not p.needs_output_conversion():
659                 continue
661             body += p.copy(Direction.OUTPUT)
663         # Perform any required cleanups. Most of these are for array functions.
664         for p in self.params:
665             if not p.needs_free():
666                 continue
668             body += p.free()
670         # Finally return the result.
671         if self.type != "void":
672             body += "    return result;\n"
674         return body
676     def spec(self, prefix=None, symbol=None):
677         """ Generate spec file entry for this function.
679         Args
680             prefix (str, optional): prefix to prepend to entry point name.
681             symbol (str, optional): allows overriding the name of the function implementing the entry point.
682         """
684         spec = ""
685         params = " ".join([p.spec() for p in self.params])
686         if prefix is not None:
687             spec += "@ stdcall -private {0}{1}({2})".format(prefix, self.name, params)
688         else:
689             spec += "@ stdcall {0}({1})".format(self.name, params)
691         if symbol is not None:
692             spec += " " + symbol
694         spec += "\n"
695         return spec
697     def stub(self, call_conv=None, prefix=None):
698         stub = self.prototype(call_conv=call_conv, prefix=prefix)
699         stub += "\n{\n"
700         stub += "    {0}".format(self.trace(message="stub: ", trace_func="FIXME"))
702         if self.type == "VkResult":
703             stub += "    return VK_ERROR_OUT_OF_HOST_MEMORY;\n"
704         elif self.type == "VkBool32":
705             stub += "    return VK_FALSE;\n"
706         elif self.type == "PFN_vkVoidFunction":
707             stub += "    return NULL;\n"
709         stub += "}\n\n"
710         return stub
712     def thunk(self, call_conv=None, prefix=None):
713         thunk = self.prototype(call_conv=call_conv, prefix=prefix)
714         thunk += "\n{\n"
716         if self.needs_conversion():
717             thunk += "#if defined(USE_STRUCT_CONVERSION)\n"
718             thunk += self.body_conversion()
719             thunk += "#else\n"
720             thunk += self.body()
721             thunk += "#endif\n"
722         else:
723             thunk += self.body()
725         thunk += "}\n\n"
726         return thunk
728     def trace(self, message=None, trace_func=None):
729         """ Create a trace string including all parameters.
731         Args:
732             message (str, optional): text to print at start of trace message e.g. 'stub: '
733             trace_func (str, optional): used to override trace function e.g. FIXME, printf, etcetera.
734         """
735         if trace_func is not None:
736             trace = "{0}(\"".format(trace_func)
737         else:
738             trace = "TRACE(\""
740         if message is not None:
741             trace += message
743         # First loop is for all the format strings.
744         trace += ", ".join([p.format_string() for p in self.params])
745         trace += "\\n\""
747         # Second loop for parameter names and optional conversions.
748         for param in self.params:
749             if param.format_conv is not None:
750                 trace += ", " + param.format_conv.format(param.name)
751             else:
752                 trace += ", {0}".format(param.name)
753         trace += ");\n"
755         return trace
758 class VkFunctionPointer(object):
759     def __init__(self, _type, name, members):
760         self.name = name
761         self.members = members
762         self.type = _type
763         self.required = False
765     @staticmethod
766     def from_xml(funcpointer):
767         members = []
768         begin = None
770         for t in funcpointer.findall("type"):
771             # General form:
772             # <type>void</type>*       pUserData,
773             # Parsing of the tail (anything past </type>) is tricky since there
774             # can be other data on the next line like: const <type>int</type>..
776             const = True if begin and "const" in begin else False
777             _type = t.text
778             lines = t.tail.split(",\n")
779             if lines[0][0] == "*":
780                 pointer = "*"
781                 name = lines[0][1:].strip()
782             else:
783                 pointer = None
784                 name = lines[0].strip()
786             # Filter out ); if it is contained.
787             name = name.partition(");")[0]
789             # If tail encompasses multiple lines, assign the second line to begin
790             # for the next line.
791             try:
792                 begin = lines[1].strip()
793             except IndexError:
794                 begin = None
796             members.append(VkMember(const=const, _type=_type, pointer=pointer, name=name))
798         _type = funcpointer.text
799         name = funcpointer.find("name").text
800         return VkFunctionPointer(_type, name, members)
802     def definition(self):
803         text = "{0} {1})(\n".format(self.type, self.name)
805         first = True
806         if len(self.members) > 0:
807             for m in self.members:
808                 if first:
809                     text += "    " + m.definition()
810                     first = False
811                 else:
812                     text += ",\n    " + m.definition()
813         else:
814             # Just make the compiler happy by adding a void parameter.
815             text += "void"
816         text += ");\n"
817         return text
820 class VkHandle(object):
821     def __init__(self, name, _type, parent, alias=None):
822         self.name = name
823         self.type = _type
824         self.parent = parent
825         self.alias = alias
826         self.required = False
828     @staticmethod
829     def from_alias(handle, alias):
830         name = handle.attrib.get("name")
831         return VkHandle(name, alias.type, alias.parent, alias=alias)
833     @staticmethod
834     def from_xml(handle):
835         name = handle.find("name").text
836         _type = handle.find("type").text
837         parent = handle.attrib.get("parent") # Most objects have a parent e.g. VkQueue has VkDevice.
838         return VkHandle(name, _type, parent)
840     def dispatch_table(self):
841         if not self.is_dispatchable():
842             return None
844         if self.parent is None:
845             # Should only happen for VkInstance
846             return "funcs"
847         elif self.name == "VkDevice":
848             # VkDevice has VkInstance as a parent, but has its own dispatch table.
849             return "funcs"
850         elif self.parent in ["VkInstance", "VkPhysicalDevice"]:
851             return "instance->funcs"
852         elif self.parent in ["VkDevice", "VkCommandPool"]:
853             return "device->funcs"
854         else:
855             LOGGER.error("Unhandled dispatchable parent: {0}".format(self.parent))
857     def definition(self):
858         """ Generates handle definition e.g. VK_DEFINE_HANDLE(vkInstance) """
860         # Legacy types are typedef'ed to the new type if they are aliases.
861         if self.is_alias():
862             return "typedef {0} {1};\n".format(self.alias.name, self.name)
864         return "{0}({1})\n".format(self.type, self.name)
866     def is_alias(self):
867         return self.alias is not None
869     def is_dispatchable(self):
870         """ Some handles like VkInstance, VkDevice are dispatchable objects,
871         which means they contain a dispatch table of function pointers.
872         """
873         return self.type == "VK_DEFINE_HANDLE"
875     def is_required(self):
876         return self.required
878     def native_handle(self, name):
879         """ Provide access to the native handle of a wrapped object. """
881         if self.name == "VkCommandPool":
882             return "wine_cmd_pool_from_handle({0})->command_pool".format(name)
884         native_handle_name = None
886         if self.name == "VkCommandBuffer":
887             native_handle_name = "command_buffer"
888         if self.name == "VkDevice":
889             native_handle_name = "device"
890         if self.name == "VkInstance":
891             native_handle_name = "instance"
892         if self.name == "VkPhysicalDevice":
893             native_handle_name = "phys_dev"
894         if self.name == "VkQueue":
895             native_handle_name = "queue"
897         if native_handle_name:
898             return "{0}->{1}".format(name, native_handle_name)
900         if self.is_dispatchable():
901             LOGGER.error("Unhandled native handle for: {0}".format(self.name))
902         return None
905 class VkMember(object):
906     def __init__(self, const=False, struct_fwd_decl=False,_type=None, pointer=None, name=None, array_len=None,
907             dyn_array_len=None, optional=False):
908         self.const = const
909         self.struct_fwd_decl = struct_fwd_decl
910         self.name = name
911         self.pointer = pointer
912         self.type = _type
913         self.type_info = None
914         self.array_len = array_len
915         self.dyn_array_len = dyn_array_len
916         self.optional = optional
918     def __eq__(self, other):
919         """ Compare member based on name against a string.
921         This method is for convenience by VkStruct, which holds a number of members and needs quick checking
922         if certain members exist.
923         """
925         if self.name == other:
926             return True
928         return False
930     def __repr__(self):
931         return "{0} {1} {2} {3} {4} {5} {6}".format(self.const, self.struct_fwd_decl, self.type, self.pointer,
932                 self.name, self.array_len, self.dyn_array_len)
934     @staticmethod
935     def from_xml(member):
936         """ Helper function for parsing a member tag within a struct or union. """
938         name_elem = member.find("name")
939         type_elem = member.find("type")
941         const = False
942         struct_fwd_decl = False
943         member_type = None
944         pointer = None
945         array_len = None
947         if member.text:
948             if "const" in member.text:
949                 const = True
951             # Some members contain forward declarations:
952             # - VkBaseInstructure has a member "const struct VkBaseInStructure *pNext"
953             # - VkWaylandSurfaceCreateInfoKHR has a member "struct wl_display *display"
954             if "struct" in member.text:
955                 struct_fwd_decl = True
957         if type_elem is not None:
958             member_type = type_elem.text
959             if type_elem.tail is not None:
960                 pointer = type_elem.tail.strip() if type_elem.tail.strip() != "" else None
962         # Name of other member within, which stores the number of
963         # elements pointed to be by this member.
964         dyn_array_len = member.get("len")
966         # Some members are optional, which is important for conversion code e.g. not dereference NULL pointer.
967         optional = True if member.get("optional") else False
969         # Usually we need to allocate memory for dynamic arrays. We need to do the same in a few other cases
970         # like for VkCommandBufferBeginInfo.pInheritanceInfo. Just threat such cases as dynamic arrays of
971         # size 1 to simplify code generation.
972         if dyn_array_len is None and pointer is not None:
973             dyn_array_len = 1
975         # Some members are arrays, attempt to parse these. Formats include:
976         # <member><type>char</type><name>extensionName</name>[<enum>VK_MAX_EXTENSION_NAME_SIZE</enum>]</member>
977         # <member><type>uint32_t</type><name>foo</name>[4]</member>
978         if name_elem.tail and name_elem.tail[0] == '[':
979             LOGGER.debug("Found array type")
980             enum_elem = member.find("enum")
981             if enum_elem is not None:
982                 array_len = enum_elem.text
983             else:
984                 # Remove brackets around length
985                 array_len = name_elem.tail.strip("[]")
987         return VkMember(const=const, struct_fwd_decl=struct_fwd_decl, _type=member_type, pointer=pointer, name=name_elem.text,
988                 array_len=array_len, dyn_array_len=dyn_array_len, optional=optional)
990     def copy(self, input, output, direction):
991         """ Helper method for use by conversion logic to generate a C-code statement to copy this member. """
993         if self.needs_conversion():
994             if self.is_dynamic_array():
995                 if direction == Direction.OUTPUT:
996                     LOGGER.warn("TODO: implement copying of returnedonly dynamic array for {0}.{1}".format(self.type, self.name))
997                 else:
998                     # Array length is either a variable name (string) or an int.
999                     count = self.dyn_array_len if isinstance(self.dyn_array_len, int) else "{0}{1}".format(input, self.dyn_array_len)
1000                     return "{0}{1} = convert_{2}_array_win_to_host({3}{1}, {4});\n".format(output, self.name, self.type, input, count)
1001             elif self.is_static_array():
1002                 count = self.array_len
1003                 if direction == Direction.OUTPUT:
1004                     # Needed by VkMemoryHeap.memoryHeaps
1005                     return "convert_{0}_static_array_host_to_win({2}{1}, {3}{1}, {4});\n".format(self.type, self.name, input, output, count)
1006                 else:
1007                     # Nothing needed this yet.
1008                     LOGGER.warn("TODO: implement copying of static array for {0}.{1}".format(self.type, self.name))
1009             else:
1010                 if direction == Direction.OUTPUT:
1011                     return "convert_{0}_host_to_win(&{2}{1}, &{3}{1});\n".format(self.type, self.name, input, output)
1012                 else:
1013                     return "convert_{0}_win_to_host(&{2}{1}, &{3}{1});\n".format(self.type, self.name, input, output)
1014         elif self.is_static_array():
1015             bytes_count = "{0} * sizeof({1})".format(self.array_len, self.type)
1016             return "memcpy({0}{1}, {2}{1}, {3});\n".format(output, self.name, input, bytes_count)
1017         else:
1018             return "{0}{1} = {2}{1};\n".format(output, self.name, input)
1020     def definition(self, align=False, conv=False):
1021         """ Generate prototype for given function.
1023         Args:
1024             align (bool, optional): Enable alignment if a type needs it. This adds WINE_VK_ALIGN(8) to a member.
1025             conv (bool, optional): Enable conversion if a type needs it. This appends '_host' to the name.
1026         """
1028         text = ""
1029         if self.is_const():
1030             text += "const "
1032         if self.is_struct_forward_declaration():
1033             text += "struct "
1035         if conv and self.is_struct():
1036             text += "{0}_host".format(self.type)
1037         else:
1038             text += self.type
1040         if self.is_pointer():
1041             text += " {0}{1}".format(self.pointer, self.name)
1042         else:
1043             if align and self.needs_alignment():
1044                 text += " WINE_VK_ALIGN(8) " + self.name
1045             else:
1046                 text += " " + self.name
1048         if self.is_static_array():
1049             text += "[{0}]".format(self.array_len)
1051         return text
1053     def get_conversions(self):
1054         """ Return any conversion description for this member and its children when conversion is needed. """
1056         # Check if we need conversion either for this member itself or for any child members
1057         # in case member represents a struct.
1058         if not self.needs_conversion():
1059             return None
1061         conversions = []
1063         # Collect any conversion for any member structs.
1064         struct = self.type_info["data"]
1065         for m in struct:
1066             m.needs_struct_extensions_conversion()
1067             if m.needs_conversion():
1068                 conversions.extend(m.get_conversions())
1070         struct.needs_struct_extensions_conversion()
1072         struct = self.type_info["data"]
1073         direction = Direction.OUTPUT if struct.returnedonly else Direction.INPUT
1074         if self.is_dynamic_array():
1075             conversions.append(ConversionFunction(False, True, direction, struct))
1076         elif self.is_static_array():
1077             conversions.append(ConversionFunction(True, False, direction, struct))
1078         else:
1079             conversions.append(ConversionFunction(False, False, direction, struct))
1081         if self.needs_free():
1082             conversions.append(FreeFunction(self.is_dynamic_array(), struct))
1084         return conversions
1086     def is_const(self):
1087         return self.const
1089     def is_dynamic_array(self):
1090         """ Returns if the member is an array element.
1091         Vulkan uses this for dynamically sized arrays for which
1092         there is a 'count' parameter.
1093         """
1094         return self.dyn_array_len is not None
1096     def is_handle(self):
1097         return self.type_info["category"] == "handle"
1099     def is_pointer(self):
1100         return self.pointer is not None
1102     def is_static_array(self):
1103         """ Returns if the member is an array.
1104         Vulkan uses this often for fixed size arrays in which the
1105         length is part of the member.
1106         """
1107         return self.array_len is not None
1109     def is_struct(self):
1110         return self.type_info["category"] == "struct"
1112     def is_struct_forward_declaration(self):
1113         return self.struct_fwd_decl
1115     def is_union(self):
1116         return self.type_info["category"] == "union"
1118     def needs_alignment(self):
1119         """ Check if this member needs alignment for 64-bit data.
1120         Various structures need alignment on 64-bit variables due
1121         to compiler differences on 32-bit between Win32 and Linux.
1122         """
1124         if self.is_pointer():
1125             return False
1126         elif self.type == "size_t":
1127             return False
1128         elif self.type in ["uint64_t", "VkDeviceSize"]:
1129             return True
1130         elif self.is_struct():
1131             struct = self.type_info["data"]
1132             return struct.needs_alignment()
1133         elif self.is_handle():
1134             # Dispatchable handles are pointers to objects, while
1135             # non-dispatchable are uint64_t and hence need alignment.
1136             handle = self.type_info["data"]
1137             return False if handle.is_dispatchable() else True
1138         return False
1140     def needs_conversion(self):
1141         """ Structures requiring alignment, need conversion between win32 and host. """
1143         if not self.is_struct():
1144             return False
1146         struct = self.type_info["data"]
1147         return struct.needs_conversion()
1149     def needs_free(self):
1150         if not self.needs_conversion():
1151             return False
1153         if self.is_dynamic_array():
1154             return True
1156         # TODO: some non-pointer structs and optional pointer structs may need freeing,
1157         # though none of this type have been encountered yet.
1158         return False
1160     def needs_struct_extensions_conversion(self):
1161         if not self.is_struct():
1162             return False
1164         struct = self.type_info["data"]
1165         return struct.needs_struct_extensions_conversion()
1167     def set_type_info(self, type_info):
1168         """ Helper function to set type information from the type registry.
1169         This is needed, because not all type data is available at time of
1170         parsing.
1171         """
1172         self.type_info = type_info
1175 class VkParam(object):
1176     """ Helper class which describes a parameter to a function call. """
1178     def __init__(self, type_info, const=None, pointer=None, name=None, array_len=None, dyn_array_len=None):
1179         self.const = const
1180         self.name = name
1181         self.array_len = array_len
1182         self.dyn_array_len = dyn_array_len
1183         self.pointer = pointer
1184         self.type_info = type_info
1185         self.type = type_info["name"] # For convenience
1186         self.handle = type_info["data"] if type_info["category"] == "handle" else None
1187         self.struct = type_info["data"] if type_info["category"] == "struct" else None
1189         self._set_direction()
1190         self._set_format_string()
1191         self._set_conversions()
1193     def __repr__(self):
1194         return "{0} {1} {2} {3} {4} {5}".format(self.const, self.type, self.pointer, self.name, self.array_len, self.dyn_array_len)
1196     @staticmethod
1197     def from_xml(param, types):
1198         """ Helper function to create VkParam from xml. """
1200         # Parameter parsing is slightly tricky. All the data is contained within
1201         # a param tag, but some data is within subtags while others are text
1202         # before or after the type tag.
1203         # Common structure:
1204         # <param>const <type>char</type>* <name>pLayerName</name></param>
1206         name_elem = param.find("name")
1207         array_len = None
1208         name = name_elem.text
1209         # Tail contains array length e.g. for blendConstants param of vkSetBlendConstants
1210         if name_elem.tail is not None:
1211             array_len = name_elem.tail.strip("[]")
1213         # Name of other parameter in function prototype, which stores the number of
1214         # elements pointed to be by this parameter.
1215         dyn_array_len = param.get("len", None)
1217         const = param.text.strip() if param.text else None
1218         type_elem = param.find("type")
1219         pointer = type_elem.tail.strip() if type_elem.tail.strip() != "" else None
1221         # Since we have parsed all types before hand, this should not happen.
1222         type_info = types.get(type_elem.text, None)
1223         if type_info is None:
1224             LOGGER.err("type info not found for: {0}".format(type_elem.text))
1226         return VkParam(type_info, const=const, pointer=pointer, name=name, array_len=array_len, dyn_array_len=dyn_array_len)
1228     def _set_conversions(self):
1229         """ Internal helper function to configure any needed conversion functions. """
1231         self.free_func = None
1232         self.input_conv = None
1233         self.output_conv = None
1234         if not self.needs_conversion():
1235             return
1237         # Input functions require win to host conversion.
1238         if self._direction in [Direction.INPUT, Direction.INPUT_OUTPUT]:
1239             self.input_conv = ConversionFunction(False, self.is_dynamic_array(), Direction.INPUT, self.struct)
1241         # Output functions require host to win conversion.
1242         if self._direction in [Direction.INPUT_OUTPUT, Direction.OUTPUT]:
1243             self.output_conv = ConversionFunction(False, self.is_dynamic_array(), Direction.OUTPUT, self.struct)
1245         # Dynamic arrays, but also some normal structs (e.g. VkCommandBufferBeginInfo) need memory
1246         # allocation and thus some cleanup.
1247         if self.is_dynamic_array() or self.struct.needs_free():
1248             self.free_func = FreeFunction(self.is_dynamic_array(), self.struct)
1250     def _set_direction(self):
1251         """ Internal helper function to set parameter direction (input/output/input_output). """
1253         # The parameter direction needs to be determined from hints in vk.xml like returnedonly,
1254         # parameter constness and other heuristics.
1255         # For now we need to get this right for structures as we need to convert these, we may have
1256         # missed a few other edge cases (e.g. count variables).
1257         # See also https://github.com/KhronosGroup/Vulkan-Docs/issues/610
1259         if not self.is_pointer():
1260             self._direction = Direction.INPUT
1261         elif self.is_const() and self.is_pointer():
1262             self._direction = Direction.INPUT
1263         elif self.is_struct():
1264             if not self.struct.returnedonly:
1265                 self._direction = Direction.INPUT
1266                 return
1268             # Returnedonly hints towards output, however in some cases
1269             # it is inputoutput. In particular if pNext / sType exist,
1270             # which are used to link in other structures without having
1271             # to introduce new APIs. E.g. vkGetPhysicalDeviceProperties2KHR.
1272             if "pNext" in self.struct:
1273                 self._direction = Direction.INPUT_OUTPUT
1274                 return
1276             self._direction = Direction.OUTPUT
1277         else:
1278             # This should mostly be right. Count variables can be inout, but we don't care about these yet.
1279             self._direction = Direction.OUTPUT
1281     def _set_format_string(self):
1282         """ Internal helper function to be used by constructor to set format string. """
1284         # Determine a format string used by code generation for traces.
1285         # 64-bit types need a conversion function.
1286         self.format_conv = None
1287         if self.is_static_array() or self.is_pointer():
1288             self.format_str = "%p"
1289         else:
1290             if self.type_info["category"] in ["bitmask", "enum"]:
1291                 self.format_str = "%#x"
1292             elif self.is_handle():
1293                 # We use uint64_t for non-dispatchable handles as opposed to pointers
1294                 # for dispatchable handles.
1295                 if self.handle.is_dispatchable():
1296                     self.format_str = "%p"
1297                 else:
1298                     self.format_str = "0x%s"
1299                     self.format_conv = "wine_dbgstr_longlong({0})"
1300             elif self.type == "float":
1301                 self.format_str = "%f"
1302             elif self.type == "int":
1303                 self.format_str = "%d"
1304             elif self.type == "int32_t":
1305                 self.format_str = "%d"
1306             elif self.type == "size_t":
1307                 self.format_str = "0x%s"
1308                 self.format_conv = "wine_dbgstr_longlong({0})"
1309             elif self.type in ["uint32_t", "VkBool32"]:
1310                 self.format_str = "%u"
1311             elif self.type in ["uint64_t", "VkDeviceSize"]:
1312                 self.format_str = "0x%s"
1313                 self.format_conv = "wine_dbgstr_longlong({0})"
1314             elif self.type == "HANDLE":
1315                 self.format_str = "%p"
1316             elif self.type in ["VisualID", "xcb_visualid_t", "RROutput"]:
1317                 # Don't care about Linux specific types.
1318                 self.format_str = ""
1319             else:
1320                 LOGGER.warn("Unhandled type: {0}".format(self.type_info))
1322     def copy(self, direction):
1323         if direction == Direction.INPUT:
1324             if self.is_dynamic_array():
1325                 return "    {0}_host = convert_{1}_array_win_to_host({0}, {2});\n".format(self.name, self.type, self.dyn_array_len)
1326             else:
1327                 return "    convert_{0}_win_to_host({1}, &{1}_host);\n".format(self.type, self.name)
1328         else:
1329             if self.is_dynamic_array():
1330                 LOGGER.error("Unimplemented output conversion for: {0}".format(self.name))
1331             else:
1332                 return "    convert_{0}_host_to_win(&{1}_host, {1});\n".format(self.type, self.name)
1334     def definition(self, postfix=None):
1335         """ Return prototype for the parameter. E.g. 'const char *foo' """
1337         proto = ""
1338         if self.const:
1339             proto += self.const + " "
1341         proto += self.type
1343         if self.is_pointer():
1344             proto += " {0}{1}".format(self.pointer, self.name)
1345         else:
1346             proto += " " + self.name
1348         # Allows appending something to the variable name useful for
1349         # win32 to host conversion.
1350         if postfix is not None:
1351             proto += postfix
1353         if self.is_static_array():
1354             proto += "[{0}]".format(self.array_len)
1356         return proto
1358     def direction(self):
1359         """ Returns parameter direction: input, output, input_output.
1361         Parameter direction in Vulkan is not straight-forward, which this function determines.
1362         """
1364         return self._direction
1366     def dispatch_table(self):
1367         """ Return functions dispatch table pointer for dispatchable objects. """
1369         if not self.is_dispatchable():
1370             return None
1372         return "{0}->{1}".format(self.name, self.handle.dispatch_table())
1374     def format_string(self):
1375         return self.format_str
1377     def free(self):
1378         if self.is_dynamic_array():
1379             if self.struct.returnedonly:
1380                 # For returnedonly, counts is stored in a pointer.
1381                 return "    free_{0}_array({1}_host, *{2});\n".format(self.type, self.name, self.dyn_array_len)
1382             else:
1383                 return "    free_{0}_array({1}_host, {2});\n".format(self.type, self.name, self.dyn_array_len)
1384         else:
1385             # We are operating on a single structure. Some structs (very rare) contain dynamic members,
1386             # which would need freeing.
1387             if self.struct.needs_free():
1388                 return "    free_{0}(&{1}_host);\n".format(self.type, self.name)
1389         return ""
1391     def get_conversions(self):
1392         """ Get a list of conversions required for this parameter if any.
1393         Parameters which are structures may require conversion between win32
1394         and the host platform. This function returns a list of conversions
1395         required.
1396         """
1398         if not self.is_struct():
1399             return None
1401         self.struct.needs_struct_extensions_conversion()
1402         for m in self.struct:
1403             m.needs_struct_extensions_conversion()
1405         if not self.needs_conversion():
1406             return None
1408         conversions = []
1410         # Collect any member conversions first, so we can guarantee
1411         # those functions will be defined prior to usage by the
1412         # 'parent' param requiring conversion.
1413         for m in self.struct:
1414             if not m.is_struct():
1415                 continue
1417             if not m.needs_conversion():
1418                 continue
1420             conversions.extend(m.get_conversions())
1422         # Conversion requirements for the 'parent' parameter.
1423         if self.input_conv is not None:
1424             conversions.append(self.input_conv)
1425         if self.output_conv is not None:
1426             conversions.append(self.output_conv)
1427         if self.free_func is not None:
1428             conversions.append(self.free_func)
1430         return conversions
1432     def is_const(self):
1433         return self.const is not None
1435     def is_dynamic_array(self):
1436         return self.dyn_array_len is not None
1438     def is_dispatchable(self):
1439         if not self.is_handle():
1440             return False
1442         return self.handle.is_dispatchable()
1444     def is_handle(self):
1445         return self.handle is not None
1447     def is_pointer(self):
1448         return self.pointer is not None
1450     def is_static_array(self):
1451         return self.array_len is not None
1453     def is_struct(self):
1454         return self.struct is not None
1456     def needs_conversion(self):
1457         """ Returns if parameter needs conversion between win32 and host. """
1459         if not self.is_struct():
1460             return False
1462         # VkSparseImageMemoryRequirements(2) is used by vkGetImageSparseMemoryRequirements(2).
1463         # This function is tricky to wrap, because how to wrap depends on whether
1464         # pSparseMemoryRequirements is NULL or not. Luckily for VkSparseImageMemoryRequirements(2)
1465         # the alignment works out in such a way that no conversion is needed between win32 and Linux.
1466         if self.type in ["VkSparseImageMemoryRequirements", "VkSparseImageMemoryRequirements2"]:
1467             return False
1469         # If a structure needs alignment changes, it means we need to
1470         # perform parameter conversion between win32 and host.
1471         if self.struct.needs_conversion():
1472             return True
1474         return False
1476     def needs_free(self):
1477         return self.free_func is not None
1479     def needs_input_conversion(self):
1480         return self.input_conv is not None
1482     def needs_output_conversion(self):
1483         return self.output_conv is not None
1485     def spec(self):
1486         """ Generate spec file entry for this parameter. """
1488         if self.type_info["category"] in ["bitmask", "enum"]:
1489             return "long"
1490         if self.is_pointer() and self.type == "char":
1491             return "str"
1492         if self.is_dispatchable() or self.is_pointer() or self.is_static_array():
1493             return "ptr"
1494         if self.is_handle() and not self.is_dispatchable():
1495             return "int64"
1496         if self.type == "float":
1497             return "float"
1498         if self.type in ["int", "int32_t", "size_t", "uint32_t", "VkBool32"]:
1499             return "long"
1500         if self.type in ["uint64_t", "VkDeviceSize"]:
1501             return "int64"
1503         LOGGER.error("Unhandled spec conversion for type: {0}".format(self.type))
1505     def variable(self, conv=False):
1506         """ Returns 'glue' code during generation of a function call on how to access the variable.
1507         This function handles various scenarios such as 'unwrapping' if dispatchable objects and
1508         renaming of parameters in case of win32 -> host conversion.
1510         Args:
1511             conv (bool, optional): Enable conversion if the param needs it. This appends '_host' to the name.
1512         """
1514         # Hack until we enable allocation callbacks from ICD to application. These are a joy
1515         # to enable one day, because of calling convention conversion.
1516         if "VkAllocationCallbacks" in self.type:
1517             LOGGER.debug("TODO: setting NULL VkAllocationCallbacks for {0}".format(self.name))
1518             return "NULL"
1520         if conv and self.needs_conversion():
1521             if self.is_dynamic_array():
1522                 return "{0}_host".format(self.name)
1523             else:
1524                 return "&{0}_host".format(self.name)
1525         else:
1526             # We need to pass the native handle to the native Vulkan calls.
1527             native_handle = self.handle.native_handle(self.name) if self.is_handle() else None
1528             return native_handle if native_handle else self.name
1531 class VkStruct(Sequence):
1532     """ Class which represents the type union and struct. """
1534     def __init__(self, name, members, returnedonly, structextends, alias=None, union=False):
1535         self.name = name
1536         self.members = members
1537         self.returnedonly = returnedonly
1538         self.structextends = structextends
1539         self.required = False
1540         self.alias = alias
1541         self.union = union
1542         self.type_info = None # To be set later.
1543         self.struct_extensions = []
1545     def __getitem__(self, i):
1546         return self.members[i]
1548     def __len__(self):
1549         return len(self.members)
1551     @staticmethod
1552     def from_alias(struct, alias):
1553         name = struct.attrib.get("name")
1554         return VkStruct(name, alias.members, alias.returnedonly, alias.structextends, alias=alias)
1556     @staticmethod
1557     def from_xml(struct):
1558         # Unions and structs are the same parsing wise, but we need to
1559         # know which one we are dealing with later on for code generation.
1560         union = True if struct.attrib["category"] == "union" else False
1562         name = struct.attrib.get("name")
1564         # 'Output' structures for which data is filled in by the API are
1565         # marked as 'returnedonly'.
1566         returnedonly = True if struct.attrib.get("returnedonly") else False
1568         structextends = struct.attrib.get("structextends")
1569         structextends = structextends.split(",") if structextends else []
1571         members = []
1572         for member in struct.findall("member"):
1573             vk_member = VkMember.from_xml(member)
1574             members.append(vk_member)
1576         return VkStruct(name, members, returnedonly, structextends, union=union)
1578     @staticmethod
1579     def decouple_structs(structs):
1580         """ Helper function which decouples a list of structs.
1581         Structures often depend on other structures. To make the C compiler
1582         happy we need to define 'substructures' first. This function analyzes
1583         the list of structures and reorders them in such a way that they are
1584         decoupled.
1585         """
1587         tmp_structs = list(structs) # Don't modify the original structures.
1588         decoupled_structs = []
1590         while (len(tmp_structs) > 0):
1591             for struct in tmp_structs:
1592                 dependends = False
1594                 if not struct.required:
1595                     tmp_structs.remove(struct)
1596                     continue
1598                 for m in struct:
1599                     if not (m.is_struct() or m.is_union()):
1600                         continue
1602                     # VkBaseInstructure and VkBaseOutStructure reference themselves.
1603                     if m.type == struct.name:
1604                         break
1606                     found = False
1607                     # Check if a struct we depend on has already been defined.
1608                     for s in decoupled_structs:
1609                         if s.name == m.type:
1610                             found = True
1611                             break
1613                     if not found:
1614                         # Check if the struct we depend on is even in the list of structs.
1615                         # If found now, it means we haven't met all dependencies before we
1616                         # can operate on the current struct.
1617                         # When generating 'host' structs we may not be able to find a struct
1618                         # as the list would only contain the structs requiring conversion.
1619                         for s in tmp_structs:
1620                             if s.name == m.type:
1621                                 dependends = True
1622                                 break
1624                 if dependends == False:
1625                     decoupled_structs.append(struct)
1626                     tmp_structs.remove(struct)
1628         return decoupled_structs
1630     def definition(self, align=False, conv=False, postfix=None):
1631         """ Convert structure to textual definition.
1633         Args:
1634             align (bool, optional): enable alignment to 64-bit for win32 struct compatibility.
1635             conv (bool, optional): enable struct conversion if the struct needs it.
1636             postfix (str, optional): text to append to end of struct name, useful for struct renaming.
1637         """
1639         if self.union:
1640             text = "typedef union {0}".format(self.name)
1641         else:
1642             text = "typedef struct {0}".format(self.name)
1644         if postfix is not None:
1645             text += postfix
1647         text += "\n{\n"
1649         for m in self:
1650             if align and m.needs_alignment():
1651                 text += "    {0};\n".format(m.definition(align=align))
1652             elif conv and m.needs_conversion():
1653                 text += "    {0};\n".format(m.definition(conv=conv))
1654             else:
1655                 text += "    {0};\n".format(m.definition())
1657         if postfix is not None:
1658             text += "}} {0}{1};\n\n".format(self.name, postfix)
1659         else:
1660             text += "}} {0};\n\n".format(self.name)
1661         return text
1663     def is_alias(self):
1664         return bool(self.alias)
1666     def needs_alignment(self):
1667         """ Check if structure needs alignment for 64-bit data.
1668         Various structures need alignment on 64-bit variables due
1669         to compiler differences on 32-bit between Win32 and Linux.
1670         """
1672         for m in self.members:
1673             if m.needs_alignment():
1674                 return True
1675         return False
1677     def needs_conversion(self):
1678         """ Returns if struct members needs conversion between win32 and host.
1679         Structures need conversion if they contain members requiring alignment
1680         or if they include other structures which need alignment.
1681         """
1683         if self.needs_alignment():
1684             return True
1686         for m in self.members:
1687             if m.needs_conversion():
1688                 return True
1689         return False
1691     def needs_free(self):
1692         """ Check if any struct member needs some memory freeing."""
1694         for m in self.members:
1695             if m.needs_free():
1696                 return True
1698             continue
1700         return False
1702     def needs_struct_extensions_conversion(self):
1703         """ Checks if structure extensions in pNext chain need conversion. """
1704         ret = False
1706         for e in self.struct_extensions:
1707             if e.required and e.needs_conversion():
1708                 LOGGER.error("Unhandled pNext chain conversion for {0}".format(e.name))
1709                 ret = True
1711         return ret
1713     def set_type_info(self, types):
1714         """ Helper function to set type information from the type registry.
1715         This is needed, because not all type data is available at time of
1716         parsing.
1717         """
1718         for m in self.members:
1719             type_info = types[m.type]
1720             m.set_type_info(type_info)
1723 class ConversionFunction(object):
1724     def __init__(self, array, dyn_array, direction, struct):
1725         self.array = array
1726         self.direction = direction
1727         self.dyn_array = dyn_array
1728         self.struct = struct
1729         self.type = struct.name
1731         self._set_name()
1733     def __eq__(self, other):
1734         if self.name != other.name:
1735             return False
1737         return True
1739     def _generate_array_conversion_func(self):
1740         """ Helper function for generating a conversion function for array structs. """
1742         if self.direction == Direction.OUTPUT:
1743             params = ["const {0}_host *in".format(self.type), "uint32_t count"]
1744             return_type = self.type
1745         else:
1746             params = ["const {0} *in".format(self.type), "uint32_t count"]
1747             return_type = "{0}_host".format(self.type)
1749         # Generate function prototype.
1750         body = "static inline {0} *{1}(".format(return_type, self.name)
1751         body += ", ".join(p for p in params)
1752         body += ")\n{\n"
1754         body += "    {0} *out;\n".format(return_type)
1755         body += "    unsigned int i;\n\n"
1756         body += "    if (!in) return NULL;\n\n"
1758         body += "    out = heap_alloc(count * sizeof(*out));\n"
1760         body += "    for (i = 0; i < count; i++)\n"
1761         body += "    {\n"
1763         for m in self.struct:
1764             # TODO: support copying of pNext extension structures!
1765             # Luckily though no extension struct at this point needs conversion.
1766             body += "        " + m.copy("in[i].", "out[i].", self.direction)
1768         body += "    }\n\n"
1769         body += "    return out;\n"
1770         body += "}\n\n"
1771         return body
1773     def _generate_conversion_func(self):
1774         """ Helper function for generating a conversion function for non-array structs. """
1776         if self.direction == Direction.OUTPUT:
1777             params = ["const {0}_host *in".format(self.type), "{0} *out".format(self.type)]
1778         else:
1779             params = ["const {0} *in".format(self.type), "{0}_host *out".format(self.type)]
1781         body = "static inline void {0}(".format(self.name)
1783         # Generate parameter list
1784         body += ", ".join(p for p in params)
1785         body += ")\n{\n"
1787         body += "    if (!in) return;\n\n"
1789         if self.direction == Direction.INPUT and "pNext" in self.struct and self.struct.returnedonly:
1790             # We are dealing with an input_output parameter. For these we only need to copy
1791             # pNext and sType as the other fields are filled in by the host. We do potentially
1792             # have to iterate over pNext and perform conversions based on switch(sType)!
1793             # Luckily though no extension structs at this point need conversion.
1794             # TODO: support copying of pNext extension structures!
1795             body += "    out->pNext = in->pNext;\n"
1796             body += "    out->sType = in->sType;\n"
1797         else:
1798             for m in self.struct:
1799                 # TODO: support copying of pNext extension structures!
1800                 body += "    " + m.copy("in->", "out->", self.direction)
1802         body += "}\n\n"
1803         return body
1805     def _generate_static_array_conversion_func(self):
1806         """ Helper function for generating a conversion function for array structs. """
1808         if self.direction == Direction.OUTPUT:
1809             params = ["const {0}_host *in".format(self.type), "{0} *out".format(self.type), "uint32_t count"]
1810         else:
1811             params = ["const {0} *in".format(self.type), "{0} *out_host".format(self.type), "uint32_t count"]
1813         # Generate function prototype.
1814         body = "static inline void {0}(".format(self.name)
1815         body += ", ".join(p for p in params)
1816         body += ")\n{\n"
1817         body += "    unsigned int i;\n\n"
1818         body += "    if (!in) return;\n\n"
1819         body += "    for (i = 0; i < count; i++)\n"
1820         body += "    {\n"
1822         for m in self.struct:
1823             # TODO: support copying of pNext extension structures!
1824             body += "        " + m.copy("in[i].", "out[i].", self.direction)
1826         body += "    }\n"
1827         body += "}\n\n"
1828         return body
1830     def _set_name(self):
1831         if self.direction == Direction.INPUT:
1832             if self.array:
1833                 name = "convert_{0}_static_array_win_to_host".format(self.type)
1834             elif self.dyn_array:
1835                 name = "convert_{0}_array_win_to_host".format(self.type)
1836             else:
1837                 name = "convert_{0}_win_to_host".format(self.type)
1838         else: # Direction.OUTPUT
1839             if self.array:
1840                 name = "convert_{0}_static_array_host_to_win".format(self.type)
1841             elif self.dyn_array:
1842                 name = "convert_{0}_array_host_to_win".format(self.type)
1843             else:
1844                 name = "convert_{0}_host_to_win".format(self.type)
1846         self.name = name
1848     def definition(self):
1849         if self.array:
1850             return self._generate_static_array_conversion_func()
1851         elif self.dyn_array:
1852             return self._generate_array_conversion_func()
1853         else:
1854             return self._generate_conversion_func()
1857 class FreeFunction(object):
1858     def __init__(self, dyn_array, struct):
1859         self.dyn_array = dyn_array
1860         self.struct = struct
1861         self.type = struct.name
1863         if dyn_array:
1864             self.name = "free_{0}_array".format(self.type)
1865         else:
1866             self.name = "free_{0}".format(self.type)
1868     def __eq__(self, other):
1869         if self.name == other.name:
1870             return True
1872         return False
1874     def _generate_array_free_func(self):
1875         """ Helper function for cleaning up temporary buffers required for array conversions. """
1877         # Generate function prototype.
1878         body = "static inline void {0}({1}_host *in, uint32_t count)\n{{\n".format(self.name, self.type)
1880         # E.g. VkGraphicsPipelineCreateInfo_host needs freeing for pStages.
1881         if self.struct.needs_free():
1882             body += "    unsigned int i;\n\n"
1883             body += "    if (!in) return;\n\n"
1884             body += "    for (i = 0; i < count; i++)\n"
1885             body += "    {\n"
1887             for m in self.struct:
1888                 if m.needs_conversion() and m.is_dynamic_array():
1889                     if m.is_const():
1890                         # Add a cast to ignore const on conversion structs we allocated ourselves.
1891                         body += "        free_{0}_array(({0}_host *)in[i].{1}, in[i].{2});\n".format(m.type, m.name, m.dyn_array_len)
1892                     else:
1893                         body += "        free_{0}_array(in[i].{1}, in[i].{2});\n".format(m.type, m.name, m.dyn_array_len)
1894                 elif m.needs_conversion():
1895                     LOGGER.error("Unhandled conversion for {0}".format(m.name))
1896             body += "    }\n"
1897         else:
1898             body += "    if (!in) return;\n\n"
1900         body += "    heap_free(in);\n"
1902         body += "}\n\n"
1903         return body
1905     def _generate_free_func(self):
1906         # E.g. VkCommandBufferBeginInfo.pInheritanceInfo needs freeing.
1907         if not self.struct.needs_free():
1908             return ""
1910         # Generate function prototype.
1911         body = "static inline void {0}({1}_host *in)\n{{\n".format(self.name, self.type)
1913         for m in self.struct:
1914             if m.needs_conversion() and m.is_dynamic_array():
1915                 count = m.dyn_array_len if isinstance(m.dyn_array_len, int) else "in->{0}".format(m.dyn_array_len)
1916                 if m.is_const():
1917                     # Add a cast to ignore const on conversion structs we allocated ourselves.
1918                     body += "    free_{0}_array(({0}_host *)in->{1}, {2});\n".format(m.type, m.name, count)
1919                 else:
1920                     body += "    free_{0}_array(in->{1}, {2});\n".format(m.type, m.name, count)
1922         body += "}\n\n"
1923         return body
1925     def definition(self):
1926         if self.dyn_array:
1927             return self._generate_array_free_func()
1928         else:
1929             # Some structures need freeing too if they contain dynamic arrays.
1930             # E.g. VkCommandBufferBeginInfo
1931             return self._generate_free_func()
1934 class VkGenerator(object):
1935     def __init__(self, registry):
1936         self.registry = registry
1938         # Build a list conversion functions for struct conversion.
1939         self.conversions = []
1940         self.host_structs = []
1941         for func in self.registry.funcs.values():
1942             if not func.is_required():
1943                 continue
1945             if not func.needs_conversion():
1946                 continue
1948             conversions = func.get_conversions()
1949             for conv in conversions:
1950                 # Pull in any conversions for vulkan_thunks.c.
1951                 if func.needs_thunk():
1952                     # Append if we don't already have this conversion.
1953                     if not any(c == conv for c in self.conversions):
1954                         self.conversions.append(conv)
1956                 # Structs can be used in different ways by different conversions
1957                 # e.g. array vs non-array. Just make sure we pull in each struct once.
1958                 if not any(s.name == conv.struct.name for s in self.host_structs):
1959                     self.host_structs.append(conv.struct)
1961     def _generate_copyright(self, f, spec_file=False):
1962         f.write("# " if spec_file else "/* ")
1963         f.write("Automatically generated from Vulkan vk.xml; DO NOT EDIT!\n")
1964         lines = ["", "This file is generated from Vulkan vk.xml file covered",
1965             "by the following copyright and permission notice:"]
1966         lines.extend([l.rstrip(" ") for l in self.registry.copyright.splitlines()])
1967         for line in lines:
1968             f.write("{0}{1}".format("# " if spec_file else " * ", line).rstrip(" ") + "\n")
1969         f.write("\n" if spec_file else " */\n\n")
1971     def generate_thunks_c(self, f, prefix):
1972         self._generate_copyright(f)
1973         f.write("#include \"config.h\"\n")
1974         f.write("#include \"wine/port.h\"\n\n")
1976         f.write("#include \"vulkan_private.h\"\n\n")
1978         f.write("WINE_DEFAULT_DEBUG_CHANNEL(vulkan);\n\n")
1980         # Generate any conversion helper functions.
1981         f.write("#if defined(USE_STRUCT_CONVERSION)\n")
1982         for conv in self.conversions:
1983             f.write(conv.definition())
1984         f.write("#endif /* USE_STRUCT_CONVERSION */\n\n")
1986         # Create thunks for instance and device functions.
1987         # Global functions don't go through the thunks.
1988         for vk_func in self.registry.funcs.values():
1989             if not vk_func.is_required():
1990                 continue
1992             if vk_func.is_global_func():
1993                 continue
1995             if not vk_func.needs_thunk():
1996                 continue
1998             # Exports symbols for Core functions.
1999             if not vk_func.is_core_func() and not vk_func.needs_private_thunk():
2000                 f.write("static ")
2002             if vk_func.needs_private_thunk():
2003                 f.write(vk_func.thunk(prefix="thunk_"))
2004             else:
2005                 f.write(vk_func.thunk(prefix=prefix, call_conv="WINAPI"))
2007         f.write("static const struct vulkan_func vk_device_dispatch_table[] =\n{\n")
2008         for vk_func in self.registry.device_funcs:
2009             if not vk_func.is_required():
2010                 continue
2012             f.write("    {{\"{0}\", &{1}{0}}},\n".format(vk_func.name, prefix))
2013         f.write("};\n\n")
2015         f.write("static const struct vulkan_func vk_instance_dispatch_table[] =\n{\n")
2016         for vk_func in self.registry.instance_funcs:
2017             if not vk_func.is_required():
2018                 continue
2020             f.write("    {{\"{0}\", &{1}{0}}},\n".format(vk_func.name, prefix))
2021         f.write("};\n\n")
2023         f.write("void *wine_vk_get_device_proc_addr(const char *name)\n")
2024         f.write("{\n")
2025         f.write("    unsigned int i;\n")
2026         f.write("    for (i = 0; i < ARRAY_SIZE(vk_device_dispatch_table); i++)\n")
2027         f.write("    {\n")
2028         f.write("        if (strcmp(vk_device_dispatch_table[i].name, name) == 0)\n")
2029         f.write("        {\n")
2030         f.write("            TRACE(\"Found name=%s in device table\\n\", debugstr_a(name));\n")
2031         f.write("            return vk_device_dispatch_table[i].func;\n")
2032         f.write("        }\n")
2033         f.write("    }\n")
2034         f.write("    return NULL;\n")
2035         f.write("}\n\n")
2037         f.write("void *wine_vk_get_instance_proc_addr(const char *name)\n")
2038         f.write("{\n")
2039         f.write("    unsigned int i;\n")
2040         f.write("    for (i = 0; i < ARRAY_SIZE(vk_instance_dispatch_table); i++)\n")
2041         f.write("    {\n")
2042         f.write("        if (strcmp(vk_instance_dispatch_table[i].name, name) == 0)\n")
2043         f.write("        {\n")
2044         f.write("            TRACE(\"Found name=%s in instance table\\n\", debugstr_a(name));\n")
2045         f.write("            return vk_instance_dispatch_table[i].func;\n")
2046         f.write("        }\n")
2047         f.write("    }\n")
2048         f.write("    return NULL;\n")
2049         f.write("}\n\n")
2051         # Create array of device extensions.
2052         f.write("static const char * const vk_device_extensions[] =\n{\n")
2053         for ext in self.registry.extensions:
2054             if ext["type"] != "device":
2055                 continue
2057             f.write("    \"{0}\",\n".format(ext["name"]))
2058         f.write("};\n\n")
2060         # Create array of instance extensions.
2061         f.write("static const char * const vk_instance_extensions[] =\n{\n")
2062         for ext in self.registry.extensions:
2063             if ext["type"] != "instance":
2064                 continue
2066             f.write("    \"{0}\",\n".format(ext["name"]))
2067         f.write("};\n\n")
2069         f.write("BOOL wine_vk_device_extension_supported(const char *name)\n")
2070         f.write("{\n")
2071         f.write("    unsigned int i;\n")
2072         f.write("    for (i = 0; i < ARRAY_SIZE(vk_device_extensions); i++)\n")
2073         f.write("    {\n")
2074         f.write("        if (strcmp(vk_device_extensions[i], name) == 0)\n")
2075         f.write("            return TRUE;\n")
2076         f.write("    }\n")
2077         f.write("    return FALSE;\n")
2078         f.write("}\n\n")
2080         f.write("BOOL wine_vk_instance_extension_supported(const char *name)\n")
2081         f.write("{\n")
2082         f.write("    unsigned int i;\n")
2083         f.write("    for (i = 0; i < ARRAY_SIZE(vk_instance_extensions); i++)\n")
2084         f.write("    {\n")
2085         f.write("        if (strcmp(vk_instance_extensions[i], name) == 0)\n")
2086         f.write("            return TRUE;\n")
2087         f.write("    }\n")
2088         f.write("    return FALSE;\n")
2089         f.write("}\n")
2091     def generate_thunks_h(self, f, prefix):
2092         self._generate_copyright(f)
2094         f.write("#ifndef __WINE_VULKAN_THUNKS_H\n")
2095         f.write("#define __WINE_VULKAN_THUNKS_H\n\n")
2097         f.write("#define WINE_VK_VERSION VK_API_VERSION_{0}_{1}\n\n".format(WINE_VK_VERSION[0], WINE_VK_VERSION[1]))
2099         # Generate prototypes for device and instance functions requiring a custom implementation.
2100         f.write("/* Functions for which we have custom implementations outside of the thunks. */\n")
2101         for vk_func in self.registry.funcs.values():
2102             if not vk_func.is_required() or vk_func.is_global_func():
2103                 continue
2104             if vk_func.needs_thunk() and not vk_func.needs_private_thunk():
2105                 continue
2107             if vk_func.is_core_func():
2108                 f.write("{0};\n".format(vk_func.prototype("WINAPI", prefix="wine_")))
2109             else:
2110                 f.write("{0};\n".format(vk_func.prototype("WINAPI", prefix="wine_", postfix="DECLSPEC_HIDDEN")))
2111         f.write("\n")
2113         f.write("/* Private thunks */\n")
2114         for vk_func in self.registry.funcs.values():
2115             if vk_func.needs_private_thunk():
2116                 f.write("{0};\n".format(vk_func.prototype(prefix="thunk_", postfix="DECLSPEC_HIDDEN")))
2117         f.write("\n")
2119         for struct in self.host_structs:
2120             f.write(struct.definition(align=False, conv=True, postfix="_host"))
2121         f.write("\n")
2123         f.write("/* For use by vkDevice and children */\n")
2124         f.write("struct vulkan_device_funcs\n{\n")
2125         for vk_func in self.registry.device_funcs:
2126             if not vk_func.is_required():
2127                 continue
2129             if not vk_func.needs_dispatch():
2130                 LOGGER.debug("skipping {0} in vulkan_device_funcs".format(vk_func.name))
2131                 continue
2133             if vk_func.needs_conversion():
2134                 f.write("#if defined(USE_STRUCT_CONVERSION)\n")
2135                 f.write("    {0};\n".format(vk_func.pfn(conv=True)))
2136                 f.write("#else\n")
2137                 f.write("    {0};\n".format(vk_func.pfn(conv=False)))
2138                 f.write("#endif\n")
2139             else:
2140                 f.write("    {0};\n".format(vk_func.pfn(conv=False)))
2141         f.write("};\n\n")
2143         f.write("/* For use by vkInstance and children */\n")
2144         f.write("struct vulkan_instance_funcs\n{\n")
2145         for vk_func in self.registry.instance_funcs:
2146             if not vk_func.is_required():
2147                 continue
2149             if not vk_func.needs_dispatch():
2150                 LOGGER.debug("skipping {0} in vulkan_instance_funcs".format(vk_func.name))
2151                 continue
2153             if vk_func.needs_conversion():
2154                 f.write("#if defined(USE_STRUCT_CONVERSION)\n")
2155                 f.write("    {0};\n".format(vk_func.pfn(conv=True)))
2156                 f.write("#else\n")
2157                 f.write("    {0};\n".format(vk_func.pfn(conv=False)))
2158                 f.write("#endif\n")
2159             else:
2160                 f.write("    {0};\n".format(vk_func.pfn(conv=False)))
2161         f.write("};\n\n")
2163         f.write("#define ALL_VK_DEVICE_FUNCS() \\\n")
2164         first = True
2165         for vk_func in self.registry.device_funcs:
2166             if not vk_func.is_required():
2167                 continue
2169             if not vk_func.needs_dispatch():
2170                 LOGGER.debug("skipping {0} in ALL_VK_DEVICE_FUNCS".format(vk_func.name))
2171                 continue
2173             if first:
2174                 f.write("    USE_VK_FUNC({0})".format(vk_func.name))
2175                 first = False
2176             else:
2177                 f.write(" \\\n    USE_VK_FUNC({0})".format(vk_func.name))
2178         f.write("\n\n")
2180         f.write("#define ALL_VK_INSTANCE_FUNCS() \\\n")
2181         first = True
2182         for vk_func in self.registry.instance_funcs:
2183             if not vk_func.is_required():
2184                 continue
2186             if not vk_func.needs_dispatch():
2187                 LOGGER.debug("skipping {0} in ALL_VK_INSTANCE_FUNCS".format(vk_func.name))
2188                 continue
2190             if first:
2191                 f.write("    USE_VK_FUNC({0})".format(vk_func.name))
2192                 first = False
2193             else:
2194                 f.write(" \\\n    USE_VK_FUNC({0})".format(vk_func.name))
2195         f.write("\n\n")
2197         f.write("#endif /* __WINE_VULKAN_THUNKS_H */\n")
2199     def generate_vulkan_h(self, f):
2200         self._generate_copyright(f)
2201         f.write("#ifndef __WINE_VULKAN_H\n")
2202         f.write("#define __WINE_VULKAN_H\n\n")
2204         f.write("#include <windef.h>\n")
2205         f.write("#include <stdint.h>\n\n")
2207         f.write("/* Define WINE_VK_HOST to get 'host' headers. */\n")
2208         f.write("#ifdef WINE_VK_HOST\n")
2209         f.write("#define VKAPI_CALL\n")
2210         f.write('#define WINE_VK_ALIGN(x)\n')
2211         f.write("#endif\n\n")
2213         f.write("#ifndef VKAPI_CALL\n")
2214         f.write("#define VKAPI_CALL __stdcall\n")
2215         f.write("#endif\n\n")
2217         f.write("#ifndef VKAPI_PTR\n")
2218         f.write("#define VKAPI_PTR VKAPI_CALL\n")
2219         f.write("#endif\n\n")
2221         f.write("#ifndef WINE_VK_ALIGN\n")
2222         f.write("#define WINE_VK_ALIGN DECLSPEC_ALIGN\n")
2223         f.write("#endif\n\n")
2225         # The overall strategy is to define independent constants and datatypes,
2226         # prior to complex structures and function calls to avoid forward declarations.
2227         for const in self.registry.consts:
2228             # For now just generate things we may not need. The amount of parsing needed
2229             # to get some of the info is tricky as you need to figure out which structure
2230             # references a certain constant.
2231             f.write(const.definition())
2232         f.write("\n")
2234         for define in self.registry.defines:
2235             f.write(define.definition())
2237         for handle in self.registry.handles:
2238             # For backward compatibility also create definitions for aliases.
2239             # These types normally don't get pulled in as we use the new types
2240             # even in legacy functions if they are aliases.
2241             if handle.is_required() or handle.is_alias():
2242                  f.write(handle.definition())
2243         f.write("\n")
2245         for base_type in self.registry.base_types:
2246             f.write(base_type.definition())
2247         f.write("\n")
2249         for bitmask in self.registry.bitmasks:
2250             f.write(bitmask.definition())
2251         f.write("\n")
2253         # Define enums, this includes values for some of the bitmask types as well.
2254         for enum in self.registry.enums.values():
2255             if enum.required:
2256                 f.write(enum.definition())
2258         for fp in self.registry.funcpointers:
2259             if fp.required:
2260                 f.write(fp.definition())
2261         f.write("\n")
2263         # This generates both structures and unions. Since structures
2264         # may depend on other structures/unions, we need a list of
2265         # decoupled structs.
2266         # Note: unions are stored in structs for dependency reasons,
2267         # see comment in parsing section.
2268         structs = VkStruct.decouple_structs(self.registry.structs)
2269         for struct in structs:
2270             LOGGER.debug("Generating struct: {0}".format(struct.name))
2271             f.write(struct.definition(align=True))
2273         for func in self.registry.funcs.values():
2274             if not func.is_required():
2275                 LOGGER.debug("Skipping PFN definition for: {0}".format(func.name))
2276                 continue
2278             f.write("typedef {0};\n".format(func.pfn(prefix="PFN", call_conv="VKAPI_PTR")))
2279         f.write("\n")
2281         f.write("#ifndef VK_NO_PROTOTYPES\n")
2282         for func in self.registry.funcs.values():
2283             if not func.is_required():
2284                 LOGGER.debug("Skipping API definition for: {0}".format(func.name))
2285                 continue
2287             LOGGER.debug("Generating API definition for: {0}".format(func.name))
2288             f.write("{0};\n".format(func.prototype(call_conv="VKAPI_CALL")))
2289         f.write("#endif /* VK_NO_PROTOTYPES */\n\n")
2291         f.write("#endif /* __WINE_VULKAN_H */\n")
2293     def generate_vulkan_driver_h(self, f):
2294         self._generate_copyright(f)
2295         f.write("#ifndef __WINE_VULKAN_DRIVER_H\n")
2296         f.write("#define __WINE_VULKAN_DRIVER_H\n\n")
2298         f.write("/* Wine internal vulkan driver version, needs to be bumped upon vulkan_funcs changes. */\n")
2299         f.write("#define WINE_VULKAN_DRIVER_VERSION {0}\n\n".format(DRIVER_VERSION))
2301         f.write("struct vulkan_funcs\n{\n")
2302         f.write("    /* Vulkan global functions. These are the only calls at this point a graphics driver\n")
2303         f.write("     * needs to provide. Other function calls will be provided indirectly by dispatch\n")
2304         f.write("     * tables part of dispatchable Vulkan objects such as VkInstance or vkDevice.\n")
2305         f.write("     */\n")
2307         for vk_func in self.registry.funcs.values():
2308             if not vk_func.is_driver_func():
2309                 continue
2311             pfn = vk_func.pfn()
2312             # Avoid PFN_vkVoidFunction in driver interface as Vulkan likes to put calling convention
2313             # stuff in there. For simplicity substitute with "void *".
2314             pfn = pfn.replace("PFN_vkVoidFunction", "void *")
2315             f.write("    {0};\n".format(pfn))
2316         f.write("};\n\n")
2318         f.write("extern const struct vulkan_funcs * CDECL __wine_get_vulkan_driver(HDC hdc, UINT version);\n\n")
2320         f.write("static inline void *get_vulkan_driver_device_proc_addr(\n")
2321         f.write("        const struct vulkan_funcs *vulkan_funcs, const char *name)\n{\n")
2322         f.write("    if (!name || name[0] != 'v' || name[1] != 'k') return NULL;\n\n")
2323         f.write("    name += 2;\n\n")
2324         for vk_func in self.registry.funcs.values():
2325             if vk_func.is_driver_func() and vk_func.is_device_func():
2326                 f.write('    if (!strcmp(name, "{0}"))\n'.format(vk_func.name[2:]))
2327                 f.write('        return vulkan_funcs->p_{0};\n'.format(vk_func.name))
2328         f.write("\n")
2329         f.write("    return NULL;\n}\n\n")
2331         f.write("static inline void *get_vulkan_driver_instance_proc_addr(\n")
2332         f.write("        const struct vulkan_funcs *vulkan_funcs, VkInstance instance, const char *name)\n{\n")
2333         f.write("    if (!name || name[0] != 'v' || name[1] != 'k') return NULL;\n\n")
2334         f.write("    name += 2;\n\n")
2335         for vk_func in self.registry.funcs.values():
2336             if vk_func.is_driver_func() and vk_func.is_global_func() and vk_func.name != "vkGetInstanceProcAddr":
2337                 f.write('    if (!strcmp(name, "{0}"))\n'.format(vk_func.name[2:]))
2338                 f.write('        return vulkan_funcs->p_{0};\n'.format(vk_func.name))
2339         f.write("\n")
2340         f.write("    if (!instance) return NULL;\n\n")
2341         for vk_func in self.registry.funcs.values():
2342             if vk_func.is_driver_func() and vk_func.is_instance_func():
2343                 f.write('    if (!strcmp(name, "{0}"))\n'.format(vk_func.name[2:]))
2344                 f.write('        return vulkan_funcs->p_{0};\n'.format(vk_func.name))
2345         f.write("\n")
2346         f.write("    name -= 2;\n\n")
2347         f.write("    return get_vulkan_driver_device_proc_addr(vulkan_funcs, name);\n}\n\n")
2349         f.write("#endif /* __WINE_VULKAN_DRIVER_H */\n")
2351     def generate_vulkan_spec(self, f):
2352         self._generate_copyright(f, spec_file=True)
2353         f.write("@ stdcall -private vk_icdGetInstanceProcAddr(ptr str) wine_vk_icdGetInstanceProcAddr\n")
2354         f.write("@ stdcall -private vk_icdNegotiateLoaderICDInterfaceVersion(ptr) wine_vk_icdNegotiateLoaderICDInterfaceVersion\n")
2355         f.write("@ cdecl -norelay native_vkGetInstanceProcAddrWINE(ptr str)\n")
2357         # Export symbols for all Vulkan Core functions.
2358         for func in self.registry.funcs.values():
2359             if not func.is_core_func():
2360                 continue
2362             # We support all Core functions except for VK_KHR_display* APIs.
2363             # Create stubs for unsupported Core functions.
2364             if func.is_required():
2365                 f.write(func.spec(prefix="wine_"))
2366             else:
2367                 f.write("@ stub {0}\n".format(func.name))
2369     def generate_vulkan_loader_spec(self, f):
2370         self._generate_copyright(f, spec_file=True)
2372         # Export symbols for all Vulkan Core functions.
2373         for func in self.registry.funcs.values():
2374             if not func.is_core_func():
2375                 continue
2377             # We support all Core functions except for VK_KHR_display* APIs.
2378             # Create stubs for unsupported Core functions.
2379             if func.is_required():
2380                 f.write(func.spec(symbol="winevulkan.wine_" + func.name))
2381             else:
2382                 f.write("@ stub {0}\n".format(func.name))
2385 class VkRegistry(object):
2386     def __init__(self, reg_filename):
2387         # Used for storage of type information.
2388         self.base_types = None
2389         self.bitmasks = None
2390         self.consts = None
2391         self.defines = None
2392         self.enums = None
2393         self.funcpointers = None
2394         self.handles = None
2395         self.structs = None
2397         # We aggregate all types in here for cross-referencing.
2398         self.funcs = {}
2399         self.types = {}
2401         self.version_regex = re.compile(
2402             r'^'
2403             r'VK_VERSION_'
2404             r'(?P<major>[0-9])'
2405             r'_'
2406             r'(?P<minor>[0-9])'
2407             r'$'
2408         )
2410         # Overall strategy for parsing the registry is to first
2411         # parse all type / function definitions. Then parse
2412         # features and extensions to decide which types / functions
2413         # to actually 'pull in' for code generation. For each type or
2414         # function call we want we set a member 'required' to True.
2415         tree = ET.parse(reg_filename)
2416         root = tree.getroot()
2417         self._parse_enums(root)
2418         self._parse_types(root)
2419         self._parse_commands(root)
2421         # Pull in any required types and functions.
2422         self._parse_features(root)
2423         self._parse_extensions(root)
2425         self.copyright = root.find('./comment').text
2427     def _is_feature_supported(self, feature):
2428         version = self.version_regex.match(feature)
2429         if not version:
2430             return True
2432         version = tuple(map(int, version.group('major', 'minor')))
2433         return version <= WINE_VK_VERSION
2435     def _is_extension_supported(self, extension):
2436         # We disable some extensions as either we haven't implemented
2437         # support yet or because they are for platforms other than win32.
2438         return extension not in BLACKLISTED_EXTENSIONS
2440     def _mark_command_required(self, command):
2441         """ Helper function to mark a certain command and the datatypes it needs as required."""
2442         def mark_bitmask_dependencies(bitmask, types):
2443             if bitmask.requires is not None:
2444                 types[bitmask.requires]["data"].required = True
2446         def mark_funcpointer_dependencies(fp, types):
2447             for m in fp.members:
2448                 type_info = types[m.type]
2450                 # Complex types have a matching definition e.g. VkStruct.
2451                 # Not needed for base types such as uint32_t.
2452                 if "data" in type_info:
2453                     types[m.type]["data"].required = True
2455         def mark_struct_dependencies(struct, types):
2456              for m in struct:
2457                 type_info = types[m.type]
2459                 # Complex types have a matching definition e.g. VkStruct.
2460                 # Not needed for base types such as uint32_t.
2461                 if "data" in type_info:
2462                     types[m.type]["data"].required = True
2464                 if type_info["category"] == "struct":
2465                     # Yay, recurse
2466                     mark_struct_dependencies(type_info["data"], types)
2467                 elif type_info["category"] == "funcpointer":
2468                     mark_funcpointer_dependencies(type_info["data"], types)
2469                 elif type_info["category"] == "bitmask":
2470                     mark_bitmask_dependencies(type_info["data"], types)
2472         func = self.funcs[command]
2473         func.required = True
2475         # Pull in return type
2476         if func.type != "void":
2477             self.types[func.type]["data"].required = True
2479         # Analyze parameter dependencies and pull in any type needed.
2480         for p in func.params:
2481             type_info = self.types[p.type]
2483             # Check if we are dealing with a complex type e.g. VkEnum, VkStruct and others.
2484             if "data" not in type_info:
2485                 continue
2487             # Mark the complex type as required.
2488             type_info["data"].required = True
2489             if type_info["category"] == "struct":
2490                 struct = type_info["data"]
2491                 mark_struct_dependencies(struct, self.types)
2493         if func.is_alias():
2494             func.alias.required = True
2496     def _parse_commands(self, root):
2497         """ Parse command section containing the Vulkan function calls. """
2498         funcs = {}
2499         commands = root.findall("./commands/")
2501         # As of Vulkan 1.1, various extensions got promoted to Core.
2502         # The old commands (e.g. KHR) are available for backwards compatibility
2503         # and are marked in vk.xml as 'alias' to the non-extension type.
2504         # The registry likes to avoid data duplication, so parameters and other
2505         # metadata need to be looked up from the Core command.
2506         # We parse the alias commands in a second pass.
2507         alias_commands = []
2508         for command in commands:
2509             alias_name = command.attrib.get("alias")
2510             if alias_name:
2511                 alias_commands.append(command)
2512                 continue
2514             func = VkFunction.from_xml(command, self.types)
2515             funcs[func.name] = func
2517         for command in alias_commands:
2518             alias_name = command.attrib.get("alias")
2519             alias = funcs[alias_name]
2520             func = VkFunction.from_alias(command, alias)
2521             funcs[func.name] = func
2523         # To make life easy for the code generation, separate all function
2524         # calls out in the 3 types of Vulkan functions: device, global and instance.
2525         device_funcs = []
2526         global_funcs = []
2527         instance_funcs = []
2528         for func in funcs.values():
2529             if func.is_device_func():
2530                 device_funcs.append(func)
2531             elif func.is_global_func():
2532                 global_funcs.append(func)
2533             else:
2534                 instance_funcs.append(func)
2536         # Sort function lists by name and store them.
2537         self.device_funcs = sorted(device_funcs, key=lambda func: func.name)
2538         self.global_funcs = sorted(global_funcs, key=lambda func: func.name)
2539         self.instance_funcs = sorted(instance_funcs, key=lambda func: func.name)
2541         # The funcs dictionary is used as a convenient way to lookup function
2542         # calls when needed e.g. to adjust member variables.
2543         self.funcs = OrderedDict(sorted(funcs.items()))
2545     def _parse_enums(self, root):
2546         """ Parse enums section or better described as constants section. """
2547         enums = {}
2548         self.consts = []
2549         for enum in root.findall("./enums"):
2550             name = enum.attrib.get("name")
2551             _type = enum.attrib.get("type")
2553             if _type in ("enum", "bitmask"):
2554                 enums[name] = VkEnum.from_xml(enum)
2555             else:
2556                 # If no type is set, we are dealing with API constants.
2557                 for value in enum.findall("enum"):
2558                     # If enum is an alias, set the value to the alias name.
2559                     # E.g. VK_LUID_SIZE_KHR is an alias to VK_LUID_SIZE.
2560                     alias = value.attrib.get("alias")
2561                     if alias:
2562                         self.consts.append(VkConstant(value.attrib.get("name"), alias))
2563                     else:
2564                         self.consts.append(VkConstant(value.attrib.get("name"), value.attrib.get("value")))
2566         self.enums = OrderedDict(sorted(enums.items()))
2568     def _process_require_enum(self, enum_elem, ext=None):
2569         if "extends" in enum_elem.keys():
2570             enum = self.types[enum_elem.attrib["extends"]]["data"]
2572             if "bitpos" in enum_elem.keys():
2573                 # We need to add an extra value to an existing enum type.
2574                 # E.g. VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG to VkFormatFeatureFlagBits.
2575                 enum.add(VkEnumValue(enum_elem.attrib["name"], 1 << int(enum_elem.attrib["bitpos"]), hex=True))
2577             elif "offset" in enum_elem.keys():
2578                 # Extensions promoted to Core, have the extension number as part
2579                 # of the enum value. Else retrieve from the extension tag.
2580                 if enum_elem.attrib.get("extnumber"):
2581                     ext_number = int(enum_elem.attrib.get("extnumber"))
2582                 else:
2583                     ext_number = int(ext.attrib["number"])
2584                 offset = int(enum_elem.attrib["offset"])
2585                 value = EXT_BASE + (ext_number - 1) * EXT_BLOCK_SIZE + offset
2587                 # Deal with negative values.
2588                 direction = enum_elem.attrib.get("dir")
2589                 if direction is not None:
2590                     value = -value
2592                 enum.add(VkEnumValue(enum_elem.attrib["name"], value))
2594             elif "value" in enum_elem.keys():
2595                 enum.add(VkEnumValue(enum_elem.attrib["name"], int(enum_elem.attrib["value"])))
2597         elif "value" in enum_elem.keys():
2598             self.consts.append(VkConstant(enum_elem.attrib["name"], enum_elem.attrib["value"]))
2600     def _parse_extensions(self, root):
2601         """ Parse extensions section and pull in any types and commands for this extensioin. """
2602         extensions = []
2603         exts = root.findall("./extensions/extension")
2604         for ext in exts:
2605             ext_name = ext.attrib["name"]
2607             # Set extension name on any functions calls part of this extension as we
2608             # were not aware of the name during initial parsing.
2609             commands = ext.findall("require/command")
2610             for command in commands:
2611                 cmd_name = command.attrib["name"]
2612                 self.funcs[cmd_name].extensions.append(ext_name)
2614             # Some extensions are not ready or have numbers reserved as a place holder.
2615             if ext.attrib["supported"] == "disabled":
2616                 LOGGER.debug("Skipping disabled extension: {0}".format(ext_name))
2617                 continue
2619             # Disable highly experimental extensions as the APIs are unstable and can
2620             # change between minor Vulkan revisions until API is final and becomes KHR
2621             # or NV.
2622             if "KHX" in ext_name or "NVX" in ext_name:
2623                 LOGGER.debug("Skipping experimental extension: {0}".format(ext_name))
2624                 continue
2626             platform = ext.attrib.get("platform")
2627             if platform and platform != "win32":
2628                 LOGGER.debug("Skipping extensions {0} for platform {1}".format(ext_name, platform))
2629                 continue;
2631             if not self._is_extension_supported(ext_name):
2632                 LOGGER.debug("Skipping blacklisted extension: {0}".format(ext_name))
2633                 continue
2634             elif "requires" in ext.attrib:
2635                 # Check if this extension builds on top of another blacklisted
2636                 # extension.
2637                 requires = ext.attrib["requires"].split(",")
2638                 if len(set(requires).intersection(BLACKLISTED_EXTENSIONS)) > 0:
2639                     continue
2641             LOGGER.debug("Loading extension: {0}".format(ext_name))
2643             # Extensions can define one or more require sections each requiring
2644             # different features (e.g. Vulkan 1.1). Parse each require section
2645             # separately, so we can skip sections we don't want.
2646             for require in ext.findall("require"):
2647                 # Extensions can add enum values to Core / extension enums, so add these.
2648                 for enum_elem in require.findall("enum"):
2649                     self._process_require_enum(enum_elem, ext)
2651                 for t in require.findall("type"):
2652                     type_info = self.types[t.attrib["name"]]["data"]
2653                     if type_info.is_alias():
2654                         type_info = type_info.alias
2655                     type_info.required = True
2657                 feature = require.attrib.get("feature")
2658                 if feature and not self._is_feature_supported(feature):
2659                     continue
2661                 required_extension = require.attrib.get("extension")
2662                 if required_extension and not self._is_extension_supported(required_extension):
2663                     continue
2665                 # Pull in any commands we need. We infer types to pull in from the command
2666                 # as well.
2667                 for command in require.findall("command"):
2668                     cmd_name = command.attrib["name"]
2669                     self._mark_command_required(cmd_name)
2671             # Store a list with extensions.
2672             ext_info = {"name" : ext_name, "type" : ext.attrib["type"]}
2673             extensions.append(ext_info)
2675         # Sort in alphabetical order.
2676         self.extensions = sorted(extensions, key=lambda ext: ext["name"])
2678     def _parse_features(self, root):
2679         """ Parse the feature section, which describes Core commands and types needed. """
2681         for feature in root.findall("./feature"):
2682             feature_name = feature.attrib["name"]
2683             for require in feature.findall("require"):
2684                 LOGGER.info("Including features for {0}".format(require.attrib.get("comment")))
2685                 for tag in require:
2686                     if tag.tag == "comment":
2687                         continue
2688                     elif tag.tag == "command":
2689                         if not self._is_feature_supported(feature_name):
2690                             continue
2691                         name = tag.attrib["name"]
2692                         self._mark_command_required(name)
2693                     elif tag.tag == "enum":
2694                         self._process_require_enum(tag)
2695                     elif tag.tag == "type":
2696                         name = tag.attrib["name"]
2698                         # Skip pull in for vk_platform.h for now.
2699                         if name == "vk_platform":
2700                             continue
2702                         type_info = self.types[name]
2703                         type_info["data"].required = True
2705     def _parse_types(self, root):
2706         """ Parse types section, which contains all data types e.g. structs, typedefs etcetera. """
2707         types = root.findall("./types/type")
2709         base_types = []
2710         bitmasks = []
2711         defines = []
2712         funcpointers = []
2713         handles = []
2714         structs = []
2716         alias_types = []
2717         for t in types:
2718             type_info = {}
2719             type_info["category"] = t.attrib.get("category", None)
2721             # We parse aliases in a second pass when we know more.
2722             alias = t.attrib.get("alias")
2723             if alias:
2724                 LOGGER.debug("Alias found: {0}".format(alias))
2725                 alias_types.append(t)
2726                 continue
2728             if type_info["category"] in ["include"]:
2729                 continue
2731             if type_info["category"] == "basetype":
2732                 name = t.find("name").text
2733                 _type = t.find("type").text
2734                 basetype = VkBaseType(name, _type)
2735                 base_types.append(basetype)
2736                 type_info["data"] = basetype
2738             if type_info["category"] == "bitmask":
2739                 name = t.find("name").text
2740                 _type = t.find("type").text
2742                 # Most bitmasks have a requires attribute used to pull in
2743                 # required '*FlagBits" enum.
2744                 requires = t.attrib.get("requires")
2745                 bitmask = VkBaseType(name, _type, requires=requires)
2746                 bitmasks.append(bitmask)
2747                 type_info["data"] = bitmask
2749             if type_info["category"] == "define":
2750                 define = VkDefine.from_xml(t)
2751                 defines.append(define)
2752                 type_info["data"] = define
2754             if type_info["category"] == "enum":
2755                 name = t.attrib.get("name")
2756                 # The type section only contains enum names, not the actual definition.
2757                 # Since we already parsed the enum before, just link it in.
2758                 try:
2759                     type_info["data"] = self.enums[name]
2760                 except KeyError as e:
2761                     # Not all enums seem to be defined yet, typically that's for
2762                     # ones ending in 'FlagBits' where future extensions may add
2763                     # definitions.
2764                     type_info["data"] = None
2766             if type_info["category"] == "funcpointer":
2767                 funcpointer = VkFunctionPointer.from_xml(t)
2768                 funcpointers.append(funcpointer)
2769                 type_info["data"] = funcpointer
2771             if type_info["category"] == "handle":
2772                 handle = VkHandle.from_xml(t)
2773                 handles.append(handle)
2774                 type_info["data"] = handle
2776             if type_info["category"] in ["struct", "union"]:
2777                 # We store unions among structs as some structs depend
2778                 # on unions. The types are very similar in parsing and
2779                 # generation anyway. The official Vulkan scripts use
2780                 # a similar kind of hack.
2781                 struct = VkStruct.from_xml(t)
2782                 structs.append(struct)
2783                 type_info["data"] = struct
2785             # Name is in general within a name tag else it is an optional
2786             # attribute on the type tag.
2787             name_elem = t.find("name")
2788             if name_elem is not None:
2789                 type_info["name"] = name_elem.text
2790             else:
2791                 type_info["name"] = t.attrib.get("name", None)
2793             # Store all type data in a shared dictionary, so we can easily
2794             # look up information for a given type. There are no duplicate
2795             # names.
2796             self.types[type_info["name"]] = type_info
2798         # Second pass for alias types, so we can retrieve all data from
2799         # the aliased object.
2800         for t in alias_types:
2801             type_info = {}
2802             type_info["category"] = t.attrib.get("category")
2803             type_info["name"] = t.attrib.get("name")
2805             alias = t.attrib.get("alias")
2807             if type_info["category"] == "bitmask":
2808                 bitmask = VkBaseType(type_info["name"], alias, alias=self.types[alias]["data"])
2809                 bitmasks.append(bitmask)
2810                 type_info["data"] = bitmask
2812             if type_info["category"] == "enum":
2813                 enum = VkEnum.from_alias(t, self.types[alias]["data"])
2814                 type_info["data"] = enum
2815                 self.enums[enum.name] = enum
2817             if type_info["category"] == "handle":
2818                 handle = VkHandle.from_alias(t, self.types[alias]["data"])
2819                 handles.append(handle)
2820                 type_info["data"] = handle
2822             if type_info["category"] == "struct":
2823                 struct = VkStruct.from_alias(t, self.types[alias]["data"])
2824                 structs.append(struct)
2825                 type_info["data"] = struct
2827             self.types[type_info["name"]] = type_info
2829         # We need detailed type information during code generation
2830         # on structs for alignment reasons. Unfortunately structs
2831         # are parsed among other types, so there is no guarantee
2832         # that any types needed have been parsed already, so set
2833         # the data now.
2834         for struct in structs:
2835             struct.set_type_info(self.types)
2837             for structextend in struct.structextends:
2838                 s = self.types[structextend]["data"]
2839                 s.struct_extensions.append(struct)
2841         # Guarantee everything is sorted, so code generation doesn't have
2842         # to deal with this.
2843         self.base_types = sorted(base_types, key=lambda base_type: base_type.name)
2844         self.bitmasks = sorted(bitmasks, key=lambda bitmask: bitmask.name)
2845         self.defines = defines
2846         self.enums = OrderedDict(sorted(self.enums.items()))
2847         self.funcpointers = sorted(funcpointers, key=lambda fp: fp.name)
2848         self.handles = sorted(handles, key=lambda handle: handle.name)
2849         self.structs = sorted(structs, key=lambda struct: struct.name)
2851 def set_working_directory():
2852     path = os.path.abspath(__file__)
2853     path = os.path.dirname(path)
2854     os.chdir(path)
2856 def download_vk_xml(filename):
2857     url = "https://raw.github.com/KhronosGroup/Vulkan-Docs/v{0}/xml/vk.xml".format(VK_XML_VERSION)
2858     if not os.path.isfile(filename):
2859         urllib.request.urlretrieve(url, filename)
2861 def main():
2862     parser = argparse.ArgumentParser()
2863     parser.add_argument("-v", "--verbose", action="count", default=0, help="increase output verbosity")
2865     args = parser.parse_args()
2866     if args.verbose == 0:
2867         LOGGER.setLevel(logging.WARNING)
2868     elif args.verbose == 1:
2869         LOGGER.setLevel(logging.INFO)
2870     else: # > 1
2871         LOGGER.setLevel(logging.DEBUG)
2873     set_working_directory()
2875     vk_xml = "vk-{0}.xml".format(VK_XML_VERSION)
2876     download_vk_xml(vk_xml)
2877     registry = VkRegistry(vk_xml)
2878     generator = VkGenerator(registry)
2880     with open(WINE_VULKAN_H, "w") as f:
2881         generator.generate_vulkan_h(f)
2883     with open(WINE_VULKAN_DRIVER_H, "w") as f:
2884         generator.generate_vulkan_driver_h(f)
2886     with open(WINE_VULKAN_THUNKS_H, "w") as f:
2887         generator.generate_thunks_h(f, "wine_")
2889     with open(WINE_VULKAN_THUNKS_C, "w") as f:
2890         generator.generate_thunks_c(f, "wine_")
2892     with open(WINE_VULKAN_SPEC, "w") as f:
2893         generator.generate_vulkan_spec(f)
2895     with open(WINE_VULKAN_LOADER_SPEC, "w") as f:
2896         generator.generate_vulkan_loader_spec(f)
2898 if __name__ == "__main__":
2899     main()