Skip to content

Commit

Permalink
[Modules] Moved loading dynamic module into RenderSystemModule and Re…
Browse files Browse the repository at this point in the history
…nderSystemRegistry.

This allows to re-use already loaded modules and avoid loading the 'extern "C"' functions again once a module is loaded.
While rarely used, it allows LLGL to load the same render system multiple times with potentially different configurations.
  • Loading branch information
LukasBanana committed Sep 27, 2024
1 parent f98a367 commit 21b6880
Show file tree
Hide file tree
Showing 9 changed files with 475 additions and 167 deletions.
8 changes: 4 additions & 4 deletions sources/Core/Exception.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ LLGL_EXPORT void Trap(const char* origin, const char* format, ...)

LLGL_STRING_PRINTF(report, format);

#ifdef LLGL_ENABLE_EXCEPTIONS
#if LLGL_ENABLE_EXCEPTIONS

/* Throw exception with report and optional origin */
throw std::runtime_error(report);
Expand Down Expand Up @@ -167,13 +167,13 @@ LLGL_EXPORT void TrapReport(const char* origin, const Report& report)

LLGL_EXPORT std::nullptr_t ReportException(Report* report, const char* format, ...)
{
#ifdef LLGL_ENABLE_EXCEPTIONS
#if LLGL_ENABLE_EXCEPTIONS

std::string errorStr;
LLGL_STRING_PRINTF(errorStr, format);
throw std::runtime_error(errorStr);

#else
#else // LLGL_ENABLE_EXCEPTIONS

if (report != nullptr)
{
Expand All @@ -184,7 +184,7 @@ LLGL_EXPORT std::nullptr_t ReportException(Report* report, const char* format, .

return nullptr;

#endif
#endif // /LLGL_ENABLE_EXCEPTIONS
}


Expand Down
2 changes: 1 addition & 1 deletion sources/Renderer/CheckedCast.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ inline TDst& ObjectCast(TSrc& obj)

return dynamic_cast<TDst&>(obj);

#endif
#endif // /LLGL_ENABLE_EXCEPTIONS
}

template <typename TDst, typename TSrc>
Expand Down
179 changes: 22 additions & 157 deletions sources/Renderer/RenderSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "BuildID.h"

#include <LLGL/RenderSystem.h>
#include "RenderSystemRegistry.h"
#include <string>
#include <unordered_map>

Expand Down Expand Up @@ -55,7 +56,6 @@ struct RenderSystem::Pimpl
Report report;
};

static std::unordered_map<RenderSystem*, std::unique_ptr<Module>> g_renderSystemModules;

RenderSystem::RenderSystem() :
pimpl_ { new Pimpl{} }
Expand All @@ -67,131 +67,15 @@ RenderSystem::~RenderSystem()
delete pimpl_;
}

#ifdef LLGL_BUILD_STATIC_LIB

std::vector<std::string> RenderSystem::FindModules()
{
return StaticModule::GetStaticModules();
}

#else // LLGL_BUILD_STATIC_LIB

std::vector<std::string> RenderSystem::FindModules()
{
/* Iterate over all known modules and return those that are available on the current platform */
constexpr const char* knownModules[] =
{
"Null",

#if defined(LLGL_OS_IOS) || defined(LLGL_OS_ANDROID)
"OpenGLES3",
#else
"OpenGL",
#endif

#if defined(LLGL_OS_MACOS) || defined(LLGL_OS_IOS)
"Metal",
#else
"Vulkan",
#endif

#if defined(LLGL_OS_WIN32) || defined(LLGL_OS_UWP)
"Direct3D11",
"Direct3D12",
#endif
};

std::vector<std::string> modules;

for (const char* m : knownModules)
{
std::string moduleFilename = Module::GetModuleFilename(m);
if (Module::IsAvailable(moduleFilename.c_str()))
modules.push_back(m);
}

return modules;
}

static bool LoadRenderSystemBuildID(
Module& module,
const std::string& moduleFilename,
Report* report)
{
/* Load "LLGL_RenderSystem_BuildID" procedure */
LLGL_PROC_INTERFACE(int, PFN_RENDERSYSTEM_BUILDID, (void));

auto RenderSystem_BuildID = reinterpret_cast<PFN_RENDERSYSTEM_BUILDID>(module.LoadProcedure("LLGL_RenderSystem_BuildID"));
if (!RenderSystem_BuildID)
{
ReportException(report, "failed to load <LLGL_RenderSystem_BuildID> procedure from module: %s", moduleFilename.c_str());
return false;
}

return (RenderSystem_BuildID() == LLGL_BUILD_ID);
}

static int LoadRenderSystemRendererID(Module& module, const RenderSystemDescriptor& renderSystemDesc)
{
/* Load "LLGL_RenderSystem_RendererID" procedure */
LLGL_PROC_INTERFACE(int, PFN_RENDERSYSTEM_RENDERERID, (const void*));

auto RenderSystem_RendererID = reinterpret_cast<PFN_RENDERSYSTEM_RENDERERID>(module.LoadProcedure("LLGL_RenderSystem_RendererID"));
if (RenderSystem_RendererID)
return RenderSystem_RendererID(&renderSystemDesc);

return RendererID::Undefined;
}

static const char* LoadRenderSystemName(Module& module, const RenderSystemDescriptor& renderSystemDesc)
{
/* Load "LLGL_RenderSystem_Name" procedure */
LLGL_PROC_INTERFACE(const char*, PFN_RENDERSYSTEM_NAME, (const void*));

if (auto RenderSystem_Name = reinterpret_cast<PFN_RENDERSYSTEM_NAME>(module.LoadProcedure("LLGL_RenderSystem_Name")))
return RenderSystem_Name(&renderSystemDesc);
else
return "";
}

static RenderSystem* LoadRenderSystem(
Module& module,
const char* moduleFilename,
const RenderSystemDescriptor& renderSystemDesc,
Report* outReport)
{
/* Load "LLGL_RenderSystem_Alloc" procedure */
LLGL_PROC_INTERFACE(void*, PFN_RENDERSYSTEM_ALLOC, (const void*, int));

auto RenderSystem_Alloc = reinterpret_cast<PFN_RENDERSYSTEM_ALLOC>(module.LoadProcedure("LLGL_RenderSystem_Alloc"));
if (!RenderSystem_Alloc)
return ReportException(outReport, "failed to load 'LLGL_RenderSystem_Alloc' procedure from module: %s", moduleFilename);

/* Allocate render system */
auto renderSystem = reinterpret_cast<RenderSystem*>(RenderSystem_Alloc(&renderSystemDesc, static_cast<int>(sizeof(RenderSystemDescriptor))));
if (!renderSystem)
return ReportException(outReport, "failed to allocate render system from module: %s", moduleFilename);

/* Check if errors where reported and the render system is unusable */
if (const Report* report = renderSystem->GetReport())
{
if (outReport != nullptr)
*outReport = *report;
if (report->HasErrors())
return nullptr;
}

return renderSystem;
}

static RenderSystemDeleter::RenderSystemDeleterFuncPtr LoadRenderSystemDeleter(Module& module)
{
/* Load "LLGL_RenderSystem_Free" procedure */
return reinterpret_cast<RenderSystemDeleter::RenderSystemDeleterFuncPtr>(module.LoadProcedure("LLGL_RenderSystem_Free"));
#if LLGL_BUILD_STATIC_LIB
return StaticModules::GetStaticModules();
#else
return RenderSystemModule::FindModules();
#endif
}

#endif // /LLGL_BUILD_STATIC_LIB

RenderSystemPtr RenderSystem::Load(const RenderSystemDescriptor& renderSystemDesc, Report* report)
{
/* Initialize mobile specific states */
Expand All @@ -204,7 +88,7 @@ RenderSystemPtr RenderSystem::Load(const RenderSystemDescriptor& renderSystemDes
#ifdef LLGL_BUILD_STATIC_LIB

/* Allocate render system */
RenderSystemPtr renderSystem{ StaticModule::AllocRenderSystem(renderSystemDesc) };
RenderSystemPtr renderSystem{ StaticModules::AllocRenderSystem(renderSystemDesc) };

if (renderSystemDesc.debugger != nullptr)
{
Expand All @@ -221,56 +105,38 @@ RenderSystemPtr RenderSystem::Load(const RenderSystemDescriptor& renderSystemDes
#endif // /LLGL_ENABLE_DEBUG_LAYER
}

renderSystem->pimpl_->name = StaticModule::GetRendererName(renderSystemDesc.moduleName);
renderSystem->pimpl_->rendererID = StaticModule::GetRendererID(renderSystemDesc.moduleName);
renderSystem->pimpl_->name = StaticModules::GetRendererName(renderSystemDesc.moduleName);
renderSystem->pimpl_->rendererID = StaticModules::GetRendererID(renderSystemDesc.moduleName);

/* Return new render system and unique pointer */
return renderSystem;

#else // LLGL_BUILD_STATIC_LIB

/* Load render system module */
const std::string moduleFilename = Module::GetModuleFilename(renderSystemDesc.moduleName.c_str());
std::unique_ptr<Module> module;

#ifdef LLGL_ENABLE_EXCEPTIONS

Report moduleReport;
module = Module::Load(moduleFilename.c_str(), &moduleReport);
if (!module)
TrapReport(__FUNCTION__, moduleReport);

#else

module = Module::Load(moduleFilename.c_str(), report);
if (!module)
RenderSystemModule* module = RenderSystemRegistry::Get().LoadModule(renderSystemDesc.moduleName.c_str(), report);
if (module == nullptr)
return nullptr;

#endif

/*
Verify build ID from render system module to detect a module,
that has compiled with a different compiler (type, version, debug/release mode etc.)
*/
if (!LoadRenderSystemBuildID(*module, moduleFilename, report))
if (module->BuildID() != LLGL_BUILD_ID)
return ReportException(report, "build ID mismatch in render system module");

#ifdef LLGL_ENABLE_EXCEPTIONS
#if LLGL_ENABLE_EXCEPTIONS
try
#endif
{
/* Allocate render system */
RenderSystemPtr renderSystem
{
LoadRenderSystem(*module, moduleFilename.c_str(), renderSystemDesc, report),
RenderSystemDeleter{ LoadRenderSystemDeleter(*module) }
};
RenderSystemPtr renderSystem = module->AllocRenderSystem(renderSystemDesc, report);

if (renderSystem)
{
if (renderSystemDesc.debugger != nullptr)
{
#ifdef LLGL_ENABLE_DEBUG_LAYER
#if LLGL_ENABLE_DEBUG_LAYER

/* Create debug layer render system */
renderSystem = RenderSystemPtr{ new DbgRenderSystem{ std::move(renderSystem), renderSystemDesc.debugger } };
Expand All @@ -283,16 +149,16 @@ RenderSystemPtr RenderSystem::Load(const RenderSystemDescriptor& renderSystemDes
#endif // /LLGL_ENABLE_DEBUG_LAYER
}

renderSystem->pimpl_->name = LoadRenderSystemName(*module,renderSystemDesc);
renderSystem->pimpl_->rendererID = LoadRenderSystemRendererID(*module,renderSystemDesc);
renderSystem->pimpl_->name = module->RendererName();
renderSystem->pimpl_->rendererID = module->RendererID();

/* Store new module inside internal map */
g_renderSystemModules[renderSystem.get()] = std::move(module);
/* Link render system to module */
RenderSystemRegistry::Get().RegisterRenderSystem(renderSystem.get(), module);
}

return renderSystem;
}
#ifdef LLGL_ENABLE_EXCEPTIONS
#if LLGL_ENABLE_EXCEPTIONS
catch (const std::exception& e)
{
/* Throw with new exception, otherwise the exception's v-table will be corrupted since it's part of the module */
Expand All @@ -305,12 +171,11 @@ RenderSystemPtr RenderSystem::Load(const RenderSystemDescriptor& renderSystemDes

void RenderSystem::Unload(RenderSystemPtr&& renderSystem)
{
auto it = g_renderSystemModules.find(renderSystem.get());
if (it != g_renderSystemModules.end())
if (RenderSystem* renderSystemRef = renderSystem.get())
{
/* Delete render system first, then release module */
renderSystem.reset();
g_renderSystemModules.erase(it);
RenderSystemRegistry::Get().UnregisterRenderSystem(renderSystemRef);
}
}

Expand Down
Loading

0 comments on commit 21b6880

Please sign in to comment.