tools/spec: pass files rather than paths to write_foo functions

This commit is contained in:
Danny Robson 2019-01-05 15:29:13 +11:00
parent 336e9632d3
commit deca2ded59

View File

@ -2,7 +2,7 @@
import sys import sys
import logging import logging
from typing import List, Dict, Set from typing import List, Dict, Set, TextIO
import xml.etree.ElementTree import xml.etree.ElementTree
@ -699,167 +699,167 @@ def parse_extensions(reg: Registry, root):
############################################################################### ###############################################################################
def write_header(path: str, q: List[Type], reg: Registry): def write_header(dst: TextIO, q: List[Type], reg: Registry):
with open(path, 'w') as dst: dst.write("#pragma once\n")
dst.write("#pragma once\n")
# Write the declarations and definitions for all types. # Write the declarations and definitions for all types.
for obj in q: for obj in q:
dst.write(obj.declare()) dst.write(obj.declare())
dst.write('\n') dst.write('\n')
dst.write(obj.define(reg)) dst.write(obj.define(reg))
dst.write('\n') dst.write('\n')
# Define the default case for device and instance type traits. # Define the default case for device and instance type traits.
dst.write(""" dst.write("""
#include <type_traits> #include <type_traits>
/// A type trait that tests if a Vulkan type is an instance type /// A type trait that tests if a Vulkan type is an instance type
template <typename NativeT> template <typename NativeT>
struct is_instance: struct is_instance:
public std::false_type public std::false_type
{}; {};
/// A type trait that tests if a Vulkan type is a device type /// A type trait that tests if a Vulkan type is a device type
template <typename NativeT> template <typename NativeT>
struct is_device: struct is_device:
public std::false_type public std::false_type
{}; {};
template <typename T> template <typename T>
constexpr auto is_instance_v = is_instance<T>::value; constexpr auto is_instance_v = is_instance<T>::value;
template <typename T> template <typename T>
constexpr auto is_device_v = is_device<T>::value; constexpr auto is_device_v = is_device<T>::value;
""")
# Specialise traits for device and instance types.
for obj in q:
if not isinstance(obj, Handle):
continue
device_value = "true_type" if obj.has_parent("VkDevice", reg) else "false_type"
instance_value = "true_type" if obj.has_parent("VkInstance", reg) else "false_type"
dst.write(f"""
template <> struct is_instance<{obj.name}>: public std::{instance_value} {{ }};
template <> struct is_device<{obj.name}>: public std::{device_value} {{ }};
""") """)
# Specialise traits for device and instance types.
for obj in q:
if not isinstance(obj, Handle):
continue
device_value = "true_type" if obj.has_parent("VkDevice", reg) else "false_type" # -----------------------------------------------------------------------------
instance_value = "true_type" if obj.has_parent("VkInstance", reg) else "false_type" 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)
dst.write(f"""
#include "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;
}};
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
))
dst.write("""};
struct device_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
))
dst.write("""
};
}
""")
# -----------------------------------------------------------------------------
def write_dispatch(dst: TextIO, q: List[Type], reg: Registry):
dst.write("""
#include "../vk.hpp"
#include "vtable.hpp"
#include "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;
}
""")
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):
dst.write(f""" dst.write(f"""
template <> struct is_instance<{obj.name}>: public std::{instance_value} {{ }};
template <> struct is_device<{obj.name}>: public std::{device_value} {{ }};
""")
# -----------------------------------------------------------------------------
def write_icd(path: str, q: List[Type], reg: Registry):
with open(path, 'w') as icd:
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 <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;
}};
struct instance_table {{
instance_table (vendor &);
""")
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("""
};
}
""")
# -----------------------------------------------------------------------------
def write_dispatch(path: str, q: List[Type], reg: Registry):
with open(path, 'w') as dispatch:
dispatch.write("""
#include "../vk.hpp"
#include "vtable.hpp"
#include "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;
}
""")
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):
dispatch.write(f"""
extern "C" {obj.result} {rename(obj.name)} ({", ".join(p.param for p in obj.params)}) noexcept {{
unimplemented ();
}}""")
continue
if first_arg.has_parent('VkDevice', reg):
table = "d_table"
elif first_arg.has_parent('VkInstance', reg):
table = 'i_table'
else:
raise Exception("Unknown param type")
dispatch.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})>; unimplemented ();
}}""")
continue
if constexpr (is_instance_v<first_arg_t>) {{ if first_arg.has_parent('VkDevice', reg):
auto const entry = reinterpret_cast<cruft::vk::icd::func const*> ({obj.params[0].name}); table = "d_table"
auto const *table = reinterpret_cast<decltype({table})> (entry->table); elif first_arg.has_parent('VkInstance', reg):
table = 'i_table'
else:
raise Exception("Unknown param type")
return (table->{obj.name})( dst.write(f"""
reinterpret_cast<decltype({obj.params[0].name})> (entry->handle) extern "C" {obj.result} {rename(obj.name)} ({", ".join(p.param for p in obj.params)}) noexcept {{
{", ".join([''] + [p.name for p in obj.params[1:]])} using first_arg_t = std::decay_t<decltype({obj.params[0].name})>;
);
}} else {{ if constexpr (is_instance_v<first_arg_t>) {{
unimplemented (); 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:]])}
);
}} else {{
unimplemented ();
}} }}
""") }}
""")
############################################################################### ###############################################################################
@ -918,9 +918,14 @@ def main():
q = reg.serialise(args.platform) q = reg.serialise(args.platform)
# Finally write out the header, icd, and dispatch code. # Finally write out the header, icd, and dispatch code.
write_header(args.dst, q, reg) with open(args.dst, 'w') as dst:
write_icd(args.icd, q, reg) write_header(dst, q, reg)
write_dispatch(args.dispatch, q, reg)
with open(args.icd, 'w') as dst:
write_icd(dst, q, reg)
with open(args.dispatch, 'w') as dst:
write_dispatch(dst, q, reg)
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------