icd: add initial instance and device vtables

This commit is contained in:
Danny Robson 2018-09-10 13:21:02 +10:00
parent 26c9c3f70d
commit b8f405c134
6 changed files with 173 additions and 66 deletions

View File

@ -63,11 +63,13 @@ endif()
##----------------------------------------------------------------------------- ##-----------------------------------------------------------------------------
add_library (cruft-vk-icd STATIC add_library (cruft-vk-icd STATIC
icd/fwd.hpp
${CMAKE_CURRENT_BINARY_DIR}/icd/vtable.hpp ${CMAKE_CURRENT_BINARY_DIR}/icd/vtable.hpp
${CMAKE_CURRENT_BINARY_DIR}/icd/dispatch.cpp ${CMAKE_CURRENT_BINARY_DIR}/icd/dispatch.cpp
icd/vendor.hpp icd/vendor.hpp
icd/vendor.cpp icd/vendor.cpp
icd/vendor_${VK_LOADER_VENDOR} icd/vendor_${VK_LOADER_VENDOR}
icd/vtable.cpp
) )
target_link_libraries (cruft-vk-icd cruft-json cruft) target_link_libraries (cruft-vk-icd cruft-json cruft)

0
icd/fwd.hpp Normal file
View File

View File

@ -37,9 +37,10 @@ namespace cruft::vk::icd {
} vtable; } vtable;
private: private:
using get_proc_t = void* (*)(VkInstance, char const*);
::cruft::library m_library; ::cruft::library m_library;
public:
using get_proc_t = void* (*)(VkInstance, char const*);
get_proc_t const m_get_proc; get_proc_t const m_get_proc;
}; };
} }

14
icd/vtable.cpp Normal file
View File

@ -0,0 +1,14 @@
#include "icd/vtable.hpp"
#include "vendor.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")
);
}

View File

@ -4,7 +4,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
* *
* Copyright: * Copyright:
* 2017, Danny Robson <danny@nerdcruft.net> * 2017-2018, Danny Robson <danny@nerdcruft.net>
*/ */
#include <cruft/util/iterator.hpp> #include <cruft/util/iterator.hpp>
@ -17,6 +17,7 @@
#include "../icd/vendor.hpp" #include "../icd/vendor.hpp"
#include "icd/vtable.hpp"
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -25,6 +26,7 @@ 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);
//std::cout << "available_layers: [ " //std::cout << "available_layers: [ "
// << cruft::make_infix (cruft::vk::instance::available_layers ()) // << cruft::make_infix (cruft::vk::instance::available_layers ())

View File

@ -229,6 +229,7 @@ class handle(type):
super().__init__(name, depends=[type]) super().__init__(name, depends=[type])
self.type = type self.type = type
self.parent = node.attrib.get('parent', None)
def declare(self): def declare(self):
return "struct %(name)s_t; using %(name)s = %(name)s_t*;" % { return "struct %(name)s_t; using %(name)s = %(name)s_t*;" % {
@ -236,6 +237,20 @@ class handle(type):
"type": self.type "type": self.type
} }
def has_parent(self, name:str, reg:registry) -> bool:
"""
Recursively check if this type is derived from a given parent type.
"""
assert name
assert reg
if not self.parent:
return False
if self.parent == name:
return True
return reg.types[self.parent].has_parent(name, reg)
class enum(type): class enum(type):
def __init__(self,node): def __init__(self,node):
@ -395,10 +410,14 @@ class command(type):
**kwargs **kwargs
) )
self.type = "" self.type = node.find('type').text
self.param = ""
for i in node.iter(): for i in node.iter():
self.type += i.text or "" self.param += i.text or ""
self.type += i.tail or "" self.param += i.tail or ""
# normalise whitespace
self.param = " ".join(self.param.split())
def __init__(self, node): def __init__(self, node):
assert node.tag == "command" assert node.tag == "command"
@ -416,9 +435,43 @@ class command(type):
return "%(result)s %(name)s (%(params)s) noexcept;" % { return "%(result)s %(name)s (%(params)s) noexcept;" % {
'name': rename(self.name), 'name': rename(self.name),
'result': self.result, 'result': self.result,
'params': ", ".join(p.type for p in self.params) 'params': ", ".join(p.param for p in self.params)
} }
def is_instance(self, reg:registry):
assert reg
if not self.params:
return True
first_arg = self.params[0].type
if first_arg == 'VkInstance':
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):
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
def is_device(self, reg:registry):
return not self.is_instance(reg)
class require(object): class require(object):
def __init__(self, root): def __init__(self, root):
@ -586,7 +639,7 @@ def parse_types(reg:registry, root):
] ]
if category in supported_categories: if category in supported_categories:
obj = globals()[category] (t) obj = globals()[category](t)
reg.types[name] = obj reg.types[name] = obj
else: else:
raise 'unhandled type' raise 'unhandled type'
@ -729,17 +782,43 @@ if __name__ == '__main__':
dst.write('}\n') dst.write('}\n')
with open(args.icd, 'w') as icd: with open(args.icd, 'w') as icd:
icd.write(""" 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 "vk.hpp"
namespace cruft::vk::icd { #include <cruft/util/preprocessor.hpp>
struct vtable {
#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 {{
struct vendor;
struct func {{
void *handle;
void const *table;
}};
struct instance_table {{
instance_table (vendor &);
""") """)
for obj in q: for obj in instance_commands:
if not isinstance(obj, command): icd.write(f"{obj.result} (*{obj.name}) ({','.join(p.param for p in obj.params)}) = nullptr;\n")
continue
icd.write(f"{obj.result} (*{obj.name}) ({','.join(p.type for p in obj.params)});\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(""" icd.write("""
}; };
@ -756,16 +835,25 @@ if __name__ == '__main__':
#pragma GCC diagnostic ignored "-Wunused-parameter" #pragma GCC diagnostic ignored "-Wunused-parameter"
static cruft::vk::icd::vtable *s_vtable = nullptr; static cruft::vk::icd::instance_table const *i_table = nullptr;
static cruft::vk::icd::device_table const *d_table = nullptr;
""") """)
for obj in commands:
for obj in q: if obj.is_instance(reg):
if not isinstance(obj, command): table = "i_table"
continue elif obj.is_device(reg):
table = "d_table"
else:
raise Exception("unhandled command type")
dispatch.write(f""" dispatch.write(f"""
extern "C" {obj.result} {rename(obj.name)} ({", ".join(p.type for p in obj.params)}) noexcept {{ extern "C" {obj.result} {rename(obj.name)} ({", ".join(p.param for p in obj.params)}) noexcept {{
return (*s_vtable->{obj.name})({", ".join(p.name for p in obj.params)}); auto const entry = reinterpret_cast<cruft::vk::icd::func const*> ({obj.params[0].name});
}} auto const *table = reinterpret_cast<decltype({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:])}
);
""") """)