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)
|
if (WIN32)
|
||||||
@ -29,18 +30,18 @@ endif()
|
|||||||
##-----------------------------------------------------------------------------
|
##-----------------------------------------------------------------------------
|
||||||
add_custom_command (
|
add_custom_command (
|
||||||
OUTPUT
|
OUTPUT
|
||||||
"${CMAKE_CURRENT_BINARY_DIR}/vk.hpp"
|
"${GENERATED_PREFIX}/vk.hpp"
|
||||||
"${CMAKE_CURRENT_BINARY_DIR}/icd/dispatch.cpp"
|
"${GENERATED_PREFIX}/icd/dispatch.cpp"
|
||||||
"${CMAKE_CURRENT_BINARY_DIR}/icd/vtable.hpp"
|
"${GENERATED_PREFIX}/icd/vtable.hpp"
|
||||||
COMMENT
|
COMMENT
|
||||||
"[spec.py] vk.hpp"
|
"[spec.py] vk.hpp"
|
||||||
COMMAND
|
COMMAND
|
||||||
"${PYTHON_EXECUTABLE}"
|
"${PYTHON_EXECUTABLE}"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/tools/spec.py"
|
"${CMAKE_CURRENT_SOURCE_DIR}/tools/spec.py"
|
||||||
"--src" "${CMAKE_CURRENT_SOURCE_DIR}/specs/xml/vk.xml"
|
"--src" "${CMAKE_CURRENT_SOURCE_DIR}/specs/xml/vk.xml"
|
||||||
"--dst" "${CMAKE_CURRENT_BINARY_DIR}/vk.hpp"
|
"--dst" "${GENERATED_PREFIX}/vk.hpp"
|
||||||
"--icd" "${CMAKE_CURRENT_BINARY_DIR}/icd/vtable.hpp"
|
"--icd" "${GENERATED_PREFIX}/icd/vtable.hpp"
|
||||||
"--dispatch" "${CMAKE_CURRENT_BINARY_DIR}/icd/dispatch.cpp"
|
"--dispatch" "${GENERATED_PREFIX}/icd/dispatch.cpp"
|
||||||
"--platform" "${VK_PLATFORM}"
|
"--platform" "${VK_PLATFORM}"
|
||||||
DEPENDS
|
DEPENDS
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/tools/spec.py"
|
"${CMAKE_CURRENT_SOURCE_DIR}/tools/spec.py"
|
||||||
@ -62,8 +63,8 @@ endif()
|
|||||||
##-----------------------------------------------------------------------------
|
##-----------------------------------------------------------------------------
|
||||||
add_library (cruft-vk-icd STATIC
|
add_library (cruft-vk-icd STATIC
|
||||||
icd/fwd.hpp
|
icd/fwd.hpp
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/icd/vtable.hpp
|
${GENERATED_PREFIX}/icd/vtable.hpp
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/icd/dispatch.cpp
|
${GENERATED_PREFIX}/icd/dispatch.cpp
|
||||||
icd/dispatch.hpp
|
icd/dispatch.hpp
|
||||||
icd/vendor.hpp
|
icd/vendor.hpp
|
||||||
icd/vendor.cpp
|
icd/vendor.cpp
|
||||||
@ -82,7 +83,7 @@ target_link_libraries (cruft-vk-icd cruft-json cruft)
|
|||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
list (APPEND sources
|
list (APPEND sources
|
||||||
vk.hpp
|
"${GENERATED_PREFIX}/vk.hpp"
|
||||||
|
|
||||||
fwd.hpp
|
fwd.hpp
|
||||||
object.cpp
|
object.cpp
|
||||||
@ -144,7 +145,7 @@ target_link_libraries (cruft-vk cruft-vk-icd cruft)
|
|||||||
target_include_directories (cruft-vk
|
target_include_directories (cruft-vk
|
||||||
PUBLIC
|
PUBLIC
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}"
|
"${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
"${CMAKE_CURRENT_BINARY_DIR}"
|
"${GENERATED_PREFIX}"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/specs/include/vulkan"
|
"${CMAKE_CURRENT_SOURCE_DIR}/specs/include/vulkan"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
using cruft::vk::icd::vendor;
|
using cruft::vk::icd::vendor;
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
template <>
|
template <>
|
||||||
cruft::vk::icd::icd_t
|
cruft::vk::icd::icd_t
|
||||||
json::tree::io<cruft::vk::icd::icd_t>::deserialise (json::tree::node const &obj)
|
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::vendor (icd_t const &_icd):
|
||||||
vendor (cruft::library (_icd.icd.library_path))
|
vendor (cruft::library (_icd.icd.library_path))
|
||||||
@ -28,7 +34,16 @@ vendor::vendor (icd_t const &_icd):
|
|||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
vendor::vendor (::cruft::library &&_library)
|
vendor::vendor (::cruft::library &&_library)
|
||||||
: m_library (std::move (_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
|
#pragma once
|
||||||
|
|
||||||
#include "vk.hpp"
|
#include <cruft/vk/vk.hpp>
|
||||||
|
#include <cruft/vk/icd/vtable.hpp>
|
||||||
|
|
||||||
#include <cruft/util/library.hpp>
|
#include <cruft/util/library.hpp>
|
||||||
|
|
||||||
@ -28,20 +29,12 @@ namespace cruft::vk::icd {
|
|||||||
vendor (icd_t const&);
|
vendor (icd_t const&);
|
||||||
vendor (::cruft::library &&);
|
vendor (::cruft::library &&);
|
||||||
|
|
||||||
struct vtable_t {
|
|
||||||
VkResult (*CreateInstance) (
|
|
||||||
VkInstanceCreateInfo const*,
|
|
||||||
VkAllocationCallbacks const*,
|
|
||||||
VkInstance*
|
|
||||||
) noexcept;
|
|
||||||
|
|
||||||
void (*GetInstanceProc) (VkInstance instance, const char* pName) noexcept;
|
|
||||||
} vtable;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
::cruft::library m_library;
|
::cruft::library m_library;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
global_table vtable;
|
||||||
|
|
||||||
using get_proc_t = void* (*)(VkInstance, char const*);
|
using get_proc_t = void* (*)(VkInstance, char const*);
|
||||||
get_proc_t const m_get_proc;
|
get_proc_t const m_get_proc;
|
||||||
};
|
};
|
||||||
|
@ -1,14 +1,7 @@
|
|||||||
#include "icd/vtable.hpp"
|
#include <cruft/vk/icd/vtable.hpp>
|
||||||
|
|
||||||
#include "vendor.hpp"
|
|
||||||
|
|
||||||
using cruft::vk::icd::instance_table;
|
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>
|
* 2016-2017, Danny Robson <danny@nerdcruft.net>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef CRUFT_VK_INSTANCE_HPP
|
#pragma once
|
||||||
#define CRUFT_VK_INSTANCE_HPP
|
|
||||||
|
|
||||||
#include "./object.hpp"
|
#include "./object.hpp"
|
||||||
|
|
||||||
@ -54,5 +53,3 @@ namespace cruft::vk {
|
|||||||
static std::vector<VkLayerProperties> available_layers (void);
|
static std::vector<VkLayerProperties> available_layers (void);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
@ -9,6 +9,8 @@
|
|||||||
|
|
||||||
#include <cruft/util/iterator.hpp>
|
#include <cruft/util/iterator.hpp>
|
||||||
|
|
||||||
|
#include <cruft/vk/icd/vtable.hpp>
|
||||||
|
|
||||||
#include <cruft/vk/instance.hpp>
|
#include <cruft/vk/instance.hpp>
|
||||||
#include <cruft/vk/physical_device.hpp>
|
#include <cruft/vk/physical_device.hpp>
|
||||||
#include <cruft/vk/ostream.hpp>
|
#include <cruft/vk/ostream.hpp>
|
||||||
@ -26,7 +28,8 @@ main (int, char**)
|
|||||||
{
|
{
|
||||||
for (auto const &i: cruft::vk::icd::enumerate ()) {
|
for (auto const &i: cruft::vk::icd::enumerate ()) {
|
||||||
cruft::vk::icd::vendor v (i);
|
cruft::vk::icd::vendor v (i);
|
||||||
cruft::vk::icd::instance_table t (v);
|
|
||||||
|
cruft::vk::icd::g_table = &v.vtable;
|
||||||
|
|
||||||
//std::cout << "available_layers: [ "
|
//std::cout << "available_layers: [ "
|
||||||
// << cruft::make_infix (cruft::vk::instance::available_layers ())
|
// << cruft::make_infix (cruft::vk::instance::available_layers ())
|
||||||
@ -35,7 +38,7 @@ main (int, char**)
|
|||||||
cruft::vk::instance instance;
|
cruft::vk::instance instance;
|
||||||
std::cout << "instance: " << instance << '\n';
|
std::cout << "instance: " << instance << '\n';
|
||||||
|
|
||||||
for (const auto &d: cruft::vk::physical_device::find (instance))
|
//for (const auto &d: cruft::vk::physical_device::find (instance))
|
||||||
std::cout << d << '\n';
|
// 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)
|
'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):
|
def is_instance(self, reg: Registry):
|
||||||
assert reg
|
assert reg
|
||||||
|
|
||||||
if not self.params:
|
if not self.params:
|
||||||
return True
|
return False
|
||||||
|
|
||||||
first_arg = self.params[0].type
|
first_name = self.params[0].type
|
||||||
if first_arg == 'VkInstance':
|
first_obj = reg.types[first_name]
|
||||||
return True
|
|
||||||
|
|
||||||
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):
|
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
|
return False
|
||||||
if first_arg == 'VkDevice' or first_obj.has_parent('VkDevice', reg):
|
|
||||||
return False
|
instance = first_obj.has_parent('VkInstance', reg)
|
||||||
return True
|
device = first_obj.has_parent('VkPhysicalDevice', reg)
|
||||||
|
return instance and not device
|
||||||
|
|
||||||
def is_device(self, reg: Registry):
|
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):
|
def write_icd(dst: TextIO, q: List[Type], reg: Registry):
|
||||||
commands = [i for i in q if isinstance(i, Command)]
|
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"""
|
dst.write(f"""
|
||||||
#include "vk.hpp"
|
#pragma once
|
||||||
|
|
||||||
|
#include <cruft/vk/vk.hpp>
|
||||||
|
|
||||||
#include <cruft/util/preprocessor.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 {{
|
namespace cruft::vk::icd {{
|
||||||
class vendor;
|
class vendor;
|
||||||
|
|
||||||
struct func {{
|
#define MAP_COMMANDS(FUNC) MAP0(FUNC,{",".join(i.name for i in commands)})
|
||||||
void *handle;
|
|
||||||
void const *table;
|
|
||||||
}};
|
|
||||||
|
|
||||||
struct instance_table {{
|
|
||||||
instance_table (vendor &);
|
|
||||||
""")
|
""")
|
||||||
|
|
||||||
# Generate the vtable entries for instance methods
|
for name, test in collections.items():
|
||||||
dst.writelines((
|
dst.write(f"""
|
||||||
f"{obj.result} (*{obj.name}) ({','.join(p.param for p in obj.params)}) = nullptr;"
|
#define MAP_{name.upper()}_COMMANDS(FUNC) \
|
||||||
for obj in instance_commands
|
MAP0(FUNC,{",".join(i.name for i in commands if i.is_global(reg))})
|
||||||
))
|
|
||||||
|
|
||||||
dst.write("""};
|
struct {name}_table{{
|
||||||
struct device_table {
|
""")
|
||||||
""")
|
|
||||||
|
|
||||||
# Generate the vtable and entries for device_commands
|
# Generate the vtable entries for instance methods
|
||||||
dst.writelines((
|
dst.writelines((
|
||||||
f"{obj.result} (*{obj.name}) ({','.join(p.param for p in obj.params)}) = nullptr;"
|
f"{obj.result} (*{obj.name}) ({','.join(p.param for p in obj.params)}) = nullptr;"
|
||||||
for obj in device_commands
|
for obj in commands if test(obj, reg)
|
||||||
))
|
))
|
||||||
|
|
||||||
|
dst.write("""
|
||||||
|
};
|
||||||
|
""")
|
||||||
|
|
||||||
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):
|
def write_dispatch(dst: TextIO, q: List[Type], reg: Registry):
|
||||||
dst.write("""
|
dst.write("""
|
||||||
#include "../vk.hpp"
|
#include <cruft/vk/vk.hpp>
|
||||||
#include "vtable.hpp"
|
#include <cruft/vk/icd/vtable.hpp>
|
||||||
|
#include <cruft/vk/icd/dispatch.hpp>
|
||||||
#include "icd/dispatch.hpp"
|
|
||||||
|
|
||||||
#include <cruft/util/debug.hpp>
|
#include <cruft/util/debug.hpp>
|
||||||
|
|
||||||
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||||
|
|
||||||
static cruft::vk::icd::instance_table const *i_table [[maybe_unused]] = nullptr;
|
struct indirect {
|
||||||
static cruft::vk::icd::device_table const *d_table [[maybe_unused]] = nullptr;
|
void *handle;
|
||||||
|
void const *table;
|
||||||
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)):
|
for obj in (i for i in q if isinstance(i, Command)):
|
||||||
first_arg = reg.types[obj.params[0].type]
|
first_arg = reg.types[obj.params[0].type]
|
||||||
|
|
||||||
if not isinstance(first_arg, Handle):
|
if obj.is_global(reg):
|
||||||
dst.write(f"""
|
dst.write(f"""
|
||||||
extern "C" {obj.result} {rename(obj.name)} ({", ".join(p.param for p in obj.params)}) noexcept {{
|
extern "C"
|
||||||
unimplemented ();
|
{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
|
continue
|
||||||
|
elif obj.is_instance(reg):
|
||||||
if first_arg.has_parent('VkDevice', reg):
|
table = 'instance'
|
||||||
table = "d_table"
|
elif obj.is_device(reg):
|
||||||
elif first_arg.has_parent('VkInstance', reg):
|
table = 'device'
|
||||||
table = 'i_table'
|
|
||||||
else:
|
else:
|
||||||
raise Exception("Unknown param type")
|
raise Exception("Unhandled command type")
|
||||||
|
|
||||||
dst.write(f"""
|
dst.write(f"""
|
||||||
extern "C" {obj.result} {rename(obj.name)} ({", ".join(p.param for p in obj.params)}) noexcept {{
|
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})>;
|
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<indirect const*> ({obj.params[0].name});
|
||||||
auto const entry = reinterpret_cast<cruft::vk::icd::func const*> ({obj.params[0].name});
|
auto const *table = reinterpret_cast<{table}_table*> (entry->table);
|
||||||
auto const *table = reinterpret_cast<decltype({table})> (entry->table);
|
|
||||||
|
|
||||||
return (table->{obj.name})(
|
return (table->{obj.name})(
|
||||||
reinterpret_cast<decltype({obj.params[0].name})> (entry->handle)
|
reinterpret_cast<decltype({obj.params[0].name})> (entry->handle)
|
||||||
{", ".join([''] + [p.name for p in obj.params[1:]])}
|
{", ".join([''] + [p.name for p in obj.params[1:]])}
|
||||||
);
|
);
|
||||||
}} else {{
|
|
||||||
unimplemented ();
|
|
||||||
}}
|
|
||||||
}}
|
}}
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user