monado/scripts/generate_vk_helpers.py

403 lines
12 KiB
Python
Raw Normal View History

#!/usr/bin/env python3
# Copyright 2019-2021, Collabora, Ltd.
# SPDX-License-Identifier: BSL-1.0
"""Simple script to update vk_helpers.{c,h}."""
from pathlib import Path
from typing import List, Optional, Tuple
# Each tuple is a function name, followed optionally by one or more conditions
# to test in the preprocessor, which will be wrapped in "defined()"
# if they aren't already. Empty tuples insert a blank line.
DEVICE_FUNCTIONS = [
("vkDestroyDevice",),
("vkDeviceWaitIdle",),
("vkAllocateMemory",),
("vkFreeMemory",),
("vkMapMemory",),
("vkUnmapMemory",),
(),
("vkCreateBuffer",),
("vkDestroyBuffer",),
("vkBindBufferMemory",),
(),
("vkCreateImage",),
("vkDestroyImage",),
("vkBindImageMemory",),
(),
("vkGetBufferMemoryRequirements",),
("vkFlushMappedMemoryRanges",),
("vkGetImageMemoryRequirements",),
("vkGetImageMemoryRequirements2KHR",),
("vkGetImageSubresourceLayout",),
(),
("vkCreateImageView",),
("vkDestroyImageView",),
(),
("vkCreateSampler",),
("vkDestroySampler",),
(),
("vkCreateShaderModule",),
("vkDestroyShaderModule",),
(),
("vkCreateCommandPool",),
("vkDestroyCommandPool",),
(),
("vkAllocateCommandBuffers",),
("vkBeginCommandBuffer",),
("vkCmdPipelineBarrier",),
("vkCmdBeginRenderPass",),
("vkCmdSetScissor",),
("vkCmdSetViewport",),
("vkCmdClearColorImage",),
("vkCmdEndRenderPass",),
("vkCmdBindDescriptorSets",),
("vkCmdBindPipeline",),
("vkCmdBindVertexBuffers",),
("vkCmdBindIndexBuffer",),
("vkCmdDraw",),
("vkCmdDrawIndexed",),
("vkCmdDispatch",),
("vkCmdCopyBuffer",),
("vkCmdCopyBufferToImage",),
("vkCmdCopyImage",),
("vkCmdCopyImageToBuffer",),
("vkEndCommandBuffer",),
("vkFreeCommandBuffers",),
(),
("vkCreateRenderPass",),
("vkDestroyRenderPass",),
(),
("vkCreateFramebuffer",),
("vkDestroyFramebuffer",),
(),
("vkCreatePipelineCache",),
("vkDestroyPipelineCache",),
(),
("vkResetDescriptorPool",),
("vkCreateDescriptorPool",),
("vkDestroyDescriptorPool",),
(),
("vkAllocateDescriptorSets",),
("vkFreeDescriptorSets",),
(),
("vkCreateComputePipelines",),
("vkCreateGraphicsPipelines",),
("vkDestroyPipeline",),
(),
("vkCreatePipelineLayout",),
("vkDestroyPipelineLayout",),
(),
("vkCreateDescriptorSetLayout",),
("vkUpdateDescriptorSets",),
("vkDestroyDescriptorSetLayout",),
(),
("vkGetDeviceQueue",),
("vkQueueSubmit",),
("vkQueueWaitIdle",),
(),
("vkCreateSemaphore",),
("vkSignalSemaphoreKHR", "VK_KHR_timeline_semaphore"),
("vkDestroySemaphore",),
(),
("vkCreateFence",),
("vkWaitForFences",),
("vkGetFenceStatus",),
("vkDestroyFence",),
("vkResetFences",),
(),
("vkCreateSwapchainKHR",),
("vkDestroySwapchainKHR",),
("vkGetSwapchainImagesKHR",),
("vkAcquireNextImageKHR",),
("vkQueuePresentKHR",),
(),
("vkGetMemoryWin32HandleKHR", "VK_USE_PLATFORM_WIN32_KHR"),
("vkImportSemaphoreWin32HandleKHR", "VK_USE_PLATFORM_WIN32_KHR"),
("vkImportFenceWin32HandleKHR", "VK_USE_PLATFORM_WIN32_KHR"),
("vkGetMemoryFdKHR", "!defined(VK_USE_PLATFORM_WIN32_KHR)"),
(),
("vkImportSemaphoreFdKHR", "!defined(VK_USE_PLATFORM_WIN32_KHR)"),
("vkGetSemaphoreFdKHR", "!defined(VK_USE_PLATFORM_WIN32_KHR)"),
(),
("vkImportFenceFdKHR", "!defined(VK_USE_PLATFORM_WIN32_KHR)"),
("vkGetFenceFdKHR", "!defined(VK_USE_PLATFORM_WIN32_KHR)"),
("vkGetMemoryAndroidHardwareBufferANDROID", "VK_USE_PLATFORM_ANDROID_KHR"),
(
"vkGetAndroidHardwareBufferPropertiesANDROID",
"VK_USE_PLATFORM_ANDROID_KHR",
),
(),
("vkGetPastPresentationTimingGOOGLE",),
]
INSTANCE_FUNCTIONS = [
("vkDestroyInstance",),
("vkGetDeviceProcAddr",),
("vkCreateDevice",),
("vkDestroySurfaceKHR",),
(),
("vkCreateDebugReportCallbackEXT",),
("vkDestroyDebugReportCallbackEXT",),
(),
("vkEnumeratePhysicalDevices",),
("vkGetPhysicalDeviceProperties",),
("vkGetPhysicalDeviceProperties2",),
("vkGetPhysicalDeviceFeatures2",),
("vkGetPhysicalDeviceMemoryProperties",),
("vkGetPhysicalDeviceQueueFamilyProperties",),
("vkGetPhysicalDeviceSurfaceCapabilitiesKHR",),
("vkGetPhysicalDeviceSurfaceFormatsKHR",),
("vkGetPhysicalDeviceSurfacePresentModesKHR",),
("vkGetPhysicalDeviceSurfaceSupportKHR",),
("vkGetPhysicalDeviceFormatProperties",),
("vkEnumerateDeviceExtensionProperties",),
("vkGetPhysicalDeviceImageFormatProperties2",),
(),
("vkCreateDisplayPlaneSurfaceKHR", "VK_USE_PLATFORM_DISPLAY_KHR"),
("vkGetDisplayPlaneCapabilitiesKHR", "VK_USE_PLATFORM_DISPLAY_KHR"),
("vkGetPhysicalDeviceDisplayPropertiesKHR", "VK_USE_PLATFORM_DISPLAY_KHR"),
("vkGetPhysicalDeviceDisplayPlanePropertiesKHR", "VK_USE_PLATFORM_DISPLAY_KHR"),
("vkGetDisplayModePropertiesKHR", "VK_USE_PLATFORM_DISPLAY_KHR"),
("vkReleaseDisplayEXT", "VK_USE_PLATFORM_DISPLAY_KHR"),
(),
("vkCreateXcbSurfaceKHR", "VK_USE_PLATFORM_XCB_KHR"),
(),
("vkCreateWaylandSurfaceKHR", "VK_USE_PLATFORM_WAYLAND_KHR"),
(),
(
"vkAcquireDrmDisplayEXT",
"VK_USE_PLATFORM_WAYLAND_KHR",
"VK_EXT_acquire_drm_display",
),
("vkGetDrmDisplayEXT", "VK_USE_PLATFORM_WAYLAND_KHR", "VK_EXT_acquire_drm_display"),
(),
("vkGetRandROutputDisplayEXT", "VK_USE_PLATFORM_XLIB_XRANDR_EXT"),
("vkAcquireXlibDisplayEXT", "VK_USE_PLATFORM_XLIB_XRANDR_EXT"),
(),
("vkCreateAndroidSurfaceKHR", "VK_USE_PLATFORM_ANDROID_KHR"),
(),
("vkCreateWin32SurfaceKHR", "VK_USE_PLATFORM_WIN32_KHR"),
]
EXTENSIONS_TO_CHECK = [
"VK_GOOGLE_display_timing",
"VK_EXT_global_priority",
"VK_EXT_robustness2",
]
ROOT = Path(__file__).resolve().parent.parent
DIR = ROOT / "src" / "xrt" / "auxiliary" / "vk"
HEADER_FN = DIR / "vk_helpers.h"
IMPL_FN = DIR / "vk_helpers.c"
BEGIN_TEMPLATE = "\t// beginning of GENERATED %s code - do not modify - used by scripts"
END_TEMPLATE = "\t// end of GENERATED %s code - do not modify - used by scripts"
def wrap_condition(condition):
if "defined" in condition:
return condition
return "defined({})".format(condition)
def compute_condition(pp_conditions):
if not pp_conditions:
return None
return " && ".join(wrap_condition(x) for x in pp_conditions)
class ConditionalGenerator:
"""Keep track of conditions to avoid unneeded repetition of ifdefs."""
def __init__(self):
self.current_condition = None
def process_condition(self, new_condition: Optional[str]) -> Optional[str]:
"""Return a line (or lines) to yield if required based on the new condition state."""
lines = []
if self.current_condition and new_condition != self.current_condition:
# Close current condition if required.
lines.append("#endif // {}".format(self.current_condition))
# empty line
lines.append("")
self.current_condition = None
if new_condition != self.current_condition:
# Open new condition if required
lines.append("#if {}".format(new_condition))
self.current_condition = new_condition
if lines:
return "\n".join(lines)
def finish(self) -> Optional[str]:
"""Return a line (or lines) to yield if required at the end of the loop."""
return self.process_condition(None)
def generate_per_function(functions: List[Tuple[str, ...]], per_function_handler):
conditional = ConditionalGenerator()
for data in functions:
if not data:
# empty line
yield ""
continue
condition_line = conditional.process_condition(compute_condition(data[1:]))
if condition_line:
yield condition_line
yield per_function_handler(data[0])
# close any trailing conditions
condition_line = conditional.finish()
if condition_line:
yield condition_line
def generate_structure_members(functions: List[Tuple[str, ...]]):
def per_function(name):
return "\tPFN_{} {};".format(name, name)
return generate_per_function(functions, per_function)
def generate_ins_proc(functions: List[Tuple[str, ...]]):
def per_function(func: str) -> str:
return "\tvk->{} = GET_INS_PROC(vk, {});".format(func, func)
return generate_per_function(functions, per_function)
def generate_dev_proc(functions: List[Tuple[str, ...]]):
def per_function(func: str) -> str:
return "\tvk->{} = GET_DEV_PROC(vk, {});".format(func, func)
return generate_per_function(functions, per_function)
def make_ext_member_name(ext: str):
return "has_{}".format(ext[3:])
def make_ext_name_define(ext: str):
return "{}_EXTENSION_NAME".format(ext.upper()).replace("2", "_2")
def generate_ext_members():
for ext in EXTENSIONS_TO_CHECK:
yield "\tbool {};".format(make_ext_member_name(ext))
def generate_ext_check():
yield "\t// Reset before filling out."
for ext in EXTENSIONS_TO_CHECK:
yield "\tvk->{} = false;".format(make_ext_member_name(ext))
yield ""
yield "\tfor (uint32_t i = 0; i < device_extension_count; i++) {"
yield "\t\tconst char *ext = device_extensions[i];"
yield ""
conditional = ConditionalGenerator()
for ext in EXTENSIONS_TO_CHECK:
condition_line = conditional.process_condition(compute_condition((ext,)))
if condition_line:
yield condition_line
yield "\t\tif (strcmp(ext, {}) == 0) {{".format(make_ext_name_define(ext))
yield "\t\t\tvk->{} = true;".format(make_ext_member_name(ext))
yield "\t\t\tcontinue;"
yield "\t\t}"
# close any trailing conditions
condition_line = conditional.finish()
if condition_line:
yield condition_line
yield "\t}"
def replace_middle(
lines: List[str], start_sentinel: str, end_sentinel: str, new_middle: List[str]
) -> List[str]:
middle_start = lines.index(start_sentinel) + 1
middle_end = lines.index(end_sentinel)
return lines[:middle_start] + new_middle + lines[middle_end:]
DEVICE_TEMPLATES = {
"BEGIN": BEGIN_TEMPLATE % "device loader",
"END": END_TEMPLATE % "device loader",
}
INSTANCE_TEMPLATES = {
"BEGIN": BEGIN_TEMPLATE % "instance loader",
"END": END_TEMPLATE % "instance loader",
}
EXT_TEMPLATES = {
"BEGIN": BEGIN_TEMPLATE % "extension",
"END": END_TEMPLATE % "extension",
}
def process_header():
with open(str(HEADER_FN), "r", encoding="utf-8") as fp:
lines = [line.rstrip() for line in fp.readlines()]
lines = replace_middle(
lines,
INSTANCE_TEMPLATES["BEGIN"],
INSTANCE_TEMPLATES["END"],
list(generate_structure_members(INSTANCE_FUNCTIONS)),
)
lines = replace_middle(
lines,
DEVICE_TEMPLATES["BEGIN"],
DEVICE_TEMPLATES["END"],
list(generate_structure_members(DEVICE_FUNCTIONS)),
)
lines = replace_middle(
lines,
EXT_TEMPLATES["BEGIN"],
EXT_TEMPLATES["END"],
list(generate_ext_members()),
)
with open(str(HEADER_FN), "w", encoding="utf-8") as fp:
fp.write("\n".join(lines))
fp.write("\n")
def process_impl():
with open(str(IMPL_FN), "r", encoding="utf-8") as fp:
lines = [line.rstrip() for line in fp.readlines()]
lines = replace_middle(
lines,
INSTANCE_TEMPLATES["BEGIN"],
INSTANCE_TEMPLATES["END"],
list(generate_ins_proc(INSTANCE_FUNCTIONS)),
)
lines = replace_middle(
lines,
DEVICE_TEMPLATES["BEGIN"],
DEVICE_TEMPLATES["END"],
list(generate_dev_proc(DEVICE_FUNCTIONS)),
)
lines = replace_middle(
lines,
EXT_TEMPLATES["BEGIN"],
EXT_TEMPLATES["END"],
list(generate_ext_check()),
)
with open(str(IMPL_FN), "w", encoding="utf-8") as fp:
fp.write("\n".join(lines))
fp.write("\n")
if __name__ == "__main__":
process_header()
process_impl()