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.3.213"
68 WINE_VK_VERSION = (1, 3)
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_GOOGLE_display_timing",
100 "VK_KHR_external_fence_win32",
101 "VK_KHR_external_semaphore_win32",
102 # Relates to external_semaphore and needs type conversions in bitflags.
103 "VK_KHR_shared_presentable_image", # Needs WSI work.
104 "VK_KHR_win32_keyed_mutex",
105 "VK_NV_external_memory_rdma", # Needs shared resources work.
107 # Extensions for other platforms
108 "VK_EXT_external_memory_dma_buf",
109 "VK_EXT_image_drm_format_modifier",
110 "VK_EXT_physical_device_drm",
111 "VK_GOOGLE_surfaceless_query",
112 "VK_KHR_external_fence_fd",
113 "VK_KHR_external_memory_fd",
114 "VK_KHR_external_semaphore_fd",
116 # Extensions which require callback handling
117 "VK_EXT_device_memory_report",
119 # Needs https://github.com/KhronosGroup/Vulkan-Docs/pull/1848
120 # or a rework of how we detect returned structs.
121 "VK_EXT_image_compression_control",
123 # Deprecated extensions
124 "VK_NV_external_memory_capabilities",
125 "VK_NV_external_memory_win32",
128 # Either internal extensions which aren't present on the win32 platform which
129 # winevulkan may nonetheless use, or extensions we want to generate headers for
130 # but not expose to applications (useful for test commits)
131 UNEXPOSED_EXTENSIONS = {
132 "VK_KHR_external_memory_win32",
135 # The Vulkan loader provides entry-points for core functionality and important
136 # extensions. Based on vulkan-1.def this amounts to WSI extensions on 1.0.51.
139 "VK_KHR_display_swapchain",
140 "VK_KHR_get_surface_capabilities2",
143 "VK_KHR_win32_surface",
146 # Some experimental extensions are used by shipping applications so their API is extremely unlikely
147 # to change in a backwards-incompatible way. Allow translation of those extensions with WineVulkan.
148 ALLOWED_X_EXTENSIONS = [
149 "VK_NVX_binary_import",
150 "VK_NVX_image_view_handle",
153 # We can't use syscall interface for functions that may call display drivers
154 # until drivers are converted to pure Unix libraries. Also some frequently
155 # called functions use direct calls for performance reasons.
156 DIRECT_CALL_FUNCTIONS = [
158 "vkEnumerateInstanceVersion",
159 "vkUpdateDescriptorSets",
160 "vkUpdateDescriptorSetWithTemplate",
163 # Functions part of our winevulkan graphics driver interface.
164 # DRIVER_VERSION should be bumped on any change to driver interface
165 # in FUNCTION_OVERRIDES
168 class ThunkType(Enum):
173 # Table of functions for which we have a special implementation.
174 # These are regular device / instance functions for which we need
175 # to do more work compared to a regular thunk or because they are
176 # part of the driver interface.
177 # - dispatch set whether we need a function pointer in the device
178 # / instance dispatch table.
179 # - driver sets whether the API is part of the driver interface.
180 # - thunk sets whether to create a thunk in vulkan_thunks.c.
181 # - NONE means there's a fully custom implementation.
182 # - PUBLIC means the implementation is fully auto generated.
183 # - PRIVATE thunks can be used in custom implementations for
185 # - loader_thunk sets whether to create a thunk for unix_funcs.
186 FUNCTION_OVERRIDES = {
188 "vkCreateInstance" : {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE},
189 "vkEnumerateInstanceExtensionProperties" : {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE},
190 "vkEnumerateInstanceLayerProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.NONE},
191 "vkEnumerateInstanceVersion": {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE},
192 "vkGetInstanceProcAddr": {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.NONE},
195 "vkCreateDevice" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
196 "vkDestroyInstance" : {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE },
197 "vkEnumerateDeviceExtensionProperties" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
198 "vkEnumerateDeviceLayerProperties": {"dispatch": True, "driver": False, "thunk": ThunkType.NONE},
199 "vkEnumeratePhysicalDeviceGroups" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
200 "vkEnumeratePhysicalDevices" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
201 "vkGetPhysicalDeviceExternalBufferProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
202 "vkGetPhysicalDeviceExternalFenceProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
203 "vkGetPhysicalDeviceExternalSemaphoreProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
204 "vkGetPhysicalDeviceImageFormatProperties2" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE},
205 "vkGetPhysicalDeviceProperties2" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PUBLIC, "loader_thunk" : ThunkType.PRIVATE},
206 "vkGetPhysicalDeviceProperties2KHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PUBLIC, "loader_thunk" : ThunkType.PRIVATE},
209 "vkAllocateCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
210 "vkCreateCommandPool" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
211 "vkCreateComputePipelines" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.PRIVATE},
212 "vkCreateGraphicsPipelines" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.PRIVATE},
213 "vkDestroyCommandPool" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
214 "vkDestroyDevice" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
215 "vkFreeCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
216 "vkGetDeviceProcAddr" : {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.NONE},
217 "vkGetDeviceQueue" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
218 "vkGetDeviceQueue2" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
221 "vkDestroySurfaceKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.NONE},
222 "vkGetPhysicalDeviceSurfaceSupportKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
223 "vkGetPhysicalDeviceSurfaceCapabilitiesKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PRIVATE},
224 "vkGetPhysicalDeviceSurfaceFormatsKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
225 "vkGetPhysicalDeviceSurfacePresentModesKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
227 # VK_KHR_get_surface_capabilities2
228 "vkGetPhysicalDeviceSurfaceCapabilities2KHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PRIVATE},
229 "vkGetPhysicalDeviceSurfaceFormats2KHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
231 # VK_KHR_win32_surface
232 "vkCreateWin32SurfaceKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.NONE},
233 "vkGetPhysicalDeviceWin32PresentationSupportKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
236 "vkCreateSwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
237 "vkDestroySwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
238 "vkGetSwapchainImagesKHR": {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
239 "vkQueuePresentKHR": {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
241 # VK_KHR_external_fence_capabilities
242 "vkGetPhysicalDeviceExternalFencePropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
244 # VK_KHR_external_memory_capabilities
245 "vkGetPhysicalDeviceExternalBufferPropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
246 "vkGetPhysicalDeviceImageFormatProperties2KHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE},
248 # VK_KHR_external_semaphore_capabilities
249 "vkGetPhysicalDeviceExternalSemaphorePropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
251 # VK_KHR_device_group_creation
252 "vkEnumeratePhysicalDeviceGroupsKHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
254 # VK_KHR_device_group
255 "vkGetDeviceGroupSurfacePresentModesKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
256 "vkGetPhysicalDevicePresentRectanglesKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
258 # VK_KHR_ray_tracing_pipeline
259 "vkCreateRayTracingPipelinesKHR" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.PRIVATE},
261 # VK_EXT_calibrated_timestamps
262 "vkGetPhysicalDeviceCalibrateableTimeDomainsEXT" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
263 "vkGetCalibratedTimestampsEXT" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
266 "vkCreateDebugUtilsMessengerEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
267 "vkDestroyDebugUtilsMessengerEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
269 # VK_EXT_debug_report
270 "vkCreateDebugReportCallbackEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
271 "vkDestroyDebugReportCallbackEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
274 "vkCreateRayTracingPipelinesNV" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.PRIVATE},
277 STRUCT_CHAIN_CONVERSIONS = {
278 # Ignore to not confuse host loader.
279 "VkDeviceCreateInfo": ["VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO"],
280 "VkInstanceCreateInfo": ["VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO"],
284 class Direction(Enum):
285 """ Parameter direction: input, output, input_output. """
291 class VkBaseType(object):
292 def __init__(self, name, _type, alias=None, requires=None):
293 """ Vulkan base type class.
295 VkBaseType is mostly used by Vulkan to define its own
296 base types like VkFlags through typedef out of e.g. uint32_t.
299 name (:obj:'str'): Name of the base type.
300 _type (:obj:'str'): Underlying type
301 alias (bool): type is an alias or not.
302 requires (:obj:'str', optional): Other types required.
303 Often bitmask values pull in a *FlagBits type.
308 self.requires = requires
309 self.required = False
311 def definition(self):
312 # Definition is similar for alias or non-alias as type
313 # is already set to alias.
314 if not self.type is None:
315 return "typedef {0} {1};\n".format(self.type, self.name)
317 return "struct {0};\n".format(self.name)
320 return bool(self.alias)
323 class VkConstant(object):
324 def __init__(self, name, value):
328 def definition(self):
329 text = "#define {0} {1}\n".format(self.name, self.value)
333 class VkDefine(object):
334 def __init__(self, name, value):
339 def from_xml(define):
340 name_elem = define.find("name")
342 if name_elem is None:
343 # <type category="define" name="some_name">some_value</type>
344 name = define.attrib.get("name")
346 # We override behavior of VK_USE_64_BIT_PTR_DEFINES as the default non-dispatchable handle
347 # definition various between 64-bit (uses pointers) and 32-bit (uses uint64_t).
348 # This complicates TRACEs in the thunks, so just use uint64_t.
349 if name == "VK_USE_64_BIT_PTR_DEFINES":
350 value = "#define VK_USE_64_BIT_PTR_DEFINES 0"
353 return VkDefine(name, value)
355 # With a name element the structure is like:
356 # <type category="define"><name>some_name</name>some_value</type>
357 name = name_elem.text
359 # Perform minimal parsing for Vulkan constants, which we don't need, but are referenced
360 # elsewhere in vk.xml.
361 # - VK_API_VERSION is a messy, deprecated constant and we don't want generate code for it.
362 # - AHardwareBuffer/ANativeWindow are forward declarations for Android types, which leaked
363 # into the define region.
364 if name in ["VK_API_VERSION", "AHardwareBuffer", "ANativeWindow", "CAMetalLayer"]:
365 return VkDefine(name, None)
367 # The body of the define is basically unstructured C code. It is not meant for easy parsing.
368 # Some lines contain deprecated values or comments, which we try to filter out.
370 for line in define.text.splitlines():
371 # Skip comments or deprecated values.
378 if child.tail is not None:
379 # Split comments for VK_API_VERSION_1_0 / VK_API_VERSION_1_1
380 if "//" in child.tail:
381 value += child.tail.split("//")[0]
385 return VkDefine(name, value.rstrip(' '))
387 def definition(self):
388 if self.value is None:
391 # Nothing to do as the value was already put in the right form during parsing.
392 return "{0}\n".format(self.value)
395 class VkEnum(object):
396 def __init__(self, name, bitwidth, alias=None):
397 if not bitwidth in [32, 64]:
398 LOGGER.error("unknown bitwidth {0} for {1}".format(bitwidth, name))
400 self.bitwidth = bitwidth
401 self.values = [] if alias == None else alias.values
402 self.required = False
407 def from_alias(enum, alias):
408 name = enum.attrib.get("name")
409 aliasee = VkEnum(name, alias.bitwidth, alias=alias)
411 alias.add_aliased_by(aliasee)
416 name = enum.attrib.get("name")
417 bitwidth = int(enum.attrib.get("bitwidth", "32"))
418 result = VkEnum(name, bitwidth)
420 for v in enum.findall("enum"):
421 value_name = v.attrib.get("name")
422 # Value is either a value or a bitpos, only one can exist.
423 value = v.attrib.get("value")
424 alias_name = v.attrib.get("alias")
426 result.create_alias(value_name, alias_name)
428 result.create_value(value_name, value)
431 result.create_bitpos(value_name, int(v.attrib.get("bitpos")))
434 # vulkan.h contains a *_MAX_ENUM value set to 32-bit at the time of writing,
435 # which is to prepare for extensions as they can add values and hence affect
436 # the size definition.
437 max_name = re.sub(r'([0-9a-z_])([A-Z0-9])',r'\1_\2', name).upper() + "_MAX_ENUM"
438 result.create_value(max_name, "0x7fffffff")
442 def create_alias(self, name, alias_name):
443 """ Create an aliased value for this enum """
444 # Older GCC versions need a literal to initialize a static const uint64_t
445 # which is what we use for 64bit bitmasks.
446 if self.bitwidth == 64:
447 alias = next(x for x in self.values if x.name == alias_name)
448 self.add(VkEnumValue(name, self.bitwidth, value=alias.value, hex=alias.hex, alias=alias_name))
450 self.add(VkEnumValue(name, self.bitwidth, alias=alias_name))
452 def create_value(self, name, value):
453 """ Create a new value for this enum """
454 # Some values are in hex form. We want to preserve the hex representation
455 # at least when we convert back to a string. Internally we want to use int.
457 self.add(VkEnumValue(name, self.bitwidth, value=int(value, 0), hex=hex))
459 def create_bitpos(self, name, pos):
460 """ Create a new bitmask value for this enum """
461 self.add(VkEnumValue(name, self.bitwidth, value=(1 << pos), hex=True))
463 def add(self, value):
464 """ Add a value to enum. """
466 # Extensions can add new enum values. When an extension is promoted to Core
467 # the registry defines the value twice once for old extension and once for
468 # new Core features. Add the duplicate if it's explicitly marked as an
469 # alias, otherwise ignore it.
470 for v in self.values:
471 if not value.is_alias() and v.value == value.value:
472 LOGGER.debug("Adding duplicate enum value {0} to {1}".format(v, self.name))
474 # Avoid adding duplicate aliases multiple times
475 if not any(x.name == value.name for x in self.values):
476 self.values.append(value)
478 def definition(self):
482 default_value = 0x7ffffffe if self.bitwidth == 32 else 0xfffffffffffffffe
484 # Print values sorted, values can have been added in a random order.
485 values = sorted(self.values, key=lambda value: value.value if value.value is not None else default_value)
487 if self.bitwidth == 32:
488 text = "typedef enum {0}\n{{\n".format(self.name)
490 text += " {0},\n".format(value.definition())
491 text += "}} {0};\n".format(self.name)
492 elif self.bitwidth == 64:
493 text = "typedef VkFlags64 {0};\n\n".format(self.name)
495 text += "static const {0} {1};\n".format(self.name, value.definition())
497 for aliasee in self.aliased_by:
498 text += "typedef {0} {1};\n".format(self.name, aliasee.name)
504 return bool(self.alias)
506 def add_aliased_by(self, aliasee):
507 self.aliased_by.append(aliasee)
510 class VkEnumValue(object):
511 def __init__(self, name, bitwidth, value=None, hex=False, alias=None):
513 self.bitwidth = bitwidth
519 postfix = "ull" if self.bitwidth == 64 else ""
520 if self.is_alias() and self.value == None:
521 return "{0}={1}".format(self.name, self.alias)
522 return "{0}={1}{2}".format(self.name, self.value, postfix)
524 def definition(self):
525 """ Convert to text definition e.g. VK_FOO = 1 """
526 postfix = "ull" if self.bitwidth == 64 else ""
527 if self.is_alias() and self.value == None:
528 return "{0} = {1}".format(self.name, self.alias)
530 # Hex is commonly used for FlagBits and sometimes within
531 # a non-FlagBits enum for a bitmask value as well.
533 return "{0} = 0x{1:08x}{2}".format(self.name, self.value, postfix)
535 return "{0} = {1}{2}".format(self.name, self.value, postfix)
538 return self.alias is not None
541 class VkFunction(object):
542 def __init__(self, _type=None, name=None, params=[], alias=None):
543 self.extensions = set()
549 # For some functions we need some extra metadata from FUNCTION_OVERRIDES.
550 func_info = FUNCTION_OVERRIDES.get(self.name, None)
551 self.dispatch = func_info["dispatch"] if func_info else True
552 self.driver = func_info["driver"] if func_info else False
553 self.thunk_type = func_info["thunk"] if func_info else ThunkType.PUBLIC
554 self.loader_thunk_type = func_info["loader_thunk"] if func_info and "loader_thunk" in func_info else ThunkType.PUBLIC
556 # Required is set while parsing which APIs and types are required
557 # and is used by the code generation.
558 self.required = True if func_info else False
561 def from_alias(command, alias):
562 """ Create VkFunction from an alias command.
565 command: xml data for command
566 alias (VkFunction): function to use as a base for types / parameters.
571 func_name = command.attrib.get("name")
572 func_type = alias.type
573 params = alias.params
575 return VkFunction(_type=func_type, name=func_name, params=params, alias=alias)
578 def from_xml(command, types):
579 proto = command.find("proto")
580 func_name = proto.find("name").text
581 func_type = proto.find("type").text
584 for param in command.findall("param"):
585 vk_param = VkParam.from_xml(param, types)
586 params.append(vk_param)
588 return VkFunction(_type=func_type, name=func_name, params=params)
590 def get_conversions(self):
591 """ Get a list of conversion functions required for this function if any.
592 Parameters which are structures may require conversion between win32
593 and the host platform. This function returns a list of conversions
598 for param in self.params:
599 convs = param.get_conversions()
600 if convs is not None:
601 conversions.extend(convs)
606 return bool(self.alias)
608 def is_core_func(self):
609 """ Returns whether the function is a Vulkan core function.
610 Core functions are APIs defined by the Vulkan spec to be part of the
611 Core API as well as several KHR WSI extensions.
614 if not self.extensions:
617 return any(ext in self.extensions for ext in CORE_EXTENSIONS)
619 def is_device_func(self):
620 # If none of the other, it must be a device function
621 return not self.is_global_func() and not self.is_instance_func() and not self.is_phys_dev_func()
623 def is_driver_func(self):
624 """ Returns if function is part of Wine driver interface. """
627 def is_global_func(self):
628 # Treat vkGetInstanceProcAddr as a global function as it
629 # can operate with NULL for vkInstance.
630 if self.name == "vkGetInstanceProcAddr":
632 # Global functions are not passed a dispatchable object.
633 elif self.params[0].is_dispatchable():
637 def is_instance_func(self):
638 # Instance functions are passed VkInstance.
639 if self.params[0].type == "VkInstance":
643 def is_phys_dev_func(self):
644 # Physical device functions are passed VkPhysicalDevice.
645 if self.params[0].type == "VkPhysicalDevice":
649 def is_required(self):
652 def returns_longlong(self):
653 return self.type in ["uint64_t", "VkDeviceAddress"]
655 def needs_conversion(self):
656 """ Check if the function needs any input/output type conversion.
657 Functions need input/output conversion if struct parameters have
658 alignment differences between Win32 and Linux 32-bit.
661 for p in self.params:
662 if p.needs_conversion():
663 LOGGER.debug("Parameter {0} to {1} requires conversion".format(p.name, self.name))
668 def needs_unwrapping(self):
669 """ Check if the function needs any input/output type unwrapping.
670 Functions need input/output unwrapping if struct parameters have
674 for p in self.params:
675 if p.needs_unwrapping():
680 def needs_dispatch(self):
683 def needs_thunk(self):
684 return self.thunk_type != ThunkType.NONE
686 def needs_private_thunk(self):
687 return self.thunk_type == ThunkType.PRIVATE
689 def needs_exposing(self):
690 # The function needs exposed if at-least one extension isn't both UNSUPPORTED and UNEXPOSED
691 return self.is_required() and (not self.extensions or not self.extensions.issubset(UNEXPOSED_EXTENSIONS))
693 def needs_direct_call(self):
694 # vkCmd* functions are frequently called, use direct calls for performance
695 if self.name.startswith("vkCmd"):
697 return self.is_driver_func() or self.name in DIRECT_CALL_FUNCTIONS
699 def pfn(self, prefix="p", call_conv=None, conv=False):
700 """ Create function pointer. """
703 pfn = "{0} ({1} *{2}_{3})(".format(self.type, call_conv, prefix, self.name)
705 pfn = "{0} (*{1}_{2})(".format(self.type, prefix, self.name)
707 for i, param in enumerate(self.params):
709 pfn += param.const + " "
712 if conv and param.needs_conversion():
715 if param.is_pointer():
716 pfn += " " + param.pointer
718 if param.array_len is not None:
719 pfn += "[{0}]".format(param.array_len)
721 if i < len(self.params) - 1:
726 def prototype(self, call_conv=None, prefix=None, postfix=None):
727 """ Generate prototype for given function.
730 call_conv (str, optional): calling convention e.g. WINAPI
731 prefix (str, optional): prefix to append prior to function name e.g. vkFoo -> wine_vkFoo
732 postfix (str, optional): text to append after function name but prior to semicolon e.g. DECLSPEC_HIDDEN
735 proto = "{0}".format(self.type)
737 if call_conv is not None:
738 proto += " {0}".format(call_conv)
740 if prefix is not None:
741 proto += " {0}{1}(".format(prefix, self.name)
743 proto += " {0}(".format(self.name)
745 # Add all the parameters.
746 proto += ", ".join([p.definition() for p in self.params])
748 if postfix is not None:
749 proto += ") {0}".format(postfix)
755 def body(self, params_prefix=""):
758 if not self.needs_private_thunk():
759 body += " {0}".format(self.trace(params_prefix=params_prefix))
761 params = ", ".join([p.variable(conv=False, params_prefix=params_prefix) for p in self.params])
763 # Call the native Vulkan function.
765 if self.returns_longlong():
766 body += "{0}result = ".format(params_prefix)
767 elif self.type != "void":
769 body += "{0}{1}.p_{2}({3});\n".format(params_prefix, self.params[0].dispatch_table(),
771 if self.type == "void" or self.returns_longlong():
772 body += " return STATUS_SUCCESS;\n"
776 def loader_body(self):
777 body = " struct {0}_params params;\n".format(self.name)
778 for p in self.params:
779 body += " params.{0} = {0};\n".format(p.name)
782 # Call the Unix function.
783 if self.type != "void" and not self.returns_longlong():
785 if self.needs_direct_call():
786 body += "unix_funcs->p_vk_call(unix_{0}, ¶ms);\n".format(self.name)
788 body += "vk_unix_call(unix_{0}, ¶ms);\n".format(self.name)
789 if self.returns_longlong():
790 body += " return params.result;\n"
793 def body_conversion(self, conv, params_prefix=""):
797 # Declare a variable to hold the result for non-void functions.
798 if self.returns_longlong():
799 result_prefix = "params->"
800 elif self.type != "void":
801 body += " {0} result;\n".format(self.type)
803 # Declare any tmp parameters for conversion.
804 for p in self.params:
805 if p.needs_conversion() and conv:
806 if p.is_dynamic_array():
807 body += " {0}_host *{1}_host;\n".format(p.type, p.name)
809 body += " {0}_host {1}_host;\n".format(p.type, p.name)
810 elif p.needs_unwrapping():
811 if p.is_dynamic_array():
812 body += " {0} *{1}_host;\n".format(p.type, p.name)
814 body += " {0} {1}_host;\n".format(p.type, p.name)
816 if not self.needs_private_thunk():
817 body += " {0}\n".format(self.trace(params_prefix=params_prefix))
819 # Call any win_to_host conversion calls.
820 for p in self.params:
821 if p.needs_input_conversion() and (p.needs_unwrapping() or conv):
822 body += p.copy(Direction.INPUT, prefix=params_prefix)
824 # Build list of parameters containing converted and non-converted parameters.
825 # The param itself knows if conversion is needed and applies it when we set conv=True.
826 params = ", ".join([p.variable(conv=conv, params_prefix=params_prefix) for p in self.params])
828 # Call the native Vulkan function.
829 if self.type == "void":
830 body += " {0}{1}.p_{2}({3});\n".format(params_prefix, self.params[0].dispatch_table(),
833 body += " {0}result = {1}{2}.p_{3}({4});\n".format(result_prefix, params_prefix,
834 self.params[0].dispatch_table(),
839 # Call any host_to_win conversion calls.
840 for p in self.params:
841 if not p.needs_output_conversion():
844 body += p.copy(Direction.OUTPUT, prefix=params_prefix)
846 # Perform any required cleanups. Most of these are for array functions.
847 for p in self.params:
848 if p.needs_free() and (p.needs_unwrapping() or conv):
849 body += p.free(prefix=params_prefix)
851 # Finally return the result.
852 if self.type != "void" and not self.returns_longlong():
853 body += " return result;\n"
855 body += " return STATUS_SUCCESS;\n"
859 def spec(self, prefix=None, symbol=None):
860 """ Generate spec file entry for this function.
863 prefix (str, optional): prefix to prepend to entry point name.
864 symbol (str, optional): allows overriding the name of the function implementing the entry point.
868 params = " ".join([p.spec() for p in self.params])
869 if prefix is not None:
870 spec += "@ stdcall -private {0}{1}({2})".format(prefix, self.name, params)
872 spec += "@ stdcall {0}({1})".format(self.name, params)
874 if symbol is not None:
880 def stub(self, call_conv=None, prefix=None):
881 stub = self.prototype(call_conv=call_conv, prefix=prefix)
883 stub += " {0}".format(self.trace(message="stub: ", trace_func="FIXME"))
885 if self.type == "VkResult":
886 stub += " return VK_ERROR_OUT_OF_HOST_MEMORY;\n"
887 elif self.type == "VkBool32":
888 stub += " return VK_FALSE;\n"
889 elif self.type == "PFN_vkVoidFunction":
890 stub += " return NULL;\n"
895 def thunk(self, prefix=None):
896 if prefix == "thunk_":
897 thunk = self.prototype(prefix=prefix)
901 thunk = "NTSTATUS {0}{1}(void *args)\n".format(prefix, self.name)
903 thunk += " struct {0}_params *params = args;\n".format(self.name)
904 params_prefix = "params->"
906 if self.needs_conversion():
907 thunk += "#if defined(USE_STRUCT_CONVERSION)\n"
908 thunk += self.body_conversion(conv=True, params_prefix=params_prefix)
910 if self.needs_unwrapping():
911 thunk += self.body_conversion(conv=False, params_prefix=params_prefix)
913 thunk += self.body(params_prefix=params_prefix)
915 elif self.needs_unwrapping():
916 thunk += self.body_conversion(conv=False, params_prefix=params_prefix)
918 thunk += self.body(params_prefix=params_prefix)
923 def loader_thunk(self, prefix=None):
924 thunk = self.prototype(call_conv="WINAPI", prefix=prefix)
926 thunk += self.loader_body()
930 def trace(self, message=None, trace_func=None, params_prefix=""):
931 """ Create a trace string including all parameters.
934 message (str, optional): text to print at start of trace message e.g. 'stub: '
935 trace_func (str, optional): used to override trace function e.g. FIXME, printf, etcetera.
937 if trace_func is not None:
938 trace = "{0}(\"".format(trace_func)
942 if message is not None:
945 # First loop is for all the format strings.
946 trace += ", ".join([p.format_string() for p in self.params])
949 # Second loop for parameter names and optional conversions.
950 for param in self.params:
951 if param.format_conv is not None:
952 trace += ", " + param.format_conv.format("{0}{1}".format(params_prefix, param.name))
954 trace += ", {0}{1}".format(params_prefix, param.name)
960 class VkFunctionPointer(object):
961 def __init__(self, _type, name, members, forward_decls):
963 self.members = members
965 self.required = False
966 self.forward_decls = forward_decls
969 def from_xml(funcpointer):
973 for t in funcpointer.findall("type"):
975 # <type>void</type>* pUserData,
976 # Parsing of the tail (anything past </type>) is tricky since there
977 # can be other data on the next line like: const <type>int</type>..
979 const = True if begin and "const" in begin else False
981 lines = t.tail.split(",\n")
982 if lines[0][0] == "*":
984 name = lines[0][1:].strip()
987 name = lines[0].strip()
989 # Filter out ); if it is contained.
990 name = name.partition(");")[0]
992 # If tail encompasses multiple lines, assign the second line to begin
995 begin = lines[1].strip()
999 members.append(VkMember(const=const, _type=_type, pointer=pointer, name=name))
1001 _type = funcpointer.text
1002 name = funcpointer.find("name").text
1003 if "requires" in funcpointer.attrib:
1004 forward_decls = funcpointer.attrib.get("requires").split(",")
1007 return VkFunctionPointer(_type, name, members, forward_decls)
1009 def definition(self):
1011 # forward declare required structs
1012 for decl in self.forward_decls:
1013 text += "typedef struct {0} {0};\n".format(decl)
1015 text += "{0} {1})(\n".format(self.type, self.name)
1018 if len(self.members) > 0:
1019 for m in self.members:
1021 text += " " + m.definition()
1024 text += ",\n " + m.definition()
1026 # Just make the compiler happy by adding a void parameter.
1034 class VkHandle(object):
1035 def __init__(self, name, _type, parent, alias=None):
1038 self.parent = parent
1040 self.required = False
1041 self.object_type = None
1044 def from_alias(handle, alias):
1045 name = handle.attrib.get("name")
1046 return VkHandle(name, alias.type, alias.parent, alias=alias)
1049 def from_xml(handle):
1050 name = handle.find("name").text
1051 _type = handle.find("type").text
1052 parent = handle.attrib.get("parent") # Most objects have a parent e.g. VkQueue has VkDevice.
1053 return VkHandle(name, _type, parent)
1055 def dispatch_table(self):
1056 if not self.is_dispatchable():
1059 if self.parent is None:
1060 # Should only happen for VkInstance
1062 elif self.name == "VkDevice":
1063 # VkDevice has VkInstance as a parent, but has its own dispatch table.
1065 elif self.parent in ["VkInstance", "VkPhysicalDevice"]:
1066 return "instance->funcs"
1067 elif self.parent in ["VkDevice", "VkCommandPool"]:
1068 return "device->funcs"
1070 LOGGER.error("Unhandled dispatchable parent: {0}".format(self.parent))
1072 def definition(self):
1073 """ Generates handle definition e.g. VK_DEFINE_HANDLE(vkInstance) """
1075 # Legacy types are typedef'ed to the new type if they are aliases.
1077 return "typedef {0} {1};\n".format(self.alias.name, self.name)
1079 return "{0}({1})\n".format(self.type, self.name)
1082 return self.alias is not None
1084 def is_dispatchable(self):
1085 """ Some handles like VkInstance, VkDevice are dispatchable objects,
1086 which means they contain a dispatch table of function pointers.
1088 return self.type == "VK_DEFINE_HANDLE"
1090 def is_required(self):
1091 return self.required
1093 def native_handle(self, name):
1094 """ Provide access to the native handle of a wrapped object. """
1096 if self.name == "VkCommandPool":
1097 return "wine_cmd_pool_from_handle({0})->command_pool".format(name)
1098 if self.name == "VkDebugUtilsMessengerEXT":
1099 return "wine_debug_utils_messenger_from_handle({0})->debug_messenger".format(name)
1100 if self.name == "VkDebugReportCallbackEXT":
1101 return "wine_debug_report_callback_from_handle({0})->debug_callback".format(name)
1102 if self.name == "VkSurfaceKHR":
1103 return "wine_surface_from_handle({0})->surface".format(name)
1105 native_handle_name = None
1107 if self.name == "VkCommandBuffer":
1108 native_handle_name = "command_buffer"
1109 if self.name == "VkDevice":
1110 native_handle_name = "device"
1111 if self.name == "VkInstance":
1112 native_handle_name = "instance"
1113 if self.name == "VkPhysicalDevice":
1114 native_handle_name = "phys_dev"
1115 if self.name == "VkQueue":
1116 native_handle_name = "queue"
1118 if native_handle_name:
1119 return "{0}->{1}".format(name, native_handle_name)
1121 if self.is_dispatchable():
1122 LOGGER.error("Unhandled native handle for: {0}".format(self.name))
1125 def driver_handle(self, name):
1126 """ Provide access to the handle that should be passed to the wine driver """
1128 if self.name == "VkSurfaceKHR":
1129 return "wine_surface_from_handle({0})->driver_surface".format(name)
1131 return self.native_handle(name)
1133 def is_wrapped(self):
1134 return self.native_handle("test") is not None
1136 def needs_conversion(self):
1139 def needs_unwrapping(self):
1140 return self.is_wrapped()
1142 class VkMember(object):
1143 def __init__(self, const=False, struct_fwd_decl=False,_type=None, pointer=None, name=None, array_len=None,
1144 dyn_array_len=None, optional=False, values=None, object_type=None, bit_width=None):
1146 self.struct_fwd_decl = struct_fwd_decl
1148 self.pointer = pointer
1150 self.type_info = None
1151 self.array_len = array_len
1152 self.dyn_array_len = dyn_array_len
1153 self.optional = optional
1154 self.values = values
1155 self.object_type = object_type
1156 self.bit_width = bit_width
1158 def __eq__(self, other):
1159 """ Compare member based on name against a string.
1161 This method is for convenience by VkStruct, which holds a number of members and needs quick checking
1162 if certain members exist.
1165 return self.name == other
1168 return "{0} {1} {2} {3} {4} {5} {6}".format(self.const, self.struct_fwd_decl, self.type, self.pointer,
1169 self.name, self.array_len, self.dyn_array_len)
1172 def from_xml(member):
1173 """ Helper function for parsing a member tag within a struct or union. """
1175 name_elem = member.find("name")
1176 type_elem = member.find("type")
1179 struct_fwd_decl = False
1185 values = member.get("values")
1188 if "const" in member.text:
1191 # Some members contain forward declarations:
1192 # - VkBaseInstructure has a member "const struct VkBaseInStructure *pNext"
1193 # - VkWaylandSurfaceCreateInfoKHR has a member "struct wl_display *display"
1194 if "struct" in member.text:
1195 struct_fwd_decl = True
1197 if type_elem is not None:
1198 member_type = type_elem.text
1199 if type_elem.tail is not None:
1200 pointer = type_elem.tail.strip() if type_elem.tail.strip() != "" else None
1202 # Name of other member within, which stores the number of
1203 # elements pointed to be by this member.
1204 dyn_array_len = member.get("len")
1206 # Some members are optional, which is important for conversion code e.g. not dereference NULL pointer.
1207 optional = True if member.get("optional") else False
1209 # Usually we need to allocate memory for dynamic arrays. We need to do the same in a few other cases
1210 # like for VkCommandBufferBeginInfo.pInheritanceInfo. Just threat such cases as dynamic arrays of
1211 # size 1 to simplify code generation.
1212 if dyn_array_len is None and pointer is not None:
1215 # Some members are arrays, attempt to parse these. Formats include:
1216 # <member><type>char</type><name>extensionName</name>[<enum>VK_MAX_EXTENSION_NAME_SIZE</enum>]</member>
1217 # <member><type>uint32_t</type><name>foo</name>[4]</member>
1218 if name_elem.tail and name_elem.tail[0] == '[':
1219 LOGGER.debug("Found array type")
1220 enum_elem = member.find("enum")
1221 if enum_elem is not None:
1222 array_len = enum_elem.text
1224 # Remove brackets around length
1225 array_len = name_elem.tail.strip("[]")
1227 object_type = member.get("objecttype", None)
1229 # Some members are bit field values:
1230 # <member><type>uint32_t</type> <name>mask</name>:8</member>
1231 if name_elem.tail and name_elem.tail[0] == ':':
1232 LOGGER.debug("Found bit field")
1233 bit_width = int(name_elem.tail[1:])
1235 return VkMember(const=const, struct_fwd_decl=struct_fwd_decl, _type=member_type, pointer=pointer, name=name_elem.text,
1236 array_len=array_len, dyn_array_len=dyn_array_len, optional=optional, values=values, object_type=object_type, bit_width=bit_width)
1238 def copy(self, input, output, direction, conv):
1239 """ Helper method for use by conversion logic to generate a C-code statement to copy this member.
1240 - `conv` indicates whether the statement is in a struct alignment conversion path. """
1242 if (conv and self.needs_conversion()) or self.needs_unwrapping():
1243 if self.is_dynamic_array():
1244 if direction == Direction.OUTPUT:
1245 LOGGER.warn("TODO: implement copying of returnedonly dynamic array for {0}.{1}".format(self.type, self.name))
1247 # Array length is either a variable name (string) or an int.
1248 count = self.dyn_array_len if isinstance(self.dyn_array_len, int) else "{0}{1}".format(input, self.dyn_array_len)
1249 return "{0}{1} = convert_{2}_array_win_to_host({3}{1}, {4});\n".format(output, self.name, self.type, input, count)
1250 elif self.is_static_array():
1251 count = self.array_len
1252 if direction == Direction.OUTPUT:
1253 # Needed by VkMemoryHeap.memoryHeaps
1254 return "convert_{0}_static_array_host_to_win({2}{1}, {3}{1}, {4});\n".format(self.type, self.name, input, output, count)
1256 # Nothing needed this yet.
1257 LOGGER.warn("TODO: implement copying of static array for {0}.{1}".format(self.type, self.name))
1258 elif self.is_handle() and self.needs_unwrapping():
1259 if direction == Direction.OUTPUT:
1260 LOGGER.err("OUTPUT parameter {0}.{1} cannot be unwrapped".format(self.type, self.name))
1262 handle = self.type_info["data"]
1263 return "{0}{1} = {2};\n".format(output, self.name, handle.driver_handle("{0}{1}".format(input, self.name)))
1264 elif self.is_generic_handle():
1265 if direction == Direction.OUTPUT:
1266 LOGGER.err("OUTPUT parameter {0}.{1} cannot be unwrapped".format(self.type, self.name))
1268 return "{0}{1} = wine_vk_unwrap_handle({2}{3}, {2}{1});\n".format(output, self.name, input, self.object_type)
1270 if direction == Direction.OUTPUT:
1271 return "convert_{0}_host_to_win(&{2}{1}, &{3}{1});\n".format(self.type, self.name, input, output)
1273 return "convert_{0}_win_to_host(&{2}{1}, &{3}{1});\n".format(self.type, self.name, input, output)
1274 elif self.is_static_array():
1275 bytes_count = "{0} * sizeof({1})".format(self.array_len, self.type)
1276 return "memcpy({0}{1}, {2}{1}, {3});\n".format(output, self.name, input, bytes_count)
1278 return "{0}{1} = {2}{1};\n".format(output, self.name, input)
1280 def free(self, location, conv):
1281 """ Helper method for use by conversion logic to generate a C-code statement to free this member. """
1283 if not self.needs_unwrapping() and not conv:
1286 # Add a cast to ignore const on conversion structs we allocated ourselves.
1287 # sample expected output: (VkSparseMemoryBind_host *)
1289 cast = "(" + self.type
1290 if self.needs_conversion() and conv:
1296 if self.is_dynamic_array():
1297 count = self.dyn_array_len if isinstance(self.dyn_array_len, int) else "{0}{1}".format(location, self.dyn_array_len)
1298 if self.is_struct() and self.type_info["data"].returnedonly:
1299 # For returnedonly, counts is stored in a pointer.
1300 return "free_{0}_array({1}{2}{3}, *{4});\n".format(self.type, cast, location, self.name, count)
1302 return "free_{0}_array({1}{2}{3}, {4});\n".format(self.type, cast, location, self.name, count)
1304 # We are operating on a single structure. Some structs (very rare) contain dynamic members,
1305 # which would need freeing.
1306 if self.needs_free():
1307 return "free_{0}({1}&{2}{3});\n".format(self.type, cast, location, self.name)
1310 def definition(self, align=False, conv=False):
1311 """ Generate prototype for given function.
1314 align (bool, optional): Enable alignment if a type needs it. This adds WINE_VK_ALIGN(8) to a member.
1315 conv (bool, optional): Enable conversion if a type needs it. This appends '_host' to the name.
1322 if self.is_struct_forward_declaration():
1325 if conv and self.is_struct():
1326 text += "{0}_host".format(self.type)
1330 if self.is_pointer():
1331 text += " {0}{1}".format(self.pointer, self.name)
1333 if align and self.needs_alignment():
1334 text += " WINE_VK_ALIGN(8) " + self.name
1336 text += " " + self.name
1338 if self.is_static_array():
1339 text += "[{0}]".format(self.array_len)
1341 if self.is_bit_field():
1342 text += ":{}".format(self.bit_width)
1346 def get_conversions(self):
1347 """ Return any conversion description for this member and its children when conversion is needed. """
1349 # Check if we need conversion either for this member itself or for any child members
1350 # in case member represents a struct.
1351 if not self.needs_conversion() and not self.needs_unwrapping():
1356 # Collect any conversion for any member structs.
1357 if self.is_struct():
1358 struct = self.type_info["data"]
1360 m.needs_struct_extensions_conversion()
1361 if m.needs_conversion() or m.needs_unwrapping():
1362 conversions.extend(m.get_conversions())
1364 struct.needs_struct_extensions_conversion()
1365 direction = Direction.OUTPUT if struct.returnedonly else Direction.INPUT
1366 elif self.is_handle() or self.is_generic_handle():
1367 direction = Direction.INPUT
1369 operand = self.type_info["data"]
1370 if self.is_dynamic_array():
1371 conversions.append(ConversionFunction(False, True, direction, operand))
1372 elif self.is_static_array():
1373 conversions.append(ConversionFunction(True, False, direction, operand))
1375 conversions.append(ConversionFunction(False, False, direction, operand))
1377 if self.needs_free():
1378 conversions.append(FreeFunction(self.is_dynamic_array(), operand))
1385 def is_dynamic_array(self):
1386 """ Returns if the member is an array element.
1387 Vulkan uses this for dynamically sized arrays for which
1388 there is a 'count' parameter.
1390 return self.dyn_array_len is not None
1392 def is_handle(self):
1393 return self.type_info["category"] == "handle"
1395 def is_pointer(self):
1396 return self.pointer is not None
1398 def is_static_array(self):
1399 """ Returns if the member is an array.
1400 Vulkan uses this often for fixed size arrays in which the
1401 length is part of the member.
1403 return self.array_len is not None
1405 def is_struct(self):
1406 return self.type_info["category"] == "struct"
1408 def is_struct_forward_declaration(self):
1409 return self.struct_fwd_decl
1412 return self.type_info["category"] == "union"
1414 def is_generic_handle(self):
1415 """ Returns True if the member is a unit64_t containing
1416 a handle with a separate object type
1419 return self.object_type != None and self.type == "uint64_t"
1421 def is_bit_field(self):
1422 return self.bit_width is not None
1424 def needs_alignment(self):
1425 """ Check if this member needs alignment for 64-bit data.
1426 Various structures need alignment on 64-bit variables due
1427 to compiler differences on 32-bit between Win32 and Linux.
1430 if self.is_pointer():
1432 elif self.type == "size_t":
1434 elif self.type in ["uint64_t", "VkDeviceSize"]:
1436 elif self.is_struct():
1437 struct = self.type_info["data"]
1438 return struct.needs_alignment()
1439 elif self.is_handle():
1440 # Dispatchable handles are pointers to objects, while
1441 # non-dispatchable are uint64_t and hence need alignment.
1442 handle = self.type_info["data"]
1443 return False if handle.is_dispatchable() else True
1446 def needs_conversion(self):
1447 """ Structures requiring alignment, need conversion between win32 and host. """
1449 if not self.is_struct():
1452 struct = self.type_info["data"]
1453 return struct.needs_conversion()
1455 def needs_unwrapping(self):
1456 """ Structures with wrapped handles need unwrapping. """
1458 if self.is_struct():
1459 struct = self.type_info["data"]
1460 return struct.needs_unwrapping()
1462 if self.is_handle():
1463 handle = self.type_info["data"]
1464 return handle.is_wrapped()
1466 if self.is_generic_handle():
1471 def needs_free(self):
1472 if not self.needs_conversion() and not self.needs_unwrapping():
1475 if self.is_dynamic_array():
1478 # TODO: some non-pointer structs and optional pointer structs may need freeing,
1479 # though none of this type have been encountered yet.
1482 def needs_struct_extensions_conversion(self):
1483 if not self.is_struct():
1486 struct = self.type_info["data"]
1487 return struct.needs_struct_extensions_conversion()
1489 def set_type_info(self, type_info):
1490 """ Helper function to set type information from the type registry.
1491 This is needed, because not all type data is available at time of
1494 self.type_info = type_info
1497 class VkParam(object):
1498 """ Helper class which describes a parameter to a function call. """
1500 def __init__(self, type_info, const=None, pointer=None, name=None, array_len=None, dyn_array_len=None, object_type=None):
1503 self.array_len = array_len
1504 self.dyn_array_len = dyn_array_len
1505 self.pointer = pointer
1506 self.object_type = object_type
1507 self.type_info = type_info
1508 self.type = type_info["name"] # For convenience
1509 self.handle = type_info["data"] if type_info["category"] == "handle" else None
1510 self.struct = type_info["data"] if type_info["category"] == "struct" else None
1512 self._set_direction()
1513 self._set_format_string()
1514 self._set_conversions()
1517 return "{0} {1} {2} {3} {4} {5}".format(self.const, self.type, self.pointer, self.name, self.array_len, self.dyn_array_len)
1520 def from_xml(param, types):
1521 """ Helper function to create VkParam from xml. """
1523 # Parameter parsing is slightly tricky. All the data is contained within
1524 # a param tag, but some data is within subtags while others are text
1525 # before or after the type tag.
1527 # <param>const <type>char</type>* <name>pLayerName</name></param>
1529 name_elem = param.find("name")
1531 name = name_elem.text
1532 # Tail contains array length e.g. for blendConstants param of vkSetBlendConstants
1533 if name_elem.tail is not None:
1534 array_len = name_elem.tail.strip("[]")
1536 # Name of other parameter in function prototype, which stores the number of
1537 # elements pointed to be by this parameter.
1538 dyn_array_len = param.get("len", None)
1540 const = param.text.strip() if param.text else None
1541 type_elem = param.find("type")
1542 pointer = type_elem.tail.strip() if type_elem.tail.strip() != "" else None
1544 # Some uint64_t are actually handles with a separate type param
1545 object_type = param.get("objecttype", None)
1547 # Since we have parsed all types before hand, this should not happen.
1548 type_info = types.get(type_elem.text, None)
1549 if type_info is None:
1550 LOGGER.err("type info not found for: {0}".format(type_elem.text))
1552 return VkParam(type_info, const=const, pointer=pointer, name=name, array_len=array_len, dyn_array_len=dyn_array_len, object_type=object_type)
1554 def _set_conversions(self):
1555 """ Internal helper function to configure any needed conversion functions. """
1557 self.free_func = None
1558 self.input_conv = None
1559 self.output_conv = None
1560 if not self.needs_conversion() and not self.needs_unwrapping():
1563 operand = self.struct if self.is_struct() else self.handle
1565 # Input functions require win to host conversion.
1566 if self._direction in [Direction.INPUT, Direction.INPUT_OUTPUT]:
1567 self.input_conv = ConversionFunction(False, self.is_dynamic_array(), Direction.INPUT, operand)
1569 # Output functions require host to win conversion.
1570 if self._direction in [Direction.INPUT_OUTPUT, Direction.OUTPUT]:
1571 self.output_conv = ConversionFunction(False, self.is_dynamic_array(), Direction.OUTPUT, operand)
1573 # Dynamic arrays, but also some normal structs (e.g. VkCommandBufferBeginInfo) need memory
1574 # allocation and thus some cleanup.
1575 if self.is_dynamic_array() or self.struct.needs_free():
1576 self.free_func = FreeFunction(self.is_dynamic_array(), operand)
1578 def _set_direction(self):
1579 """ Internal helper function to set parameter direction (input/output/input_output). """
1581 # The parameter direction needs to be determined from hints in vk.xml like returnedonly,
1582 # parameter constness and other heuristics.
1583 # For now we need to get this right for structures as we need to convert these, we may have
1584 # missed a few other edge cases (e.g. count variables).
1585 # See also https://github.com/KhronosGroup/Vulkan-Docs/issues/610
1587 if not self.is_pointer():
1588 self._direction = Direction.INPUT
1589 elif self.is_const() and self.is_pointer():
1590 self._direction = Direction.INPUT
1591 elif self.is_struct():
1592 if not self.struct.returnedonly:
1593 self._direction = Direction.INPUT
1596 # Returnedonly hints towards output, however in some cases
1597 # it is inputoutput. In particular if pNext / sType exist,
1598 # which are used to link in other structures without having
1599 # to introduce new APIs. E.g. vkGetPhysicalDeviceProperties2KHR.
1600 if "pNext" in self.struct:
1601 self._direction = Direction.INPUT_OUTPUT
1604 self._direction = Direction.OUTPUT
1606 # This should mostly be right. Count variables can be inout, but we don't care about these yet.
1607 self._direction = Direction.OUTPUT
1609 def _set_format_string(self):
1610 """ Internal helper function to be used by constructor to set format string. """
1612 # Determine a format string used by code generation for traces.
1613 # 64-bit types need a conversion function.
1614 self.format_conv = None
1615 if self.is_static_array() or self.is_pointer():
1616 self.format_str = "%p"
1618 if self.type_info["category"] in ["bitmask"]:
1619 # Since 1.2.170 bitmasks can be 32 or 64-bit, check the basetype.
1620 if self.type_info["data"].type == "VkFlags64":
1621 self.format_str = "0x%s"
1622 self.format_conv = "wine_dbgstr_longlong({0})"
1624 self.format_str = "%#x"
1625 elif self.type_info["category"] in ["enum"]:
1626 self.format_str = "%#x"
1627 elif self.is_handle():
1628 # We use uint64_t for non-dispatchable handles as opposed to pointers
1629 # for dispatchable handles.
1630 if self.handle.is_dispatchable():
1631 self.format_str = "%p"
1633 self.format_str = "0x%s"
1634 self.format_conv = "wine_dbgstr_longlong({0})"
1635 elif self.type == "float":
1636 self.format_str = "%f"
1637 elif self.type == "int":
1638 self.format_str = "%d"
1639 elif self.type == "int32_t":
1640 self.format_str = "%d"
1641 elif self.type == "size_t":
1642 self.format_str = "0x%s"
1643 self.format_conv = "wine_dbgstr_longlong({0})"
1644 elif self.type in ["uint16_t", "uint32_t", "VkBool32"]:
1645 self.format_str = "%u"
1646 elif self.type in ["uint64_t", "VkDeviceAddress", "VkDeviceSize"]:
1647 self.format_str = "0x%s"
1648 self.format_conv = "wine_dbgstr_longlong({0})"
1649 elif self.type == "HANDLE":
1650 self.format_str = "%p"
1651 elif self.type in ["VisualID", "xcb_visualid_t", "RROutput", "zx_handle_t"]:
1652 # Don't care about specific types for non-Windows platforms.
1653 self.format_str = ""
1655 LOGGER.warn("Unhandled type: {0}".format(self.type_info))
1657 def copy(self, direction, prefix=""):
1658 if direction == Direction.INPUT:
1659 if self.is_dynamic_array():
1660 return " {1}_host = convert_{2}_array_win_to_host({0}{1}, {0}{3});\n".format(prefix, self.name, self.type, self.dyn_array_len)
1662 return " convert_{0}_win_to_host({1}{2}, &{2}_host);\n".format(self.type, prefix, self.name)
1664 if self.is_dynamic_array():
1665 LOGGER.error("Unimplemented output conversion for: {0}".format(self.name))
1667 return " convert_{0}_host_to_win(&{2}_host, {1}{2});\n".format(self.type, prefix, self.name)
1669 def definition(self, postfix=None, is_member=False):
1670 """ Return prototype for the parameter. E.g. 'const char *foo' """
1674 proto += self.const + " "
1678 if self.is_pointer():
1679 proto += " {0}{1}".format(self.pointer, self.name)
1680 elif is_member and self.is_static_array():
1681 proto += " *" + self.name
1683 proto += " " + self.name
1685 # Allows appending something to the variable name useful for
1686 # win32 to host conversion.
1687 if postfix is not None:
1690 if not is_member and self.is_static_array():
1691 proto += "[{0}]".format(self.array_len)
1695 def direction(self):
1696 """ Returns parameter direction: input, output, input_output.
1698 Parameter direction in Vulkan is not straight-forward, which this function determines.
1701 return self._direction
1703 def dispatch_table(self):
1704 """ Return functions dispatch table pointer for dispatchable objects. """
1706 if not self.is_dispatchable():
1709 return "{0}->{1}".format(self.name, self.handle.dispatch_table())
1711 def format_string(self):
1712 return self.format_str
1714 def free(self, prefix=""):
1715 if self.is_dynamic_array():
1716 if self.is_struct() and self.struct.returnedonly:
1717 # For returnedonly, counts is stored in a pointer.
1718 return " free_{0}_array({1}_host, *{2}{3});\n".format(self.type, self.name, prefix, self.dyn_array_len)
1720 return " free_{0}_array({1}_host, {2}{3});\n".format(self.type, self.name, prefix, self.dyn_array_len)
1722 # We are operating on a single structure. Some structs (very rare) contain dynamic members,
1723 # which would need freeing.
1724 if self.is_struct() and self.struct.needs_free():
1725 return " free_{0}(&{1}_host);\n".format(self.type, self.name)
1728 def get_conversions(self):
1729 """ Get a list of conversions required for this parameter if any.
1730 Parameters which are structures may require conversion between win32
1731 and the host platform. This function returns a list of conversions
1735 if self.is_struct():
1736 self.struct.needs_struct_extensions_conversion()
1737 for m in self.struct:
1738 m.needs_struct_extensions_conversion()
1739 elif not self.is_handle():
1742 if not self.needs_conversion() and not self.needs_unwrapping():
1747 # Collect any member conversions first, so we can guarantee
1748 # those functions will be defined prior to usage by the
1749 # 'parent' param requiring conversion.
1750 if self.is_struct():
1751 for m in self.struct:
1752 if not m.is_struct():
1755 if not m.needs_conversion() and not m.needs_unwrapping():
1758 conversions.extend(m.get_conversions())
1760 # Conversion requirements for the 'parent' parameter.
1761 if self.input_conv is not None:
1762 conversions.append(self.input_conv)
1763 if self.output_conv is not None:
1764 conversions.append(self.output_conv)
1765 if self.free_func is not None:
1766 conversions.append(self.free_func)
1771 return self.const is not None
1773 def is_dynamic_array(self):
1774 return self.dyn_array_len is not None
1776 def is_dispatchable(self):
1777 if not self.is_handle():
1780 return self.handle.is_dispatchable()
1782 def is_handle(self):
1783 return self.handle is not None
1785 def is_pointer(self):
1786 return self.pointer is not None
1788 def is_static_array(self):
1789 return self.array_len is not None
1791 def is_struct(self):
1792 return self.struct is not None
1794 def needs_conversion(self):
1795 """ Returns if parameter needs conversion between win32 and host. """
1797 if not self.is_struct():
1800 # VkSparseImageMemoryRequirements(2) is used by vkGetImageSparseMemoryRequirements(2).
1801 # This function is tricky to wrap, because how to wrap depends on whether
1802 # pSparseMemoryRequirements is NULL or not. Luckily for VkSparseImageMemoryRequirements(2)
1803 # the alignment works out in such a way that no conversion is needed between win32 and Linux.
1804 if self.type in ["VkSparseImageMemoryRequirements", "VkSparseImageMemoryRequirements2"]:
1807 # If a structure needs alignment changes, it means we need to
1808 # perform parameter conversion between win32 and host.
1809 if self.struct.needs_conversion():
1814 def needs_unwrapping(self):
1815 """ Returns if parameter needs unwrapping of handle. """
1817 # Wrapped handle parameters are handled separately, only look for wrapped handles in structs
1818 if self.is_struct():
1819 return self.struct.needs_unwrapping()
1821 if self.is_handle() and self.is_dynamic_array():
1822 return self.handle.needs_unwrapping()
1826 def needs_free(self):
1827 return self.free_func is not None
1829 def needs_input_conversion(self):
1830 return self.input_conv is not None
1832 def needs_output_conversion(self):
1833 return self.output_conv is not None
1836 """ Generate spec file entry for this parameter. """
1838 if self.is_pointer() and self.type == "char":
1840 if self.is_dispatchable() or self.is_pointer() or self.is_static_array():
1842 if self.type_info["category"] in ["bitmask"]:
1843 # Since 1.2.170 bitmasks can be 32 or 64-bit, check the basetype.
1844 if self.type_info["data"].type == "VkFlags64":
1848 if self.type_info["category"] in ["enum"]:
1850 if self.is_handle() and not self.is_dispatchable():
1852 if self.type == "float":
1854 if self.type in ["int", "int32_t", "size_t", "uint16_t", "uint32_t", "VkBool32"]:
1856 if self.type in ["uint64_t", "VkDeviceSize"]:
1859 LOGGER.error("Unhandled spec conversion for type: {0}".format(self.type))
1861 def variable(self, conv=False, params_prefix=""):
1862 """ Returns 'glue' code during generation of a function call on how to access the variable.
1863 This function handles various scenarios such as 'unwrapping' if dispatchable objects and
1864 renaming of parameters in case of win32 -> host conversion.
1867 conv (bool, optional): Enable conversion if the param needs it. This appends '_host' to the name.
1870 # Hack until we enable allocation callbacks from ICD to application. These are a joy
1871 # to enable one day, because of calling convention conversion.
1872 if "VkAllocationCallbacks" in self.type:
1873 LOGGER.debug("TODO: setting NULL VkAllocationCallbacks for {0}".format(self.name))
1876 if self.needs_unwrapping() or (conv and self.needs_conversion()):
1877 if self.is_dynamic_array():
1878 return "{0}_host".format(self.name)
1880 return "&{0}_host".format(self.name)
1882 if self.object_type != None and self.type == "uint64_t":
1883 return "wine_vk_unwrap_handle({0}{1}, {0}{2})".format(params_prefix, self.object_type, self.name)
1885 # We need to pass the native handle to the native Vulkan calls and
1886 # the wine driver's handle to calls which are wrapped by the driver.
1887 p = "{0}{1}".format(params_prefix, self.name)
1888 driver_handle = self.handle.driver_handle(p) if self.is_handle() else None
1889 return driver_handle if driver_handle else p
1892 class VkStruct(Sequence):
1893 """ Class which represents the type union and struct. """
1895 def __init__(self, name, members, returnedonly, structextends, alias=None, union=False):
1897 self.members = members
1898 self.returnedonly = returnedonly
1899 self.structextends = structextends
1900 self.required = False
1903 self.type_info = None # To be set later.
1904 self.struct_extensions = []
1905 self.aliased_by = []
1907 def __getitem__(self, i):
1908 return self.members[i]
1911 return len(self.members)
1914 def from_alias(struct, alias):
1915 name = struct.attrib.get("name")
1916 aliasee = VkStruct(name, alias.members, alias.returnedonly, alias.structextends, alias=alias)
1918 alias.add_aliased_by(aliasee)
1922 def from_xml(struct):
1923 # Unions and structs are the same parsing wise, but we need to
1924 # know which one we are dealing with later on for code generation.
1925 union = True if struct.attrib["category"] == "union" else False
1927 name = struct.attrib.get("name")
1929 # 'Output' structures for which data is filled in by the API are
1930 # marked as 'returnedonly'.
1931 returnedonly = True if struct.attrib.get("returnedonly") else False
1933 structextends = struct.attrib.get("structextends")
1934 structextends = structextends.split(",") if structextends else []
1937 for member in struct.findall("member"):
1938 vk_member = VkMember.from_xml(member)
1939 members.append(vk_member)
1941 return VkStruct(name, members, returnedonly, structextends, union=union)
1944 def decouple_structs(structs):
1945 """ Helper function which decouples a list of structs.
1946 Structures often depend on other structures. To make the C compiler
1947 happy we need to define 'substructures' first. This function analyzes
1948 the list of structures and reorders them in such a way that they are
1952 tmp_structs = list(structs) # Don't modify the original structures.
1953 decoupled_structs = []
1955 while (len(tmp_structs) > 0):
1956 # Iterate over a copy because we want to modify the list inside the loop.
1957 for struct in list(tmp_structs):
1960 if not struct.required:
1961 tmp_structs.remove(struct)
1965 if not (m.is_struct() or m.is_union()):
1968 # VkBaseInstructure and VkBaseOutStructure reference themselves.
1969 if m.type == struct.name:
1973 # Check if a struct we depend on has already been defined.
1974 for s in decoupled_structs:
1975 if s.name == m.type:
1980 # Check if the struct we depend on is even in the list of structs.
1981 # If found now, it means we haven't met all dependencies before we
1982 # can operate on the current struct.
1983 # When generating 'host' structs we may not be able to find a struct
1984 # as the list would only contain the structs requiring conversion.
1985 for s in tmp_structs:
1986 if s.name == m.type:
1990 if dependends == False:
1991 decoupled_structs.append(struct)
1992 tmp_structs.remove(struct)
1994 return decoupled_structs
1996 def definition(self, align=False, conv=False, postfix=None):
1997 """ Convert structure to textual definition.
2000 align (bool, optional): enable alignment to 64-bit for win32 struct compatibility.
2001 conv (bool, optional): enable struct conversion if the struct needs it.
2002 postfix (str, optional): text to append to end of struct name, useful for struct renaming.
2005 # Only define alias structs when doing conversions
2006 if self.is_alias() and not conv:
2010 text = "typedef union {0}".format(self.name)
2012 text = "typedef struct {0}".format(self.name)
2014 if postfix is not None:
2020 if align and m.needs_alignment():
2021 text += " {0};\n".format(m.definition(align=align))
2022 elif conv and m.needs_conversion():
2023 text += " {0};\n".format(m.definition(conv=conv))
2025 text += " {0};\n".format(m.definition())
2027 if postfix is not None:
2028 text += "}} {0}{1};\n".format(self.name, postfix)
2030 text += "}} {0};\n".format(self.name)
2032 for aliasee in self.aliased_by:
2033 text += "typedef {0} {1};\n".format(self.name, aliasee.name)
2038 return bool(self.alias)
2040 def add_aliased_by(self, aliasee):
2041 self.aliased_by.append(aliasee)
2043 def needs_alignment(self):
2044 """ Check if structure needs alignment for 64-bit data.
2045 Various structures need alignment on 64-bit variables due
2046 to compiler differences on 32-bit between Win32 and Linux.
2049 for m in self.members:
2050 if self.name == m.type:
2052 if m.needs_alignment():
2056 def needs_conversion(self):
2057 """ Returns if struct members needs conversion between win32 and host.
2058 Structures need conversion if they contain members requiring alignment
2059 or if they include other structures which need alignment.
2062 if self.needs_alignment():
2065 for m in self.members:
2066 if self.name == m.type:
2068 if m.needs_conversion():
2072 def needs_unwrapping(self):
2073 """ Returns if struct members need unwrapping of handle. """
2075 for m in self.members:
2076 if self.name == m.type:
2078 if m.needs_unwrapping():
2082 def needs_free(self):
2083 """ Check if any struct member needs some memory freeing."""
2085 for m in self.members:
2086 if self.name == m.type:
2093 def needs_struct_extensions_conversion(self):
2094 """ Checks if structure extensions in pNext chain need conversion. """
2097 for e in self.struct_extensions:
2098 if e.required and e.needs_conversion():
2099 LOGGER.error("Unhandled pNext chain alignment conversion for {0}".format(e.name))
2101 if e.required and e.needs_unwrapping():
2102 LOGGER.error("Unhandled pNext chain unwrapping conversion for {0}".format(e.name))
2107 def set_type_info(self, types):
2108 """ Helper function to set type information from the type registry.
2109 This is needed, because not all type data is available at time of
2112 for m in self.members:
2113 type_info = types[m.type]
2114 m.set_type_info(type_info)
2117 class ConversionFunction(object):
2118 def __init__(self, array, dyn_array, direction, operand):
2120 self.direction = direction
2121 self.dyn_array = dyn_array
2122 self.operand = operand
2123 self.type = operand.name
2127 def __eq__(self, other):
2128 return self.name == other.name
2130 def _generate_array_conversion_func(self):
2131 """ Helper function for generating a conversion function for array operands. """
2135 if self.operand.needs_conversion():
2136 body += "#if defined(USE_STRUCT_CONVERSION)\n"
2138 if self.direction == Direction.OUTPUT:
2139 params = ["const {0}_host *in".format(self.type), "uint32_t count"]
2140 return_type = self.type
2142 params = ["const {0} *in".format(self.type), "uint32_t count"]
2143 return_type = "{0}_host".format(self.type)
2145 # Generate function prototype.
2146 body += "static inline {0} *{1}(".format(return_type, self.name)
2147 body += ", ".join(p for p in params)
2150 body += " {0} *out;\n".format(return_type)
2152 if self.operand.needs_unwrapping():
2153 if self.operand.needs_conversion():
2156 params = ["const {0} *in".format(self.type), "uint32_t count"]
2157 return_type = "{0}".format(self.type)
2159 # Generate function prototype.
2160 body += "static inline {0} *{1}(".format(return_type, self.name)
2161 body += ", ".join(p for p in params)
2164 body += " {0} *out;\n".format(return_type)
2166 if self.operand.needs_conversion():
2167 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2169 body += " unsigned int i;\n\n"
2170 body += " if (!in || !count) return NULL;\n\n"
2172 body += " out = malloc(count * sizeof(*out));\n"
2174 body += " for (i = 0; i < count; i++)\n"
2177 if isinstance(self.operand, VkStruct):
2178 for m in self.operand:
2179 # TODO: support copying of pNext extension structures!
2180 # Luckily though no extension struct at this point needs conversion.
2181 convert = m.copy("in[i].", "out[i].", self.direction, conv=True)
2182 if self.operand.needs_conversion() and not self.operand.needs_unwrapping():
2183 body += " " + convert
2185 unwrap = m.copy("in[i].", "out[i].", self.direction, conv=False)
2186 if unwrap == convert:
2187 body += " " + unwrap
2189 body += "#if defined(USE_STRUCT_CONVERSION)\n"
2190 body += " " + convert
2192 body += " " + unwrap
2193 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2195 elif isinstance(self.operand, VkHandle) and self.direction == Direction.INPUT:
2196 body += " out[i] = " + self.operand.driver_handle("in[i]") + ";\n"
2198 LOGGER.warn("Unhandled conversion operand type")
2199 body += " out[i] = in[i];\n"
2202 body += " return out;\n"
2205 if not self.operand.needs_unwrapping():
2206 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2212 def _generate_conversion_func(self):
2213 """ Helper function for generating a conversion function for non-array operands. """
2215 # It doesn't make sense to generate conversion functions for non-struct variables
2216 # which aren't in arrays, as this should be handled by the copy() function
2217 if not isinstance(self.operand, VkStruct):
2222 if self.operand.needs_conversion():
2223 body += "#if defined(USE_STRUCT_CONVERSION)\n"
2224 body += "static inline void {0}(".format(self.name)
2226 if self.direction == Direction.OUTPUT:
2227 params = ["const {0}_host *in".format(self.type), "{0} *out".format(self.type)]
2229 params = ["const {0} *in".format(self.type), "{0}_host *out".format(self.type)]
2231 # Generate parameter list
2232 body += ", ".join(p for p in params)
2235 if self.operand.needs_unwrapping():
2236 if self.operand.needs_conversion():
2239 body += "static inline void {0}(".format(self.name)
2241 params = ["const {0} *in".format(self.type), "{0} *out".format(self.type)]
2243 # Generate parameter list
2244 body += ", ".join(p for p in params)
2247 if self.operand.needs_conversion():
2248 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2250 body += "{\n if (!in) return;\n\n"
2252 if self.direction == Direction.INPUT and "pNext" in self.operand and self.operand.returnedonly:
2253 # We are dealing with an input_output parameter. For these we only need to copy
2254 # pNext and sType as the other fields are filled in by the host. We do potentially
2255 # have to iterate over pNext and perform conversions based on switch(sType)!
2256 # Luckily though no extension structs at this point need conversion.
2257 # TODO: support copying of pNext extension structures!
2258 body += " out->pNext = in->pNext;\n"
2259 body += " out->sType = in->sType;\n"
2261 for m in self.operand:
2262 # TODO: support copying of pNext extension structures!
2263 convert = m.copy("in->", "out->", self.direction, conv=True)
2264 if self.operand.needs_conversion() and not self.operand.needs_unwrapping():
2265 body += " " + convert
2267 unwrap = m.copy("in->", "out->", self.direction, conv=False)
2268 if unwrap == convert:
2269 body += " " + unwrap
2271 body += "#if defined(USE_STRUCT_CONVERSION)\n"
2272 body += " " + convert
2274 body += " " + unwrap
2275 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2279 if not self.operand.needs_unwrapping():
2280 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2286 def _generate_static_array_conversion_func(self):
2287 """ Helper function for generating a conversion function for array operands. """
2291 if self.operand.needs_conversion():
2292 body += "#if defined(USE_STRUCT_CONVERSION)\n"
2294 if self.direction == Direction.OUTPUT:
2295 params = ["const {0}_host *in".format(self.type), "{0} *out".format(self.type), "uint32_t count"]
2297 params = ["const {0} *in".format(self.type), "{0} *out_host".format(self.type), "uint32_t count"]
2299 # Generate function prototype.
2300 body += "static inline void {0}(".format(self.name)
2301 body += ", ".join(p for p in params)
2304 if self.operand.needs_unwrapping():
2305 if self.operand.needs_conversion():
2308 params = ["const {0} *in".format(self.type), "{0} *out".format(self.type), "uint32_t count"]
2310 # Generate function prototype.
2311 body += "static inline void {0}(".format(self.name)
2312 body += ", ".join(p for p in params)
2316 body += " unsigned int i;\n\n"
2317 body += " if (!in) return;\n\n"
2318 body += " for (i = 0; i < count; i++)\n"
2321 if isinstance(self.operand, VkStruct):
2322 for m in self.operand:
2323 # TODO: support copying of pNext extension structures!
2324 convert = m.copy("in[i].", "out[i].", self.direction, conv=True)
2325 if self.operand.needs_conversion() and not self.operand.needs_unwrapping():
2326 body += " " + convert
2328 unwrap = m.copy("in[i].", "out[i].", self.direction, conv=False)
2329 if unwrap == convert:
2330 body += " " + unwrap
2332 body += "#if defined(USE_STRUCT_CONVERSION)\n"
2333 body += " " + convert
2335 body += " " + unwrap
2336 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2337 elif isinstance(self.operand, VkHandle) and self.direction == Direction.INPUT:
2338 body += " out[i] = " + self.operand.driver_handle("in[i]") + ";\n"
2340 LOGGER.warn("Unhandled conversion operand type")
2341 body += " out[i] = in[i];\n"
2346 if not self.operand.needs_unwrapping():
2347 body += "#endif /* USE_STRUCT_CONVERSION) */\n"
2353 def _set_name(self):
2354 if self.direction == Direction.INPUT:
2356 name = "convert_{0}_static_array_win_to_host".format(self.type)
2357 elif self.dyn_array:
2358 name = "convert_{0}_array_win_to_host".format(self.type)
2360 name = "convert_{0}_win_to_host".format(self.type)
2361 else: # Direction.OUTPUT
2363 name = "convert_{0}_static_array_host_to_win".format(self.type)
2364 elif self.dyn_array:
2365 name = "convert_{0}_array_host_to_win".format(self.type)
2367 name = "convert_{0}_host_to_win".format(self.type)
2371 def definition(self):
2373 return self._generate_static_array_conversion_func()
2374 elif self.dyn_array:
2375 return self._generate_array_conversion_func()
2377 return self._generate_conversion_func()
2380 class FreeFunction(object):
2381 def __init__(self, dyn_array, operand):
2382 self.dyn_array = dyn_array
2383 self.operand = operand
2384 self.type = operand.name
2387 self.name = "free_{0}_array".format(self.type)
2389 self.name = "free_{0}".format(self.type)
2391 def __eq__(self, other):
2392 return self.name == other.name
2394 def _generate_array_free_func(self):
2395 """ Helper function for cleaning up temporary buffers required for array conversions. """
2399 if self.operand.needs_conversion():
2400 body += "#if defined(USE_STRUCT_CONVERSION)\n"
2401 # Generate function prototype.
2402 body += "static inline void {0}({1}_host *in, uint32_t count)\n".format(self.name, self.type)
2404 if self.operand.needs_unwrapping():
2405 if self.operand.needs_conversion():
2408 # Generate function prototype.
2409 body += "static inline void {0}({1} *in, uint32_t count)\n".format(self.name, self.type)
2411 if self.operand.needs_conversion():
2412 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2416 # E.g. VkGraphicsPipelineCreateInfo_host needs freeing for pStages.
2417 if isinstance(self.operand, VkStruct) and self.operand.needs_free():
2418 body += " unsigned int i;\n\n"
2419 body += " if (!in) return;\n\n"
2420 body += " for (i = 0; i < count; i++)\n"
2423 for m in self.operand:
2425 convert = m.free("in[i].", conv=True)
2426 if self.operand.needs_conversion() and not self.operand.needs_unwrapping():
2427 body += " " + convert
2429 unwrap = m.free("in[i].", conv=False)
2430 if convert == unwrap:
2431 body += " " + unwrap
2433 body += "#if defined(USE_STRUCT_CONVERSION)\n"
2434 body += " " + convert
2435 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2437 body += "#if defined(USE_STRUCT_CONVERSION)\n"
2438 body += " " + convert
2440 body += " " + unwrap
2441 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2444 body += " if (!in) return;\n\n"
2446 body += " free(in);\n"
2450 if not self.operand.needs_unwrapping():
2451 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2457 def _generate_free_func(self):
2458 # E.g. VkCommandBufferBeginInfo.pInheritanceInfo needs freeing.
2459 if not self.operand.needs_free():
2462 if not isinstance(self.operand, VkStruct):
2467 if self.operand.needs_conversion():
2468 body += "#if defined(USE_STRUCT_CONVERSION)\n"
2469 # Generate function prototype.
2470 body += "static inline void {0}({1}_host *in)\n".format(self.name, self.type)
2472 if self.operand.needs_unwrapping():
2473 if self.operand.needs_conversion():
2476 # Generate function prototype.
2477 body += "static inline void {0}({1} *in)\n".format(self.name, self.type)
2479 if self.operand.needs_conversion():
2480 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2484 for m in self.operand:
2486 convert = m.free("in->", conv=True)
2487 if self.operand.needs_conversion() and not self.operand.needs_unwrapping():
2488 body += " " + convert
2490 unwrap = m.free("in->", conv=False)
2491 if convert == unwrap:
2492 body += " " + unwrap
2494 body += "#if defined(USE_STRUCT_CONVERSION)\n"
2495 body += " " + convert
2496 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2498 body += "#if defined(USE_STRUCT_CONVERSION)\n"
2499 body += " " + convert
2501 body += " " + unwrap
2502 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2506 if not self.operand.needs_unwrapping():
2507 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2513 def definition(self):
2515 return self._generate_array_free_func()
2517 # Some structures need freeing too if they contain dynamic arrays.
2518 # E.g. VkCommandBufferBeginInfo
2519 return self._generate_free_func()
2522 class StructChainConversionFunction(object):
2523 def __init__(self, direction, struct, ignores):
2524 self.direction = direction
2525 self.struct = struct
2526 self.ignores = ignores
2527 self.type = struct.name
2529 self.name = "convert_{0}_struct_chain".format(self.type)
2531 def __eq__(self, other):
2532 return self.name == other.name
2534 def prototype(self, postfix=""):
2535 return "VkResult {0}(const void *pNext, {1} *out_struct) {2}".format(self.name, self.type, postfix).strip()
2537 def definition(self):
2538 body = self.prototype()
2541 body += " VkBaseOutStructure *out_header = (VkBaseOutStructure *)out_struct;\n";
2542 body += " const VkBaseInStructure *in_header;\n\n";
2544 body += " out_header->pNext = NULL;\n\n"
2546 body += " for (in_header = pNext; in_header; in_header = in_header->pNext)\n"
2548 body += " switch (in_header->sType)\n"
2551 for i in self.ignores:
2552 body += " case {0}:\n".format(i)
2553 body += " break;\n\n"
2555 for e in self.struct.struct_extensions:
2559 stype = next(x for x in e.members if x.name == "sType")
2561 if stype.values in self.ignores:
2564 body += " case {0}:\n".format(stype.values)
2567 body += " const {0} *in = (const {0} *)in_header;\n".format(e.name)
2568 body += " {0} *out;\n\n".format(e.name)
2570 body += " if (!(out = malloc(sizeof(*out)))) goto out_of_memory;\n\n"
2573 if m.name == "pNext":
2574 body += " out->pNext = NULL;\n"
2576 convert = m.copy("in->", "out->", self.direction, conv=True)
2577 unwrap = m.copy("in->", "out->", self.direction, conv=False)
2578 if unwrap == convert:
2579 body += " " + unwrap
2581 body += "#if defined(USE_STRUCT_CONVERSION)\n"
2582 body += " " + convert
2584 body += " " + unwrap
2585 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2587 body += "\n out_header->pNext = (VkBaseOutStructure *)out;\n"
2588 body += " out_header = out_header->pNext;\n"
2592 body += " default:\n"
2593 body += " FIXME(\"Application requested a linked structure of type %u.\\n\", in_header->sType);\n"
2598 body += " return VK_SUCCESS;\n"
2600 if any(x for x in self.struct.struct_extensions if x.required):
2601 body += "\nout_of_memory:\n"
2602 body += " free_{0}_struct_chain(out_struct);\n".format(self.type)
2603 body += " return VK_ERROR_OUT_OF_HOST_MEMORY;\n"
2608 class FreeStructChainFunction(object):
2609 def __init__(self, struct):
2610 self.struct = struct
2611 self.type = struct.name
2613 self.name = "free_{0}_struct_chain".format(self.type)
2615 def __eq__(self, other):
2616 return self.name == other.name
2618 def prototype(self, postfix=""):
2619 return "void {0}({1} *s) {2}".format(self.name, self.type, postfix).strip()
2621 def definition(self):
2622 body = self.prototype()
2625 body += " VkBaseOutStructure *header = (void *)s->pNext;\n\n";
2627 body += " while (header)\n"
2629 body += " void *prev = header;\n\n"
2630 body += " switch (header->sType)\n"
2633 for e in self.struct.struct_extensions:
2637 if not any(m.needs_free() for m in e):
2640 stype = next(x for x in e.members if x.name == "sType")
2642 body += " case {0}:\n".format(stype.values)
2644 body += " {0} *structure = ({0} *) header;\n".format(e.name)
2648 convert = m.free("structure->", conv=True)
2649 unwrap = m.free("structure->", conv=False)
2650 if convert == unwrap:
2651 body += " " + unwrap
2653 body += "#if defined(USE_STRUCT_CONVERSION)\n"
2654 body += " " + convert
2655 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2657 body += "#if defined(USE_STRUCT_CONVERSION)\n"
2658 body += " " + convert
2660 body += " " + unwrap
2661 body += "#endif /* USE_STRUCT_CONVERSION */\n"
2666 body += " default:\n"
2670 body += " header = header->pNext;\n"
2671 body += " free(prev);\n"
2674 body += " s->pNext = NULL;\n"
2680 class VkGenerator(object):
2681 def __init__(self, registry):
2682 self.registry = registry
2684 # Build a list conversion functions for struct conversion.
2685 self.conversions = []
2686 self.struct_chain_conversions = []
2687 self.host_structs = []
2688 for func in self.registry.funcs.values():
2689 if not func.is_required():
2692 if not func.needs_conversion() and not func.needs_unwrapping():
2695 conversions = func.get_conversions()
2696 for conv in conversions:
2697 # Pull in any conversions for vulkan_thunks.c.
2698 if func.needs_thunk():
2699 # Append if we don't already have this conversion.
2700 if not any(c == conv for c in self.conversions):
2701 self.conversions.append(conv)
2703 if not isinstance(conv.operand, VkStruct):
2706 # Structs can be used in different ways by different conversions
2707 # e.g. array vs non-array. Just make sure we pull in each struct once.
2708 if not any(s.name == conv.operand.name for s in self.host_structs):
2709 self.host_structs.append(conv.operand)
2711 for struct in self.registry.structs:
2712 if struct.name in STRUCT_CHAIN_CONVERSIONS:
2713 self.struct_chain_conversions.append(StructChainConversionFunction(Direction.INPUT, struct, STRUCT_CHAIN_CONVERSIONS[struct.name]))
2714 self.struct_chain_conversions.append(FreeStructChainFunction(struct))
2715 # Once we decide to support pNext chains conversion everywhere, move this under get_conversions
2716 for e in struct.struct_extensions:
2718 if m.needs_conversion() or m.needs_unwrapping():
2719 conversions = m.get_conversions()
2720 for conv in conversions:
2721 if not any(c == conv for c in self.conversions):
2722 self.conversions.append(conv)
2724 def _generate_copyright(self, f, spec_file=False):
2725 f.write("# " if spec_file else "/* ")
2726 f.write("Automatically generated from Vulkan vk.xml; DO NOT EDIT!\n")
2727 lines = ["", "This file is generated from Vulkan vk.xml file covered",
2728 "by the following copyright and permission notice:"]
2729 lines.extend([l.rstrip(" ") for l in self.registry.copyright.splitlines()])
2731 f.write("{0}{1}".format("# " if spec_file else " * ", line).rstrip(" ") + "\n")
2732 f.write("\n" if spec_file else " */\n\n")
2734 def generate_thunks_c(self, f, prefix):
2735 self._generate_copyright(f)
2738 f.write("#pragma makedep unix\n")
2739 f.write("#endif\n\n")
2741 f.write("#include \"config.h\"\n\n")
2743 f.write("#include <stdlib.h>\n\n")
2745 f.write("#include \"vulkan_private.h\"\n\n")
2747 f.write("WINE_DEFAULT_DEBUG_CHANNEL(vulkan);\n\n")
2749 # Generate any conversion helper functions.
2750 for conv in self.conversions:
2751 f.write(conv.definition())
2753 for conv in self.struct_chain_conversions:
2754 f.write(conv.definition())
2756 # Create thunks for instance and device functions.
2757 # Global functions don't go through the thunks.
2758 for vk_func in self.registry.funcs.values():
2759 if not vk_func.needs_exposing():
2761 if vk_func.loader_thunk_type == ThunkType.NONE:
2764 if vk_func.needs_private_thunk():
2765 f.write(vk_func.thunk(prefix="thunk_"))
2767 if vk_func.thunk_type == ThunkType.PUBLIC:
2769 f.write(vk_func.thunk(prefix=prefix))
2771 # Create array of device extensions.
2772 f.write("static const char * const vk_device_extensions[] =\n{\n")
2773 for ext in self.registry.extensions:
2774 if ext["type"] != "device":
2776 if ext["name"] in UNEXPOSED_EXTENSIONS:
2779 f.write(" \"{0}\",\n".format(ext["name"]))
2782 # Create array of instance extensions.
2783 f.write("static const char * const vk_instance_extensions[] =\n{\n")
2784 for ext in self.registry.extensions:
2785 if ext["type"] != "instance":
2787 if ext["name"] in UNEXPOSED_EXTENSIONS:
2790 f.write(" \"{0}\",\n".format(ext["name"]))
2793 f.write("BOOL wine_vk_device_extension_supported(const char *name)\n")
2795 f.write(" unsigned int i;\n")
2796 f.write(" for (i = 0; i < ARRAY_SIZE(vk_device_extensions); i++)\n")
2798 f.write(" if (strcmp(vk_device_extensions[i], name) == 0)\n")
2799 f.write(" return TRUE;\n")
2801 f.write(" return FALSE;\n")
2804 f.write("BOOL wine_vk_instance_extension_supported(const char *name)\n")
2806 f.write(" unsigned int i;\n")
2807 f.write(" for (i = 0; i < ARRAY_SIZE(vk_instance_extensions); i++)\n")
2809 f.write(" if (strcmp(vk_instance_extensions[i], name) == 0)\n")
2810 f.write(" return TRUE;\n")
2812 f.write(" return FALSE;\n")
2815 f.write("BOOL wine_vk_is_type_wrapped(VkObjectType type)\n")
2817 f.write(" return FALSE")
2818 for handle in self.registry.handles:
2819 if not handle.is_required() or not handle.is_wrapped() or handle.is_alias():
2821 f.write(" ||\n type == {}".format(handle.object_type))
2825 f.write("uint64_t wine_vk_unwrap_handle(VkObjectType type, uint64_t handle)\n")
2827 f.write(" switch(type)\n")
2829 for handle in self.registry.handles:
2830 if not handle.is_required() or not handle.is_wrapped() or handle.is_alias():
2832 f.write(" case {}:\n".format(handle.object_type))
2833 if handle.is_dispatchable():
2834 f.write(" return (uint64_t) (uintptr_t) ")
2835 f.write(handle.native_handle("(({}) (uintptr_t) handle)".format(handle.name)))
2837 f.write(" return (uint64_t) ")
2838 f.write(handle.native_handle("handle"))
2840 f.write(" default:\n")
2841 f.write(" return handle;\n")
2845 f.write("const unixlib_entry_t __wine_unix_call_funcs[] =\n")
2847 f.write(" init_vulkan,\n")
2848 for vk_func in self.registry.funcs.values():
2849 if not vk_func.needs_exposing():
2851 if vk_func.loader_thunk_type == ThunkType.NONE:
2854 f.write(" {1}{0},\n".format(vk_func.name, prefix))
2856 f.write("C_ASSERT(ARRAYSIZE(__wine_unix_call_funcs) == unix_count);\n\n")
2858 f.write("static NTSTATUS WINAPI wine_vk_call(enum unix_call code, void *params)\n")
2860 f.write(" return __wine_unix_call_funcs[code](params);\n")
2863 f.write("const struct unix_funcs loader_funcs =\n")
2865 f.write(" wine_vk_call,\n")
2866 f.write(" wine_vk_is_available_instance_function,\n")
2867 f.write(" wine_vk_is_available_device_function,\n")
2870 def generate_thunks_h(self, f, prefix):
2871 self._generate_copyright(f)
2873 f.write("#ifndef __WINE_VULKAN_THUNKS_H\n")
2874 f.write("#define __WINE_VULKAN_THUNKS_H\n\n")
2876 f.write("#define WINE_VK_VERSION VK_API_VERSION_{0}_{1}\n\n".format(WINE_VK_VERSION[0], WINE_VK_VERSION[1]))
2878 # Generate prototypes for device and instance functions requiring a custom implementation.
2879 f.write("/* Functions for which we have custom implementations outside of the thunks. */\n")
2880 for vk_func in self.registry.funcs.values():
2881 if not vk_func.needs_exposing():
2883 if vk_func.needs_thunk() and not vk_func.needs_private_thunk():
2886 f.write("NTSTATUS {0}{1}(void *args) DECLSPEC_HIDDEN;\n".format(prefix, vk_func.name))
2889 f.write("/* Private thunks */\n")
2890 for vk_func in self.registry.funcs.values():
2891 if vk_func.needs_private_thunk():
2892 f.write("{0};\n".format(vk_func.prototype(prefix="thunk_", postfix="DECLSPEC_HIDDEN")))
2895 for struct in self.host_structs:
2896 f.write("#if defined(USE_STRUCT_CONVERSION)\n")
2897 f.write(struct.definition(align=False, conv=True, postfix="_host"))
2899 f.write("typedef {0} {0}_host;\n".format(struct.name))
2900 f.write("#endif\n\n")
2903 for func in self.struct_chain_conversions:
2904 f.write(func.prototype(postfix="DECLSPEC_HIDDEN") + ";\n")
2907 f.write("/* For use by vkDevice and children */\n")
2908 f.write("struct vulkan_device_funcs\n{\n")
2909 for vk_func in self.registry.device_funcs:
2910 if not vk_func.is_required():
2913 if not vk_func.needs_dispatch():
2914 LOGGER.debug("skipping {0} in vulkan_device_funcs".format(vk_func.name))
2917 f.write(" {0};\n".format(vk_func.pfn(conv=vk_func.needs_conversion())))
2920 f.write("/* For use by vkInstance and children */\n")
2921 f.write("struct vulkan_instance_funcs\n{\n")
2922 for vk_func in self.registry.instance_funcs + self.registry.phys_dev_funcs:
2923 if not vk_func.is_required():
2926 if not vk_func.needs_dispatch():
2927 LOGGER.debug("skipping {0} in vulkan_instance_funcs".format(vk_func.name))
2930 f.write(" {0};\n".format(vk_func.pfn(conv=vk_func.needs_conversion())))
2933 f.write("#define ALL_VK_DEVICE_FUNCS() \\\n")
2935 for vk_func in self.registry.device_funcs:
2936 if not vk_func.is_required():
2939 if not vk_func.needs_dispatch():
2940 LOGGER.debug("skipping {0} in ALL_VK_DEVICE_FUNCS".format(vk_func.name))
2944 f.write(" USE_VK_FUNC({0})".format(vk_func.name))
2947 f.write(" \\\n USE_VK_FUNC({0})".format(vk_func.name))
2950 f.write("#define ALL_VK_INSTANCE_FUNCS() \\\n")
2952 for vk_func in self.registry.instance_funcs + self.registry.phys_dev_funcs:
2953 if not vk_func.is_required():
2956 if not vk_func.needs_dispatch():
2957 LOGGER.debug("skipping {0} in ALL_VK_INSTANCE_FUNCS".format(vk_func.name))
2961 f.write(" USE_VK_FUNC({0})".format(vk_func.name))
2964 f.write(" \\\n USE_VK_FUNC({0})".format(vk_func.name))
2967 f.write("#endif /* __WINE_VULKAN_THUNKS_H */\n")
2969 def generate_loader_thunks_c(self, f):
2970 self._generate_copyright(f)
2972 f.write("#include \"vulkan_loader.h\"\n\n")
2974 f.write("WINE_DEFAULT_DEBUG_CHANNEL(vulkan);\n\n")
2976 for vk_func in self.registry.funcs.values():
2977 if not vk_func.needs_exposing():
2979 if vk_func.loader_thunk_type != ThunkType.PUBLIC:
2982 f.write(vk_func.loader_thunk())
2984 f.write("static const struct vulkan_func vk_device_dispatch_table[] =\n{\n")
2985 for vk_func in self.registry.device_funcs:
2986 if not vk_func.needs_exposing():
2989 f.write(" {{\"{0}\", {0}}},\n".format(vk_func.name))
2992 f.write("static const struct vulkan_func vk_phys_dev_dispatch_table[] =\n{\n")
2993 for vk_func in self.registry.phys_dev_funcs:
2994 if not vk_func.needs_exposing():
2997 f.write(" {{\"{0}\", {0}}},\n".format(vk_func.name))
3000 f.write("static const struct vulkan_func vk_instance_dispatch_table[] =\n{\n")
3001 for vk_func in self.registry.instance_funcs:
3002 if not vk_func.needs_exposing():
3005 f.write(" {{\"{0}\", {0}}},\n".format(vk_func.name))
3008 f.write("void *wine_vk_get_device_proc_addr(const char *name)\n")
3010 f.write(" unsigned int i;\n")
3011 f.write(" for (i = 0; i < ARRAY_SIZE(vk_device_dispatch_table); i++)\n")
3013 f.write(" if (strcmp(vk_device_dispatch_table[i].name, name) == 0)\n")
3015 f.write(" TRACE(\"Found name=%s in device table\\n\", debugstr_a(name));\n")
3016 f.write(" return vk_device_dispatch_table[i].func;\n")
3019 f.write(" return NULL;\n")
3022 f.write("void *wine_vk_get_phys_dev_proc_addr(const char *name)\n")
3024 f.write(" unsigned int i;\n")
3025 f.write(" for (i = 0; i < ARRAY_SIZE(vk_phys_dev_dispatch_table); i++)\n")
3027 f.write(" if (strcmp(vk_phys_dev_dispatch_table[i].name, name) == 0)\n")
3029 f.write(" TRACE(\"Found name=%s in physical device table\\n\", debugstr_a(name));\n")
3030 f.write(" return vk_phys_dev_dispatch_table[i].func;\n")
3033 f.write(" return NULL;\n")
3036 f.write("void *wine_vk_get_instance_proc_addr(const char *name)\n")
3038 f.write(" unsigned int i;\n")
3039 f.write(" for (i = 0; i < ARRAY_SIZE(vk_instance_dispatch_table); i++)\n")
3041 f.write(" if (strcmp(vk_instance_dispatch_table[i].name, name) == 0)\n")
3043 f.write(" TRACE(\"Found name=%s in instance table\\n\", debugstr_a(name));\n")
3044 f.write(" return vk_instance_dispatch_table[i].func;\n")
3047 f.write(" return NULL;\n")
3050 def generate_loader_thunks_h(self, f):
3051 self._generate_copyright(f)
3053 f.write("#ifndef __WINE_VULKAN_LOADER_THUNKS_H\n")
3054 f.write("#define __WINE_VULKAN_LOADER_THUNKS_H\n\n")
3056 f.write("enum unix_call\n")
3058 f.write(" unix_init,\n")
3059 for vk_func in self.registry.funcs.values():
3060 if not vk_func.needs_exposing():
3062 if vk_func.loader_thunk_type == ThunkType.NONE:
3065 f.write(" unix_{0},\n".format(vk_func.name))
3066 f.write(" unix_count,\n")
3069 f.write("#include \"pshpack4.h\"\n\n")
3071 for vk_func in self.registry.funcs.values():
3072 if not vk_func.needs_exposing():
3074 if vk_func.loader_thunk_type == ThunkType.NONE:
3077 f.write("struct {0}_params\n".format(vk_func.name))
3079 for p in vk_func.params:
3080 f.write(" {0};\n".format(p.definition(is_member=True)))
3081 if vk_func.returns_longlong():
3082 f.write(" {0} result;\n".format(vk_func.type))
3085 f.write("#include \"poppack.h\"\n\n")
3086 f.write("#endif /* __WINE_VULKAN_LOADER_THUNKS_H */\n")
3088 def generate_vulkan_h(self, f):
3089 self._generate_copyright(f)
3090 f.write("#ifndef __WINE_VULKAN_H\n")
3091 f.write("#define __WINE_VULKAN_H\n\n")
3093 f.write("#include <windef.h>\n")
3094 f.write("#include <stdint.h>\n\n")
3096 f.write("/* Define WINE_VK_HOST to get 'host' headers. */\n")
3097 f.write("#ifdef WINE_VK_HOST\n")
3098 f.write("#define VKAPI_CALL\n")
3099 f.write('#define WINE_VK_ALIGN(x)\n')
3100 f.write("#endif\n\n")
3102 f.write("#ifndef VKAPI_CALL\n")
3103 f.write("#define VKAPI_CALL __stdcall\n")
3104 f.write("#endif\n\n")
3106 f.write("#ifndef VKAPI_PTR\n")
3107 f.write("#define VKAPI_PTR VKAPI_CALL\n")
3108 f.write("#endif\n\n")
3110 f.write("#ifndef WINE_VK_ALIGN\n")
3111 f.write("#define WINE_VK_ALIGN DECLSPEC_ALIGN\n")
3112 f.write("#endif\n\n")
3114 # The overall strategy is to define independent constants and datatypes,
3115 # prior to complex structures and function calls to avoid forward declarations.
3116 for const in self.registry.consts:
3117 # For now just generate things we may not need. The amount of parsing needed
3118 # to get some of the info is tricky as you need to figure out which structure
3119 # references a certain constant.
3120 f.write(const.definition())
3123 for define in self.registry.defines:
3124 f.write(define.definition())
3126 for handle in self.registry.handles:
3127 # For backward compatibility also create definitions for aliases.
3128 # These types normally don't get pulled in as we use the new types
3129 # even in legacy functions if they are aliases.
3130 if handle.is_required() or handle.is_alias():
3131 f.write(handle.definition())
3134 for base_type in self.registry.base_types:
3135 f.write(base_type.definition())
3138 for bitmask in self.registry.bitmasks:
3139 f.write(bitmask.definition())
3142 # Define enums, this includes values for some of the bitmask types as well.
3143 for enum in self.registry.enums.values():
3145 f.write(enum.definition())
3147 for fp in self.registry.funcpointers:
3149 f.write(fp.definition())
3152 # This generates both structures and unions. Since structures
3153 # may depend on other structures/unions, we need a list of
3154 # decoupled structs.
3155 # Note: unions are stored in structs for dependency reasons,
3156 # see comment in parsing section.
3157 structs = VkStruct.decouple_structs(self.registry.structs)
3158 for struct in structs:
3159 LOGGER.debug("Generating struct: {0}".format(struct.name))
3160 f.write(struct.definition(align=True))
3163 for func in self.registry.funcs.values():
3164 if not func.is_required():
3165 LOGGER.debug("Skipping PFN definition for: {0}".format(func.name))
3168 f.write("typedef {0};\n".format(func.pfn(prefix="PFN", call_conv="VKAPI_PTR")))
3171 f.write("#ifndef VK_NO_PROTOTYPES\n")
3172 for func in self.registry.funcs.values():
3173 if not func.is_required():
3174 LOGGER.debug("Skipping API definition for: {0}".format(func.name))
3177 LOGGER.debug("Generating API definition for: {0}".format(func.name))
3178 f.write("{0};\n".format(func.prototype(call_conv="VKAPI_CALL")))
3179 f.write("#endif /* VK_NO_PROTOTYPES */\n\n")
3181 f.write("#endif /* __WINE_VULKAN_H */\n")
3183 def generate_vulkan_driver_h(self, f):
3184 self._generate_copyright(f)
3185 f.write("#ifndef __WINE_VULKAN_DRIVER_H\n")
3186 f.write("#define __WINE_VULKAN_DRIVER_H\n\n")
3188 f.write("/* Wine internal vulkan driver version, needs to be bumped upon vulkan_funcs changes. */\n")
3189 f.write("#define WINE_VULKAN_DRIVER_VERSION {0}\n\n".format(DRIVER_VERSION))
3191 f.write("struct vulkan_funcs\n{\n")
3192 f.write(" /* Vulkan global functions. These are the only calls at this point a graphics driver\n")
3193 f.write(" * needs to provide. Other function calls will be provided indirectly by dispatch\n")
3194 f.write(" * tables part of dispatchable Vulkan objects such as VkInstance or vkDevice.\n")
3197 for vk_func in self.registry.funcs.values():
3198 if not vk_func.is_driver_func():
3202 # Avoid PFN_vkVoidFunction in driver interface as Vulkan likes to put calling convention
3203 # stuff in there. For simplicity substitute with "void *".
3204 pfn = pfn.replace("PFN_vkVoidFunction", "void *")
3205 f.write(" {0};\n".format(pfn))
3208 f.write(" /* winevulkan specific functions */\n")
3209 f.write(" VkSurfaceKHR (*p_wine_get_native_surface)(VkSurfaceKHR);\n")
3212 f.write("extern const struct vulkan_funcs * CDECL __wine_get_vulkan_driver(UINT version);\n\n")
3214 f.write("static inline void *get_vulkan_driver_device_proc_addr(\n")
3215 f.write(" const struct vulkan_funcs *vulkan_funcs, const char *name)\n{\n")
3216 f.write(" if (!name || name[0] != 'v' || name[1] != 'k') return NULL;\n\n")
3217 f.write(" name += 2;\n\n")
3218 for vk_func in self.registry.funcs.values():
3219 if vk_func.is_driver_func() and vk_func.is_device_func():
3220 f.write(' if (!strcmp(name, "{0}"))\n'.format(vk_func.name[2:]))
3221 f.write(' return vulkan_funcs->p_{0};\n'.format(vk_func.name))
3223 f.write(" return NULL;\n}\n\n")
3225 f.write("static inline void *get_vulkan_driver_instance_proc_addr(\n")
3226 f.write(" const struct vulkan_funcs *vulkan_funcs, VkInstance instance, const char *name)\n{\n")
3227 f.write(" if (!name || name[0] != 'v' || name[1] != 'k') return NULL;\n\n")
3228 f.write(" name += 2;\n\n")
3229 for vk_func in self.registry.funcs.values():
3230 if vk_func.is_driver_func() and vk_func.is_global_func() and vk_func.name != "vkGetInstanceProcAddr":
3231 f.write(' if (!strcmp(name, "{0}"))\n'.format(vk_func.name[2:]))
3232 f.write(' return vulkan_funcs->p_{0};\n'.format(vk_func.name))
3234 f.write(" if (!instance) return NULL;\n\n")
3235 for vk_func in self.registry.funcs.values():
3236 if vk_func.is_driver_func() and (vk_func.is_instance_func() or vk_func.is_phys_dev_func()):
3237 f.write(' if (!strcmp(name, "{0}"))\n'.format(vk_func.name[2:]))
3238 f.write(' return vulkan_funcs->p_{0};\n'.format(vk_func.name))
3240 f.write(" name -= 2;\n\n")
3241 f.write(" return get_vulkan_driver_device_proc_addr(vulkan_funcs, name);\n}\n\n")
3243 f.write("#endif /* __WINE_VULKAN_DRIVER_H */\n")
3245 def generate_vulkan_spec(self, f):
3246 self._generate_copyright(f, spec_file=True)
3247 f.write("@ stdcall -private vk_icdGetInstanceProcAddr(ptr str)\n")
3248 f.write("@ stdcall -private vk_icdGetPhysicalDeviceProcAddr(ptr str)\n")
3249 f.write("@ stdcall -private vk_icdNegotiateLoaderICDInterfaceVersion(ptr)\n")
3251 # Export symbols for all Vulkan Core functions.
3252 for func in self.registry.funcs.values():
3253 if not func.is_core_func():
3256 # We support all Core functions except for VK_KHR_display* APIs.
3257 # Create stubs for unsupported Core functions.
3258 if func.is_required():
3259 f.write(func.spec())
3261 f.write("@ stub {0}\n".format(func.name))
3263 f.write("@ stdcall -private DllRegisterServer()\n")
3264 f.write("@ stdcall -private DllUnregisterServer()\n")
3266 def generate_vulkan_loader_spec(self, f):
3267 self._generate_copyright(f, spec_file=True)
3269 # Export symbols for all Vulkan Core functions.
3270 for func in self.registry.funcs.values():
3271 if not func.is_core_func():
3274 # We support all Core functions except for VK_KHR_display* APIs.
3275 # Create stubs for unsupported Core functions.
3276 if func.is_required():
3277 f.write(func.spec(symbol="winevulkan." + func.name))
3279 f.write("@ stub {0}\n".format(func.name))
3282 class VkRegistry(object):
3283 def __init__(self, reg_filename):
3284 # Used for storage of type information.
3285 self.base_types = None
3286 self.bitmasks = None
3290 self.funcpointers = None
3294 # We aggregate all types in here for cross-referencing.
3298 self.version_regex = re.compile(
3307 # Overall strategy for parsing the registry is to first
3308 # parse all type / function definitions. Then parse
3309 # features and extensions to decide which types / functions
3310 # to actually 'pull in' for code generation. For each type or
3311 # function call we want we set a member 'required' to True.
3312 tree = ET.parse(reg_filename)
3313 root = tree.getroot()
3314 self._parse_enums(root)
3315 self._parse_types(root)
3316 self._parse_commands(root)
3318 # Pull in any required types and functions.
3319 self._parse_features(root)
3320 self._parse_extensions(root)
3322 self._match_object_types()
3324 self.copyright = root.find('./comment').text
3326 def _is_feature_supported(self, feature):
3327 version = self.version_regex.match(feature)
3331 version = tuple(map(int, version.group('major', 'minor')))
3332 return version <= WINE_VK_VERSION
3334 def _is_extension_supported(self, extension):
3335 # We disable some extensions as either we haven't implemented
3336 # support yet or because they are for platforms other than win32.
3337 return extension not in UNSUPPORTED_EXTENSIONS
3339 def _mark_command_required(self, command):
3340 """ Helper function to mark a certain command and the datatypes it needs as required."""
3341 def mark_bitmask_dependencies(bitmask, types):
3342 if bitmask.requires is not None:
3343 types[bitmask.requires]["data"].required = True
3345 def mark_funcpointer_dependencies(fp, types):
3346 for m in fp.members:
3347 type_info = types[m.type]
3349 # Complex types have a matching definition e.g. VkStruct.
3350 # Not needed for base types such as uint32_t.
3351 if "data" in type_info:
3352 types[m.type]["data"].required = True
3354 def mark_struct_dependencies(struct, types):
3356 type_info = types[m.type]
3358 # Complex types have a matching definition e.g. VkStruct.
3359 # Not needed for base types such as uint32_t.
3360 if "data" in type_info:
3361 types[m.type]["data"].required = True
3363 if type_info["category"] == "struct" and struct.name != m.type:
3365 mark_struct_dependencies(type_info["data"], types)
3366 elif type_info["category"] == "funcpointer":
3367 mark_funcpointer_dependencies(type_info["data"], types)
3368 elif type_info["category"] == "bitmask":
3369 mark_bitmask_dependencies(type_info["data"], types)
3371 func = self.funcs[command]
3372 func.required = True
3374 # Pull in return type
3375 if func.type != "void":
3376 self.types[func.type]["data"].required = True
3378 # Analyze parameter dependencies and pull in any type needed.
3379 for p in func.params:
3380 type_info = self.types[p.type]
3382 # Check if we are dealing with a complex type e.g. VkEnum, VkStruct and others.
3383 if "data" not in type_info:
3386 # Mark the complex type as required.
3387 type_info["data"].required = True
3388 if type_info["category"] == "struct":
3389 struct = type_info["data"]
3390 mark_struct_dependencies(struct, self.types)
3391 elif type_info["category"] == "bitmask":
3392 mark_bitmask_dependencies(type_info["data"], self.types)
3394 def _match_object_types(self):
3395 """ Matches each handle with the correct object type. """
3396 # Use upper case comparison for simplicity.
3398 for value in self.enums["VkObjectType"].values:
3399 object_name = "VK" + value.name[len("VK_OBJECT_TYPE"):].replace("_", "")
3400 object_types[object_name] = value.name
3402 for handle in self.handles:
3403 if not handle.is_required():
3405 handle.object_type = object_types.get(handle.name.upper())
3406 if not handle.object_type:
3407 LOGGER.warning("No object type found for {}".format(handle.name))
3409 def _parse_commands(self, root):
3410 """ Parse command section containing the Vulkan function calls. """
3412 commands = root.findall("./commands/")
3414 # As of Vulkan 1.1, various extensions got promoted to Core.
3415 # The old commands (e.g. KHR) are available for backwards compatibility
3416 # and are marked in vk.xml as 'alias' to the non-extension type.
3417 # The registry likes to avoid data duplication, so parameters and other
3418 # metadata need to be looked up from the Core command.
3419 # We parse the alias commands in a second pass.
3421 for command in commands:
3422 alias_name = command.attrib.get("alias")
3424 alias_commands.append(command)
3427 func = VkFunction.from_xml(command, self.types)
3428 funcs[func.name] = func
3430 for command in alias_commands:
3431 alias_name = command.attrib.get("alias")
3432 alias = funcs[alias_name]
3433 func = VkFunction.from_alias(command, alias)
3434 funcs[func.name] = func
3436 # To make life easy for the code generation, separate all function
3437 # calls out in the 4 types of Vulkan functions:
3438 # device, global, physical device and instance.
3443 for func in funcs.values():
3444 if func.is_device_func():
3445 device_funcs.append(func)
3446 elif func.is_global_func():
3447 global_funcs.append(func)
3448 elif func.is_phys_dev_func():
3449 phys_dev_funcs.append(func)
3451 instance_funcs.append(func)
3453 # Sort function lists by name and store them.
3454 self.device_funcs = sorted(device_funcs, key=lambda func: func.name)
3455 self.global_funcs = sorted(global_funcs, key=lambda func: func.name)
3456 self.phys_dev_funcs = sorted(phys_dev_funcs, key=lambda func: func.name)
3457 self.instance_funcs = sorted(instance_funcs, key=lambda func: func.name)
3459 # The funcs dictionary is used as a convenient way to lookup function
3460 # calls when needed e.g. to adjust member variables.
3461 self.funcs = OrderedDict(sorted(funcs.items()))
3463 def _parse_enums(self, root):
3464 """ Parse enums section or better described as constants section. """
3467 for enum in root.findall("./enums"):
3468 name = enum.attrib.get("name")
3469 _type = enum.attrib.get("type")
3471 if _type in ("enum", "bitmask"):
3472 enums[name] = VkEnum.from_xml(enum)
3474 # If no type is set, we are dealing with API constants.
3475 for value in enum.findall("enum"):
3476 # If enum is an alias, set the value to the alias name.
3477 # E.g. VK_LUID_SIZE_KHR is an alias to VK_LUID_SIZE.
3478 alias = value.attrib.get("alias")
3480 self.consts.append(VkConstant(value.attrib.get("name"), alias))
3482 self.consts.append(VkConstant(value.attrib.get("name"), value.attrib.get("value")))
3484 self.enums = OrderedDict(sorted(enums.items()))
3486 def _process_require_enum(self, enum_elem, ext=None, only_aliased=False):
3487 if "extends" in enum_elem.keys():
3488 enum = self.types[enum_elem.attrib["extends"]]["data"]
3490 # Need to define VkEnumValues which were aliased to by another value. This is necessary
3491 # from VK spec version 1.2.135 where the provisional VK_KHR_ray_tracing extension was
3492 # added which altered VK_NV_ray_tracing's VkEnumValues to alias to the provisional
3495 for _, t in self.types.items():
3496 if t["category"] != "enum":
3500 for value in t["data"].values:
3501 if value.alias == enum_elem.attrib["name"]:
3504 if only_aliased and not aliased:
3507 if "bitpos" in enum_elem.keys():
3508 # We need to add an extra value to an existing enum type.
3509 # E.g. VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG to VkFormatFeatureFlagBits.
3510 enum.create_bitpos(enum_elem.attrib["name"], int(enum_elem.attrib["bitpos"]))
3512 elif "offset" in enum_elem.keys():
3513 # Extensions promoted to Core, have the extension number as part
3514 # of the enum value. Else retrieve from the extension tag.
3515 if enum_elem.attrib.get("extnumber"):
3516 ext_number = int(enum_elem.attrib.get("extnumber"))
3518 ext_number = int(ext.attrib["number"])
3519 offset = int(enum_elem.attrib["offset"])
3520 value = EXT_BASE + (ext_number - 1) * EXT_BLOCK_SIZE + offset
3522 # Deal with negative values.
3523 direction = enum_elem.attrib.get("dir")
3524 if direction is not None:
3527 enum.create_value(enum_elem.attrib["name"], str(value))
3529 elif "value" in enum_elem.keys():
3530 enum.create_value(enum_elem.attrib["name"], enum_elem.attrib["value"])
3531 elif "alias" in enum_elem.keys():
3532 enum.create_alias(enum_elem.attrib["name"], enum_elem.attrib["alias"])
3534 elif "value" in enum_elem.keys():
3535 # Constant with an explicit value
3539 self.consts.append(VkConstant(enum_elem.attrib["name"], enum_elem.attrib["value"]))
3540 elif "alias" in enum_elem.keys():
3542 if not only_aliased:
3545 self.consts.append(VkConstant(enum_elem.attrib["name"], enum_elem.attrib["alias"]))
3548 def _require_type(type_info):
3549 if type_info.is_alias():
3550 type_info = type_info.alias
3551 type_info.required = True
3552 if type(type_info) == VkStruct:
3553 for member in type_info.members:
3554 if "data" in member.type_info:
3555 VkRegistry._require_type(member.type_info["data"])
3557 def _parse_extensions(self, root):
3558 """ Parse extensions section and pull in any types and commands for this extension. """
3560 exts = root.findall("./extensions/extension")
3562 skipped_exts = UNSUPPORTED_EXTENSIONS.copy()
3564 def process_ext(ext, deferred=False):
3565 ext_name = ext.attrib["name"]
3567 # Set extension name on any functions calls part of this extension as we
3568 # were not aware of the name during initial parsing.
3569 commands = ext.findall("require/command")
3570 for command in commands:
3571 cmd_name = command.attrib["name"]
3572 # Need to verify that the command is defined, and otherwise skip it.
3573 # vkCreateScreenSurfaceQNX is declared in <extensions> but not defined in
3574 # <commands>. A command without a definition cannot be enabled, so it's valid for
3575 # the XML file to handle this, but because of the manner in which we parse the XML
3576 # file we pre-populate from <commands> before we check if a command is enabled.
3577 if cmd_name in self.funcs:
3578 self.funcs[cmd_name].extensions.add(ext_name)
3580 # Some extensions are not ready or have numbers reserved as a place holder.
3581 if ext.attrib["supported"] == "disabled":
3582 LOGGER.debug("Skipping disabled extension: {0}".format(ext_name))
3583 skipped_exts.append(ext_name)
3586 # Defer extensions with 'sortorder' as they are order-dependent for spec-parsing.
3587 if not deferred and "sortorder" in ext.attrib:
3588 deferred_exts.append(ext)
3591 # Disable highly experimental extensions as the APIs are unstable and can
3592 # change between minor Vulkan revisions until API is final and becomes KHR
3594 if ("KHX" in ext_name or "NVX" in ext_name) and ext_name not in ALLOWED_X_EXTENSIONS:
3595 LOGGER.debug("Skipping experimental extension: {0}".format(ext_name))
3596 skipped_exts.append(ext_name)
3599 # Extensions can define VkEnumValues which alias to provisional extensions. Pre-process
3600 # extensions to define any required VkEnumValues before the platform check below.
3601 for require in ext.findall("require"):
3602 # Extensions can add enum values to Core / extension enums, so add these.
3603 for enum_elem in require.findall("enum"):
3604 self._process_require_enum(enum_elem, ext, only_aliased=True)
3606 platform = ext.attrib.get("platform")
3607 if platform and platform != "win32":
3608 LOGGER.debug("Skipping extensions {0} for platform {1}".format(ext_name, platform))
3609 skipped_exts.append(ext_name)
3612 if not self._is_extension_supported(ext_name):
3613 LOGGER.debug("Skipping unsupported extension: {0}".format(ext_name))
3614 skipped_exts.append(ext_name)
3616 elif "requires" in ext.attrib:
3617 # Check if this extension builds on top of another unsupported extension.
3618 requires = ext.attrib["requires"].split(",")
3619 if len(set(requires).intersection(skipped_exts)) > 0:
3620 skipped_exts.append(ext_name)
3623 LOGGER.debug("Loading extension: {0}".format(ext_name))
3625 # Extensions can define one or more require sections each requiring
3626 # different features (e.g. Vulkan 1.1). Parse each require section
3627 # separately, so we can skip sections we don't want.
3628 for require in ext.findall("require"):
3629 # Extensions can add enum values to Core / extension enums, so add these.
3630 for enum_elem in require.findall("enum"):
3631 self._process_require_enum(enum_elem, ext)
3633 for t in require.findall("type"):
3634 type_info = self.types[t.attrib["name"]]["data"]
3635 self._require_type(type_info)
3636 feature = require.attrib.get("feature")
3637 if feature and not self._is_feature_supported(feature):
3640 required_extension = require.attrib.get("extension")
3641 if required_extension and not self._is_extension_supported(required_extension):
3644 # Pull in any commands we need. We infer types to pull in from the command
3646 for command in require.findall("command"):
3647 cmd_name = command.attrib["name"]
3648 self._mark_command_required(cmd_name)
3651 # Store a list with extensions.
3652 ext_info = {"name" : ext_name, "type" : ext.attrib["type"]}
3653 extensions.append(ext_info)
3656 # Process extensions, allowing for sortorder to defer extension processing
3660 deferred_exts.sort(key=lambda ext: ext.attrib["sortorder"])
3663 for ext in deferred_exts:
3664 process_ext(ext, deferred=True)
3666 # Sort in alphabetical order.
3667 self.extensions = sorted(extensions, key=lambda ext: ext["name"])
3669 def _parse_features(self, root):
3670 """ Parse the feature section, which describes Core commands and types needed. """
3672 for feature in root.findall("./feature"):
3673 feature_name = feature.attrib["name"]
3674 for require in feature.findall("require"):
3675 LOGGER.info("Including features for {0}".format(require.attrib.get("comment")))
3677 if tag.tag == "comment":
3679 elif tag.tag == "command":
3680 if not self._is_feature_supported(feature_name):
3682 name = tag.attrib["name"]
3683 self._mark_command_required(name)
3684 elif tag.tag == "enum":
3685 self._process_require_enum(tag)
3686 elif tag.tag == "type":
3687 name = tag.attrib["name"]
3689 # Skip pull in for vk_platform.h for now.
3690 if name == "vk_platform":
3693 type_info = self.types[name]
3694 type_info["data"].required = True
3696 def _parse_types(self, root):
3697 """ Parse types section, which contains all data types e.g. structs, typedefs etcetera. """
3698 types = root.findall("./types/type")
3710 type_info["category"] = t.attrib.get("category", None)
3711 type_info["requires"] = t.attrib.get("requires", None)
3713 # We parse aliases in a second pass when we know more.
3714 alias = t.attrib.get("alias")
3716 LOGGER.debug("Alias found: {0}".format(alias))
3717 alias_types.append(t)
3720 if type_info["category"] in ["include"]:
3723 if type_info["category"] == "basetype":
3724 name = t.find("name").text
3726 if not t.find("type") is None:
3727 _type = t.find("type").text
3728 tail = t.find("type").tail
3729 if tail is not None:
3730 _type += tail.strip()
3731 basetype = VkBaseType(name, _type)
3732 base_types.append(basetype)
3733 type_info["data"] = basetype
3735 # Basic C types don't need us to define them, but we do need data for them
3736 if type_info["requires"] == "vk_platform":
3737 requires = type_info["requires"]
3738 basic_c = VkBaseType(name, _type, requires=requires)
3739 type_info["data"] = basic_c
3741 if type_info["category"] == "bitmask":
3742 name = t.find("name").text
3743 _type = t.find("type").text
3745 # Most bitmasks have a requires attribute used to pull in
3746 # required '*FlagBits" enum.
3747 requires = type_info["requires"]
3748 bitmask = VkBaseType(name, _type, requires=requires)
3749 bitmasks.append(bitmask)
3750 type_info["data"] = bitmask
3752 if type_info["category"] == "define":
3753 define = VkDefine.from_xml(t)
3754 defines.append(define)
3755 type_info["data"] = define
3757 if type_info["category"] == "enum":
3758 name = t.attrib.get("name")
3759 # The type section only contains enum names, not the actual definition.
3760 # Since we already parsed the enum before, just link it in.
3762 type_info["data"] = self.enums[name]
3763 except KeyError as e:
3764 # Not all enums seem to be defined yet, typically that's for
3765 # ones ending in 'FlagBits' where future extensions may add
3767 type_info["data"] = None
3769 if type_info["category"] == "funcpointer":
3770 funcpointer = VkFunctionPointer.from_xml(t)
3771 funcpointers.append(funcpointer)
3772 type_info["data"] = funcpointer
3774 if type_info["category"] == "handle":
3775 handle = VkHandle.from_xml(t)
3776 handles.append(handle)
3777 type_info["data"] = handle
3779 if type_info["category"] in ["struct", "union"]:
3780 # We store unions among structs as some structs depend
3781 # on unions. The types are very similar in parsing and
3782 # generation anyway. The official Vulkan scripts use
3783 # a similar kind of hack.
3784 struct = VkStruct.from_xml(t)
3785 structs.append(struct)
3786 type_info["data"] = struct
3788 # Name is in general within a name tag else it is an optional
3789 # attribute on the type tag.
3790 name_elem = t.find("name")
3791 if name_elem is not None:
3792 type_info["name"] = name_elem.text
3794 type_info["name"] = t.attrib.get("name", None)
3796 # Store all type data in a shared dictionary, so we can easily
3797 # look up information for a given type. There are no duplicate
3799 self.types[type_info["name"]] = type_info
3801 # Second pass for alias types, so we can retrieve all data from
3802 # the aliased object.
3803 for t in alias_types:
3805 type_info["category"] = t.attrib.get("category")
3806 type_info["name"] = t.attrib.get("name")
3808 alias = t.attrib.get("alias")
3810 if type_info["category"] == "bitmask":
3811 bitmask = VkBaseType(type_info["name"], alias, alias=self.types[alias]["data"])
3812 bitmasks.append(bitmask)
3813 type_info["data"] = bitmask
3815 if type_info["category"] == "enum":
3816 enum = VkEnum.from_alias(t, self.types[alias]["data"])
3817 type_info["data"] = enum
3818 self.enums[enum.name] = enum
3820 if type_info["category"] == "handle":
3821 handle = VkHandle.from_alias(t, self.types[alias]["data"])
3822 handles.append(handle)
3823 type_info["data"] = handle
3825 if type_info["category"] == "struct":
3826 struct = VkStruct.from_alias(t, self.types[alias]["data"])
3827 structs.append(struct)
3828 type_info["data"] = struct
3830 self.types[type_info["name"]] = type_info
3832 # We need detailed type information during code generation
3833 # on structs for alignment reasons. Unfortunately structs
3834 # are parsed among other types, so there is no guarantee
3835 # that any types needed have been parsed already, so set
3837 for struct in structs:
3838 struct.set_type_info(self.types)
3840 # Alias structures have enum values equivalent to those of the
3841 # structure which they are aliased against. we need to ignore alias
3842 # structs when populating the struct extensions list, otherwise we
3843 # will create duplicate case entries.
3847 for structextend in struct.structextends:
3848 s = self.types[structextend]["data"]
3849 s.struct_extensions.append(struct)
3851 # Guarantee everything is sorted, so code generation doesn't have
3852 # to deal with this.
3853 self.base_types = sorted(base_types, key=lambda base_type: base_type.name)
3854 self.bitmasks = sorted(bitmasks, key=lambda bitmask: bitmask.name)
3855 self.defines = defines
3856 self.enums = OrderedDict(sorted(self.enums.items()))
3857 self.funcpointers = sorted(funcpointers, key=lambda fp: fp.name)
3858 self.handles = sorted(handles, key=lambda handle: handle.name)
3859 self.structs = sorted(structs, key=lambda struct: struct.name)
3861 def generate_vulkan_json(f):
3863 f.write(" \"file_format_version\": \"1.0.0\",\n")
3864 f.write(" \"ICD\": {\n")
3865 f.write(" \"library_path\": \".\\\\winevulkan.dll\",\n")
3866 f.write(" \"api_version\": \"{0}\"\n".format(VK_XML_VERSION))
3870 def set_working_directory():
3871 path = os.path.abspath(__file__)
3872 path = os.path.dirname(path)
3875 def download_vk_xml(filename):
3876 url = "https://raw.githubusercontent.com/KhronosGroup/Vulkan-Docs/v{0}/xml/vk.xml".format(VK_XML_VERSION)
3877 if not os.path.isfile(filename):
3878 urllib.request.urlretrieve(url, filename)
3881 parser = argparse.ArgumentParser()
3882 parser.add_argument("-v", "--verbose", action="count", default=0, help="increase output verbosity")
3883 parser.add_argument("-x", "--xml", default=None, type=str, help="path to specification XML file")
3885 args = parser.parse_args()
3886 if args.verbose == 0:
3887 LOGGER.setLevel(logging.WARNING)
3888 elif args.verbose == 1:
3889 LOGGER.setLevel(logging.INFO)
3891 LOGGER.setLevel(logging.DEBUG)
3893 set_working_directory()
3898 vk_xml = "vk-{0}.xml".format(VK_XML_VERSION)
3899 download_vk_xml(vk_xml)
3901 registry = VkRegistry(vk_xml)
3902 generator = VkGenerator(registry)
3904 with open(WINE_VULKAN_H, "w") as f:
3905 generator.generate_vulkan_h(f)
3907 with open(WINE_VULKAN_DRIVER_H, "w") as f:
3908 generator.generate_vulkan_driver_h(f)
3910 with open(WINE_VULKAN_THUNKS_H, "w") as f:
3911 generator.generate_thunks_h(f, "wine_")
3913 with open(WINE_VULKAN_THUNKS_C, "w") as f:
3914 generator.generate_thunks_c(f, "wine_")
3916 with open(WINE_VULKAN_LOADER_THUNKS_H, "w") as f:
3917 generator.generate_loader_thunks_h(f)
3919 with open(WINE_VULKAN_LOADER_THUNKS_C, "w") as f:
3920 generator.generate_loader_thunks_c(f)
3922 with open(WINE_VULKAN_JSON, "w") as f:
3923 generate_vulkan_json(f)
3925 with open(WINE_VULKAN_SPEC, "w") as f:
3926 generator.generate_vulkan_spec(f)
3928 with open(WINE_VULKAN_LOADER_SPEC, "w") as f:
3929 generator.generate_vulkan_loader_spec(f)
3931 if __name__ == "__main__":