diff --git a/CMakeLists.txt b/CMakeLists.txt index 77cd2ac..1b25e37 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,7 +14,8 @@ endif () ############################################################################### -file (MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/icd") +set (GENERATED_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/cruft/vk/") +file (MAKE_DIRECTORY "${GENERATED_PREFIX}/icd") if (WIN32) @@ -29,18 +30,18 @@ endif() ##----------------------------------------------------------------------------- add_custom_command ( OUTPUT - "${CMAKE_CURRENT_BINARY_DIR}/vk.hpp" - "${CMAKE_CURRENT_BINARY_DIR}/icd/dispatch.cpp" - "${CMAKE_CURRENT_BINARY_DIR}/icd/vtable.hpp" + "${GENERATED_PREFIX}/vk.hpp" + "${GENERATED_PREFIX}/icd/dispatch.cpp" + "${GENERATED_PREFIX}/icd/vtable.hpp" COMMENT "[spec.py] vk.hpp" COMMAND "${PYTHON_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/tools/spec.py" "--src" "${CMAKE_CURRENT_SOURCE_DIR}/specs/xml/vk.xml" - "--dst" "${CMAKE_CURRENT_BINARY_DIR}/vk.hpp" - "--icd" "${CMAKE_CURRENT_BINARY_DIR}/icd/vtable.hpp" - "--dispatch" "${CMAKE_CURRENT_BINARY_DIR}/icd/dispatch.cpp" + "--dst" "${GENERATED_PREFIX}/vk.hpp" + "--icd" "${GENERATED_PREFIX}/icd/vtable.hpp" + "--dispatch" "${GENERATED_PREFIX}/icd/dispatch.cpp" "--platform" "${VK_PLATFORM}" DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/tools/spec.py" @@ -62,8 +63,8 @@ endif() ##----------------------------------------------------------------------------- add_library (cruft-vk-icd STATIC icd/fwd.hpp - ${CMAKE_CURRENT_BINARY_DIR}/icd/vtable.hpp - ${CMAKE_CURRENT_BINARY_DIR}/icd/dispatch.cpp + ${GENERATED_PREFIX}/icd/vtable.hpp + ${GENERATED_PREFIX}/icd/dispatch.cpp icd/dispatch.hpp icd/vendor.hpp icd/vendor.cpp @@ -82,7 +83,7 @@ target_link_libraries (cruft-vk-icd cruft-json cruft) ############################################################################### list (APPEND sources - vk.hpp + "${GENERATED_PREFIX}/vk.hpp" fwd.hpp object.cpp @@ -144,7 +145,7 @@ target_link_libraries (cruft-vk cruft-vk-icd cruft) target_include_directories (cruft-vk PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}" - "${CMAKE_CURRENT_BINARY_DIR}" + "${GENERATED_PREFIX}" "${CMAKE_CURRENT_SOURCE_DIR}/specs/include/vulkan" ) diff --git a/icd/vendor.cpp b/icd/vendor.cpp index aa09bd0..6a3d9c7 100644 --- a/icd/vendor.cpp +++ b/icd/vendor.cpp @@ -5,6 +5,7 @@ using cruft::vk::icd::vendor; +/////////////////////////////////////////////////////////////////////////////// template <> cruft::vk::icd::icd_t json::tree::io::deserialise (json::tree::node const &obj) @@ -19,6 +20,11 @@ json::tree::io::deserialise (json::tree::node const &obj) } +/////////////////////////////////////////////////////////////////////////////// +cruft::vk::icd::global_table const *cruft::vk::icd::g_table; + + + /////////////////////////////////////////////////////////////////////////////// vendor::vendor (icd_t const &_icd): vendor (cruft::library (_icd.icd.library_path)) @@ -28,7 +34,16 @@ vendor::vendor (icd_t const &_icd): //----------------------------------------------------------------------------- vendor::vendor (::cruft::library &&_library) : m_library (std::move (_library)) - , m_get_proc (m_library.symbol ("vk_icdGetInstanceProcAddr")) + , m_get_proc ( + m_library.symbol ("vk_icdGetInstanceProcAddr") + ) { - vtable.CreateInstance = reinterpret_cast (m_get_proc (nullptr, "vkCreateInstance")); -} + #define LOADFN(name) \ + vtable.name = reinterpret_cast< \ + decltype(vtable.name) \ + > ( \ + m_get_proc(nullptr, #name) \ + ); + + MAP_INSTANCE_COMMANDS (LOADFN) +} \ No newline at end of file diff --git a/icd/vendor.hpp b/icd/vendor.hpp index 668f1ef..1fc7c77 100644 --- a/icd/vendor.hpp +++ b/icd/vendor.hpp @@ -1,6 +1,7 @@ #pragma once -#include "vk.hpp" +#include +#include #include @@ -28,20 +29,12 @@ namespace cruft::vk::icd { vendor (icd_t const&); vendor (::cruft::library &&); - struct vtable_t { - VkResult (*CreateInstance) ( - VkInstanceCreateInfo const*, - VkAllocationCallbacks const*, - VkInstance* - ) noexcept; - - void (*GetInstanceProc) (VkInstance instance, const char* pName) noexcept; - } vtable; - private: ::cruft::library m_library; public: + global_table vtable; + using get_proc_t = void* (*)(VkInstance, char const*); get_proc_t const m_get_proc; }; diff --git a/icd/vtable.cpp b/icd/vtable.cpp index 054bc77..309b3a4 100644 --- a/icd/vtable.cpp +++ b/icd/vtable.cpp @@ -1,14 +1,7 @@ -#include "icd/vtable.hpp" - -#include "vendor.hpp" +#include using cruft::vk::icd::instance_table; -instance_table::instance_table (vendor &src) -{ -#define LOADFN(name) this->name = reinterpret_castname)> (src.m_get_proc( - this->vkCreateInstance = reinterpret_castvkCreateInstance)> ( - src.m_get_proc(nullptr, "vkCreateInstance") - ); -} +/////////////////////////////////////////////////////////////////////////////// + diff --git a/instance.hpp b/instance.hpp index bf254aa..d0fa466 100644 --- a/instance.hpp +++ b/instance.hpp @@ -7,8 +7,7 @@ * 2016-2017, Danny Robson */ -#ifndef CRUFT_VK_INSTANCE_HPP -#define CRUFT_VK_INSTANCE_HPP +#pragma once #include "./object.hpp" @@ -54,5 +53,3 @@ namespace cruft::vk { static std::vector available_layers (void); }; } - -#endif diff --git a/tools/info.cpp b/tools/info.cpp index 04992e2..691f332 100644 --- a/tools/info.cpp +++ b/tools/info.cpp @@ -9,6 +9,8 @@ #include +#include + #include #include #include @@ -26,7 +28,8 @@ main (int, char**) { for (auto const &i: cruft::vk::icd::enumerate ()) { cruft::vk::icd::vendor v (i); - cruft::vk::icd::instance_table t (v); + + cruft::vk::icd::g_table = &v.vtable; //std::cout << "available_layers: [ " // << cruft::make_infix (cruft::vk::instance::available_layers ()) @@ -35,7 +38,7 @@ main (int, char**) cruft::vk::instance instance; std::cout << "instance: " << instance << '\n'; - for (const auto &d: cruft::vk::physical_device::find (instance)) - std::cout << d << '\n'; + //for (const auto &d: cruft::vk::physical_device::find (instance)) + // std::cout << d << '\n'; } } \ No newline at end of file diff --git a/tools/spec.py b/tools/spec.py index 8b8b364..b361ec2 100644 --- a/tools/spec.py +++ b/tools/spec.py @@ -428,39 +428,38 @@ class Command(Type): 'params': ", ".join(p.param for p in self.params) } + def is_global(self, reg: Registry): + if not self.params: + return True + + return not isinstance(self.params[0], Handle) + def is_instance(self, reg: Registry): assert reg if not self.params: - return True + return False - first_arg = self.params[0].type - if first_arg == 'VkInstance': - return True + first_name = self.params[0].type + first_obj = reg.types[first_name] - first_obj = reg.types[first_arg] - - # If the first type isn't a handle of any description then it should - # be an instance function. if not isinstance(first_obj, Handle): - return True - - # Both VkInstance and VkPhysicalDevice are listed as possible instance - # parameters. - # - # Test that the handle is derived from VkInstance, and not derived from - # VkDevice. The second test is required because VkDevice is indirectly - # derived from VkInstance. This approach buys us a little more - # generality. - - if not first_obj.has_parent('VkInstance', reg): return False - if first_arg == 'VkDevice' or first_obj.has_parent('VkDevice', reg): - return False - return True + + instance = first_obj.has_parent('VkInstance', reg) + device = first_obj.has_parent('VkPhysicalDevice', reg) + return instance and not device def is_device(self, reg: Registry): - return not self.is_instance(reg) + if not self.params: + return False + + first_name = self.params[0].type + first_obj = reg.types[first_name] + if not isinstance(first_obj, Handle): + return False + + return first_obj.has_parent('VkPhysicalDevice', reg) ############################################################################### @@ -751,50 +750,47 @@ def write_header(dst: TextIO, q: List[Type], reg: Registry): # ----------------------------------------------------------------------------- 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) + collections = { + 'global': Command.is_global, + 'instance': Command.is_instance, + 'device': Command.is_device, + } dst.write(f""" - #include "vk.hpp" + #pragma once + + #include #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; - }}; + #define MAP_COMMANDS(FUNC) MAP0(FUNC,{",".join(i.name for i in commands)}) - 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 - )) + for name, test in collections.items(): + dst.write(f""" + #define MAP_{name.upper()}_COMMANDS(FUNC) \ + MAP0(FUNC,{",".join(i.name for i in commands if i.is_global(reg))}) - dst.write("""}; - struct device_table { - """) + struct {name}_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 - )) + # 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 commands if test(obj, reg) + )) + + dst.write(""" + }; + """) dst.write(""" - }; + extern cruft::vk::icd::global_table const *g_table [[maybe_unused]]; } """) @@ -802,62 +798,50 @@ def write_icd(dst: TextIO, q: List[Type], reg: Registry): # ----------------------------------------------------------------------------- def write_dispatch(dst: TextIO, q: List[Type], reg: Registry): dst.write(""" - #include "../vk.hpp" - #include "vtable.hpp" - - #include "icd/dispatch.hpp" + #include + #include + #include #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; - } - + struct indirect { + void *handle; + void const *table; + }; """) 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): + if obj.is_global(reg): dst.write(f""" - extern "C" {obj.result} {rename(obj.name)} ({", ".join(p.param for p in obj.params)}) noexcept {{ - unimplemented (); - }}""") + extern "C" + {obj.result} + {rename(obj.name)} ({", ".join(p.param for p in obj.params)}) noexcept {{ + return cruft::vk::icd::g_table->{obj.name} ({", ".join(p.name for p in obj.params)}); + }} + """) continue - - if first_arg.has_parent('VkDevice', reg): - table = "d_table" - elif first_arg.has_parent('VkInstance', reg): - table = 'i_table' + elif obj.is_instance(reg): + table = 'instance' + elif obj.is_device(reg): + table = 'device' else: - raise Exception("Unknown param type") + raise Exception("Unhandled command type") 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); + auto const entry = reinterpret_cast ({obj.params[0].name}); + auto const *table = reinterpret_cast<{table}_table*> (entry->table); - return (table->{obj.name})( - reinterpret_cast (entry->handle) - {", ".join([''] + [p.name for p in obj.params[1:]])} - ); - }} else {{ - unimplemented (); - }} + return (table->{obj.name})( + reinterpret_cast (entry->handle) + {", ".join([''] + [p.name for p in obj.params[1:]])} + ); }} """)