From 1eb8dc727ea0c6df81cc68de09c5e0e333e19507 Mon Sep 17 00:00:00 2001 From: benkyd Date: Thu, 17 Nov 2022 17:37:42 +0000 Subject: [PATCH] mody mody module wtf --- hart/inferno-hart-cpu/src/main.cpp | 41 ++++-- hart/inferno-hart-opencl/src/main.cpp | 41 ++++-- imgui.ini | 37 ++++++ libhart/hardware_accelerator.hpp | 13 -- libhart/inferno_hart.hpp | 31 +++++ src/hart_directory.cpp | 179 ++++++++++++++++++++++++++ src/hart_directory.hpp | 64 +++++++++ src/inferno.cpp | 39 +++++- 8 files changed, 407 insertions(+), 38 deletions(-) create mode 100644 imgui.ini create mode 100644 src/hart_directory.cpp create mode 100644 src/hart_directory.hpp diff --git a/hart/inferno-hart-cpu/src/main.cpp b/hart/inferno-hart-cpu/src/main.cpp index 66e39a0..c91b51a 100644 --- a/hart/inferno-hart-cpu/src/main.cpp +++ b/hart/inferno-hart-cpu/src/main.cpp @@ -5,23 +5,40 @@ using namespace inferno; -extern "C" Accelerator* get() +class HARTCPU : public ::HARTModule { - Mesh* mesh = new Mesh(); - return new Accelerator; +public: + HARTCPU() + { + std::cout << "Module HART CPU" << std::endl; + } + + ~HARTCPU() + { + std::cout << "Goodbye Module HART CPU" << std::endl; + } + +}; + +HART_INTERFACE void* _GET() +{ + return new HARTCPU; } -extern "C" void destroy(Accelerator* inst) +HART_INTERFACE void _DESTROY(void* inst) { - delete inst; + HARTCPU* instance = (HARTCPU*)inst; + delete instance; } -Accelerator::Accelerator() +HART_INTERFACE void* _CREDIT() { - -} - -void Accelerator::Init() -{ - std::cout << "Shared Library!" << std::endl; + return new ModuleCredit { + .ModuleName = "HART_CPU", + .AuthorName = "Ben Kyd", + .ModuleDesc = "Accelerating inferno raytracing with CPU", + .VersionMajor = 0, + .VersionMinor = 0, + .VersionBuild = 1, + }; } diff --git a/hart/inferno-hart-opencl/src/main.cpp b/hart/inferno-hart-opencl/src/main.cpp index a854ee9..080d53f 100644 --- a/hart/inferno-hart-opencl/src/main.cpp +++ b/hart/inferno-hart-opencl/src/main.cpp @@ -1,25 +1,44 @@ #include +#include #include using namespace inferno; -extern "C" ::Accelerator* get() +class HARTGPU : public ::HARTModule { - return new ::Accelerator; +public: + HARTGPU() + { + std::cout << "Module HART GPU" << std::endl; + } + + ~HARTGPU() + { + std::cout << "Goodbye Module HART GPU" << std::endl; + } + +}; + +HART_INTERFACE void* _GET() +{ + return new HARTGPU; } -extern "C" void destroy(::Accelerator* inst) +HART_INTERFACE void _DESTROY(void* inst) { - delete inst; + HARTGPU* instance = (HARTGPU*)inst; + delete instance; } -Accelerator::Accelerator() +HART_INTERFACE void* _CREDIT() { - -} - -void Accelerator::Init() -{ - std::cout << "Shared Library!" << std::endl; + return new ModuleCredit { + .ModuleName = "HART_GPU", + .AuthorName = "Ben Kyd", + .ModuleDesc = "Accelerating inferno raytracing with OpenCL", + .VersionMajor = 0, + .VersionMinor = 0, + .VersionBuild = 1, + }; } diff --git a/imgui.ini b/imgui.ini new file mode 100644 index 0000000..b7fa689 --- /dev/null +++ b/imgui.ini @@ -0,0 +1,37 @@ +[Window][Preview] +Pos=8,34 +Size=499,677 +Collapsed=0 +DockId=0x00000001,0 + +[Window][Render] +Pos=509,34 +Size=763,677 +Collapsed=0 +DockId=0x00000002,0 + +[Window][main] +Pos=0,0 +Size=1280,720 +Collapsed=0 + +[Window][Debug##Default] +Pos=60,60 +Size=400,400 +Collapsed=0 + +[Window][Inferno HART] +Pos=60,60 +Size=338,222 +Collapsed=0 + +[Window][Dear ImGui Demo] +Pos=650,20 +Size=550,680 +Collapsed=0 + +[Docking][Data] +DockSpace ID=0x9498A894 Window=0xBF28CD64 Pos=8,34 Size=1264,677 Split=X + DockNode ID=0x00000001 Parent=0x9498A894 SizeRef=499,1000 Selected=0x382916D5 + DockNode ID=0x00000002 Parent=0x9498A894 SizeRef=499,1000 CentralNode=1 Selected=0x81AED595 + diff --git a/libhart/hardware_accelerator.hpp b/libhart/hardware_accelerator.hpp index dcd100e..52a52af 100644 --- a/libhart/hardware_accelerator.hpp +++ b/libhart/hardware_accelerator.hpp @@ -1,18 +1,5 @@ #pragma once -// THIS IS WHAT THE LIBRARY IMPLEMENTS AND PASSES BACK - EVERYTHING ELSE IS JUST DATA namespace inferno { -enum ACCEL_TYPE -{ - ACCEL_TYPE_RAY_TRI_ONLY, -}; - -class Accelerator -{ -public: - Accelerator(); - virtual void Init(); -}; - } diff --git a/libhart/inferno_hart.hpp b/libhart/inferno_hart.hpp index 056f115..fbb66fd 100644 --- a/libhart/inferno_hart.hpp +++ b/libhart/inferno_hart.hpp @@ -1,9 +1,40 @@ #pragma once +#include + #include "hardware_accelerator.hpp" namespace inferno { +#ifdef _WIN32 +#include +#define HART_EXTENSION ".dll" +#define HART_INTERFACE extern "C" __declspec(dllexport) +#else // UNIX-Like +#include +#define HART_EXTENSION ".so" +#define HART_INTERFACE extern "C" +#endif +HART_INTERFACE typedef void* (*HART_INIT_F)(void); +HART_INTERFACE typedef void (*HART_DESTROY_F)(void*); +HART_INTERFACE typedef void* (*HART_CREDIT_F)(void); + +struct ModuleCredit +{ + const std::string ModuleName; + const std::string AuthorName; + const std::string ModuleDesc; + const int VersionMajor; + const int VersionMinor; + const int VersionBuild; +}; + +class HARTModule +{ +public: + // Constructor & destructor is done in the module + // virtual void takeScene() = 0; +}; } diff --git a/src/hart_directory.cpp b/src/hart_directory.cpp new file mode 100644 index 0000000..93e2631 --- /dev/null +++ b/src/hart_directory.cpp @@ -0,0 +1,179 @@ +#include "hart_directory.hpp" + +#include + +#include + +using namespace inferno; + +HARTModuleDirectory::HARTModuleDirectory() +{ + +} + +HARTModuleDirectory::~HARTModuleDirectory() +{ + +} + +std::vector HARTModuleDirectory::discoverModules(std::filesystem::path folder, bool recurse) +{ + if (!std::filesystem::exists(folder)) return { }; + + if (!std::filesystem::is_directory(folder)) + { + return { this->registerModule(folder) }; + } + + std::error_code err; + if (recurse) + { + for (const auto& file : std::filesystem::recursive_directory_iterator(folder, err)) + { + if (file.path().extension() == HART_EXTENSION) + { + this->registerModule(file); + } + } + } else + { + for (const auto& file : std::filesystem::directory_iterator(folder, err)) + { + if (file.path().extension() == HART_EXTENSION) + { + this->registerModule(file); + } + } + } + + return { }; +} + +HARTModuleDirectory::discoveryEntry HARTModuleDirectory::registerModule(std::filesystem::path file) +{ + spdlog::debug("Registering module at {}", file.c_str()); + + discoveryEntry entry; + entry.Location = file; + +#ifdef _WIN32 + entry.Handle = LoadLibraryA(file.c_str()); + if (entry.Handle == NULL) + { + spdlog::error("Cannot load module at {}.", file.c_str()); + entry.Handle = NULL; entry.DidLink = false; + return entry; + } + HART_CREDIT_F credit = (HART_CREDIT_F)GetProcAddress(entry.Handle, "_CREDIT"); + entry.InitCallback = (HART_INIT_F)GetProcAddress(entry.Handle, "_GET"); + entry.DestroyCallback = (HART_DESTROY_F)GetProcAddress(entry.Handle, "_DESTROY"); +#else // UNIX-Like + entry.Handle = dlopen(file.c_str(), RTLD_LAZY | RTLD_LOCAL); + if (entry.Handle == NULL) + { + spdlog::error("Cannot load module at {}.", file.c_str()); + entry.Handle = NULL; entry.DidLink = false; + return entry; + } + HART_CREDIT_F credit = (HART_CREDIT_F)dlsym(entry.Handle, "_CREDIT"); + entry.InitCallback = (HART_INIT_F)dlsym(entry.Handle, "_GET"); + entry.DestroyCallback = (HART_DESTROY_F)dlsym(entry.Handle, "_DESTROY"); +#endif + + if (credit == NULL) + { + spdlog::error("Cannot load module at {}... No credit...", file.c_str()); + entry.Handle = NULL; entry.DidLink = false; + return entry; + } + if (entry.InitCallback == NULL) + { + spdlog::error("Cannot load module at {}... No get...", file.c_str()); + entry.Handle = NULL; entry.DidLink = false; + return entry; + } + if (entry.DestroyCallback == NULL) + { + spdlog::error("Cannot load module at {}... No destroy...", file.c_str()); + entry.Handle = NULL; entry.DidLink = false; + return entry; + } + + entry.Credit = (ModuleCredit*)credit(); + + spdlog::info("Module {} v{}.{}.{} by {}", entry.Credit->ModuleName, + entry.Credit->VersionMajor, + entry.Credit->VersionMinor, + entry.Credit->VersionBuild, + entry.Credit->AuthorName); + + entry.DidLink = true; + mEntries[entry.Credit->ModuleName] = { entry, nullptr }; + + if (mEntries.size() == 1) + { + // this is the first, make it active - or else + mActiveModule = entry.Credit->ModuleName; + this->load(mActiveModule); + } + + return entry; +} + +std::vector HARTModuleDirectory::getModules() +{ + std::vector keys; + for(auto kv : mEntries) + { + keys.push_back(kv.first); + } + return keys; +} + +void HARTModuleDirectory::setActive(std::string moduleName) +{ + if (moduleName == mActiveModule) return; + this->destroy(mActiveModule); + mActiveModule = moduleName; + this->load(mActiveModule); +} + +void HARTModuleDirectory::setActiveIndex(int index) +{ + std::vector keys = this->getModules(); + this->setActive(keys[index]); +} + +std::string HARTModuleDirectory::getActive() +{ + return mActiveModule; +} + +int HARTModuleDirectory::getActiveIndex() +{ + std::vector keys = this->getModules(); + for (int i = 0; i < keys.size(); i++) + { + if (keys[i] == mActiveModule) return i; + } + return -1; // this should never happen +} + +ModuleCredit* HARTModuleDirectory::getActiveCredit() +{ + mEntries[mActiveModule].Discovery.Credit; +} + +void HARTModuleDirectory::load(std::string moduleName) +{ + HARTModule* mod = (HARTModule*)mEntries[moduleName].Discovery.InitCallback(); + mEntries[moduleName].Module = mod; + mEntries[moduleName].Active = true; +} + +void HARTModuleDirectory::destroy(std::string moduleName) +{ + mEntries[moduleName].Discovery.DestroyCallback(mEntries[moduleName].Module); + mEntries[moduleName].Module = nullptr; + mEntries[moduleName].Active = false; +} diff --git a/src/hart_directory.hpp b/src/hart_directory.hpp new file mode 100644 index 0000000..31f3f1e --- /dev/null +++ b/src/hart_directory.hpp @@ -0,0 +1,64 @@ +#pragma once + +// INFERNO-HART Modules +// _GET returns derived HARTModule +// _DESTROY returns void but takes derived HARTModule +// _CREDIT returns ModuleCredit + +#include +#include +#include + +#include "inferno_hart.hpp" + +namespace inferno { + +class HARTModuleDirectory +{ +public: + HARTModuleDirectory(); + ~HARTModuleDirectory(); + + struct discoveryEntry + { + std::filesystem::path Location; + bool DidLink = false; +#ifdef _WIN32 + HMODULE Handle; +#else // UNIX-Like + void* Handle; +#endif + ModuleCredit* Credit; + HART_INIT_F InitCallback; + HART_DESTROY_F DestroyCallback; + }; + + struct moduleEntry + { + discoveryEntry Discovery; + HARTModule* Module; + bool Active; + }; + + std::vector discoverModules(std::filesystem::path folder, bool recurse = false); + discoveryEntry registerModule(std::filesystem::path file); + + std::vector getModules(); + + void setActive(std::string moduleName); + void setActiveIndex(int index); + + std::string getActive(); + int getActiveIndex(); + ModuleCredit* getActiveCredit(); + + void load(std::string moduleName); + void destroy(std::string moduleName); + +private: + std::string mActiveModule; + std::unordered_map mEntries; +}; + +} + diff --git a/src/inferno.cpp b/src/inferno.cpp index a9d5499..28b4522 100644 --- a/src/inferno.cpp +++ b/src/inferno.cpp @@ -4,6 +4,8 @@ #include "gui/layout.hpp" #include "window.hpp" +#include "hart_directory.hpp" + #include "preview_renderer/renderer.hpp" #include "preview_renderer/shader.hpp" #include "scene/camera.hpp" @@ -116,8 +118,11 @@ void Inferno::stopMoveInput() mouseDelta = { 0.0f, 0.0f }; } -int Inferno::run() +int Inferno::run() { + HARTModuleDirectory moduleDirectory; + moduleDirectory.discoverModules("./hart/", true); + Camera camera; Mesh cornell; cornell.loadOBJ("res/cornell-box.obj"); @@ -208,6 +213,37 @@ int Inferno::run() { if (ImGui::TreeNode("Render")) { + if (ImGui::TreeNode("Accelerator")) + { + ImGui::Button("Find Accelerator..."); + ImGui::Text("Select Accelerator:"); + if (ImGui::BeginListBox("", ImVec2(-FLT_MIN, 3 * ImGui::GetTextLineHeightWithSpacing()))) + { + std::vector moduleNames = moduleDirectory.getModules(); + int active = moduleDirectory.getActiveIndex(); + for (int n = 0; n < moduleNames.size(); n++) + { + const bool is_selected = (active == n); + if (ImGui::Selectable(moduleNames[n].c_str(), is_selected)) + moduleDirectory.setActiveIndex(n); + + // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) + if (is_selected) + ImGui::SetItemDefaultFocus(); + } + ImGui::EndListBox(); + } + auto* activeCredit = moduleDirectory.getActiveCredit(); + ImGui::Text(moduleDirectory.getActive().c_str()); + ImGui::BulletText(activeCredit->ModuleDesc.c_str()); + ImGui::BulletText("v%i.%i.%i", activeCredit->VersionMajor, + activeCredit->VersionMinor, + activeCredit->VersionBuild); + ImGui::BulletText("Authored by %s", activeCredit->AuthorName.c_str()); + + ImGui::TreePop(); + } + ImGui::TreePop(); } @@ -257,6 +293,5 @@ int Inferno::run() mWin->render(); } - delete mWin; return 0; } \ No newline at end of file