Working on CLI args

This commit is contained in:
Alexandre 2026-08-23 16:22:22 +02:00
parent f8b47fbdd4
commit 77ff2d7c0e
7 changed files with 266 additions and 35 deletions

6
.gitmodules vendored
View File

@ -3,6 +3,6 @@
url = https://github.com/ocornut/imgui.git url = https://github.com/ocornut/imgui.git
branch = docking branch = docking
[submodule "include/CL11"] [submodule "include/CLI11"]
path = include/CL11 path = include/CLI11
url = "https://github.com/CLIUtils/CLI11.git" url = https://github.com/CLIUtils/CLI11.git

View File

@ -31,6 +31,9 @@ find_program (GLSLANG_VALIDATOR "glslangValidator" HINTS $ENV{VULKAN_SDK}/bin RE
set_property (TARGET glslang::validator PROPERTY IMPORTED_LOCATION "${GLSLANG_VALIDATOR}") set_property (TARGET glslang::validator PROPERTY IMPORTED_LOCATION "${GLSLANG_VALIDATOR}")
find_program(SLANGC_EXECUTABLE slangc HINTS $ENV{VULKAN_SDK}/bin REQUIRED) find_program(SLANGC_EXECUTABLE slangc HINTS $ENV{VULKAN_SDK}/bin REQUIRED)
# CL11
add_subdirectory(include/CLI11)
# fastgltf because it's not in nixpkgs # fastgltf because it's not in nixpkgs
FetchContent_Declare( FetchContent_Declare(
@ -91,7 +94,7 @@ endfunction()
# A function to automate executables aditions # A function to automate executables aditions
function ( addBinary BINARY_NAME ) function ( addBinary BINARY_NAME )
cmake_parse_arguments ( BINARY "IMGUI;LICENSE" "SOURCE" "SHADERS;SLANG_SHADERS;LIBS;TEXTURES;MODELS" ${ARGN} ) cmake_parse_arguments ( BINARY "IMGUI;LICENSE;GLOB_INCLUDE" "SOURCE" "SHADERS;SLANG_SHADERS;LIBS;TEXTURES;MODELS" ${ARGN} )
if (DEFINED BINARY_SOURCE) if (DEFINED BINARY_SOURCE)
add_executable ( ${BINARY_NAME} src/${BINARY_SOURCE}.cpp ) add_executable ( ${BINARY_NAME} src/${BINARY_SOURCE}.cpp )
endif() endif()
@ -118,20 +121,21 @@ function ( addBinary BINARY_NAME )
) )
if(BINARY_IMGUI) if(BINARY_IMGUI)
target_include_directories(${BINARY_NAME} PRIVATE target_include_directories(${BINARY_NAME} PRIVATE
${CMAKE_SOURCE_DIR}/src/imgui ${CMAKE_SOURCE_DIR}/include/imgui
${CMAKE_SOURCE_DIR}/src/imgui/backends ${CMAKE_SOURCE_DIR}/include/imgui/backends
) )
target_sources(${BINARY_NAME} PRIVATE target_sources(${BINARY_NAME} PRIVATE
${CMAKE_SOURCE_DIR}/src/imgui/imgui.cpp ${CMAKE_SOURCE_DIR}/include/imgui/imgui.cpp
${CMAKE_SOURCE_DIR}/src/imgui/imgui_draw.cpp ${CMAKE_SOURCE_DIR}/include/imgui/imgui_draw.cpp
${CMAKE_SOURCE_DIR}/src/imgui/imgui_tables.cpp ${CMAKE_SOURCE_DIR}/include/imgui/imgui_tables.cpp
${CMAKE_SOURCE_DIR}/src/imgui/imgui_widgets.cpp ${CMAKE_SOURCE_DIR}/include/imgui/imgui_widgets.cpp
${CMAKE_SOURCE_DIR}/src/imgui/imgui_demo.cpp ${CMAKE_SOURCE_DIR}/include/imgui/imgui_demo.cpp
#${CMAKE_SOURCE_DIR}/src/imgui/imgui_memory_editor.h #${CMAKE_SOURCE_DIR}/include/imgui/imgui_memory_editor.h
${CMAKE_SOURCE_DIR}/src/imgui/backends/imgui_impl_glfw.cpp ${CMAKE_SOURCE_DIR}/include/imgui/backends/imgui_impl_glfw.cpp
${CMAKE_SOURCE_DIR}/src/imgui/backends/imgui_impl_vulkan.cpp ${CMAKE_SOURCE_DIR}/include/imgui/backends/imgui_impl_vulkan.cpp
) )
endif() endif()
@ -219,7 +223,7 @@ addBinary (
SHADERS ${SHADER_SOURCES} SHADERS ${SHADER_SOURCES}
SHADERS SHADERS
LIBS glfw fmt vk-bootstrap vulkan LIBS glfw fmt vk-bootstrap vulkan CLI11::CLI11
IMGUI IMGUI
LICENSE LICENSE
) )

1
include/CLI11 Submodule

@ -0,0 +1 @@
Subproject commit c1cfe00d2f3d862aecfe6e69ec810414d5f4c906

View File

@ -86,8 +86,12 @@ class Logger {
Args&&... args Args&&... args
); // Logs to console and file, in cases of crashes or errors ); // Logs to console and file, in cases of crashes or errors
// Utils functions
void merge(std::string_view source); // Merges a source dumped logs into this void merge(std::string_view source); // Merges a source dumped logs into this
void logSeparator();
void clear(); void clear();
private: private:
@ -301,6 +305,10 @@ void Logger::merge(std::string_view source) {
logBuffer += source; logBuffer += source;
} }
void Logger::logSeparator() {
logDisk("=========================================================================");
}
void Logger::clear() { void Logger::clear() {
logBuffer.clear(); logBuffer.clear();
} }

View File

@ -100,6 +100,11 @@ struct GPUDrawPushConstants {
VkDeviceAddress vertexBuffer; VkDeviceAddress vertexBuffer;
}; };
// Engine config
struct EngineConfig {
int gpuIndex;
};
// "Global" ? (I hope so) logger // "Global" ? (I hope so) logger
Logger logger; Logger logger;

View File

@ -44,6 +44,8 @@ constexpr uint32_t FRAME_OVERLAP = 2;
class Engine { class Engine {
public: public:
//========== Class Members ========== //========== Class Members ==========
// Config
int _gpuIndex {0}; // Unitialized
bool _isInitialized { false }; bool _isInitialized { false };
int _frameNumber { 0 }; int _frameNumber { 0 };
VkExtent2D _windowExtent; VkExtent2D _windowExtent;
@ -128,6 +130,9 @@ class Engine {
GPUMeshBuffers rectangle; GPUMeshBuffers rectangle;
void parseConfig(
int gpuIndex = 0
);
void init(); void init();
@ -141,6 +146,9 @@ class Engine {
std::function <void(VkCommandBuffer cmd)>&& function std::function <void(VkCommandBuffer cmd)>&& function
); );
// Public functions (for CLI args)
void getAvailableGPU();
private: private:
using enum LogModule; using enum LogModule;
using enum LogLevel; using enum LogLevel;
@ -266,6 +274,13 @@ constexpr bool bUseValidationLayers = false;
//=== Main Functions === //=== Main Functions ===
//====================== //======================
void Engine::parseConfig(
int gpuIndex
) {
_gpuIndex = gpuIndex;
}
void Engine::init() { void Engine::init() {
#ifdef DEBUG #ifdef DEBUG
std::ifstream infile("LICENSE"); std::ifstream infile("LICENSE");
@ -352,7 +367,7 @@ void Engine::cleanup() {
glfwTerminate(); glfwTerminate();
} }
_logger.logDisk("========================================================================="); _logger.logSeparator();
#ifdef DEBUG #ifdef DEBUG
_logger.logConsole(CLEANUP, EINFO, "Engine cleaned up !"); _logger.logConsole(CLEANUP, EINFO, "Engine cleaned up !");
@ -616,6 +631,10 @@ void Engine::initVulkan() {
.bufferDeviceAddress = true .bufferDeviceAddress = true
}; };
if(_gpuIndex < 0) {
// No overwrite, use VKB
// Use vkBootstrap to select the GPU // Use vkBootstrap to select the GPU
vkb::PhysicalDeviceSelector selector { vkbInst }; vkb::PhysicalDeviceSelector selector { vkbInst };
vkb::PhysicalDevice physicalDevice = selector vkb::PhysicalDevice physicalDevice = selector
@ -638,6 +657,93 @@ void Engine::initVulkan() {
_graphicsQueue = { vkbDevice.get_queue(vkb::QueueType::graphics).value() }; _graphicsQueue = { vkbDevice.get_queue(vkb::QueueType::graphics).value() };
_graphicsQueueFamily = { vkbDevice.get_queue_index(vkb::QueueType::graphics).value() }; _graphicsQueueFamily = { vkbDevice.get_queue_index(vkb::QueueType::graphics).value() };
} else {
// Overwrite, select GPU by hand
#ifdef DEBUG
_logger.logAll(ENGINE, EINFO, "Manual GPU selection, choose {}", _gpuIndex);
#endif
uint32_t deviceCount = 0;
vkEnumeratePhysicalDevices(_instance, &deviceCount, nullptr);
if (deviceCount == 0) {
throw std::runtime_error("[Engine:Error] No Vulkan GPU found !");
}
std::vector<VkPhysicalDevice> devices(deviceCount);
vkEnumeratePhysicalDevices(_instance, &deviceCount, devices.data());
if (_gpuIndex >= deviceCount) {
throw std::runtime_error(
"[Engine:Error] GPU index "
+ std::to_string(_gpuIndex)
+ " out of bounds !("
+ std::to_string(deviceCount)
+ " available GPUs)"
);
}
_choosenGPU = devices[_gpuIndex];
VkPhysicalDeviceProperties props{};
vkGetPhysicalDeviceProperties(_choosenGPU, &props);
_logger.logAll(ENGINE, EINFO, "Device {}", props.deviceName);
// Now, find queues by hand
uint32_t queueFamilyCount = 0;
vkGetPhysicalDeviceQueueFamilyProperties(_choosenGPU, &queueFamilyCount, nullptr);
std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
vkGetPhysicalDeviceQueueFamilyProperties(_choosenGPU, &queueFamilyCount, queueFamilies.data());
std::optional<uint32_t> queueFamily;
for (uint32_t i = 0; i < queueFamilyCount; ++i) {
VkBool32 presentSupport = VK_FALSE;
vkGetPhysicalDeviceSurfaceSupportKHR(_choosenGPU, i, _surface, &presentSupport);
if ((queueFamilies[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) && presentSupport) {
queueFamily = i;
break;
}
}
if (!queueFamily.has_value()) {
throw std::runtime_error("[Engine:Error] No graphics queue compatible with the surface on the selected GPU !");
}
_graphicsQueueFamily = queueFamily.value();
// 3. Créer le device logique
float queuePriority = 1.0f;
VkDeviceQueueCreateInfo queueCreateInfo{};
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queueCreateInfo.queueFamilyIndex = _graphicsQueueFamily;
queueCreateInfo.queueCount = 1;
queueCreateInfo.pQueuePriorities = &queuePriority;
features13.pNext = &features12;
std::vector<const char*> deviceExtensions = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME
};
VkDeviceCreateInfo deviceCreateInfo{};
deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
deviceCreateInfo.pNext = &features13;
deviceCreateInfo.queueCreateInfoCount = 1;
deviceCreateInfo.pQueueCreateInfos = &queueCreateInfo;
deviceCreateInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size());
deviceCreateInfo.ppEnabledExtensionNames = deviceExtensions.data();
if (vkCreateDevice(_choosenGPU, &deviceCreateInfo, nullptr, &_device) != VK_SUCCESS) {
throw std::runtime_error("[Engine:Error] Failed to create Vulkan device !");
}
vkGetDeviceQueue(_device, _graphicsQueueFamily, 0, &_graphicsQueue);
}
VmaAllocatorCreateInfo allocatorInfo = {}; VmaAllocatorCreateInfo allocatorInfo = {};
allocatorInfo.physicalDevice = _choosenGPU; allocatorInfo.physicalDevice = _choosenGPU;
allocatorInfo.device = _device; allocatorInfo.device = _device;
@ -2067,7 +2173,50 @@ void Engine::resizeRenderImage(uint32_t width, uint32_t height) {
#endif #endif
} }
void Engine::getAvailableGPU() {
// Creates a temporary Vulkan Instance
// Largely copied from initVulkan function
#ifdef DEBUG
_logger.logDisk(ENGINE, EINFO, "Listing available GPUs...");
#endif
vkb::InstanceBuilder builder;
// Create a minimal instance
auto instRet = builder.set_app_name("Engine")
.request_validation_layers(false)
.use_default_debug_messenger()
.require_api_version(1, 3, 0)
.build();
vkb::Instance vkbInst = instRet.value();
VkInstance instance = vkbInst.instance;
// Get GPUs
uint32_t deviceCount {0};
vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
// Juicy vector, to interate upon
std::vector<VkPhysicalDevice> devices(deviceCount);
vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
_logger.logAll(ENGINE, EINFO, "Found {} devices !", deviceCount);
// Now, loop !
for(
uint32_t i = 0;
i < devices.size();
++i
) {
// Get properties
VkPhysicalDeviceProperties2 deviceProperties{
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2
};
vkGetPhysicalDeviceProperties2(
devices[i],
&deviceProperties
);
_logger.logAll(ENGINE, EINFO, "GPU {}:\n{}", i, deviceProperties.properties.deviceName);
}
}
#endif #endif
#endif #endif

View File

@ -7,18 +7,82 @@ Also, checkout the roadmap
#define ENGINE_IMPL #define ENGINE_IMPL
#include "engine/engine.h" #include "engine/engine.h"
#include "CLI/CLI.hpp"
class ArgHandler {
public:
CLI::App* _run;
// All options
bool _listGPU {false};
int _gpuIndex {0};
void buildArgs() {
// Setup
// Subcommands
_run = _app.add_subcommand("run", "Starts the Engine");
// Main options/flags
_app.add_flag("--list-gpu", _listGPU, "Lists available Graphics cards, useful for debugging");
// Subcommand options/flags
// Run
_run->add_option("--gpu, -g", _gpuIndex, "Manually select a GPU");
}
int dispatch(int argc, char* argv[]) {
CLI11_PARSE(_app, argc, argv);
return 0;
}
void printHelp() {
fmt::println("{}", _app.help());
}
private:
CLI::App _app;
};
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
// Classes we need
Engine engine; Engine engine;
ArgHandler handler;
// Exemple of overwriting a class value // Exemple of overwriting a class value
//engine._windowExtent = { 67, 67 }; //engine._windowExtent = { 67, 67 };
handler.buildArgs();
if (argc == 1) {
handler.printHelp();
return 0;
}
// Checks for -h flag
int result = handler.dispatch(argc, argv);
if(result != 0) return result;
if (handler._run->parsed() &&
handler._run->get_help_ptr()->as<bool>()) {
return 0;
}
if(handler._listGPU) {
engine.getAvailableGPU();
return 0;
}
if(handler._run->parsed()){
engine.parseConfig(handler._gpuIndex);
engine.init(); engine.init();
engine.run(); engine.run();
engine.cleanup(); engine.cleanup();
}
return 0; return 0;
} }