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.178"
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"
78 WINE_VULKAN_LOADER_THUNKS_C = "loader_thunks.c"
79 WINE_VULKAN_LOADER_THUNKS_H = "loader_thunks.h"
81 # Extension enum values start at a certain offset (EXT_BASE).
82 # Relative to the offset each extension has a block (EXT_BLOCK_SIZE)
84 # Start for a given extension is:
85 # EXT_BASE + (extension_number-1) * EXT_BLOCK_SIZE
89 UNSUPPORTED_EXTENSIONS = [
91 "VK_EXT_headless_surface", # Needs WSI work.
92 "VK_KHR_display", # Needs WSI work.
93 "VK_KHR_surface_protected_capabilities",
96 "VK_AMD_display_native_hdr",
97 "VK_EXT_full_screen_exclusive",
98 "VK_EXT_hdr_metadata", # Needs WSI work.
99 "VK_EXT_pipeline_creation_feedback",
100 "VK_GOOGLE_display_timing",
101 "VK_KHR_external_fence_win32",
102 "VK_KHR_external_memory_win32",
103 "VK_KHR_external_semaphore_win32",
104 # Relates to external_semaphore and needs type conversions in bitflags.
105 "VK_KHR_shared_presentable_image", # Needs WSI work.
106 "VK_KHR_win32_keyed_mutex",
108 # Extensions for other platforms
109 "VK_EXT_external_memory_dma_buf",
110 "VK_EXT_image_drm_format_modifier",
111 "VK_KHR_external_fence_fd",
112 "VK_KHR_external_memory_fd",
113 "VK_KHR_external_semaphore_fd",
115 # Extensions which require callback handling
116 "VK_EXT_device_memory_report",
118 # Deprecated extensions
119 "VK_NV_external_memory_capabilities",
120 "VK_NV_external_memory_win32",
123 # The Vulkan loader provides entry-points for core functionality and important
124 # extensions. Based on vulkan-1.def this amounts to WSI extensions on 1.0.51.
127 "VK_KHR_display_swapchain",
128 "VK_KHR_get_surface_capabilities2",
131 "VK_KHR_win32_surface",
134 # Some experimental extensions are used by shipping applications so their API is extremely unlikely
135 # to change in a backwards-incompatible way. Allow translation of those extensions with WineVulkan.
136 ALLOWED_X_EXTENSIONS = [
137 "VK_NVX_binary_import",
138 "VK_NVX_image_view_handle",
141 # Functions part of our winevulkan graphics driver interface.
142 # DRIVER_VERSION should be bumped on any change to driver interface
143 # in FUNCTION_OVERRIDES
146 class ThunkType(Enum):
151 # Table of functions for which we have a special implementation.
152 # These are regular device / instance functions for which we need
153 # to do more work compared to a regular thunk or because they are
154 # part of the driver interface.
155 # - dispatch set whether we need a function pointer in the device
156 # / instance dispatch table.
157 # - driver sets whether the API is part of the driver interface.
158 # - thunk sets whether to create a thunk in vulkan_thunks.c.
159 # - NONE means there's a fully custom implementation.
160 # - PUBLIC means the implementation is fully auto generated.
161 # - PRIVATE thunks can be used in custom implementations for
163 # - loader_thunk sets whether to create a thunk for unix_funcs.
164 FUNCTION_OVERRIDES = {
166 "vkCreateInstance" : {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE},
167 "vkEnumerateInstanceExtensionProperties" : {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE},
168 "vkEnumerateInstanceLayerProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.NONE},
169 "vkEnumerateInstanceVersion": {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE},
170 "vkGetInstanceProcAddr": {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.NONE},
173 "vkCreateDevice" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
174 "vkDestroyInstance" : {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE },
175 "vkEnumerateDeviceExtensionProperties" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
176 "vkEnumerateDeviceLayerProperties": {"dispatch": True, "driver": False, "thunk": ThunkType.NONE},
177 "vkEnumeratePhysicalDeviceGroups" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
178 "vkEnumeratePhysicalDevices" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
179 "vkGetPhysicalDeviceExternalBufferProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
180 "vkGetPhysicalDeviceExternalFenceProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
181 "vkGetPhysicalDeviceExternalSemaphoreProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
182 "vkGetPhysicalDeviceImageFormatProperties2" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE},
183 "vkGetPhysicalDeviceProperties2" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PUBLIC, "loader_thunk" : ThunkType.PRIVATE},
184 "vkGetPhysicalDeviceProperties2KHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PUBLIC, "loader_thunk" : ThunkType.PRIVATE},
187 "vkAllocateCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
188 "vkCreateCommandPool" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
189 "vkDestroyCommandPool" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
190 "vkDestroyDevice" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
191 "vkFreeCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
192 "vkGetDeviceProcAddr" : {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.NONE},
193 "vkGetDeviceQueue" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
194 "vkGetDeviceQueue2" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
197 "vkDestroySurfaceKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.NONE},
198 "vkGetPhysicalDeviceSurfaceSupportKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
199 "vkGetPhysicalDeviceSurfaceCapabilitiesKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PRIVATE},
200 "vkGetPhysicalDeviceSurfaceFormatsKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
201 "vkGetPhysicalDeviceSurfacePresentModesKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
203 # VK_KHR_get_surface_capabilities2
204 "vkGetPhysicalDeviceSurfaceCapabilities2KHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PRIVATE},
205 "vkGetPhysicalDeviceSurfaceFormats2KHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
207 # VK_KHR_win32_surface
208 "vkCreateWin32SurfaceKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.NONE},
209 "vkGetPhysicalDeviceWin32PresentationSupportKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
212 "vkCreateSwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
213 "vkDestroySwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
214 "vkGetSwapchainImagesKHR": {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
215 "vkQueuePresentKHR": {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
217 # VK_KHR_external_fence_capabilities
218 "vkGetPhysicalDeviceExternalFencePropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
220 # VK_KHR_external_memory_capabilities
221 "vkGetPhysicalDeviceExternalBufferPropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
222 "vkGetPhysicalDeviceImageFormatProperties2KHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE},
224 # VK_KHR_external_semaphore_capabilities
225 "vkGetPhysicalDeviceExternalSemaphorePropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
227 # VK_KHR_device_group_creation
228 "vkEnumeratePhysicalDeviceGroupsKHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
230 # VK_KHR_device_group
231 "vkGetDeviceGroupSurfacePresentModesKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
232 "vkGetPhysicalDevicePresentRectanglesKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
234 # VK_EXT_private_data
235 "vkGetPrivateDataEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
236 "vkSetPrivateDataEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
238 # VK_EXT_calibrated_timestamps
239 "vkGetPhysicalDeviceCalibrateableTimeDomainsEXT" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
240 "vkGetCalibratedTimestampsEXT" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
243 "vkCreateDebugUtilsMessengerEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
244 "vkDestroyDebugUtilsMessengerEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
245 "vkSubmitDebugUtilsMessageEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.PRIVATE},
246 "vkSetDebugUtilsObjectTagEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.PRIVATE},
247 "vkSetDebugUtilsObjectNameEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.PRIVATE},
249 # VK_EXT_debug_report
250 "vkCreateDebugReportCallbackEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
251 "vkDestroyDebugReportCallbackEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
252 "vkDebugReportMessageEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
254 # VK_EXT_debug_marker
255 "vkDebugMarkerSetObjectNameEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.PRIVATE},
256 "vkDebugMarkerSetObjectTagEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.PRIVATE},
259 STRUCT_CHAIN_CONVERSIONS = [
260 "VkDeviceCreateInfo",
261 "VkInstanceCreateInfo",
265 class Direction(Enum):
266 """ Parameter direction: input, output, input_output. """
272 class VkBaseType(object):
273 def __init__(self, name, _type, alias=None, requires=None):
274 """ Vulkan base type class.
276 VkBaseType is mostly used by Vulkan to define its own
277 base types like VkFlags through typedef out of e.g. uint32_t.
280 name (:obj:'str'): Name of the base type.
281 _type (:obj:'str'): Underlying type
282 alias (bool): type is an alias or not.
283 requires (:obj:'str', optional): Other types required.
284 Often bitmask values pull in a *FlagBits type.
289 self.requires = requires
290 self.required = False
292 def definition(self):
293 # Definition is similar for alias or non-alias as type
294 # is already set to alias.
295 if not self.type is None:
296 return "typedef {0} {1};\n".format(self.type, self.name)
298 return "struct {0};\n".format(self.name)
301 return bool(self.alias)
304 class VkConstant(object):
305 def __init__(self, name, value):
309 def definition(self):
310 text = "#define {0} {1}\n".format(self.name, self.value)
314 class VkDefine(object):
315 def __init__(self, name, value):
320 def from_xml(define):
321 name_elem = define.find("name")
323 if name_elem is None:
324 # <type category="define" name="some_name">some_value</type>
325 name = define.attrib.get("name")
327 # We override behavior of VK_USE_64_BIT_PTR_DEFINES as the default non-dispatchable handle
328 # definition various between 64-bit (uses pointers) and 32-bit (uses uint64_t).
329 # This complicates TRACEs in the thunks, so just use uint64_t.
330 if name == "VK_USE_64_BIT_PTR_DEFINES":
331 value = "#define VK_USE_64_BIT_PTR_DEFINES 0"
334 return VkDefine(name, value)
336 # With a name element the structure is like:
337 # <type category="define"><name>some_name</name>some_value</type>
338 name = name_elem.text
340 # Perform minimal parsing for Vulkan constants, which we don't need, but are referenced
341 # elsewhere in vk.xml.
342 # - VK_API_VERSION is a messy, deprecated constant and we don't want generate code for it.
343 # - AHardwareBuffer/ANativeWindow are forward declarations for Android types, which leaked
344 # into the define region.
345 if name in ["VK_API_VERSION", "AHardwareBuffer", "ANativeWindow", "CAMetalLayer"]:
346 return VkDefine(name, None)
348 # The body of the define is basically unstructured C code. It is not meant for easy parsing.
349 # Some lines contain deprecated values or comments, which we try to filter out.
351 for line in define.text.splitlines():
352 # Skip comments or deprecated values.
359 if child.tail is not None:
360 # Split comments for VK_API_VERSION_1_0 / VK_API_VERSION_1_1
361 if "//" in child.tail:
362 value += child.tail.split("//")[0]
366 return VkDefine(name, value.rstrip(' '))
368 def definition(self):
369 if self.value is None:
372 # Nothing to do as the value was already put in the right form during parsing.
373 return "{0}\n".format(self.value)
376 class VkEnum(object):
377 def __init__(self, name, bitwidth, alias=None):
378 if not bitwidth in [32, 64]:
379 LOGGER.error("unknown bitwidth {0} for {1}".format(bitwidth, name))
381 self.bitwidth = bitwidth
382 self.values = [] if alias == None else alias.values
383 self.required = False
388 def from_alias(enum, alias):
389 name = enum.attrib.get("name")
390 aliasee = VkEnum(name, alias.bitwidth, alias=alias)
392 alias.add_aliased_by(aliasee)
397 name = enum.attrib.get("name")
398 bitwidth = int(enum.attrib.get("bitwidth", "32"))
399 result = VkEnum(name, bitwidth)
401 for v in enum.findall("enum"):
402 value_name = v.attrib.get("name")
403 # Value is either a value or a bitpos, only one can exist.
404 value = v.attrib.get("value")
405 alias_name = v.attrib.get("alias")
407 result.create_alias(value_name, alias_name)
409 result.create_value(value_name, value)
412 result.create_bitpos(value_name, int(v.attrib.get("bitpos")))
415 # vulkan.h contains a *_MAX_ENUM value set to 32-bit at the time of writing,
416 # which is to prepare for extensions as they can add values and hence affect
417 # the size definition.
418 max_name = re.sub(r'([0-9a-z_])([A-Z0-9])',r'\1_\2', name).upper() + "_MAX_ENUM"
419 result.create_value(max_name, "0x7fffffff")
423 def create_alias(self, name, alias_name):
424 """ Create an aliased value for this enum """
425 # Older GCC versions need a literal to initialize a static const uint64_t
426 # which is what we use for 64bit bitmasks.
427 if self.bitwidth == 64:
428 alias = next(x for x in self.values if x.name == alias_name)
429 self.add(VkEnumValue(name, self.bitwidth, value=alias.value, hex=alias.hex, alias=alias_name))
431 self.add(VkEnumValue(name, self.bitwidth, alias=alias_name))
433 def create_value(self, name, value):
434 """ Create a new value for this enum """
435 # Some values are in hex form. We want to preserve the hex representation
436 # at least when we convert back to a string. Internally we want to use int.
438 self.add(VkEnumValue(name, self.bitwidth, value=int(value, 0), hex=hex))
440 def create_bitpos(self, name, pos):
441 """ Create a new bitmask value for this enum """
442 self.add(VkEnumValue(name, self.bitwidth, value=(1 << pos), hex=True))
444 def add(self, value):
445 """ Add a value to enum. """
447 # Extensions can add new enum values. When an extension is promoted to Core
448 # the registry defines the value twice once for old extension and once for
449 # new Core features. Add the duplicate if it's explicitly marked as an
450 # alias, otherwise ignore it.
451 for v in self.values:
452 if not value.is_alias() and v.value == value.value:
453 LOGGER.debug("Adding duplicate enum value {0} to {1}".format(v, self.name))
455 # Avoid adding duplicate aliases multiple times
456 if not any(x.name == value.name for x in self.values):
457 self.values.append(value)
459 def definition(self):
463 default_value = 0x7ffffffe if self.bitwidth == 32 else 0xfffffffffffffffe
465 # Print values sorted, values can have been added in a random order.
466 values = sorted(self.values, key=lambda value: value.value if value.value is not None else default_value)
468 if self.bitwidth == 32:
469 text = "typedef enum {0}\n{{\n".format(self.name)
471 text += " {0},\n".format(value.definition())
472 text += "}} {0};\n".format(self.name)
473 elif self.bitwidth == 64:
474 text = "typedef VkFlags64 {0};\n\n".format(self.name)
476 text += "static const {0} {1};\n".format(self.name, value.definition())
478 for aliasee in self.aliased_by:
479 text += "typedef {0} {1};\n".format(self.name, aliasee.name)
485 return bool(self.alias)
487 def add_aliased_by(self, aliasee):
488 self.aliased_by.append(aliasee)
491 class VkEnumValue(object):
492 def __init__(self, name, bitwidth, value=None, hex=False, alias=None):
494 self.bitwidth = bitwidth
500 postfix = "ull" if self.bitwidth == 64 else ""
501 if self.is_alias() and self.value == None:
502 return "{0}={1}".format(self.name, self.alias)
503 return "{0}={1}{2}".format(self.name, self.value, postfix)
505 def definition(self):
506 """ Convert to text definition e.g. VK_FOO = 1 """
507 postfix = "ull" if self.bitwidth == 64 else ""
508 if self.is_alias() and self.value == None:
509 return "{0} = {1}".format(self.name, self.alias)
511 # Hex is commonly used for FlagBits and sometimes within
512 # a non-FlagBits enum for a bitmask value as well.
514 return "{0} = 0x{1:08x}{2}".format(self.name, self.value, postfix)
516 return "{0} = {1}{2}".format(self.name, self.value, postfix)
519 return self.alias is not None
522 class VkFunction(object):
523 def __init__(self, _type=None, name=None, params=[], extensions=[], alias=None):
530 # For some functions we need some extra metadata from FUNCTION_OVERRIDES.
531 func_info = FUNCTION_OVERRIDES.get(self.name, None)
532 self.dispatch = func_info["dispatch"] if func_info else True
533 self.driver = func_info["driver"] if func_info else False
534 self.thunk_type = func_info["thunk"] if func_info else ThunkType.PUBLIC
535 self.loader_thunk_type = func_info["loader_thunk"] if func_info and "loader_thunk" in func_info else ThunkType.PUBLIC
537 # Required is set while parsing which APIs and types are required
538 # and is used by the code generation.
539 self.required = True if func_info else False
542 def from_alias(command, alias):
543 """ Create VkFunction from an alias command.
546 command: xml data for command
547 alias (VkFunction): function to use as a base for types / parameters.
552 func_name = command.attrib.get("name")
553 func_type = alias.type
554 params = alias.params
556 return VkFunction(_type=func_type, name=func_name, params=params, alias=alias)
559 def from_xml(command, types):
560 proto = command.find("proto")
561 func_name = proto.find("name").text
562 func_type = proto.find("type").text
565 for param in command.findall("param"):
566 vk_param = VkParam.from_xml(param, types)
567 params.append(vk_param)
569 return VkFunction(_type=func_type, name=func_name, params=params)
571 def get_conversions(self):
572 """ Get a list of conversion functions required for this function if any.
573 Parameters which are structures may require conversion between win32
574 and the host platform. This function returns a list of conversions
579 for param in self.params:
580 convs = param.get_conversions()
581 if convs is not None:
582 conversions.extend(convs)
587 return bool(self.alias)
589 def is_core_func(self):
590 """ Returns whether the function is a Vulkan core function.
591 Core functions are APIs defined by the Vulkan spec to be part of the
592 Core API as well as several KHR WSI extensions.
595 if not self.extensions:
598 return any(ext in self.extensions for ext in CORE_EXTENSIONS)
600 def is_device_func(self):
601 # If none of the other, it must be a device function
602 return not self.is_global_func() and not self.is_instance_func() and not self.is_phys_dev_func()
604 def is_driver_func(self):
605 """ Returns if function is part of Wine driver interface. """
608 def is_global_func(self):
609 # Treat vkGetInstanceProcAddr as a global function as it
610 # can operate with NULL for vkInstance.
611 if self.name == "vkGetInstanceProcAddr":
613 # Global functions are not passed a dispatchable object.
614 elif self.params[0].is_dispatchable():
618 def is_instance_func(self):
619 # Instance functions are passed VkInstance.
620 if self.params[0].type == "VkInstance":
624 def is_phys_dev_func(self):
625 # Physical device functions are passed VkPhysicalDevice.
626 if self.params[0].type == "VkPhysicalDevice":
630 def is_required(self):
633 def needs_conversion(self):
634 """ Check if the function needs any input/output type conversion.
635 Functions need input/output conversion if struct parameters have
636 alignment differences between Win32 and Linux 32-bit.
639 for p in self.params:
640 if p.needs_conversion():
641 LOGGER.debug("Parameter {0} to {1} requires conversion".format(p.name, self.name))
646 def needs_unwrapping(self):
647 """ Check if the function needs any input/output type unwrapping.
648 Functions need input/output unwrapping if struct parameters have
652 for p in self.params:
653 if p.needs_unwrapping():
658 def needs_dispatch(self):
661 def needs_thunk(self):
662 return self.thunk_type != ThunkType.NONE
664 def needs_private_thunk(self):
665 return self.thunk_type == ThunkType.PRIVATE
667 def pfn(self, prefix="p", call_conv=None, conv=False):
668 """ Create function pointer. """
671 pfn = "{0} ({1} *{2}_{3})(".format(self.type, call_conv, prefix, self.name)
673 pfn = "{0} (*{1}_{2})(".format(self.type, prefix, self.name)
675 for i, param in enumerate(self.params):
677 pfn += param.const + " "
680 if conv and param.needs_conversion():
683 if param.is_pointer():
684 pfn += " " + param.pointer
686 if param.array_len is not None:
687 pfn += "[{0}]".format(param.array_len)
689 if i < len(self.params) - 1:
694 def prototype(self, call_conv=None, prefix=None, postfix=None):
695 """ Generate prototype for given function.
698 call_conv (str, optional): calling convention e.g. WINAPI
699 prefix (str, optional): prefix to append prior to function name e.g. vkFoo -> wine_vkFoo
700 postfix (str, optional): text to append after function name but prior to semicolon e.g. DECLSPEC_HIDDEN
703 proto = "{0}".format(self.type)
705 if call_conv is not None:
706 proto += " {0}".format(call_conv)
708 if prefix is not None:
709 proto += " {0}{1}(".format(prefix, self.name)
711 proto += " {0}(".format(self.name)
713 # Add all the parameters.
714 proto += ", ".join([p.definition() for p in self.params])
716 if postfix is not None:
717 proto += ") {0}".format(postfix)
726 if not self.needs_private_thunk():
727 body += " {0}".format(self.trace())
729 params = ", ".join([p.variable(conv=False) for p in self.params])
731 # Call the native Vulkan function.
732 if self.type == "void":
733 body += " {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
735 body += " return {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
739 def loader_body(self):
742 params = ", ".join([p.name for p in self.params])
744 # Call the function from unix_funcs.
745 if self.type == "void":
746 body += " unix_funcs->p_{0}({1});\n".format(self.name, params)
748 body += " return unix_funcs->p_{0}({1});\n".format(self.name, params)
752 def body_conversion(self, conv):
755 # Declare a variable to hold the result for non-void functions.
756 if self.type != "void":
757 body += " {0} result;\n".format(self.type)
759 # Declare any tmp parameters for conversion.
760 for p in self.params:
761 if p.needs_conversion() and conv:
762 if p.is_dynamic_array():
763 body += " {0}_host *{1}_host;\n".format(p.type, p.name)
765 body += " {0}_host {1}_host;\n".format(p.type, p.name)
766 elif p.needs_unwrapping():
767 if p.is_dynamic_array():
768 body += " {0} *{1}_host;\n".format(p.type, p.name)
770 body += " {0} {1}_host;\n".format(p.type, p.name)
772 if not self.needs_private_thunk():
773 body += " {0}\n".format(self.trace())
775 # Call any win_to_host conversion calls.
776 for p in self.params:
777 if p.needs_input_conversion() and (p.needs_unwrapping() or conv):
778 body += p.copy(Direction.INPUT)
780 # Build list of parameters containing converted and non-converted parameters.
781 # The param itself knows if conversion is needed and applies it when we set conv=True.
782 params = ", ".join([p.variable(conv=conv) for p in self.params])
784 # Call the native Vulkan function.
785 if self.type == "void":
786 body += " {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
788 body += " result = {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
792 # Call any host_to_win conversion calls.
793 for p in self.params:
794 if not p.needs_output_conversion():
797 body += p.copy(Direction.OUTPUT)
799 # Perform any required cleanups. Most of these are for array functions.
800 for p in self.params:
801 if p.needs_free() and (p.needs_unwrapping() or conv):
804 # Finally return the result.
805 if self.type != "void":
806 body += " return result;\n"
810 def spec(self, prefix=None, symbol=None):
811 """ Generate spec file entry for this function.
814 prefix (str, optional): prefix to prepend to entry point name.
815 symbol (str, optional): allows overriding the name of the function implementing the entry point.
819 params = " ".join([p.spec() for p in self.params])
820 if prefix is not None:
821 spec += "@ stdcall -private {0}{1}({2})".format(prefix, self.name, params)
823 spec += "@ stdcall {0}({1})".format(self.name, params)
825 if symbol is not None:
831 def stub(self, call_conv=None, prefix=None):
832 stub = self.prototype(call_conv=call_conv, prefix=prefix)
834 stub += " {0}".format(self.trace(message="stub: ", trace_func="FIXME"))
836 if self.type == "VkResult":
837 stub += " return VK_ERROR_OUT_OF_HOST_MEMORY;\n"
838 elif self.type == "VkBool32":
839 stub += " return VK_FALSE;\n"
840 elif self.type == "PFN_vkVoidFunction":
841 stub += " return NULL;\n"
846 def thunk(self, call_conv=None, prefix=None):
847 thunk = self.prototype(call_conv=call_conv, prefix=prefix)
850 if self.needs_conversion():
851 thunk += "#if defined(USE_STRUCT_CONVERSION)\n"
852 thunk += self.body_conversion(conv=True)
854 if self.needs_unwrapping():
855 thunk += self.body_conversion(conv=False)
859 elif self.needs_unwrapping():
860 thunk += self.body_conversion(conv=False)
867 def loader_thunk(self, prefix=None):
868 thunk = self.prototype(call_conv="WINAPI", prefix=prefix)
870 thunk += self.loader_body()
874 def trace(self, message=None, trace_func=None):
875 """ Create a trace string including all parameters.
878 message (str, optional): text to print at start of trace message e.g. 'stub: '
879 trace_func (str, optional): used to override trace function e.g. FIXME, printf, etcetera.
881 if trace_func is not None:
882 trace = "{0}(\"".format(trace_func)
886 if message is not None:
889 # First loop is for all the format strings.
890 trace += ", ".join([p.format_string() for p in self.params])
893 # Second loop for parameter names and optional conversions.
894 for param in self.params:
895 if param.format_conv is not None:
896 trace += ", " + param.format_conv.format(param.name)
898 trace += ", {0}".format(param.name)
904 class VkFunctionPointer(object):
905 def __init__(self, _type, name, members, forward_decls):
907 self.members = members
909 self.required = False
910 self.forward_decls = forward_decls
913 def from_xml(funcpointer):
917 for t in funcpointer.findall("type"):
919 # <type>void</type>* pUserData,
920 # Parsing of the tail (anything past </type>) is tricky since there
921 # can be other data on the next line like: const <type>int</type>..
923 const = True if begin and "const" in begin else False
925 lines = t.tail.split(",\n")
926 if lines[0][0] == "*":
928 name = lines[0][1:].strip()
931 name = lines[0].strip()
933 # Filter out ); if it is contained.
934 name = name.partition(");")[0]
936 # If tail encompasses multiple lines, assign the second line to begin
939 begin = lines[1].strip()
943 members.append(VkMember(const=const, _type=_type, pointer=pointer, name=name))
945 _type = funcpointer.text
946 name = funcpointer.find("name").text
947 if "requires" in funcpointer.attrib:
948 forward_decls = funcpointer.attrib.get("requires").split(",")
951 return VkFunctionPointer(_type, name, members, forward_decls)
953 def definition(self):
955 # forward declare required structs
956 for decl in self.forward_decls:
957 text += "typedef struct {0} {0};\n".format(decl)
959 text += "{0} {1})(\n".format(self.type, self.name)
962 if len(self.members) > 0:
963 for m in self.members:
965 text += " " + m.definition()
968 text += ",\n " + m.definition()
970 # Just make the compiler happy by adding a void parameter.
978 class VkHandle(object):
979 def __init__(self, name, _type, parent, alias=None):
984 self.required = False
985 self.object_type = None
988 def from_alias(handle, alias):
989 name = handle.attrib.get("name")
990 return VkHandle(name, alias.type, alias.parent, alias=alias)
993 def from_xml(handle):
994 name = handle.find("name").text
995 _type = handle.find("type").text
996 parent = handle.attrib.get("parent") # Most objects have a parent e.g. VkQueue has VkDevice.
997 return VkHandle(name, _type, parent)
999 def dispatch_table(self):
1000 if not self.is_dispatchable():
1003 if self.parent is None:
1004 # Should only happen for VkInstance
1006 elif self.name == "VkDevice":
1007 # VkDevice has VkInstance as a parent, but has its own dispatch table.
1009 elif self.parent in ["VkInstance", "VkPhysicalDevice"]:
1010 return "instance->funcs"
1011 elif self.parent in ["VkDevice", "VkCommandPool"]:
1012 return "device->funcs"
1014 LOGGER.error("Unhandled dispatchable parent: {0}".format(self.parent))
1016 def definition(self):
1017 """ Generates handle definition e.g. VK_DEFINE_HANDLE(vkInstance) """
1019 # Legacy types are typedef'ed to the new type if they are aliases.
1021 return "typedef {0} {1};\n".format(self.alias.name, self.name)
1023 return "{0}({1})\n".format(self.type, self.name)
1026 return self.alias is not None
1028 def is_dispatchable(self):
1029 """ Some handles like VkInstance, VkDevice are dispatchable objects,
1030 which means they contain a dispatch table of function pointers.
1032 return self.type == "VK_DEFINE_HANDLE"
1034 def is_required(self):
1035 return self.required
1037 def native_handle(self, name):
1038 """ Provide access to the native handle of a wrapped object. """
1040 if self.name == "VkCommandPool":
1041 return "wine_cmd_pool_from_handle({0})->command_pool".format(name)
1042 if self.name == "VkDebugUtilsMessengerEXT":
1043 return "wine_debug_utils_messenger_from_handle({0})->debug_messenger".format(name)
1044 if self.name == "VkDebugReportCallbackEXT":
1045 return "wine_debug_report_callback_from_handle({0})->debug_callback".format(name)
1046 if self.name == "VkSurfaceKHR":
1047 return "wine_surface_from_handle({0})->surface".format(name)
1049 native_handle_name = None
1051 if self.name == "VkCommandBuffer":
1052 native_handle_name = "command_buffer"
1053 if self.name == "VkDevice":
1054 native_handle_name = "device"
1055 if self.name == "VkInstance":
1056 native_handle_name = "instance"
1057 if self.name == "VkPhysicalDevice":
1058 native_handle_name = "phys_dev"
1059 if self.name == "VkQueue":
1060 native_handle_name = "queue"
1062 if native_handle_name:
1063 return "{0}->{1}".format(name, native_handle_name)
1065 if self.is_dispatchable():
1066 LOGGER.error("Unhandled native handle for: {0}".format(self.name))
1069 def driver_handle(self, name):
1070 """ Provide access to the handle that should be passed to the wine driver """
1072 if self.name == "VkSurfaceKHR":
1073 return "wine_surface_from_handle({0})->driver_surface".format(name)
1075 return self.native_handle(name)
1077 def is_wrapped(self):
1078 return self.native_handle("test") is not None
1080 def needs_conversion(self):
1083 def needs_unwrapping(self):
1084 return self.is_wrapped()
1086 class VkMember(object):
1087 def __init__(self, const=False, struct_fwd_decl=False,_type=None, pointer=None, name=None, array_len=None,
1088 dyn_array_len=None, optional=False, values=None):
1090 self.struct_fwd_decl = struct_fwd_decl
1092 self.pointer = pointer
1094 self.type_info = None
1095 self.array_len = array_len
1096 self.dyn_array_len = dyn_array_len
1097 self.optional = optional
1098 self.values = values
1100 def __eq__(self, other):
1101 """ Compare member based on name against a string.
1103 This method is for convenience by VkStruct, which holds a number of members and needs quick checking
1104 if certain members exist.
1107 return self.name == other
1110 return "{0} {1} {2} {3} {4} {5} {6}".format(self.const, self.struct_fwd_decl, self.type, self.pointer,
1111 self.name, self.array_len, self.dyn_array_len)
1114 def from_xml(member):
1115 """ Helper function for parsing a member tag within a struct or union. """
1117 name_elem = member.find("name")
1118 type_elem = member.find("type")
1121 struct_fwd_decl = False
1126 values = member.get("values")
1129 if "const" in member.text:
1132 # Some members contain forward declarations:
1133 # - VkBaseInstructure has a member "const struct VkBaseInStructure *pNext"
1134 # - VkWaylandSurfaceCreateInfoKHR has a member "struct wl_display *display"
1135 if "struct" in member.text:
1136 struct_fwd_decl = True
1138 if type_elem is not None:
1139 member_type = type_elem.text
1140 if type_elem.tail is not None:
1141 pointer = type_elem.tail.strip() if type_elem.tail.strip() != "" else None
1143 # Name of other member within, which stores the number of
1144 # elements pointed to be by this member.
1145 dyn_array_len = member.get("len")
1147 # Some members are optional, which is important for conversion code e.g. not dereference NULL pointer.
1148 optional = True if member.get("optional") else False
1150 # Usually we need to allocate memory for dynamic arrays. We need to do the same in a few other cases
1151 # like for VkCommandBufferBeginInfo.pInheritanceInfo. Just threat such cases as dynamic arrays of
1152 # size 1 to simplify code generation.
1153 if dyn_array_len is None and pointer is not None:
1156 # Some members are arrays, attempt to parse these. Formats include:
1157 # <member><type>char</type><name>extensionName</name>[<enum>VK_MAX_EXTENSION_NAME_SIZE</enum>]</member>
1158 # <member><type>uint32_t</type><name>foo</name>[4]</member>
1159 if name_elem.tail and name_elem.tail[0] == '[':
1160 LOGGER.debug("Found array type")
1161 enum_elem = member.find("enum")
1162 if enum_elem is not None:
1163 array_len = enum_elem.text
1165 # Remove brackets around length
1166 array_len = name_elem.tail.strip("[]")
1168 return VkMember(const=const, struct_fwd_decl=struct_fwd_decl, _type=member_type, pointer=pointer, name=name_elem.text,
1169 array_len=array_len, dyn_array_len=dyn_array_len, optional=optional, values=values)
1171 def copy(self, input, output, direction, conv):
1172 """ Helper method for use by conversion logic to generate a C-code statement to copy this member.
1173 - `conv` indicates whether the statement is in a struct alignment conversion path. """
1175 if (conv and self.needs_conversion()) or self.needs_unwrapping():
1176 if self.is_dynamic_array():
1177 if direction == Direction.OUTPUT:
1178 LOGGER.warn("TODO: implement copying of returnedonly dynamic array for {0}.{1}".format(self.type, self.name))
1180 # Array length is either a variable name (string) or an int.
1181 count = self.dyn_array_len if isinstance(self.dyn_array_len, int) else "{0}{1}".format(input, self.dyn_array_len)
1182 return "{0}{1} = convert_{2}_array_win_to_host({3}{1}, {4});\n".format(output, self.name, self.type, input, count)
1183 elif self.is_static_array():
1184 count = self.array_len
1185 if direction == Direction.OUTPUT:
1186 # Needed by VkMemoryHeap.memoryHeaps
1187 return "convert_{0}_static_array_host_to_win({2}{1}, {3}{1}, {4});\n".format(self.type, self.name, input, output, count)
1189 # Nothing needed this yet.
1190 LOGGER.warn("TODO: implement copying of static array for {0}.{1}".format(self.type, self.name))
1191 elif self.is_handle() and self.needs_unwrapping():
1192 if direction == Direction.OUTPUT:
1193 LOGGER.err("OUTPUT parameter {0}.{1} cannot be unwrapped".format(self.type, self.name))
1195 handle = self.type_info["data"]
1196 return "{0}{1} = {2};\n".format(output, self.name, handle.driver_handle("{0}{1}".format(input, self.name)))
1198 if direction == Direction.OUTPUT:
1199 return "convert_{0}_host_to_win(&{2}{1}, &{3}{1});\n".format(self.type, self.name, input, output)
1201 return "convert_{0}_win_to_host(&{2}{1}, &{3}{1});\n".format(self.type, self.name, input, output)
1202 elif self.is_static_array():
1203 bytes_count = "{0} * sizeof({1})".format(self.array_len, self.type)
1204 return "memcpy({0}{1}, {2}{1}, {3});\n".format(output, self.name, input, bytes_count)
1206 return "{0}{1} = {2}{1};\n".format(output, self.name, input)
1208 def free(self, location, conv):
1209 """ Helper method for use by conversion logic to generate a C-code statement to free this member. """
1211 if not self.needs_unwrapping() and not conv:
1214 # Add a cast to ignore const on conversion structs we allocated ourselves.
1215 # sample expected output: (VkSparseMemoryBind_host *)
1217 cast = "(" + self.type
1218 if self.needs_conversion() and conv:
1224 if self.is_dynamic_array():
1225 count = self.dyn_array_len if isinstance(self.dyn_array_len, int) else "{0}{1}".format(location, self.dyn_array_len)
1226 if self.is_struct() and self.type_info["data"].returnedonly:
1227 # For returnedonly, counts is stored in a pointer.
1228 return "free_{0}_array({1}{2}{3}, *{4});\n".format(self.type, cast, location, self.name, count)
1230 return "free_{0}_array({1}{2}{3}, {4});\n".format(self.type, cast, location, self.name, count)
1232 # We are operating on a single structure. Some structs (very rare) contain dynamic members,
1233 # which would need freeing.
1234 if self.needs_free():
1235 return "free_{0}({1}&{2}{3});\n".format(self.type, cast, location, self.name)
1238 def definition(self, align=False, conv=False):
1239 """ Generate prototype for given function.
1242 align (bool, optional): Enable alignment if a type needs it. This adds WINE_VK_ALIGN(8) to a member.
1243 conv (bool, optional): Enable conversion if a type needs it. This appends '_host' to the name.
1250 if self.is_struct_forward_declaration():
1253 if conv and self.is_struct():
1254 text += "{0}_host".format(self.type)
1258 if self.is_pointer():
1259 text += " {0}{1}".format(self.pointer, self.name)
1261 if align and self.needs_alignment():
1262 text += " WINE_VK_ALIGN(8) " + self.name
1264 text += " " + self.name
1266 if self.is_static_array():
1267 text += "[{0}]".format(self.array_len)
1271 def get_conversions(self):
1272 """ Return any conversion description for this member and its children when conversion is needed. """
1274 # Check if we need conversion either for this member itself or for any child members
1275 # in case member represents a struct.
1276 if not self.needs_conversion() and not self.needs_unwrapping():
1281 # Collect any conversion for any member structs.
1282 if self.is_struct():
1283 struct = self.type_info["data"]
1285 m.needs_struct_extensions_conversion()
1286 if m.needs_conversion() or m.needs_unwrapping():
1287 conversions.extend(m.get_conversions())
1289 struct.needs_struct_extensions_conversion()
1290 direction = Direction.OUTPUT if struct.returnedonly else Direction.INPUT
1291 elif self.is_handle():
1292 direction = Direction.INPUT
1294 operand = self.type_info["data"]
1295 if self.is_dynamic_array():
1296 conversions.append(ConversionFunction(False, True, direction, operand))
1297 elif self.is_static_array():
1298 conversions.append(ConversionFunction(True, False, direction, operand))
1300 conversions.append(ConversionFunction(False, False, direction, operand))
1302 if self.needs_free():
1303 conversions.append(FreeFunction(self.is_dynamic_array(), operand))
1310 def is_dynamic_array(self):
1311 """ Returns if the member is an array element.
1312 Vulkan uses this for dynamically sized arrays for which
1313 there is a 'count' parameter.
1315 return self.dyn_array_len is not None
1317 def is_handle(self):
1318 return self.type_info["category"] == "handle"
1320 def is_pointer(self):
1321 return self.pointer is not None
1323 def is_static_array(self):
1324 """ Returns if the member is an array.
1325 Vulkan uses this often for fixed size arrays in which the
1326 length is part of the member.
1328 return self.array_len is not None
1330 def is_struct(self):
1331 return self.type_info["category"] == "struct"
1333 def is_struct_forward_declaration(self):
1334 return self.struct_fwd_decl
1337 return self.type_info["category"] == "union"
1339 def needs_alignment(self):
1340 """ Check if this member needs alignment for 64-bit data.
1341 Various structures need alignment on 64-bit variables due
1342 to compiler differences on 32-bit between Win32 and Linux.
1345 if self.is_pointer():
1347 elif self.type == "size_t":
1349 elif self.type in ["uint64_t", "VkDeviceSize"]:
1351 elif self.is_struct():
1352 struct = self.type_info["data"]
1353 return struct.needs_alignment()
1354 elif self.is_handle():
1355 # Dispatchable handles are pointers to objects, while
1356 # non-dispatchable are uint64_t and hence need alignment.
1357 handle = self.type_info["data"]
1358 return False if handle.is_dispatchable() else True
1361 def needs_conversion(self):
1362 """ Structures requiring alignment, need conversion between win32 and host. """
1364 if not self.is_struct():
1367 struct = self.type_info["data"]
1368 return struct.needs_conversion()
1370 def needs_unwrapping(self):
1371 """ Structures with wrapped handles need unwrapping. """
1373 if self.is_struct():
1374 struct = self.type_info["data"]
1375 return struct.needs_unwrapping()
1377 if self.is_handle():
1378 handle = self.type_info["data"]
1379 return handle.is_wrapped()
1383 def needs_free(self):
1384 if not self.needs_conversion() and not self.needs_unwrapping():
1387 if self.is_dynamic_array():
1390 # TODO: some non-pointer structs and optional pointer structs may need freeing,
1391 # though none of this type have been encountered yet.
1394 def needs_struct_extensions_conversion(self):
1395 if not self.is_struct():
1398 struct = self.type_info["data"]
1399 return struct.needs_struct_extensions_conversion()
1401 def set_type_info(self, type_info):
1402 """ Helper function to set type information from the type registry.
1403 This is needed, because not all type data is available at time of
1406 self.type_info = type_info
1409 class VkParam(object):
1410 """ Helper class which describes a parameter to a function call. """
1412 def __init__(self, type_info, const=None, pointer=None, name=None, array_len=None, dyn_array_len=None):
1415 self.array_len = array_len
1416 self.dyn_array_len = dyn_array_len
1417 self.pointer = pointer
1418 self.type_info = type_info
1419 self.type = type_info["name"] # For convenience
1420 self.handle = type_info["data"] if type_info["category"] == "handle" else None
1421 self.struct = type_info["data"] if type_info["category"] == "struct" else None
1423 self._set_direction()
1424 self._set_format_string()
1425 self._set_conversions()
1428 return "{0} {1} {2} {3} {4} {5}".format(self.const, self.type, self.pointer, self.name, self.array_len, self.dyn_array_len)
1431 def from_xml(param, types):
1432 """ Helper function to create VkParam from xml. """
1434 # Parameter parsing is slightly tricky. All the data is contained within
1435 # a param tag, but some data is within subtags while others are text
1436 # before or after the type tag.
1438 # <param>const <type>char</type>* <name>pLayerName</name></param>
1440 name_elem = param.find("name")
1442 name = name_elem.text
1443 # Tail contains array length e.g. for blendConstants param of vkSetBlendConstants
1444 if name_elem.tail is not None:
1445 array_len = name_elem.tail.strip("[]")
1447 # Name of other parameter in function prototype, which stores the number of
1448 # elements pointed to be by this parameter.
1449 dyn_array_len = param.get("len", None)
1451 const = param.text.strip() if param.text else None
1452 type_elem = param.find("type")
1453 pointer = type_elem.tail.strip() if type_elem.tail.strip() != "" else None
1455 # Since we have parsed all types before hand, this should not happen.
1456 type_info = types.get(type_elem.text, None)
1457 if type_info is None:
1458 LOGGER.err("type info not found for: {0}".format(type_elem.text))
1460 return VkParam(type_info, const=const, pointer=pointer, name=name, array_len=array_len, dyn_array_len=dyn_array_len)
1462 def _set_conversions(self):
1463 """ Internal helper function to configure any needed conversion functions. """
1465 self.free_func = None
1466 self.input_conv = None
1467 self.output_conv = None
1468 if not self.needs_conversion() and not self.needs_unwrapping():
1471 operand = self.struct if self.is_struct() else self.handle
1473 # Input functions require win to host conversion.
1474 if self._direction in [Direction.INPUT, Direction.INPUT_OUTPUT]:
1475 self.input_conv = ConversionFunction(False, self.is_dynamic_array(), Direction.INPUT, operand)
1477 # Output functions require host to win conversion.
1478 if self._direction in [Direction.INPUT_OUTPUT, Direction.OUTPUT]:
1479 self.output_conv = ConversionFunction(False, self.is_dynamic_array(), Direction.OUTPUT, operand)
1481 # Dynamic arrays, but also some normal structs (e.g. VkCommandBufferBeginInfo) need memory
1482 # allocation and thus some cleanup.
1483 if self.is_dynamic_array() or self.struct.needs_free():
1484 self.free_func = FreeFunction(self.is_dynamic_array(), operand)
1486 def _set_direction(self):
1487 """ Internal helper function to set parameter direction (input/output/input_output). """
1489 # The parameter direction needs to be determined from hints in vk.xml like returnedonly,
1490 # parameter constness and other heuristics.
1491 # For now we need to get this right for structures as we need to convert these, we may have
1492 # missed a few other edge cases (e.g. count variables).
1493 # See also https://github.com/KhronosGroup/Vulkan-Docs/issues/610
1495 if not self.is_pointer():
1496 self._direction = Direction.INPUT
1497 elif self.is_const() and self.is_pointer():
1498 self._direction = Direction.INPUT
1499 elif self.is_struct():
1500 if not self.struct.returnedonly:
1501 self._direction = Direction.INPUT
1504 # Returnedonly hints towards output, however in some cases
1505 # it is inputoutput. In particular if pNext / sType exist,
1506 # which are used to link in other structures without having
1507 # to introduce new APIs. E.g. vkGetPhysicalDeviceProperties2KHR.
1508 if "pNext" in self.struct:
1509 self._direction = Direction.INPUT_OUTPUT
1512 self._direction = Direction.OUTPUT
1514 # This should mostly be right. Count variables can be inout, but we don't care about these yet.
1515 self._direction = Direction.OUTPUT
1517 def _set_format_string(self):
1518 """ Internal helper function to be used by constructor to set format string. """
1520 # Determine a format string used by code generation for traces.
1521 # 64-bit types need a conversion function.
1522 self.format_conv = None
1523 if self.is_static_array() or self.is_pointer():
1524 self.format_str = "%p"
1526 if self.type_info["category"] in ["bitmask"]:
1527 # Since 1.2.170 bitmasks can be 32 or 64-bit, check the basetype.
1528 if self.type_info["data"].type == "VkFlags64":
1529 self.format_str = "0x%s"
1530 self.format_conv = "wine_dbgstr_longlong({0})"
1532 self.format_str = "%#x"
1533 elif self.type_info["category"] in ["enum"]:
1534 self.format_str = "%#x"
1535 elif self.is_handle():
1536 # We use uint64_t for non-dispatchable handles as opposed to pointers
1537 # for dispatchable handles.
1538 if self.handle.is_dispatchable():
1539 self.format_str = "%p"
1541 self.format_str = "0x%s"
1542 self.format_conv = "wine_dbgstr_longlong({0})"
1543 elif self.type == "float":
1544 self.format_str = "%f"
1545 elif self.type == "int":
1546 self.format_str = "%d"
1547 elif self.type == "int32_t":
1548 self.format_str = "%d"
1549 elif self.type == "size_t":
1550 self.format_str = "0x%s"
1551 self.format_conv = "wine_dbgstr_longlong({0})"
1552 elif self.type in ["uint16_t", "uint32_t", "VkBool32"]:
1553 self.format_str = "%u"
1554 elif self.type in ["uint64_t", "VkDeviceAddress", "VkDeviceSize"]:
1555 self.format_str = "0x%s"
1556 self.format_conv = "wine_dbgstr_longlong({0})"
1557 elif self.type == "HANDLE":
1558 self.format_str = "%p"
1559 elif self.type in ["VisualID", "xcb_visualid_t", "RROutput", "zx_handle_t"]:
1560 # Don't care about specific types for non-Windows platforms.
1561 self.format_str = ""
1563 LOGGER.warn("Unhandled type: {0}".format(self.type_info))
1565 def copy(self, direction):
1566 if direction == Direction.INPUT:
1567 if self.is_dynamic_array():
1568 return " {0}_host = convert_{1}_array_win_to_host({0}, {2});\n".format(self.name, self.type, self.dyn_array_len)
1570 return " convert_{0}_win_to_host({1}, &{1}_host);\n".format(self.type, self.name)
1572 if self.is_dynamic_array():
1573 LOGGER.error("Unimplemented output conversion for: {0}".format(self.name))
1575 return " convert_{0}_host_to_win(&{1}_host, {1});\n".format(self.type, self.name)
1577 def definition(self, postfix=None):
1578 """ Return prototype for the parameter. E.g. 'const char *foo' """
1582 proto += self.const + " "
1586 if self.is_pointer():
1587 proto += " {0}{1}".format(self.pointer, self.name)
1589 proto += " " + self.name
1591 # Allows appending something to the variable name useful for
1592 # win32 to host conversion.
1593 if postfix is not None:
1596 if self.is_static_array():
1597 proto += "[{0}]".format(self.array_len)
1601 def direction(self):
1602 """ Returns parameter direction: input, output, input_output.
1604 Parameter direction in Vulkan is not straight-forward, which this function determines.
1607 return self._direction
1609 def dispatch_table(self):
1610 """ Return functions dispatch table pointer for dispatchable objects. """
1612 if not self.is_dispatchable():
1615 return "{0}->{1}".format(self.name, self.handle.dispatch_table())
1617 def format_string(self):
1618 return self.format_str
1621 if self.is_dynamic_array():
1622 if self.is_struct() and self.struct.returnedonly:
1623 # For returnedonly, counts is stored in a pointer.
1624 return " free_{0}_array({1}_host, *{2});\n".format(self.type, self.name, self.dyn_array_len)
1626 return " free_{0}_array({1}_host, {2});\n".format(self.type, self.name, self.dyn_array_len)
1628 # We are operating on a single structure. Some structs (very rare) contain dynamic members,
1629 # which would need freeing.
1630 if self.is_struct() and self.struct.needs_free():
1631 return " free_{0}(&{1}_host);\n".format(self.type, self.name)
1634 def get_conversions(self):
1635 """ Get a list of conversions required for this parameter if any.
1636 Parameters which are structures may require conversion between win32
1637 and the host platform. This function returns a list of conversions
1641 if self.is_struct():
1642 self.struct.needs_struct_extensions_conversion()
1643 for m in self.struct:
1644 m.needs_struct_extensions_conversion()
1645 elif not self.is_handle():
1648 if not self.needs_conversion() and not self.needs_unwrapping():
1653 # Collect any member conversions first, so we can guarantee
1654 # those functions will be defined prior to usage by the
1655 # 'parent' param requiring conversion.
1656 if self.is_struct():
1657 for m in self.struct:
1658 if not m.is_struct():
1661 if not m.needs_conversion() and not m.needs_unwrapping():
1664 conversions.extend(m.get_conversions())
1666 # Conversion requirements for the 'parent' parameter.
1667 if self.input_conv is not None:
1668 conversions.append(self.input_conv)
1669 if self.output_conv is not None:
1670 conversions.append(self.output_conv)
1671 if self.free_func is not None:
1672 conversions.append(self.free_func)
1677 return self.const is not None
1679 def is_dynamic_array(self):
1680 return self.dyn_array_len is not None
1682 def is_dispatchable(self):
1683 if not self.is_handle():
1686 return self.handle.is_dispatchable()
1688 def is_handle(self):
1689 return self.handle is not None
1691 def is_pointer(self):
1692 return self.pointer is not None
1694 def is_static_array(self):
1695 return self.array_len is not None
1697 def is_struct(self):
1698 return self.struct is not None
1700 def needs_conversion(self):
1701 """ Returns if parameter needs conversion between win32 and host. """
1703 if not self.is_struct():
1706 # VkSparseImageMemoryRequirements(2) is used by vkGetImageSparseMemoryRequirements(2).
1707 # This function is tricky to wrap, because how to wrap depends on whether
1708 # pSparseMemoryRequirements is NULL or not. Luckily for VkSparseImageMemoryRequirements(2)
1709 # the alignment works out in such a way that no conversion is needed between win32 and Linux.
1710 if self.type in ["VkSparseImageMemoryRequirements", "VkSparseImageMemoryRequirements2"]:
1713 # If a structure needs alignment changes, it means we need to
1714 # perform parameter conversion between win32 and host.
1715 if self.struct.needs_conversion():
1720 def needs_unwrapping(self):
1721 """ Returns if parameter needs unwrapping of handle. """
1723 # Wrapped handle parameters are handled seperately, only look for wrapped handles in structs
1724 if self.is_struct():
1725 return self.struct.needs_unwrapping()
1727 if self.is_handle() and self.is_dynamic_array():
1728 return self.handle.needs_unwrapping()
1732 def needs_free(self):
1733 return self.free_func is not None
1735 def needs_input_conversion(self):
1736 return self.input_conv is not None
1738 def needs_output_conversion(self):
1739 return self.output_conv is not None
1742 """ Generate spec file entry for this parameter. """
1744 if self.is_pointer() and self.type == "char":
1746 if self.is_dispatchable() or self.is_pointer() or self.is_static_array():
1748 if self.type_info["category"] in ["bitmask"]:
1749 # Since 1.2.170 bitmasks can be 32 or 64-bit, check the basetype.
1750 if self.type_info["data"].type == "VkFlags64":
1754 if self.type_info["category"] in ["enum"]:
1756 if self.is_handle() and not self.is_dispatchable():
1758 if self.type == "float":
1760 if self.type in ["int", "int32_t", "size_t", "uint16_t", "uint32_t", "VkBool32"]:
1762 if self.type in ["uint64_t", "VkDeviceSize"]:
1765 LOGGER.error("Unhandled spec conversion for type: {0}".format(self.type))
1767 def variable(self, conv=False):
1768 """ Returns 'glue' code during generation of a function call on how to access the variable.
1769 This function handles various scenarios such as 'unwrapping' if dispatchable objects and
1770 renaming of parameters in case of win32 -> host conversion.
1773 conv (bool, optional): Enable conversion if the param needs it. This appends '_host' to the name.
1776 # Hack until we enable allocation callbacks from ICD to application. These are a joy
1777 # to enable one day, because of calling convention conversion.
1778 if "VkAllocationCallbacks" in self.type:
1779 LOGGER.debug("TODO: setting NULL VkAllocationCallbacks for {0}".format(self.name))
1782 if self.needs_unwrapping() or (conv and self.needs_conversion()):
1783 if self.is_dynamic_array():
1784 return "{0}_host".format(self.name)
1786 return "&{0}_host".format(self.name)
1788 # We need to pass the native handle to the native Vulkan calls and
1789 # the wine driver's handle to calls which are wrapped by the driver.
1790 driver_handle = self.handle.driver_handle(self.name) if self.is_handle() else None
1791 return driver_handle if driver_handle else self.name
1794 class VkStruct(Sequence):
1795 """ Class which represents the type union and struct. """
1797 def __init__(self, name, members, returnedonly, structextends, alias=None, union=False):
1799 self.members = members
1800 self.returnedonly = returnedonly
1801 self.structextends = structextends
1802 self.required = False
1805 self.type_info = None # To be set later.
1806 self.struct_extensions = []
1807 self.aliased_by = []
1809 def __getitem__(self, i):
1810 return self.members[i]
1813 return len(self.members)
1816 def from_alias(struct, alias):
1817 name = struct.attrib.get("name")
1818 aliasee = VkStruct(name, alias.members, alias.returnedonly, alias.structextends, alias=alias)
1820 alias.add_aliased_by(aliasee)
1824 def from_xml(struct):
1825 # Unions and structs are the same parsing wise, but we need to
1826 # know which one we are dealing with later on for code generation.
1827 union = True if struct.attrib["category"] == "union" else False
1829 name = struct.attrib.get("name")
1831 # 'Output' structures for which data is filled in by the API are
1832 # marked as 'returnedonly'.
1833 returnedonly = True if struct.attrib.get("returnedonly") else False
1835 structextends = struct.attrib.get("structextends")
1836 structextends = structextends.split(",") if structextends else []
1839 for member in struct.findall("member"):
1840 vk_member = VkMember.from_xml(member)
1841 members.append(vk_member)
1843 return VkStruct(name, members, returnedonly, structextends, union=union)
1846 def decouple_structs(structs):
1847 """ Helper function which decouples a list of structs.
1848 Structures often depend on other structures. To make the C compiler
1849 happy we need to define 'substructures' first. This function analyzes
1850 the list of structures and reorders them in such a way that they are
1854 tmp_structs = list(structs) # Don't modify the original structures.
1855 decoupled_structs = []
1857 while (len(tmp_structs) > 0):
1858 for struct in tmp_structs:
1861 if not struct.required:
1862 tmp_structs.remove(struct)
1866 if not (m.is_struct() or m.is_union()):
1869 # VkBaseInstructure and VkBaseOutStructure reference themselves.
1870 if m.type == struct.name:
1874 # Check if a struct we depend on has already been defined.
1875 for s in decoupled_structs:
1876 if s.name == m.type:
1881 # Check if the struct we depend on is even in the list of structs.
1882 # If found now, it means we haven't met all dependencies before we
1883 # can operate on the current struct.
1884 # When generating 'host' structs we may not be able to find a struct
1885 # as the list would only contain the structs requiring conversion.
1886 for s in tmp_structs:
1887 if s.name == m.type:
1891 if dependends == False:
1892 decoupled_structs.append(struct)
1893 tmp_structs.remove(struct)
1895 return decoupled_structs
1897 def definition(self, align=False, conv=False, postfix=None):
1898 """ Convert structure to textual definition.
1901 align (bool, optional): enable alignment to 64-bit for win32 struct compatibility.
1902 conv (bool, optional): enable struct conversion if the struct needs it.
1903 postfix (str, optional): text to append to end of struct name, useful for struct renaming.
1906 # Only define alias structs when doing conversions
1907 if self.is_alias() and not conv:
1911 text = "typedef union {0}".format(self.name)
1913 text = "typedef struct {0}".format(self.name)
1915 if postfix is not None:
1921 if align and m.needs_alignment():
1922 text += " {0};\n".format(m.definition(align=align))
1923 elif conv and m.needs_conversion():
1924 text += " {0};\n".format(m.definition(conv=conv))
1926 text += " {0};\n".format(m.definition())
1928 if postfix is not None:
1929 text += "}} {0}{1};\n\n".format(self.name, postfix)
1931 text += "}} {0};\n".format(self.name)
1933 for aliasee in self.aliased_by:
1934 text += "typedef {0} {1};\n".format(self.name, aliasee.name)
1941 return bool(self.alias)
1943 def add_aliased_by(self, aliasee):
1944 self.aliased_by.append(aliasee)
1946 def needs_alignment(self):
1947 """ Check if structure needs alignment for 64-bit data.
1948 Various structures need alignment on 64-bit variables due
1949 to compiler differences on 32-bit between Win32 and Linux.
1952 for m in self.members:
1953 if m.needs_alignment():
1957 def needs_conversion(self):
1958 """ Returns if struct members needs conversion between win32 and host.
1959 Structures need conversion if they contain members requiring alignment
1960 or if they include other structures which need alignment.
1963 if self.needs_alignment():
1966 for m in self.members:
1967 if m.needs_conversion():
1971 def needs_unwrapping(self):
1972 """ Returns if struct members need unwrapping of handle. """
1974 for m in self.members:
1975 if m.needs_unwrapping():
1979 def needs_free(self):
1980 """ Check if any struct member needs some memory freeing."""
1982 for m in self.members:
1990 def needs_struct_extensions_conversion(self):
1991 """ Checks if structure extensions in pNext chain need conversion. """
1994 for e in self.struct_extensions:
1995 if e.required and e.needs_conversion():
1996 LOGGER.error("Unhandled pNext chain alignment conversion for {0}".format(e.name))
1998 if e.required and e.needs_unwrapping():
1999 LOGGER.error("Unhandled pNext chain unwrapping conversion for {0}".format(e.name))
2004 def set_type_info(self, types):
2005 """ Helper function to set type information from the type registry.
2006 This is needed, because not all type data is available at time of
2009 for m in self.members:
2010 type_info = types[m.type]
2011 m.set_type_info(type_info)
2014 class ConversionFunction(object):
2015 def __init__(self, array, dyn_array, direction, operand):
2017 self.direction = direction
2018 self.dyn_array = dyn_array
2019 self.operand = operand
2020 self.type = operand.name
2024 def __eq__(self, other):
2025 return self.name == other.name
2027 def _generate_array_conversion_func(self):
2028 """ Helper function for generating a conversion function for array operands. """
2032 if self.operand.needs_conversion():
2033 body += "#if defined(USE_STRUCT_CONVERSION)\n"
2035 if self.direction == Direction.OUTPUT:
2036 params = ["const {0}_host *in".format(self.type), "uint32_t count"]
2037 return_type = self.type
2039 params = ["const {0} *in".format(self.type), "uint32_t count"]
2040 return_type = "{0}_host".format(self.type)
2042 # Generate function prototype.
2043 body += "static inline {0} *{1}(".format(return_type, self.name)
2044 body += ", ".join(p for p in params)
2047 body += " {0} *out;\n".format(return_type)
2049 if self.operand.needs_unwrapping():
2050 if self.operand.needs_conversion():
2053 params = ["const {0} *in".format(self.type), "uint32_t count"]
2054 return_type = "{0}".format(self.type)
2056 # Generate function prototype.
2057 body += "static inline {0} *{1}(".format(return_type, self.name)
2058 body += ", ".join(p for p in params)
2061 body += " {0} *out;\n".format(return_type)
2063 if self.operand.needs_conversion():
2064 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2066 body += " unsigned int i;\n\n"
2067 body += " if (!in) return NULL;\n\n"
2069 body += " out = malloc(count * sizeof(*out));\n"
2071 body += " for (i = 0; i < count; i++)\n"
2074 if isinstance(self.operand, VkStruct):
2075 for m in self.operand:
2076 # TODO: support copying of pNext extension structures!
2077 # Luckily though no extension struct at this point needs conversion.
2078 convert = m.copy("in[i].", "out[i].", self.direction, conv=True)
2079 if self.operand.needs_conversion() and not self.operand.needs_unwrapping():
2080 body += " " + convert
2082 unwrap = m.copy("in[i].", "out[i].", self.direction, conv=False)
2083 if unwrap == convert:
2084 body += " " + unwrap
2086 body += "#if defined(USE_STRUCT_CONVERSION)\n"
2087 body += " " + convert
2089 body += " " + unwrap
2090 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2092 elif isinstance(self.operand, VkHandle) and self.direction == Direction.INPUT:
2093 body += " out[i] = " + self.operand.driver_handle("in[i]") + ";\n"
2095 LOGGER.warn("Unhandled conversion operand type")
2096 body += " out[i] = in[i];\n"
2099 body += " return out;\n"
2102 if not self.operand.needs_unwrapping():
2103 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2109 def _generate_conversion_func(self):
2110 """ Helper function for generating a conversion function for non-array operands. """
2112 # It doesn't make sense to generate conversion functions for non-struct variables
2113 # which aren't in arrays, as this should be handled by the copy() function
2114 if not isinstance(self.operand, VkStruct):
2119 if self.operand.needs_conversion():
2120 body += "#if defined(USE_STRUCT_CONVERSION)\n"
2121 body += "static inline void {0}(".format(self.name)
2123 if self.direction == Direction.OUTPUT:
2124 params = ["const {0}_host *in".format(self.type), "{0} *out".format(self.type)]
2126 params = ["const {0} *in".format(self.type), "{0}_host *out".format(self.type)]
2128 # Generate parameter list
2129 body += ", ".join(p for p in params)
2132 if self.operand.needs_unwrapping():
2133 if self.operand.needs_conversion():
2136 body += "static inline void {0}(".format(self.name)
2138 params = ["const {0} *in".format(self.type), "{0} *out".format(self.type)]
2140 # Generate parameter list
2141 body += ", ".join(p for p in params)
2144 if self.operand.needs_conversion():
2145 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2147 body += "{\n if (!in) return;\n\n"
2149 if self.direction == Direction.INPUT and "pNext" in self.operand and self.operand.returnedonly:
2150 # We are dealing with an input_output parameter. For these we only need to copy
2151 # pNext and sType as the other fields are filled in by the host. We do potentially
2152 # have to iterate over pNext and perform conversions based on switch(sType)!
2153 # Luckily though no extension structs at this point need conversion.
2154 # TODO: support copying of pNext extension structures!
2155 body += " out->pNext = in->pNext;\n"
2156 body += " out->sType = in->sType;\n"
2158 for m in self.operand:
2159 # TODO: support copying of pNext extension structures!
2160 convert = m.copy("in->", "out->", self.direction, conv=True)
2161 if self.operand.needs_conversion() and not self.operand.needs_unwrapping():
2162 body += " " + convert
2164 unwrap = m.copy("in->", "out->", self.direction, conv=False)
2165 if unwrap == convert:
2166 body += " " + unwrap
2168 body += "#if defined(USE_STRUCT_CONVERSION)\n"
2169 body += " " + convert
2171 body += " " + unwrap
2172 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2176 if not self.operand.needs_unwrapping():
2177 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2183 def _generate_static_array_conversion_func(self):
2184 """ Helper function for generating a conversion function for array operands. """
2188 if self.operand.needs_conversion():
2189 body += "#if defined(USE_STRUCT_CONVERSION)\n"
2191 if self.direction == Direction.OUTPUT:
2192 params = ["const {0}_host *in".format(self.type), "{0} *out".format(self.type), "uint32_t count"]
2194 params = ["const {0} *in".format(self.type), "{0} *out_host".format(self.type), "uint32_t count"]
2196 # Generate function prototype.
2197 body += "static inline void {0}(".format(self.name)
2198 body += ", ".join(p for p in params)
2201 if self.operand.needs_unwrapping():
2202 if self.operand.needs_conversion():
2205 params = ["const {0} *in".format(self.type), "{0} *out".format(self.type), "uint32_t count"]
2207 # Generate function prototype.
2208 body += "static inline void {0}(".format(self.name)
2209 body += ", ".join(p for p in params)
2213 body += " unsigned int i;\n\n"
2214 body += " if (!in) return;\n\n"
2215 body += " for (i = 0; i < count; i++)\n"
2218 if isinstance(self.operand, VkStruct):
2219 for m in self.operand:
2220 # TODO: support copying of pNext extension structures!
2221 convert = m.copy("in[i].", "out[i].", self.direction, conv=True)
2222 if self.operand.needs_conversion() and not self.operand.needs_unwrapping():
2223 body += " " + convert
2225 unwrap = m.copy("in[i].", "out[i].", self.direction, conv=False)
2226 if unwrap == convert:
2227 body += " " + unwrap
2229 body += "#if defined(USE_STRUCT_CONVERSION)\n"
2230 body += " " + convert
2232 body += " " + unwrap
2233 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2234 elif isinstance(self.operand, VkHandle) and self.direction == Direction.INPUT:
2235 body += " out[i] = " + self.operand.driver_handle("in[i]") + ";\n"
2237 LOGGER.warn("Unhandled conversion operand type")
2238 body += " out[i] = in[i];\n"
2243 if not self.operand.needs_unwrapping():
2244 body += "#endif /* USE_STRUCT_CONVERSION) */\n"
2250 def _set_name(self):
2251 if self.direction == Direction.INPUT:
2253 name = "convert_{0}_static_array_win_to_host".format(self.type)
2254 elif self.dyn_array:
2255 name = "convert_{0}_array_win_to_host".format(self.type)
2257 name = "convert_{0}_win_to_host".format(self.type)
2258 else: # Direction.OUTPUT
2260 name = "convert_{0}_static_array_host_to_win".format(self.type)
2261 elif self.dyn_array:
2262 name = "convert_{0}_array_host_to_win".format(self.type)
2264 name = "convert_{0}_host_to_win".format(self.type)
2268 def definition(self):
2270 return self._generate_static_array_conversion_func()
2271 elif self.dyn_array:
2272 return self._generate_array_conversion_func()
2274 return self._generate_conversion_func()
2277 class FreeFunction(object):
2278 def __init__(self, dyn_array, operand):
2279 self.dyn_array = dyn_array
2280 self.operand = operand
2281 self.type = operand.name
2284 self.name = "free_{0}_array".format(self.type)
2286 self.name = "free_{0}".format(self.type)
2288 def __eq__(self, other):
2289 return self.name == other.name
2291 def _generate_array_free_func(self):
2292 """ Helper function for cleaning up temporary buffers required for array conversions. """
2296 if self.operand.needs_conversion():
2297 body += "#if defined(USE_STRUCT_CONVERSION)\n"
2298 # Generate function prototype.
2299 body += "static inline void {0}({1}_host *in, uint32_t count)\n".format(self.name, self.type)
2301 if self.operand.needs_unwrapping():
2302 if self.operand.needs_conversion():
2305 # Generate function prototype.
2306 body += "static inline void {0}({1} *in, uint32_t count)\n".format(self.name, self.type)
2308 if self.operand.needs_conversion():
2309 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2313 # E.g. VkGraphicsPipelineCreateInfo_host needs freeing for pStages.
2314 if isinstance(self.operand, VkStruct) and self.operand.needs_free():
2315 body += " unsigned int i;\n\n"
2316 body += " if (!in) return;\n\n"
2317 body += " for (i = 0; i < count; i++)\n"
2320 for m in self.operand:
2322 convert = m.free("in[i].", conv=True)
2323 if self.operand.needs_conversion() and not self.operand.needs_unwrapping():
2324 body += " " + convert
2326 unwrap = m.free("in[i].", conv=False)
2327 if convert == unwrap:
2328 body += " " + unwrap
2330 body += "#if defined(USE_STRUCT_CONVERSION)\n"
2331 body += " " + convert
2332 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2334 body += "#if defined(USE_STRUCT_CONVERSION)\n"
2335 body += " " + convert
2337 body += " " + unwrap
2338 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2341 body += " if (!in) return;\n\n"
2343 body += " free(in);\n"
2347 if not self.operand.needs_unwrapping():
2348 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2354 def _generate_free_func(self):
2355 # E.g. VkCommandBufferBeginInfo.pInheritanceInfo needs freeing.
2356 if not self.operand.needs_free():
2359 if not isinstance(self.operand, VkStruct):
2364 if self.operand.needs_conversion():
2365 body += "#if defined(USE_STRUCT_CONVERSION)\n"
2366 # Generate function prototype.
2367 body += "static inline void {0}({1}_host *in)\n".format(self.name, self.type)
2369 if self.operand.needs_unwrapping():
2370 if self.operand.needs_conversion():
2373 # Generate function prototype.
2374 body += "static inline void {0}({1} *in)\n".format(self.name, self.type)
2376 if self.operand.needs_conversion():
2377 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2381 for m in self.operand:
2383 convert = m.free("in->", conv=True)
2384 if self.operand.needs_conversion() and not self.operand.needs_unwrapping():
2385 body += " " + convert
2387 unwrap = m.free("in->", conv=False)
2388 if convert == unwrap:
2389 body += " " + unwrap
2391 body += "#if defined(USE_STRUCT_CONVERSION)\n"
2392 body += " " + convert
2393 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2395 body += "#if defined(USE_STRUCT_CONVERSION)\n"
2396 body += " " + convert
2398 body += " " + unwrap
2399 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2403 if not self.operand.needs_unwrapping():
2404 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2410 def definition(self):
2412 return self._generate_array_free_func()
2414 # Some structures need freeing too if they contain dynamic arrays.
2415 # E.g. VkCommandBufferBeginInfo
2416 return self._generate_free_func()
2419 class StructChainConversionFunction(object):
2420 def __init__(self, direction, struct):
2421 self.direction = direction
2422 self.struct = struct
2423 self.type = struct.name
2425 self.name = "convert_{0}_struct_chain".format(self.type)
2427 def __eq__(self, other):
2428 return self.name == other.name
2430 def prototype(self, postfix=""):
2431 return "VkResult {0}(const void *pNext, {1} *out_struct) {2}".format(self.name, self.type, postfix).strip()
2433 def definition(self):
2434 body = self.prototype()
2437 body += " VkBaseOutStructure *out_header = (VkBaseOutStructure *)out_struct;\n";
2438 body += " const VkBaseInStructure *in_header;\n\n";
2440 body += " out_header->pNext = NULL;\n\n"
2442 body += " for (in_header = pNext; in_header; in_header = in_header->pNext)\n"
2444 body += " switch (in_header->sType)\n"
2447 # Ignore to not confuse host loader.
2448 body += " case VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO:\n"
2449 body += " case VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO:\n"
2450 body += " break;\n\n"
2452 for e in self.struct.struct_extensions:
2456 stype = next(x for x in e.members if x.name == "sType")
2458 body += " case {0}:\n".format(stype.values)
2461 body += " const {0} *in = (const {0} *)in_header;\n".format(e.name)
2462 body += " {0} *out;\n\n".format(e.name)
2464 body += " if (!(out = malloc(sizeof(*out)))) goto out_of_memory;\n\n"
2467 if m.name == "pNext":
2468 body += " out->pNext = NULL;\n"
2470 convert = m.copy("in->", "out->", self.direction, conv=True)
2471 unwrap = m.copy("in->", "out->", self.direction, conv=False)
2472 if unwrap == convert:
2473 body += " " + unwrap
2475 body += "#if defined(USE_STRUCT_CONVERSION)\n"
2476 body += " " + convert
2478 body += " " + unwrap
2479 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2481 body += "\n out_header->pNext = (VkBaseOutStructure *)out;\n"
2482 body += " out_header = out_header->pNext;\n"
2486 body += " default:\n"
2487 body += " FIXME(\"Application requested a linked structure of type %u.\\n\", in_header->sType);\n"
2492 body += " return VK_SUCCESS;\n"
2494 if any(x for x in self.struct.struct_extensions if x.required):
2495 body += "\nout_of_memory:\n"
2496 body += " free_{0}_struct_chain(out_struct);\n".format(self.type)
2497 body += " return VK_ERROR_OUT_OF_HOST_MEMORY;\n"
2502 class FreeStructChainFunction(object):
2503 def __init__(self, struct):
2504 self.struct = struct
2505 self.type = struct.name
2507 self.name = "free_{0}_struct_chain".format(self.type)
2509 def __eq__(self, other):
2510 return self.name == other.name
2512 def prototype(self, postfix=""):
2513 return "void {0}({1} *s) {2}".format(self.name, self.type, postfix).strip()
2515 def definition(self):
2516 body = self.prototype()
2519 body += " VkBaseOutStructure *header = (void *)s->pNext;\n\n";
2521 body += " while (header)\n"
2523 body += " void *prev = header;\n\n"
2524 body += " switch (header->sType)\n"
2527 for e in self.struct.struct_extensions:
2531 if not any(m.needs_free() for m in e):
2534 stype = next(x for x in e.members if x.name == "sType")
2536 body += " case {0}:\n".format(stype.values)
2538 body += " {0} *structure = ({0} *) header;\n".format(e.name)
2542 convert = m.free("structure->", conv=True)
2543 unwrap = m.free("structure->", conv=False)
2544 if convert == unwrap:
2545 body += " " + unwrap
2547 body += "#if defined(USE_STRUCT_CONVERSION)\n"
2548 body += " " + convert
2549 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2551 body += "#if defined(USE_STRUCT_CONVERSION)\n"
2552 body += " " + convert
2554 body += " " + unwrap
2555 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2560 body += " default:\n"
2564 body += " header = header->pNext;\n"
2565 body += " free(prev);\n"
2568 body += " s->pNext = NULL;\n"
2574 class VkGenerator(object):
2575 def __init__(self, registry):
2576 self.registry = registry
2578 # Build a list conversion functions for struct conversion.
2579 self.conversions = []
2580 self.struct_chain_conversions = []
2581 self.host_structs = []
2582 for func in self.registry.funcs.values():
2583 if not func.is_required():
2586 if not func.needs_conversion() and not func.needs_unwrapping():
2589 conversions = func.get_conversions()
2590 for conv in conversions:
2591 # Pull in any conversions for vulkan_thunks.c.
2592 if func.needs_thunk():
2593 # Append if we don't already have this conversion.
2594 if not any(c == conv for c in self.conversions):
2595 self.conversions.append(conv)
2597 if not isinstance(conv.operand, VkStruct):
2600 # Structs can be used in different ways by different conversions
2601 # e.g. array vs non-array. Just make sure we pull in each struct once.
2602 if not any(s.name == conv.operand.name for s in self.host_structs):
2603 self.host_structs.append(conv.operand)
2605 for struct in self.registry.structs:
2606 if struct.name in STRUCT_CHAIN_CONVERSIONS:
2607 self.struct_chain_conversions.append(StructChainConversionFunction(Direction.INPUT, struct))
2608 self.struct_chain_conversions.append(FreeStructChainFunction(struct))
2609 # Once we decide to support pNext chains conversion everywhere, move this under get_conversions
2610 for e in struct.struct_extensions:
2612 if m.needs_conversion() or m.needs_unwrapping():
2613 conversions = m.get_conversions()
2614 for conv in conversions:
2615 if not any(c == conv for c in self.conversions):
2616 self.conversions.append(conv)
2618 def _generate_copyright(self, f, spec_file=False):
2619 f.write("# " if spec_file else "/* ")
2620 f.write("Automatically generated from Vulkan vk.xml; DO NOT EDIT!\n")
2621 lines = ["", "This file is generated from Vulkan vk.xml file covered",
2622 "by the following copyright and permission notice:"]
2623 lines.extend([l.rstrip(" ") for l in self.registry.copyright.splitlines()])
2625 f.write("{0}{1}".format("# " if spec_file else " * ", line).rstrip(" ") + "\n")
2626 f.write("\n" if spec_file else " */\n\n")
2628 def generate_thunks_c(self, f, prefix):
2629 self._generate_copyright(f)
2632 f.write("#pragma makedep unix\n")
2633 f.write("#endif\n\n")
2635 f.write("#include \"config.h\"\n")
2636 f.write("#include \"wine/port.h\"\n\n")
2638 f.write("#include \"vulkan_private.h\"\n\n")
2640 f.write("WINE_DEFAULT_DEBUG_CHANNEL(vulkan);\n\n")
2642 # Generate any conversion helper functions.
2643 for conv in self.conversions:
2644 f.write(conv.definition())
2646 for conv in self.struct_chain_conversions:
2647 f.write(conv.definition())
2649 # Create thunks for instance and device functions.
2650 # Global functions don't go through the thunks.
2651 for vk_func in self.registry.funcs.values():
2652 if not vk_func.is_required():
2655 if vk_func.is_global_func():
2658 if not vk_func.needs_thunk():
2661 # Exports symbols for Core functions.
2662 if not vk_func.is_core_func() and not vk_func.needs_private_thunk():
2665 if vk_func.needs_private_thunk():
2666 f.write(vk_func.thunk(prefix="thunk_"))
2668 f.write(vk_func.thunk(prefix=prefix, call_conv="WINAPI"))
2670 # Create array of device extensions.
2671 f.write("static const char * const vk_device_extensions[] =\n{\n")
2672 for ext in self.registry.extensions:
2673 if ext["type"] != "device":
2676 f.write(" \"{0}\",\n".format(ext["name"]))
2679 # Create array of instance extensions.
2680 f.write("static const char * const vk_instance_extensions[] =\n{\n")
2681 for ext in self.registry.extensions:
2682 if ext["type"] != "instance":
2685 f.write(" \"{0}\",\n".format(ext["name"]))
2688 f.write("BOOL wine_vk_device_extension_supported(const char *name)\n")
2690 f.write(" unsigned int i;\n")
2691 f.write(" for (i = 0; i < ARRAY_SIZE(vk_device_extensions); i++)\n")
2693 f.write(" if (strcmp(vk_device_extensions[i], name) == 0)\n")
2694 f.write(" return TRUE;\n")
2696 f.write(" return FALSE;\n")
2699 f.write("BOOL wine_vk_instance_extension_supported(const char *name)\n")
2701 f.write(" unsigned int i;\n")
2702 f.write(" for (i = 0; i < ARRAY_SIZE(vk_instance_extensions); i++)\n")
2704 f.write(" if (strcmp(vk_instance_extensions[i], name) == 0)\n")
2705 f.write(" return TRUE;\n")
2707 f.write(" return FALSE;\n")
2710 f.write("BOOL wine_vk_is_type_wrapped(VkObjectType type)\n")
2712 f.write(" return FALSE")
2713 for handle in self.registry.handles:
2714 if not handle.is_required() or not handle.is_wrapped() or handle.is_alias():
2716 f.write(" ||\n type == {}".format(handle.object_type))
2720 f.write("uint64_t wine_vk_unwrap_handle(VkObjectType type, uint64_t handle)\n")
2722 f.write(" switch(type)\n")
2724 for handle in self.registry.handles:
2725 if not handle.is_required() or not handle.is_wrapped() or handle.is_alias():
2727 f.write(" case {}:\n".format(handle.object_type))
2728 if handle.is_dispatchable():
2729 f.write(" return (uint64_t) (uintptr_t) ")
2730 f.write(handle.native_handle("(({}) (uintptr_t) handle)".format(handle.name)))
2732 f.write(" return (uint64_t) ")
2733 f.write(handle.native_handle("handle"))
2735 f.write(" default:\n")
2736 f.write(" return handle;\n")
2740 f.write("const struct unix_funcs loader_funcs =\n")
2742 for vk_func in self.registry.funcs.values():
2743 if not vk_func.is_required():
2745 if vk_func.loader_thunk_type == ThunkType.NONE:
2748 f.write(" &{1}{0},\n".format(vk_func.name, prefix))
2751 def generate_thunks_h(self, f, prefix):
2752 self._generate_copyright(f)
2754 f.write("#ifndef __WINE_VULKAN_THUNKS_H\n")
2755 f.write("#define __WINE_VULKAN_THUNKS_H\n\n")
2757 f.write("#define WINE_VK_VERSION VK_API_VERSION_{0}_{1}\n\n".format(WINE_VK_VERSION[0], WINE_VK_VERSION[1]))
2759 # Generate prototypes for device and instance functions requiring a custom implementation.
2760 f.write("/* Functions for which we have custom implementations outside of the thunks. */\n")
2761 for vk_func in self.registry.funcs.values():
2762 if not vk_func.is_required():
2764 if vk_func.needs_thunk() and not vk_func.needs_private_thunk():
2767 if vk_func.is_core_func():
2768 f.write("{0};\n".format(vk_func.prototype("WINAPI", prefix=prefix)))
2770 f.write("{0};\n".format(vk_func.prototype("WINAPI", prefix=prefix, postfix="DECLSPEC_HIDDEN")))
2773 f.write("/* Private thunks */\n")
2774 for vk_func in self.registry.funcs.values():
2775 if vk_func.needs_private_thunk():
2776 f.write("{0};\n".format(vk_func.prototype(prefix="thunk_", postfix="DECLSPEC_HIDDEN")))
2779 for struct in self.host_structs:
2780 f.write(struct.definition(align=False, conv=True, postfix="_host"))
2783 for func in self.struct_chain_conversions:
2784 f.write(func.prototype(postfix="DECLSPEC_HIDDEN") + ";\n")
2787 f.write("/* For use by vkDevice and children */\n")
2788 f.write("struct vulkan_device_funcs\n{\n")
2789 for vk_func in self.registry.device_funcs:
2790 if not vk_func.is_required():
2793 if not vk_func.needs_dispatch():
2794 LOGGER.debug("skipping {0} in vulkan_device_funcs".format(vk_func.name))
2797 if vk_func.needs_conversion():
2798 f.write("#if defined(USE_STRUCT_CONVERSION)\n")
2799 f.write(" {0};\n".format(vk_func.pfn(conv=True)))
2801 f.write(" {0};\n".format(vk_func.pfn(conv=False)))
2804 f.write(" {0};\n".format(vk_func.pfn(conv=False)))
2807 f.write("/* For use by vkInstance and children */\n")
2808 f.write("struct vulkan_instance_funcs\n{\n")
2809 for vk_func in self.registry.instance_funcs + self.registry.phys_dev_funcs:
2810 if not vk_func.is_required():
2813 if not vk_func.needs_dispatch():
2814 LOGGER.debug("skipping {0} in vulkan_instance_funcs".format(vk_func.name))
2817 if vk_func.needs_conversion():
2818 f.write("#if defined(USE_STRUCT_CONVERSION)\n")
2819 f.write(" {0};\n".format(vk_func.pfn(conv=True)))
2821 f.write(" {0};\n".format(vk_func.pfn(conv=False)))
2824 f.write(" {0};\n".format(vk_func.pfn(conv=False)))
2827 f.write("#define ALL_VK_DEVICE_FUNCS() \\\n")
2829 for vk_func in self.registry.device_funcs:
2830 if not vk_func.is_required():
2833 if not vk_func.needs_dispatch():
2834 LOGGER.debug("skipping {0} in ALL_VK_DEVICE_FUNCS".format(vk_func.name))
2838 f.write(" USE_VK_FUNC({0})".format(vk_func.name))
2841 f.write(" \\\n USE_VK_FUNC({0})".format(vk_func.name))
2844 f.write("#define ALL_VK_INSTANCE_FUNCS() \\\n")
2846 for vk_func in self.registry.instance_funcs + self.registry.phys_dev_funcs:
2847 if not vk_func.is_required():
2850 if not vk_func.needs_dispatch():
2851 LOGGER.debug("skipping {0} in ALL_VK_INSTANCE_FUNCS".format(vk_func.name))
2855 f.write(" USE_VK_FUNC({0})".format(vk_func.name))
2858 f.write(" \\\n USE_VK_FUNC({0})".format(vk_func.name))
2861 f.write("#endif /* __WINE_VULKAN_THUNKS_H */\n")
2863 def generate_loader_thunks_c(self, f):
2864 self._generate_copyright(f)
2866 f.write("#include \"vulkan_loader.h\"\n\n")
2868 f.write("WINE_DEFAULT_DEBUG_CHANNEL(vulkan);\n\n")
2870 for vk_func in self.registry.funcs.values():
2871 if not vk_func.is_required():
2873 if vk_func.loader_thunk_type != ThunkType.PUBLIC:
2876 f.write(vk_func.loader_thunk())
2878 f.write("static const struct vulkan_func vk_device_dispatch_table[] =\n{\n")
2879 for vk_func in self.registry.device_funcs:
2880 if not vk_func.is_required():
2883 f.write(" {{\"{0}\", &{0}}},\n".format(vk_func.name))
2886 f.write("static const struct vulkan_func vk_phys_dev_dispatch_table[] =\n{\n")
2887 for vk_func in self.registry.phys_dev_funcs:
2888 if not vk_func.is_required():
2891 f.write(" {{\"{0}\", &{0}}},\n".format(vk_func.name))
2894 f.write("static const struct vulkan_func vk_instance_dispatch_table[] =\n{\n")
2895 for vk_func in self.registry.instance_funcs:
2896 if not vk_func.is_required():
2899 f.write(" {{\"{0}\", &{0}}},\n".format(vk_func.name))
2902 f.write("void *wine_vk_get_device_proc_addr(const char *name)\n")
2904 f.write(" unsigned int i;\n")
2905 f.write(" for (i = 0; i < ARRAY_SIZE(vk_device_dispatch_table); i++)\n")
2907 f.write(" if (strcmp(vk_device_dispatch_table[i].name, name) == 0)\n")
2909 f.write(" TRACE(\"Found name=%s in device table\\n\", debugstr_a(name));\n")
2910 f.write(" return vk_device_dispatch_table[i].func;\n")
2913 f.write(" return NULL;\n")
2916 f.write("void *wine_vk_get_phys_dev_proc_addr(const char *name)\n")
2918 f.write(" unsigned int i;\n")
2919 f.write(" for (i = 0; i < ARRAY_SIZE(vk_phys_dev_dispatch_table); i++)\n")
2921 f.write(" if (strcmp(vk_phys_dev_dispatch_table[i].name, name) == 0)\n")
2923 f.write(" TRACE(\"Found name=%s in physical device table\\n\", debugstr_a(name));\n")
2924 f.write(" return vk_phys_dev_dispatch_table[i].func;\n")
2927 f.write(" return NULL;\n")
2930 f.write("void *wine_vk_get_instance_proc_addr(const char *name)\n")
2932 f.write(" unsigned int i;\n")
2933 f.write(" for (i = 0; i < ARRAY_SIZE(vk_instance_dispatch_table); i++)\n")
2935 f.write(" if (strcmp(vk_instance_dispatch_table[i].name, name) == 0)\n")
2937 f.write(" TRACE(\"Found name=%s in instance table\\n\", debugstr_a(name));\n")
2938 f.write(" return vk_instance_dispatch_table[i].func;\n")
2941 f.write(" return NULL;\n")
2944 def generate_loader_thunks_h(self, f):
2945 self._generate_copyright(f)
2947 f.write("#ifndef __WINE_VULKAN_LOADER_THUNKS_H\n")
2948 f.write("#define __WINE_VULKAN_LOADER_THUNKS_H\n\n")
2950 f.write("struct unix_funcs\n")
2952 for vk_func in self.registry.funcs.values():
2953 if not vk_func.is_required():
2955 if vk_func.loader_thunk_type == ThunkType.NONE:
2958 f.write(" {0};\n".format(vk_func.pfn(conv=False, call_conv="WINAPI")))
2961 f.write("#endif /* __WINE_VULKAN_LOADER_THUNKS_H */\n")
2963 def generate_vulkan_h(self, f):
2964 self._generate_copyright(f)
2965 f.write("#ifndef __WINE_VULKAN_H\n")
2966 f.write("#define __WINE_VULKAN_H\n\n")
2968 f.write("#include <windef.h>\n")
2969 f.write("#include <stdint.h>\n\n")
2971 f.write("/* Define WINE_VK_HOST to get 'host' headers. */\n")
2972 f.write("#ifdef WINE_VK_HOST\n")
2973 f.write("#define VKAPI_CALL\n")
2974 f.write('#define WINE_VK_ALIGN(x)\n')
2975 f.write("#endif\n\n")
2977 f.write("#ifndef VKAPI_CALL\n")
2978 f.write("#define VKAPI_CALL __stdcall\n")
2979 f.write("#endif\n\n")
2981 f.write("#ifndef VKAPI_PTR\n")
2982 f.write("#define VKAPI_PTR VKAPI_CALL\n")
2983 f.write("#endif\n\n")
2985 f.write("#ifndef WINE_VK_ALIGN\n")
2986 f.write("#define WINE_VK_ALIGN DECLSPEC_ALIGN\n")
2987 f.write("#endif\n\n")
2989 # The overall strategy is to define independent constants and datatypes,
2990 # prior to complex structures and function calls to avoid forward declarations.
2991 for const in self.registry.consts:
2992 # For now just generate things we may not need. The amount of parsing needed
2993 # to get some of the info is tricky as you need to figure out which structure
2994 # references a certain constant.
2995 f.write(const.definition())
2998 for define in self.registry.defines:
2999 f.write(define.definition())
3001 for handle in self.registry.handles:
3002 # For backward compatibility also create definitions for aliases.
3003 # These types normally don't get pulled in as we use the new types
3004 # even in legacy functions if they are aliases.
3005 if handle.is_required() or handle.is_alias():
3006 f.write(handle.definition())
3009 for base_type in self.registry.base_types:
3010 f.write(base_type.definition())
3013 for bitmask in self.registry.bitmasks:
3014 f.write(bitmask.definition())
3017 # Define enums, this includes values for some of the bitmask types as well.
3018 for enum in self.registry.enums.values():
3020 f.write(enum.definition())
3022 for fp in self.registry.funcpointers:
3024 f.write(fp.definition())
3027 # This generates both structures and unions. Since structures
3028 # may depend on other structures/unions, we need a list of
3029 # decoupled structs.
3030 # Note: unions are stored in structs for dependency reasons,
3031 # see comment in parsing section.
3032 structs = VkStruct.decouple_structs(self.registry.structs)
3033 for struct in structs:
3034 LOGGER.debug("Generating struct: {0}".format(struct.name))
3035 f.write(struct.definition(align=True))
3037 for func in self.registry.funcs.values():
3038 if not func.is_required():
3039 LOGGER.debug("Skipping PFN definition for: {0}".format(func.name))
3042 f.write("typedef {0};\n".format(func.pfn(prefix="PFN", call_conv="VKAPI_PTR")))
3045 f.write("#ifndef VK_NO_PROTOTYPES\n")
3046 for func in self.registry.funcs.values():
3047 if not func.is_required():
3048 LOGGER.debug("Skipping API definition for: {0}".format(func.name))
3051 LOGGER.debug("Generating API definition for: {0}".format(func.name))
3052 f.write("{0};\n".format(func.prototype(call_conv="VKAPI_CALL")))
3053 f.write("#endif /* VK_NO_PROTOTYPES */\n\n")
3055 f.write("#endif /* __WINE_VULKAN_H */\n")
3057 def generate_vulkan_driver_h(self, f):
3058 self._generate_copyright(f)
3059 f.write("#ifndef __WINE_VULKAN_DRIVER_H\n")
3060 f.write("#define __WINE_VULKAN_DRIVER_H\n\n")
3062 f.write("/* Wine internal vulkan driver version, needs to be bumped upon vulkan_funcs changes. */\n")
3063 f.write("#define WINE_VULKAN_DRIVER_VERSION {0}\n\n".format(DRIVER_VERSION))
3065 f.write("struct vulkan_funcs\n{\n")
3066 f.write(" /* Vulkan global functions. These are the only calls at this point a graphics driver\n")
3067 f.write(" * needs to provide. Other function calls will be provided indirectly by dispatch\n")
3068 f.write(" * tables part of dispatchable Vulkan objects such as VkInstance or vkDevice.\n")
3071 for vk_func in self.registry.funcs.values():
3072 if not vk_func.is_driver_func():
3076 # Avoid PFN_vkVoidFunction in driver interface as Vulkan likes to put calling convention
3077 # stuff in there. For simplicity substitute with "void *".
3078 pfn = pfn.replace("PFN_vkVoidFunction", "void *")
3079 f.write(" {0};\n".format(pfn))
3082 f.write(" /* winevulkan specific functions */\n")
3083 f.write(" VkSurfaceKHR (*p_wine_get_native_surface)(VkSurfaceKHR);\n")
3086 f.write("extern const struct vulkan_funcs * CDECL __wine_get_vulkan_driver(HDC hdc, UINT version);\n\n")
3088 f.write("static inline void *get_vulkan_driver_device_proc_addr(\n")
3089 f.write(" const struct vulkan_funcs *vulkan_funcs, const char *name)\n{\n")
3090 f.write(" if (!name || name[0] != 'v' || name[1] != 'k') return NULL;\n\n")
3091 f.write(" name += 2;\n\n")
3092 for vk_func in self.registry.funcs.values():
3093 if vk_func.is_driver_func() and vk_func.is_device_func():
3094 f.write(' if (!strcmp(name, "{0}"))\n'.format(vk_func.name[2:]))
3095 f.write(' return vulkan_funcs->p_{0};\n'.format(vk_func.name))
3097 f.write(" return NULL;\n}\n\n")
3099 f.write("static inline void *get_vulkan_driver_instance_proc_addr(\n")
3100 f.write(" const struct vulkan_funcs *vulkan_funcs, VkInstance instance, const char *name)\n{\n")
3101 f.write(" if (!name || name[0] != 'v' || name[1] != 'k') return NULL;\n\n")
3102 f.write(" name += 2;\n\n")
3103 for vk_func in self.registry.funcs.values():
3104 if vk_func.is_driver_func() and vk_func.is_global_func() and vk_func.name != "vkGetInstanceProcAddr":
3105 f.write(' if (!strcmp(name, "{0}"))\n'.format(vk_func.name[2:]))
3106 f.write(' return vulkan_funcs->p_{0};\n'.format(vk_func.name))
3108 f.write(" if (!instance) return NULL;\n\n")
3109 for vk_func in self.registry.funcs.values():
3110 if vk_func.is_driver_func() and (vk_func.is_instance_func() or vk_func.is_phys_dev_func()):
3111 f.write(' if (!strcmp(name, "{0}"))\n'.format(vk_func.name[2:]))
3112 f.write(' return vulkan_funcs->p_{0};\n'.format(vk_func.name))
3114 f.write(" name -= 2;\n\n")
3115 f.write(" return get_vulkan_driver_device_proc_addr(vulkan_funcs, name);\n}\n\n")
3117 f.write("#endif /* __WINE_VULKAN_DRIVER_H */\n")
3119 def generate_vulkan_spec(self, f):
3120 self._generate_copyright(f, spec_file=True)
3121 f.write("@ stdcall -private vk_icdGetInstanceProcAddr(ptr str)\n")
3122 f.write("@ stdcall -private vk_icdGetPhysicalDeviceProcAddr(ptr str)\n")
3123 f.write("@ stdcall -private vk_icdNegotiateLoaderICDInterfaceVersion(ptr)\n")
3125 # Export symbols for all Vulkan Core functions.
3126 for func in self.registry.funcs.values():
3127 if not func.is_core_func():
3130 # We support all Core functions except for VK_KHR_display* APIs.
3131 # Create stubs for unsupported Core functions.
3132 if func.is_required():
3133 f.write(func.spec())
3135 f.write("@ stub {0}\n".format(func.name))
3137 f.write("@ stdcall -private DllRegisterServer()\n")
3138 f.write("@ stdcall -private DllUnregisterServer()\n")
3140 def generate_vulkan_loader_spec(self, f):
3141 self._generate_copyright(f, spec_file=True)
3143 # Export symbols for all Vulkan Core functions.
3144 for func in self.registry.funcs.values():
3145 if not func.is_core_func():
3148 # We support all Core functions except for VK_KHR_display* APIs.
3149 # Create stubs for unsupported Core functions.
3150 if func.is_required():
3151 f.write(func.spec(symbol="winevulkan." + func.name))
3153 f.write("@ stub {0}\n".format(func.name))
3156 class VkRegistry(object):
3157 def __init__(self, reg_filename):
3158 # Used for storage of type information.
3159 self.base_types = None
3160 self.bitmasks = None
3164 self.funcpointers = None
3168 # We aggregate all types in here for cross-referencing.
3172 self.version_regex = re.compile(
3181 # Overall strategy for parsing the registry is to first
3182 # parse all type / function definitions. Then parse
3183 # features and extensions to decide which types / functions
3184 # to actually 'pull in' for code generation. For each type or
3185 # function call we want we set a member 'required' to True.
3186 tree = ET.parse(reg_filename)
3187 root = tree.getroot()
3188 self._parse_enums(root)
3189 self._parse_types(root)
3190 self._parse_commands(root)
3192 # Pull in any required types and functions.
3193 self._parse_features(root)
3194 self._parse_extensions(root)
3196 self._match_object_types()
3198 self.copyright = root.find('./comment').text
3200 def _is_feature_supported(self, feature):
3201 version = self.version_regex.match(feature)
3205 version = tuple(map(int, version.group('major', 'minor')))
3206 return version <= WINE_VK_VERSION
3208 def _is_extension_supported(self, extension):
3209 # We disable some extensions as either we haven't implemented
3210 # support yet or because they are for platforms other than win32.
3211 return extension not in UNSUPPORTED_EXTENSIONS
3213 def _mark_command_required(self, command):
3214 """ Helper function to mark a certain command and the datatypes it needs as required."""
3215 def mark_bitmask_dependencies(bitmask, types):
3216 if bitmask.requires is not None:
3217 types[bitmask.requires]["data"].required = True
3219 def mark_funcpointer_dependencies(fp, types):
3220 for m in fp.members:
3221 type_info = types[m.type]
3223 # Complex types have a matching definition e.g. VkStruct.
3224 # Not needed for base types such as uint32_t.
3225 if "data" in type_info:
3226 types[m.type]["data"].required = True
3228 def mark_struct_dependencies(struct, types):
3230 type_info = types[m.type]
3232 # Complex types have a matching definition e.g. VkStruct.
3233 # Not needed for base types such as uint32_t.
3234 if "data" in type_info:
3235 types[m.type]["data"].required = True
3237 if type_info["category"] == "struct":
3239 mark_struct_dependencies(type_info["data"], types)
3240 elif type_info["category"] == "funcpointer":
3241 mark_funcpointer_dependencies(type_info["data"], types)
3242 elif type_info["category"] == "bitmask":
3243 mark_bitmask_dependencies(type_info["data"], types)
3245 func = self.funcs[command]
3246 func.required = True
3248 # Pull in return type
3249 if func.type != "void":
3250 self.types[func.type]["data"].required = True
3252 # Analyze parameter dependencies and pull in any type needed.
3253 for p in func.params:
3254 type_info = self.types[p.type]
3256 # Check if we are dealing with a complex type e.g. VkEnum, VkStruct and others.
3257 if "data" not in type_info:
3260 # Mark the complex type as required.
3261 type_info["data"].required = True
3262 if type_info["category"] == "struct":
3263 struct = type_info["data"]
3264 mark_struct_dependencies(struct, self.types)
3265 elif type_info["category"] == "bitmask":
3266 mark_bitmask_dependencies(type_info["data"], self.types)
3268 def _match_object_types(self):
3269 """ Matches each handle with the correct object type. """
3270 # Use upper case comparison for simplicity.
3272 for value in self.enums["VkObjectType"].values:
3273 object_name = "VK" + value.name[len("VK_OBJECT_TYPE"):].replace("_", "")
3274 object_types[object_name] = value.name
3276 for handle in self.handles:
3277 if not handle.is_required():
3279 handle.object_type = object_types.get(handle.name.upper())
3280 if not handle.object_type:
3281 LOGGER.warning("No object type found for {}".format(handle.name))
3283 def _parse_commands(self, root):
3284 """ Parse command section containing the Vulkan function calls. """
3286 commands = root.findall("./commands/")
3288 # As of Vulkan 1.1, various extensions got promoted to Core.
3289 # The old commands (e.g. KHR) are available for backwards compatibility
3290 # and are marked in vk.xml as 'alias' to the non-extension type.
3291 # The registry likes to avoid data duplication, so parameters and other
3292 # metadata need to be looked up from the Core command.
3293 # We parse the alias commands in a second pass.
3295 for command in commands:
3296 alias_name = command.attrib.get("alias")
3298 alias_commands.append(command)
3301 func = VkFunction.from_xml(command, self.types)
3302 funcs[func.name] = func
3304 for command in alias_commands:
3305 alias_name = command.attrib.get("alias")
3306 alias = funcs[alias_name]
3307 func = VkFunction.from_alias(command, alias)
3308 funcs[func.name] = func
3310 # To make life easy for the code generation, separate all function
3311 # calls out in the 4 types of Vulkan functions:
3312 # device, global, physical device and instance.
3317 for func in funcs.values():
3318 if func.is_device_func():
3319 device_funcs.append(func)
3320 elif func.is_global_func():
3321 global_funcs.append(func)
3322 elif func.is_phys_dev_func():
3323 phys_dev_funcs.append(func)
3325 instance_funcs.append(func)
3327 # Sort function lists by name and store them.
3328 self.device_funcs = sorted(device_funcs, key=lambda func: func.name)
3329 self.global_funcs = sorted(global_funcs, key=lambda func: func.name)
3330 self.phys_dev_funcs = sorted(phys_dev_funcs, key=lambda func: func.name)
3331 self.instance_funcs = sorted(instance_funcs, key=lambda func: func.name)
3333 # The funcs dictionary is used as a convenient way to lookup function
3334 # calls when needed e.g. to adjust member variables.
3335 self.funcs = OrderedDict(sorted(funcs.items()))
3337 def _parse_enums(self, root):
3338 """ Parse enums section or better described as constants section. """
3341 for enum in root.findall("./enums"):
3342 name = enum.attrib.get("name")
3343 _type = enum.attrib.get("type")
3345 if _type in ("enum", "bitmask"):
3346 enums[name] = VkEnum.from_xml(enum)
3348 # If no type is set, we are dealing with API constants.
3349 for value in enum.findall("enum"):
3350 # If enum is an alias, set the value to the alias name.
3351 # E.g. VK_LUID_SIZE_KHR is an alias to VK_LUID_SIZE.
3352 alias = value.attrib.get("alias")
3354 self.consts.append(VkConstant(value.attrib.get("name"), alias))
3356 self.consts.append(VkConstant(value.attrib.get("name"), value.attrib.get("value")))
3358 self.enums = OrderedDict(sorted(enums.items()))
3360 def _process_require_enum(self, enum_elem, ext=None, only_aliased=False):
3361 if "extends" in enum_elem.keys():
3362 enum = self.types[enum_elem.attrib["extends"]]["data"]
3364 # Need to define VkEnumValues which were aliased to by another value. This is necessary
3365 # from VK spec version 1.2.135 where the provisional VK_KHR_ray_tracing extension was
3366 # added which altered VK_NV_ray_tracing's VkEnumValues to alias to the provisional
3369 for _, t in self.types.items():
3370 if t["category"] != "enum":
3374 for value in t["data"].values:
3375 if value.alias == enum_elem.attrib["name"]:
3378 if only_aliased and not aliased:
3381 if "bitpos" in enum_elem.keys():
3382 # We need to add an extra value to an existing enum type.
3383 # E.g. VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG to VkFormatFeatureFlagBits.
3384 enum.create_bitpos(enum_elem.attrib["name"], int(enum_elem.attrib["bitpos"]))
3386 elif "offset" in enum_elem.keys():
3387 # Extensions promoted to Core, have the extension number as part
3388 # of the enum value. Else retrieve from the extension tag.
3389 if enum_elem.attrib.get("extnumber"):
3390 ext_number = int(enum_elem.attrib.get("extnumber"))
3392 ext_number = int(ext.attrib["number"])
3393 offset = int(enum_elem.attrib["offset"])
3394 value = EXT_BASE + (ext_number - 1) * EXT_BLOCK_SIZE + offset
3396 # Deal with negative values.
3397 direction = enum_elem.attrib.get("dir")
3398 if direction is not None:
3401 enum.create_value(enum_elem.attrib["name"], str(value))
3403 elif "value" in enum_elem.keys():
3404 enum.create_value(enum_elem.attrib["name"], enum_elem.attrib["value"])
3405 elif "alias" in enum_elem.keys():
3406 enum.create_alias(enum_elem.attrib["name"], enum_elem.attrib["alias"])
3408 elif "value" in enum_elem.keys():
3409 # Constants are not aliased, no need to add them here, they'll get added later on.
3413 self.consts.append(VkConstant(enum_elem.attrib["name"], enum_elem.attrib["value"]))
3416 def _require_type(type_info):
3417 if type_info.is_alias():
3418 type_info = type_info.alias
3419 type_info.required = True
3420 if type(type_info) == VkStruct:
3421 for member in type_info.members:
3422 if "data" in member.type_info:
3423 VkRegistry._require_type(member.type_info["data"])
3425 def _parse_extensions(self, root):
3426 """ Parse extensions section and pull in any types and commands for this extension. """
3428 exts = root.findall("./extensions/extension")
3430 skipped_exts = UNSUPPORTED_EXTENSIONS.copy()
3432 def process_ext(ext, deferred=False):
3433 ext_name = ext.attrib["name"]
3435 # Set extension name on any functions calls part of this extension as we
3436 # were not aware of the name during initial parsing.
3437 commands = ext.findall("require/command")
3438 for command in commands:
3439 cmd_name = command.attrib["name"]
3440 # Need to verify that the command is defined, and otherwise skip it.
3441 # vkCreateScreenSurfaceQNX is declared in <extensions> but not defined in
3442 # <commands>. A command without a definition cannot be enabled, so it's valid for
3443 # the XML file to handle this, but because of the manner in which we parse the XML
3444 # file we pre-populate from <commands> before we check if a command is enabled.
3445 if cmd_name in self.funcs:
3446 self.funcs[cmd_name].extensions.append(ext_name)
3448 # Some extensions are not ready or have numbers reserved as a place holder.
3449 if ext.attrib["supported"] == "disabled":
3450 LOGGER.debug("Skipping disabled extension: {0}".format(ext_name))
3451 skipped_exts.append(ext_name)
3454 # Defer extensions with 'sortorder' as they are order-dependent for spec-parsing.
3455 if not deferred and "sortorder" in ext.attrib:
3456 deferred_exts.append(ext)
3459 # Disable highly experimental extensions as the APIs are unstable and can
3460 # change between minor Vulkan revisions until API is final and becomes KHR
3462 if ("KHX" in ext_name or "NVX" in ext_name) and ext_name not in ALLOWED_X_EXTENSIONS:
3463 LOGGER.debug("Skipping experimental extension: {0}".format(ext_name))
3464 skipped_exts.append(ext_name)
3467 # Extensions can define VkEnumValues which alias to provisional extensions. Pre-process
3468 # extensions to define any required VkEnumValues before the platform check below.
3469 for require in ext.findall("require"):
3470 # Extensions can add enum values to Core / extension enums, so add these.
3471 for enum_elem in require.findall("enum"):
3472 self._process_require_enum(enum_elem, ext, only_aliased=True)
3474 platform = ext.attrib.get("platform")
3475 if platform and platform != "win32":
3476 LOGGER.debug("Skipping extensions {0} for platform {1}".format(ext_name, platform))
3477 skipped_exts.append(ext_name)
3480 if not self._is_extension_supported(ext_name):
3481 LOGGER.debug("Skipping unsupported extension: {0}".format(ext_name))
3482 skipped_exts.append(ext_name)
3484 elif "requires" in ext.attrib:
3485 # Check if this extension builds on top of another unsupported extension.
3486 requires = ext.attrib["requires"].split(",")
3487 if len(set(requires).intersection(skipped_exts)) > 0:
3488 skipped_exts.append(ext_name)
3491 LOGGER.debug("Loading extension: {0}".format(ext_name))
3493 # Extensions can define one or more require sections each requiring
3494 # different features (e.g. Vulkan 1.1). Parse each require section
3495 # separately, so we can skip sections we don't want.
3496 for require in ext.findall("require"):
3497 # Extensions can add enum values to Core / extension enums, so add these.
3498 for enum_elem in require.findall("enum"):
3499 self._process_require_enum(enum_elem, ext)
3501 for t in require.findall("type"):
3502 type_info = self.types[t.attrib["name"]]["data"]
3503 self._require_type(type_info)
3504 feature = require.attrib.get("feature")
3505 if feature and not self._is_feature_supported(feature):
3508 required_extension = require.attrib.get("extension")
3509 if required_extension and not self._is_extension_supported(required_extension):
3512 # Pull in any commands we need. We infer types to pull in from the command
3514 for command in require.findall("command"):
3515 cmd_name = command.attrib["name"]
3516 self._mark_command_required(cmd_name)
3519 # Store a list with extensions.
3520 ext_info = {"name" : ext_name, "type" : ext.attrib["type"]}
3521 extensions.append(ext_info)
3524 # Process extensions, allowing for sortorder to defer extension processing
3528 deferred_exts.sort(key=lambda ext: ext.attrib["sortorder"])
3531 for ext in deferred_exts:
3532 process_ext(ext, deferred=True)
3534 # Sort in alphabetical order.
3535 self.extensions = sorted(extensions, key=lambda ext: ext["name"])
3537 def _parse_features(self, root):
3538 """ Parse the feature section, which describes Core commands and types needed. """
3540 for feature in root.findall("./feature"):
3541 feature_name = feature.attrib["name"]
3542 for require in feature.findall("require"):
3543 LOGGER.info("Including features for {0}".format(require.attrib.get("comment")))
3545 if tag.tag == "comment":
3547 elif tag.tag == "command":
3548 if not self._is_feature_supported(feature_name):
3550 name = tag.attrib["name"]
3551 self._mark_command_required(name)
3552 elif tag.tag == "enum":
3553 self._process_require_enum(tag)
3554 elif tag.tag == "type":
3555 name = tag.attrib["name"]
3557 # Skip pull in for vk_platform.h for now.
3558 if name == "vk_platform":
3561 type_info = self.types[name]
3562 type_info["data"].required = True
3564 def _parse_types(self, root):
3565 """ Parse types section, which contains all data types e.g. structs, typedefs etcetera. """
3566 types = root.findall("./types/type")
3578 type_info["category"] = t.attrib.get("category", None)
3579 type_info["requires"] = t.attrib.get("requires", None)
3581 # We parse aliases in a second pass when we know more.
3582 alias = t.attrib.get("alias")
3584 LOGGER.debug("Alias found: {0}".format(alias))
3585 alias_types.append(t)
3588 if type_info["category"] in ["include"]:
3591 if type_info["category"] == "basetype":
3592 name = t.find("name").text
3594 if not t.find("type") is None:
3595 _type = t.find("type").text
3596 basetype = VkBaseType(name, _type)
3597 base_types.append(basetype)
3598 type_info["data"] = basetype
3600 # Basic C types don't need us to define them, but we do need data for them
3601 if type_info["requires"] == "vk_platform":
3602 requires = type_info["requires"]
3603 basic_c = VkBaseType(name, _type, requires=requires)
3604 type_info["data"] = basic_c
3606 if type_info["category"] == "bitmask":
3607 name = t.find("name").text
3608 _type = t.find("type").text
3610 # Most bitmasks have a requires attribute used to pull in
3611 # required '*FlagBits" enum.
3612 requires = type_info["requires"]
3613 bitmask = VkBaseType(name, _type, requires=requires)
3614 bitmasks.append(bitmask)
3615 type_info["data"] = bitmask
3617 if type_info["category"] == "define":
3618 define = VkDefine.from_xml(t)
3619 defines.append(define)
3620 type_info["data"] = define
3622 if type_info["category"] == "enum":
3623 name = t.attrib.get("name")
3624 # The type section only contains enum names, not the actual definition.
3625 # Since we already parsed the enum before, just link it in.
3627 type_info["data"] = self.enums[name]
3628 except KeyError as e:
3629 # Not all enums seem to be defined yet, typically that's for
3630 # ones ending in 'FlagBits' where future extensions may add
3632 type_info["data"] = None
3634 if type_info["category"] == "funcpointer":
3635 funcpointer = VkFunctionPointer.from_xml(t)
3636 funcpointers.append(funcpointer)
3637 type_info["data"] = funcpointer
3639 if type_info["category"] == "handle":
3640 handle = VkHandle.from_xml(t)
3641 handles.append(handle)
3642 type_info["data"] = handle
3644 if type_info["category"] in ["struct", "union"]:
3645 # We store unions among structs as some structs depend
3646 # on unions. The types are very similar in parsing and
3647 # generation anyway. The official Vulkan scripts use
3648 # a similar kind of hack.
3649 struct = VkStruct.from_xml(t)
3650 structs.append(struct)
3651 type_info["data"] = struct
3653 # Name is in general within a name tag else it is an optional
3654 # attribute on the type tag.
3655 name_elem = t.find("name")
3656 if name_elem is not None:
3657 type_info["name"] = name_elem.text
3659 type_info["name"] = t.attrib.get("name", None)
3661 # Store all type data in a shared dictionary, so we can easily
3662 # look up information for a given type. There are no duplicate
3664 self.types[type_info["name"]] = type_info
3666 # Second pass for alias types, so we can retrieve all data from
3667 # the aliased object.
3668 for t in alias_types:
3670 type_info["category"] = t.attrib.get("category")
3671 type_info["name"] = t.attrib.get("name")
3673 alias = t.attrib.get("alias")
3675 if type_info["category"] == "bitmask":
3676 bitmask = VkBaseType(type_info["name"], alias, alias=self.types[alias]["data"])
3677 bitmasks.append(bitmask)
3678 type_info["data"] = bitmask
3680 if type_info["category"] == "enum":
3681 enum = VkEnum.from_alias(t, self.types[alias]["data"])
3682 type_info["data"] = enum
3683 self.enums[enum.name] = enum
3685 if type_info["category"] == "handle":
3686 handle = VkHandle.from_alias(t, self.types[alias]["data"])
3687 handles.append(handle)
3688 type_info["data"] = handle
3690 if type_info["category"] == "struct":
3691 struct = VkStruct.from_alias(t, self.types[alias]["data"])
3692 structs.append(struct)
3693 type_info["data"] = struct
3695 self.types[type_info["name"]] = type_info
3697 # We need detailed type information during code generation
3698 # on structs for alignment reasons. Unfortunately structs
3699 # are parsed among other types, so there is no guarantee
3700 # that any types needed have been parsed already, so set
3702 for struct in structs:
3703 struct.set_type_info(self.types)
3705 # Alias structures have enum values equivalent to those of the
3706 # structure which they are aliased against. we need to ignore alias
3707 # structs when populating the struct extensions list, otherwise we
3708 # will create duplicate case entries.
3712 for structextend in struct.structextends:
3713 s = self.types[structextend]["data"]
3714 s.struct_extensions.append(struct)
3716 # Guarantee everything is sorted, so code generation doesn't have
3717 # to deal with this.
3718 self.base_types = sorted(base_types, key=lambda base_type: base_type.name)
3719 self.bitmasks = sorted(bitmasks, key=lambda bitmask: bitmask.name)
3720 self.defines = defines
3721 self.enums = OrderedDict(sorted(self.enums.items()))
3722 self.funcpointers = sorted(funcpointers, key=lambda fp: fp.name)
3723 self.handles = sorted(handles, key=lambda handle: handle.name)
3724 self.structs = sorted(structs, key=lambda struct: struct.name)
3726 def generate_vulkan_json(f):
3728 f.write(" \"file_format_version\": \"1.0.0\",\n")
3729 f.write(" \"ICD\": {\n")
3730 f.write(" \"library_path\": \".\\\\winevulkan.dll\",\n")
3731 f.write(" \"api_version\": \"{0}\"\n".format(VK_XML_VERSION))
3735 def set_working_directory():
3736 path = os.path.abspath(__file__)
3737 path = os.path.dirname(path)
3740 def download_vk_xml(filename):
3741 url = "https://raw.githubusercontent.com/KhronosGroup/Vulkan-Docs/v{0}/xml/vk.xml".format(VK_XML_VERSION)
3742 if not os.path.isfile(filename):
3743 urllib.request.urlretrieve(url, filename)
3746 parser = argparse.ArgumentParser()
3747 parser.add_argument("-v", "--verbose", action="count", default=0, help="increase output verbosity")
3748 parser.add_argument("-x", "--xml", default=None, type=str, help="path to specification XML file")
3750 args = parser.parse_args()
3751 if args.verbose == 0:
3752 LOGGER.setLevel(logging.WARNING)
3753 elif args.verbose == 1:
3754 LOGGER.setLevel(logging.INFO)
3756 LOGGER.setLevel(logging.DEBUG)
3758 set_working_directory()
3763 vk_xml = "vk-{0}.xml".format(VK_XML_VERSION)
3764 download_vk_xml(vk_xml)
3766 registry = VkRegistry(vk_xml)
3767 generator = VkGenerator(registry)
3769 with open(WINE_VULKAN_H, "w") as f:
3770 generator.generate_vulkan_h(f)
3772 with open(WINE_VULKAN_DRIVER_H, "w") as f:
3773 generator.generate_vulkan_driver_h(f)
3775 with open(WINE_VULKAN_THUNKS_H, "w") as f:
3776 generator.generate_thunks_h(f, "wine_")
3778 with open(WINE_VULKAN_THUNKS_C, "w") as f:
3779 generator.generate_thunks_c(f, "wine_")
3781 with open(WINE_VULKAN_LOADER_THUNKS_H, "w") as f:
3782 generator.generate_loader_thunks_h(f)
3784 with open(WINE_VULKAN_LOADER_THUNKS_C, "w") as f:
3785 generator.generate_loader_thunks_c(f)
3787 with open(WINE_VULKAN_JSON, "w") as f:
3788 generate_vulkan_json(f)
3790 with open(WINE_VULKAN_SPEC, "w") as f:
3791 generator.generate_vulkan_spec(f)
3793 with open(WINE_VULKAN_LOADER_SPEC, "w") as f:
3794 generator.generate_vulkan_loader_spec(f)
3796 if __name__ == "__main__":