icd: use global, instance, and device tables
This commit is contained in:
parent
deca2ded59
commit
833d82f818
@ -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"
|
||||
)
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
using cruft::vk::icd::vendor;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <>
|
||||
cruft::vk::icd::icd_t
|
||||
json::tree::io<cruft::vk::icd::icd_t>::deserialise (json::tree::node const &obj)
|
||||
@ -19,6 +20,11 @@ json::tree::io<cruft::vk::icd::icd_t>::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<decltype(m_get_proc)> ("vk_icdGetInstanceProcAddr"))
|
||||
, m_get_proc (
|
||||
m_library.symbol<decltype(m_get_proc)> ("vk_icdGetInstanceProcAddr")
|
||||
)
|
||||
{
|
||||
vtable.CreateInstance = reinterpret_cast<decltype(vtable.CreateInstance)> (m_get_proc (nullptr, "vkCreateInstance"));
|
||||
}
|
||||
#define LOADFN(name) \
|
||||
vtable.name = reinterpret_cast< \
|
||||
decltype(vtable.name) \
|
||||
> ( \
|
||||
m_get_proc(nullptr, #name) \
|
||||
);
|
||||
|
||||
MAP_INSTANCE_COMMANDS (LOADFN)
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "vk.hpp"
|
||||
#include <cruft/vk/vk.hpp>
|
||||
#include <cruft/vk/icd/vtable.hpp>
|
||||
|
||||
#include <cruft/util/library.hpp>
|
||||
|
||||
@ -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;
|
||||
};
|
||||
|
@ -1,14 +1,7 @@
|
||||
#include "icd/vtable.hpp"
|
||||
|
||||
#include "vendor.hpp"
|
||||
#include <cruft/vk/icd/vtable.hpp>
|
||||
|
||||
using cruft::vk::icd::instance_table;
|
||||
|
||||
instance_table::instance_table (vendor &src)
|
||||
{
|
||||
#define LOADFN(name) this->name = reinterpret_cast<decltype(this->name)> (src.m_get_proc(
|
||||
|
||||
this->vkCreateInstance = reinterpret_cast<decltype(this->vkCreateInstance)> (
|
||||
src.m_get_proc(nullptr, "vkCreateInstance")
|
||||
);
|
||||
}
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -7,8 +7,7 @@
|
||||
* 2016-2017, Danny Robson <danny@nerdcruft.net>
|
||||
*/
|
||||
|
||||
#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<VkLayerProperties> available_layers (void);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -9,6 +9,8 @@
|
||||
|
||||
#include <cruft/util/iterator.hpp>
|
||||
|
||||
#include <cruft/vk/icd/vtable.hpp>
|
||||
|
||||
#include <cruft/vk/instance.hpp>
|
||||
#include <cruft/vk/physical_device.hpp>
|
||||
#include <cruft/vk/ostream.hpp>
|
||||
@ -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';
|
||||
}
|
||||
}
|
160
tools/spec.py
160
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 <cruft/vk/vk.hpp>
|
||||
|
||||
#include <cruft/util/preprocessor.hpp>
|
||||
|
||||
#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 <cruft/vk/vk.hpp>
|
||||
#include <cruft/vk/icd/vtable.hpp>
|
||||
#include <cruft/vk/icd/dispatch.hpp>
|
||||
|
||||
#include <cruft/util/debug.hpp>
|
||||
|
||||
#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<decltype({obj.params[0].name})>;
|
||||
|
||||
if constexpr (is_instance_v<first_arg_t>) {{
|
||||
auto const entry = reinterpret_cast<cruft::vk::icd::func const*> ({obj.params[0].name});
|
||||
auto const *table = reinterpret_cast<decltype({table})> (entry->table);
|
||||
auto const entry = reinterpret_cast<indirect const*> ({obj.params[0].name});
|
||||
auto const *table = reinterpret_cast<{table}_table*> (entry->table);
|
||||
|
||||
return (table->{obj.name})(
|
||||
reinterpret_cast<decltype({obj.params[0].name})> (entry->handle)
|
||||
{", ".join([''] + [p.name for p in obj.params[1:]])}
|
||||
);
|
||||
}} else {{
|
||||
unimplemented ();
|
||||
}}
|
||||
return (table->{obj.name})(
|
||||
reinterpret_cast<decltype({obj.params[0].name})> (entry->handle)
|
||||
{", ".join([''] + [p.name for p in obj.params[1:]])}
|
||||
);
|
||||
}}
|
||||
""")
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user