kernel32/tests: Add a test to check some fields in fake dlls.
[wine.git] / dlls / winevulkan / make_vulkan
blob960417d4284d4f84783af697db0a942f4c83e1b8
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.94"
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 # In general instance extensions can't be automatically generated
87 # and need custom wrappers due to e.g. win32 / X11 specific code.
88 # List of supported instance extensions.
89 SUPPORTED_INSTANCE_EXTENSIONS = [
90     "VK_KHR_device_group_creation",
91     "VK_KHR_get_physical_device_properties2",
92     "VK_KHR_surface",
93     "VK_KHR_win32_surface",
96 BLACKLISTED_EXTENSIONS = [
97     "VK_AMD_memory_overallocation_behavior",
98     # Handling of VK_EXT_debug_report requires some consideration. The win32
99     # loader already provides it for us and it is somewhat usable. If we add
100     # plumbing down to the native layer, we will get each message twice as we
101     # use 2 loaders (win32+native), but we may get output from the driver.
102     # In any case callback conversion is required.
103     "VK_EXT_calibrated_timestamps",
104     "VK_EXT_debug_report",
105     "VK_EXT_display_control", # Requires VK_EXT_display_surface_counter
106     "VK_EXT_external_memory_dma_buf", # Linux specific
107     "VK_EXT_hdr_metadata", # Needs WSI work.
108     "VK_EXT_image_drm_format_modifier",
109     "VK_GOOGLE_display_timing",
110     "VK_KHR_display", # Needs WSI work.
111     "VK_KHR_external_fence",
112     "VK_KHR_external_fence_fd",
113     "VK_KHR_external_fence_win32",
114     "VK_KHR_external_memory",
115     "VK_KHR_external_semaphore",
116     # Relates to external_semaphore and needs type conversions in bitflags.
117     "VK_KHR_external_semaphore_capabilities",
118     "VK_KHR_shared_presentable_image", # Needs WSI work.
119     "VK_KHR_win32_keyed_mutex",
120     "VK_NV_external_memory_win32",
123 # The Vulkan loader provides entry-points for core functionality and important
124 # extensions. Based on vulkan-1.def this amounts to WSI extensions on 1.0.51.
125 CORE_EXTENSIONS = [
126     "VK_KHR_display",
127     "VK_KHR_display_swapchain",
128     "VK_KHR_surface",
129     "VK_KHR_swapchain",
130     "VK_KHR_win32_surface",
133 # Functions part of our winevulkan graphics driver interface.
134 # DRIVER_VERSION should be bumped on any change to driver interface
135 # in FUNCTION_OVERRIDES
136 DRIVER_VERSION = 7
138 # Table of functions for which we have a special implementation.
139 # These are regular device / instance functions for which we need
140 # to do more work compared to a regular thunk or because they are
141 # part of the driver interface.
142 # - dispatch set whether we need a function pointer in the device
143 #   / instance dispatch table.
144 # - driver sets whether the API is part of the driver interface.
145 # - thunk sets whether to create a thunk in vulkan_thunks.c.
146 FUNCTION_OVERRIDES = {
147     # Global functions
148     "vkCreateInstance" : {"dispatch" : False, "driver" : True, "thunk" : False},
149     "vkEnumerateInstanceExtensionProperties" : {"dispatch" : False, "driver" : True, "thunk" : False},
150     "vkEnumerateInstanceVersion": {"dispatch" : False, "driver" : False, "thunk" : False},
151     "vkGetInstanceProcAddr": {"dispatch" : False, "driver" : True, "thunk" : False},
153     # Instance functions
154     "vkCreateDevice" : {"dispatch" : True, "driver" : False, "thunk" : False},
155     "vkDestroyInstance" : {"dispatch" : False, "driver" : True, "thunk" : False },
156     "vkEnumerateDeviceExtensionProperties" : {"dispatch" : True, "driver" : False, "thunk" : False},
157     "vkEnumeratePhysicalDevices" : {"dispatch" : True, "driver" : False, "thunk" : False},
158     "vkEnumeratePhysicalDeviceGroups" : {"dispatch" : True, "driver" : False, "thunk" : False},
160     # Device functions
161     "vkAllocateCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : False},
162     "vkCmdExecuteCommands" : {"dispatch" : True, "driver" : False, "thunk" : False},
163     "vkCreateCommandPool" : {"dispatch": True, "driver" : False, "thunk" : False},
164     "vkDestroyCommandPool" : {"dispatch": True, "driver" : False, "thunk" : False},
165     "vkDestroyDevice" : {"dispatch" : True, "driver" : False, "thunk" : False},
166     "vkFreeCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : False},
167     "vkGetDeviceProcAddr" : {"dispatch" : False, "driver" : True, "thunk" : False},
168     "vkGetDeviceQueue" : {"dispatch": True, "driver" : False, "thunk" : False},
169     "vkGetDeviceQueue2" : {"dispatch": True, "driver" : False, "thunk" : False},
170     "vkQueueSubmit" : {"dispatch": True, "driver" : False, "thunk" : False},
172     # VK_KHR_surface
173     "vkDestroySurfaceKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
174     "vkGetPhysicalDeviceSurfaceSupportKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
175     "vkGetPhysicalDeviceSurfaceCapabilitiesKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
176     "vkGetPhysicalDeviceSurfaceFormatsKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
177     "vkGetPhysicalDeviceSurfacePresentModesKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
179     # VK_KHR_win32_surface
180     "vkCreateWin32SurfaceKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
181     "vkGetPhysicalDeviceWin32PresentationSupportKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
183     # VK_KHR_swapchain
184     "vkCreateSwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
185     "vkDestroySwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
186     "vkGetSwapchainImagesKHR": {"dispatch" : True, "driver" : True, "thunk" : True},
187     "vkQueuePresentKHR": {"dispatch" : True, "driver" : True, "thunk" : True},
189     # VK_KHR_device_group_creation
190     "vkEnumeratePhysicalDeviceGroupsKHR" : {"dispatch" : True, "driver" : False, "thunk" : False},
192     # VK_KHR_device_group
193     "vkGetDeviceGroupSurfacePresentModesKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
194     "vkGetPhysicalDevicePresentRectanglesKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
198 class Direction(Enum):
199     """ Parameter direction: input, output, input_output. """
200     INPUT = 1
201     OUTPUT = 2
202     INPUT_OUTPUT = 3
205 class VkBaseType(object):
206     def __init__(self, name, _type, alias=None, requires=None):
207         """ Vulkan base type class.
209         VkBaseType is mostly used by Vulkan to define its own
210         base types like VkFlags through typedef out of e.g. uint32_t.
212         Args:
213             name (:obj:'str'): Name of the base type.
214             _type (:obj:'str'): Underlaying type
215             alias (bool): type is an alias or not.
216             requires (:obj:'str', optional): Other types required.
217                 Often bitmask values pull in a *FlagBits type.
218         """
219         self.name = name
220         self.type = _type
221         self.alias = alias
222         self.requires = requires
223         self.required = False
225     def definition(self):
226         # Definition is similar for alias or non-alias as type
227         # is already set to alias.
228         return "typedef {0} {1};\n".format(self.type, self.name)
230     def is_alias(self):
231         return bool(self.alias)
234 class VkConstant(object):
235     def __init__(self, name, value):
236         self.name = name
237         self.value = value
239     def definition(self):
240         text = "#define {0} {1}\n".format(self.name, self.value)
241         return text
244 class VkDefine(object):
245     def __init__(self, name, value):
246         self.name = name
247         self.value = value
249     @staticmethod
250     def from_xml(define):
251         name_elem = define.find("name")
253         if name_elem is None:
254             # <type category="define" name="some_name">some_value</type>
255             # At the time of writing there is only 1 define of this category
256             # 'VK_DEFINE_NON_DISPATCHABLE_HANDLE'.
257             name = define.attrib.get("name")
259             # We override behavior of VK_DEFINE_NON_DISPATCHABLE handle as the default
260             # definition various between 64-bit (uses pointers) and 32-bit (uses uint64_t).
261             # This complicates TRACEs in the thunks, so just use uint64_t.
262             if name == "VK_DEFINE_NON_DISPATCHABLE_HANDLE":
263                 value = "#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object;"
264             else:
265                 value = define.text
266             return VkDefine(name, value)
268         # With a name element the structure is like:
269         # <type category="define"><name>some_name</name>some_value</type>
270         name = name_elem.text
272         # Perform minimal parsing for Vulkan constants, which we don't need, but are referenced
273         # elsewhere in vk.xml.
274         # - VK_API_VERSION is a messy, deprecated constant and we don't want generate code for it.
275         # - AHardwareBuffer/ANativeWindow are forard declarations for Android types, which leaked
276         #   into the define region.
277         if name in ["VK_API_VERSION", "AHardwareBuffer", "ANativeWindow"]:
278             return VkDefine(name, None)
280         # The body of the define is basically unstructured C code. It is not meant for easy parsing.
281         # Some lines contain deprecated values or comments, which we try to filter out.
282         value = ""
283         for line in define.text.splitlines():
284             # Skip comments or deprecated values.
285             if "//" in line:
286                 continue
287             value += line
289         for child in define:
290             value += child.text
291             if child.tail is not None:
292                 # Split comments for VK_API_VERSION_1_0 / VK_API_VERSION_1_1
293                 if "//" in child.tail:
294                     value += child.tail.split("//")[0]
295                 else:
296                     value += child.tail
298         return VkDefine(name, value.rstrip(' '))
300     def definition(self):
301         if self.value is None:
302             return ""
304         # Nothing to do as the value was already put in the right form during parsing.
305         return "{0}\n".format(self.value)
308 class VkEnum(object):
309     def __init__(self, name, values, alias=None):
310         self.name = name
311         self.values = values
312         self.required = False
313         self.alias = alias
315     @staticmethod
316     def from_alias(enum, alias):
317         name = enum.attrib.get("name")
318         return VkEnum(name, alias.values, alias=alias)
320     @staticmethod
321     def from_xml(enum):
322         name = enum.attrib.get("name")
323         values = []
325         for v in enum.findall("enum"):
326             # Value is either a value or a bitpos, only one can exist.
327             value = v.attrib.get("value")
328             alias_name = v.attrib.get("alias")
329             if alias_name:
330                 alias = next(x for x in values if x.name == alias_name)
331                 values.append(VkEnumValue(v.attrib.get("name"), alias.value, alias.hex))
332             elif value:
333                 # Some values are in hex form. We want to preserve the hex representation
334                 # at least when we convert back to a string. Internally we want to use int.
335                 if "0x" in value:
336                     values.append(VkEnumValue(v.attrib.get("name"), int(value, 0), hex=True))
337                 else:
338                     values.append(VkEnumValue(v.attrib.get("name"), int(value, 0)))
339             else:
340                 # bitmask
341                 value = 1 << int(v.attrib.get("bitpos"))
342                 values.append(VkEnumValue(v.attrib.get("name"), value, hex=True))
344         # vulkan.h contains a *_MAX_ENUM value set to 32-bit at the time of writing,
345         # which is to prepare for extensions as they can add values and hence affect
346         # the size definition.
347         max_name = re.sub(r'([0-9a-z_])([A-Z0-9])',r'\1_\2', name).upper() + "_MAX_ENUM"
348         values.append(VkEnumValue(max_name, 0x7fffffff, hex=True))
350         return VkEnum(name, values)
352     def add(self, value):
353         """ Add a value to enum. """
355         # Extensions can add new enum values. When an extension is promoted to Core
356         # the registry defines the value twice once for old extension and once for
357         # new Core features. Ignore the duplicate entry.
358         for v in self.values:
359             if v.value == value.value:
360                 LOGGER.debug("Adding duplicate enum value {0} to {1}".format(v, self.name))
361                 return
362         self.values.append(value)
364     def definition(self):
365         text = "typedef enum {0}\n{{\n".format(self.name)
367         # Print values sorted, values can have been added in a random order.
368         values = sorted(self.values, key=lambda value: value.value)
369         for value in values:
370             text += "    {0},\n".format(value.definition())
371         text += "}} {0};\n\n".format(self.name)
372         return text
374     def is_alias(self):
375         return bool(self.alias)
378 class VkEnumValue(object):
379     def __init__(self, name, value, hex=False):
380         self.name = name
381         self.value = value
382         self.hex = hex
384     def __repr__(self):
385         return "{0}={1}".format(self.name, self.value)
387     def definition(self):
388         """ Convert to text definition e.g. VK_FOO = 1 """
390         # Hex is commonly used for FlagBits and sometimes within
391         # a non-FlagBits enum for a bitmask value as well.
392         if self.hex:
393             return "{0} = 0x{1:08x}".format(self.name, self.value)
394         else:
395             return "{0} = {1}".format(self.name, self.value)
398 class VkFunction(object):
399     def __init__(self, _type=None, name=None, params=[], extensions=[], alias=None):
400         self.extensions = []
401         self.name = name
402         self.type = _type
403         self.params = params
404         self.alias = alias
406         # For some functions we need some extra metadata from FUNCTION_OVERRIDES.
407         func_info = FUNCTION_OVERRIDES.get(self.name, None)
408         self.dispatch = func_info["dispatch"] if func_info is not None else True
409         self.driver = func_info["driver"] if func_info is not None else False
410         self.thunk_needed = func_info["thunk"] if func_info is not None else True
412         # Required is set while parsing which APIs and types are required
413         # and is used by the code generation.
414         self.required = True if func_info else False
416     @staticmethod
417     def from_alias(command, alias):
418         """ Create VkFunction from an alias command.
420         Args:
421             command: xml data for command
422             alias (VkFunction): function to use as a base for types / parameters.
424         Returns:
425             VkFunction
426         """
427         func_name = command.attrib.get("name")
428         func_type = alias.type
429         params = alias.params
431         return VkFunction(_type=func_type, name=func_name, params=params, alias=alias)
433     @staticmethod
434     def from_xml(command, types):
435         proto = command.find("proto")
436         func_name = proto.find("name").text
437         func_type = proto.find("type").text
439         params = []
440         for param in command.findall("param"):
441             vk_param = VkParam.from_xml(param, types)
442             params.append(vk_param)
444         return VkFunction(_type=func_type, name=func_name, params=params)
446     def get_conversions(self):
447         """ Get a list of conversion functions required for this function if any.
448         Parameters which are structures may require conversion between win32
449         and the host platform. This function returns a list of conversions
450         required.
451         """
453         conversions = []
454         for param in self.params:
455             convs = param.get_conversions()
456             if convs is not None:
457                 conversions.extend(convs)
459         return conversions
461     def is_alias(self):
462         return bool(self.alias)
464     def is_core_func(self):
465         """ Returns whether the function is a Vulkan core function.
466         Core functions are APIs defined by the Vulkan spec to be part of the
467         Core API as well as several KHR WSI extensions.
468         """
470         if not self.extensions:
471             return True
473         return any(ext in self.extensions for ext in CORE_EXTENSIONS)
475     def is_device_func(self):
476         # If none of the other, it must be a device function
477         return not self.is_global_func() and not self.is_instance_func()
479     def is_driver_func(self):
480         """ Returns if function is part of Wine driver interface. """
481         return self.driver
483     def is_global_func(self):
484         # Treat vkGetInstanceProcAddr as a global function as it
485         # can operate with NULL for vkInstance.
486         if self.name == "vkGetInstanceProcAddr":
487             return True
488         # Global functions are not passed a dispatchable object.
489         elif self.params[0].is_dispatchable():
490             return False
491         return True
493     def is_instance_func(self):
494         # Instance functions are passed VkInstance or VkPhysicalDevice.
495         if self.params[0].type in ["VkInstance", "VkPhysicalDevice"]:
496             return True
497         return False
499     def is_required(self):
500         return self.required
502     def needs_conversion(self):
503         """ Check if the function needs any input/output type conversion.
504         Functions need input/output conversion if struct parameters have
505         alignment differences between Win32 and Linux 32-bit.
506         """
508         for p in self.params:
509             if p.needs_conversion():
510                 LOGGER.debug("Parameter {0} to {1} requires conversion".format(p.name, self.name))
511                 return True
513         return False
515     def needs_dispatch(self):
516         return self.dispatch
518     def needs_thunk(self):
519         return self.thunk_needed
521     def pfn(self, prefix="p", call_conv=None, conv=False):
522         """ Create function pointer. """
524         if call_conv:
525             pfn = "{0} ({1} *{2}_{3})(".format(self.type, call_conv, prefix, self.name)
526         else:
527             pfn = "{0} (*{1}_{2})(".format(self.type, prefix, self.name)
529         for i, param in enumerate(self.params):
530             if param.const:
531                 pfn += param.const + " "
533             pfn += param.type
534             if conv and param.needs_conversion():
535                 pfn += "_host"
537             if param.is_pointer():
538                 pfn += " " + param.pointer
540             if param.array_len is not None:
541                 pfn += "[{0}]".format(param.array_len)
543             if i < len(self.params) - 1:
544                 pfn += ", "
545         pfn += ")"
546         return pfn
548     def prototype(self, call_conv=None, prefix=None, postfix=None):
549         """ Generate prototype for given function.
551         Args:
552             call_conv (str, optional): calling convention e.g. WINAPI
553             prefix (str, optional): prefix to append prior to function name e.g. vkFoo -> wine_vkFoo
554             postfix (str, optional): text to append after function name but prior to semicolon e.g. DECLSPEC_HIDDEN
555         """
557         proto = "{0}".format(self.type)
559         if call_conv is not None:
560             proto += " {0}".format(call_conv)
562         if prefix is not None:
563             proto += " {0}{1}(".format(prefix, self.name)
564         else:
565             proto += " {0}(".format(self.name)
567         # Add all the parameters.
568         proto += ", ".join([p.definition() for p in self.params])
570         if postfix is not None:
571             proto += ") {0}".format(postfix)
572         else:
573             proto += ")"
575         return proto
577     def body(self):
578         body = "    {0}".format(self.trace())
580         params = ", ".join([p.variable(conv=False) for p in self.params])
582         # Call the native Vulkan function.
583         if self.type == "void":
584             body += "    {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
585         else:
586             body += "    return {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
588         return body
590     def body_conversion(self):
591         body = ""
593         # Declare a variable to hold the result for non-void functions.
594         if self.type != "void":
595             body += "    {0} result;\n".format(self.type)
597         # Declare any tmp parameters for conversion.
598         for p in self.params:
599             if not p.needs_conversion():
600                 continue
602             if p.is_dynamic_array():
603                 body += "    {0}_host *{1}_host;\n".format(p.type, p.name)
604             else:
605                 body += "    {0}_host {1}_host;\n".format(p.type, p.name)
607         body += "    {0}\n".format(self.trace())
609         # Call any win_to_host conversion calls.
610         for p in self.params:
611             if not p.needs_input_conversion():
612                 continue
614             body += p.copy(Direction.INPUT)
616         # Build list of parameters containing converted and non-converted parameters.
617         # The param itself knows if conversion is needed and applies it when we set conv=True.
618         params = ", ".join([p.variable(conv=True) for p in self.params])
620         # Call the native Vulkan function.
621         if self.type == "void":
622             body += "    {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
623         else:
624             body += "    result = {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
626         body += "\n"
628         # Call any host_to_win conversion calls.
629         for p in self.params:
630             if not p.needs_output_conversion():
631                 continue
633             body += p.copy(Direction.OUTPUT)
635         # Perform any required cleanups. Most of these are for array functions.
636         for p in self.params:
637             if not p.needs_free():
638                 continue
640             body += p.free()
642         # Finally return the result.
643         if self.type != "void":
644             body += "    return result;\n"
646         return body
648     def spec(self, prefix=None, symbol=None):
649         """ Generate spec file entry for this function.
651         Args
652             prefix (str, optional): prefix to prepend to entry point name.
653             symbol (str, optional): allows overriding the name of the function implementing the entry point.
654         """
656         spec = ""
657         params = " ".join([p.spec() for p in self.params])
658         if prefix is not None:
659             spec += "@ stdcall -private {0}{1}({2})".format(prefix, self.name, params)
660         else:
661             spec += "@ stdcall {0}({1})".format(self.name, params)
663         if symbol is not None:
664             spec += " " + symbol
666         spec += "\n"
667         return spec
669     def stub(self, call_conv=None, prefix=None):
670         stub = self.prototype(call_conv=call_conv, prefix=prefix)
671         stub += "\n{\n"
672         stub += "    {0}".format(self.trace(message="stub: ", trace_func="FIXME"))
674         if self.type == "VkResult":
675             stub += "    return VK_ERROR_OUT_OF_HOST_MEMORY;\n"
676         elif self.type == "VkBool32":
677             stub += "    return VK_FALSE;\n"
678         elif self.type == "PFN_vkVoidFunction":
679             stub += "    return NULL;\n"
681         stub += "}\n\n"
682         return stub
684     def thunk(self, call_conv=None, prefix=None):
685         thunk = self.prototype(call_conv=call_conv, prefix=prefix)
686         thunk += "\n{\n"
688         if self.needs_conversion():
689             thunk += "#if defined(USE_STRUCT_CONVERSION)\n"
690             thunk += self.body_conversion()
691             thunk += "#else\n"
692             thunk += self.body()
693             thunk += "#endif\n"
694         else:
695             thunk += self.body()
697         thunk += "}\n\n"
698         return thunk
700     def trace(self, message=None, trace_func=None):
701         """ Create a trace string including all parameters.
703         Args:
704             message (str, optional): text to print at start of trace message e.g. 'stub: '
705             trace_func (str, optional): used to override trace function e.g. FIXME, printf, etcetera.
706         """
707         if trace_func is not None:
708             trace = "{0}(\"".format(trace_func)
709         else:
710             trace = "TRACE(\""
712         if message is not None:
713             trace += message
715         # First loop is for all the format strings.
716         trace += ", ".join([p.format_string() for p in self.params])
717         trace += "\\n\""
719         # Second loop for parameter names and optional conversions.
720         for param in self.params:
721             if param.format_conv is not None:
722                 trace += ", " + param.format_conv.format(param.name)
723             else:
724                 trace += ", {0}".format(param.name)
725         trace += ");\n"
727         return trace
730 class VkFunctionPointer(object):
731     def __init__(self, _type, name, members):
732         self.name = name
733         self.members = members
734         self.type = _type
735         self.required = False
737     @staticmethod
738     def from_xml(funcpointer):
739         members = []
740         begin = None
742         for t in funcpointer.findall("type"):
743             # General form:
744             # <type>void</type>*       pUserData,
745             # Parsing of the tail (anything past </type>) is tricky since there
746             # can be other data on the next line like: const <type>int</type>..
748             const = True if begin and "const" in begin else False
749             _type = t.text
750             lines = t.tail.split(",\n")
751             if lines[0][0] == "*":
752                 pointer = "*"
753                 name = lines[0][1:].strip()
754             else:
755                 pointer = None
756                 name = lines[0].strip()
758             # Filter out ); if it is contained.
759             name = name.partition(");")[0]
761             # If tail encompasses multiple lines, assign the second line to begin
762             # for the next line.
763             try:
764                 begin = lines[1].strip()
765             except IndexError:
766                 begin = None
768             members.append(VkMember(const=const, _type=_type, pointer=pointer, name=name))
770         _type = funcpointer.text
771         name = funcpointer.find("name").text
772         return VkFunctionPointer(_type, name, members)
774     def definition(self):
775         text = "{0} {1})(\n".format(self.type, self.name)
777         first = True
778         if len(self.members) > 0:
779             for m in self.members:
780                 if first:
781                     text += "    " + m.definition()
782                     first = False
783                 else:
784                     text += ",\n    " + m.definition()
785         else:
786             # Just make the compiler happy by adding a void parameter.
787             text += "void"
788         text += ");\n"
789         return text
792 class VkHandle(object):
793     def __init__(self, name, _type, parent, alias=None):
794         self.name = name
795         self.type = _type
796         self.parent = parent
797         self.alias = alias
798         self.required = False
800     @staticmethod
801     def from_alias(handle, alias):
802         name = handle.attrib.get("name")
803         return VkHandle(name, alias.type, alias.parent, alias=alias)
805     @staticmethod
806     def from_xml(handle):
807         name = handle.find("name").text
808         _type = handle.find("type").text
809         parent = handle.attrib.get("parent") # Most objects have a parent e.g. VkQueue has VkDevice.
810         return VkHandle(name, _type, parent)
812     def dispatch_table(self):
813         if not self.is_dispatchable():
814             return None
816         if self.parent is None:
817             # Should only happen for VkInstance
818             return "funcs"
819         elif self.name == "VkDevice":
820             # VkDevice has VkInstance as a parent, but has its own dispatch table.
821             return "funcs"
822         elif self.parent in ["VkInstance", "VkPhysicalDevice"]:
823             return "instance->funcs"
824         elif self.parent in ["VkDevice", "VkCommandPool"]:
825             return "device->funcs"
826         else:
827             LOGGER.error("Unhandled dispatchable parent: {0}".format(self.parent))
829     def definition(self):
830         """ Generates handle definition e.g. VK_DEFINE_HANDLE(vkInstance) """
832         # Legacy types are typedef'ed to the new type if they are aliases.
833         if self.is_alias():
834             return "typedef {0} {1};\n".format(self.alias.name, self.name)
836         return "{0}({1})\n".format(self.type, self.name)
838     def is_alias(self):
839         return self.alias is not None
841     def is_dispatchable(self):
842         """ Some handles like VkInstance, VkDevice are dispatchable objects,
843         which means they contain a dispatch table of function pointers.
844         """
845         return self.type == "VK_DEFINE_HANDLE"
847     def is_required(self):
848         return self.required
850     def native_handle(self, name):
851         """ Provide access to the native handle of a wrapped object. """
853         if self.name == "VkCommandPool":
854             return "wine_cmd_pool_from_handle({0})->command_pool".format(name)
856         native_handle_name = None
858         if self.name == "VkCommandBuffer":
859             native_handle_name = "command_buffer"
860         if self.name == "VkDevice":
861             native_handle_name = "device"
862         if self.name == "VkInstance":
863             native_handle_name = "instance"
864         if self.name == "VkPhysicalDevice":
865             native_handle_name = "phys_dev"
866         if self.name == "VkQueue":
867             native_handle_name = "queue"
869         if native_handle_name:
870             return "{0}->{1}".format(name, native_handle_name)
872         if self.is_dispatchable():
873             LOGGER.error("Unhandled native handle for: {0}".format(self.name))
874         return None
877 class VkMember(object):
878     def __init__(self, const=False, struct_fwd_decl=False,_type=None, pointer=None, name=None, array_len=None,
879             dyn_array_len=None, optional=False):
880         self.const = const
881         self.struct_fwd_decl = struct_fwd_decl
882         self.name = name
883         self.pointer = pointer
884         self.type = _type
885         self.type_info = None
886         self.array_len = array_len
887         self.dyn_array_len = dyn_array_len
888         self.optional = optional
890     def __eq__(self, other):
891         """ Compare member based on name against a string.
893         This method is for convenience by VkStruct, which holds a number of members and needs quick checking
894         if certain members exist.
895         """
897         if self.name == other:
898             return True
900         return False
902     def __repr__(self):
903         return "{0} {1} {2} {3} {4} {5} {6}".format(self.const, self.struct_fwd_decl, self.type, self.pointer,
904                 self.name, self.array_len, self.dyn_array_len)
906     @staticmethod
907     def from_xml(member):
908         """ Helper function for parsing a member tag within a struct or union. """
910         name_elem = member.find("name")
911         type_elem = member.find("type")
913         const = False
914         struct_fwd_decl = False
915         member_type = None
916         pointer = None
917         array_len = None
919         if member.text:
920             if "const" in member.text:
921                 const = True
923             # Some members contain forward declarations:
924             # - VkBaseInstructure has a member "const struct VkBaseInStructure *pNext"
925             # - VkWaylandSurfaceCreateInfoKHR has a member "struct wl_display *display"
926             if "struct" in member.text:
927                 struct_fwd_decl = True
929         if type_elem is not None:
930             member_type = type_elem.text
931             if type_elem.tail is not None:
932                 pointer = type_elem.tail.strip() if type_elem.tail.strip() != "" else None
934         # Name of other member within, which stores the number of
935         # elements pointed to be by this member.
936         dyn_array_len = member.get("len")
938         # Some members are optional, which is important for conversion code e.g. not dereference NULL pointer.
939         optional = True if member.get("optional") else False
941         # Usually we need to allocate memory for dynamic arrays. We need to do the same in a few other cases
942         # like for VkCommandBufferBeginInfo.pInheritanceInfo. Just threat such cases as dynamic arrays of
943         # size 1 to simplify code generation.
944         if dyn_array_len is None and pointer is not None:
945             dyn_array_len = 1
947         # Some members are arrays, attempt to parse these. Formats include:
948         # <member><type>char</type><name>extensionName</name>[<enum>VK_MAX_EXTENSION_NAME_SIZE</enum>]</member>
949         # <member><type>uint32_t</type><name>foo</name>[4]</member>
950         if name_elem.tail and name_elem.tail[0] == '[':
951             LOGGER.debug("Found array type")
952             enum_elem = member.find("enum")
953             if enum_elem is not None:
954                 array_len = enum_elem.text
955             else:
956                 # Remove brackets around length
957                 array_len = name_elem.tail.strip("[]")
959         return VkMember(const=const, struct_fwd_decl=struct_fwd_decl, _type=member_type, pointer=pointer, name=name_elem.text,
960                 array_len=array_len, dyn_array_len=dyn_array_len, optional=optional)
962     def copy(self, input, output, direction):
963         """ Helper method for use by conversion logic to generate a C-code statement to copy this member. """
965         if self.needs_conversion():
966             if self.is_dynamic_array():
967                 if direction == Direction.OUTPUT:
968                     LOGGER.warn("TODO: implement copying of returnedonly dynamic array for {0}.{1}".format(self.type, self.name))
969                 else:
970                     # Array length is either a variable name (string) or an int.
971                     count = self.dyn_array_len if isinstance(self.dyn_array_len, int) else "{0}{1}".format(input, self.dyn_array_len)
972                     return "{0}{1} = convert_{2}_array_win_to_host({3}{1}, {4});\n".format(output, self.name, self.type, input, count)
973             elif self.is_static_array():
974                 count = self.array_len
975                 if direction == Direction.OUTPUT:
976                     # Needed by VkMemoryHeap.memoryHeaps
977                     return "convert_{0}_static_array_host_to_win({2}{1}, {3}{1}, {4});\n".format(self.type, self.name, input, output, count)
978                 else:
979                     # Nothing needed this yet.
980                     LOGGER.warn("TODO: implement copying of static array for {0}.{1}".format(self.type, self.name))
981             else:
982                 if direction == Direction.OUTPUT:
983                     return "convert_{0}_host_to_win(&{2}{1}, &{3}{1});\n".format(self.type, self.name, input, output)
984                 else:
985                     return "convert_{0}_win_to_host(&{2}{1}, &{3}{1});\n".format(self.type, self.name, input, output)
986         elif self.is_static_array():
987             bytes_count = "{0} * sizeof({1})".format(self.array_len, self.type)
988             return "memcpy({0}{1}, {2}{1}, {3});\n".format(output, self.name, input, bytes_count)
989         else:
990             return "{0}{1} = {2}{1};\n".format(output, self.name, input)
992     def definition(self, align=False, conv=False):
993         """ Generate prototype for given function.
995         Args:
996             align (bool, optional): Enable alignment if a type needs it. This adds WINE_VK_ALIGN(8) to a member.
997             conv (bool, optional): Enable conversion if a type needs it. This appends '_host' to the name.
998         """
1000         text = ""
1001         if self.is_const():
1002             text += "const "
1004         if self.is_struct_forward_declaration():
1005             text += "struct "
1007         if conv and self.is_struct():
1008             text += "{0}_host".format(self.type)
1009         else:
1010             text += self.type
1012         if self.is_pointer():
1013             text += " {0}{1}".format(self.pointer, self.name)
1014         else:
1015             if align and self.needs_alignment():
1016                 text += " WINE_VK_ALIGN(8) " + self.name
1017             else:
1018                 text += " " + self.name
1020         if self.is_static_array():
1021             text += "[{0}]".format(self.array_len)
1023         return text
1025     def get_conversions(self):
1026         """ Return any conversion description for this member and its children when conversion is needed. """
1028         # Check if we need conversion either for this member itself or for any child members
1029         # in case member represents a struct.
1030         if not self.needs_conversion():
1031             return None
1033         conversions = []
1035         # Collect any conversion for any member structs.
1036         struct = self.type_info["data"]
1037         for m in struct:
1038             m.needs_struct_extensions_conversion()
1039             if m.needs_conversion():
1040                 conversions.extend(m.get_conversions())
1042         struct.needs_struct_extensions_conversion()
1044         struct = self.type_info["data"]
1045         direction = Direction.OUTPUT if struct.returnedonly else Direction.INPUT
1046         if self.is_dynamic_array():
1047             conversions.append(ConversionFunction(False, True, direction, struct))
1048         elif self.is_static_array():
1049             conversions.append(ConversionFunction(True, False, direction, struct))
1050         else:
1051             conversions.append(ConversionFunction(False, False, direction, struct))
1053         if self.needs_free():
1054             conversions.append(FreeFunction(self.is_dynamic_array(), struct))
1056         return conversions
1058     def is_const(self):
1059         return self.const
1061     def is_dynamic_array(self):
1062         """ Returns if the member is an array element.
1063         Vulkan uses this for dynamically sized arrays for which
1064         there is a 'count' parameter.
1065         """
1066         return self.dyn_array_len is not None
1068     def is_handle(self):
1069         return self.type_info["category"] == "handle"
1071     def is_pointer(self):
1072         return self.pointer is not None
1074     def is_static_array(self):
1075         """ Returns if the member is an array.
1076         Vulkan uses this often for fixed size arrays in which the
1077         length is part of the member.
1078         """
1079         return self.array_len is not None
1081     def is_struct(self):
1082         return self.type_info["category"] == "struct"
1084     def is_struct_forward_declaration(self):
1085         return self.struct_fwd_decl
1087     def is_union(self):
1088         return self.type_info["category"] == "union"
1090     def needs_alignment(self):
1091         """ Check if this member needs alignment for 64-bit data.
1092         Various structures need alignment on 64-bit variables due
1093         to compiler differences on 32-bit between Win32 and Linux.
1094         """
1096         if self.is_pointer():
1097             return False
1098         elif self.type == "size_t":
1099             return False
1100         elif self.type in ["uint64_t", "VkDeviceSize"]:
1101             return True
1102         elif self.is_struct():
1103             struct = self.type_info["data"]
1104             return struct.needs_alignment()
1105         elif self.is_handle():
1106             # Dispatchable handles are pointers to objects, while
1107             # non-dispatchable are uint64_t and hence need alignment.
1108             handle = self.type_info["data"]
1109             return False if handle.is_dispatchable() else True
1110         return False
1112     def needs_conversion(self):
1113         """ Structures requiring alignment, need conversion between win32 and host. """
1115         if not self.is_struct():
1116             return False
1118         struct = self.type_info["data"]
1119         return struct.needs_conversion()
1121     def needs_free(self):
1122         if not self.needs_conversion():
1123             return False
1125         if self.is_dynamic_array():
1126             return True
1128         # TODO: some non-pointer structs and optional pointer structs may need freeing,
1129         # though none of this type have been encountered yet.
1130         return False
1132     def needs_struct_extensions_conversion(self):
1133         if not self.is_struct():
1134             return False
1136         struct = self.type_info["data"]
1137         return struct.needs_struct_extensions_conversion()
1139     def set_type_info(self, type_info):
1140         """ Helper function to set type information from the type registry.
1141         This is needed, because not all type data is available at time of
1142         parsing.
1143         """
1144         self.type_info = type_info
1147 class VkParam(object):
1148     """ Helper class which describes a parameter to a function call. """
1150     def __init__(self, type_info, const=None, pointer=None, name=None, array_len=None, dyn_array_len=None):
1151         self.const = const
1152         self.name = name
1153         self.array_len = array_len
1154         self.dyn_array_len = dyn_array_len
1155         self.pointer = pointer
1156         self.type_info = type_info
1157         self.type = type_info["name"] # For convenience
1158         self.handle = type_info["data"] if type_info["category"] == "handle" else None
1159         self.struct = type_info["data"] if type_info["category"] == "struct" else None
1161         self._set_direction()
1162         self._set_format_string()
1163         self._set_conversions()
1165     def __repr__(self):
1166         return "{0} {1} {2} {3} {4} {5}".format(self.const, self.type, self.pointer, self.name, self.array_len, self.dyn_array_len)
1168     @staticmethod
1169     def from_xml(param, types):
1170         """ Helper function to create VkParam from xml. """
1172         # Parameter parsing is slightly tricky. All the data is contained within
1173         # a param tag, but some data is within subtags while others are text
1174         # before or after the type tag.
1175         # Common structure:
1176         # <param>const <type>char</type>* <name>pLayerName</name></param>
1178         name_elem = param.find("name")
1179         array_len = None
1180         name = name_elem.text
1181         # Tail contains array length e.g. for blendConstants param of vkSetBlendConstants
1182         if name_elem.tail is not None:
1183             array_len = name_elem.tail.strip("[]")
1185         # Name of other parameter in function prototype, which stores the number of
1186         # elements pointed to be by this parameter.
1187         dyn_array_len = param.get("len", None)
1189         const = param.text.strip() if param.text else None
1190         type_elem = param.find("type")
1191         pointer = type_elem.tail.strip() if type_elem.tail.strip() != "" else None
1193         # Since we have parsed all types before hand, this should not happen.
1194         type_info = types.get(type_elem.text, None)
1195         if type_info is None:
1196             LOGGER.err("type info not found for: {0}".format(type_elem.text))
1198         return VkParam(type_info, const=const, pointer=pointer, name=name, array_len=array_len, dyn_array_len=dyn_array_len)
1200     def _set_conversions(self):
1201         """ Internal helper function to configure any needed conversion functions. """
1203         self.free_func = None
1204         self.input_conv = None
1205         self.output_conv = None
1206         if not self.needs_conversion():
1207             return
1209         # Input functions require win to host conversion.
1210         if self._direction in [Direction.INPUT, Direction.INPUT_OUTPUT]:
1211             self.input_conv = ConversionFunction(False, self.is_dynamic_array(), Direction.INPUT, self.struct)
1213         # Output functions require host to win conversion.
1214         if self._direction in [Direction.INPUT_OUTPUT, Direction.OUTPUT]:
1215             self.output_conv = ConversionFunction(False, self.is_dynamic_array(), Direction.OUTPUT, self.struct)
1217         # Dynamic arrays, but also some normal structs (e.g. VkCommandBufferBeginInfo) need memory
1218         # allocation and thus some cleanup.
1219         if self.is_dynamic_array() or self.struct.needs_free():
1220             self.free_func = FreeFunction(self.is_dynamic_array(), self.struct)
1222     def _set_direction(self):
1223         """ Internal helper function to set parameter direction (input/output/input_output). """
1225         # The parameter direction needs to be determined from hints in vk.xml like returnedonly,
1226         # parameter constness and other heuristics.
1227         # For now we need to get this right for structures as we need to convert these, we may have
1228         # missed a few other edge cases (e.g. count variables).
1229         # See also https://github.com/KhronosGroup/Vulkan-Docs/issues/610
1231         if not self.is_pointer():
1232             self._direction = Direction.INPUT
1233         elif self.is_const() and self.is_pointer():
1234             self._direction = Direction.INPUT
1235         elif self.is_struct():
1236             if not self.struct.returnedonly:
1237                 self._direction = Direction.INPUT
1238                 return
1240             # Returnedonly hints towards output, however in some cases
1241             # it is inputoutput. In particular if pNext / sType exist,
1242             # which are used to link in other structures without having
1243             # to introduce new APIs. E.g. vkGetPhysicalDeviceProperties2KHR.
1244             if "pNext" in self.struct:
1245                 self._direction = Direction.INPUT_OUTPUT
1246                 return
1248             self._direction = Direction.OUTPUT
1249         else:
1250             # This should mostly be right. Count variables can be inout, but we don't care about these yet.
1251             self._direction = Direction.OUTPUT
1253     def _set_format_string(self):
1254         """ Internal helper function to be used by constructor to set format string. """
1256         # Determine a format string used by code generation for traces.
1257         # 64-bit types need a conversion function.
1258         self.format_conv = None
1259         if self.is_static_array() or self.is_pointer():
1260             self.format_str = "%p"
1261         else:
1262             if self.type_info["category"] in ["bitmask", "enum"]:
1263                 self.format_str = "%#x"
1264             elif self.is_handle():
1265                 # We use uint64_t for non-dispatchable handles as opposed to pointers
1266                 # for dispatchable handles.
1267                 if self.handle.is_dispatchable():
1268                     self.format_str = "%p"
1269                 else:
1270                     self.format_str = "0x%s"
1271                     self.format_conv = "wine_dbgstr_longlong({0})"
1272             elif self.type == "float":
1273                 self.format_str = "%f"
1274             elif self.type == "int":
1275                 self.format_str = "%d"
1276             elif self.type == "int32_t":
1277                 self.format_str = "%d"
1278             elif self.type == "size_t":
1279                 self.format_str = "0x%s"
1280                 self.format_conv = "wine_dbgstr_longlong({0})"
1281             elif self.type in ["uint32_t", "VkBool32"]:
1282                 self.format_str = "%u"
1283             elif self.type in ["uint64_t", "VkDeviceSize"]:
1284                 self.format_str = "0x%s"
1285                 self.format_conv = "wine_dbgstr_longlong({0})"
1286             elif self.type == "HANDLE":
1287                 self.format_str = "%p"
1288             elif self.type in ["VisualID", "xcb_visualid_t", "RROutput"]:
1289                 # Don't care about Linux specific types.
1290                 self.format_str = ""
1291             else:
1292                 LOGGER.warn("Unhandled type: {0}".format(self.type_info))
1294     def copy(self, direction):
1295         if direction == Direction.INPUT:
1296             if self.is_dynamic_array():
1297                 return "    {0}_host = convert_{1}_array_win_to_host({0}, {2});\n".format(self.name, self.type, self.dyn_array_len)
1298             else:
1299                 return "    convert_{0}_win_to_host({1}, &{1}_host);\n".format(self.type, self.name)
1300         else:
1301             if self.is_dynamic_array():
1302                 LOGGER.error("Unimplemented output conversion for: {0}".format(self.name))
1303             else:
1304                 return "    convert_{0}_host_to_win(&{1}_host, {1});\n".format(self.type, self.name)
1306     def definition(self, postfix=None):
1307         """ Return prototype for the parameter. E.g. 'const char *foo' """
1309         proto = ""
1310         if self.const:
1311             proto += self.const + " "
1313         proto += self.type
1315         if self.is_pointer():
1316             proto += " {0}{1}".format(self.pointer, self.name)
1317         else:
1318             proto += " " + self.name
1320         # Allows appending something to the variable name useful for
1321         # win32 to host conversion.
1322         if postfix is not None:
1323             proto += postfix
1325         if self.is_static_array():
1326             proto += "[{0}]".format(self.array_len)
1328         return proto
1330     def direction(self):
1331         """ Returns parameter direction: input, output, input_output.
1333         Parameter direction in Vulkan is not straight-forward, which this function determines.
1334         """
1336         return self._direction
1338     def dispatch_table(self):
1339         """ Return functions dispatch table pointer for dispatchable objects. """
1341         if not self.is_dispatchable():
1342             return None
1344         return "{0}->{1}".format(self.name, self.handle.dispatch_table())
1346     def format_string(self):
1347         return self.format_str
1349     def free(self):
1350         if self.is_dynamic_array():
1351             if self.struct.returnedonly:
1352                 # For returnedonly, counts is stored in a pointer.
1353                 return "    free_{0}_array({1}_host, *{2});\n".format(self.type, self.name, self.dyn_array_len)
1354             else:
1355                 return "    free_{0}_array({1}_host, {2});\n".format(self.type, self.name, self.dyn_array_len)
1356         else:
1357             # We are operating on a single structure. Some structs (very rare) contain dynamic members,
1358             # which would need freeing.
1359             if self.struct.needs_free():
1360                 return "    free_{0}(&{1}_host);\n".format(self.type, self.name)
1361         return ""
1363     def get_conversions(self):
1364         """ Get a list of conversions required for this parameter if any.
1365         Parameters which are structures may require conversion between win32
1366         and the host platform. This function returns a list of conversions
1367         required.
1368         """
1370         if not self.is_struct():
1371             return None
1373         self.struct.needs_struct_extensions_conversion()
1374         for m in self.struct:
1375             m.needs_struct_extensions_conversion()
1377         if not self.needs_conversion():
1378             return None
1380         conversions = []
1382         # Collect any member conversions first, so we can guarantee
1383         # those functions will be defined prior to usage by the
1384         # 'parent' param requiring conversion.
1385         for m in self.struct:
1386             if not m.is_struct():
1387                 continue
1389             if not m.needs_conversion():
1390                 continue
1392             conversions.extend(m.get_conversions())
1394         # Conversion requirements for the 'parent' parameter.
1395         if self.input_conv is not None:
1396             conversions.append(self.input_conv)
1397         if self.output_conv is not None:
1398             conversions.append(self.output_conv)
1399         if self.free_func is not None:
1400             conversions.append(self.free_func)
1402         return conversions
1404     def is_const(self):
1405         return self.const is not None
1407     def is_dynamic_array(self):
1408         return self.dyn_array_len is not None
1410     def is_dispatchable(self):
1411         if not self.is_handle():
1412             return False
1414         return self.handle.is_dispatchable()
1416     def is_handle(self):
1417         return self.handle is not None
1419     def is_pointer(self):
1420         return self.pointer is not None
1422     def is_static_array(self):
1423         return self.array_len is not None
1425     def is_struct(self):
1426         return self.struct is not None
1428     def needs_conversion(self):
1429         """ Returns if parameter needs conversion between win32 and host. """
1431         if not self.is_struct():
1432             return False
1434         # VkSparseImageMemoryRequirements(2) is used by vkGetImageSparseMemoryRequirements(2).
1435         # This function is tricky to wrap, because how to wrap depends on whether
1436         # pSparseMemoryRequirements is NULL or not. Luckily for VkSparseImageMemoryRequirements(2)
1437         # the alignment works out in such a way that no conversion is needed between win32 and Linux.
1438         if self.type in ["VkSparseImageMemoryRequirements", "VkSparseImageMemoryRequirements2"]:
1439             return False
1441         # If a structure needs alignment changes, it means we need to
1442         # perform parameter conversion between win32 and host.
1443         if self.struct.needs_conversion():
1444             return True
1446         return False
1448     def needs_free(self):
1449         return self.free_func is not None
1451     def needs_input_conversion(self):
1452         return self.input_conv is not None
1454     def needs_output_conversion(self):
1455         return self.output_conv is not None
1457     def spec(self):
1458         """ Generate spec file entry for this parameter. """
1460         if self.type_info["category"] in ["bitmask", "enum"]:
1461             return "long"
1462         if self.is_pointer() and self.type == "char":
1463             return "str"
1464         if self.is_dispatchable() or self.is_pointer() or self.is_static_array():
1465             return "ptr"
1466         if self.is_handle() and not self.is_dispatchable():
1467             return "int64"
1468         if self.type == "float":
1469             return "float"
1470         if self.type in ["int", "int32_t", "size_t", "uint32_t", "VkBool32"]:
1471             return "long"
1472         if self.type in ["uint64_t", "VkDeviceSize"]:
1473             return "int64"
1475         LOGGER.error("Unhandled spec conversion for type: {0}".format(self.type))
1477     def variable(self, conv=False):
1478         """ Returns 'glue' code during generation of a function call on how to access the variable.
1479         This function handles various scenarios such as 'unwrapping' if dispatchable objects and
1480         renaming of parameters in case of win32 -> host conversion.
1482         Args:
1483             conv (bool, optional): Enable conversion if the param needs it. This appends '_host' to the name.
1484         """
1486         # Hack until we enable allocation callbacks from ICD to application. These are a joy
1487         # to enable one day, because of calling convention conversion.
1488         if "VkAllocationCallbacks" in self.type:
1489             LOGGER.debug("TODO: setting NULL VkAllocationCallbacks for {0}".format(self.name))
1490             return "NULL"
1492         if conv and self.needs_conversion():
1493             if self.is_dynamic_array():
1494                 return "{0}_host".format(self.name)
1495             else:
1496                 return "&{0}_host".format(self.name)
1497         else:
1498             # We need to pass the native handle to the native Vulkan calls.
1499             native_handle = self.handle.native_handle(self.name) if self.is_handle() else None
1500             return native_handle if native_handle else self.name
1503 class VkStruct(Sequence):
1504     """ Class which represents the type union and struct. """
1506     def __init__(self, name, members, returnedonly, structextends, alias=None, union=False):
1507         self.name = name
1508         self.members = members
1509         self.returnedonly = returnedonly
1510         self.structextends = structextends
1511         self.required = False
1512         self.alias = alias
1513         self.union = union
1514         self.type_info = None # To be set later.
1515         self.struct_extensions = []
1517     def __getitem__(self, i):
1518         return self.members[i]
1520     def __len__(self):
1521         return len(self.members)
1523     @staticmethod
1524     def from_alias(struct, alias):
1525         name = struct.attrib.get("name")
1526         return VkStruct(name, alias.members, alias.returnedonly, alias.structextends, alias=alias)
1528     @staticmethod
1529     def from_xml(struct):
1530         # Unions and structs are the same parsing wise, but we need to
1531         # know which one we are dealing with later on for code generation.
1532         union = True if struct.attrib["category"] == "union" else False
1534         name = struct.attrib.get("name")
1536         # 'Output' structures for which data is filled in by the API are
1537         # marked as 'returnedonly'.
1538         returnedonly = True if struct.attrib.get("returnedonly") else False
1540         structextends = struct.attrib.get("structextends")
1541         structextends = structextends.split(",") if structextends else []
1543         members = []
1544         for member in struct.findall("member"):
1545             vk_member = VkMember.from_xml(member)
1546             members.append(vk_member)
1548         return VkStruct(name, members, returnedonly, structextends, union=union)
1550     @staticmethod
1551     def decouple_structs(structs):
1552         """ Helper function which decouples a list of structs.
1553         Structures often depend on other structures. To make the C compiler
1554         happy we need to define 'substructures' first. This function analyzes
1555         the list of structures and reorders them in such a way that they are
1556         decoupled.
1557         """
1559         tmp_structs = list(structs) # Don't modify the original structures.
1560         decoupled_structs = []
1562         while (len(tmp_structs) > 0):
1563             for struct in tmp_structs:
1564                 dependends = False
1566                 if not struct.required:
1567                     tmp_structs.remove(struct)
1568                     continue
1570                 for m in struct:
1571                     if not (m.is_struct() or m.is_union()):
1572                         continue
1574                     # VkBaseInstructure and VkBaseOutStructure reference themselves.
1575                     if m.type == struct.name:
1576                         break
1578                     found = False
1579                     # Check if a struct we depend on has already been defined.
1580                     for s in decoupled_structs:
1581                         if s.name == m.type:
1582                             found = True
1583                             break
1585                     if not found:
1586                         # Check if the struct we depend on is even in the list of structs.
1587                         # If found now, it means we haven't met all dependencies before we
1588                         # can operate on the current struct.
1589                         # When generating 'host' structs we may not be able to find a struct
1590                         # as the list would only contain the structs requiring conversion.
1591                         for s in tmp_structs:
1592                             if s.name == m.type:
1593                                 dependends = True
1594                                 break
1596                 if dependends == False:
1597                     decoupled_structs.append(struct)
1598                     tmp_structs.remove(struct)
1600         return decoupled_structs
1602     def definition(self, align=False, conv=False, postfix=None):
1603         """ Convert structure to textual definition.
1605         Args:
1606             align (bool, optional): enable alignment to 64-bit for win32 struct compatibility.
1607             conv (bool, optional): enable struct conversion if the struct needs it.
1608             postfix (str, optional): text to append to end of struct name, useful for struct renaming.
1609         """
1611         if self.union:
1612             text = "typedef union {0}".format(self.name)
1613         else:
1614             text = "typedef struct {0}".format(self.name)
1616         if postfix is not None:
1617             text += postfix
1619         text += "\n{\n"
1621         for m in self:
1622             if align and m.needs_alignment():
1623                 text += "    {0};\n".format(m.definition(align=align))
1624             elif conv and m.needs_conversion():
1625                 text += "    {0};\n".format(m.definition(conv=conv))
1626             else:
1627                 text += "    {0};\n".format(m.definition())
1629         if postfix is not None:
1630             text += "}} {0}{1};\n\n".format(self.name, postfix)
1631         else:
1632             text += "}} {0};\n\n".format(self.name)
1633         return text
1635     def is_alias(self):
1636         return bool(self.alias)
1638     def needs_alignment(self):
1639         """ Check if structure needs alignment for 64-bit data.
1640         Various structures need alignment on 64-bit variables due
1641         to compiler differences on 32-bit between Win32 and Linux.
1642         """
1644         for m in self.members:
1645             if m.needs_alignment():
1646                 return True
1647         return False
1649     def needs_conversion(self):
1650         """ Returns if struct members needs conversion between win32 and host.
1651         Structures need conversion if they contain members requiring alignment
1652         or if they include other structures which need alignment.
1653         """
1655         if self.needs_alignment():
1656             return True
1658         for m in self.members:
1659             if m.needs_conversion():
1660                 return True
1661         return False
1663     def needs_free(self):
1664         """ Check if any struct member needs some memory freeing."""
1666         for m in self.members:
1667             if m.needs_free():
1668                 return True
1670             continue
1672         return False
1674     def needs_struct_extensions_conversion(self):
1675         """ Checks if structure extensions in pNext chain need conversion. """
1676         ret = False
1678         for e in self.struct_extensions:
1679             if e.required and e.needs_conversion():
1680                 LOGGER.error("Unhandled pNext chain conversion for {0}".format(e.name))
1681                 ret = True
1683         return ret
1685     def set_type_info(self, types):
1686         """ Helper function to set type information from the type registry.
1687         This is needed, because not all type data is available at time of
1688         parsing.
1689         """
1690         for m in self.members:
1691             type_info = types[m.type]
1692             m.set_type_info(type_info)
1695 class ConversionFunction(object):
1696     def __init__(self, array, dyn_array, direction, struct):
1697         self.array = array
1698         self.direction = direction
1699         self.dyn_array = dyn_array
1700         self.struct = struct
1701         self.type = struct.name
1703         self._set_name()
1705     def __eq__(self, other):
1706         if self.name != other.name:
1707             return False
1709         return True
1711     def _generate_array_conversion_func(self):
1712         """ Helper function for generating a conversion function for array structs. """
1714         if self.direction == Direction.OUTPUT:
1715             params = ["const {0}_host *in".format(self.type), "uint32_t count"]
1716             return_type = self.type
1717         else:
1718             params = ["const {0} *in".format(self.type), "uint32_t count"]
1719             return_type = "{0}_host".format(self.type)
1721         # Generate function prototype.
1722         body = "static inline {0} *{1}(".format(return_type, self.name)
1723         body += ", ".join(p for p in params)
1724         body += ")\n{\n"
1726         body += "    {0} *out;\n".format(return_type)
1727         body += "    unsigned int i;\n\n"
1728         body += "    if (!in) return NULL;\n\n"
1730         body += "    out = heap_alloc(count * sizeof(*out));\n"
1732         body += "    for (i = 0; i < count; i++)\n"
1733         body += "    {\n"
1735         for m in self.struct:
1736             # TODO: support copying of pNext extension structures!
1737             # Luckily though no extension struct at this point needs conversion.
1738             body += "        " + m.copy("in[i].", "out[i].", self.direction)
1740         body += "    }\n\n"
1741         body += "    return out;\n"
1742         body += "}\n\n"
1743         return body
1745     def _generate_conversion_func(self):
1746         """ Helper function for generating a conversion function for non-array structs. """
1748         if self.direction == Direction.OUTPUT:
1749             params = ["const {0}_host *in".format(self.type), "{0} *out".format(self.type)]
1750         else:
1751             params = ["const {0} *in".format(self.type), "{0}_host *out".format(self.type)]
1753         body = "static inline void {0}(".format(self.name)
1755         # Generate parameter list
1756         body += ", ".join(p for p in params)
1757         body += ")\n{\n"
1759         body += "    if (!in) return;\n\n"
1761         if self.direction == Direction.INPUT and "pNext" in self.struct and self.struct.returnedonly:
1762             # We are dealing with an input_output parameter. For these we only need to copy
1763             # pNext and sType as the other fields are filled in by the host. We do potentially
1764             # have to iterate over pNext and perform conversions based on switch(sType)!
1765             # Luckily though no extension structs at this point need conversion.
1766             # TODO: support copying of pNext extension structures!
1767             body += "    out->pNext = in->pNext;\n"
1768             body += "    out->sType = in->sType;\n"
1769         else:
1770             for m in self.struct:
1771                 # TODO: support copying of pNext extension structures!
1772                 body += "    " + m.copy("in->", "out->", self.direction)
1774         body += "}\n\n"
1775         return body
1777     def _generate_static_array_conversion_func(self):
1778         """ Helper function for generating a conversion function for array structs. """
1780         if self.direction == Direction.OUTPUT:
1781             params = ["const {0}_host *in".format(self.type), "{0} *out".format(self.type), "uint32_t count"]
1782         else:
1783             params = ["const {0} *in".format(self.type), "{0} *out_host".format(self.type), "uint32_t count"]
1785         # Generate function prototype.
1786         body = "static inline void {0}(".format(self.name)
1787         body += ", ".join(p for p in params)
1788         body += ")\n{\n"
1789         body += "    unsigned int i;\n\n"
1790         body += "    if (!in) return;\n\n"
1791         body += "    for (i = 0; i < count; i++)\n"
1792         body += "    {\n"
1794         for m in self.struct:
1795             # TODO: support copying of pNext extension structures!
1796             body += "        " + m.copy("in[i].", "out[i].", self.direction)
1798         body += "    }\n"
1799         body += "}\n\n"
1800         return body
1802     def _set_name(self):
1803         if self.direction == Direction.INPUT:
1804             if self.array:
1805                 name = "convert_{0}_static_array_win_to_host".format(self.type)
1806             elif self.dyn_array:
1807                 name = "convert_{0}_array_win_to_host".format(self.type)
1808             else:
1809                 name = "convert_{0}_win_to_host".format(self.type)
1810         else: # Direction.OUTPUT
1811             if self.array:
1812                 name = "convert_{0}_static_array_host_to_win".format(self.type)
1813             elif self.dyn_array:
1814                 name = "convert_{0}_array_host_to_win".format(self.type)
1815             else:
1816                 name = "convert_{0}_host_to_win".format(self.type)
1818         self.name = name
1820     def definition(self):
1821         if self.array:
1822             return self._generate_static_array_conversion_func()
1823         elif self.dyn_array:
1824             return self._generate_array_conversion_func()
1825         else:
1826             return self._generate_conversion_func()
1829 class FreeFunction(object):
1830     def __init__(self, dyn_array, struct):
1831         self.dyn_array = dyn_array
1832         self.struct = struct
1833         self.type = struct.name
1835         if dyn_array:
1836             self.name = "free_{0}_array".format(self.type)
1837         else:
1838             self.name = "free_{0}".format(self.type)
1840     def __eq__(self, other):
1841         if self.name == other.name:
1842             return True
1844         return False
1846     def _generate_array_free_func(self):
1847         """ Helper function for cleaning up temporary buffers required for array conversions. """
1849         # Generate function prototype.
1850         body = "static inline void {0}({1}_host *in, uint32_t count)\n{{\n".format(self.name, self.type)
1852         # E.g. VkGraphicsPipelineCreateInfo_host needs freeing for pStages.
1853         if self.struct.needs_free():
1854             body += "    unsigned int i;\n\n"
1855             body += "    if (!in) return;\n\n"
1856             body += "    for (i = 0; i < count; i++)\n"
1857             body += "    {\n"
1859             for m in self.struct:
1860                 if m.needs_conversion() and m.is_dynamic_array():
1861                     if m.is_const():
1862                         # Add a cast to ignore const on conversion structs we allocated ourselves.
1863                         body += "        free_{0}_array(({0}_host *)in[i].{1}, in[i].{2});\n".format(m.type, m.name, m.dyn_array_len)
1864                     else:
1865                         body += "        free_{0}_array(in[i].{1}, in[i].{2});\n".format(m.type, m.name, m.dyn_array_len)
1866                 elif m.needs_conversion():
1867                     LOGGER.error("Unhandled conversion for {0}".format(m.name))
1868             body += "    }\n"
1869         else:
1870             body += "    if (!in) return;\n\n"
1872         body += "    heap_free(in);\n"
1874         body += "}\n\n"
1875         return body
1877     def _generate_free_func(self):
1878         # E.g. VkCommandBufferBeginInfo.pInheritanceInfo needs freeing.
1879         if not self.struct.needs_free():
1880             return ""
1882         # Generate function prototype.
1883         body = "static inline void {0}({1}_host *in)\n{{\n".format(self.name, self.type)
1885         for m in self.struct:
1886             if m.needs_conversion() and m.is_dynamic_array():
1887                 count = m.dyn_array_len if isinstance(m.dyn_array_len, int) else "in->{0}".format(m.dyn_array_len)
1888                 if m.is_const():
1889                     # Add a cast to ignore const on conversion structs we allocated ourselves.
1890                     body += "    free_{0}_array(({0}_host *)in->{1}, {2});\n".format(m.type, m.name, count)
1891                 else:
1892                     body += "    free_{0}_array(in->{1}, {2});\n".format(m.type, m.name, count)
1894         body += "}\n\n"
1895         return body
1897     def definition(self):
1898         if self.dyn_array:
1899             return self._generate_array_free_func()
1900         else:
1901             # Some structures need freeing too if they contain dynamic arrays.
1902             # E.g. VkCommandBufferBeginInfo
1903             return self._generate_free_func()
1906 class VkGenerator(object):
1907     def __init__(self, registry):
1908         self.registry = registry
1910         # Build a list conversion functions for struct conversion.
1911         self.conversions = []
1912         self.host_structs = []
1913         for func in self.registry.funcs.values():
1914             if not func.is_required():
1915                 continue
1917             if not func.needs_conversion():
1918                 continue
1920             conversions = func.get_conversions()
1921             for conv in conversions:
1922                 # Pull in any conversions for vulkan_thunks.c.
1923                 if func.needs_thunk():
1924                     # Append if we don't already have this conversion.
1925                     if not any(c == conv for c in self.conversions):
1926                         self.conversions.append(conv)
1928                 # Structs can be used in different ways by different conversions
1929                 # e.g. array vs non-array. Just make sure we pull in each struct once.
1930                 if not any(s.name == conv.struct.name for s in self.host_structs):
1931                     self.host_structs.append(conv.struct)
1933     def _generate_copyright(self, f, spec_file=False):
1934         f.write("# " if spec_file else "/* ")
1935         f.write("Automatically generated from Vulkan vk.xml; DO NOT EDIT!\n")
1936         lines = ["", "This file is generated from Vulkan vk.xml file covered",
1937             "by the following copyright and permission notice:"]
1938         lines.extend([l.rstrip(" ") for l in self.registry.copyright.splitlines()])
1939         for line in lines:
1940             f.write("{0}{1}".format("# " if spec_file else " * ", line).rstrip(" ") + "\n")
1941         f.write("\n" if spec_file else " */\n\n")
1943     def generate_thunks_c(self, f, prefix):
1944         self._generate_copyright(f)
1945         f.write("#include \"config.h\"\n")
1946         f.write("#include \"wine/port.h\"\n\n")
1948         f.write("#include \"vulkan_private.h\"\n\n")
1950         f.write("WINE_DEFAULT_DEBUG_CHANNEL(vulkan);\n\n")
1952         # Generate any conversion helper functions.
1953         f.write("#if defined(USE_STRUCT_CONVERSION)\n")
1954         for conv in self.conversions:
1955             f.write(conv.definition())
1956         f.write("#endif /* USE_STRUCT_CONVERSION */\n\n")
1958         # Create thunks for instance and device functions.
1959         # Global functions don't go through the thunks.
1960         for vk_func in self.registry.funcs.values():
1961             if not vk_func.is_required():
1962                 continue
1964             if vk_func.is_global_func():
1965                 continue
1967             if not vk_func.needs_thunk():
1968                 continue
1970             # Exports symbols for Core functions.
1971             if not vk_func.is_core_func():
1972                 f.write("static ")
1973             f.write(vk_func.thunk(prefix=prefix, call_conv="WINAPI"))
1975         f.write("static const struct vulkan_func vk_device_dispatch_table[] =\n{\n")
1976         for vk_func in self.registry.device_funcs:
1977             if not vk_func.is_required():
1978                 continue
1980             f.write("    {{\"{0}\", &{1}{0}}},\n".format(vk_func.name, prefix))
1981         f.write("};\n\n")
1983         f.write("static const struct vulkan_func vk_instance_dispatch_table[] =\n{\n")
1984         for vk_func in self.registry.instance_funcs:
1985             if not vk_func.is_required():
1986                 continue
1988             f.write("    {{\"{0}\", &{1}{0}}},\n".format(vk_func.name, prefix))
1989         f.write("};\n\n")
1991         f.write("void *wine_vk_get_device_proc_addr(const char *name)\n")
1992         f.write("{\n")
1993         f.write("    unsigned int i;\n")
1994         f.write("    for (i = 0; i < ARRAY_SIZE(vk_device_dispatch_table); i++)\n")
1995         f.write("    {\n")
1996         f.write("        if (strcmp(vk_device_dispatch_table[i].name, name) == 0)\n")
1997         f.write("        {\n")
1998         f.write("            TRACE(\"Found name=%s in device table\\n\", debugstr_a(name));\n")
1999         f.write("            return vk_device_dispatch_table[i].func;\n")
2000         f.write("        }\n")
2001         f.write("    }\n")
2002         f.write("    return NULL;\n")
2003         f.write("}\n\n")
2005         f.write("void *wine_vk_get_instance_proc_addr(const char *name)\n")
2006         f.write("{\n")
2007         f.write("    unsigned int i;\n")
2008         f.write("    for (i = 0; i < ARRAY_SIZE(vk_instance_dispatch_table); i++)\n")
2009         f.write("    {\n")
2010         f.write("        if (strcmp(vk_instance_dispatch_table[i].name, name) == 0)\n")
2011         f.write("        {\n")
2012         f.write("            TRACE(\"Found name=%s in instance table\\n\", debugstr_a(name));\n")
2013         f.write("            return vk_instance_dispatch_table[i].func;\n")
2014         f.write("        }\n")
2015         f.write("    }\n")
2016         f.write("    return NULL;\n")
2017         f.write("}\n\n")
2019         # Create array of device extensions.
2020         f.write("static const char * const vk_device_extensions[] =\n{\n")
2021         for ext in self.registry.extensions:
2022             if ext["type"] != "device":
2023                 continue
2025             f.write("    \"{0}\",\n".format(ext["name"]))
2026         f.write("};\n\n")
2028         # Create array of instance extensions.
2029         f.write("static const char * const vk_instance_extensions[] =\n{\n")
2030         for ext in self.registry.extensions:
2031             if ext["type"] != "instance":
2032                 continue
2034             f.write("    \"{0}\",\n".format(ext["name"]))
2035         f.write("};\n\n")
2037         f.write("BOOL wine_vk_device_extension_supported(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_device_extensions); i++)\n")
2041         f.write("    {\n")
2042         f.write("        if (strcmp(vk_device_extensions[i], name) == 0)\n")
2043         f.write("            return TRUE;\n")
2044         f.write("    }\n")
2045         f.write("    return FALSE;\n")
2046         f.write("}\n\n")
2048         f.write("BOOL wine_vk_instance_extension_supported(const char *name)\n")
2049         f.write("{\n")
2050         f.write("    unsigned int i;\n")
2051         f.write("    for (i = 0; i < ARRAY_SIZE(vk_instance_extensions); i++)\n")
2052         f.write("    {\n")
2053         f.write("        if (strcmp(vk_instance_extensions[i], name) == 0)\n")
2054         f.write("            return TRUE;\n")
2055         f.write("    }\n")
2056         f.write("    return FALSE;\n")
2057         f.write("}\n")
2059     def generate_thunks_h(self, f, prefix):
2060         self._generate_copyright(f)
2062         f.write("#ifndef __WINE_VULKAN_THUNKS_H\n")
2063         f.write("#define __WINE_VULKAN_THUNKS_H\n\n")
2065         f.write("#define WINE_VK_VERSION VK_API_VERSION_{0}_{1}\n\n".format(WINE_VK_VERSION[0], WINE_VK_VERSION[1]))
2067         # Generate prototypes for device and instance functions requiring a custom implementation.
2068         f.write("/* Functions for which we have custom implementations outside of the thunks. */\n")
2069         for vk_func in self.registry.funcs.values():
2070             if not vk_func.is_required() or vk_func.is_global_func() or vk_func.needs_thunk():
2071                 continue
2073             if vk_func.is_core_func():
2074                 f.write("{0};\n".format(vk_func.prototype("WINAPI", prefix="wine_")))
2075             else:
2076                 f.write("{0};\n".format(vk_func.prototype("WINAPI", prefix="wine_", postfix="DECLSPEC_HIDDEN")))
2077         f.write("\n")
2079         for struct in self.host_structs:
2080             f.write(struct.definition(align=False, conv=True, postfix="_host"))
2081         f.write("\n")
2083         f.write("/* For use by vkDevice and children */\n")
2084         f.write("struct vulkan_device_funcs\n{\n")
2085         for vk_func in self.registry.device_funcs:
2086             if not vk_func.is_required():
2087                 continue
2089             if not vk_func.needs_dispatch():
2090                 LOGGER.debug("skipping {0} in vulkan_device_funcs".format(vk_func.name))
2091                 continue
2093             if vk_func.needs_conversion():
2094                 f.write("#if defined(USE_STRUCT_CONVERSION)\n")
2095                 f.write("    {0};\n".format(vk_func.pfn(conv=True)))
2096                 f.write("#else\n")
2097                 f.write("    {0};\n".format(vk_func.pfn(conv=False)))
2098                 f.write("#endif\n")
2099             else:
2100                 f.write("    {0};\n".format(vk_func.pfn(conv=False)))
2101         f.write("};\n\n")
2103         f.write("/* For use by vkInstance and children */\n")
2104         f.write("struct vulkan_instance_funcs\n{\n")
2105         for vk_func in self.registry.instance_funcs:
2106             if not vk_func.is_required():
2107                 continue
2109             if not vk_func.needs_dispatch():
2110                 LOGGER.debug("skipping {0} in vulkan_instance_funcs".format(vk_func.name))
2111                 continue
2113             if vk_func.needs_conversion():
2114                 f.write("#if defined(USE_STRUCT_CONVERSION)\n")
2115                 f.write("    {0};\n".format(vk_func.pfn(conv=True)))
2116                 f.write("#else\n")
2117                 f.write("    {0};\n".format(vk_func.pfn(conv=False)))
2118                 f.write("#endif\n")
2119             else:
2120                 f.write("    {0};\n".format(vk_func.pfn(conv=False)))
2121         f.write("};\n\n")
2123         f.write("#define ALL_VK_DEVICE_FUNCS() \\\n")
2124         first = True
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 ALL_VK_DEVICE_FUNCS".format(vk_func.name))
2131                 continue
2133             if first:
2134                 f.write("    USE_VK_FUNC({0})".format(vk_func.name))
2135                 first = False
2136             else:
2137                 f.write(" \\\n    USE_VK_FUNC({0})".format(vk_func.name))
2138         f.write("\n\n")
2140         f.write("#define ALL_VK_INSTANCE_FUNCS() \\\n")
2141         first = True
2142         for vk_func in self.registry.instance_funcs:
2143             if not vk_func.is_required():
2144                 continue
2146             if not vk_func.needs_dispatch():
2147                 LOGGER.debug("skipping {0} in ALL_VK_INSTANCE_FUNCS".format(vk_func.name))
2148                 continue
2150             if first:
2151                 f.write("    USE_VK_FUNC({0})".format(vk_func.name))
2152                 first = False
2153             else:
2154                 f.write(" \\\n    USE_VK_FUNC({0})".format(vk_func.name))
2155         f.write("\n\n")
2157         f.write("#endif /* __WINE_VULKAN_THUNKS_H */\n")
2159     def generate_vulkan_h(self, f):
2160         self._generate_copyright(f)
2161         f.write("#ifndef __WINE_VULKAN_H\n")
2162         f.write("#define __WINE_VULKAN_H\n\n")
2164         f.write("#include <windef.h>\n")
2165         f.write("#include <stdint.h>\n\n")
2167         f.write("/* Define WINE_VK_HOST to get 'host' headers. */\n")
2168         f.write("#ifdef WINE_VK_HOST\n")
2169         f.write("#define VKAPI_CALL\n")
2170         f.write('#define WINE_VK_ALIGN(x)\n')
2171         f.write("#endif\n\n")
2173         f.write("#ifndef VKAPI_CALL\n")
2174         f.write("#define VKAPI_CALL __stdcall\n")
2175         f.write("#endif\n\n")
2177         f.write("#ifndef VKAPI_PTR\n")
2178         f.write("#define VKAPI_PTR VKAPI_CALL\n")
2179         f.write("#endif\n\n")
2181         f.write("#ifndef WINE_VK_ALIGN\n")
2182         f.write("#define WINE_VK_ALIGN DECLSPEC_ALIGN\n")
2183         f.write("#endif\n\n")
2185         # The overall strategy is to define independent constants and datatypes,
2186         # prior to complex structures and function calls to avoid forward declarations.
2187         for const in self.registry.consts:
2188             # For now just generate things we may not need. The amount of parsing needed
2189             # to get some of the info is tricky as you need to figure out which structure
2190             # references a certain constant.
2191             f.write(const.definition())
2192         f.write("\n")
2194         for define in self.registry.defines:
2195             f.write(define.definition())
2197         for handle in self.registry.handles:
2198             # For backward compatibility also create definitions for aliases.
2199             # These types normally don't get pulled in as we use the new types
2200             # even in legacy functions if they are aliases.
2201             if handle.is_required() or handle.is_alias():
2202                  f.write(handle.definition())
2203         f.write("\n")
2205         for base_type in self.registry.base_types:
2206             f.write(base_type.definition())
2207         f.write("\n")
2209         for bitmask in self.registry.bitmasks:
2210             f.write(bitmask.definition())
2211         f.write("\n")
2213         # Define enums, this includes values for some of the bitmask types as well.
2214         for enum in self.registry.enums.values():
2215             if enum.required:
2216                 f.write(enum.definition())
2218         for fp in self.registry.funcpointers:
2219             if fp.required:
2220                 f.write(fp.definition())
2221         f.write("\n")
2223         # This generates both structures and unions. Since structures
2224         # may depend on other structures/unions, we need a list of
2225         # decoupled structs.
2226         # Note: unions are stored in structs for dependency reasons,
2227         # see comment in parsing section.
2228         structs = VkStruct.decouple_structs(self.registry.structs)
2229         for struct in structs:
2230             LOGGER.debug("Generating struct: {0}".format(struct.name))
2231             f.write(struct.definition(align=True))
2233         for func in self.registry.funcs.values():
2234             if not func.is_required():
2235                 LOGGER.debug("Skipping PFN definition for: {0}".format(func.name))
2236                 continue
2238             f.write("typedef {0};\n".format(func.pfn(prefix="PFN", call_conv="VKAPI_PTR")))
2239         f.write("\n")
2241         f.write("#ifndef VK_NO_PROTOTYPES\n")
2242         for func in self.registry.funcs.values():
2243             if not func.is_required():
2244                 LOGGER.debug("Skipping API definition for: {0}".format(func.name))
2245                 continue
2247             LOGGER.debug("Generating API definition for: {0}".format(func.name))
2248             f.write("{0};\n".format(func.prototype(call_conv="VKAPI_CALL")))
2249         f.write("#endif /* VK_NO_PROTOTYPES */\n\n")
2251         f.write("#endif /* __WINE_VULKAN_H */\n")
2253     def generate_vulkan_driver_h(self, f):
2254         self._generate_copyright(f)
2255         f.write("#ifndef __WINE_VULKAN_DRIVER_H\n")
2256         f.write("#define __WINE_VULKAN_DRIVER_H\n\n")
2258         f.write("/* Wine internal vulkan driver version, needs to be bumped upon vulkan_funcs changes. */\n")
2259         f.write("#define WINE_VULKAN_DRIVER_VERSION {0}\n\n".format(DRIVER_VERSION))
2261         f.write("struct vulkan_funcs\n{\n")
2262         f.write("    /* Vulkan global functions. These are the only calls at this point a graphics driver\n")
2263         f.write("     * needs to provide. Other function calls will be provided indirectly by dispatch\n")
2264         f.write("     * tables part of dispatchable Vulkan objects such as VkInstance or vkDevice.\n")
2265         f.write("     */\n")
2267         for vk_func in self.registry.funcs.values():
2268             if not vk_func.is_driver_func():
2269                 continue
2271             pfn = vk_func.pfn()
2272             # Avoid PFN_vkVoidFunction in driver interface as Vulkan likes to put calling convention
2273             # stuff in there. For simplicity substitute with "void *".
2274             pfn = pfn.replace("PFN_vkVoidFunction", "void *")
2275             f.write("    {0};\n".format(pfn))
2276         f.write("};\n\n")
2278         f.write("extern const struct vulkan_funcs * CDECL __wine_get_vulkan_driver(HDC hdc, UINT version);\n\n")
2280         f.write("static inline void *get_vulkan_driver_device_proc_addr(\n")
2281         f.write("        const struct vulkan_funcs *vulkan_funcs, const char *name)\n{\n")
2282         f.write("    if (!name || name[0] != 'v' || name[1] != 'k') return NULL;\n\n")
2283         f.write("    name += 2;\n\n")
2284         for vk_func in self.registry.funcs.values():
2285             if vk_func.is_driver_func() and vk_func.is_device_func():
2286                 f.write('    if (!strcmp(name, "{0}"))\n'.format(vk_func.name[2:]))
2287                 f.write('        return vulkan_funcs->p_{0};\n'.format(vk_func.name))
2288         f.write("\n")
2289         f.write("    return NULL;\n}\n\n")
2291         f.write("static inline void *get_vulkan_driver_instance_proc_addr(\n")
2292         f.write("        const struct vulkan_funcs *vulkan_funcs, VkInstance instance, const char *name)\n{\n")
2293         f.write("    if (!name || name[0] != 'v' || name[1] != 'k') return NULL;\n\n")
2294         f.write("    name += 2;\n\n")
2295         for vk_func in self.registry.funcs.values():
2296             if vk_func.is_driver_func() and vk_func.is_global_func() and vk_func.name != "vkGetInstanceProcAddr":
2297                 f.write('    if (!strcmp(name, "{0}"))\n'.format(vk_func.name[2:]))
2298                 f.write('        return vulkan_funcs->p_{0};\n'.format(vk_func.name))
2299         f.write("\n")
2300         f.write("    if (!instance) return NULL;\n\n")
2301         for vk_func in self.registry.funcs.values():
2302             if vk_func.is_driver_func() and vk_func.is_instance_func():
2303                 f.write('    if (!strcmp(name, "{0}"))\n'.format(vk_func.name[2:]))
2304                 f.write('        return vulkan_funcs->p_{0};\n'.format(vk_func.name))
2305         f.write("\n")
2306         f.write("    name -= 2;\n\n")
2307         f.write("    return get_vulkan_driver_device_proc_addr(vulkan_funcs, name);\n}\n\n")
2309         f.write("#endif /* __WINE_VULKAN_DRIVER_H */\n")
2311     def generate_vulkan_spec(self, f):
2312         self._generate_copyright(f, spec_file=True)
2313         f.write("@ stdcall -private vk_icdGetInstanceProcAddr(ptr str) wine_vk_icdGetInstanceProcAddr\n")
2314         f.write("@ stdcall -private vk_icdNegotiateLoaderICDInterfaceVersion(ptr) wine_vk_icdNegotiateLoaderICDInterfaceVersion\n")
2315         f.write("@ cdecl -norelay native_vkGetInstanceProcAddrWINE(ptr str)\n")
2317         # Export symbols for all Vulkan Core functions.
2318         for func in self.registry.funcs.values():
2319             if not func.is_core_func():
2320                 continue
2322             # We support all Core functions except for VK_KHR_display* APIs.
2323             # Create stubs for unsupported Core functions.
2324             if func.is_required():
2325                 f.write(func.spec(prefix="wine_"))
2326             else:
2327                 f.write("@ stub {0}\n".format(func.name))
2329     def generate_vulkan_loader_spec(self, f):
2330         self._generate_copyright(f, spec_file=True)
2332         # Export symbols for all Vulkan Core functions.
2333         for func in self.registry.funcs.values():
2334             if not func.is_core_func():
2335                 continue
2337             # We support all Core functions except for VK_KHR_display* APIs.
2338             # Create stubs for unsupported Core functions.
2339             if func.is_required():
2340                 f.write(func.spec(symbol="winevulkan.wine_" + func.name))
2341             else:
2342                 f.write("@ stub {0}\n".format(func.name))
2345 class VkRegistry(object):
2346     def __init__(self, reg_filename):
2347         # Used for storage of type information.
2348         self.base_types = None
2349         self.bitmasks = None
2350         self.consts = None
2351         self.defines = None
2352         self.enums = None
2353         self.funcpointers = None
2354         self.handles = None
2355         self.structs = None
2357         # We aggregate all types in here for cross-referencing.
2358         self.funcs = {}
2359         self.types = {}
2361         self.version_regex = re.compile(
2362             r'^'
2363             r'VK_VERSION_'
2364             r'(?P<major>[0-9])'
2365             r'_'
2366             r'(?P<minor>[0-9])'
2367             r'$'
2368         )
2370         # Overall strategy for parsing the registry is to first
2371         # parse all type / function definitions. Then parse
2372         # features and extensions to decide which types / functions
2373         # to actually 'pull in' for code generation. For each type or
2374         # function call we want we set a member 'required' to True.
2375         tree = ET.parse(reg_filename)
2376         root = tree.getroot()
2377         self._parse_enums(root)
2378         self._parse_types(root)
2379         self._parse_commands(root)
2381         # Pull in any required types and functions.
2382         self._parse_features(root)
2383         self._parse_extensions(root)
2385         self.copyright = root.find('./comment').text
2387     def _is_feature_supported(self, feature):
2388         version = self.version_regex.match(feature)
2389         if not version:
2390             return True
2392         version = tuple(map(int, version.group('major', 'minor')))
2393         return version <= WINE_VK_VERSION
2395     def _mark_command_required(self, command):
2396         """ Helper function to mark a certain command and the datatypes it needs as required."""
2397         def mark_bitmask_dependencies(bitmask, types):
2398             if bitmask.requires is not None:
2399                 types[bitmask.requires]["data"].required = True
2401         def mark_funcpointer_dependencies(fp, types):
2402             for m in fp.members:
2403                 type_info = types[m.type]
2405                 # Complex types have a matching definition e.g. VkStruct.
2406                 # Not needed for base types such as uint32_t.
2407                 if "data" in type_info:
2408                     types[m.type]["data"].required = True
2410         def mark_struct_dependencies(struct, types):
2411              for m in struct:
2412                 type_info = types[m.type]
2414                 # Complex types have a matching definition e.g. VkStruct.
2415                 # Not needed for base types such as uint32_t.
2416                 if "data" in type_info:
2417                     types[m.type]["data"].required = True
2419                 if type_info["category"] == "struct":
2420                     # Yay, recurse
2421                     mark_struct_dependencies(type_info["data"], types)
2422                 elif type_info["category"] == "funcpointer":
2423                     mark_funcpointer_dependencies(type_info["data"], types)
2424                 elif type_info["category"] == "bitmask":
2425                     mark_bitmask_dependencies(type_info["data"], types)
2427         func = self.funcs[command]
2428         func.required = True
2430         # Pull in return type
2431         if func.type != "void":
2432             self.types[func.type]["data"].required = True
2434         # Analyze parameter dependencies and pull in any type needed.
2435         for p in func.params:
2436             type_info = self.types[p.type]
2438             # Check if we are dealing with a complex type e.g. VkEnum, VkStruct and others.
2439             if "data" not in type_info:
2440                 continue
2442             # Mark the complex type as required.
2443             type_info["data"].required = True
2444             if type_info["category"] == "struct":
2445                 struct = type_info["data"]
2446                 mark_struct_dependencies(struct, self.types)
2448         if func.is_alias():
2449             func.alias.required = True
2451     def _parse_commands(self, root):
2452         """ Parse command section containing the Vulkan function calls. """
2453         funcs = {}
2454         commands = root.findall("./commands/")
2456         # As of Vulkan 1.1, various extensions got promoted to Core.
2457         # The old commands (e.g. KHR) are available for backwards compatibility
2458         # and are marked in vk.xml as 'alias' to the non-extension type.
2459         # The registry likes to avoid data duplication, so parameters and other
2460         # metadata need to be looked up from the Core command.
2461         # We parse the alias commands in a second pass.
2462         alias_commands = []
2463         for command in commands:
2464             alias_name = command.attrib.get("alias")
2465             if alias_name:
2466                 alias_commands.append(command)
2467                 continue
2469             func = VkFunction.from_xml(command, self.types)
2470             funcs[func.name] = func
2472         for command in alias_commands:
2473             alias_name = command.attrib.get("alias")
2474             alias = funcs[alias_name]
2475             func = VkFunction.from_alias(command, alias)
2476             funcs[func.name] = func
2478         # To make life easy for the code generation, separate all function
2479         # calls out in the 3 types of Vulkan functions: device, global and instance.
2480         device_funcs = []
2481         global_funcs = []
2482         instance_funcs = []
2483         for func in funcs.values():
2484             if func.is_device_func():
2485                 device_funcs.append(func)
2486             elif func.is_global_func():
2487                 global_funcs.append(func)
2488             else:
2489                 instance_funcs.append(func)
2491         # Sort function lists by name and store them.
2492         self.device_funcs = sorted(device_funcs, key=lambda func: func.name)
2493         self.global_funcs = sorted(global_funcs, key=lambda func: func.name)
2494         self.instance_funcs = sorted(instance_funcs, key=lambda func: func.name)
2496         # The funcs dictionary is used as a convenient way to lookup function
2497         # calls when needed e.g. to adjust member variables.
2498         self.funcs = OrderedDict(sorted(funcs.items()))
2500     def _parse_enums(self, root):
2501         """ Parse enums section or better described as constants section. """
2502         enums = {}
2503         self.consts = []
2504         for enum in root.findall("./enums"):
2505             name = enum.attrib.get("name")
2506             _type = enum.attrib.get("type")
2508             if _type in ("enum", "bitmask"):
2509                 enums[name] = VkEnum.from_xml(enum)
2510             else:
2511                 # If no type is set, we are dealing with API constants.
2512                 for value in enum.findall("enum"):
2513                     # If enum is an alias, set the value to the alias name.
2514                     # E.g. VK_LUID_SIZE_KHR is an alias to VK_LUID_SIZE.
2515                     alias = value.attrib.get("alias")
2516                     if alias:
2517                         self.consts.append(VkConstant(value.attrib.get("name"), alias))
2518                     else:
2519                         self.consts.append(VkConstant(value.attrib.get("name"), value.attrib.get("value")))
2521         self.enums = OrderedDict(sorted(enums.items()))
2523     def _process_require_enum(self, enum_elem, ext=None):
2524         if "extends" in enum_elem.keys():
2525             enum = self.types[enum_elem.attrib["extends"]]["data"]
2527             if "bitpos" in enum_elem.keys():
2528                 # We need to add an extra value to an existing enum type.
2529                 # E.g. VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG to VkFormatFeatureFlagBits.
2530                 enum.add(VkEnumValue(enum_elem.attrib["name"], 1 << int(enum_elem.attrib["bitpos"]), hex=True))
2532             elif "offset" in enum_elem.keys():
2533                 # Extensions promoted to Core, have the extension number as part
2534                 # of the enum value. Else retrieve from the extension tag.
2535                 if enum_elem.attrib.get("extnumber"):
2536                     ext_number = int(enum_elem.attrib.get("extnumber"))
2537                 else:
2538                     ext_number = int(ext.attrib["number"])
2539                 offset = int(enum_elem.attrib["offset"])
2540                 value = EXT_BASE + (ext_number - 1) * EXT_BLOCK_SIZE + offset
2542                 # Deal with negative values.
2543                 direction = enum_elem.attrib.get("dir")
2544                 if direction is not None:
2545                     value = -value
2547                 enum.add(VkEnumValue(enum_elem.attrib["name"], value))
2549             elif "value" in enum_elem.keys():
2550                 enum.add(VkEnumValue(enum_elem.attrib["name"], int(enum_elem.attrib["value"])))
2552         elif "value" in enum_elem.keys():
2553             self.consts.append(VkConstant(enum_elem.attrib["name"], enum_elem.attrib["value"]))
2555     def _parse_extensions(self, root):
2556         """ Parse extensions section and pull in any types and commands for this extensioin. """
2557         extensions = []
2558         exts = root.findall("./extensions/extension")
2559         for ext in exts:
2560             ext_name = ext.attrib["name"]
2562             # Set extension name on any functions calls part of this extension as we
2563             # were not aware of the name during initial parsing.
2564             commands = ext.findall("require/command")
2565             for command in commands:
2566                 cmd_name = command.attrib["name"]
2567                 self.funcs[cmd_name].extensions.append(ext_name)
2569             # Some extensions are not ready or have numbers reserved as a place holder.
2570             if ext.attrib["supported"] == "disabled":
2571                 LOGGER.debug("Skipping disabled extension: {0}".format(ext_name))
2572                 continue
2574             # Disable highly experimental extensions as the APIs are unstable and can
2575             # change between minor Vulkan revisions until API is final and becomes KHR
2576             # or NV.
2577             if "KHX" in ext_name or "NVX" in ext_name:
2578                 LOGGER.debug("Skipping experimental extension: {0}".format(ext_name))
2579                 continue
2581             # Instance extensions often require a custom implementation, so filter.
2582             ext_type = ext.attrib["type"]
2583             if ext_type == "instance" and not ext_name in SUPPORTED_INSTANCE_EXTENSIONS:
2584                 LOGGER.debug("Skipping instance extension: {0}".format(ext_name))
2585                 continue
2587             # We disable some extensions as either we haven't implemented
2588             # support yet or because they are for platforms other than win32.
2589             if ext_name in BLACKLISTED_EXTENSIONS:
2590                 LOGGER.debug("Skipping blacklisted extension: {0}".format(ext_name))
2591                 continue
2592             elif "requires" in ext.attrib:
2593                 # Check if this extension builds on top of another blacklisted
2594                 # extension.
2595                 requires = ext.attrib["requires"].split(",")
2596                 if len(set(requires).intersection(BLACKLISTED_EXTENSIONS)) > 0:
2597                     continue
2599             LOGGER.debug("Loading extension: {0}".format(ext_name))
2601             # Extensions can define one or more require sections each requiring
2602             # different features (e.g. Vulkan 1.1). Parse each require section
2603             # separately, so we can skip sections we don't want.
2604             for require in ext.findall("require"):
2605                 # Extensions can add enum values to Core / extension enums, so add these.
2606                 for enum_elem in require.findall("enum"):
2607                     self._process_require_enum(enum_elem, ext)
2609                 for t in require.findall("type"):
2610                     type_info = self.types[t.attrib["name"]]["data"]
2611                     if type_info.is_alias():
2612                         type_info = type_info.alias
2613                     type_info.required = True
2615                 feature = require.attrib.get("feature")
2616                 if feature and not self._is_feature_supported(feature):
2617                     continue
2619                 # Pull in any commands we need. We infer types to pull in from the command
2620                 # as well.
2621                 for command in require.findall("command"):
2622                     cmd_name = command.attrib["name"]
2623                     self._mark_command_required(cmd_name)
2625             # Store a list with extensions.
2626             ext_info = {"name" : ext_name, "type" : ext_type}
2627             extensions.append(ext_info)
2629         # Sort in alphabetical order.
2630         self.extensions = sorted(extensions, key=lambda ext: ext["name"])
2632     def _parse_features(self, root):
2633         """ Parse the feature section, which describes Core commands and types needed. """
2635         for feature in root.findall("./feature"):
2636             feature_name = feature.attrib["name"]
2637             for require in feature.findall("require"):
2638                 LOGGER.info("Including features for {0}".format(require.attrib.get("comment")))
2639                 for tag in require:
2640                     if tag.tag == "comment":
2641                         continue
2642                     elif tag.tag == "command":
2643                         if not self._is_feature_supported(feature_name):
2644                             continue
2645                         name = tag.attrib["name"]
2646                         self._mark_command_required(name)
2647                     elif tag.tag == "enum":
2648                         self._process_require_enum(tag)
2649                     elif tag.tag == "type":
2650                         name = tag.attrib["name"]
2652                         # Skip pull in for vk_platform.h for now.
2653                         if name == "vk_platform":
2654                             continue
2656                         type_info = self.types[name]
2657                         type_info["data"].required = True
2659     def _parse_types(self, root):
2660         """ Parse types section, which contains all data types e.g. structs, typedefs etcetera. """
2661         types = root.findall("./types/type")
2663         base_types = []
2664         bitmasks = []
2665         defines = []
2666         funcpointers = []
2667         handles = []
2668         structs = []
2670         alias_types = []
2671         for t in types:
2672             type_info = {}
2673             type_info["category"] = t.attrib.get("category", None)
2675             # We parse aliases in a second pass when we know more.
2676             alias = t.attrib.get("alias")
2677             if alias:
2678                 LOGGER.debug("Alias found: {0}".format(alias))
2679                 alias_types.append(t)
2680                 continue
2682             if type_info["category"] in ["include"]:
2683                 continue
2685             if type_info["category"] == "basetype":
2686                 name = t.find("name").text
2687                 _type = t.find("type").text
2688                 basetype = VkBaseType(name, _type)
2689                 base_types.append(basetype)
2690                 type_info["data"] = basetype
2692             if type_info["category"] == "bitmask":
2693                 name = t.find("name").text
2694                 _type = t.find("type").text
2696                 # Most bitmasks have a requires attribute used to pull in
2697                 # required '*FlagBits" enum.
2698                 requires = t.attrib.get("requires")
2699                 bitmask = VkBaseType(name, _type, requires=requires)
2700                 bitmasks.append(bitmask)
2701                 type_info["data"] = bitmask
2703             if type_info["category"] == "define":
2704                 define = VkDefine.from_xml(t)
2705                 defines.append(define)
2706                 type_info["data"] = define
2708             if type_info["category"] == "enum":
2709                 name = t.attrib.get("name")
2710                 # The type section only contains enum names, not the actual definition.
2711                 # Since we already parsed the enum before, just link it in.
2712                 try:
2713                     type_info["data"] = self.enums[name]
2714                 except KeyError as e:
2715                     # Not all enums seem to be defined yet, typically that's for
2716                     # ones ending in 'FlagBits' where future extensions may add
2717                     # definitions.
2718                     type_info["data"] = None
2720             if type_info["category"] == "funcpointer":
2721                 funcpointer = VkFunctionPointer.from_xml(t)
2722                 funcpointers.append(funcpointer)
2723                 type_info["data"] = funcpointer
2725             if type_info["category"] == "handle":
2726                 handle = VkHandle.from_xml(t)
2727                 handles.append(handle)
2728                 type_info["data"] = handle
2730             if type_info["category"] in ["struct", "union"]:
2731                 # We store unions among structs as some structs depend
2732                 # on unions. The types are very similar in parsing and
2733                 # generation anyway. The official Vulkan scripts use
2734                 # a similar kind of hack.
2735                 struct = VkStruct.from_xml(t)
2736                 structs.append(struct)
2737                 type_info["data"] = struct
2739             # Name is in general within a name tag else it is an optional
2740             # attribute on the type tag.
2741             name_elem = t.find("name")
2742             if name_elem is not None:
2743                 type_info["name"] = name_elem.text
2744             else:
2745                 type_info["name"] = t.attrib.get("name", None)
2747             # Store all type data in a shared dictionary, so we can easily
2748             # look up information for a given type. There are no duplicate
2749             # names.
2750             self.types[type_info["name"]] = type_info
2752         # Second pass for alias types, so we can retrieve all data from
2753         # the aliased object.
2754         for t in alias_types:
2755             type_info = {}
2756             type_info["category"] = t.attrib.get("category")
2757             type_info["name"] = t.attrib.get("name")
2759             alias = t.attrib.get("alias")
2761             if type_info["category"] == "bitmask":
2762                 bitmask = VkBaseType(type_info["name"], alias, alias=self.types[alias]["data"])
2763                 bitmasks.append(bitmask)
2764                 type_info["data"] = bitmask
2766             if type_info["category"] == "enum":
2767                 enum = VkEnum.from_alias(t, self.types[alias]["data"])
2768                 type_info["data"] = enum
2769                 self.enums[enum.name] = enum
2771             if type_info["category"] == "handle":
2772                 handle = VkHandle.from_alias(t, self.types[alias]["data"])
2773                 handles.append(handle)
2774                 type_info["data"] = handle
2776             if type_info["category"] == "struct":
2777                 struct = VkStruct.from_alias(t, self.types[alias]["data"])
2778                 structs.append(struct)
2779                 type_info["data"] = struct
2781             self.types[type_info["name"]] = type_info
2783         # We need detailed type information during code generation
2784         # on structs for alignment reasons. Unfortunately structs
2785         # are parsed among other types, so there is no guarantee
2786         # that any types needed have been parsed already, so set
2787         # the data now.
2788         for struct in structs:
2789             struct.set_type_info(self.types)
2791             for structextend in struct.structextends:
2792                 s = self.types[structextend]["data"]
2793                 s.struct_extensions.append(struct)
2795         # Guarantee everything is sorted, so code generation doesn't have
2796         # to deal with this.
2797         self.base_types = sorted(base_types, key=lambda base_type: base_type.name)
2798         self.bitmasks = sorted(bitmasks, key=lambda bitmask: bitmask.name)
2799         self.defines = defines
2800         self.enums = OrderedDict(sorted(self.enums.items()))
2801         self.funcpointers = sorted(funcpointers, key=lambda fp: fp.name)
2802         self.handles = sorted(handles, key=lambda handle: handle.name)
2803         self.structs = sorted(structs, key=lambda struct: struct.name)
2805 def set_working_directory():
2806     path = os.path.abspath(__file__)
2807     path = os.path.dirname(path)
2808     os.chdir(path)
2810 def download_vk_xml(filename):
2811     url = "https://raw.github.com/KhronosGroup/Vulkan-Docs/v{0}/xml/vk.xml".format(VK_XML_VERSION)
2812     if not os.path.isfile(filename):
2813         urllib.request.urlretrieve(url, filename)
2815 def main():
2816     parser = argparse.ArgumentParser()
2817     parser.add_argument("-v", "--verbose", action="count", default=0, help="increase output verbosity")
2819     args = parser.parse_args()
2820     if args.verbose == 0:
2821         LOGGER.setLevel(logging.WARNING)
2822     elif args.verbose == 1:
2823         LOGGER.setLevel(logging.INFO)
2824     else: # > 1
2825         LOGGER.setLevel(logging.DEBUG)
2827     set_working_directory()
2829     vk_xml = "vk-{0}.xml".format(VK_XML_VERSION)
2830     download_vk_xml(vk_xml)
2831     registry = VkRegistry(vk_xml)
2832     generator = VkGenerator(registry)
2834     with open(WINE_VULKAN_H, "w") as f:
2835         generator.generate_vulkan_h(f)
2837     with open(WINE_VULKAN_DRIVER_H, "w") as f:
2838         generator.generate_vulkan_driver_h(f)
2840     with open(WINE_VULKAN_THUNKS_H, "w") as f:
2841         generator.generate_thunks_h(f, "wine_")
2843     with open(WINE_VULKAN_THUNKS_C, "w") as f:
2844         generator.generate_thunks_c(f, "wine_")
2846     with open(WINE_VULKAN_SPEC, "w") as f:
2847         generator.generate_vulkan_spec(f)
2849     with open(WINE_VULKAN_LOADER_SPEC, "w") as f:
2850         generator.generate_vulkan_loader_spec(f)
2852 if __name__ == "__main__":
2853     main()