icd: resolve enough to run the info
tool
This commit is contained in:
parent
6e813ecc5e
commit
ce02f21614
16
except.hpp
16
except.hpp
@ -49,10 +49,18 @@ namespace cruft::vk {
|
|||||||
>;
|
>;
|
||||||
|
|
||||||
if constexpr (returns_vkresult) {
|
if constexpr (returns_vkresult) {
|
||||||
try_code (func (maybe_native (args)...));
|
try_code (
|
||||||
|
std::invoke (
|
||||||
|
std::forward<FuncT> (func),
|
||||||
|
maybe_native (std::forward<Args> (args))...
|
||||||
|
)
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
return func (maybe_native (args)...);
|
return std::invoke (
|
||||||
|
std::forward<FuncT> (func),
|
||||||
|
maybe_native (std::forward<Args> (args))...
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,7 +125,9 @@ namespace cruft::vk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------
|
///--------------------------------------------------------------------
|
||||||
|
/// Safely calls a function that returns an array of Handle objects,
|
||||||
|
/// and returns a vector of wrapped objects.
|
||||||
template <
|
template <
|
||||||
typename ReturnT,
|
typename ReturnT,
|
||||||
template <typename,typename...> class ContainerT = std::vector,
|
template <typename,typename...> class ContainerT = std::vector,
|
||||||
|
@ -2,9 +2,18 @@
|
|||||||
|
|
||||||
#include <cruft/json/tree.hpp>
|
#include <cruft/json/tree.hpp>
|
||||||
|
|
||||||
|
#include <cruft/util/std.hpp>
|
||||||
|
#include <cruft/util/log.hpp>
|
||||||
|
|
||||||
using cruft::vk::icd::vendor;
|
using cruft::vk::icd::vendor;
|
||||||
|
|
||||||
|
|
||||||
|
#define MAP_ICD_COMMANDS(FUNC,...) MAP0(FUNC,\
|
||||||
|
vk_icdNegotiateLoaderICDInterfaceVersion,\
|
||||||
|
vk_icdGetInstanceProcAddr,\
|
||||||
|
vk_icdGetPhysicalDeviceProcAddr)
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
template <>
|
template <>
|
||||||
cruft::vk::icd::icd_t
|
cruft::vk::icd::icd_t
|
||||||
@ -20,11 +29,6 @@ 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))
|
||||||
@ -34,16 +38,44 @@ 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")
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
#define LOADFN(name) \
|
// Negotiate needs to be called before anything else. But we load all the
|
||||||
vtable.name = reinterpret_cast< \
|
// ICD calls at once for simplicity.
|
||||||
decltype(vtable.name) \
|
#define GET(NAME) vtable.NAME = m_library.symbol<decltype(vtable.NAME)> (#NAME);
|
||||||
> ( \
|
MAP_ICD_COMMANDS (GET)
|
||||||
m_get_proc(nullptr, #name) \
|
#undef GET
|
||||||
|
|
||||||
|
version = 2;
|
||||||
|
switch (auto err = vtable.vk_icdNegotiateLoaderICDInterfaceVersion (&version); err) {
|
||||||
|
case VK_ERROR_INCOMPATIBLE_DRIVER:
|
||||||
|
static constexpr char incompatible_message[] = "Incompatible Vulkan ICD interface";
|
||||||
|
LOG_ERROR ("%! %!", incompatible_message, version);
|
||||||
|
throw std::runtime_error (incompatible_message);
|
||||||
|
|
||||||
|
default:
|
||||||
|
static constexpr char unknown_message[] = "Unknown Vulkan ICD interface response";
|
||||||
|
LOG_ERROR (
|
||||||
|
"%! %!",
|
||||||
|
unknown_message,
|
||||||
|
static_cast<std::underlying_type_t<decltype(err)>>(err)
|
||||||
);
|
);
|
||||||
|
|
||||||
MAP_INSTANCE_COMMANDS (LOADFN)
|
throw std::runtime_error (unknown_message);
|
||||||
|
|
||||||
|
case VK_SUCCESS:
|
||||||
|
LOG_INFO ("vk::icd version %!", version);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only load the instance table after we've queried all the icd functions.
|
||||||
|
itable = {
|
||||||
|
#define LOADFN(NAME) \
|
||||||
|
.NAME = reinterpret_cast< \
|
||||||
|
decltype(itable.NAME) \
|
||||||
|
> ( \
|
||||||
|
vtable.vk_icdGetInstanceProcAddr (nullptr, #NAME) \
|
||||||
|
),
|
||||||
|
|
||||||
|
MAP_INSTANCE_COMMANDS (LOADFN)
|
||||||
|
};
|
||||||
}
|
}
|
@ -4,6 +4,7 @@
|
|||||||
#include <cruft/vk/icd/vtable.hpp>
|
#include <cruft/vk/icd/vtable.hpp>
|
||||||
|
|
||||||
#include <cruft/util/library.hpp>
|
#include <cruft/util/library.hpp>
|
||||||
|
#include <cruft/util/std.hpp>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
@ -24,6 +25,12 @@ namespace cruft::vk::icd {
|
|||||||
enumerate (void);
|
enumerate (void);
|
||||||
|
|
||||||
|
|
||||||
|
struct vendor_table {
|
||||||
|
VkResult (*vk_icdNegotiateLoaderICDInterfaceVersion)(u32*) = nullptr;
|
||||||
|
void* (*vk_icdGetInstanceProcAddr) (VkInstance, char const*) = nullptr;
|
||||||
|
void* (*vk_icdGetPhysicalDeviceProcAddr) (VkInstance, char const*) = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
class vendor {
|
class vendor {
|
||||||
public:
|
public:
|
||||||
vendor (icd_t const&);
|
vendor (icd_t const&);
|
||||||
@ -33,9 +40,8 @@ namespace cruft::vk::icd {
|
|||||||
::cruft::library m_library;
|
::cruft::library m_library;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
global_table vtable;
|
vendor_table vtable;
|
||||||
|
instance_table itable;
|
||||||
using get_proc_t = void* (*)(VkInstance, char const*);
|
u32 version = 0;
|
||||||
get_proc_t const m_get_proc;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,9 @@ cruft::vk::icd::enumerate (void)
|
|||||||
for (size_t i = 0; i < words.we_wordc; ++i) {
|
for (size_t i = 0; i < words.we_wordc; ++i) {
|
||||||
try {
|
try {
|
||||||
for (auto const &path: fs::directory_iterator (words.we_wordv[i])) {
|
for (auto const &path: fs::directory_iterator (words.we_wordv[i])) {
|
||||||
|
if (path.is_directory ())
|
||||||
|
continue;
|
||||||
|
|
||||||
found.push_back (from_json<icd_t> (*json::tree::parse (path)));
|
found.push_back (from_json<icd_t> (*json::tree::parse (path)));
|
||||||
}
|
}
|
||||||
} catch (std::exception const &e) {
|
} catch (std::exception const &e) {
|
||||||
|
@ -4,4 +4,5 @@ using cruft::vk::icd::instance_table;
|
|||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
cruft::vk::icd::vendor_table const *cruft::vk::icd::v_table = nullptr;
|
||||||
|
cruft::vk::icd::instance_table const *cruft::vk::icd::i_table = nullptr;
|
||||||
|
@ -90,16 +90,18 @@ namespace cruft::vk {
|
|||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
/// a vulkan object that is obtained by listings from a parent object.
|
/// A vulkan object that is obtained by listings from a parent object.
|
||||||
template <typename SelfT, typename ParentT>
|
template <typename SelfT, typename ParentT>
|
||||||
struct enumerated : public object<SelfT> {
|
struct enumerated : public object<SelfT> {
|
||||||
using object<SelfT>::object;
|
using object<SelfT>::object;
|
||||||
|
|
||||||
|
/// Returns a vector of available objects given a parent object.
|
||||||
static std::vector<SelfT>
|
static std::vector<SelfT>
|
||||||
find (const ParentT &parent)
|
find (const ParentT &parent)
|
||||||
{
|
{
|
||||||
return error::try_handles<SelfT> (
|
return error::try_handles<SelfT> (
|
||||||
enum_traits<native_t<SelfT>>::enumerate, parent.native ()
|
enum_traits<native_t<SelfT>>::enumerate,
|
||||||
|
parent.native ()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -30,7 +30,8 @@ main (int, char**)
|
|||||||
std::cout << "[ ";
|
std::cout << "[ ";
|
||||||
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::g_table = &v.vtable;
|
cruft::vk::icd::i_table = &v.itable;
|
||||||
|
cruft::vk::icd::v_table = &v.vtable;
|
||||||
|
|
||||||
cruft::vk::instance instance;
|
cruft::vk::instance instance;
|
||||||
|
|
||||||
|
277
tools/spec.py
277
tools/spec.py
@ -3,6 +3,7 @@
|
|||||||
import sys
|
import sys
|
||||||
import logging
|
import logging
|
||||||
from typing import List, Dict, Set, TextIO
|
from typing import List, Dict, Set, TextIO
|
||||||
|
import pprint
|
||||||
|
|
||||||
import xml.etree.ElementTree
|
import xml.etree.ElementTree
|
||||||
|
|
||||||
@ -392,32 +393,27 @@ class Constant(Type):
|
|||||||
class Command(Type):
|
class Command(Type):
|
||||||
class Param(Type):
|
class Param(Type):
|
||||||
name: str
|
name: str
|
||||||
"""An appropriate title for this parameter"""
|
"""An string that can be used to refer to the parameter variable"""
|
||||||
type: str
|
type: str
|
||||||
"""The name of this parameter's dependant type"""
|
"""The name of this parameter's dependant type"""
|
||||||
param: str
|
param: str
|
||||||
"""
|
"""
|
||||||
The components of this type for a C definition (ie, includes
|
The components of this type for a C definition (ie, includes
|
||||||
pointer, const, and other decorations
|
pointer, const, other decorations, _and_ the variable name (which must
|
||||||
|
be the same as self.name for a useful system).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, node, **kwargs):
|
def __init__(self, name:str, type:str, param:str, depends:List[str]):
|
||||||
assert node.tag == 'param'
|
|
||||||
|
|
||||||
super().__init__(
|
super().__init__(
|
||||||
name=node.find('name').text,
|
name=name,
|
||||||
depends=[node.find('type').text],
|
depends=depends,
|
||||||
**kwargs
|
|
||||||
)
|
)
|
||||||
|
|
||||||
self.type = node.find('type').text
|
self.type = type
|
||||||
|
self.param = param
|
||||||
|
|
||||||
self.param = ""
|
def __repr__(self) -> str:
|
||||||
for i in node.iter():
|
return f"{{ name: '{self.name}', type: '{self.type}', param: '{self.param}' }}"
|
||||||
self.param += i.text or ""
|
|
||||||
self.param += i.tail or ""
|
|
||||||
# normalise whitespace
|
|
||||||
self.param = " ".join(self.param.split())
|
|
||||||
|
|
||||||
def is_pointer(self):
|
def is_pointer(self):
|
||||||
return '*' in self.param
|
return '*' in self.param
|
||||||
@ -429,6 +425,9 @@ class Command(Type):
|
|||||||
self.params = params
|
self.params = params
|
||||||
self.depends += depends or []
|
self.depends += depends or []
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f"{{ name: '{self.name}', result: '{self.result}', param: {self.params} }}"
|
||||||
|
|
||||||
def declare(self):
|
def declare(self):
|
||||||
return 'extern "C" %(result)s %(name)s (%(params)s) noexcept;' % {
|
return 'extern "C" %(result)s %(name)s (%(params)s) noexcept;' % {
|
||||||
'name': rename(self.name),
|
'name': rename(self.name),
|
||||||
@ -436,14 +435,6 @@ 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
|
|
||||||
|
|
||||||
first_name = self.params[0].type
|
|
||||||
first_obj = reg.types[first_name]
|
|
||||||
return not isinstance(first_obj, Handle)
|
|
||||||
|
|
||||||
def is_instance(self, reg: Registry):
|
def is_instance(self, reg: Registry):
|
||||||
assert reg
|
assert reg
|
||||||
|
|
||||||
@ -454,11 +445,11 @@ class Command(Type):
|
|||||||
first_obj = reg.types[first_name]
|
first_obj = reg.types[first_name]
|
||||||
|
|
||||||
if not isinstance(first_obj, Handle):
|
if not isinstance(first_obj, Handle):
|
||||||
return False
|
return True
|
||||||
|
|
||||||
instance = first_obj.has_parent('VkInstance', reg)
|
instance = first_obj.name == 'VkInstance'
|
||||||
device = first_obj.has_parent('VkPhysicalDevice', reg)
|
physical = first_obj.name == 'VkPhysicalDevice'
|
||||||
return instance and not device
|
return instance or physical
|
||||||
|
|
||||||
def is_device(self, reg: Registry):
|
def is_device(self, reg: Registry):
|
||||||
if not self.params:
|
if not self.params:
|
||||||
@ -469,24 +460,18 @@ class Command(Type):
|
|||||||
if not isinstance(first_obj, Handle):
|
if not isinstance(first_obj, Handle):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return first_obj.has_parent('VkPhysicalDevice', reg)
|
for i in ['VkDevice', 'VkQueue', 'VkCommandBuffer']:
|
||||||
|
if first_obj.has_parent(i, reg):
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
class Require(object):
|
class Require(object):
|
||||||
def __init__(self, root):
|
def __init__(self, values, depends: List[str]):
|
||||||
self.values = []
|
self.values = values or []
|
||||||
self.depends = []
|
self.depends = depends or []
|
||||||
|
|
||||||
for node in root:
|
|
||||||
if node.tag == 'enum':
|
|
||||||
self.values.append(node)
|
|
||||||
elif node.tag in ['command', 'type']:
|
|
||||||
self.depends.append(node.attrib['name'])
|
|
||||||
elif node.tag in ['comment']:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
raise RuntimeError("Unknown requires node")
|
|
||||||
|
|
||||||
def apply(self, reg: Registry, extnumber=None):
|
def apply(self, reg: Registry, extnumber=None):
|
||||||
required = []
|
required = []
|
||||||
@ -559,7 +544,7 @@ class Extension(Type):
|
|||||||
|
|
||||||
for node in root:
|
for node in root:
|
||||||
if node.tag == 'require':
|
if node.tag == 'require':
|
||||||
self.requires.append(Require(node))
|
self.requires.append(parse_require(node))
|
||||||
else:
|
else:
|
||||||
raise RuntimeError("Unknown extension node")
|
raise RuntimeError("Unknown extension node")
|
||||||
|
|
||||||
@ -660,6 +645,28 @@ def parse_enums(reg: Registry, root):
|
|||||||
else:
|
else:
|
||||||
owner[valuename] = Constant(node)
|
owner[valuename] = Constant(node)
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
def parse_param(root) -> Command.Param:
|
||||||
|
assert root.tag == 'param'
|
||||||
|
|
||||||
|
param = ""
|
||||||
|
for i in root.iter():
|
||||||
|
param += i.text or ""
|
||||||
|
param += i.tail or ""
|
||||||
|
# normalise whitespace
|
||||||
|
param = " ".join(param.split())
|
||||||
|
|
||||||
|
name = root.find('name').text
|
||||||
|
type = root.find('type').text
|
||||||
|
depends = [root.find('type').text]
|
||||||
|
|
||||||
|
return Command.Param(
|
||||||
|
name=name,
|
||||||
|
type=type,
|
||||||
|
param=param,
|
||||||
|
depends=depends,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
def parse_commands(reg: Registry, root):
|
def parse_commands(reg: Registry, root):
|
||||||
@ -677,7 +684,7 @@ def parse_commands(reg: Registry, root):
|
|||||||
name = proto.find('name').text
|
name = proto.find('name').text
|
||||||
|
|
||||||
result = proto.find('type').text
|
result = proto.find('type').text
|
||||||
params = [Command.Param(p) for p in node.findall('./param')]
|
params = [parse_param(p) for p in node.findall('./param')]
|
||||||
depends = [result]
|
depends = [result]
|
||||||
for p in params:
|
for p in params:
|
||||||
depends += p.depends
|
depends += p.depends
|
||||||
@ -686,6 +693,25 @@ def parse_commands(reg: Registry, root):
|
|||||||
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
|
def parse_require(root) -> Require:
|
||||||
|
assert root.tag == 'require'
|
||||||
|
|
||||||
|
values = []
|
||||||
|
depends = []
|
||||||
|
|
||||||
|
for node in root:
|
||||||
|
if node.tag == 'enum':
|
||||||
|
values.append(node)
|
||||||
|
elif node.tag in ['command', 'type']:
|
||||||
|
depends.append(node.attrib['name'])
|
||||||
|
elif node.tag in ['comment']:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
raise RuntimeError("Unknown requires node")
|
||||||
|
|
||||||
|
return Require(values=values, depends=depends)
|
||||||
|
|
||||||
|
##-----------------------------------------------------------------------------
|
||||||
def parse_feature(reg: Registry, root):
|
def parse_feature(reg: Registry, root):
|
||||||
assert root.tag == 'feature'
|
assert root.tag == 'feature'
|
||||||
|
|
||||||
@ -695,7 +721,7 @@ def parse_feature(reg: Registry, root):
|
|||||||
requires = []
|
requires = []
|
||||||
for node in root:
|
for node in root:
|
||||||
if 'require' == node.tag:
|
if 'require' == node.tag:
|
||||||
requires.append(Require(node))
|
requires.append(parse_require(node))
|
||||||
else:
|
else:
|
||||||
raise RuntimeError("Unhandled feature node")
|
raise RuntimeError("Unhandled feature node")
|
||||||
|
|
||||||
@ -769,7 +795,6 @@ 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)]
|
||||||
|
|
||||||
collections = {
|
collections = {
|
||||||
'global': Command.is_global,
|
|
||||||
'instance': Command.is_instance,
|
'instance': Command.is_instance,
|
||||||
'device': Command.is_device,
|
'device': Command.is_device,
|
||||||
}
|
}
|
||||||
@ -789,9 +814,13 @@ def write_icd(dst: TextIO, q: List[Type], reg: Registry):
|
|||||||
""")
|
""")
|
||||||
|
|
||||||
for name, test in collections.items():
|
for name, test in collections.items():
|
||||||
|
curr = [i for i in commands if test(i, reg)]
|
||||||
|
next = [i for i in commands if not test(i, reg)]
|
||||||
|
commands = next
|
||||||
|
|
||||||
dst.write(f"""
|
dst.write(f"""
|
||||||
#define MAP_{name.upper()}_COMMANDS(FUNC) \
|
#define MAP_{name.upper()}_COMMANDS(FUNC) \
|
||||||
MAP0(FUNC,{",".join(i.name for i in commands if i.is_global(reg))})
|
MAP0(FUNC,{",".join([i.name for i in curr])})
|
||||||
|
|
||||||
struct {name}_table{{
|
struct {name}_table{{
|
||||||
""")
|
""")
|
||||||
@ -799,7 +828,7 @@ def write_icd(dst: TextIO, q: List[Type], reg: Registry):
|
|||||||
# Generate the vtable entries for instance methods
|
# 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 commands if test(obj, reg)
|
for obj in curr
|
||||||
))
|
))
|
||||||
|
|
||||||
dst.write("""
|
dst.write("""
|
||||||
@ -807,7 +836,9 @@ def write_icd(dst: TextIO, q: List[Type], reg: Registry):
|
|||||||
""")
|
""")
|
||||||
|
|
||||||
dst.write("""
|
dst.write("""
|
||||||
extern cruft::vk::icd::global_table const *g_table [[maybe_unused]];
|
struct vendor_table;
|
||||||
|
extern cruft::vk::icd::vendor_table const *v_table;
|
||||||
|
extern cruft::vk::icd::instance_table const *i_table;
|
||||||
}
|
}
|
||||||
""")
|
""")
|
||||||
|
|
||||||
@ -823,30 +854,88 @@ def write_dispatch(dst: TextIO, q: List[Type], reg: Registry):
|
|||||||
|
|
||||||
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||||
|
|
||||||
|
template <typename HandleT, typename TableT>
|
||||||
struct indirect {
|
struct indirect {
|
||||||
void *handle;
|
HandleT handle;
|
||||||
void const *table;
|
TableT table;
|
||||||
};
|
};
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
implementations = {
|
||||||
|
'vkCreateInstance': """
|
||||||
|
auto res = std::make_unique<indirect<VkInstance,cruft::vk::icd::instance_table>> ();
|
||||||
|
auto err = cruft::vk::icd::i_table->vkCreateInstance (pCreateInfo, pAllocator, &res->handle);
|
||||||
|
if (err != VK_SUCCESS)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
#define GET(NAME) res->table.NAME = reinterpret_cast<decltype(&NAME)> (cruft::vk::icd::v_table->vk_icdGetInstanceProcAddr (res->handle, #NAME));
|
||||||
|
MAP_INSTANCE_COMMANDS(GET)
|
||||||
|
#undef GET
|
||||||
|
|
||||||
|
#define GET(NAME) if (!res->table.NAME) res->table.NAME = reinterpret_cast<decltype(&NAME)> (res->table.vkGetInstanceProcAddr (res->handle, #NAME));
|
||||||
|
MAP_INSTANCE_COMMANDS(GET)
|
||||||
|
#undef GET
|
||||||
|
|
||||||
|
*pInstance = (VkInstance)res.release ();
|
||||||
|
return err;
|
||||||
|
""",
|
||||||
|
|
||||||
|
'vkCreateDevice': """
|
||||||
|
(void)physicalDevice;
|
||||||
|
(void)pCreateInfo;
|
||||||
|
(void)pAllocator;
|
||||||
|
(void)pDevice;
|
||||||
|
unimplemented ();
|
||||||
|
""",
|
||||||
|
|
||||||
|
'vkEnumeratePhysicalDevices': """
|
||||||
|
auto const entry = reinterpret_cast<
|
||||||
|
indirect<VkInstance,cruft::vk::icd::instance_table> const*
|
||||||
|
> (instance);
|
||||||
|
|
||||||
|
if (!pPhysicalDeviceCount || !pPhysicalDevices) {
|
||||||
|
return (entry->table.vkEnumeratePhysicalDevices)(
|
||||||
|
entry->handle, pPhysicalDeviceCount, pPhysicalDevices
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<VkPhysicalDevice> res (*pPhysicalDeviceCount);
|
||||||
|
auto err = (entry->table.vkEnumeratePhysicalDevices)(
|
||||||
|
entry->handle, pPhysicalDeviceCount, res.data ()
|
||||||
|
);
|
||||||
|
res.resize (*pPhysicalDeviceCount);
|
||||||
|
|
||||||
|
if (err != VK_SUCCESS)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < *pPhysicalDeviceCount; ++i) {
|
||||||
|
auto wrapped = std::make_unique<indirect<VkPhysicalDevice,cruft::vk::icd::instance_table>> ();
|
||||||
|
wrapped->handle = res[i];
|
||||||
|
|
||||||
|
#define GET(NAME) wrapped->table.NAME = wrapped->table.NAME ?: reinterpret_cast<decltype(&NAME)> (vkGetInstanceProcAddr (instance, #NAME));
|
||||||
|
MAP_INSTANCE_COMMANDS(GET)
|
||||||
|
#undef GET
|
||||||
|
|
||||||
|
pPhysicalDevices[i] = (VkPhysicalDevice)wrapped.release ();
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
|
||||||
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 obj.is_global(reg):
|
instance_forward = f"""
|
||||||
dst.write(f"""
|
return cruft::vk::icd::i_table->{obj.name} ({", ".join(p.name for p in obj.params)});
|
||||||
extern "C"
|
"""
|
||||||
{obj.result}
|
|
||||||
{rename(obj.name)} ({", ".join(p.param for p in obj.params)}) noexcept {{
|
if obj.is_instance(reg):
|
||||||
return cruft::vk::icd::g_table->{obj.name} ({", ".join(p.name for p in obj.params)});
|
|
||||||
}}
|
|
||||||
""")
|
|
||||||
continue
|
|
||||||
elif obj.is_instance(reg):
|
|
||||||
table = 'instance'
|
table = 'instance'
|
||||||
elif obj.is_device(reg):
|
elif obj.is_device(reg):
|
||||||
table = 'device'
|
table = 'device'
|
||||||
else:
|
else:
|
||||||
raise Exception("Unhandled command type")
|
raise Exception(f"Unhandled command type for {obj}")
|
||||||
|
|
||||||
if obj.params:
|
if obj.params:
|
||||||
last_param = obj.params[-1]
|
last_param = obj.params[-1]
|
||||||
@ -855,15 +944,20 @@ def write_dispatch(dst: TextIO, q: List[Type], reg: Registry):
|
|||||||
else:
|
else:
|
||||||
is_creating = False
|
is_creating = False
|
||||||
|
|
||||||
|
if obj.is_instance(reg) and obj.params[0].type not in ['VkInstance', 'VkPhysicalDevice']:
|
||||||
|
forwarding = f"return ::cruft::vk::icd::i_table->{obj.name} ({', '.join (i.name for i in obj.params)});"
|
||||||
|
else:
|
||||||
|
forwarding = f"""
|
||||||
|
auto const entry = reinterpret_cast<indirect<{obj.params[0].type},cruft::vk::icd::{table}_table> const*> ({obj.params[0].name});
|
||||||
|
|
||||||
|
return (entry->table.{obj.name})(
|
||||||
|
{", ".join(['entry->handle'] + [p.name for p in obj.params[1:]])}
|
||||||
|
);
|
||||||
|
"""
|
||||||
|
|
||||||
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 {{
|
||||||
auto const entry = reinterpret_cast<indirect const*> ({obj.params[0].name});
|
{implementations.get(obj.name, forwarding)}
|
||||||
auto const *table = reinterpret_cast<cruft::vk::icd::{table}_table const*> (entry->table);
|
|
||||||
|
|
||||||
return (table->{obj.name})(
|
|
||||||
reinterpret_cast<decltype({obj.params[0].name})> (entry->handle)
|
|
||||||
{", ".join([''] + [p.name for p in obj.params[1:]])}
|
|
||||||
);
|
|
||||||
}}
|
}}
|
||||||
""")
|
""")
|
||||||
|
|
||||||
@ -912,6 +1006,53 @@ def main():
|
|||||||
reg.types['VK_DEFINE_HANDLE'] = AliasType("VK_DEFINE_HANDLE", "void*")
|
reg.types['VK_DEFINE_HANDLE'] = AliasType("VK_DEFINE_HANDLE", "void*")
|
||||||
reg.types['VK_NULL_HANDLE'] = AliasValue("VK_NULL_HANDLE", "nullptr")
|
reg.types['VK_NULL_HANDLE'] = AliasValue("VK_NULL_HANDLE", "nullptr")
|
||||||
|
|
||||||
|
#reg.types['vk_icdGetInstanceProcAddr'] = Command(
|
||||||
|
# name='vk_icdGetInstanceProcAddr',
|
||||||
|
# result='void*',
|
||||||
|
# params=[
|
||||||
|
# Command.Param(
|
||||||
|
# name='instance',
|
||||||
|
# type='VkInstance',
|
||||||
|
# param='VkInstance instance',
|
||||||
|
# depends=['VkInstance']
|
||||||
|
# ),
|
||||||
|
# Command.Param(
|
||||||
|
# name='pName',
|
||||||
|
# type='void*',
|
||||||
|
# param='char const *pName',
|
||||||
|
# depends=[]
|
||||||
|
# ),
|
||||||
|
# ]
|
||||||
|
#)
|
||||||
|
#reg.types['vk_icdGetPhysicalDeviceProcAddr'] = Command(
|
||||||
|
# name='vk_icdGetPhysicalDeviceProcAddr',
|
||||||
|
# result='void*',
|
||||||
|
# params=[
|
||||||
|
# Command.Param(
|
||||||
|
# name='instance',
|
||||||
|
# type='VkInstance',
|
||||||
|
# param='VkInstance instance',
|
||||||
|
# depends=['VkInstance']
|
||||||
|
# ),
|
||||||
|
# Command.Param(
|
||||||
|
# name='pName',
|
||||||
|
# type='void*',
|
||||||
|
# param='char const *pName',
|
||||||
|
# depends=[]
|
||||||
|
# ),
|
||||||
|
# ]
|
||||||
|
#)
|
||||||
|
|
||||||
|
#icd = Feature(
|
||||||
|
# "__nerdcruft_icd",
|
||||||
|
# requires=[
|
||||||
|
# Require(None, ["vk_icdGetInstanceProcAddr"]),
|
||||||
|
# Require(None, ["vk_icdGetPhysicalDeviceProcAddr"])
|
||||||
|
# ]
|
||||||
|
#)
|
||||||
|
#reg.features['__nerdcruft_icd'] = icd
|
||||||
|
#reg.types['__nerdcruft_icd'] = reg.features['__nerdcruft_icd']
|
||||||
|
|
||||||
# Request serialisation of all features
|
# Request serialisation of all features
|
||||||
#features = [Feature(n) for n in root.findall('./feature')]
|
#features = [Feature(n) for n in root.findall('./feature')]
|
||||||
#features = dict((f.name,f) for f in features)
|
#features = dict((f.name,f) for f in features)
|
||||||
|
Loading…
Reference in New Issue
Block a user