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
icd/fwd.hpp
${CMAKE_CURRENT_BINARY_DIR}/icd/vtable.hpp
${CMAKE_CURRENT_BINARY_DIR}/icd/dispatch.cpp
icd/vendor.hpp
icd/vendor.cpp
icd/vendor_${VK_LOADER_VENDOR}
icd/vtable.cpp
)
target_link_libraries (cruft-vk-icd cruft-json cruft)

0
icd/fwd.hpp Normal file
View File

View File

@ -1,45 +1,46 @@
#pragma once
#include "vk.hpp"
#include <cruft/util/library.hpp>
#include <string>
#include <experimental/filesystem>
///////////////////////////////////////////////////////////////////////////////
namespace cruft::vk::icd {
struct icd_t {
std::string file_format_version;
struct {
std::experimental::filesystem::path library_path;
std::string api_version;
} icd;
};
std::vector<icd_t>
enumerate (void);
class vendor {
public:
vendor (icd_t const&);
vendor (::cruft::library &&);
struct vtable_t {
VkResult (*CreateInstance) (
VkInstanceCreateInfo const*,
VkAllocationCallbacks const*,
VkInstance*
) noexcept;
} vtable;
private:
using get_proc_t = void* (*)(VkInstance, char const*);
::cruft::library m_library;
get_proc_t const m_get_proc;
};
}
#pragma once
#include "vk.hpp"
#include <cruft/util/library.hpp>
#include <string>
#include <experimental/filesystem>
///////////////////////////////////////////////////////////////////////////////
namespace cruft::vk::icd {
struct icd_t {
std::string file_format_version;
struct {
std::experimental::filesystem::path library_path;
std::string api_version;
} icd;
};
std::vector<icd_t>
enumerate (void);
class vendor {
public:
vendor (icd_t const&);
vendor (::cruft::library &&);
struct vtable_t {
VkResult (*CreateInstance) (
VkInstanceCreateInfo const*,
VkAllocationCallbacks const*,
VkInstance*
) noexcept;
} vtable;
private:
::cruft::library m_library;
public:
using get_proc_t = void* (*)(VkInstance, char const*);
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/.
*
* Copyright:
* 2017, Danny Robson <danny@nerdcruft.net>
* 2017-2018, Danny Robson <danny@nerdcruft.net>
*/
#include <cruft/util/iterator.hpp>
@ -17,6 +17,7 @@
#include "../icd/vendor.hpp"
#include "icd/vtable.hpp"
///////////////////////////////////////////////////////////////////////////////
@ -25,6 +26,7 @@ main (int, char**)
{
for (auto const &i: cruft::vk::icd::enumerate ()) {
cruft::vk::icd::vendor v (i);
cruft::vk::icd::instance_table t (v);
//std::cout << "available_layers: [ "
// << cruft::make_infix (cruft::vk::instance::available_layers ())

View File

@ -229,6 +229,7 @@ class handle(type):
super().__init__(name, depends=[type])
self.type = type
self.parent = node.attrib.get('parent', None)
def declare(self):
return "struct %(name)s_t; using %(name)s = %(name)s_t*;" % {
@ -236,6 +237,20 @@ class handle(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):
def __init__(self,node):
@ -395,10 +410,14 @@ class command(type):
**kwargs
)
self.type = ""
self.type = node.find('type').text
self.param = ""
for i in node.iter():
self.type += i.text or ""
self.type += i.tail or ""
self.param += i.text or ""
self.param += i.tail or ""
# normalise whitespace
self.param = " ".join(self.param.split())
def __init__(self, node):
assert node.tag == "command"
@ -416,9 +435,43 @@ class command(type):
return "%(result)s %(name)s (%(params)s) noexcept;" % {
'name': rename(self.name),
'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):
def __init__(self, root):
@ -586,7 +639,7 @@ def parse_types(reg:registry, root):
]
if category in supported_categories:
obj = globals()[category] (t)
obj = globals()[category](t)
reg.types[name] = obj
else:
raise 'unhandled type'
@ -729,17 +782,43 @@ if __name__ == '__main__':
dst.write('}\n')
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"
namespace cruft::vk::icd {
struct vtable {
#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 {{
struct vendor;
struct func {{
void *handle;
void const *table;
}};
struct instance_table {{
instance_table (vendor &);
""")
for obj in q:
if not isinstance(obj, command):
continue
icd.write(f"{obj.result} (*{obj.name}) ({','.join(p.type for p in obj.params)});\n")
for obj in instance_commands:
icd.write(f"{obj.result} (*{obj.name}) ({','.join(p.param for p in obj.params)}) = nullptr;\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("""
};
@ -756,16 +835,25 @@ if __name__ == '__main__':
#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 q:
if not isinstance(obj, command):
continue
for obj in commands:
if obj.is_instance(reg):
table = "i_table"
elif obj.is_device(reg):
table = "d_table"
else:
raise Exception("unhandled command type")
dispatch.write(f"""
extern "C" {obj.result} {rename(obj.name)} ({", ".join(p.type for p in obj.params)}) noexcept {{
return (*s_vtable->{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 {{
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:])}
);
""")