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