const {
getFieldsInformation
} = require('./utils');
const { EXTENSIONS } = require('./data');
function generateFunctionTableDefinition(functions) {
for (let func of functions) {
if (!func.argsInfo) {
func.argsInfo = getFieldsInformation(func.args);
}
}
return [
`#![allow(non_snake_case)]`,
genUses(functions),
genDefinition(functions),
genFromMethods(functions),
genNullFunctions(functions),
genExterns(functions)
];
}
const FUNCTION_TABLE_NAME = 'VkFunctionTable';
function genUses() {
return [
`std::os::raw::c_char`,
`std::mem`,
`utils::c_bindings::*`,
`utils::vk_convert::{get_vk_instance_function_pointer, get_vk_device_function_pointer}`,
'vulkan::vk::*',
`vulkan::{${EXTENSIONS.map(str => str.toLowerCase()).join(',')}}`
].map(x => `use ${x};`);
}
function genDefinition(functions) {
return [
`#[doc(hidden)]`,
`pub struct ${FUNCTION_TABLE_NAME}`, [
`pub instance: RawVkInstance,`,
`pub device: RawVkDevice,`,
...functions.map(func => `pub ${func.name}: ${functionToDeclaration(func)},`)
]
];
}
function getArgType(arg) {
let type = arg.rawType;
if (arg.extension) {
type = type.replace(arg.rawTypeName, `${arg.extension}::${arg.rawTypeName}`)
}
return type;
}
function functionToDeclaration(func) {
const args = func.argsInfo.map(getArgType);
const returnType = func.type === 'VkResult' ? ' -> RawVkResult' : '';
return `unsafe extern fn(${args.join(', ')})${returnType}`;
}
function getVkFunctionPrototype(func) {
const args = func.argsInfo.map(arg => `${arg.varName}: ${getArgType(arg)}`);
const returnType = func.type === 'VkResult' ? ' -> RawVkResult' : '';
return `(${args.join(', ')})${returnType}`;
}
function genNullFunctions(functions) {
return genNullFunctionsForParent(functions, 'instance').concat(genNullFunctionsForParent(functions, 'device'));
}
function genNullFunctionsForParent(functions, parent) {
return functions.filter(func => func.name.startsWith('vk')).map(func => {
const funcName = `null_${parent}_${func.name}`;
return [
`unsafe extern fn ${funcName}${getVkFunctionPrototype(func)}`, [
`panic!("\\"vkGet${parent.capitalize()}ProcAddr\\" returned NULL for \\"${func.name}\\"");`
]
];
}).reduce((acc, value) => acc.concat(value), []);
}
function getFunctionPointer(func, parent) {
if (func.name.startsWith('vk')) {
return `{ let fn_ptr = get_vk_${parent}_function_pointer(${parent}, "${func.name}"); if fn_ptr.is_null() { null_${parent}_${func.name} } else { mem::transmute(fn_ptr) } }`;
} else {
return func.name;
}
}
function genFromMethods(functions) {
return [
`impl ${FUNCTION_TABLE_NAME}`, [
`pub fn from_instance(instance: RawVkInstance) -> Self`, [
`unsafe`, [
`Self`, [
`instance: instance,`,
`device: 0,`,
...functions.map(func => `${func.name}: ${getFunctionPointer(func, 'instance')},`)
]
]
],
`pub fn from_device(device: RawVkDevice) -> Self`, [
`unsafe`, [
`Self`, [
`instance: 0,`,
`device: device,`,
...functions.map(func => `${func.name}: ${getFunctionPointer(func, 'device')},`)
]
]
]
]
]
}
function genExterns(functions) {
const externs = functions.filter(func => !func.name.startsWith('vk'));
if (externs.length) {
return [
`extern`,
externs.map(func => `fn ${func.name}${getVkFunctionPrototype(func)};`)
]
}
}
module.exports = {
generateFunctionTableDefinition,
getVkFunctionPrototype
};