Continuing here with the restoring process for my NervLand project: as mentioned at the end of my last post, I now need to retore my “NervBind” application to generate some lua bindings automagically: let's get started.
load_library()
,unload_library()
and unload_all_libraries()
: so let's use those methods instead.$ nvp nvl bind_core
#pragma clang diagnostic ignored “-Wundefined-var-template”
in the register_package.cpp to avoid too many warnings on template forward declarations.[2022-09-19 21:08:11.463] [debug] Binding for nv::operator* [2022-09-19 21:08:11.465] [debug] Binding for std::operator<< [2022-09-19 21:08:11.465] [critical] Error in lua app: [string "bind.FunctionWriter"]:287: attempt to index local 'rtype' (a nil value) stack traceback: [string "bind.FunctionWriter"]:287: in function 'writeFunctionOverload' [string "bind.FunctionWriter"]:190: in function 'writeFunctionBinds' [string "bind.FunctionWriter"]:57: in function 'writeFunctionBindings' [string "bind.GlobalFunctionsWriter"]:27: in function 'writeContent' [string "bind.GlobalFunctionsWriter"]:6: in function '__init' [string "setup.lua"]:160: in function <[string "setup.lua"]:152> [string "app.NervBind"]:243: in function 'writeBindings' [string "app.NervBind"]:199: in function 'run' [string "app.AppBase"]:23: in function '__init' [string "app.NervBind"]:12: in function '__init' [string "setup.lua"]:160: in function 'app' [string "run.lua"]:65: in function <[string "run.lua"]:63> [C]: in function 'xpcall'
-- Return type cannot be nil: CHECK(rtype ~= nil, "Invalid return type for signature: ", signame) sig:setReturnType(rtype)
[2022-09-19 21:29:59.527] [debug] Type kind: Unexposed [2022-09-19 21:29:59.527] [debug] Converting type name 'conditional<is_reference_v<_Ty>, type-parameter-0-0, const typename remove_reference<type-parameter-0-0>::type>::type' to template contextual name: conditional<is_reference_v<${}${_Ty}${}>,${} $${}{_Ty}${}, const typename remove_reference<${}${_Ty}${}>:${}:type>${}::type@std::_Atomic_storage with 2 template parameters. [2022-09-19 21:29:59.527] [debug] Creating template type conditional<is_reference_v<${}${_Ty}${}>,${} $${}{_Ty}${}, const typename remove_reference<${}${_Ty}${}>:${}:type>${}::type@std::_Atomic_storage with 2 template parameters [2022-09-19 21:29:59.528] [debug] TypeManager: Registering type { "conditional<is_reference_v<${}${_Ty}${}>,${} $${}{_Ty}${}, const typename remove_reference<${}${_Ty}${}>:${}:type>${}::type@std::_Atomic_storage" } [2022-09-19 21:29:59.529] [debug] Type already registered for 'conditional<is_reference_v<${}${_Ty}${}>,${} $${}{_Ty}${}, const typename remove_reference<${}${_Ty}${}>:${}:type>${}::type@std::_Atomic_storage' [2022-09-19 21:29:59.529] [debug] Default value cursor is defined at: D:\Softs\VisualStudio2022CE\VC\Tools\MSVC\14.32.31326\include\atomic:491:60:19868 [2022-09-19 21:29:59.529] [critical] [FATAL] Invalid name for cursor of kind OverloadedDeclRef stack traceback: [string "setup.lua"]:203: in function 'THROW' [string "setup.lua"]:198: in function 'CHECK' [string "bind.Clang"]:75: in function 'getFullName' [string "bind.ClangParser"]:1060: in function 'resolveArgument' [string "bind.ClangParser"]:1195: in function 'parseFunction' [string "bind.ClangParser"]:1431: in function <[string "bind.ClangParser"]:1355> [C]: in function 'visitChildren' [string "bind.ClangParser"]:1355: in function 'parseClassTemplate' [string "bind.ClangParser"]:1567: in function <[string "bind.ClangParser"]:1524> [C]: in function 'visitChildren' [string "bind.ClangParser"]:1524: in function 'parseNamespace' ... [string "bind.ClangParser"]:1524: in function 'parseNamespace' [string "bind.ClangParser"]:1602: in function 'parseFile' [string "app.NervBind"]:169: in function 'parseInputs' [string "app.NervBind"]:189: in function 'run' [string "app.AppBase"]:23: in function '__init' [string "app.NervBind"]:12: in function '__init' [string "setup.lua"]:160: in function 'app' [string "run.lua"]:65: in function <[string "run.lua"]:63> [C]: in function 'xpcall' [string "run.lua"]:68: in main chunk (at D:/Projects/NervLand/sources/nvCore/src/lua/nerv_bindings.cpp:27) [2022-09-19 21:29:59.531] [error] Error in cursorVisitor: C++ exception
[2022-09-20 12:08:41.558] [debug] Registering type for class name type_info [2022-09-20 12:08:41.559] [debug] TypeManager: Registering type { "type_info" } [2022-09-20 12:08:41.559] [debug] Done registering class type_info [2022-09-20 12:08:41.559] [debug] Parsing type_info [2022-09-20 12:08:41.559] [debug] Visiting children of type_info
isLocationParseable(cursor)
on it will crash ?SOL_CUSTOM_FUNC(getSpelling) = [](class_t& obj) { if (clang_equalLocations(obj, clang_getNullLocation()) != 0) { // This is an invalid location: std::string filestr(""); U32 line = 0; U32 column = 0; U32 offset = 0; return std::tuple(filestr, line, column, offset); } CXFile file; U32 line; U32 column; U32 offset; std::cout << "=>getSpellingLocation" << std::endl; clang_getSpellingLocation(obj, &file, &line, &column, &offset); // We try to retrieve the real file name first if possible: std::cout << "=>clang_File_tryGetRealPathName" << std::endl; CXString filename = clang_File_tryGetRealPathName(file); std::cout << "=>clang_getCString" << std::endl; std::string filestr(clang_getCString(filename)); clang_disposeString(filename); if (filestr.empty()) { std::cout << "=>clang_getFileName" << std::endl; filename = clang_getFileName(file); std::cout << "=>clang_getCString" << std::endl; filestr = clang_getCString(filename); clang_disposeString(filename); } std::cout << "=>return tuple" << std::endl; return std::tuple(filestr, line, column, offset); };
[2022-09-20 18:15:08.698] [debug] Adding name std::locale::facet * to type { "std::locale::facet" }
while tname:endsWith("%s*&") do local n = t:getName().."&" local newType = typeManager:getType(n) if not newType then logDEBUG("Type inference: ", "Auto generating reference type: ", n) newType = Type(n) newType:setBaseType(t) newType:addReference() end t = newType tname = tname:gsub("%s*&$","") end
hasNameRaw(name)
method below: function Class:hasNameRaw(name) for _,n in ipairs(self._names) do if n == name then return true end end return false end
const char*&
type, fixed there: if self:isChar() then if self:isConst() and self:getPointerCount()==1 and not self:isReference() then -- This is a char pointer, so we expect to get a string: return import("reflection.lua.ConstCharPtrConverter") elseif self:getPointerCount()==0 then return import("reflection.lua.CharConverter") end end
local allowedClasses = { "^nv::Vec", "^nv::RefObject", "^nv::AppComponent" } local ignoreClasses = function(ent) local name = ent:getFullName() if name == "void" then -- Keep the class. return end -- for _,p in ipairs(ignoredEntities) do -- if name:find(p) then -- ent:setIgnored(true) -- logDEBUG("=> Ignoring entity ", name) -- return -- end -- end for _,p in ipairs(allowedClasses) do if name:find(p) then return end end -- Ignore this entity: ent:setIgnored(true) -- logDEBUG("=> Ignoring entity ", name) return end
luna_dumpStack()
with luna::dumpStack()
operator“”
: D:/Projects/NervLand/sources/lua_bindings/Core/src/luna/register_functions.cpp:112:31: error: expected ';' after top level declarator static bool _check_nv_operator""_sid_sig1(lua_State* L) { ^ ; 1 error generated.
cfg.cmakeConfig = { includeDirs = {"../include" }, libDirs = {}, libs = {"nvCore"} }
D:/Projects/NervLand/sources/lua_bindings/Core/src/luna/bind_nv_SDLWindow.cpp:241:13: error: no matching constructor for initialization of 'nv::SDLWindow' return new nv::SDLWindow(*traits); ^ ~~~~~~~ D:/Projects/NervLand/sources/nvCore/src\view/SDLWindow.h:13:24: note: candidate constructor not viable: no known conversion from 'nv::Window::Traits' to 'const nv::SDLWindow' for 1st argument NV_DECLARE_NO_COPY(SDLWindow)
$ nvp nvl sdlapp
[2022-09-21 21:03:15.123] [debug] Loading bindings for Core with libname luaCore [2022-09-21 21:03:15.123] [debug] Loading dynamic library: luaCore.dll [2022-09-21 21:03:15.123] [debug] NervApp: load_library... [2022-09-21 21:03:15.123] [debug] lib file: modules/luaCore.dll [2022-09-21 21:03:15.140] [debug] Opened DynamicLibrary modules/luaCore.dll [2022-09-21 21:03:15.140] [critical] [FATAL] No lua bindings could be loaded for Core stack traceback: [string "setup.lua"]:203: in function 'THROW' [string "setup.lua"]:198: in function 'CHECK' [string "base.BindingsManager"]:43: in function 'loadBindings' [string "app.SDLApp"]:11: in function 'init'
cfg.moduleName = "luaCore" cfg.bindingName = "Core" -- define asLuaModule to create a regular lua module: -- cfg.moduleName = "luaCore" -- cfg.asLuaModule = true
[2022-09-22 12:21:55.154] [critical] Error in lua app: [string "app.SDLApp"]:22: Cannot find field 'title' in class 'nv.Window.Traits' stack traceback: [C]: in function '__newindex' [string "app.SDLApp"]:22: in function 'init'
-- We manually register the types that should be available directly: -- typeManager:addType("std::string", Type("std::string", "std::string")) typeManager:addLuaConverter("std::string", import("reflection.lua.StringConverter")) typeManager:addLuaConverter("nv::String", import("reflection.lua.StringConverter")) typeManager:addLuaConverter("luna::LuaFunction", import("reflection.lua.LuaFunctionConverter"))
namespace luna { template <> struct luna_provider<nv::RefObject> { typedef nv::RefPtr<nv::RefObject> container_t; static nv::RefObject *get(const container_t &cont) { return cont.get(); }; static void set(container_t &cont, nv::RefObject *ptr) { cont = ptr; }; static nv::RefObject *release(container_t &cont) { return cont.release(); }; static void destruct(container_t &cont) { cont.reset(); }; }; };
#ifndef COMPILE_CONTEXT_ #define COMPILE_CONTEXT_ // Write here the content that should be provided during compilation. #include <core_common.h> // Add support for RefPtr container usage for RefObjects: namespace luna { template <> struct luna_provider<nv::RefObject> { using container_t = nv::RefPtr<nv::RefObject>; static auto get(const container_t& cont) -> nv::RefObject* { return cont.get(); }; static void set(container_t& cont, nv::RefObject* ptr) { cont = ptr; }; static auto release(container_t& cont) -> nv::RefObject* { return cont.release(); }; static void destruct(container_t& cont) { cont.reset(); }; }; }; // namespace luna #endif/
namespace luna { // template <typename T, uint64_t U> class luna_provider; template <typename T> struct luna_prov_base<T, typename std::enable_if< std::is_base_of<nv::RefObject, T>::value>::type> { using type = nv::RefObject; }; template <typename T> struct luna_prov_base<T, typename std::enable_if< !std::is_base_of<nv::RefObject, T>::value>::type> { using type = T; }; template <> struct luna_provider<nv::RefObject> { using container_t = nv::RefPtr<nv::RefObject>; static auto get(const container_t& cont) -> nv::RefObject* { return cont.get(); }; static void set(container_t& cont, nv::RefObject* ptr) { logINFO("Acquiring RefObject at {}", (const void*)ptr); cont = ptr; }; static auto release(container_t& cont) -> nv::RefObject* { logINFO("Releasing RefObject at {}", (const void*)cont.get()); return cont.release(); }; static void destruct(container_t& cont) { logINFO("Resetting RefObject at {}", (const void*)cont.get()); cont.reset(); }; }; }; // namespace luna
template <> struct luna_base<nv::SDLWindowManager> { using type = nv::RefObject; };
function Class:writeBindProviderBases(classes) self:writeLine[[#ifndef BIND_BASES_ #define BIND_BASES_ #include <lua/luna.h> namespace luna { ]] cfg = luna:getConfig() cprovs = cfg.custom_providers or {} local check_provider = function(cl) bnames = cl:getRootBaseNames() for _,bname in ipairs(bnames) do for _,cprov in ipairs(cprovs) do if bname == cprov then -- logINFO("Writting custom provider for ", cl:getFullName()) self:writeSubLine("template <> struct luna_base<${1}> { using type = ${2}; };", cl:getFullName(), cprov) return end end end end for _,cl in ipairs(classes) do -- Get the root base of this class: check_provider(cl) -- logINFO("Got root base names: ", bnames) end self:newLine() self:writeLine("}\n") self:writeLine("#endif\n") self:writeOutputFile("include/bind_bases.h") self:reset() end
#ifndef BIND_BASES_ #define BIND_BASES_ #include <lua/luna.h> namespace luna { template <> struct luna_base<nv::RefObject> { using type = nv::RefObject; }; template <> struct luna_base<nv::AppComponent> { using type = nv::RefObject; }; template <> struct luna_base<nv::EventHandler> { using type = nv::RefObject; }; template <> struct luna_base<nv::Window> { using type = nv::RefObject; }; template <> struct luna_base<nv::SDLWindow> { using type = nv::RefObject; }; template <> struct luna_base<nv::WindowManager> { using type = nv::RefObject; }; template <> struct luna_base<nv::SDLWindowManager> { using type = nv::RefObject; }; } #endif
-- custom providers in this module: cfg.custom_providers = {"nv::RefObject"}
function Class:init() logDEBUG("Loading Vulkan bindings...") bm:loadBindings("Vulkan", "luaVulkan") -- Create the Library: local vk = nv.vulkan local lib = vk.Library.instance();
lld-link: error: undefined symbol: public: static unsigned __int64 const luna::LunaTraits<class nv::STLAllocator<char, class nv::DefaultPoolAllocator>>::id >>> referenced by sources/lua_bindings/Vulkan/src/CMakeFiles/luaVulkan.dir/luna/register_package.cpp.obj:(public: static void __cdecl luna::Luna<class nv::STLAllocator<char, class nv::DefaultPoolAllocator>>::Register(struct lua_State *)) >>> referenced by sources/lua_bindings/Vulkan/src/CMakeFiles/luaVulkan.dir/luna/register_package.cpp.obj:(<auto> __cdecl luna::luna_toUserData<class nv::STLAllocator<char, class nv::DefaultPoolAllocator>>(struct lua_State *, int)) >>> referenced by sources/lua_bindings/Vulkan/src/CMakeFiles/luaVulkan.dir/luna/register_package.cpp.obj:(public: static void __cdecl luna::Luna<class nv::STLAllocator<char, class nv::DefaultPoolAllocator>>::push(struct lua_State *, class nv::STLAllocator<char, class nv::DefaultPoolAllocator> const *, bool)) lld-link: error: undefined symbol: public: static char const *const luna::LunaTraits<class nv::STLAllocator<char, class nv::DefaultPoolAllocator>>::fullName >>> referenced by sources/lua_bindings/Vulkan/src/CMakeFiles/luaVulkan.dir/luna/register_package.cpp.obj:(public: static void __cdecl luna::Luna<class nv::STLAllocator<char, class nv::DefaultPoolAllocator>>::Register(struct lua_State *)) >>> referenced by sources/lua_bindings/Vulkan/src/CMakeFiles/luaVulkan.dir/luna/register_package.cpp.obj:(public: static void __cdecl luna::Luna<class nv::STLAllocator<char, class nv::DefaultPoolAllocator>>::Register(struct lua_State *)) >>> referenced by sources/lua_bindings/Vulkan/src/CMakeFiles/luaVulkan.dir/luna/register_package.cpp.obj:(public: static int __cdecl luna::Luna<class nv::STLAllocator<char, class nv::DefaultPoolAllocator>>::set_index(struct lua_State *)) >>> referenced 1 more times lld-link: error: undefined symbol: public: static char const *const luna::LunaTraits<class nv::STLAllocator<char, class nv::DefaultPoolAllocator>>::className >>> referenced by sources/lua_bindings/Vulkan/src/CMakeFiles/luaVulkan.dir/luna/register_package.cpp.obj:(public: static void __cdecl luna::Luna<class nv::STLAllocator<char, class nv::DefaultPoolAllocator>>::Register(struct lua_State *)) >>> referenced by sources/lua_bindings/Vulkan/src/CMakeFiles/luaVulkan.dir/luna/register_package.cpp.obj:(public: static void __cdecl luna::Luna<class nv::STLAllocator<char, class nv::DefaultPoolAllocator>>::push(struct lua_State *, class nv::STLAllocator<char, class nv::DefaultPoolAllocator> const *, bool)) >>> referenced by sources/lua_bindings/Vulkan/src/CMakeFiles/luaVulkan.dir/luna/register_package.cpp.obj:(public: static void __cdecl luna::Luna<class nv::STLAllocator<char, class nv::DefaultPoolAllocator>>::push(struct lua_State *, class nv::STLAllocator<char, class nv::DefaultPoolAllocator> const *, bool))
Luna< nv::QueueInfo >::Register(L); Luna< nv::QueueFamilyInfo >::Register(L); Luna< nv::Vector<float> >::Register(L); Luna< nv::VulkanMemoryRange >::Register(L); Luna< nv::VulkanWindowParameters >::Register(L); Luna< nv::STLAllocator<char> >::Register(L); Luna< nv::String >::Register(L); Luna< nv::DefaultPoolAllocator >::Register(L);
nv::STLAllocator<char>
was already found while building luaCore, but I ignored that class on purpose: should do the same here (it comes from the nv::String definition by the way)Luna<class_t>::get()
: that method will use the LunaTraits<class_t>::id
and also access the provider in use fro class_t so we need those 2 elements available even if we are not binding class_t to be able to get() it.Luna<class_t>::push()
, which itself will use traits_t::className
, traits_t::namespaces
, traits_t::id
, traits_t::baseIDs
template<> struct LunaTraits< nv::WindowManager > { using root_t = nv::RefObject; constexpr const char className[] = "WindowManager"; constexpr const char fullName[] = "nv.WindowManager"; constexpr const char* namespaces[] = {"nv",0}; constexpr const char* parents[] = {"nv.AppComponent",0}; constexpr LunaID id = LUNA_SID("nv::WindowManager"); constexpr LunaID baseIDs[] = {LUNA_SID("nv::AppComponent"),LUNA_SID("nv::EventHandler"),LUNA_SID("nv::RefObject"),0}; }
LunaTraits<T>
specialization written in the common include/${module_name}_classes.h file, and I keep the methods/fields descriped in a LunaBehavior<t>
class.local path = import "pl.path" local bind_dir = path.abspath(root_path.."../sources/lua_bindings") -- Return the list of configs that should be built in order: return { path.join(bind_dir,"Core/nervbind.lua"), path.join(bind_dir,"Vulkan/nervbind.lua"), }
-- Before registering the classes we sort the namespace stacks: local nsStacks = {} local nsNames = Set() for _,cl in ipairs(classes) do stack = self:getNamespaceStack(cl) stackName = table.concat(stack,".") nsStacks[stackName] = nsStacks[stackName] or {} nsNames:insert(stackName) table.insert(nsStacks[stackName], cl) end nsNames = nsNames:getElements() table.sort(nsNames) -- Then we should register all the classes: for _,nsName in ipairs(nsNames) do stack = nsStacks[nsName] for _, cl in ipairs(stack) do self:updateNamespaceStack(cl) self:writeSubLine("Luna< ${1} >::Register(L);", cl:getFullName()) end end
-- Instead of the previous implementation above we can use the list of namespace names already available: -- but we add "_G" to it first: table.insert(nsNames, "_G") for _, name in ipairs(nsNames) do self:writeSubLine("luna_copyParents(L, \"${1}\");", name) end
logDEBUG("Loading Vulkan bindings...") bm:loadBindings("Vulkan", "luaVulkan") -- Create the Library: local vk = nv.vulkan local lib = vk.Library.instance();
auto exts = vulkan["Extensions"].get_or_create<sol::table>(); exts["VK_KHR_SURFACE"] = VK_KHR_SURFACE_EXTENSION_NAME; exts["VK_KHR_WIN32_SURFACE"] = VK_KHR_WIN32_SURFACE_EXTENSION_NAME; exts["VK_EXT_DEBUG_UTILS"] = VK_EXT_DEBUG_UTILS_EXTENSION_NAME; exts["VK_KHR_SWAPCHAIN"] = VK_KHR_SWAPCHAIN_EXTENSION_NAME;
namespace nvk { struct InstanceExtensions { InstanceExtensions() = delete; static constexpr const char* VK_KHR_SURFACE = VK_KHR_SURFACE_EXTENSION_NAME; } } // namespace nvk/
- name: fmt url: git@github.com:roche-emmanuel/fmt.git version: 9.1.1
"""This module provide the builder for the fmt library.""" import logging from nvp.core.build_manager import BuildManager from nvp.nvp_builder import NVPBuilder logger = logging.getLogger(__name__) def register_builder(bman: BuildManager): """Register the build function""" bman.register_builder("fmt", FmtBuilder(bman)) class FmtBuilder(NVPBuilder): """Fmt builder class.""" def build_on_windows(self, build_dir, prefix, _desc): """Build method for Fmt on windows""" flags = ["-S", ".", "-B", "build", "-DBUILD_SHARED_LIBS=FALSE", "-DCMAKE_POSITION_INDEPENDENT_CODE=TRUE"] self.run_cmake(build_dir, prefix, flags=flags) sub_dir = self.get_path(build_dir, "build") self.run_ninja(sub_dir) def build_on_linux(self, build_dir, prefix, desc): """Build method for Fmt on linux""" flags = ["-S", ".", "-B", "build", "-DBUILD_SHARED_LIBS=FALSE", "-DCMAKE_POSITION_INDEPENDENT_CODE=TRUE"] self.run_cmake(build_dir, prefix, flags=flags) sub_dir = self.get_path(build_dir, "build") self.run_ninja(sub_dir)
$ nvp build libs fmt
$ nvp build lib fmt -c clang
local exts = nvk.Extensions; local layers = {"VK_LAYER_LUNARG_standard_validation"}
InstanceExtensions
class with static fields. So updating accordingly…local inst = nvk.Instance({exts.VK_KHR_SURFACE, exts.VK_KHR_WIN32_SURFACE, exts.VK_EXT_DEBUG_UTILS}, layers, false) logDEBUG("Number of physical vulkan devices: ", inst:getNumPhysicalDevices())
LuaFunction
elements, __lunaext__
prefix or __lunarawext__
prefix… So let's see if I can figure out how to use these again.inline auto __lunarawext__VulkanInstance(VulkanInstance& /*inst*/, lua_State* L) -> int { // Construct a new instance from tables on stack: int luatop = lua_gettop(L); if (luatop < 2) return 0; // Get the extensions: int num = (int)lua_objlen(L, 1); nv::StringList exts; for (int i = 0; i < num; ++i) { // Get from the table at index 1: lua_rawgeti(L, 1, i + 1); // Read the string from the stack: // We can use a simple tostring call here as we don't need the string // length for simple extension names: const char* str = lua_tostring(L, -1); logDEBUG("Reading from lua extension name: {}", str); exts.push_back(str); // pop the string value: lua_pop(L, 1); } nv::StringList layers; for (int i = 0; i < num; ++i) { // Get from the table at index 2: lua_rawgeti(L, 2, i + 1); // Read the string from the stack: // We can use a simple tostring call here as we don't need the string // length for simple extension names: const char* str = lua_tostring(L, -1); logDEBUG("Reading from lua layer name: {}", str); layers.push_back(str); // pop the string value: lua_pop(L, 1); } // VulkanInstance(const nv::StringList& extensions, // const nv::StringList& layers, // bool useDebugMessenger = false); }
create_instance
method I'm adding on the VulkanLibrary class instead. I know… lazy implementation like that sounds dangerous… but I feel really lazy/tired/unmotivated right now.Ignoring non DLL imported signature: nvk::VulkanLibrary::create_instance [auto (nvk::VulkanLibrary &, lua_State *) -> int]
Ignoring non-public function nvk::%%__lunarawext__%%create_instance
function Class:isLuaConvertible() for k,arg in ipairs(self._arguments) do -- Canonical lua state is convertible to lua: if arg:getType():getLuaConverter() == nil and not arg:isCanonicalLuaState() then return false, arg:getType():getName() end end end
// Also prepare here the registration of the void type: luna::pushGlobalNamespace(L); luna::Luna<void>::Register(L); luna::popNamespace(L);
createPresentationSurface
method now. So we need the VulkanSurface
class.create_presentation_surface()
method as it has the following signature: auto create_presentation_surface(const VulkanWindowParameters& params) -> nv::RefPtr<VulkanSurface>;
nv::RefPtr<VulkanSurface>
is considered unbindable: too bad 😆RefPtrConverter
class in NervLuna that will handle extracting/injecting RefPtr object on the Lua stack. Base implementation was adapted from the default ClassConverter
version: local Class = createClass{name="RefPtrConverter", bases="reflection.LuaConverter"} -- local luna = import "bind.LunaManager" -- This converter is used for parameters/results that are raw class objects. function Class:__init() Class.super.__init(self) end function Class:writeTypeCheck(buf, idx, atype, hasDef) local cond = "" if hasDef then -- Conditional check: cond = ("luatop>=%d && "):format(idx) end -- Once we have the type we can retrieve the target class from it: local tgtCl = atype:getTarget() -- Extract the real target name: local refptr_name = tgtCl:getFullName() local cl_name = refptr_name:sub(12, -2) local luna = import "bind.LunaManager" -- #104: If the type is a pointer, then we should also accept a nil value as input here: local allowNull = atype:getPointerCount()>0 and "true" or "false" buf:writeSubLine("if( ${1}!luna_isInstanceOf(L,${2},${3},${4}) ) return false;", cond, idx, luna:getSID(cl_name), allowNull) end function Class:writeGetter(buf, idx, arg, isField) -- The arg value we received should be an instance of the Argument class -- So from there we can retrieve: the target type, argument name, default value, etc. -- if we have the given lue entry then we can retrieve it -- Otherwise we use the default value: local atype = arg:getType() local typeName = atype:getUnqualifiedName() local argName = arg:getName() local defVal = nil if not isField then defVal = arg:getDefault() end -- Extract the real target name: local tgtCl = atype:getTarget() local refptr_name = tgtCl:getFullName() local cl_name = refptr_name:sub(12, -2) -- Below we only add the star prefix if we are not trying to use a pointer: local pcount = atype:getPointerCount() local prefix = (pcount==2 and "&") or (pcount==1 and "") or (pcount==0 and "*") local allowNull = pcount>0 and "true" or "false" if defVal ~= nil then -- We have a default value, so we check the luatop: buf:writeSubLine("${1} ${2} = luatop>=${3}? Luna< ${5} >::get(L,${3},${4}) : nullptr;", typeName, argName, idx, allowNull, cl_name) return ("luatop>=%d ? %s%s.get() : %s"):format(idx, prefix, argName, defVal) else -- No default value, we must retrieve it from the lua stack: buf:writeSubLine("${1} ${2} = Luna< ${5} >::get(L,${3},${4});", typeName, argName, idx, allowNull, cl_name); if isField then local contName = arg:isStatic() and arg:getNamespaceName().."::" or "self->" buf:writeSubLine("${3}${1} = ${2}${1}.get();", argName, prefix, contName); end return prefix..argName end end function Class:writeSetter(buf, varname, type, prefix) -- If we have resulting "instance" we should not just push it on the stack, because the object -- would then get out of scope. -- So we have to create a copy object on the heap in this case. -- So we expect to have a copy constructor ? -- Update: if the type is a reference, then we can push the pointer to the object directly: local typeName = type:getUnqualifiedName(); -- Extract the real target name: local tgtCl = type:getTarget() local refptr_name = tgtCl:getFullName() local cl_name = refptr_name:sub(12, -2) if type:isReference() then -- Push the reference directly, and do not own the memory of that object: buf:writeSubLine("Luna< ${1} >::push(L, ${2}.get(), true);", cl_name, prefix..varname) elseif type:isPointer() then -- Push the pointer directly, and do not own the memory of that object: buf:writeSubLine("Luna< ${1} >::push(L, ${3}${2}->get(), true);", cl_name, prefix..varname,type:getPointerCount()==2 and "*" or "") else -- Raw object access: -- #104: if we are writting a field getter, then we expect to get a pointer on the field itself, -- not a new copy of that field (and in that case we do not own the pointer) if prefix~="" then buf:writeSubLine("Luna< ${1} >::push(L, ${3}${2}.get(), true);", cl_name, varname, prefix) else -- buf:writeSubLine("${1}* ${2}_ptr = new ${1}(${3});", typeName, varname, varname) -- buf:writeSubLine("Luna< ${1} >::push(L, ${2}_ptr, true);", typeName, varname) buf:writeSubLine("Luna< ${1} >::push(L, ${2}.get(), true);", cl_name, varname) end end end function Class:isClassSupported(tgt) fname = tgt:getFullName() -- "nv::RefPtr<" clname = fname:sub(12, -2) -- logDEBUG("RefPtrConverter: checking support for ", fname, " => clname: '", clname, "'") -- check if that class is available: local tm = import "reflection.TypeManager" cltype = tm:getType(clname) if cltype ~= nil then logDEBUG("RefPtrConverter: Found type for class ", clname, " in ", fname) return true end return false end return Class()
// enum VkAccelerationStructureMemoryRequirementsTypeNV lua_newtable(L); lua_pushnumber(L, VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV); lua_setfield(L,-2,"VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV"); lua_pushnumber(L, VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_NV); lua_setfield(L,-2,"VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_NV"); lua_pushnumber(L, VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV); lua_setfield(L,-2,"VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV"); lua_pushnumber(L, VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_MAX_ENUM_NV); lua_setfield(L,-2,"VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_MAX_ENUM_NV"); lua_setfield(L,-2,"VkAccelerationStructureMemoryRequirementsTypeNV"); // enum VkAccelerationStructureMotionInstanceTypeNV lua_newtable(L); lua_pushnumber(L, VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_STATIC_NV); lua_setfield(L,-2,"VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_STATIC_NV"); lua_pushnumber(L, VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_MATRIX_MOTION_NV); lua_setfield(L,-2,"VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_MATRIX_MOTION_NV"); lua_pushnumber(L, VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_SRT_MOTION_NV); lua_setfield(L,-2,"VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_SRT_MOTION_NV"); lua_pushnumber(L, VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_MAX_ENUM_NV); lua_setfield(L,-2,"VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_MAX_ENUM_NV"); lua_setfield(L,-2,"VkAccelerationStructureMotionInstanceTypeNV");
=> So here I'm now thinking I should probably do something to reduce the length of the name for the **values** to be retrieved in each enum: I think I could for instance remove the common part in all values like "VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_" and "VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_" above => let's handle that!
function Class:getCommonPrefixLength(constants) -- If we only have 1 element we do not search for a common prefix here: if #constants <= 1 then return 0 end ref_name = constants[1].value prefix = ref_name local is_common = function(prefix) for _, obj in ipairs(constants) do if not obj.name:startsWith(prefix) then return false end end return true end while not is_common(prefix) do prefix = prefix:sub(1,-2) if prefix == "" then return 0 end end -- Return the length of the prefix: -- logDEBUG("Found common enum prefix: ", prefix) return #prefix end
// enum VkAccelerationStructureCompatibilityKHR lua_newtable(L); lua_pushnumber(L, VK_ACCELERATION_STRUCTURE_COMPATIBILITY_COMPATIBLE_KHR); lua_setfield(L,-2,"COMPATIBLE_KHR"); lua_pushnumber(L, VK_ACCELERATION_STRUCTURE_COMPATIBILITY_INCOMPATIBLE_KHR); lua_setfield(L,-2,"INCOMPATIBLE_KHR"); lua_pushnumber(L, VK_ACCELERATION_STRUCTURE_COMPATIBILITY_MAX_ENUM_KHR); lua_setfield(L,-2,"MAX_ENUM_KHR"); lua_setfield(L,-2,"VkAccelerationStructureCompatibilityKHR"); // enum VkAccelerationStructureCreateFlagBitsKHR lua_newtable(L); lua_pushnumber(L, VK_ACCELERATION_STRUCTURE_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR); lua_setfield(L,-2,"DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR"); lua_pushnumber(L, VK_ACCELERATION_STRUCTURE_CREATE_MOTION_BIT_NV); lua_setfield(L,-2,"MOTION_BIT_NV"); lua_pushnumber(L, VK_ACCELERATION_STRUCTURE_CREATE_FLAG_BITS_MAX_ENUM_KHR); lua_setfield(L,-2,"FLAG_BITS_MAX_ENUM_KHR"); lua_setfield(L,-2,"VkAccelerationStructureCreateFlagBitsKHR");
void get_surface_formats(VulkanSurface* surface, VkSurfaceFormatList& formats) const;
ClassWriter
, and injecting the relevant functions manually as needed: function Class:injectVectorOf(cl, el_type) tm = import "reflection.TypeManager" local create_func = function(name, signame, ret_type, args) local func = cl:getOrCreateFunction(name) local sig = func:createSignature(signame) sig:setVisibility(Vis.PUBLIC) sig:setImplicit(true) sig:setDllImported(true) sig:setDefined(true) if ret_type ~= nil then sig:setReturnType(ret_type) end for _,arg in ipairs(args or {}) do sig:addArgument(Argument(arg[1], arg[2], arg[3])) end end local el_name = el_type:getName() local u32_t = tm:getType("nv::U32") local void_t = tm:getType("void") local bool_t = tm:getType("bool") local el_ref_t = tm:getType(el_name.."&") if el_ref_t == nil then local el_t = tm:getType(el_name) el_ref_t = Type(el_name.."&", el_t:getTarget(), nil) el_ref_t:addReference() tm:addType(el_ref_t) end -- Inject the functions: create_func(cl:getName(), "void ()") create_func("size", "nv::U32 ()", u32_t) create_func("at", el_name.."& (nv::U32)", el_ref_t, {{"n", u32_t}}) -- create_func("operator[]", el_name.."& (nv::U32)", el_ref_t, {{"n", u32_t}}) create_func("push_back", "void ("..el_name.."&)", void_t, {{"val", el_ref_t}}) create_func("pop_back", "void ()", void_t) create_func("assign", "void (nv::U32, "..el_name.."&)", void_t, {{"n", u32_t},{"val", el_ref_t}}) create_func("back", el_name.."& ()", el_ref_t) create_func("front", el_name.."& ()", el_ref_t) create_func("empty", "bool ()", bool_t) create_func("clear", "void ()", void_t) create_func("resize", "void (nv::U32)", void_t, {{"n", u32_t}}) end