From deca2ded59d02af693de2658f330cdfc83445744 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Sat, 5 Jan 2019 15:29:13 +1100 Subject: [PATCH] tools/spec: pass files rather than paths to write_foo functions --- tools/spec.py | 301 +++++++++++++++++++++++++------------------------- 1 file changed, 153 insertions(+), 148 deletions(-) diff --git a/tools/spec.py b/tools/spec.py index 25e1ca0..8b8b364 100644 --- a/tools/spec.py +++ b/tools/spec.py @@ -2,7 +2,7 @@ import sys import logging -from typing import List, Dict, Set +from typing import List, Dict, Set, TextIO import xml.etree.ElementTree @@ -699,167 +699,167 @@ def parse_extensions(reg: Registry, root): ############################################################################### -def write_header(path: str, q: List[Type], reg: Registry): - with open(path, 'w') as dst: - dst.write("#pragma once\n") +def write_header(dst: TextIO, q: List[Type], reg: Registry): + 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') + # 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 + # 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 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 - {}; + /// 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_instance_v = is_instance::value; - template - constexpr auto is_device_v = is_device::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} {{ }}; """) - # 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" +# ----------------------------------------------------------------------------- +def write_icd(dst: TextIO, q: List[Type], reg: Registry): + 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) + + dst.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 &); + """) + + # Generate the vtable entries for instance methods + dst.writelines(( + f"{obj.result} (*{obj.name}) ({','.join(p.param for p in obj.params)}) = nullptr;" + for obj in instance_commands + )) + + dst.write("""}; + struct device_table { + """) + + # Generate the vtable and entries for device_commands + dst.writelines(( + f"{obj.result} (*{obj.name}) ({','.join(p.param for p in obj.params)}) = nullptr;" + for obj in device_commands + )) + + dst.write(""" + }; + } + """) + + +# ----------------------------------------------------------------------------- +def write_dispatch(dst: TextIO, q: List[Type], reg: Registry): + dst.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): 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: List[Type], reg: Registry): - 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: List[Type], reg: Registry): - 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; + unimplemented (); + }}""") + continue - if constexpr (is_instance_v) {{ - auto const entry = reinterpret_cast ({obj.params[0].name}); - auto const *table = reinterpret_cast (entry->table); + 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") - return (table->{obj.name})( - reinterpret_cast (entry->handle) - {", ".join([''] + [p.name for p in obj.params[1:]])} - ); - }} else {{ - unimplemented (); - }} + dst.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 (); }} - """) - - + }} + """) ############################################################################### @@ -918,9 +918,14 @@ def main(): q = reg.serialise(args.platform) # Finally write out the header, icd, and dispatch code. - write_header(args.dst, q, reg) - write_icd(args.icd, q, reg) - write_dispatch(args.dispatch, q, reg) + with open(args.dst, 'w') as dst: + write_header(dst, q, reg) + + with open(args.icd, 'w') as dst: + write_icd(dst, q, reg) + + with open(args.dispatch, 'w') as dst: + write_dispatch(dst, q, reg) # -----------------------------------------------------------------------------