diff --git a/tools/spec.py b/tools/spec.py index 51e8f58..7009af3 100644 --- a/tools/spec.py +++ b/tools/spec.py @@ -715,6 +715,171 @@ def parse_extensions(reg:registry, root): reg.extensions[name] = extension(node) +############################################################################### +def write_header(path:str, q): + with open(path, 'w') as dst: + dst.write("#pragma once\n") + + # Write the declarations and definitions for all types. + for obj in q: + dst.write(obj.declare()) + dst.write('\n') + dst.write(obj.define(reg)) + dst.write('\n') + + + # Define the default case for device and instance type traits. + dst.write(""" + #include + + /// A type trait that tests if a Vulkan type is an instance type + template + struct is_instance: + public std::false_type + {}; + + + /// A type trait that tests if a Vulkan type is a device type + template + struct is_device: + public std::false_type + {}; + + + template + constexpr auto is_instance_v = is_instance::value; + + template + constexpr auto is_device_v = is_device::value; + """) + + # Specialise traits for device and instance types. + for obj in q: + if not isinstance(obj,handle): + continue + + device_value = "true_type" if obj.has_parent("VkDevice", reg) else "false_type" + instance_value = "true_type" if obj.has_parent("VkInstance", reg) else "false_type" + + dst.write(f""" + template <> struct is_instance<{obj.name}>: public std::{instance_value} {{ }}; + template <> struct is_device<{obj.name}>: public std::{device_value} {{ }}; + """) + + +##----------------------------------------------------------------------------- +def write_icd(path:str, q): + with open(path, 'w') as icd: + commands = [i for i in q if isinstance(i, command)] + instance_commands = [i for i in commands if i.is_instance(reg)] + device_commands = [i for i in commands if i.is_device(reg)] + + assert len(instance_commands) + len(device_commands) == len(commands) + + icd.write(f""" + #include "vk.hpp" + + #include + + #define MAP_COMMANDS(FUNC) MAP0(FUNC,{",".join(i.name for i in commands)}) + #define MAP_INSTANCE_COMMANDS(FUNC) MAP0(FUNC,{",".join(i.name for i in instance_commands)}) + #define MAP_DEVICE_COMMANDS(FUNC) MAP0(FUNC,{",".join(i.name for i in device_commands)}) + + namespace cruft::vk::icd {{ + class vendor; + + struct func {{ + void *handle; + void const *table; + }}; + + struct instance_table {{ + instance_table (vendor &); + """) + + for obj in instance_commands: + icd.write(f"{obj.result} (*{obj.name}) ({','.join(p.param for p in obj.params)}) = nullptr;\n") + + icd.write("""}; + + struct device_table { + """) + + for obj in device_commands: + icd.write(f"{obj.result} (*{obj.name}) ({','.join(p.param for p in obj.params)}) = nullptr;\n") + + icd.write(""" + }; + } + """) + + +##----------------------------------------------------------------------------- +def write_dispatch(path:str, q): + with open(path, 'w') as dispatch: + dispatch.write(""" + #include "../vk.hpp" + #include "vtable.hpp" + + #include "icd/dispatch.hpp" + + #include + + #pragma GCC diagnostic ignored "-Wunused-parameter" + + static cruft::vk::icd::instance_table const *i_table [[maybe_unused]] = nullptr; + static cruft::vk::icd::device_table const *d_table [[maybe_unused]] = nullptr; + + void (*cruft_vk_icdGetInstanceProcAddr) ( + VkInstance instance, + const char* pName + ) = nullptr; + + void cruft::vk::icd::init (vendor const &impl) + { + cruft_vk_icdGetInstanceProcAddr = impl.vtable.GetInstanceProc; + } + + """) + + for obj in (i for i in q if isinstance(i, command)): + first_arg = reg.types[obj.params[0].type] + + if not isinstance(first_arg, handle): + dispatch.write(f""" + extern "C" {obj.result} {rename(obj.name)} ({", ".join(p.param for p in obj.params)}) noexcept {{ + unimplemented (); + }}""") + continue + + if first_arg.has_parent('VkDevice', reg): + table = "d_table"; + elif first_arg.has_parent('VkInstance', reg): + table = 'i_table' + else: + raise Exception("Unknown param type") + + + dispatch.write(f""" + extern "C" {obj.result} {rename(obj.name)} ({", ".join(p.param for p in obj.params)}) noexcept {{ + using first_arg_t = std::decay_t; + + if constexpr (is_instance_v) {{ + auto const entry = reinterpret_cast ({obj.params[0].name}); + auto const *table = reinterpret_cast (entry->table); + + return (table->{obj.name})( + reinterpret_cast (entry->handle) + {", ".join([''] + [p.name for p in obj.params[1:]])} + ); + }} else {{ + unimplemented (); + }} + }} + """) + + + ############################################################################### def enqueue_type(name:str, queued:Set[str], types:Dict[str,type]): if name in queued: @@ -784,151 +949,6 @@ if __name__ == '__main__': extensions = ["VK_KHR_swapchain", "VK_EXT_debug_report", "VK_KHR_external_memory"] q = reg.serialise(args.platform) - with open(args.dst, 'w') as dst: - dst.write("#pragma once\n") - for obj in q: - dst.write(obj.declare()) - dst.write('\n') - dst.write(obj.define(reg)) - dst.write('\n') - - - dst.write(""" - #include - - template - struct is_instance: - public std::false_type - {}; - - template - struct is_device: - public std::false_type - {}; - - - template - constexpr auto is_instance_v = is_instance::value; - - template - constexpr auto is_device_v = is_device::value; - """) - - for obj in q: - if not isinstance(obj,handle): - continue - - device_value = "true_type" if obj.has_parent("VkDevice", reg) else "false_type" - instance_value = "true_type" if obj.has_parent("VkInstance", reg) else "false_type" - - dst.write(f""" - template <> struct is_instance<{obj.name}>: public std::{instance_value} {{ }}; - template <> struct is_device<{obj.name}>: public std::{device_value} {{ }}; - """) - - with open(args.icd, 'w') as icd: - commands = [i for i in q if isinstance(i, command)] - instance_commands = [i for i in commands if i.is_instance(reg)] - device_commands = [i for i in commands if i.is_device(reg)] - - assert len(instance_commands) + len(device_commands) == len(commands) - - icd.write(f""" - #include "vk.hpp" - - #include - - #define MAP_COMMANDS(FUNC) MAP0(FUNC,{",".join(i.name for i in commands)}) - #define MAP_INSTANCE_COMMANDS(FUNC) MAP0(FUNC,{",".join(i.name for i in instance_commands)}) - #define MAP_DEVICE_COMMANDS(FUNC) MAP0(FUNC,{",".join(i.name for i in device_commands)}) - - namespace cruft::vk::icd {{ - class vendor; - - struct func {{ - void *handle; - void const *table; - }}; - - struct instance_table {{ - instance_table (vendor &); - """) - - for obj in instance_commands: - icd.write(f"{obj.result} (*{obj.name}) ({','.join(p.param for p in obj.params)}) = nullptr;\n") - - icd.write("""}; - - struct device_table { - """) - - for obj in device_commands: - icd.write(f"{obj.result} (*{obj.name}) ({','.join(p.param for p in obj.params)}) = nullptr;\n") - - icd.write(""" - }; - } - """) - - - with open(args.dispatch, 'w') as dispatch: - dispatch.write(""" - #include "../vk.hpp" - #include "vtable.hpp" - - #include "icd/dispatch.hpp" - - #include - - #pragma GCC diagnostic ignored "-Wunused-parameter" - - static cruft::vk::icd::instance_table const *i_table [[maybe_unused]] = nullptr; - static cruft::vk::icd::device_table const *d_table [[maybe_unused]] = nullptr; - - void (*cruft_vk_icdGetInstanceProcAddr) ( - VkInstance instance, - const char* pName - ) = nullptr; - - void cruft::vk::icd::init (vendor const &impl) - { - cruft_vk_icdGetInstanceProcAddr = impl.vtable.GetInstanceProc; - } - - """) - - for obj in commands: - first_arg = reg.types[obj.params[0].type] - - if not isinstance(first_arg, handle): - dispatch.write(f""" - extern "C" {obj.result} {rename(obj.name)} ({", ".join(p.param for p in obj.params)}) noexcept {{ - unimplemented (); - }}""") - continue - - if first_arg.has_parent('VkDevice', reg): - table = "d_table"; - elif first_arg.has_parent('VkInstance', reg): - table = 'i_table' - else: - raise Exception("Unknown param type") - - - dispatch.write(f""" - extern "C" {obj.result} {rename(obj.name)} ({", ".join(p.param for p in obj.params)}) noexcept {{ - using first_arg_t = std::decay_t; - - if constexpr (is_instance_v) {{ - auto const entry = reinterpret_cast ({obj.params[0].name}); - auto const *table = reinterpret_cast (entry->table); - - return (table->{obj.name})( - reinterpret_cast (entry->handle) - {", ".join([''] + [p.name for p in obj.params[1:]])} - ); - }} else {{ - unimplemented (); - }} - }} - """) + write_header(args.dst, q) + write_icd(args.icd, q) + write_dispatch(args.dispatch, q)