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
25 import xml.etree.ElementTree as ET
26 from collections import OrderedDict
27 from collections.abc import Sequence
30 # This script generates code for a Wine Vulkan ICD driver from Vulkan's vk.xml.
31 # Generating the code is like 10x worse than OpenGL, which is mostly a calling
32 # convention passthrough.
34 # The script parses vk.xml and maps functions and types to helper objects. These
35 # helper objects simplify the xml parsing and map closely to the Vulkan types.
36 # The code generation utilizes the helper objects during code generation and
37 # most of the ugly work is carried out by these objects.
39 # Vulkan ICD challenges:
40 # - Vulkan ICD loader (vulkan-1.dll) relies on a section at the start of
41 # 'dispatchable handles' (e.g. VkDevice, VkInstance) for it to insert
42 # its private data. It uses this area to stare its own dispatch tables
43 # for loader internal use. This means any dispatchable objects need wrapping.
45 # - Vulkan structures have different alignment between win32 and 32-bit Linux.
46 # This means structures with alignment differences need conversion logic.
47 # Often structures are nested, so the parent structure may not need any
48 # conversion, but some child may need some.
50 # vk.xml parsing challenges:
51 # - Contains type data for all platforms (generic Vulkan, Windows, Linux,..).
52 # Parsing of extension information required to pull in types and functions
53 # we really want to generate. Just tying all the data together is tricky.
55 # - Extensions can affect core types e.g. add new enum values, bitflags or
56 # additional structure chaining through 'pNext' / 'sType'.
58 # - Arrays are used all over the place for parameters or for structure members.
59 # Array length is often stored in a previous parameter or another structure
60 # member and thus needs careful parsing.
62 LOGGER = logging.Logger("vulkan")
63 LOGGER.addHandler(logging.StreamHandler())
65 # Filenames to create.
66 WINE_VULKAN_H = "../../include/wine/vulkan.h"
67 WINE_VULKAN_DRIVER_H = "../../include/wine/vulkan_driver.h"
68 WINE_VULKAN_LOADER_SPEC = "../vulkan-1/vulkan-1.spec"
69 WINE_VULKAN_SPEC = "winevulkan.spec"
70 WINE_VULKAN_THUNKS_C = "vulkan_thunks.c"
71 WINE_VULKAN_THUNKS_H = "vulkan_thunks.h"
73 # Extension enum values start at a certain offset (EXT_BASE).
74 # Relative to the offset each extension has a block (EXT_BLOCK_SIZE)
76 # Start for a given extension is:
77 # EXT_BASE + (extension_number-1) * EXT_BLOCK_SIZE
81 # In general instance extensions can't be automatically generated
82 # and need custom wrappers due to e.g. win32 / X11 specific code.
83 # List of supported instance extensions.
84 SUPPORTED_INSTANCE_EXTENSIONS = [
85 "VK_KHR_get_physical_device_properties2",
87 "VK_KHR_win32_surface",
90 BLACKLISTED_EXTENSIONS = [
91 # Handling of VK_EXT_debug_report requires some consideration. The win32
92 # loader already provides it for us and it is somewhat usable. . If we add
93 # plumbing down to the native layer, we will get each message twice as we
94 # use 2 loaders (win32+native), but we may get output from the driver.
95 # In any case callback conversion is required.
96 "VK_EXT_debug_report",
97 "VK_EXT_display_control", # Requires VK_EXT_display_surface_counter
98 "VK_EXT_hdr_metadata", # Needs WSI work.
99 "VK_GOOGLE_display_timing",
100 "VK_KHR_display", # Needs WSI work.
101 "VK_KHR_external_fence_fd",
102 "VK_KHR_external_fence_win32",
103 "VK_KHR_external_memory",
104 "VK_KHR_external_semaphore",
105 # Relates to external_semaphore and needs type conversions in bitflags.
106 "VK_KHR_external_semaphore_capabilities",
107 "VK_KHR_shared_presentable_image", # Needs WSI work.
108 "VK_NV_external_memory_win32"
111 # The Vulkan loader provides entry-points for core functionality and important
112 # extensions. Based on vulkan-1.def this amounts to WSI extensions on 1.0.51.
115 "VK_KHR_display_swapchain",
118 "VK_KHR_win32_surface"
121 # Functions part of our winevulkan graphics driver interface.
122 # DRIVER_VERSION should be bumped on any change to driver interface
123 # in FUNCTION_OVERRIDES
126 # Table of functions for which we have a special implementation.
127 # These are regular device / instance functions for which we need
128 # to do more work compared to a regular thunk or because they are
129 # part of the driver interface.
130 # - dispatch set whether we need a function pointer in the device
131 # / instance dispatch table.
132 # - driver sets whether the API is part of the driver interface.
133 # - thunk sets whether to create a thunk in vulkan_thunks.c.
134 FUNCTION_OVERRIDES = {
136 "vkCreateInstance" : {"dispatch" : False, "driver" : True, "thunk" : False},
137 "vkEnumerateInstanceExtensionProperties" : {"dispatch" : False, "driver" : True, "thunk" : False},
138 "vkGetInstanceProcAddr": {"dispatch" : False, "driver" : True, "thunk" : False},
141 "vkCreateDevice" : {"dispatch" : True, "driver" : False, "thunk" : False},
142 "vkDestroyInstance" : {"dispatch" : False, "driver" : True, "thunk" : False },
143 "vkEnumerateDeviceExtensionProperties" : {"dispatch" : True, "driver" : False, "thunk" : False},
144 "vkEnumeratePhysicalDevices" : {"dispatch" : True, "driver" : False, "thunk" : False},
147 "vkAllocateCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : False},
148 "vkCmdExecuteCommands" : {"dispatch" : True, "driver" : False, "thunk" : False},
149 "vkDestroyDevice" : {"dispatch" : True, "driver" : False, "thunk" : False},
150 "vkFreeCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : False},
151 "vkGetDeviceProcAddr" : {"dispatch" : False, "driver" : True, "thunk" : False},
152 "vkGetDeviceQueue" : {"dispatch": True, "driver" : False, "thunk" : False},
153 "vkQueueSubmit" : {"dispatch": True, "driver" : False, "thunk" : False},
156 "vkDestroySurfaceKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
157 "vkGetPhysicalDeviceSurfaceSupportKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
158 "vkGetPhysicalDeviceSurfaceCapabilitiesKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
159 "vkGetPhysicalDeviceSurfaceFormatsKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
160 "vkGetPhysicalDeviceSurfacePresentModesKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
162 # VK_KHR_win32_surface
163 "vkCreateWin32SurfaceKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
164 "vkGetPhysicalDeviceWin32PresentationSupportKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
167 "vkAcquireNextImageKHR": {"dispatch" : True, "driver" : True, "thunk" : True},
168 "vkCreateSwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
169 "vkDestroySwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
170 "vkGetSwapchainImagesKHR": {"dispatch" : True, "driver" : True, "thunk" : True},
171 "vkQueuePresentKHR": {"dispatch" : True, "driver" : True, "thunk" : True},
175 class Direction(Enum):
176 """ Parameter direction: input, output, input_output. """
182 class VkBaseType(object):
183 def __init__(self, name, _type, requires=None):
184 """ Vulkan base type class.
186 VkBaseType is mostly used by Vulkan to define its own
187 base types like VkFlags through typedef out of e.g. uint32_t.
190 name (:obj:'str'): Name of the base type.
191 _type (:obj:'str'): Underlaying type
192 requires (:obj:'str', optional): Other types required.
193 Often bitmask values pull in a *FlagBits type.
197 self.requires = requires
198 self.required = False
200 def definition(self):
201 text = "typedef {0} {1};\n".format(self.type, self.name)
205 class VkConstant(object):
206 def __init__(self, name, value):
210 def definition(self):
211 text = "#define {0} {1}\n".format(self.name, self.value)
215 class VkDefine(object):
216 def __init__(self, name, value):
221 def from_xml(define):
222 name_elem = define.find("name")
224 if name_elem is None:
225 # <type category="define" name="some_name">some_value</type>
226 # At the time of writing there is only 1 define of this category
227 # 'VK_DEFINE_NON_DISPATCHABLE_HANDLE'.
228 name = define.attrib.get("name")
230 # We override behavior of VK_DEFINE_NON_DISPATCHABLE handle as the default
231 # definition various between 64-bit (uses pointers) and 32-bit (uses uint64_t).
232 # This complicates TRACEs in the thunks, so just use uint64_t.
233 if name == "VK_DEFINE_NON_DISPATCHABLE_HANDLE":
234 value = "#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object;"
237 return VkDefine(name, value)
239 # With a name element the structure is like:
240 # <type category="define"><name>some_name</name>some_value</type>
241 name = name_elem.text
243 # VK_API_VERSION is a deprecated constant and we don't really want to parse it or generate
244 # code for it. However the vk.xml feature section still references it.
245 if name == "VK_API_VERSION":
246 return VkDefine(name, "")
248 # The body of the define is basically unstructured C code. It is not meant for easy parsing.
249 # Some lines contain deprecated values or comments, which we try to filter out.
251 for line in define.text.splitlines():
252 # Skip comments or deprecated values.
259 if child.tail is not None:
262 return VkDefine(name, value.rstrip(' '))
264 def definition(self):
265 if self.value is None:
268 # Nothing to do as the value was already put in the right form during parsing.
269 return "{0}\n".format(self.value)
272 class VkEnum(object):
273 def __init__(self, name, values):
276 self.required = False
280 name = enum.attrib.get("name")
283 for v in enum.findall("enum"):
284 # Value is either a value or a bitpos, only one can exist.
285 value = v.attrib.get("value")
288 value = 1 << int(v.attrib.get("bitpos"))
289 values.append(VkEnumValue(v.attrib.get("name"), value, hex=True))
291 # Some values are in hex form. We want to preserve the hex representation
292 # at least when we convert back to a string. Internally we want to use int.
294 values.append(VkEnumValue(v.attrib.get("name"), int(value, 0), hex=True))
296 values.append(VkEnumValue(v.attrib.get("name"), int(value, 0)))
298 # vulkan.h contains a *_MAX_ENUM value set to 32-bit at the time of writing,
299 # which is to prepare for extensions as they can add values and hence affect
300 # the size definition.
301 max_name = re.sub(r'([0-9a-z_])([A-Z0-9])',r'\1_\2',name).upper() + "_MAX_ENUM"
302 values.append(VkEnumValue(max_name, 0x7fffffff, hex=True))
304 return VkEnum(name, values)
306 def add(self, value):
307 """ Add a value to enum. """
308 self.values.append(value)
310 def definition(self):
311 text = "typedef enum {0}\n{{\n".format(self.name)
313 # Print values sorted, values can have been added in a random order.
314 values = sorted(self.values, key=lambda value: value.value)
316 text += " {0},\n".format(value.definition())
317 text += "}} {0};\n\n".format(self.name)
321 class VkEnumValue(object):
322 def __init__(self, name, value, hex=False):
328 return "{0}={1}".format(self.name, self.value)
330 def definition(self):
331 """ Convert to text definition e.g. VK_FOO = 1 """
333 # Hex is commonly used for FlagBits and sometimes within
334 # a non-FlagBits enum for a bitmask value as well.
336 return "{0} = 0x{1:08x}".format(self.name, self.value)
338 return "{0} = {1}".format(self.name, self.value)
341 class VkFunction(object):
342 def __init__(self, _type=None, name=None, params=[], extension=None):
343 self.extension = extension
348 # For some functions we need some extra metadata from FUNCTION_OVERRIDES.
349 func_info = FUNCTION_OVERRIDES.get(self.name, None)
350 self.dispatch = func_info["dispatch"] if func_info is not None else True
351 self.driver = func_info["driver"] if func_info is not None else False
352 self.thunk_needed = func_info["thunk"] if func_info is not None else True
354 # Required is set while parsing which APIs and types are required
355 # and is used by the code generation.
356 self.required = False
359 def from_xml(command, types):
360 proto = command.find("proto")
362 func_name = proto.find("name").text
363 func_type = proto.find("type").text
366 for param in command.findall("param"):
367 vk_param = VkParam.from_xml(param, types)
368 params.append(vk_param)
370 return VkFunction(_type=func_type, name=func_name, params=params)
372 def get_conversions(self):
373 """ Get a list of conversion functions required for this function if any.
374 Parameters which are structures may require conversion between win32
375 and the host platform. This function returns a list of conversions
380 for param in self.params:
381 convs = param.get_conversions()
382 if convs is not None:
383 conversions.extend(convs)
387 def is_core_func(self):
388 """ Returns whether the function is a Vulkan core function.
389 Core functions are APIs defined by the Vulkan spec to be part of the
390 Core API as well as several KHR WSI extensions.
393 if self.extension is None:
396 if self.extension in CORE_EXTENSIONS:
401 def is_device_func(self):
402 # If none of the other, it must be a device function
403 return not self.is_global_func() and not self.is_instance_func()
405 def is_driver_func(self):
406 """ Returns if function is part of Wine driver interface. """
409 def is_global_func(self):
410 # Treat vkGetInstanceProcAddr as a global function as it
411 # can operate with NULL for vkInstance.
412 if self.name == "vkGetInstanceProcAddr":
414 # Global functions are not passed a dispatchable object.
415 elif self.params[0].is_dispatchable():
419 def is_instance_func(self):
420 # Instance functions are passed VkInstance or VkPhysicalDevice.
421 if self.params[0].type in ["VkInstance", "VkPhysicalDevice"]:
425 def is_required(self):
428 def needs_conversion(self):
429 """ Check if the function needs any input/output type conversion.
430 Functions need input/output conversion if struct parameters have
431 alignment differences between Win32 and Linux 32-bit.
434 for p in self.params:
435 if p.needs_conversion():
436 LOGGER.debug("Parameter {0} to {1} requires conversion".format(p.name, self.name))
441 def needs_dispatch(self):
444 def needs_thunk(self):
445 return self.thunk_needed
447 def pfn(self, prefix="p", call_conv=None, conv=False):
448 """ Create function pointer. """
451 pfn = "{0} ({1} *{2}_{3})(".format(self.type, call_conv, prefix, self.name)
453 pfn = "{0} (*{1}_{2})(".format(self.type, prefix, self.name)
455 for i, param in enumerate(self.params):
457 pfn += param.const + " "
460 if conv and param.needs_conversion():
463 if param.is_pointer():
464 pfn += " " + param.pointer
466 if param.array_len is not None:
467 pfn += "[{0}]".format(param.array_len)
469 if i < len(self.params) - 1:
474 def prototype(self, call_conv=None, prefix=None, postfix=None):
475 """ Generate prototype for given function.
478 call_conv (str, optional): calling convention e.g. WINAPI
479 prefix (str, optional): prefix to append prior to function name e.g. vkFoo -> wine_vkFoo
480 postfix (str, optional): text to append after function name but prior to semicolon e.g. DECLSPEC_HIDDEN
483 proto = "{0}".format(self.type)
485 if call_conv is not None:
486 proto += " {0}".format(call_conv)
488 if prefix is not None:
489 proto += " {0}{1}(".format(prefix, self.name)
491 proto += " {0}(".format(self.name)
493 # Add all the parameters.
494 proto += ", ".join([p.definition() for p in self.params])
496 if postfix is not None:
497 proto += ") {0}".format(postfix)
504 body = " {0}".format(self.trace())
506 params = ", ".join([p.variable(conv=False) for p in self.params])
508 # Call the native Vulkan function.
509 if self.type == "void":
510 body += " {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
512 body += " return {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
516 def body_conversion(self):
519 # Declare a variable to hold the result for non-void functions.
520 if self.type != "void":
521 body += " {0} result;\n".format(self.type)
523 # Declare any tmp parameters for conversion.
524 for p in self.params:
525 if not p.needs_conversion():
528 if p.is_dynamic_array():
529 body += " {0}_host *{1}_host;\n".format(p.type, p.name)
531 body += " {0}_host {1}_host;\n".format(p.type, p.name)
533 body += " {0}\n".format(self.trace())
535 # Call any win_to_host conversion calls.
536 for p in self.params:
537 if not p.needs_input_conversion():
540 body += p.copy(Direction.INPUT)
542 # Build list of parameters containing converted and non-converted parameters.
543 # The param itself knows if conversion is needed and applies it when we set conv=True.
544 params = ", ".join([p.variable(conv=True) for p in self.params])
546 # Call the native Vulkan function.
547 if self.type == "void":
548 body += " {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
550 body += " result = {0}.p_{1}({2});\n".format(self.params[0].dispatch_table(), self.name, params)
554 # Call any host_to_win conversion calls.
555 for p in self.params:
556 if not p.needs_output_conversion():
559 body += p.copy(Direction.OUTPUT)
561 # Perform any required cleanups. Most of these are for array functions.
562 for p in self.params:
563 if not p.needs_free():
568 # Finally return the result.
569 if self.type != "void":
570 body += " return result;\n"
574 def spec(self, prefix=None, symbol=None):
575 """ Generate spec file entry for this function.
578 prefix (str, optional): prefix to prepend to entry point name.
579 symbol (str, optional): allows overriding the name of the function implementing the entry point.
583 params = " ".join([p.spec() for p in self.params])
584 if prefix is not None:
585 spec += "@ stdcall {0}{1}({2})".format(prefix, self.name, params)
587 spec += "@ stdcall {0}({1})".format(self.name, params)
589 if symbol is not None:
595 def stub(self, call_conv=None, prefix=None):
596 stub = self.prototype(call_conv=call_conv, prefix=prefix)
598 stub += " {0}".format(self.trace(message="stub: ", trace_func="FIXME"))
600 if self.type == "VkResult":
601 stub += " return VK_ERROR_OUT_OF_HOST_MEMORY;\n"
602 elif self.type == "VkBool32":
603 stub += " return VK_FALSE;\n"
604 elif self.type == "PFN_vkVoidFunction":
605 stub += " return NULL;\n"
610 def thunk(self, call_conv=None, prefix=None):
611 thunk = self.prototype(call_conv=call_conv, prefix=prefix)
614 if self.needs_conversion():
615 thunk += "#if defined(USE_STRUCT_CONVERSION)\n"
616 thunk += self.body_conversion()
626 def trace(self, message=None, trace_func=None):
627 """ Create a trace string including all parameters.
630 message (str, optional): text to print at start of trace message e.g. 'stub: '
631 trace_func (str, optional): used to override trace function e.g. FIXME, printf, etcetera.
633 if trace_func is not None:
634 trace = "{0}(\"".format(trace_func)
638 if message is not None:
641 # First loop is for all the format strings.
642 trace += ", ".join([p.format_string() for p in self.params])
645 # Second loop for parameter names and optional conversions.
646 for param in self.params:
647 if param.format_conv is not None:
648 trace += ", " + param.format_conv.format(param.name)
650 trace += ", {0}".format(param.name)
656 class VkFunctionPointer(object):
657 def __init__(self, _type, name, members):
659 self.members = members
661 self.required = False
664 def from_xml(funcpointer):
668 for t in funcpointer.findall("type"):
670 # <type>void</type>* pUserData,
671 # Parsing of the tail (anything past </type>) is tricky since there
672 # can be other data on the next line like: const <type>int</type>..
675 lines = t.tail.split(",\n")
676 if lines[0][0] == "*":
678 name = lines[0][1:].strip()
681 name = lines[0].strip()
683 # Filter out ); if it is contained.
684 name = name.partition(");")[0]
686 # If tail encompasses multiple lines, assign the second line to begin
689 begin = lines[1].strip()
693 members.append(VkMember(const=const, _type=_type, pointer=pointer, name=name))
695 _type = funcpointer.text
696 name = funcpointer.find("name").text
697 return VkFunctionPointer(_type, name, members)
699 def definition(self):
700 text = "{0} {1})(\n".format(self.type, self.name)
703 if len(self.members) > 0:
704 for m in self.members:
706 text += " " + m.definition()
709 text += ",\n " + m.definition()
711 # Just make the compiler happy by adding a void parameter.
717 class VkHandle(object):
718 def __init__(self, name, _type, parent):
722 self.required = False
725 def from_xml(handle):
726 name = handle.find("name").text
727 _type = handle.find("type").text
728 parent = handle.attrib.get("parent") # Most objects have a parent e.g. VkQueue has VkDevice.
729 return VkHandle(name, _type, parent)
731 def dispatch_table(self):
732 if not self.is_dispatchable():
735 if self.parent is None:
736 # Should only happen for VkInstance
738 elif self.name == "VkDevice":
739 # VkDevice has VkInstance as a parent, but has its own dispatch table.
741 elif self.parent in ["VkInstance", "VkPhysicalDevice"]:
742 return "instance->funcs"
743 elif self.parent in ["VkDevice", "VkCommandPool"]:
744 return "device->funcs"
746 LOGGER.error("Unhandled dispatchable parent: {0}".format(self.parent))
748 def definition(self):
749 """ Generates handle definition e.g. VK_DEFINE_HANDLE(vkInstance) """
750 return "{0}({1})\n".format(self.type, self.name)
752 def is_dispatchable(self):
753 """ Some handles like VkInstance, VkDevice are dispatchable objects,
754 which means they contain a dispatch table of function pointers.
756 return self.type == "VK_DEFINE_HANDLE"
758 def native_handle(self):
759 """ Provide access to the native handle of a dispatchable object.
761 Dispatchable objects wrap an underlying 'native' object.
762 This method provides access to the native object.
764 if not self.is_dispatchable():
767 if self.name == "VkCommandBuffer":
768 return "command_buffer"
769 elif self.name == "VkDevice":
771 elif self.name == "VkInstance":
773 elif self.name == "VkPhysicalDevice":
775 elif self.name == "VkQueue":
778 LOGGER.error("Unhandled native handle for: {0}".format(self.name))
781 class VkMember(object):
782 def __init__(self, const=None, _type=None, pointer=None, name=None, array_len=None, dyn_array_len=None, optional=False,
783 extension_structs=None):
786 self.pointer = pointer
788 self.type_info = None
789 self.array_len = array_len
790 self.dyn_array_len = dyn_array_len
791 self.optional = optional
792 self.extension_structs = extension_structs
794 def __eq__(self, other):
795 """ Compare member based on name against a string.
797 This method is for convenience by VkStruct, which holds a number of members and needs quick checking
798 if certain members exist.
801 if self.name == other:
807 return "{0} {1} {2} {3} {4} {5}".format(self.const, self.type, self.pointer, self.name, self.array_len,
811 def from_xml(member):
812 """ Helper function for parsing a member tag within a struct or union. """
814 name_elem = member.find("name")
815 type_elem = member.find("type")
817 const = member.text.strip() if member.text else None
822 if type_elem is not None:
823 member_type = type_elem.text
824 if type_elem.tail is not None:
825 pointer = type_elem.tail.strip() if type_elem.tail.strip() != "" else None
827 # Name of other member within, which stores the number of
828 # elements pointed to be by this member.
829 dyn_array_len = member.get("len", None)
831 if "validextensionstructs" in member.attrib:
832 extension_structs = member.get("validextensionstructs").split(",")
834 extension_structs = None
836 # Some members are optional, which is important for conversion code e.g. not dereference NULL pointer.
837 optional = True if member.get("optional") else False
839 # Usually we need to allocate memory for dynamic arrays. We need to do the same in a few other cases
840 # like for VkCommandBufferBeginInfo.pInheritanceInfo. Just threat such cases as dynamic arrays of
841 # size 1 to simplify code generation.
842 if dyn_array_len is None and pointer is not None:
845 # Some members are arrays, attempt to parse these. Formats include:
846 # <member><type>char</type><name>extensionName</name>[<enum>VK_MAX_EXTENSION_NAME_SIZE</enum>]</member>
847 # <member><type>uint32_t</type><name>foo</name>[4]</member>
848 if name_elem.tail and name_elem.tail[0] == '[':
849 LOGGER.debug("Found array type")
850 enum_elem = member.find("enum")
851 if enum_elem is not None:
852 array_len = enum_elem.text
854 # Remove brackets around length
855 array_len = name_elem.tail.strip("[]")
857 return VkMember(const=const, _type=member_type, pointer=pointer, name=name_elem.text, array_len=array_len,
858 dyn_array_len=dyn_array_len, optional=optional, extension_structs=extension_structs)
860 def copy(self, input, output, direction):
861 """ Helper method for use by conversion logic to generate a C-code statement to copy this member. """
863 if self.needs_conversion():
864 if self.is_dynamic_array():
865 if direction == Direction.OUTPUT:
866 LOGGER.warn("TODO: implement copying of returnedonly dynamic array for {0}.{1}".format(self.type, self.name))
868 # Array length is either a variable name (string) or an int.
869 count = self.dyn_array_len if isinstance(self.dyn_array_len, int) else "{0}{1}".format(input, self.dyn_array_len)
870 return "{0}{1} = convert_{2}_array_win_to_host({3}{1}, {4});\n".format(output, self.name, self.type, input, count)
871 elif self.is_static_array():
872 count = self.array_len
873 if direction == Direction.OUTPUT:
874 # Needed by VkMemoryHeap.memoryHeaps
875 return "convert_{0}_static_array_host_to_win({2}{1}, {3}{1}, {4});\n".format(self.type, self.name, input, output, count)
877 # Nothing needed this yet.
878 LOGGER.warn("TODO: implement copying of static array for {0}.{1}".format(self.type, self.name))
880 if direction == Direction.OUTPUT:
881 return "convert_{0}_host_to_win(&{2}{1}, &{3}{1});\n".format(self.type, self.name, input, output)
883 return "convert_{0}_win_to_host(&{2}{1}, &{3}{1});\n".format(self.type, self.name, input, output)
884 elif self.is_static_array():
885 bytes_count = "{0} * sizeof({1})".format(self.array_len, self.type)
886 return "memcpy({0}{1}, {2}{1}, {3});\n".format(output, self.name, input, bytes_count)
888 return "{0}{1} = {2}{1};\n".format(output, self.name, input)
890 def definition(self, align=False, conv=False):
891 """ Generate prototype for given function.
894 align (bool, optional): Enable alignment if a type needs it. This adds WINE_VK_ALIGN(8) to a member.
895 conv (bool, optional): Enable conversion if a type needs it. This appends '_host' to the name.
902 if conv and self.is_struct():
903 text += "{0}_host".format(self.type)
907 if self.is_pointer():
908 text += " {0}{1}".format(self.pointer, self.name)
910 if align and self.needs_alignment():
911 text += " WINE_VK_ALIGN(8) " + self.name
913 text += " " + self.name
915 if self.is_static_array():
916 text += "[{0}]".format(self.array_len)
920 def get_conversions(self):
921 """ Return any conversion description for this member and its children when conversion is needed. """
923 # Check if we need conversion either for this member itself or for any child members
924 # in case member represents a struct.
925 if not self.needs_conversion():
930 # Collect any conversion for any member structs.
931 struct = self.type_info["data"]
933 if m.needs_conversion():
934 conversions.extend(m.get_conversions())
936 struct = self.type_info["data"]
937 direction = Direction.OUTPUT if struct.returnedonly else Direction.INPUT
938 if self.is_dynamic_array():
939 conversions.append(ConversionFunction(False, True, direction, struct))
940 elif self.is_static_array():
941 conversions.append(ConversionFunction(True, False, direction, struct))
943 conversions.append(ConversionFunction(False, False, direction, struct))
945 if self.needs_free():
946 conversions.append(FreeFunction(self.is_dynamic_array(), struct))
951 return self.const is not None
953 def is_dynamic_array(self):
954 """ Returns if the member is an array element.
955 Vulkan uses this for dynamically sized arrays for which
956 there is a 'count' parameter.
958 return self.dyn_array_len is not None
961 return self.type_info["category"] == "handle"
963 def is_pointer(self):
964 return self.pointer is not None
966 def is_static_array(self):
967 """ Returns if the member is an array.
968 Vulkan uses this often for fixed size arrays in which the
969 length is part of the member.
971 return self.array_len is not None
974 return self.type_info["category"] == "struct"
977 return self.type_info["category"] == "union"
979 def needs_alignment(self):
980 """ Check if this member needs alignment for 64-bit data.
981 Various structures need alignment on 64-bit variables due
982 to compiler differences on 32-bit between Win32 and Linux.
985 if self.is_pointer():
987 elif self.type == "size_t":
989 elif self.type in ["uint64_t", "VkDeviceSize"]:
991 elif self.is_struct():
992 struct = self.type_info["data"]
993 return struct.needs_alignment()
994 elif self.is_handle():
995 # Dispatchable handles are pointers to objects, while
996 # non-dispatchable are uint64_t and hence need alignment.
997 handle = self.type_info["data"]
998 return False if handle.is_dispatchable() else True
1001 def needs_conversion(self):
1002 """ Structures requiring alignment, need conversion between win32 and host. """
1004 if not self.is_struct():
1007 struct = self.type_info["data"]
1008 return struct.needs_conversion()
1010 def needs_free(self):
1011 if not self.needs_conversion():
1014 if self.is_dynamic_array():
1017 # TODO: some non-pointer structs and optional pointer structs may need freeing,
1018 # though none of this type have been encountered yet.
1021 def set_type_info(self, type_info):
1022 """ Helper function to set type information from the type registry.
1023 This is needed, because not all type data is available at time of
1026 self.type_info = type_info
1029 class VkParam(object):
1030 """ Helper class which describes a parameter to a function call. """
1032 def __init__(self, type_info, const=None, pointer=None, name=None, array_len=None, dyn_array_len=None):
1035 self.array_len = array_len
1036 self.dyn_array_len = dyn_array_len
1037 self.pointer = pointer
1038 self.type_info = type_info
1039 self.type = type_info["name"] # For convenience
1040 self.handle = type_info["data"] if type_info["category"] == "handle" else None
1041 self.struct = type_info["data"] if type_info["category"] == "struct" else None
1043 self._set_direction()
1044 self._set_format_string()
1045 self._set_conversions()
1048 return "{0} {1} {2} {3} {4}".format(self.const, self.type, self.pointer, self.name, self.array_len, self.dyn_array_len)
1051 def from_xml(param, types):
1052 """ Helper function to create VkParam from xml. """
1054 # Parameter parsing is slightly tricky. All the data is contained within
1055 # a param tag, but some data is within subtags while others are text
1056 # before or after the type tag.
1058 # <param>const <type>char</type>* <name>pLayerName</name></param>
1060 name_elem = param.find("name")
1062 name = name_elem.text
1063 # Tail contains array length e.g. for blendConstants param of vkSetBlendConstants
1064 if name_elem.tail is not None:
1065 array_len = name_elem.tail.strip("[]")
1067 # Name of other parameter in function prototype, which stores the number of
1068 # elements pointed to be by this parameter.
1069 dyn_array_len = param.get("len", None)
1071 const = param.text.strip() if param.text else None
1072 type_elem = param.find("type")
1073 pointer = type_elem.tail.strip() if type_elem.tail.strip() != "" else None
1075 # Since we have parsed all types before hand, this should not happen.
1076 type_info = types.get(type_elem.text, None)
1077 if type_info is None:
1078 LOGGER.err("type info not found for: {0}".format(type_elem.text))
1080 return VkParam(type_info, const=const, pointer=pointer, name=name, array_len=array_len, dyn_array_len=dyn_array_len)
1082 def _set_conversions(self):
1083 """ Internal helper function to configure any needed conversion functions. """
1085 self.free_func = None
1086 self.input_conv = None
1087 self.output_conv = None
1088 if not self.needs_conversion():
1091 # Input functions require win to host conversion.
1092 if self._direction in [Direction.INPUT, Direction.INPUT_OUTPUT]:
1093 self.input_conv = ConversionFunction(False, self.is_dynamic_array(), Direction.INPUT, self.struct)
1095 # Output functions require host to win conversion.
1096 if self._direction in [Direction.INPUT_OUTPUT, Direction.OUTPUT]:
1097 self.output_conv = ConversionFunction(False, self.is_dynamic_array(), Direction.OUTPUT, self.struct)
1099 # Dynamic arrays, but also some normal structs (e.g. VkCommandBufferBeginInfo) need memory
1100 # allocation and thus some cleanup.
1101 if self.is_dynamic_array() or self.struct.needs_free():
1102 self.free_func = FreeFunction(self.is_dynamic_array(), self.struct)
1104 def _set_direction(self):
1105 """ Internal helper function to set parameter direction (input/output/input_output). """
1107 # The parameter direction needs to be determined from hints in vk.xml like returnedonly,
1108 # parameter constness and other heuristics.
1109 # For now we need to get this right for structures as we need to convert these, we may have
1110 # missed a few other edge cases (e.g. count variables).
1111 # See also https://github.com/KhronosGroup/Vulkan-Docs/issues/610
1113 if not self.is_pointer():
1114 self._direction = Direction.INPUT
1115 elif self.is_const() and self.is_pointer():
1116 self._direction = Direction.INPUT
1117 elif self.is_struct():
1118 if not self.struct.returnedonly:
1119 self._direction = Direction.INPUT
1122 # Returnedonly hints towards output, however in some cases
1123 # it is inputoutput. In particular if pNext / sType exist,
1124 # which are used to link in other structures without having
1125 # to introduce new APIs. E.g. vkGetPhysicalDeviceProperties2KHR.
1126 if "pNext" in self.struct:
1127 self._direction = Direction.INPUT_OUTPUT
1130 self._direction = Direction.OUTPUT
1132 # This should mostly be right. Count variables can be inout, but we don't care about these yet.
1133 self._direction = Direction.OUTPUT
1135 def _set_format_string(self):
1136 """ Internal helper function to be used by constructor to set format string. """
1138 # Determine a format string used by code generation for traces.
1139 # 64-bit types need a conversion function.
1140 self.format_conv = None
1141 if self.is_static_array() or self.is_pointer():
1142 self.format_str = "%p"
1144 if self.type_info["category"] in ["bitmask", "enum"]:
1145 self.format_str = "%#x"
1146 elif self.is_handle():
1147 # We use uint64_t for non-dispatchable handles as opposed to pointers
1148 # for dispatchable handles.
1149 if self.handle.is_dispatchable():
1150 self.format_str = "%p"
1152 self.format_str = "0x%s"
1153 self.format_conv = "wine_dbgstr_longlong({0})"
1154 elif self.type == "float":
1155 self.format_str = "%f"
1156 elif self.type == "int":
1157 self.format_str = "%d"
1158 elif self.type == "int32_t":
1159 self.format_str = "%d"
1160 elif self.type == "size_t":
1161 self.format_str = "0x%s"
1162 self.format_conv = "wine_dbgstr_longlong({0})"
1163 elif self.type in ["uint32_t", "VkBool32"]:
1164 self.format_str = "%u"
1165 elif self.type in ["uint64_t", "VkDeviceSize"]:
1166 self.format_str = "0x%s"
1167 self.format_conv = "wine_dbgstr_longlong({0})"
1168 elif self.type == "HANDLE":
1169 self.format_str = "%p"
1170 elif self.type in ["VisualID", "xcb_visualid_t", "RROutput"]:
1171 # Don't care about Linux specific types.
1172 self.format_str = ""
1174 LOGGER.warn("Unhandled type: {0}".format(self.type_info))
1176 def copy(self, direction):
1177 if direction == Direction.INPUT:
1178 if self.is_dynamic_array():
1179 return " {0}_host = convert_{1}_array_win_to_host({0}, {2});\n".format(self.name, self.type, self.dyn_array_len)
1181 return " convert_{0}_win_to_host({1}, &{1}_host);\n".format(self.type, self.name)
1183 if self.is_dynamic_array():
1184 LOGGER.error("Unimplemented output conversion for: {0}".format(self.name))
1186 return " convert_{0}_host_to_win(&{1}_host, {1});\n".format(self.type, self.name)
1188 def definition(self, postfix=None):
1189 """ Return prototype for the parameter. E.g. 'const char *foo' """
1193 proto += self.const + " "
1197 if self.is_pointer():
1198 proto += " {0}{1}".format(self.pointer, self.name)
1200 proto += " " + self.name
1202 # Allows appending something to the variable name useful for
1203 # win32 to host conversion.
1204 if postfix is not None:
1207 if self.is_static_array():
1208 proto += "[{0}]".format(self.array_len)
1212 def direction(self):
1213 """ Returns parameter direction: input, output, input_output.
1215 Parameter direction in Vulkan is not straight-forward, which this function determines.
1218 return self._direction
1220 def format_string(self):
1221 return self.format_str
1223 def dispatch_table(self):
1224 """ Return functions dispatch table pointer for dispatchable objects. """
1226 if not self.is_dispatchable():
1229 return "{0}->{1}".format(self.name, self.handle.dispatch_table())
1231 def format_string(self):
1232 return self.format_str
1235 if self.is_dynamic_array():
1236 if self.struct.returnedonly:
1237 # For returnedonly, counts is stored in a pointer.
1238 return " free_{0}_array({1}_host, *{2});\n".format(self.type, self.name, self.dyn_array_len)
1240 return " free_{0}_array({1}_host, {2});\n".format(self.type, self.name, self.dyn_array_len)
1242 # We are operating on a single structure. Some structs (very rare) contain dynamic members,
1243 # which would need freeing.
1244 if self.struct.needs_free():
1245 return " free_{0}(&{1}_host);\n".format(self.type, self.name)
1248 def get_conversions(self):
1249 """ Get a list of conversions required for this parameter if any.
1250 Parameters which are structures may require conversion between win32
1251 and the host platform. This function returns a list of conversions
1255 if not self.is_struct():
1258 if not self.needs_conversion():
1263 # Collect any member conversions first, so we can guarantee
1264 # those functions will be defined prior to usage by the
1265 # 'parent' param requiring conversion.
1266 for m in self.struct:
1267 if not m.is_struct():
1270 if not m.needs_conversion():
1273 conversions.extend(m.get_conversions())
1275 # Conversion requirements for the 'parent' parameter.
1276 if self.input_conv is not None:
1277 conversions.append(self.input_conv)
1278 if self.output_conv is not None:
1279 conversions.append(self.output_conv)
1280 if self.free_func is not None:
1281 conversions.append(self.free_func)
1286 return self.const is not None
1288 def is_dynamic_array(self):
1289 return self.dyn_array_len is not None
1291 def is_dispatchable(self):
1292 if not self.is_handle():
1295 return self.handle.is_dispatchable()
1297 def is_handle(self):
1298 return self.handle is not None
1300 def is_pointer(self):
1301 return self.pointer is not None
1303 def is_static_array(self):
1304 return self.array_len is not None
1306 def is_struct(self):
1307 return self.struct is not None
1309 def needs_conversion(self):
1310 """ Returns if parameter needs conversion between win32 and host. """
1312 if not self.is_struct():
1315 # VkSparseImageMemoryRequirements is used by vkGetImageSparseMemoryRequirements.
1316 # This function is tricky to wrap, because how to wrap depends on whether
1317 # pSparseMemoryRequirements is NULL or not. Luckily for VkSparseImageMemoryRequirements
1318 # the alignment works out in such a way that no conversion is needed between win32 and Linux.
1319 if self.type == "VkSparseImageMemoryRequirements":
1322 # If a structure needs alignment changes, it means we need to
1323 # perform parameter conversion between win32 and host.
1324 if self.struct.needs_conversion():
1329 def needs_free(self):
1330 return self.free_func is not None
1332 def needs_input_conversion(self):
1333 return self.input_conv is not None
1335 def needs_output_conversion(self):
1336 return self.output_conv is not None
1339 """ Generate spec file entry for this parameter. """
1341 if self.type_info["category"] in ["bitmask", "enum"]:
1343 if self.is_pointer() and self.type == "char":
1345 if self.is_dispatchable() or self.is_pointer() or self.is_static_array():
1347 if self.is_handle() and not self.is_dispatchable():
1349 if self.type == "float":
1351 if self.type in ["int", "int32_t", "size_t", "uint32_t", "VkBool32"]:
1353 if self.type in ["uint64_t", "VkDeviceSize"]:
1356 LOGGER.error("Unhandled spec conversion for type: {0}".format(self.type))
1358 def variable(self, conv=False):
1359 """ Returns 'glue' code during generation of a function call on how to access the variable.
1360 This function handles various scenarios such as 'unwrapping' if dispatchable objects and
1361 renaming of parameters in case of win32 -> host conversion.
1364 conv (bool, optional): Enable conversion if the param needs it. This appends '_host' to the name.
1367 # Hack until we enable allocation callbacks from ICD to application. These are a joy
1368 # to enable one day, because of calling convention conversion.
1369 if "VkAllocationCallbacks" in self.type:
1370 LOGGER.debug("TODO: setting NULL VkAllocationCallbacks for {0}".format(self.name))
1373 # Dispatchable objects wrap the native handle. For thunk generation we
1374 # need to pass the native handle to the native Vulkan calls.
1375 if self.is_dispatchable():
1376 return "{0}->{1}".format(self.name, self.handle.native_handle())
1377 elif conv and self.needs_conversion():
1378 if self.is_dynamic_array():
1379 return "{0}_host".format(self.name)
1381 return "&{0}_host".format(self.name)
1386 class VkStruct(Sequence):
1387 """ Class which represents the type union and struct. """
1389 def __init__(self, name, members, returnedonly, union=False):
1391 self.members = members
1392 self.returnedonly = returnedonly
1393 self.required = False
1395 self.type_info = None # To be set later.
1397 def __getitem__(self, i):
1398 return self.members[i]
1401 return len(self.members)
1404 def from_xml(struct):
1405 # Unions and structs are the same parsing wise, but we need to
1406 # know which one we are dealing with later on for code generation.
1407 union = True if struct.attrib["category"] == "union" else False
1409 name = struct.attrib.get("name", None)
1411 # 'Output' structures for which data is filled in by the API are
1412 # marked as 'returnedonly'.
1413 returnedonly = True if struct.attrib.get("returnedonly") else False
1416 for member in struct.findall("member"):
1417 vk_member = VkMember.from_xml(member)
1418 members.append(vk_member)
1420 return VkStruct(name, members, returnedonly, union=union)
1423 def decouple_structs(structs):
1424 """ Helper function which decouples a list of structs.
1425 Structures often depend on other structures. To make the C compiler
1426 happy we need to define 'substructures' first. This function analyzes
1427 the list of structures and reorders them in such a way that they are
1431 tmp_structs = list(structs) # Don't modify the original structures.
1432 decoupled_structs = []
1434 while (len(tmp_structs) > 0):
1435 for struct in tmp_structs:
1438 if not struct.required:
1439 tmp_structs.remove(struct)
1443 if not (m.is_struct() or m.is_union()):
1447 # Check if a struct we depend on has already been defined.
1448 for s in decoupled_structs:
1449 if s.name == m.type:
1454 # Check if the struct we depend on is even in the list of structs.
1455 # If found now, it means we haven't met all dependencies before we
1456 # can operate on the current struct.
1457 # When generating 'host' structs we may not be able to find a struct
1458 # as the list would only contain the structs requiring conversion.
1459 for s in tmp_structs:
1460 if s.name == m.type:
1464 if dependends == False:
1465 decoupled_structs.append(struct)
1466 tmp_structs.remove(struct)
1468 return decoupled_structs
1470 def definition(self, align=False, conv=False, postfix=None):
1471 """ Convert structure to textual definition.
1474 align (bool, optional): enable alignment to 64-bit for win32 struct compatibility.
1475 conv (bool, optional): enable struct conversion if the struct needs it.
1476 postfix (str, optional): text to append to end of struct name, useful for struct renaming.
1480 text = "typedef union {0}".format(self.name)
1482 text = "typedef struct {0}".format(self.name)
1484 if postfix is not None:
1490 if align and m.needs_alignment():
1491 text += " {0};\n".format(m.definition(align=align))
1492 elif conv and m.needs_conversion():
1493 text += " {0};\n".format(m.definition(conv=conv))
1495 text += " {0};\n".format(m.definition())
1497 if postfix is not None:
1498 text += "}} {0}{1};\n\n".format(self.name, postfix)
1500 text += "}} {0};\n\n".format(self.name)
1503 def needs_alignment(self):
1504 """ Check if structure needs alignment for 64-bit data.
1505 Various structures need alignment on 64-bit variables due
1506 to compiler differences on 32-bit between Win32 and Linux.
1509 for m in self.members:
1510 if m.needs_alignment():
1514 def needs_conversion(self):
1515 """ Returns if struct members needs conversion between win32 and host.
1516 Structures need conversion if they contain members requiring alignment
1517 or if they include other structures which need alignment.
1520 if self.needs_alignment():
1523 for m in self.members:
1524 if m.needs_conversion():
1528 def needs_free(self):
1529 """ Check if any struct member needs some memory freeing."""
1531 for m in self.members:
1539 def set_type_info(self, types):
1540 """ Helper function to set type information from the type registry.
1541 This is needed, because not all type data is available at time of
1544 for m in self.members:
1545 type_info = types[m.type]
1546 m.set_type_info(type_info)
1549 class ConversionFunction(object):
1550 def __init__(self, array, dyn_array, direction, struct):
1552 self.direction = direction
1553 self.dyn_array = dyn_array
1554 self.struct = struct
1555 self.type = struct.name
1559 def __eq__(self, other):
1560 if self.name != other.name:
1565 def _generate_array_conversion_func(self):
1566 """ Helper function for generating a conversion function for array structs. """
1568 if self.direction == Direction.OUTPUT:
1569 params = ["const {0}_host *in".format(self.type), "uint32_t count"]
1570 return_type = self.type
1572 params = ["const {0} *in".format(self.type), "uint32_t count"]
1573 return_type = "{0}_host".format(self.type)
1575 # Generate function prototype.
1576 body = "static inline {0} *{1}(".format(return_type, self.name)
1577 body += ", ".join(p for p in params)
1580 body += " {0} *out;\n".format(return_type)
1581 body += " unsigned int i;\n\n"
1582 body += " if (!in) return NULL;\n\n"
1584 body += " out = heap_alloc(count * sizeof(*out));\n"
1586 body += " for (i = 0; i < count; i++)\n"
1589 for m in self.struct:
1590 # TODO: support copying of pNext extension structures!
1591 # Luckily though no extension struct at this point needs conversion.
1592 body += " " + m.copy("in[i].", "out[i].", self.direction)
1595 body += " return out;\n"
1599 def _generate_conversion_func(self):
1600 """ Helper function for generating a conversion function for non-array structs. """
1602 if self.direction == Direction.OUTPUT:
1603 params = ["const {0}_host *in".format(self.type), "{0} *out".format(self.type)]
1605 params = ["const {0} *in".format(self.type), "{0}_host *out".format(self.type)]
1607 body = "static inline void {0}(".format(self.name)
1609 # Generate parameter list
1610 body += ", ".join(p for p in params)
1613 body += " if (!in) return;\n\n"
1615 if self.direction == Direction.INPUT and "pNext" in self.struct and self.struct.returnedonly:
1616 # We are dealing with an input_output parameter. For these we only need to copy
1617 # pNext and sType as the other fields are filled in by the host. We do potentially
1618 # have to iterate over pNext and perform conversions based on switch(sType)!
1619 # Luckily though no extension structs at this point need conversion.
1620 # TODO: support copying of pNext extension structures!
1621 body += " out->pNext = in->pNext;\n"
1622 body += " out->sType = in->sType;\n"
1624 for m in self.struct:
1625 # TODO: support copying of pNext extension structures!
1626 body += " " + m.copy("in->", "out->", self.direction)
1631 def _generate_static_array_conversion_func(self):
1632 """ Helper function for generating a conversion function for array structs. """
1634 if self.direction == Direction.OUTPUT:
1635 params = ["const {0}_host *in".format(self.type), "{0} *out".format(self.type), "uint32_t count"]
1636 return_type = self.type
1638 params = ["const {0} *in".format(self.type), "{0} *out_host".format(self.type), "uint32_t count"]
1639 return_type = "{0}_host".format(self.type)
1641 # Generate function prototype.
1642 body = "static inline void {0}(".format(self.name)
1643 body += ", ".join(p for p in params)
1645 body += " unsigned int i;\n\n"
1646 body += " if (!in) return;\n\n"
1647 body += " for (i = 0; i < count; i++)\n"
1650 for m in self.struct:
1651 # TODO: support copying of pNext extension structures!
1652 body += " " + m.copy("in[i].", "out[i].", self.direction)
1658 def _set_name(self):
1659 if self.direction == Direction.INPUT:
1661 name = "convert_{0}_static_array_win_to_host".format(self.type)
1662 elif self.dyn_array:
1663 name = "convert_{0}_array_win_to_host".format(self.type)
1665 name = "convert_{0}_win_to_host".format(self.type)
1666 else: # Direction.OUTPUT
1668 name = "convert_{0}_static_array_host_to_win".format(self.type)
1669 elif self.dyn_array:
1670 name = "convert_{0}_array_host_to_win".format(self.type)
1672 name = "convert_{0}_host_to_win".format(self.type)
1676 def definition(self):
1678 return self._generate_static_array_conversion_func()
1679 elif self.dyn_array:
1680 return self._generate_array_conversion_func()
1682 return self._generate_conversion_func()
1685 class FreeFunction(object):
1686 def __init__(self, dyn_array, struct):
1687 self.dyn_array = dyn_array
1688 self.struct = struct
1689 self.type = struct.name
1692 self.name = "free_{0}_array".format(self.type)
1694 self.name = "free_{0}".format(self.type)
1696 def __eq__(self, other):
1697 if self.name == other.name:
1702 def _generate_array_free_func(self):
1703 """ Helper function for cleaning up temporary buffers required for array conversions. """
1705 # Generate function prototype.
1706 body = "static inline void {0}({1}_host *in, uint32_t count)\n{{\n".format(self.name, self.type)
1708 # E.g. VkGraphicsPipelineCreateInfo_host needs freeing for pStages.
1709 if self.struct.needs_free():
1710 body += " unsigned int i;\n\n"
1711 body += " if (!in) return;\n\n"
1712 body += " for (i = 0; i < count; i++)\n"
1715 for m in self.struct:
1716 if m.needs_conversion() and m.is_dynamic_array():
1718 # Add a cast to ignore const on conversion structs we allocated ourselves.
1719 body += " free_{0}_array(({0}_host *)in[i].{1}, in[i].{2});\n".format(m.type, m.name, m.dyn_array_len)
1721 body += " free_{0}_array(in[i].{1}, in[i].{2});\n".format(m.type, m.name, m.dyn_array_len)
1722 elif m.needs_conversion():
1723 LOGGER.error("Unhandled conversion for {0}".format(m.name))
1726 body += " if (!in) return;\n\n"
1728 body += " heap_free(in);\n"
1733 def _generate_free_func(self):
1734 # E.g. VkCommandBufferBeginInfo.pInheritanceInfo needs freeing.
1735 if not self.struct.needs_free():
1738 # Generate function prototype.
1739 body = "static inline void {0}({1}_host *in)\n{{\n".format(self.name, self.type)
1741 for m in self.struct:
1742 if m.needs_conversion() and m.is_dynamic_array():
1743 count = m.dyn_array_len if isinstance(m.dyn_array_len, int) else "in->{0}".format(m.dyn_array_len)
1745 # Add a cast to ignore const on conversion structs we allocated ourselves.
1746 body += " free_{0}_array(({0}_host *)in->{1}, {2});\n".format(m.type, m.name, count)
1748 body += " free_{0}_array(in->{1}, {2});\n".format(m.type, m.name, count)
1753 def definition(self):
1755 return self._generate_array_free_func()
1757 # Some structures need freeing too if they contain dynamic arrays.
1758 # E.g. VkCommandBufferBeginInfo
1759 return self._generate_free_func()
1762 class VkGenerator(object):
1763 def __init__(self, registry):
1764 self.registry = registry
1766 # Build a list conversion functions for struct conversion.
1767 self.conversions = []
1768 self.host_structs = []
1769 for func in self.registry.funcs.values():
1770 if not func.is_required():
1773 if not func.needs_conversion():
1776 conversions = func.get_conversions()
1777 for conv in conversions:
1778 # Pull in any conversions for vulkan_thunks.c.
1779 if func.needs_thunk():
1780 # Append if we don't already have this conversion.
1781 if not any(c == conv for c in self.conversions):
1782 self.conversions.append(conv)
1784 # Structs can be used in different ways by different conversions
1785 # e.g. array vs non-array. Just make sure we pull in each struct once.
1786 if not any(s.name == conv.struct.name for s in self.host_structs):
1787 self.host_structs.append(conv.struct)
1789 def generate_thunks_c(self, f, prefix):
1790 f.write("/* Automatically generated from Vulkan vk.xml; DO NOT EDIT! */\n\n")
1792 f.write("#include \"config.h\"\n")
1793 f.write("#include \"wine/port.h\"\n\n")
1795 f.write("#include \"vulkan_private.h\"\n\n")
1797 f.write("WINE_DEFAULT_DEBUG_CHANNEL(vulkan);\n\n")
1799 # Generate any conversion helper functions.
1800 f.write("#if defined(USE_STRUCT_CONVERSION)\n")
1801 for conv in self.conversions:
1802 f.write(conv.definition())
1803 f.write("#endif /* USE_STRUCT_CONVERSION */\n\n")
1805 # Create thunks for instance and device functions.
1806 # Global functions don't go through the thunks.
1807 for vk_func in self.registry.funcs.values():
1808 if not vk_func.is_required():
1811 if vk_func.is_global_func():
1814 if not vk_func.needs_thunk():
1817 # Exports symbols for Core functions.
1818 if not vk_func.is_core_func():
1820 f.write(vk_func.thunk(prefix=prefix, call_conv="WINAPI"))
1822 f.write("static const struct vulkan_func vk_device_dispatch_table[] =\n{\n")
1823 for vk_func in self.registry.device_funcs:
1824 if not vk_func.is_required():
1827 f.write(" {{\"{0}\", &{1}{0}}},\n".format(vk_func.name, prefix))
1830 f.write("static const struct vulkan_func vk_instance_dispatch_table[] =\n{\n")
1831 for vk_func in self.registry.instance_funcs:
1832 if not vk_func.is_required():
1835 f.write(" {{\"{0}\", &{1}{0}}},\n".format(vk_func.name, prefix))
1838 f.write("void *wine_vk_get_device_proc_addr(const char *name)\n")
1840 f.write(" unsigned int i;\n")
1841 f.write(" for (i = 0; i < ARRAY_SIZE(vk_device_dispatch_table); i++)\n")
1843 f.write(" if (strcmp(vk_device_dispatch_table[i].name, name) == 0)\n")
1845 f.write(" TRACE(\"Found name=%s in device table\\n\", debugstr_a(name));\n")
1846 f.write(" return vk_device_dispatch_table[i].func;\n")
1849 f.write(" return NULL;\n")
1852 f.write("void *wine_vk_get_instance_proc_addr(const char *name)\n")
1854 f.write(" unsigned int i;\n")
1855 f.write(" for (i = 0; i < ARRAY_SIZE(vk_instance_dispatch_table); i++)\n")
1857 f.write(" if (strcmp(vk_instance_dispatch_table[i].name, name) == 0)\n")
1859 f.write(" TRACE(\"Found name=%s in instance table\\n\", debugstr_a(name));\n")
1860 f.write(" return vk_instance_dispatch_table[i].func;\n")
1863 f.write(" return NULL;\n")
1866 # Create array of device extensions.
1867 f.write("static const char * const vk_device_extensions[] =\n{\n")
1868 for ext in self.registry.extensions:
1869 if ext["type"] != "device":
1872 f.write(" \"{0}\",\n".format(ext["name"]))
1875 # Create array of instance extensions.
1876 f.write("static const char * const vk_instance_extensions[] =\n{\n")
1877 for ext in self.registry.extensions:
1878 if ext["type"] != "instance":
1881 f.write(" \"{0}\",\n".format(ext["name"]))
1884 f.write("BOOL wine_vk_device_extension_supported(const char *name)\n")
1886 f.write(" unsigned int i;\n")
1887 f.write(" for (i = 0; i < ARRAY_SIZE(vk_device_extensions); i++)\n")
1889 f.write(" if (strcmp(vk_device_extensions[i], name) == 0)\n")
1890 f.write(" return TRUE;\n")
1892 f.write(" return FALSE;\n")
1895 f.write("BOOL wine_vk_instance_extension_supported(const char *name)\n")
1897 f.write(" unsigned int i;\n")
1898 f.write(" for (i = 0; i < ARRAY_SIZE(vk_instance_extensions); i++)\n")
1900 f.write(" if (strcmp(vk_instance_extensions[i], name) == 0)\n")
1901 f.write(" return TRUE;\n")
1903 f.write(" return FALSE;\n")
1906 def generate_thunks_h(self, f, prefix):
1907 f.write("/* Automatically generated from Vulkan vk.xml; DO NOT EDIT! */\n\n")
1909 f.write("#ifndef __WINE_VULKAN_THUNKS_H\n")
1910 f.write("#define __WINE_VULKAN_THUNKS_H\n\n")
1912 # Generate prototypes for device and instance functions requiring a custom implementation.
1913 f.write("/* Functions for which we have custom implementations outside of the thunks. */\n")
1914 for vk_func in self.registry.funcs.values():
1915 if not vk_func.is_required() or vk_func.is_global_func() or vk_func.needs_thunk():
1918 if vk_func.is_core_func():
1919 f.write("{0};\n".format(vk_func.prototype("WINAPI", prefix="wine_")))
1921 f.write("{0};\n".format(vk_func.prototype("WINAPI", prefix="wine_", postfix="DECLSPEC_HIDDEN")))
1924 for struct in self.host_structs:
1925 f.write(struct.definition(align=False, conv=True, postfix="_host"))
1928 f.write("/* For use by vkDevice and children */\n")
1929 f.write("struct vulkan_device_funcs\n{\n")
1930 for vk_func in self.registry.device_funcs:
1931 if not vk_func.is_required():
1934 if not vk_func.needs_dispatch():
1935 LOGGER.debug("skipping {0} in vulkan_device_funcs".format(vk_func.name))
1938 if vk_func.needs_conversion():
1939 f.write("#if defined(USE_STRUCT_CONVERSION)\n")
1940 f.write(" {0};\n".format(vk_func.pfn(conv=True)))
1942 f.write(" {0};\n".format(vk_func.pfn(conv=False)))
1945 f.write(" {0};\n".format(vk_func.pfn(conv=False)))
1948 f.write("/* For use by vkInstance and children */\n")
1949 f.write("struct vulkan_instance_funcs\n{\n")
1950 for vk_func in self.registry.instance_funcs:
1951 if not vk_func.is_required():
1954 if not vk_func.needs_dispatch():
1955 LOGGER.debug("skipping {0} in vulkan_instance_funcs".format(vk_func.name))
1958 if vk_func.needs_conversion():
1959 f.write("#if defined(USE_STRUCT_CONVERSION)\n")
1960 f.write(" {0};\n".format(vk_func.pfn(conv=True)))
1962 f.write(" {0};\n".format(vk_func.pfn(conv=False)))
1965 f.write(" {0};\n".format(vk_func.pfn(conv=False)))
1968 f.write("#define ALL_VK_DEVICE_FUNCS() \\\n")
1970 for vk_func in self.registry.device_funcs:
1971 if not vk_func.is_required():
1974 if not vk_func.needs_dispatch():
1975 LOGGER.debug("skipping {0} in ALL_VK_DEVICE_FUNCS".format(vk_func.name))
1979 f.write(" USE_VK_FUNC({0})".format(vk_func.name))
1982 f.write(" \\\n USE_VK_FUNC({0})".format(vk_func.name))
1985 f.write("#define ALL_VK_INSTANCE_FUNCS() \\\n")
1987 for vk_func in self.registry.instance_funcs:
1988 if not vk_func.is_required():
1991 if not vk_func.needs_dispatch():
1992 LOGGER.debug("skipping {0} in ALL_VK_INSTANCE_FUNCS".format(vk_func.name))
1996 f.write(" USE_VK_FUNC({0})".format(vk_func.name))
1999 f.write(" \\\n USE_VK_FUNC({0})".format(vk_func.name))
2002 f.write("#endif /* __WINE_VULKAN_THUNKS_H */\n")
2004 def generate_vulkan_h(self, f):
2005 f.write("/* Automatically generated from Vulkan vk.xml; DO NOT EDIT! */\n\n")
2006 f.write("#ifndef __WINE_VULKAN_H\n")
2007 f.write("#define __WINE_VULKAN_H\n\n")
2009 f.write("#include <windef.h>\n")
2010 f.write("#include <stdint.h>\n\n")
2012 f.write("#ifndef VKAPI_CALL\n")
2013 f.write("#define VKAPI_CALL __stdcall\n")
2014 f.write("#endif\n\n")
2016 f.write("#ifndef VKAPI_PTR\n")
2017 f.write("#define VKAPI_PTR VKAPI_CALL\n")
2018 f.write("#endif\n\n")
2020 f.write("/* Callers can override WINE_VK_ALIGN if they want 'host' headers. */\n")
2021 f.write("#ifndef WINE_VK_ALIGN\n")
2022 f.write("#define WINE_VK_ALIGN DECLSPEC_ALIGN\n")
2023 f.write("#endif\n\n")
2025 # The overall strategy is to define independent constants and datatypes,
2026 # prior to complex structures and function calls to avoid forward declarations.
2027 for const in self.registry.consts:
2028 # For now just generate things we may not need. The amount of parsing needed
2029 # to get some of the info is tricky as you need to figure out which structure
2030 # references a certain constant.
2031 f.write(const.definition())
2034 for define in self.registry.defines:
2035 f.write(define.definition())
2037 for handle in self.registry.handles:
2039 f.write(handle.definition())
2042 for base_type in self.registry.base_types:
2043 f.write(base_type.definition())
2046 for bitmask in self.registry.bitmasks:
2047 f.write(bitmask.definition())
2050 # Define enums, this includes values for some of the bitmask types as well.
2051 for enum in self.registry.enums.values():
2053 f.write(enum.definition())
2055 for fp in self.registry.funcpointers:
2057 f.write(fp.definition())
2060 # This generates both structures and unions. Since structures
2061 # may depend on other structures/unions, we need a list of
2062 # decoupled structs.
2063 # Note: unions are stored in structs for dependency reasons,
2064 # see comment in parsing section.
2065 structs = VkStruct.decouple_structs(self.registry.structs)
2066 for struct in structs:
2067 LOGGER.debug("Generating struct: {0}".format(struct.name))
2068 f.write(struct.definition(align=True))
2070 for func in self.registry.funcs.values():
2071 if not func.is_required():
2072 LOGGER.debug("Skipping PFN definition for: {0}".format(func.name))
2075 f.write("typedef {0};\n".format(func.pfn(prefix="PFN", call_conv="VKAPI_PTR")))
2078 f.write("#ifndef VK_NO_PROTOTYPES\n")
2079 for func in self.registry.funcs.values():
2080 if not func.is_required():
2081 LOGGER.debug("Skipping API definition for: {0}".format(func.name))
2084 LOGGER.debug("Generating API definition for: {0}".format(func.name))
2085 f.write("{0};\n".format(func.prototype(call_conv="VKAPI_CALL")))
2086 f.write("#endif /* VK_NO_PROTOTYPES */\n\n")
2088 f.write("#endif /* __WINE_VULKAN_H */\n")
2090 def generate_vulkan_driver_h(self, f):
2091 f.write("/* Automatically generated from Vulkan vk.xml; DO NOT EDIT! */\n\n")
2092 f.write("#ifndef __WINE_VULKAN_DRIVER_H\n")
2093 f.write("#define __WINE_VULKAN_DRIVER_H\n\n")
2095 f.write("/* Wine internal vulkan driver version, needs to be bumped upon vulkan_funcs changes. */\n")
2096 f.write("#define WINE_VULKAN_DRIVER_VERSION {0}\n\n".format(DRIVER_VERSION))
2098 f.write("struct vulkan_funcs\n{\n")
2099 f.write(" /* Vulkan global functions. These are the only calls at this point a graphics driver\n")
2100 f.write(" * needs to provide. Other function calls will be provided indirectly by dispatch\n")
2101 f.write(" * tables part of dispatchable Vulkan objects such as VkInstance or vkDevice.\n")
2104 for vk_func in self.registry.funcs.values():
2105 if not vk_func.is_required() or not vk_func.is_driver_func():
2109 # Avoid PFN_vkVoidFunction in driver interface as Vulkan likes to put calling convention
2110 # stuff in there. For simplicity substitute with "void *".
2111 pfn = pfn.replace("PFN_vkVoidFunction", "void *")
2112 f.write(" {0};\n".format(pfn))
2115 f.write("extern const struct vulkan_funcs * CDECL __wine_get_vulkan_driver(HDC hdc, UINT version);\n\n")
2116 f.write("#endif /* __WINE_VULKAN_DRIVER_H */\n")
2118 def generate_vulkan_spec(self, f):
2119 f.write("# Automatically generated from Vulkan vk.xml; DO NOT EDIT!\n\n")
2120 f.write("@ stdcall vk_icdGetInstanceProcAddr(ptr str) wine_vk_icdGetInstanceProcAddr\n")
2121 f.write("@ stdcall vk_icdNegotiateLoaderICDInterfaceVersion(ptr) wine_vk_icdNegotiateLoaderICDInterfaceVersion\n")
2123 # Export symbols for all Vulkan Core functions.
2124 for func in self.registry.funcs.values():
2125 if not func.is_core_func():
2128 # Not an ICD level function.
2129 if func.name == "vkEnumerateInstanceLayerProperties":
2132 # We support all Core functions except for VK_KHR_display* APIs.
2133 # Create stubs for unsupported Core functions.
2134 if func.is_required():
2135 f.write(func.spec(prefix="wine_"))
2137 f.write("@ stub {0}\n".format(func.name))
2139 def generate_vulkan_loader_spec(self, f):
2140 f.write("# Automatically generated from Vulkan vk.xml; DO NOT EDIT!\n\n")
2142 # Export symbols for all Vulkan Core functions.
2143 for func in self.registry.funcs.values():
2144 if not func.is_core_func():
2147 # We support all Core functions except for VK_KHR_display* APIs.
2148 # Create stubs for unsupported Core functions.
2149 if func.is_required():
2150 # Global functions need a custom implementation, except for
2151 # vkCreateInstance, which we can just forward.
2152 if func.is_global_func() and func.name != "vkCreateInstance":
2153 f.write(func.spec())
2155 f.write(func.spec(symbol="winevulkan.wine_" + func.name))
2157 f.write("@ stub {0}\n".format(func.name))
2160 class VkRegistry(object):
2161 def __init__(self, reg_filename):
2162 # Used for storage of type information.
2163 self.base_types = None
2164 self.bitmasks = None
2168 self.funcpointers = None
2172 # We aggregate all types in here for cross-referencing.
2176 # Overall strategy for parsing the registry is to first
2177 # parse all type / function definitions. Then parse
2178 # features and extensions to decide which types / functions
2179 # to actually 'pull in' for code generation. For each type or
2180 # function call we want we set a member 'required' to True.
2181 tree = ET.parse(reg_filename)
2182 root = tree.getroot()
2183 self._parse_enums(root)
2184 self._parse_types(root)
2185 self._parse_commands(root)
2187 # Pull in any required types and functions.
2188 self._parse_features(root)
2189 self._parse_extensions(root)
2191 def _mark_command_required(self, command):
2192 """ Helper function to mark a certain command and the datatypes it needs as required."""
2193 def mark_bitmask_dependencies(bitmask, types):
2194 if bitmask.requires is not None:
2195 types[bitmask.requires]["data"].required = True
2197 def mark_funcpointer_dependencies(fp, types):
2198 for m in fp.members:
2199 type_info = types[m.type]
2201 # Complex types have a matching definition e.g. VkStruct.
2202 # Not needed for base types such as uint32_t.
2203 if "data" in type_info:
2204 types[m.type]["data"].required = True
2206 def mark_struct_dependencies(struct, types):
2208 type_info = types[m.type]
2210 # Complex types have a matching definition e.g. VkStruct.
2211 # Not needed for base types such as uint32_t.
2212 if "data" in type_info:
2213 types[m.type]["data"].required = True
2215 if type_info["category"] == "struct":
2217 mark_struct_dependencies(type_info["data"], types)
2218 elif type_info["category"] == "funcpointer":
2219 mark_funcpointer_dependencies(type_info["data"], types)
2220 elif type_info["category"] == "bitmask":
2221 mark_bitmask_dependencies(type_info["data"], types)
2223 func = self.funcs[command]
2224 func.required = True
2226 # Pull in return type
2227 if func.type != "void":
2228 self.types[func.type]["data"].required = True
2230 # Analyze parameter dependencies and pull in any type needed.
2231 for p in func.params:
2232 type_info = self.types[p.type]
2234 # Check if we are dealing with a complex type e.g. VkEnum, VkStruct and others.
2235 if "data" not in type_info:
2238 # Mark the complex type as required.
2239 type_info["data"].required = True
2240 if type_info["category"] == "struct":
2241 struct = type_info["data"]
2242 mark_struct_dependencies(struct, self.types)
2244 def _parse_commands(self, root):
2245 """ Parse command section containing the Vulkan function calls. """
2247 commands = root.findall("./commands/")
2248 for command in commands:
2249 func = VkFunction.from_xml(command, self.types)
2250 funcs[func.name] = func
2252 # To make life easy for the code generation, separate all function
2253 # calls out in the 3 types of Vulkan functions: device, global and instance.
2257 for func in funcs.values():
2258 if func.is_device_func():
2259 device_funcs.append(func)
2260 elif func.is_global_func():
2261 global_funcs.append(func)
2263 instance_funcs.append(func)
2265 # Sort function lists by name and store them.
2266 self.device_funcs = sorted(device_funcs, key=lambda func: func.name)
2267 self.global_funcs = sorted(global_funcs, key=lambda func: func.name)
2268 self.instance_funcs = sorted(instance_funcs, key=lambda func: func.name)
2270 # The funcs dictionary is used as a convenient way to lookup function
2271 # calls when needed e.g. to adjust member variables.
2272 self.funcs = OrderedDict(sorted(funcs.items()))
2274 def _parse_enums(self, root):
2275 """ Parse enums section or better described as constants section. """
2278 for enum in root.findall("./enums"):
2279 name = enum.attrib.get("name")
2280 _type = enum.attrib.get("type")
2282 if _type in ("enum", "bitmask"):
2283 enums[name] = VkEnum.from_xml(enum)
2285 # If no type is set, we are dealing with API constants.
2287 for value in enum.findall("enum"):
2288 self.consts.append(VkConstant(value.attrib.get("name"), value.attrib.get("value")))
2290 self.enums = OrderedDict(sorted(enums.items()))
2292 def _parse_extensions(self, root):
2293 """ Parse extensions section and pull in any types and commands for this extensioin. """
2295 exts = root.findall("./extensions/extension")
2297 ext_name = ext.attrib["name"]
2299 # Set extension name on any functions calls part of this extension as we
2300 # were not aware of the name during initial parsing.
2301 commands = ext.findall("require/command")
2302 for command in commands:
2303 cmd_name = command.attrib["name"]
2304 self.funcs[cmd_name].extension = ext_name
2306 # Some extensions are not ready or have numbers reserved as a place holder.
2307 if ext.attrib["supported"] == "disabled":
2308 LOGGER.debug("Skipping disabled extension: {0}".format(ext_name))
2311 # Disable highly experimental extensions as the APIs are unstable and can
2312 # change between minor Vulkan revisions until API is final and becomes KHR
2314 if "KHX" in ext_name or "NVX" in ext_name:
2315 LOGGER.debug("Skipping experimental extension: {0}".format(ext_name))
2318 # Instance extensions often require a custom implementation, so filter.
2319 ext_type = ext.attrib["type"]
2320 if ext_type == "instance" and not ext_name in SUPPORTED_INSTANCE_EXTENSIONS:
2321 LOGGER.debug("Skipping instance extension: {0}".format(ext_name))
2324 # We disable some extensions as either we haven't implemented
2325 # support yet or because they are for platforms other than win32.
2326 if ext_name in BLACKLISTED_EXTENSIONS:
2327 LOGGER.debug("Skipping blacklisted extension: {0}".format(ext_name))
2329 elif "requires" in ext.attrib:
2330 # Check if this extension builds on top of another blacklisted
2332 requires = ext.attrib["requires"].split(",")
2333 if len(set(requires).intersection(BLACKLISTED_EXTENSIONS)) > 0:
2336 LOGGER.debug("Loading extension: {0}".format(ext_name))
2338 # Extensions can add enum values to Core / extension enums, so add these.
2339 enums = ext.findall("require/enum")
2340 for enum_elem in enums:
2341 if "bitpos" in enum_elem.keys():
2342 # We need to add an extra value to an existing enum type.
2343 # E.g. VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG to VkFormatFeatureFlagBits.
2344 type_name = enum_elem.attrib["extends"]
2345 enum = self.types[type_name]["data"]
2346 enum.add(VkEnumValue(enum_elem.attrib["name"], 1 << int(enum_elem.attrib["bitpos"]), hex=True))
2347 elif "offset" in enum_elem.keys():
2348 ext_number = int(ext.attrib["number"])
2349 offset = int(enum_elem.attrib["offset"])
2350 value = EXT_BASE + (ext_number - 1) * EXT_BLOCK_SIZE + offset
2352 # Deal with negative values.
2353 direction = enum_elem.attrib.get("dir")
2354 if direction is not None:
2357 type_name = enum_elem.attrib["extends"]
2358 enum = self.types[type_name]["data"]
2359 enum.add(VkEnumValue(enum_elem.attrib["name"], value))
2361 elif "value" in enum_elem.keys():
2362 self.consts.append(VkConstant(enum_elem.attrib.get("name"), enum_elem.attrib.get("value")))
2365 # This seems to be used to pull in constants e.g. VK_MAX_DEVICE_GROUP_KHX
2368 # Store a list with extensions.
2369 ext_info = {"name" : ext_name, "type" : ext_type}
2370 extensions.append(ext_info)
2372 # Pull in any commands we need. We infer types to pull in from the command
2374 for command in commands:
2375 cmd_name = command.attrib["name"]
2376 self._mark_command_required(cmd_name)
2378 # Sort in alphabetical order.
2379 self.extensions = sorted(extensions, key=lambda ext: ext["name"])
2381 def _parse_features(self, root):
2382 """ Parse the feature section, which describes Core commands and types needed. """
2383 requires = root.findall("./feature/require")
2385 for require in requires:
2386 LOGGER.info("Including features for {0}".format(require.attrib.get("comment")))
2388 # Only deal with command. Other values which appear are enum and type for pulling in some
2389 # constants and macros. Tricky to parse, so don't bother right now, we will generate them
2391 name = tag.attrib["name"]
2392 if tag.tag == "command":
2393 self._mark_command_required(name)
2394 elif tag.tag == "enum":
2395 # We could pull in relevant constants here. Unfortunately
2396 # this only gets half of them pulled in as others indirectly
2397 # get pulled in through structures. Constants don't harm us,
2400 elif tag.tag == "type":
2401 # Pull in types which may not have been pulled in through commands.
2403 # Skip pull in for vk_platform.h for now.
2404 if name == "vk_platform":
2407 type_info = self.types[name]
2408 type_info["data"].required = True
2410 def _parse_types(self, root):
2411 """ Parse types section, which contains all data types e.g. structs, typedefs etcetera. """
2412 types = root.findall("./types/type")
2423 type_info["category"] = t.attrib.get("category", None)
2425 if type_info["category"] in ["include"]:
2428 if type_info["category"] == "basetype":
2429 name = t.find("name").text
2430 _type = t.find("type").text
2431 basetype = VkBaseType(name, _type)
2432 base_types.append(basetype)
2433 type_info["data"] = basetype
2435 if type_info["category"] == "bitmask":
2436 name = t.find("name").text
2437 _type = t.find("type").text
2439 # Most bitmasks have a requires attribute used to pull in
2440 # required '*FlagBits" enum.
2441 requires = t.attrib.get("requires")
2442 bitmask = VkBaseType(name, _type, requires=requires)
2443 bitmasks.append(bitmask)
2444 type_info["data"] = bitmask
2446 if type_info["category"] == "define":
2447 name = t.attrib.get("name")
2448 define = VkDefine.from_xml(t)
2449 defines.append(define)
2450 type_info["data"] = define
2452 if type_info["category"] == "enum":
2453 name = t.attrib.get("name")
2454 # The type section only contains enum names, not the actual definition.
2455 # Since we already parsed the enum before, just link it in.
2457 type_info["data"] = self.enums[name]
2458 except KeyError as e:
2459 # Not all enums seem to be defined yet, typically that's for
2460 # ones ending in 'FlagBits' where future extensions may add
2462 type_info["data"] = None
2464 if type_info["category"] == "funcpointer":
2465 funcpointer = VkFunctionPointer.from_xml(t)
2466 funcpointers.append(funcpointer)
2467 type_info["data"] = funcpointer
2469 if type_info["category"] == "handle":
2470 handle = VkHandle.from_xml(t)
2471 handles.append(handle)
2472 type_info["data"] = handle
2474 if type_info["category"] in ["struct", "union"]:
2475 # We store unions among structs as some structs depend
2476 # on unions. The types are very similar in parsing and
2477 # generation anyway. The official Vulkan scripts use
2478 # a similar kind of hack.
2479 struct = VkStruct.from_xml(t)
2480 structs.append(struct)
2481 type_info["data"] = struct
2483 # Name is in general within a name tag else it is an optional
2484 # attribute on the type tag.
2485 name_elem = t.find("name")
2486 if name_elem is not None:
2487 type_info["name"] = name_elem.text
2489 type_info["name"] = t.attrib.get("name", None)
2491 # Store all type data in a shared dictionary, so we can easily
2492 # look up information for a given type. There are no duplicate
2494 self.types[type_info["name"]] = type_info
2496 # We need detailed type information during code generation
2497 # on structs for alignment reasons. Unfortunately structs
2498 # are parsed among other types, so there is no guarantee
2499 # that any types needed have been parsed already, so set
2501 for struct in structs:
2502 struct.set_type_info(self.types)
2504 # Guarantee everything is sorted, so code generation doesn't have
2505 # to deal with this.
2506 self.base_types = sorted(base_types, key=lambda base_type: base_type.name)
2507 self.bitmasks = sorted(bitmasks, key=lambda bitmask: bitmask.name)
2508 self.defines = defines
2509 self.funcpointers = sorted(funcpointers, key=lambda fp: fp.name)
2510 self.handles = sorted(handles, key=lambda handle: handle.name)
2511 self.structs = sorted(structs, key=lambda struct: struct.name)
2515 parser = argparse.ArgumentParser()
2516 parser.add_argument("-v", "--verbose", action="count", default=0, help="increase output verbosity")
2518 args = parser.parse_args()
2519 if args.verbose == 0:
2520 LOGGER.setLevel(logging.WARNING)
2521 elif args.verbose == 1:
2522 LOGGER.setLevel(logging.INFO)
2524 LOGGER.setLevel(logging.DEBUG)
2526 registry = VkRegistry("vk.xml")
2527 generator = VkGenerator(registry)
2529 with open(WINE_VULKAN_H, "w") as f:
2530 generator.generate_vulkan_h(f)
2532 with open(WINE_VULKAN_DRIVER_H, "w") as f:
2533 generator.generate_vulkan_driver_h(f)
2535 with open(WINE_VULKAN_THUNKS_H, "w") as f:
2536 generator.generate_thunks_h(f, "wine_")
2538 with open(WINE_VULKAN_THUNKS_C, "w") as f:
2539 generator.generate_thunks_c(f, "wine_")
2541 with open(WINE_VULKAN_SPEC, "w") as f:
2542 generator.generate_vulkan_spec(f)
2544 with open(WINE_VULKAN_LOADER_SPEC, "w") as f:
2545 generator.generate_vulkan_loader_spec(f)
2547 if __name__ == "__main__":