From 25cc75ba690fc5be6ed1a2f0c3cc755f2ab7294c Mon Sep 17 00:00:00 2001 From: Jiga228 Date: Tue, 16 Sep 2025 21:56:34 +0700 Subject: [PATCH 01/17] Integrate RenderEngine to Core --- CMakeLists.txt | 1 - Core/CMakeLists.txt | 2 - Core/Core/CoreInstance.cpp | 70 +++++++++++--------- Core/Core/CoreInstance.h | 32 +++++---- {RenderModule => Core/Core}/RenderEngine.cpp | 34 ++++------ {RenderModule => Core/Core}/RenderEngine.h | 16 ++--- Core/Game/GameInstance.cpp | 1 + Core/Game/SaveMap/SaveMap.cpp | 18 +++-- RenderModule/CMakeLists.txt | 23 ------- TestGame/main_config.conf | 2 +- 10 files changed, 93 insertions(+), 106 deletions(-) rename {RenderModule => Core/Core}/RenderEngine.cpp (89%) rename {RenderModule => Core/Core}/RenderEngine.h (54%) delete mode 100644 RenderModule/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 9bf010c..6d6e0a6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,6 +20,5 @@ add_subdirectory(FastRTTI) add_subdirectory(glfw) add_subdirectory(Core) add_subdirectory(ModuleLib) -add_subdirectory(RenderModule) add_subdirectory(TestGame) add_subdirectory(ProjectGenerator) diff --git a/Core/CMakeLists.txt b/Core/CMakeLists.txt index 83fcbdd..7b97125 100644 --- a/Core/CMakeLists.txt +++ b/Core/CMakeLists.txt @@ -2,8 +2,6 @@ set(CORE_NAME Core) find_package(Vulkan REQUIRED) -set(CORE_NAME Core) - file(GLOB_RECURSE SRC "*.cpp" "*.c" "*.h" "*.hpp") add_library(${CORE_NAME} STATIC ${SRC}) diff --git a/Core/Core/CoreInstance.cpp b/Core/Core/CoreInstance.cpp index 30e719b..b3799e0 100644 --- a/Core/Core/CoreInstance.cpp +++ b/Core/Core/CoreInstance.cpp @@ -1,17 +1,22 @@ #include "CoreInstance.h" #include "SystemCalls.h" -#include "GLFW/glfw3.h" #include #include #include #include +#include +#include "RenderEngine.h" +#include "Game/GameInstance.h" #include "Log/Log.h" +#include "Game/SaveMap/SaveMap.h" CoreInstance* CoreInstance::self = nullptr; +extern GameInstance* GameFactory(CoreInstance&); + std::shared_ptr CoreInstance::MainConfig::save() { return std::make_shared("MainConfig"); @@ -28,7 +33,7 @@ void CoreInstance::MainConfig::load(std::shared_ptr save) void CoreInstance::Quit_callback() { - self->game->quit(); + self->game_->quit(); } CoreInstance::CoreInstance() @@ -37,16 +42,8 @@ CoreInstance::CoreInstance() callbacks_.Quit = &Quit_callback; - countCPU = System::getCountCPU(); - memorySize = System::getMemorySize(); - - if (!glfwInit()) - { - std::string msg; - const char* error; - glfwGetError(&error); - throw std::runtime_error("Fail initialize GLFW"); - } + countCPU_ = System::getCountCPU(); + memorySize_ = System::getMemorySize(); std::ifstream main_config_file(main_config_name); if (main_config_file.fail()) @@ -56,35 +53,40 @@ CoreInstance::CoreInstance() std::getline(main_config_file, payload); SaveMap load_main_config(payload); - main_config.load(std::make_shared(load_main_config)); + main_config_.load(std::make_shared(load_main_config)); + + render_engine_ = new RenderEngine(); + + game_ = GameFactory(*this); + if (game_ == nullptr) + throw std::runtime_error("Fail create game instance!"); } CoreInstance::~CoreInstance() { - delete game; - - for (auto& module : modules) + for (auto& module : modules_) System::QuitModule(module.handler); - modules.clear(); -} + modules_.clear(); -extern GameInstance* GameFactory(CoreInstance&); + delete render_engine_; + delete game_; +} void CoreInstance::start() { - for (auto& name : main_config.modules_names) + for (auto& name : main_config_.modules_names) { try { void* handler = System::InitModule(name.c_str(), &callbacks_); - modules.push_back(Module {name.c_str(), handler}); + modules_.push_back(Module {name.c_str(), handler}); } catch (const std::exception& e) { std::cout << e.what() << '\n'; } } - for (auto& module : modules) + for (auto& module : modules_) { try { @@ -95,15 +97,21 @@ void CoreInstance::start() } } - game = GameFactory(*this); - if (game == nullptr) - throw std::runtime_error("Fail create game instance!"); - game->start(); + std::thread game_thread(&GameInstance::start, game_); + render_engine_->start(); + game_->quit(); + game_thread.join(); +} + +void CoreInstance::quit() +{ + // Stop the main loop + render_engine_->stop_render(); } void* CoreInstance::getHandlerModule(const char* name) const { - for (const auto& module : modules) + for (const auto& module : modules_) { if (std::strcmp(module.name, name) == 0) return module.handler; @@ -113,25 +121,25 @@ void* CoreInstance::getHandlerModule(const char* name) const void* CoreInstance::enableModule(const char* name) { - for (const auto& module : modules) + for (const auto& module : modules_) { if (std::strcmp(module.name, name) == 0) throw std::runtime_error("Module already enabled"); } void* module = System::InitModule(name, &callbacks_); - modules.push_back({ name, module }); + modules_.push_back({ name, module }); return module; } void CoreInstance::disableModule(const char* name) { - for (auto i = modules.cbegin(); i != modules.cend(); ++i) + for (auto i = modules_.cbegin(); i != modules_.cend(); ++i) { if (std::strcmp(i->name, name) == 0) { System::QuitModule(i->handler); - modules.erase(i); + modules_.erase(i); break; } } diff --git a/Core/Core/CoreInstance.h b/Core/Core/CoreInstance.h index 9668f1c..7fb8f03 100644 --- a/Core/Core/CoreInstance.h +++ b/Core/Core/CoreInstance.h @@ -2,13 +2,17 @@ #include #include +#include +#include -#include "Game/GameInstance.h" -#include "Game/SaveMap/SaveMap.h" +#include "Game/SaveMap/ISave.h" #include "Core/CoreCallBacks.h" +class SaveMap; +class RenderEngine; +class GameInstance; + class CoreInstance { - static CoreInstance* self; struct Module { const char* name; void* handler; @@ -28,14 +32,17 @@ class CoreInstance { }; const char* main_config_name = "main_config.conf"; - MainConfig main_config; + MainConfig main_config_; - int countCPU; + int countCPU_; // Memory in MB - double memorySize; - std::list modules; + double memorySize_; + std::list modules_; - GameInstance* game = nullptr; + RenderEngine* render_engine_; + GameInstance* game_; + + static CoreInstance* self; CoreCallBacks callbacks_; #pragma region Callbacks @@ -46,14 +53,15 @@ public: ~CoreInstance(); void start(); + void quit(); /** * This method quit game * Async */ - int getCountCPU() const { return countCPU; } - double getMemorySize() const { return memorySize; } + int getCountCPU() const { return countCPU_; } + double getMemorySize() const { return memorySize_; } /** * @throws std::runtime_error if module isn't enabled @@ -74,6 +82,6 @@ public: */ void disableModule(const char* name) noexcept(false); - const std::string& getBaseWorldName() const { return main_config.base_world; } - const std::string& getGameName() const { return main_config.game_name; } + const std::string& getBaseWorldName() const { return main_config_.base_world; } + const std::string& getGameName() const { return main_config_.game_name; } }; diff --git a/RenderModule/RenderEngine.cpp b/Core/Core/RenderEngine.cpp similarity index 89% rename from RenderModule/RenderEngine.cpp rename to Core/Core/RenderEngine.cpp index ec07447..196df2f 100644 --- a/RenderModule/RenderEngine.cpp +++ b/Core/Core/RenderEngine.cpp @@ -1,15 +1,10 @@ #include "RenderEngine.h" #include -#include #include -#include "Core/CoreInstance.h" - -PROTECTION_FROM_GB(RenderEngine) - #ifdef _DEBUG -//#include "Log/Log.h" +#include "Log/Log.h" #include #define VK_CHECK(res) assert(res == VK_SUCCESS) @@ -21,15 +16,15 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback( std::string msg = "validation layer: "; msg += pCallbackData->pMessage; - //Log(msg); + Log(msg); return VK_FALSE; } -VkResult RenderEngine::enable_layer_validation(VkInstance instance, VkDebugUtilsMessengerCreateInfoEXT* create_info) +VkResult RenderEngine::enable_layer_validation(VkDebugUtilsMessengerCreateInfoEXT* create_info) { - PFN_vkCreateDebugUtilsMessengerEXT debug_creator = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT")); - return debug_creator(instance, create_info, nullptr, &debug_messenger_); + PFN_vkCreateDebugUtilsMessengerEXT debug_creator = reinterpret_cast(vkGetInstanceProcAddr(instance_, "vkCreateDebugUtilsMessengerEXT")); + return debug_creator(instance_, create_info, nullptr, &debug_messenger_); } #else #define VK_CHECK(res) if ((res) != VK_SUCCESS) throw std::runtime_error("Vulkan error: " + std::to_string(res)) @@ -52,10 +47,15 @@ RenderEngine::RenderEngine() : window(nullptr) , debug_messenger_(nullptr) #endif { - onStop.bind(this, &RenderEngine::stop_render); - if (glfwInit() == GLFW_FALSE) throw std::runtime_error("Fail init glfw"); + + window = glfwCreateWindow(640, 480, "UwU Engine", nullptr, nullptr); + if (!window) + { + glfwTerminate(); + throw std::runtime_error("Fail create window"); + } { std::vector extensions = get_required_extensions(); @@ -91,7 +91,7 @@ RenderEngine::RenderEngine() : window(nullptr) #endif VK_CHECK(vkCreateInstance(&instance_create_info, nullptr, &instance_)); #ifdef _DEBUG - VK_CHECK(enable_layer_validation(instance_, &debug_messenger_create_info)); + VK_CHECK(enable_layer_validation(&debug_messenger_create_info)); #endif } @@ -128,19 +128,11 @@ RenderEngine::~RenderEngine() void RenderEngine::start() { - window = glfwCreateWindow(640, 480, "UwU Engine", nullptr, nullptr); - if (!window) - { - glfwTerminate(); - throw std::runtime_error("Fail create window"); - } - while (!glfwWindowShouldClose(window)) { glfwSwapBuffers(window); glfwPollEvents(); } - QuitGame(); } void RenderEngine::stop_render() diff --git a/RenderModule/RenderEngine.h b/Core/Core/RenderEngine.h similarity index 54% rename from RenderModule/RenderEngine.h rename to Core/Core/RenderEngine.h index 3551b85..c9202fc 100644 --- a/RenderModule/RenderEngine.h +++ b/Core/Core/RenderEngine.h @@ -1,31 +1,27 @@ #pragma once #define GLFW_INCLUDE_VULKAN +#include #include "GLFW/glfw3.h" -#include "ModuleInstance.h" - #include -template -class Delegate; - -class RenderEngine : public ModuleInstance +class RenderEngine { GLFWwindow* window; VkInstance instance_; #ifdef _DEBUG - VkResult enable_layer_validation(VkInstance instance, VkDebugUtilsMessengerCreateInfoEXT* create_info); + VkResult enable_layer_validation(VkDebugUtilsMessengerCreateInfoEXT* create_info); VkDebugUtilsMessengerEXT debug_messenger_; #endif static std::vector get_required_extensions(); - void stop_render(); public: RenderEngine(); - ~RenderEngine() override; + ~RenderEngine(); - void start() override; + void start(); + void stop_render(); }; \ No newline at end of file diff --git a/Core/Game/GameInstance.cpp b/Core/Game/GameInstance.cpp index 7442993..066c7ef 100644 --- a/Core/Game/GameInstance.cpp +++ b/Core/Game/GameInstance.cpp @@ -66,4 +66,5 @@ void GameInstance::start() void GameInstance::quit() { is_running = false; + core.quit(); } diff --git a/Core/Game/SaveMap/SaveMap.cpp b/Core/Game/SaveMap/SaveMap.cpp index f6df842..93f1417 100644 --- a/Core/Game/SaveMap/SaveMap.cpp +++ b/Core/Game/SaveMap/SaveMap.cpp @@ -66,7 +66,11 @@ SaveMap::SaveMap(const std::string& json_data) size_t begin = json_data.find(':', i) + 2; size_t end = i = json_data.find('\"', begin); i++; - std::string value = json_data.substr(begin, end - begin); + std::string value; + if (begin != end) + value = json_data.substr(begin, end - begin); + else + value = ""; save_string[name.c_str() + 1] = value; } else if (name[0] == 'o') { @@ -147,12 +151,16 @@ SaveMap::SaveMap(const std::string& json_data) continue; std::vector& vector_strings = save_vector_strings[key]; - size_t j = 2; + size_t j = 0; while (j < arr_data.length()) { - size_t begin = j; - size_t end = j = arr_data.find('\"', begin + 1); - std::string value = arr_data.substr(begin, end - begin); + size_t begin = arr_data.find('\"', j) + 1; + size_t end = j = arr_data.find('\"', begin); + std::string value; + if (begin != end) + value = arr_data.substr(begin, end - begin); + else + value = ""; vector_strings.push_back(value); j += 3; } diff --git a/RenderModule/CMakeLists.txt b/RenderModule/CMakeLists.txt deleted file mode 100644 index 7eda801..0000000 --- a/RenderModule/CMakeLists.txt +++ /dev/null @@ -1,23 +0,0 @@ -find_package(Vulkan REQUIRED) - -file(GLOB_RECURSE SRC "*.cpp" "*.c" "*.h" "*.hpp") -add_library(RenderModule SHARED ${SRC}) - -target_compile_features(RenderModule PRIVATE cxx_std_17) - -target_include_directories(RenderModule - PRIVATE - ${PROJECT_SOURCE_DIR}/ModuleLib - ${PROJECT_SOURCE_DIR}/Core - ${PROJECT_SOURCE_DIR}/FastRTTI - ${PROJECT_SOURCE_DIR}/Delegate - ${PROJECT_SOURCE_DIR}/glfw/Include - ${Vulkan_INCLUDE_DIRS} -) - -target_link_libraries(RenderModule PRIVATE - ModuleLib - FastRTTI - glfw - Vulkan::Vulkan -) \ No newline at end of file diff --git a/TestGame/main_config.conf b/TestGame/main_config.conf index c99154d..a51e392 100644 --- a/TestGame/main_config.conf +++ b/TestGame/main_config.conf @@ -1 +1 @@ -{"Class name":"MainConfig","dmin_memory_size":"4096.0","imin_CPU_count":"1","sgame_name":"Test Game","sbase_world":"TestWorld","vsmodules_names":["RenderModule"]} \ No newline at end of file +{"Class name":"MainConfig","dmin_memory_size":"4096.0","imin_CPU_count":"1","sgame_name":"Test Game","sbase_world":"TestWorld","vsmodules_names":[]} \ No newline at end of file From e151663de5be3a20aad55f8a2d40c397fb34d849 Mon Sep 17 00:00:00 2001 From: Jiga228 Date: Wed, 17 Sep 2025 21:51:31 +0700 Subject: [PATCH 02/17] Moved window create from RenderEngine to CoreInstance --- Core/Core/CoreInstance.cpp | 21 ++++++++++++++------- Core/Core/CoreInstance.h | 9 +++------ Core/Core/RenderEngine.cpp | 24 +++++++----------------- Core/Core/RenderEngine.h | 4 ++-- Core/Game/GameInstance.cpp | 7 ++++++- Core/Game/GameInstance.h | 5 +---- 6 files changed, 33 insertions(+), 37 deletions(-) diff --git a/Core/Core/CoreInstance.cpp b/Core/Core/CoreInstance.cpp index b3799e0..a9a72fb 100644 --- a/Core/Core/CoreInstance.cpp +++ b/Core/Core/CoreInstance.cpp @@ -8,7 +8,6 @@ #include #include -#include "RenderEngine.h" #include "Game/GameInstance.h" #include "Log/Log.h" #include "Game/SaveMap/SaveMap.h" @@ -55,11 +54,19 @@ CoreInstance::CoreInstance() main_config_.load(std::make_shared(load_main_config)); - render_engine_ = new RenderEngine(); - - game_ = GameFactory(*this); - if (game_ == nullptr) - throw std::runtime_error("Fail create game instance!"); + if (glfwInit() == GLFW_FALSE) + throw std::runtime_error("Fail init glfw"); + window_ = glfwCreateWindow(800, 600, main_config_.game_name.c_str(), nullptr, nullptr); + if (window_ == nullptr) + { + glfwTerminate(); + throw std::runtime_error("Fail create window"); + } + render_engine_ = new RenderEngine(window_); + + game_ = GameFactory(*this); + if (game_ == nullptr) + throw std::runtime_error("Fail create game instance!"); } CoreInstance::~CoreInstance() @@ -99,7 +106,7 @@ void CoreInstance::start() std::thread game_thread(&GameInstance::start, game_); render_engine_->start(); - game_->quit(); + game_->stop(); game_thread.join(); } diff --git a/Core/Core/CoreInstance.h b/Core/Core/CoreInstance.h index 7fb8f03..410c422 100644 --- a/Core/Core/CoreInstance.h +++ b/Core/Core/CoreInstance.h @@ -5,6 +5,7 @@ #include #include +#include "RenderEngine.h" #include "Game/SaveMap/ISave.h" #include "Core/CoreCallBacks.h" @@ -25,7 +26,7 @@ class CoreInstance { std::vector modules_names; double min_memory_size = -1; - int min_CPU_count = -1; + long long min_CPU_count = -1; std::shared_ptr save() override; void load(std::shared_ptr save) override; @@ -39,6 +40,7 @@ class CoreInstance { double memorySize_; std::list modules_; + GLFWwindow* window_ = nullptr; RenderEngine* render_engine_; GameInstance* game_; @@ -54,11 +56,6 @@ public: void start(); void quit(); - - /** - * This method quit game - * Async - */ int getCountCPU() const { return countCPU_; } double getMemorySize() const { return memorySize_; } diff --git a/Core/Core/RenderEngine.cpp b/Core/Core/RenderEngine.cpp index 196df2f..5610168 100644 --- a/Core/Core/RenderEngine.cpp +++ b/Core/Core/RenderEngine.cpp @@ -42,21 +42,11 @@ std::vector RenderEngine::get_required_extensions() return extensions; } -RenderEngine::RenderEngine() : window(nullptr) +RenderEngine::RenderEngine(GLFWwindow* window) : window_(window) #ifdef _DEBUG , debug_messenger_(nullptr) #endif { - if (glfwInit() == GLFW_FALSE) - throw std::runtime_error("Fail init glfw"); - - window = glfwCreateWindow(640, 480, "UwU Engine", nullptr, nullptr); - if (!window) - { - glfwTerminate(); - throw std::runtime_error("Fail create window"); - } - { std::vector extensions = get_required_extensions(); std::vector layers = { @@ -121,22 +111,22 @@ RenderEngine::~RenderEngine() if (instance_ != nullptr) vkDestroyInstance(instance_, nullptr); - if (window != nullptr) - glfwDestroyWindow(window); + if (window_ != nullptr) + glfwDestroyWindow(window_); glfwTerminate(); } void RenderEngine::start() { - while (!glfwWindowShouldClose(window)) + while (!glfwWindowShouldClose(window_)) { - glfwSwapBuffers(window); + glfwSwapBuffers(window_); glfwPollEvents(); } } void RenderEngine::stop_render() { - if (window != nullptr && !glfwWindowShouldClose(window)) - glfwSetWindowShouldClose(window, true); + if (window_ != nullptr && !glfwWindowShouldClose(window_)) + glfwSetWindowShouldClose(window_, true); } diff --git a/Core/Core/RenderEngine.h b/Core/Core/RenderEngine.h index c9202fc..f87929e 100644 --- a/Core/Core/RenderEngine.h +++ b/Core/Core/RenderEngine.h @@ -8,7 +8,7 @@ class RenderEngine { - GLFWwindow* window; + GLFWwindow* window_; VkInstance instance_; #ifdef _DEBUG @@ -19,7 +19,7 @@ class RenderEngine static std::vector get_required_extensions(); public: - RenderEngine(); + RenderEngine(GLFWwindow* window); ~RenderEngine(); void start(); diff --git a/Core/Game/GameInstance.cpp b/Core/Game/GameInstance.cpp index 066c7ef..43c5f37 100644 --- a/Core/Game/GameInstance.cpp +++ b/Core/Game/GameInstance.cpp @@ -63,8 +63,13 @@ void GameInstance::start() } } -void GameInstance::quit() +void GameInstance::stop() { is_running = false; +} + +void GameInstance::quit() +{ + stop(); core.quit(); } diff --git a/Core/Game/GameInstance.h b/Core/Game/GameInstance.h index 6fc0fc3..3da336a 100644 --- a/Core/Game/GameInstance.h +++ b/Core/Game/GameInstance.h @@ -16,11 +16,8 @@ class GameInstance std::atomic is_running = true; - // Create a window - // Render - // Pull events void start(); - + void stop(); public: void quit(); From 6ce11daa2442d0d2b159b8a2c431755b0d99327f Mon Sep 17 00:00:00 2001 From: Jiga228 Date: Thu, 18 Sep 2025 20:19:24 +0700 Subject: [PATCH 03/17] Add choose GPU. --- Core/Core/CoreInstance.cpp | 1 + Core/Core/CoreInstance.h | 2 +- Core/Core/RenderEngine.cpp | 28 ++++++++++++++++++++++++---- Core/Core/RenderEngine.h | 5 +++-- 4 files changed, 29 insertions(+), 7 deletions(-) diff --git a/Core/Core/CoreInstance.cpp b/Core/Core/CoreInstance.cpp index a9a72fb..db8f6f1 100644 --- a/Core/Core/CoreInstance.cpp +++ b/Core/Core/CoreInstance.cpp @@ -8,6 +8,7 @@ #include #include +#include "RenderEngine.h" #include "Game/GameInstance.h" #include "Log/Log.h" #include "Game/SaveMap/SaveMap.h" diff --git a/Core/Core/CoreInstance.h b/Core/Core/CoreInstance.h index 410c422..897d537 100644 --- a/Core/Core/CoreInstance.h +++ b/Core/Core/CoreInstance.h @@ -5,13 +5,13 @@ #include #include -#include "RenderEngine.h" #include "Game/SaveMap/ISave.h" #include "Core/CoreCallBacks.h" class SaveMap; class RenderEngine; class GameInstance; +struct GLFWwindow; class CoreInstance { struct Module { diff --git a/Core/Core/RenderEngine.cpp b/Core/Core/RenderEngine.cpp index 5610168..1e9a487 100644 --- a/Core/Core/RenderEngine.cpp +++ b/Core/Core/RenderEngine.cpp @@ -2,9 +2,9 @@ #include #include +#include "Log/Log.h" #ifdef _DEBUG -#include "Log/Log.h" #include #define VK_CHECK(res) assert(res == VK_SUCCESS) @@ -42,9 +42,19 @@ std::vector RenderEngine::get_required_extensions() return extensions; } +bool RenderEngine::is_device_suitable(VkPhysicalDevice device) +{ + VkPhysicalDeviceProperties device_properties; + VkPhysicalDeviceFeatures device_features; + vkGetPhysicalDeviceProperties(device, &device_properties); + vkGetPhysicalDeviceFeatures(device, &device_features); + + return device_properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU && device_features.geometryShader; +} + RenderEngine::RenderEngine(GLFWwindow* window) : window_(window) #ifdef _DEBUG -, debug_messenger_(nullptr) + , debug_messenger_(nullptr) #endif { { @@ -89,13 +99,23 @@ RenderEngine::RenderEngine(GLFWwindow* window) : window_(window) uint32_t device_count = 0; std::vector devices; VK_CHECK(vkEnumeratePhysicalDevices(instance_, &device_count, nullptr)); + devices.resize(device_count); VK_CHECK(vkEnumeratePhysicalDevices(instance_, &device_count, devices.data())); for (const auto& device : devices) { - VkPhysicalDeviceProperties device_properties; - vkGetPhysicalDeviceProperties(device, &device_properties); + if (is_device_suitable(device)) + { + physical_device_ = device; + VkPhysicalDeviceProperties device_properties; + vkGetPhysicalDeviceProperties(physical_device_, &device_properties); + Log("Using device: " + std::string(device_properties.deviceName)); + break; + } } + + if (VK_NULL_HANDLE == physical_device_) + throw std::runtime_error("No suitable device found"); } } diff --git a/Core/Core/RenderEngine.h b/Core/Core/RenderEngine.h index f87929e..764330b 100644 --- a/Core/Core/RenderEngine.h +++ b/Core/Core/RenderEngine.h @@ -9,7 +9,8 @@ class RenderEngine { GLFWwindow* window_; - VkInstance instance_; + VkInstance instance_ = VK_NULL_HANDLE; + VkPhysicalDevice physical_device_ = VK_NULL_HANDLE; #ifdef _DEBUG VkResult enable_layer_validation(VkDebugUtilsMessengerCreateInfoEXT* create_info); @@ -17,7 +18,7 @@ class RenderEngine #endif static std::vector get_required_extensions(); - + bool is_device_suitable(VkPhysicalDevice device); public: RenderEngine(GLFWwindow* window); ~RenderEngine(); From f334d723f43caacf0d47433c0f41253c20edc501 Mon Sep 17 00:00:00 2001 From: Jiga228 Date: Fri, 19 Sep 2025 20:01:00 +0700 Subject: [PATCH 04/17] Remove linux support. Add create logical device --- Core/Core/CoreInstance.cpp | 2 +- Core/Core/CoreInstance.h | 7 +- Core/Core/Linux.cpp | 64 ------- Core/Core/RenderEngine.cpp | 160 +++++++++++++----- Core/Core/RenderEngine.h | 22 ++- .../{Windows.cpp => Windows/WindowsCalls.cpp} | 4 +- 6 files changed, 144 insertions(+), 115 deletions(-) delete mode 100644 Core/Core/Linux.cpp rename Core/Core/{Windows.cpp => Windows/WindowsCalls.cpp} (95%) diff --git a/Core/Core/CoreInstance.cpp b/Core/Core/CoreInstance.cpp index db8f6f1..518705f 100644 --- a/Core/Core/CoreInstance.cpp +++ b/Core/Core/CoreInstance.cpp @@ -63,7 +63,7 @@ CoreInstance::CoreInstance() glfwTerminate(); throw std::runtime_error("Fail create window"); } - render_engine_ = new RenderEngine(window_); + render_engine_ = new RenderEngine(*this, window_); game_ = GameFactory(*this); if (game_ == nullptr) diff --git a/Core/Core/CoreInstance.h b/Core/Core/CoreInstance.h index 897d537..43ee59f 100644 --- a/Core/Core/CoreInstance.h +++ b/Core/Core/CoreInstance.h @@ -59,7 +59,9 @@ public: int getCountCPU() const { return countCPU_; } double getMemorySize() const { return memorySize_; } - + const std::string& getBaseWorldName() const { return main_config_.base_world; } + const std::string& getGameName() const { return main_config_.game_name; } + /** * @throws std::runtime_error if module isn't enabled * @throws std::runtime_error if module not found @@ -78,7 +80,4 @@ public: * @throws std::runtime_error module isn't contain QuitModule function */ void disableModule(const char* name) noexcept(false); - - const std::string& getBaseWorldName() const { return main_config_.base_world; } - const std::string& getGameName() const { return main_config_.game_name; } }; diff --git a/Core/Core/Linux.cpp b/Core/Core/Linux.cpp deleted file mode 100644 index 4e93d75..0000000 --- a/Core/Core/Linux.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#ifdef __linux__ - -#include "SystemCalls.h" - -#include -#include -#include - -#include -#include - -int System::getCountCPU() -{ - int num_cores = sysconf(_SC_NPROCESSORS_ONLN); - if(num_cores <= 0) - throw std::runtime_error("Fail get number of cores"); - - return num_cores; -} - -double System::getMemorySize() -{ - struct sysinfo info{}; - if(sysinfo(&info) == -1) - std::runtime_error("Fail get system info"); - return info.totalram / 1024 / 1024; -} - -void* System::InitModule(const char* ModuleName, CoreInstance& core) -{ - std::string fileName = "./lib"; - fileName += ModuleName; - fileName += ".so"; - - void* handler = dlopen(fileName.c_str(), RTLD_NOW); - if(handler == nullptr) - throw std::runtime_error("Module not found"); - - void(*init)(CoreInstance&) = reinterpret_cast(dlsym(handler, "InitModule")); - if(init == nullptr) - throw std::runtime_error("Module not contains InitModule"); - init(core); - - return handler; -} - -void System::StartModule(void* handler) -{ - void(*start)() = reinterpret_cast(dlsym(handler, "StartModule")); - if(start == nullptr) - throw std::runtime_error("Module not contins StartModule"); - start(); -} - -void System::QuitModule(void* handler) -{ - void(*quit)() = reinterpret_cast(dlsym(handler, "QuitModule")); - if(quit == nullptr) - throw std::runtime_error("Module not contains QuitModule"); - quit(); - dlclose(handler); -} - -#endif diff --git a/Core/Core/RenderEngine.cpp b/Core/Core/RenderEngine.cpp index 1e9a487..decf4fe 100644 --- a/Core/Core/RenderEngine.cpp +++ b/Core/Core/RenderEngine.cpp @@ -2,6 +2,8 @@ #include #include + +#include "CoreInstance.h" #include "Log/Log.h" #ifdef _DEBUG @@ -21,6 +23,11 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback( return VK_FALSE; } +bool RenderEngine::QueueFamilyIndices::is_complete() +{ + return graphycs_family.has_value(); +} + VkResult RenderEngine::enable_layer_validation(VkDebugUtilsMessengerCreateInfoEXT* create_info) { PFN_vkCreateDebugUtilsMessengerEXT debug_creator = reinterpret_cast(vkGetInstanceProcAddr(instance_, "vkCreateDebugUtilsMessengerEXT")); @@ -48,54 +55,73 @@ bool RenderEngine::is_device_suitable(VkPhysicalDevice device) VkPhysicalDeviceFeatures device_features; vkGetPhysicalDeviceProperties(device, &device_properties); vkGetPhysicalDeviceFeatures(device, &device_features); + + QueueFamilyIndices indices = find_queue_family_indices(device); - return device_properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU && device_features.geometryShader; + return device_properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU + && device_features.geometryShader + && indices.is_complete(); } -RenderEngine::RenderEngine(GLFWwindow* window) : window_(window) -#ifdef _DEBUG - , debug_messenger_(nullptr) -#endif +RenderEngine::QueueFamilyIndices RenderEngine::find_queue_family_indices(VkPhysicalDevice device) { - { - std::vector extensions = get_required_extensions(); - std::vector layers = { -#ifdef _DEBUG - "VK_LAYER_KHRONOS_validation" -#endif - }; + QueueFamilyIndices queue_family_indices; + + uint32_t queueFamilyCount = 0; + vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr); + std::vector family_propertieses(queueFamilyCount); + vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, family_propertieses.data()); - VkApplicationInfo app_info{}; - app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; - app_info.apiVersion = VK_API_VERSION_1_0; - app_info.applicationVersion = VK_MAKE_VERSION(0, 0, 0); - app_info.pApplicationName = "UwU Engine"; - app_info.pEngineName = "UwU Engine"; - app_info.engineVersion = VK_MAKE_VERSION(0, 0, 0); - - - VkInstanceCreateInfo instance_create_info{}; - instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; - instance_create_info.pApplicationInfo = &app_info; - instance_create_info.enabledExtensionCount = extensions.size(); - instance_create_info.ppEnabledExtensionNames = extensions.data(); - instance_create_info.enabledLayerCount = layers.size(); - instance_create_info.ppEnabledLayerNames = layers.data(); -#ifdef _DEBUG - VkDebugUtilsMessengerCreateInfoEXT debug_messenger_create_info{}; - debug_messenger_create_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; - debug_messenger_create_info.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; - debug_messenger_create_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; - debug_messenger_create_info.pfnUserCallback = &debugCallback; - instance_create_info.pNext = &debug_messenger_create_info; -#endif - VK_CHECK(vkCreateInstance(&instance_create_info, nullptr, &instance_)); -#ifdef _DEBUG - VK_CHECK(enable_layer_validation(&debug_messenger_create_info)); -#endif + for (uint32_t i = 0; i < family_propertieses.size(); ++i) + { + if (family_propertieses[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) + queue_family_indices.graphycs_family = i; + if(queue_family_indices.is_complete()) + break; } - { + return queue_family_indices; +} + +void RenderEngine::create_instance() +{ + std::vector extensions = get_required_extensions(); + + VkApplicationInfo app_info{}; + app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; + app_info.apiVersion = VK_API_VERSION_1_0; + app_info.applicationVersion = VK_MAKE_VERSION(0, 0, 0); + app_info.pApplicationName = core_.getGameName().c_str(); + app_info.pEngineName = "UwU Engine"; + app_info.engineVersion = VK_MAKE_VERSION(0, 0, 0); + + + VkInstanceCreateInfo instance_create_info{}; + instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + instance_create_info.pApplicationInfo = &app_info; + instance_create_info.enabledExtensionCount = static_cast(extensions.size()); + instance_create_info.ppEnabledExtensionNames = extensions.data(); +#ifdef _DEBUG + std::vector layers_validation = { + "VK_LAYER_KHRONOS_validation" + }; + instance_create_info.enabledLayerCount = static_cast(layers_validation.size()); + instance_create_info.ppEnabledLayerNames = layers_validation.data(); + VkDebugUtilsMessengerCreateInfoEXT debug_messenger_create_info{}; + debug_messenger_create_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; + debug_messenger_create_info.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; + debug_messenger_create_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; + debug_messenger_create_info.pfnUserCallback = &debugCallback; + instance_create_info.pNext = &debug_messenger_create_info; +#endif + VK_CHECK(vkCreateInstance(&instance_create_info, nullptr, &instance_)); +#ifdef _DEBUG + VK_CHECK(enable_layer_validation(&debug_messenger_create_info)); +#endif +} + +void RenderEngine::pick_physical_device() +{ uint32_t device_count = 0; std::vector devices; VK_CHECK(vkEnumeratePhysicalDevices(instance_, &device_count, nullptr)); @@ -117,10 +143,60 @@ RenderEngine::RenderEngine(GLFWwindow* window) : window_(window) if (VK_NULL_HANDLE == physical_device_) throw std::runtime_error("No suitable device found"); } + +void RenderEngine::create_logical_device() +{ + QueueFamilyIndices indices = find_queue_family_indices(physical_device_); + + VkPhysicalDeviceFeatures device_features{}; + + float queue_priority = 1.0f; + VkDeviceQueueCreateInfo device_queue_create_info{}; + device_queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + device_queue_create_info.queueFamilyIndex = indices.graphycs_family.value(); + device_queue_create_info.queueCount = 1; + device_queue_create_info.pQueuePriorities = &queue_priority; + + VkDeviceCreateInfo device_create_info{}; + device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + device_create_info.queueCreateInfoCount = 1; + device_create_info.pQueueCreateInfos = &device_queue_create_info; + device_create_info.pEnabledFeatures = &device_features; + device_create_info.enabledExtensionCount = 0; + device_create_info.ppEnabledExtensionNames = nullptr; + +#ifdef _DEBUG + std::vector layers_validation = { + "VK_LAYER_KHRONOS_validation" + }; + device_create_info.enabledLayerCount = static_cast(layers_validation.size()); + device_create_info.ppEnabledLayerNames = layers_validation.data(); +#else + device_create_info.enabledLayerCount = 0; + device_create_info.ppEnabledLayerNames = nullptr; + +#endif + VK_CHECK(vkCreateDevice(physical_device_, &device_create_info, nullptr, &device_)); + vkGetDeviceQueue(device_, indices.graphycs_family.value(), 0, &graphics_queue_); +} + +RenderEngine::RenderEngine(CoreInstance& core, GLFWwindow* window): +core_(core), +window_(window) +#ifdef _DEBUG +,debug_messenger_(nullptr) +#endif +{ + create_instance(); + pick_physical_device(); + create_logical_device(); } RenderEngine::~RenderEngine() { + if (device_ != VK_NULL_HANDLE) + vkDestroyDevice(device_, nullptr); + #ifdef _DEBUG if (debug_messenger_ != nullptr && instance_ != nullptr) { PFN_vkDestroyDebugUtilsMessengerEXT destroyer_messenger = reinterpret_cast(vkGetInstanceProcAddr(instance_, "vkDestroyDebugUtilsMessengerEXT")); @@ -128,7 +204,7 @@ RenderEngine::~RenderEngine() } #endif - if (instance_ != nullptr) + if (instance_ != VK_NULL_HANDLE) vkDestroyInstance(instance_, nullptr); if (window_ != nullptr) diff --git a/Core/Core/RenderEngine.h b/Core/Core/RenderEngine.h index 764330b..fe7476c 100644 --- a/Core/Core/RenderEngine.h +++ b/Core/Core/RenderEngine.h @@ -5,12 +5,24 @@ #include "GLFW/glfw3.h" #include +#include + +class CoreInstance; class RenderEngine { + struct QueueFamilyIndices + { + std::optional graphycs_family; + bool is_complete(); + }; + + CoreInstance& core_; GLFWwindow* window_; VkInstance instance_ = VK_NULL_HANDLE; VkPhysicalDevice physical_device_ = VK_NULL_HANDLE; + VkDevice device_ = VK_NULL_HANDLE; + VkQueue graphics_queue_ = VK_NULL_HANDLE; #ifdef _DEBUG VkResult enable_layer_validation(VkDebugUtilsMessengerCreateInfoEXT* create_info); @@ -18,9 +30,15 @@ class RenderEngine #endif static std::vector get_required_extensions(); - bool is_device_suitable(VkPhysicalDevice device); + static bool is_device_suitable(VkPhysicalDevice device); + static QueueFamilyIndices find_queue_family_indices(VkPhysicalDevice device); + + void create_instance(); + void pick_physical_device(); + void create_logical_device(); public: - RenderEngine(GLFWwindow* window); + // Can throw the exception + RenderEngine(CoreInstance& core, GLFWwindow* window); ~RenderEngine(); void start(); diff --git a/Core/Core/Windows.cpp b/Core/Core/Windows/WindowsCalls.cpp similarity index 95% rename from Core/Core/Windows.cpp rename to Core/Core/Windows/WindowsCalls.cpp index 41ab21c..ad05a22 100644 --- a/Core/Core/Windows.cpp +++ b/Core/Core/Windows/WindowsCalls.cpp @@ -1,6 +1,6 @@ #ifdef _WIN32 -#include "SystemCalls.h" +#include "../SystemCalls.h" #include @@ -38,7 +38,7 @@ double System::getMemorySize() { memStatus.dwLength = sizeof(memStatus); GlobalMemoryStatusEx(&memStatus); - return memStatus.ullTotalPhys / 1024 / 1024; + return static_cast(memStatus.ullTotalPhys) / 1024. / 1024.; } void* System::InitModule(const char* ModuleName, CoreCallBacks* callbacks) { From 5c9436a892072feb429ba7b1d2eab1fd99b440af Mon Sep 17 00:00:00 2001 From: Jiga228 Date: Sat, 20 Sep 2025 19:38:17 +0700 Subject: [PATCH 05/17] Add create window surface --- Core/Core/CoreInstance.cpp | 3 +++ Core/Core/RenderEngine.cpp | 27 +++++++++++++++++---------- Core/Core/RenderEngine.h | 18 ++++++++++++++---- 3 files changed, 34 insertions(+), 14 deletions(-) diff --git a/Core/Core/CoreInstance.cpp b/Core/Core/CoreInstance.cpp index 518705f..e6fb345 100644 --- a/Core/Core/CoreInstance.cpp +++ b/Core/Core/CoreInstance.cpp @@ -57,6 +57,9 @@ CoreInstance::CoreInstance() if (glfwInit() == GLFW_FALSE) throw std::runtime_error("Fail init glfw"); + + glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); + glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); window_ = glfwCreateWindow(800, 600, main_config_.game_name.c_str(), nullptr, nullptr); if (window_ == nullptr) { diff --git a/Core/Core/RenderEngine.cpp b/Core/Core/RenderEngine.cpp index decf4fe..49954f9 100644 --- a/Core/Core/RenderEngine.cpp +++ b/Core/Core/RenderEngine.cpp @@ -6,10 +6,9 @@ #include "CoreInstance.h" #include "Log/Log.h" -#ifdef _DEBUG -#include -#define VK_CHECK(res) assert(res == VK_SUCCESS) +#include "GLFW/glfw3.h" +#ifdef _DEBUG static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback( VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, @@ -23,18 +22,11 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback( return VK_FALSE; } -bool RenderEngine::QueueFamilyIndices::is_complete() -{ - return graphycs_family.has_value(); -} - VkResult RenderEngine::enable_layer_validation(VkDebugUtilsMessengerCreateInfoEXT* create_info) { PFN_vkCreateDebugUtilsMessengerEXT debug_creator = reinterpret_cast(vkGetInstanceProcAddr(instance_, "vkCreateDebugUtilsMessengerEXT")); return debug_creator(instance_, create_info, nullptr, &debug_messenger_); } -#else -#define VK_CHECK(res) if ((res) != VK_SUCCESS) throw std::runtime_error("Vulkan error: " + std::to_string(res)) #endif std::vector RenderEngine::get_required_extensions() @@ -49,6 +41,12 @@ std::vector RenderEngine::get_required_extensions() return extensions; } + +bool RenderEngine::QueueFamilyIndices::is_complete() +{ + return graphycs_family.has_value(); +} + bool RenderEngine::is_device_suitable(VkPhysicalDevice device) { VkPhysicalDeviceProperties device_properties; @@ -180,6 +178,11 @@ void RenderEngine::create_logical_device() vkGetDeviceQueue(device_, indices.graphycs_family.value(), 0, &graphics_queue_); } +void RenderEngine::create_surface() +{ + VK_CHECK(glfwCreateWindowSurface(instance_, window_, nullptr, &surface_)); +} + RenderEngine::RenderEngine(CoreInstance& core, GLFWwindow* window): core_(core), window_(window) @@ -188,6 +191,7 @@ window_(window) #endif { create_instance(); + create_surface(); pick_physical_device(); create_logical_device(); } @@ -197,6 +201,9 @@ RenderEngine::~RenderEngine() if (device_ != VK_NULL_HANDLE) vkDestroyDevice(device_, nullptr); + if (surface_ != VK_NULL_HANDLE) + vkDestroySurfaceKHR(instance_, surface_, nullptr); + #ifdef _DEBUG if (debug_messenger_ != nullptr && instance_ != nullptr) { PFN_vkDestroyDebugUtilsMessengerEXT destroyer_messenger = reinterpret_cast(vkGetInstanceProcAddr(instance_, "vkDestroyDebugUtilsMessengerEXT")); diff --git a/Core/Core/RenderEngine.h b/Core/Core/RenderEngine.h index fe7476c..5508c66 100644 --- a/Core/Core/RenderEngine.h +++ b/Core/Core/RenderEngine.h @@ -1,12 +1,20 @@ #pragma once -#define GLFW_INCLUDE_VULKAN -#include -#include "GLFW/glfw3.h" - #include #include +#define GLFW_INCLUDE_VULKAN +#include + +#include + +#ifdef _DEBUG +#include +#define VK_CHECK(res) assert(res == VK_SUCCESS) +#else +#define VK_CHECK(res) if ((res) != VK_SUCCESS) throw std::runtime_error("Vulkan error: " + std::to_string(res)) +#endif + class CoreInstance; class RenderEngine @@ -20,6 +28,7 @@ class RenderEngine CoreInstance& core_; GLFWwindow* window_; VkInstance instance_ = VK_NULL_HANDLE; + VkSurfaceKHR surface_ = VK_NULL_HANDLE; VkPhysicalDevice physical_device_ = VK_NULL_HANDLE; VkDevice device_ = VK_NULL_HANDLE; VkQueue graphics_queue_ = VK_NULL_HANDLE; @@ -34,6 +43,7 @@ class RenderEngine static QueueFamilyIndices find_queue_family_indices(VkPhysicalDevice device); void create_instance(); + void create_surface(); void pick_physical_device(); void create_logical_device(); public: From 84e3a2a3788dfc27d332257fec69b681d8787420 Mon Sep 17 00:00:00 2001 From: Jiga228 Date: Sat, 20 Sep 2025 20:17:46 +0700 Subject: [PATCH 06/17] Add present queue --- Core/Core/RenderEngine.cpp | 41 ++++++++++++++++++++++++++------------ Core/Core/RenderEngine.h | 6 ++++-- 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/Core/Core/RenderEngine.cpp b/Core/Core/RenderEngine.cpp index 49954f9..ba4ec23 100644 --- a/Core/Core/RenderEngine.cpp +++ b/Core/Core/RenderEngine.cpp @@ -1,5 +1,7 @@ #include "RenderEngine.h" +#include +#include #include #include @@ -44,36 +46,41 @@ std::vector RenderEngine::get_required_extensions() bool RenderEngine::QueueFamilyIndices::is_complete() { - return graphycs_family.has_value(); + return graphycs_family.has_value() && present_family.has_value(); } -bool RenderEngine::is_device_suitable(VkPhysicalDevice device) +bool RenderEngine::is_device_suitable(VkPhysicalDevice device, VkSurfaceKHR surface) { VkPhysicalDeviceProperties device_properties; VkPhysicalDeviceFeatures device_features; vkGetPhysicalDeviceProperties(device, &device_properties); vkGetPhysicalDeviceFeatures(device, &device_features); - QueueFamilyIndices indices = find_queue_family_indices(device); + QueueFamilyIndices indices = find_queue_family_indices(device, surface); return device_properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU && device_features.geometryShader && indices.is_complete(); } -RenderEngine::QueueFamilyIndices RenderEngine::find_queue_family_indices(VkPhysicalDevice device) +RenderEngine::QueueFamilyIndices RenderEngine::find_queue_family_indices(VkPhysicalDevice physical_device, VkSurfaceKHR surface) { QueueFamilyIndices queue_family_indices; uint32_t queueFamilyCount = 0; - vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr); + vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queueFamilyCount, nullptr); std::vector family_propertieses(queueFamilyCount); - vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, family_propertieses.data()); + vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queueFamilyCount, family_propertieses.data()); for (uint32_t i = 0; i < family_propertieses.size(); ++i) { if (family_propertieses[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) queue_family_indices.graphycs_family = i; + + VkBool32 present_support = false; + VK_CHECK(vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, i, surface, &present_support)); + if (present_support) + queue_family_indices.present_family = i; if(queue_family_indices.is_complete()) break; } @@ -128,7 +135,7 @@ void RenderEngine::pick_physical_device() for (const auto& device : devices) { - if (is_device_suitable(device)) + if (is_device_suitable(device, surface_)) { physical_device_ = device; VkPhysicalDeviceProperties device_properties; @@ -144,21 +151,28 @@ void RenderEngine::pick_physical_device() void RenderEngine::create_logical_device() { - QueueFamilyIndices indices = find_queue_family_indices(physical_device_); + QueueFamilyIndices indices = find_queue_family_indices(physical_device_, surface_); VkPhysicalDeviceFeatures device_features{}; + + std::vector queue_create_infos; + std::set unique_queue_families = {indices.graphycs_family.value(), indices.present_family.value()}; float queue_priority = 1.0f; VkDeviceQueueCreateInfo device_queue_create_info{}; device_queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - device_queue_create_info.queueFamilyIndex = indices.graphycs_family.value(); - device_queue_create_info.queueCount = 1; - device_queue_create_info.pQueuePriorities = &queue_priority; + device_queue_create_info.pQueuePriorities = &queue_priority; + for (auto queue_family : unique_queue_families) + { + device_queue_create_info.queueFamilyIndex = queue_family; + device_queue_create_info.queueCount = 1; + queue_create_infos.push_back(device_queue_create_info); + } VkDeviceCreateInfo device_create_info{}; device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; - device_create_info.queueCreateInfoCount = 1; - device_create_info.pQueueCreateInfos = &device_queue_create_info; + device_create_info.queueCreateInfoCount = static_cast(unique_queue_families.size()); + device_create_info.pQueueCreateInfos = queue_create_infos.data(); device_create_info.pEnabledFeatures = &device_features; device_create_info.enabledExtensionCount = 0; device_create_info.ppEnabledExtensionNames = nullptr; @@ -176,6 +190,7 @@ void RenderEngine::create_logical_device() #endif VK_CHECK(vkCreateDevice(physical_device_, &device_create_info, nullptr, &device_)); vkGetDeviceQueue(device_, indices.graphycs_family.value(), 0, &graphics_queue_); + vkGetDeviceQueue(device_, indices.present_family.value(), 0, &present_queue_); } void RenderEngine::create_surface() diff --git a/Core/Core/RenderEngine.h b/Core/Core/RenderEngine.h index 5508c66..51fc3c1 100644 --- a/Core/Core/RenderEngine.h +++ b/Core/Core/RenderEngine.h @@ -22,6 +22,7 @@ class RenderEngine struct QueueFamilyIndices { std::optional graphycs_family; + std::optional present_family; bool is_complete(); }; @@ -32,6 +33,7 @@ class RenderEngine VkPhysicalDevice physical_device_ = VK_NULL_HANDLE; VkDevice device_ = VK_NULL_HANDLE; VkQueue graphics_queue_ = VK_NULL_HANDLE; + VkQueue present_queue_ = VK_NULL_HANDLE; #ifdef _DEBUG VkResult enable_layer_validation(VkDebugUtilsMessengerCreateInfoEXT* create_info); @@ -39,8 +41,8 @@ class RenderEngine #endif static std::vector get_required_extensions(); - static bool is_device_suitable(VkPhysicalDevice device); - static QueueFamilyIndices find_queue_family_indices(VkPhysicalDevice device); + static bool is_device_suitable(VkPhysicalDevice device, VkSurfaceKHR surface); + static QueueFamilyIndices find_queue_family_indices(VkPhysicalDevice physical_device, VkSurfaceKHR surface); void create_instance(); void create_surface(); From 9a9fa710ff79188f9a7796a0e1b1729ce7b14d71 Mon Sep 17 00:00:00 2001 From: Jiga228 Date: Wed, 24 Sep 2025 21:48:34 +0700 Subject: [PATCH 07/17] Add create swapchain --- Core/Core/RenderEngine.cpp | 152 ++++++++++++++++++++++++++++++++++--- Core/Core/RenderEngine.h | 22 +++++- 2 files changed, 162 insertions(+), 12 deletions(-) diff --git a/Core/Core/RenderEngine.cpp b/Core/Core/RenderEngine.cpp index ba4ec23..e9bea64 100644 --- a/Core/Core/RenderEngine.cpp +++ b/Core/Core/RenderEngine.cpp @@ -1,5 +1,6 @@ #include "RenderEngine.h" +#include #include #include #include @@ -10,6 +11,10 @@ #include "GLFW/glfw3.h" +const std::vector RenderEngine::deviceExtensions = { + VK_KHR_SWAPCHAIN_EXTENSION_NAME +}; + #ifdef _DEBUG static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback( VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, @@ -31,6 +36,25 @@ VkResult RenderEngine::enable_layer_validation(VkDebugUtilsMessengerCreateInfoEX } #endif +RenderEngine::SwapchainSupportDetails RenderEngine::query_swapchain_details() +{ + SwapchainSupportDetails details; + + vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device_, surface_, &details.capabilities); + + uint32_t surface_format_cnt = 0; + VK_CHECK(vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device_, surface_, &surface_format_cnt, nullptr)); + details.formats.resize(surface_format_cnt); + VK_CHECK(vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device_, surface_, &surface_format_cnt, details.formats.data())); + + uint32_t present_modes_cnt = 0; + VK_CHECK(vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device_, surface_, &present_modes_cnt, nullptr)); + details.present_modes.resize(surface_format_cnt); + VK_CHECK(vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device_, surface_, &present_modes_cnt, details.present_modes.data())); + + return details; +} + std::vector RenderEngine::get_required_extensions() { uint32_t extensions_count = 0; @@ -58,9 +82,31 @@ bool RenderEngine::is_device_suitable(VkPhysicalDevice device, VkSurfaceKHR surf QueueFamilyIndices indices = find_queue_family_indices(device, surface); - return device_properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU - && device_features.geometryShader - && indices.is_complete(); + return indices.is_complete() && check_device_extensions_support(device); +} + +bool RenderEngine::check_device_extensions_support(VkPhysicalDevice device) +{ + uint32_t extension_count; + VK_CHECK(vkEnumerateDeviceExtensionProperties(device, nullptr, &extension_count, nullptr)); + std::vector available_extensions(extension_count); + VK_CHECK(vkEnumerateDeviceExtensionProperties(device, nullptr, &extension_count, available_extensions.data())); + + for (const auto& extension : deviceExtensions) + { + bool isFind = false; + for (const auto& i : available_extensions) + { + if (std::strcmp(i.extensionName, extension) == 0) + { + isFind = true; + break; + } + } + if (!isFind) + return false; + } + return true; } RenderEngine::QueueFamilyIndices RenderEngine::find_queue_family_indices(VkPhysicalDevice physical_device, VkSurfaceKHR surface) @@ -88,6 +134,43 @@ RenderEngine::QueueFamilyIndices RenderEngine::find_queue_family_indices(VkPhysi return queue_family_indices; } +VkSurfaceFormatKHR RenderEngine::choose_surface_format(const std::vector& surface_formats) +{ + for (const auto& i : surface_formats) + { + if (i.format == VK_FORMAT_B8G8R8A8_SRGB && i.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) + return i; + } + return surface_formats[0]; +} + +VkPresentModeKHR RenderEngine::choose_present_mode(const std::vector& present_modes, VkPresentModeKHR desired_present_mode) +{ + for (const auto& i : present_modes) + { + if (i == desired_present_mode) + return i; + } + return VK_PRESENT_MODE_FIFO_KHR; +} + +VkExtent2D RenderEngine::choose_extent(const VkSurfaceCapabilitiesKHR& capabilities, GLFWwindow* window) +{ + if (capabilities.currentExtent.width != std::numeric_limits::max()) + return capabilities.currentExtent; + else + { + int width, height; + glfwGetFramebufferSize(window, &width, &height); + VkExtent2D actualExtent = { + static_cast(width), + static_cast(height) + }; + actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width)); + return actualExtent; + } +} + void RenderEngine::create_instance() { std::vector extensions = get_required_extensions(); @@ -107,7 +190,7 @@ void RenderEngine::create_instance() instance_create_info.enabledExtensionCount = static_cast(extensions.size()); instance_create_info.ppEnabledExtensionNames = extensions.data(); #ifdef _DEBUG - std::vector layers_validation = { + const std::vector layers_validation = { "VK_LAYER_KHRONOS_validation" }; instance_create_info.enabledLayerCount = static_cast(layers_validation.size()); @@ -168,17 +251,17 @@ void RenderEngine::create_logical_device() device_queue_create_info.queueCount = 1; queue_create_infos.push_back(device_queue_create_info); } - + VkDeviceCreateInfo device_create_info{}; device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; device_create_info.queueCreateInfoCount = static_cast(unique_queue_families.size()); device_create_info.pQueueCreateInfos = queue_create_infos.data(); device_create_info.pEnabledFeatures = &device_features; - device_create_info.enabledExtensionCount = 0; - device_create_info.ppEnabledExtensionNames = nullptr; + device_create_info.enabledExtensionCount = static_cast(deviceExtensions.size()); + device_create_info.ppEnabledExtensionNames = deviceExtensions.data(); #ifdef _DEBUG - std::vector layers_validation = { + const std::vector layers_validation = { "VK_LAYER_KHRONOS_validation" }; device_create_info.enabledLayerCount = static_cast(layers_validation.size()); @@ -193,12 +276,59 @@ void RenderEngine::create_logical_device() vkGetDeviceQueue(device_, indices.present_family.value(), 0, &present_queue_); } +void RenderEngine::create_swapchain(VkPresentModeKHR desired_present_mode) +{ + SwapchainSupportDetails swapchain_support = query_swapchain_details(); + VkSurfaceFormatKHR surface_format = choose_surface_format(swapchain_support.formats); + VkPresentModeKHR present_mode = choose_present_mode(swapchain_support.present_modes, desired_present_mode); + VkExtent2D extent = choose_extent(swapchain_support.capabilities, window_); + + uint32_t image_count = swapchain_support.capabilities.minImageCount + 1; + if (swapchain_support.capabilities.maxImageCount > 0 && image_count > swapchain_support.capabilities.maxImageCount) + image_count = swapchain_support.capabilities.maxImageCount; + + VkSwapchainCreateInfoKHR swapchain_create_info{}; + swapchain_create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; + swapchain_create_info.surface = surface_; + swapchain_create_info.minImageCount = image_count; + swapchain_create_info.imageFormat = surface_format.format; + swapchain_create_info.imageColorSpace = surface_format.colorSpace; + swapchain_create_info.imageExtent = extent; + swapchain_create_info.imageArrayLayers = 1; + swapchain_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + swapchain_create_info.preTransform = swapchain_support.capabilities.currentTransform; + swapchain_create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + swapchain_create_info.presentMode = present_mode; + swapchain_create_info.clipped = VK_TRUE; + swapchain_create_info.oldSwapchain = VK_NULL_HANDLE; + + QueueFamilyIndices family_indices = find_queue_family_indices(physical_device_, surface_); + uint32_t queue_family_indices[] = {family_indices.graphycs_family.value(), family_indices.present_family.value()}; + if (family_indices.graphycs_family != family_indices.present_family) + { + swapchain_create_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT; + swapchain_create_info.queueFamilyIndexCount = 2; + swapchain_create_info.pQueueFamilyIndices = queue_family_indices; + } + else + { + swapchain_create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + swapchain_create_info.queueFamilyIndexCount = 0; + swapchain_create_info.pQueueFamilyIndices = nullptr; + } + + VK_CHECK(vkCreateSwapchainKHR(device_, &swapchain_create_info, nullptr, &swapchain_)); + + swapchain_images_.resize(image_count); + vkGetSwapchainImagesKHR(device_, swapchain_, &image_count, swapchain_images_.data()); +} + void RenderEngine::create_surface() { VK_CHECK(glfwCreateWindowSurface(instance_, window_, nullptr, &surface_)); } -RenderEngine::RenderEngine(CoreInstance& core, GLFWwindow* window): +RenderEngine::RenderEngine(CoreInstance& core, GLFWwindow* window, VkPresentModeKHR desired_present_mode): core_(core), window_(window) #ifdef _DEBUG @@ -209,10 +339,14 @@ window_(window) create_surface(); pick_physical_device(); create_logical_device(); + create_swapchain(desired_present_mode); } RenderEngine::~RenderEngine() { + if (swapchain_ != VK_NULL_HANDLE) + vkDestroySwapchainKHR(device_, swapchain_, nullptr); + if (device_ != VK_NULL_HANDLE) vkDestroyDevice(device_, nullptr); diff --git a/Core/Core/RenderEngine.h b/Core/Core/RenderEngine.h index 51fc3c1..5ef70bc 100644 --- a/Core/Core/RenderEngine.h +++ b/Core/Core/RenderEngine.h @@ -25,6 +25,14 @@ class RenderEngine std::optional present_family; bool is_complete(); }; + struct SwapchainSupportDetails + { + VkSurfaceCapabilitiesKHR capabilities; + std::vector formats; + std::vector present_modes; + }; + + static const std::vector deviceExtensions; CoreInstance& core_; GLFWwindow* window_; @@ -34,23 +42,31 @@ class RenderEngine VkDevice device_ = VK_NULL_HANDLE; VkQueue graphics_queue_ = VK_NULL_HANDLE; VkQueue present_queue_ = VK_NULL_HANDLE; + VkSwapchainKHR swapchain_ = VK_NULL_HANDLE; + std::vector swapchain_images_; #ifdef _DEBUG VkResult enable_layer_validation(VkDebugUtilsMessengerCreateInfoEXT* create_info); VkDebugUtilsMessengerEXT debug_messenger_; #endif - + SwapchainSupportDetails query_swapchain_details(); + static std::vector get_required_extensions(); static bool is_device_suitable(VkPhysicalDevice device, VkSurfaceKHR surface); + static bool check_device_extensions_support(VkPhysicalDevice device); static QueueFamilyIndices find_queue_family_indices(VkPhysicalDevice physical_device, VkSurfaceKHR surface); - + static VkSurfaceFormatKHR choose_surface_format(const std::vector& surface_formats); + static VkPresentModeKHR choose_present_mode(const std::vector& present_modes, VkPresentModeKHR desired_present_mode); + static VkExtent2D choose_extent(const VkSurfaceCapabilitiesKHR& capabilities, GLFWwindow* window); + void create_instance(); void create_surface(); void pick_physical_device(); void create_logical_device(); + void create_swapchain(VkPresentModeKHR desired_present_mode); public: // Can throw the exception - RenderEngine(CoreInstance& core, GLFWwindow* window); + RenderEngine(CoreInstance& core, GLFWwindow* window, VkPresentModeKHR desired_present_mode = VK_PRESENT_MODE_MAILBOX_KHR); ~RenderEngine(); void start(); From 600ff1bc2d98088a2f333367bbb46cb5677ddd02 Mon Sep 17 00:00:00 2001 From: Jiga228 Date: Wed, 24 Sep 2025 21:51:59 +0700 Subject: [PATCH 08/17] Add two members --- Core/Core/RenderEngine.cpp | 4 ++++ Core/Core/RenderEngine.h | 2 ++ 2 files changed, 6 insertions(+) diff --git a/Core/Core/RenderEngine.cpp b/Core/Core/RenderEngine.cpp index e9bea64..62a1340 100644 --- a/Core/Core/RenderEngine.cpp +++ b/Core/Core/RenderEngine.cpp @@ -319,8 +319,12 @@ void RenderEngine::create_swapchain(VkPresentModeKHR desired_present_mode) VK_CHECK(vkCreateSwapchainKHR(device_, &swapchain_create_info, nullptr, &swapchain_)); + vkGetSwapchainImagesKHR(device_, swapchain_, &image_count, nullptr); swapchain_images_.resize(image_count); vkGetSwapchainImagesKHR(device_, swapchain_, &image_count, swapchain_images_.data()); + + swapchain_image_format_ = surface_format.format; + swapchain_extent_ = extent; } void RenderEngine::create_surface() diff --git a/Core/Core/RenderEngine.h b/Core/Core/RenderEngine.h index 5ef70bc..383c2b3 100644 --- a/Core/Core/RenderEngine.h +++ b/Core/Core/RenderEngine.h @@ -44,6 +44,8 @@ class RenderEngine VkQueue present_queue_ = VK_NULL_HANDLE; VkSwapchainKHR swapchain_ = VK_NULL_HANDLE; std::vector swapchain_images_; + VkFormat swapchain_image_format_; + VkExtent2D swapchain_extent_; #ifdef _DEBUG VkResult enable_layer_validation(VkDebugUtilsMessengerCreateInfoEXT* create_info); From 175354f56a85a4cf4c69a8d43d42a8d62dc8214c Mon Sep 17 00:00:00 2001 From: Jiga228 Date: Wed, 24 Sep 2025 22:02:14 +0700 Subject: [PATCH 09/17] Add allocate image views --- Core/Core/RenderEngine.cpp | 29 +++++++++++++++++++++++++++++ Core/Core/RenderEngine.h | 2 ++ 2 files changed, 31 insertions(+) diff --git a/Core/Core/RenderEngine.cpp b/Core/Core/RenderEngine.cpp index 62a1340..ec943fc 100644 --- a/Core/Core/RenderEngine.cpp +++ b/Core/Core/RenderEngine.cpp @@ -327,6 +327,30 @@ void RenderEngine::create_swapchain(VkPresentModeKHR desired_present_mode) swapchain_extent_ = extent; } +void RenderEngine::create_image_views() +{ + VkImageViewCreateInfo image_view_info{}; + image_view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + image_view_info.viewType = VK_IMAGE_VIEW_TYPE_2D; + image_view_info.format = swapchain_image_format_; + image_view_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; + image_view_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; + image_view_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; + image_view_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; + image_view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + image_view_info.subresourceRange.baseMipLevel = 0; + image_view_info.subresourceRange.levelCount = 1; + image_view_info.subresourceRange.baseArrayLayer = 0; + image_view_info.subresourceRange.layerCount = 1; + + swapchain_image_views_.resize(swapchain_images_.size()); + for (uint32_t i = 0; i < swapchain_images_.size(); ++i) + { + image_view_info.image = swapchain_images_[i]; + VK_CHECK(vkCreateImageView(device_, &image_view_info, nullptr, &swapchain_image_views_[i])); + } +} + void RenderEngine::create_surface() { VK_CHECK(glfwCreateWindowSurface(instance_, window_, nullptr, &surface_)); @@ -344,10 +368,15 @@ window_(window) pick_physical_device(); create_logical_device(); create_swapchain(desired_present_mode); + create_image_views(); } RenderEngine::~RenderEngine() { + for (auto image_view : swapchain_image_views_) + vkDestroyImageView(device_, image_view, nullptr); + swapchain_image_views_.clear(); + if (swapchain_ != VK_NULL_HANDLE) vkDestroySwapchainKHR(device_, swapchain_, nullptr); diff --git a/Core/Core/RenderEngine.h b/Core/Core/RenderEngine.h index 383c2b3..4a841d2 100644 --- a/Core/Core/RenderEngine.h +++ b/Core/Core/RenderEngine.h @@ -46,6 +46,7 @@ class RenderEngine std::vector swapchain_images_; VkFormat swapchain_image_format_; VkExtent2D swapchain_extent_; + std::vector swapchain_image_views_; #ifdef _DEBUG VkResult enable_layer_validation(VkDebugUtilsMessengerCreateInfoEXT* create_info); @@ -66,6 +67,7 @@ class RenderEngine void pick_physical_device(); void create_logical_device(); void create_swapchain(VkPresentModeKHR desired_present_mode); + void create_image_views(); public: // Can throw the exception RenderEngine(CoreInstance& core, GLFWwindow* window, VkPresentModeKHR desired_present_mode = VK_PRESENT_MODE_MAILBOX_KHR); From 2353ac289a70b3b3d6b078dfffbf9acf8b6217ae Mon Sep 17 00:00:00 2001 From: Jiga228 Date: Fri, 26 Sep 2025 20:09:26 +0700 Subject: [PATCH 10/17] Add base shaders and create pipeline_layout --- Core/Core/RenderEngine.cpp | 129 ++++++++++++++++++++++++++++++++- Core/Core/RenderEngine.h | 4 + TestGame/CMakeLists.txt | 27 +++++++ TestGame/Shaders/fragment.frag | 8 ++ TestGame/Shaders/vertex.vert | 20 +++++ 5 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 TestGame/Shaders/fragment.frag create mode 100644 TestGame/Shaders/vertex.vert diff --git a/Core/Core/RenderEngine.cpp b/Core/Core/RenderEngine.cpp index ec943fc..e86e6de 100644 --- a/Core/Core/RenderEngine.cpp +++ b/Core/Core/RenderEngine.cpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include "CoreInstance.h" #include "Log/Log.h" @@ -171,6 +171,18 @@ VkExtent2D RenderEngine::choose_extent(const VkSurfaceCapabilitiesKHR& capabilit } } +VkShaderModule RenderEngine::create_shader_module(const std::string code) +{ + VkShaderModuleCreateInfo shader_module_info{}; + shader_module_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + shader_module_info.codeSize = code.size(); + shader_module_info.pCode = reinterpret_cast(code.c_str()); + + VkShaderModule shader_module; + VK_CHECK(vkCreateShaderModule(device_, &shader_module_info, nullptr, &shader_module)); + return shader_module; +} + void RenderEngine::create_instance() { std::vector extensions = get_required_extensions(); @@ -351,6 +363,117 @@ void RenderEngine::create_image_views() } } +void RenderEngine::create_graphycs_pipleline() +{ + std::ifstream vertex_shader_file("Shaders/vertex.spv", std::ios::binary); + if (!vertex_shader_file.is_open()) + throw std::runtime_error("Vertex shader not found"); + std::ifstream fragment_shader_file("Shaders/fragment.spv", std::ios::binary); + if (!fragment_shader_file.is_open()) { + vertex_shader_file.close(); + throw std::runtime_error("Fragment shader not found"); + } + + std::string vertex_shader_code((std::istreambuf_iterator(vertex_shader_file)), std::istreambuf_iterator()); + std::string fragment_shader_code((std::istreambuf_iterator(fragment_shader_file)), std::istreambuf_iterator()); + vertex_shader_file.close(); + fragment_shader_file.close(); + + VkShaderModule vertex_shader = create_shader_module(vertex_shader_code); + VkShaderModule fragment_shader = create_shader_module(fragment_shader_code); + + VkPipelineShaderStageCreateInfo vertex_shader_stage_info{}; + vertex_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + vertex_shader_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT; + vertex_shader_stage_info.module = vertex_shader; + vertex_shader_stage_info.pName = "main"; + + VkPipelineShaderStageCreateInfo fragment_shader_stage_info{}; + vertex_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + vertex_shader_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT; + vertex_shader_stage_info.module = fragment_shader; + vertex_shader_stage_info.pName = "main"; + + VkPipelineShaderStageCreateInfo shader_stages[] = {vertex_shader_stage_info, fragment_shader_stage_info}; + const std::vector dynamic_states = { + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR + }; + + VkPipelineDynamicStateCreateInfo dynamic_state_info{}; + dynamic_state_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dynamic_state_info.dynamicStateCount = static_cast(dynamic_states.size()); + dynamic_state_info.pDynamicStates = dynamic_states.data(); + + VkPipelineVertexInputStateCreateInfo vertex_input_info{}; + vertex_input_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + vertex_input_info.vertexAttributeDescriptionCount = 0; + vertex_input_info.pVertexAttributeDescriptions = nullptr; + vertex_input_info.vertexBindingDescriptionCount = 0; + vertex_input_info.pVertexBindingDescriptions = nullptr; + + VkPipelineInputAssemblyStateCreateInfo input_assembly_info{}; + input_assembly_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + input_assembly_info.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + input_assembly_info.primitiveRestartEnable = VK_FALSE; + + VkViewport viewport{}; + viewport.x = 0.0f; + viewport.y = 0.0f; + viewport.width = static_cast(swapchain_extent_.width); + viewport.height = static_cast(swapchain_extent_.height); + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + + VkRect2D scissor{}; + scissor.offset = {0, 0}; + scissor.extent = swapchain_extent_; + + VkPipelineViewportStateCreateInfo viewport_info{}; + viewport_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + viewport_info.viewportCount = 1; + viewport_info.pViewports = &viewport; + viewport_info.scissorCount = 1; + viewport_info.pScissors = &scissor; + + VkPipelineRasterizationStateCreateInfo rasterization_info{}; + rasterization_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rasterization_info.depthClampEnable = VK_FALSE; + rasterization_info.rasterizerDiscardEnable = VK_FALSE; + rasterization_info.polygonMode = VK_POLYGON_MODE_FILL; + rasterization_info.lineWidth = 1.0f; + rasterization_info.cullMode = VK_CULL_MODE_BACK_BIT; + rasterization_info.frontFace = VK_FRONT_FACE_CLOCKWISE; + rasterization_info.depthBiasEnable = VK_FALSE; + + VkPipelineColorBlendAttachmentState color_blend_attachment_state{}; + color_blend_attachment_state.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + color_blend_attachment_state.blendEnable = VK_TRUE; + color_blend_attachment_state.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; + color_blend_attachment_state.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + color_blend_attachment_state.colorBlendOp = VK_BLEND_OP_ADD; + color_blend_attachment_state.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; + color_blend_attachment_state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; + color_blend_attachment_state.alphaBlendOp = VK_BLEND_OP_ADD; + + VkPipelineColorBlendStateCreateInfo color_blend_info{}; + color_blend_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + color_blend_info.logicOpEnable = VK_FALSE; + color_blend_info.attachmentCount = 1; + color_blend_info.blendConstants[0] = 0.0f; + color_blend_info.blendConstants[1] = 0.0f; + color_blend_info.blendConstants[2] = 0.0f; + color_blend_info.blendConstants[3] = 0.0f; + + VkPipelineLayoutCreateInfo pipeline_layout_info{}; + pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + + VK_CHECK(vkCreatePipelineLayout(device_, &pipeline_layout_info, nullptr, &pipeline_layout_)); + + vkDestroyShaderModule(device_, vertex_shader, nullptr); + vkDestroyShaderModule(device_, fragment_shader, nullptr); +} + void RenderEngine::create_surface() { VK_CHECK(glfwCreateWindowSurface(instance_, window_, nullptr, &surface_)); @@ -369,10 +492,14 @@ window_(window) create_logical_device(); create_swapchain(desired_present_mode); create_image_views(); + create_graphycs_pipleline(); } RenderEngine::~RenderEngine() { + if (pipeline_layout_ != VK_NULL_HANDLE) + vkDestroyPipelineLayout(device_, pipeline_layout_, nullptr); + for (auto image_view : swapchain_image_views_) vkDestroyImageView(device_, image_view, nullptr); swapchain_image_views_.clear(); diff --git a/Core/Core/RenderEngine.h b/Core/Core/RenderEngine.h index 4a841d2..17cc08f 100644 --- a/Core/Core/RenderEngine.h +++ b/Core/Core/RenderEngine.h @@ -4,6 +4,7 @@ #include #define GLFW_INCLUDE_VULKAN +#include #include #include @@ -47,6 +48,7 @@ class RenderEngine VkFormat swapchain_image_format_; VkExtent2D swapchain_extent_; std::vector swapchain_image_views_; + VkPipelineLayout pipeline_layout_ = VK_NULL_HANDLE; #ifdef _DEBUG VkResult enable_layer_validation(VkDebugUtilsMessengerCreateInfoEXT* create_info); @@ -61,6 +63,7 @@ class RenderEngine static VkSurfaceFormatKHR choose_surface_format(const std::vector& surface_formats); static VkPresentModeKHR choose_present_mode(const std::vector& present_modes, VkPresentModeKHR desired_present_mode); static VkExtent2D choose_extent(const VkSurfaceCapabilitiesKHR& capabilities, GLFWwindow* window); + VkShaderModule create_shader_module(const std::string code); void create_instance(); void create_surface(); @@ -68,6 +71,7 @@ class RenderEngine void create_logical_device(); void create_swapchain(VkPresentModeKHR desired_present_mode); void create_image_views(); + void create_graphycs_pipleline(); public: // Can throw the exception RenderEngine(CoreInstance& core, GLFWwindow* window, VkPresentModeKHR desired_present_mode = VK_PRESENT_MODE_MAILBOX_KHR); diff --git a/TestGame/CMakeLists.txt b/TestGame/CMakeLists.txt index bd5b200..ae41ece 100644 --- a/TestGame/CMakeLists.txt +++ b/TestGame/CMakeLists.txt @@ -45,3 +45,30 @@ add_custom_command( ${OUTPUT_PATH}/Resources COMMENT "Copying Resources directory" ) + +add_custom_command( + TARGET ${GAME_NAME} + PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory ${OUTPUT_PATH}/Shaders + COMMENT "Creating Shaders directory" +) + +add_custom_command( + TARGET ${GAME_NAME} + POST_BUILD + COMMAND $ENV{VULKAN_SDK}/Bin/glslc.exe + ${CMAKE_CURRENT_SOURCE_DIR}/Shaders/vertex.vert + -o ${OUTPUT_PATH}/Shaders/vertex.spv + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/Shaders/vertex.vert + COMMENT "Building vertex shader" +) + +add_custom_command( + TARGET ${GAME_NAME} + POST_BUILD + COMMAND $ENV{VULKAN_SDK}/Bin/glslc.exe + ${CMAKE_CURRENT_SOURCE_DIR}/Shaders/fragment.frag + -o ${OUTPUT_PATH}/Shaders/fragment.spv + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/Shaders/fragment.frag + COMMENT "Building fragment shader" +) diff --git a/TestGame/Shaders/fragment.frag b/TestGame/Shaders/fragment.frag new file mode 100644 index 0000000..e948fd6 --- /dev/null +++ b/TestGame/Shaders/fragment.frag @@ -0,0 +1,8 @@ +#version 450 + +layout(location = 0) in vec3 fragColor; +layout(location = 0) out vec4 outColor; + +void main() { + outColor = vec4(fragColor, 1.0); +} \ No newline at end of file diff --git a/TestGame/Shaders/vertex.vert b/TestGame/Shaders/vertex.vert new file mode 100644 index 0000000..fe613ef --- /dev/null +++ b/TestGame/Shaders/vertex.vert @@ -0,0 +1,20 @@ +#version 450 + +layout(location = 0) out vec3 fragColor; + +vec3 colors[3] = vec3[]( + vec3(1.0, 0.0, 0.0), + vec3(0.0, 1.0, 0.0), + vec3(0.0, 0.0, 1.0) +); + +vec2 positions[3] = vec2[]( + vec2(0.0, -0.5), + vec2(0.5, 0.5), + vec2(-0.5, 0.5) +); + +void main() { + gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0); + fragColor = colors[gl_VertexIndex]; +} \ No newline at end of file From a9fa292ef97ea70c72a1e36934b64f338489faef Mon Sep 17 00:00:00 2001 From: Jiga228 Date: Fri, 26 Sep 2025 21:21:21 +0700 Subject: [PATCH 11/17] Add create graphycs_pipeline --- Core/Core/RenderEngine.cpp | 72 +++++++++++++++++++++++++++++++++++--- Core/Core/RenderEngine.h | 3 ++ 2 files changed, 71 insertions(+), 4 deletions(-) diff --git a/Core/Core/RenderEngine.cpp b/Core/Core/RenderEngine.cpp index e86e6de..9db638e 100644 --- a/Core/Core/RenderEngine.cpp +++ b/Core/Core/RenderEngine.cpp @@ -363,6 +363,37 @@ void RenderEngine::create_image_views() } } +void RenderEngine::create_render_pass() +{ + VkAttachmentDescription attachment_description{}; + attachment_description.format = swapchain_image_format_; + attachment_description.samples = VK_SAMPLE_COUNT_1_BIT; + attachment_description.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attachment_description.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + attachment_description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachment_description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachment_description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + attachment_description.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + + VkAttachmentReference attachment_reference{}; + attachment_reference.attachment = 0; + attachment_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + VkSubpassDescription subpass_description{}; + subpass_description.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass_description.colorAttachmentCount = 1; + subpass_description.pColorAttachments = &attachment_reference; + + VkRenderPassCreateInfo render_pass_info{}; + render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + render_pass_info.attachmentCount = 1; + render_pass_info.pAttachments = &attachment_description; + render_pass_info.subpassCount = 1; + render_pass_info.pSubpasses = &subpass_description; + + VK_CHECK(vkCreateRenderPass(device_, &render_pass_info, nullptr, &render_pass_)); +} + void RenderEngine::create_graphycs_pipleline() { std::ifstream vertex_shader_file("Shaders/vertex.spv", std::ios::binary); @@ -389,10 +420,10 @@ void RenderEngine::create_graphycs_pipleline() vertex_shader_stage_info.pName = "main"; VkPipelineShaderStageCreateInfo fragment_shader_stage_info{}; - vertex_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - vertex_shader_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT; - vertex_shader_stage_info.module = fragment_shader; - vertex_shader_stage_info.pName = "main"; + fragment_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + fragment_shader_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT; + fragment_shader_stage_info.module = fragment_shader; + fragment_shader_stage_info.pName = "main"; VkPipelineShaderStageCreateInfo shader_stages[] = {vertex_shader_stage_info, fragment_shader_stage_info}; const std::vector dynamic_states = { @@ -446,6 +477,11 @@ void RenderEngine::create_graphycs_pipleline() rasterization_info.frontFace = VK_FRONT_FACE_CLOCKWISE; rasterization_info.depthBiasEnable = VK_FALSE; + VkPipelineMultisampleStateCreateInfo multisample_info{}; + multisample_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + multisample_info.sampleShadingEnable = VK_FALSE; + multisample_info.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + VkPipelineColorBlendAttachmentState color_blend_attachment_state{}; color_blend_attachment_state.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; color_blend_attachment_state.blendEnable = VK_TRUE; @@ -460,6 +496,7 @@ void RenderEngine::create_graphycs_pipleline() color_blend_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; color_blend_info.logicOpEnable = VK_FALSE; color_blend_info.attachmentCount = 1; + color_blend_info.pAttachments = &color_blend_attachment_state; color_blend_info.blendConstants[0] = 0.0f; color_blend_info.blendConstants[1] = 0.0f; color_blend_info.blendConstants[2] = 0.0f; @@ -469,6 +506,26 @@ void RenderEngine::create_graphycs_pipleline() pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; VK_CHECK(vkCreatePipelineLayout(device_, &pipeline_layout_info, nullptr, &pipeline_layout_)); + + VkGraphicsPipelineCreateInfo graphics_pipeline_info{}; + graphics_pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + graphics_pipeline_info.stageCount = 2; + graphics_pipeline_info.pStages = shader_stages; + graphics_pipeline_info.layout = pipeline_layout_; + graphics_pipeline_info.pColorBlendState = &color_blend_info; + graphics_pipeline_info.pDynamicState = &dynamic_state_info; + graphics_pipeline_info.pInputAssemblyState = &input_assembly_info; + graphics_pipeline_info.pMultisampleState = &multisample_info; + graphics_pipeline_info.pRasterizationState = &rasterization_info; + graphics_pipeline_info.pViewportState = &viewport_info; + graphics_pipeline_info.pVertexInputState = &vertex_input_info; + graphics_pipeline_info.pDepthStencilState = nullptr; + graphics_pipeline_info.renderPass = render_pass_; + graphics_pipeline_info.subpass = 0; + graphics_pipeline_info.basePipelineHandle = nullptr; + graphics_pipeline_info.basePipelineIndex = -1; + + VK_CHECK(vkCreateGraphicsPipelines(device_, nullptr, 1, &graphics_pipeline_info, nullptr, &graphycs_pipeline_)); vkDestroyShaderModule(device_, vertex_shader, nullptr); vkDestroyShaderModule(device_, fragment_shader, nullptr); @@ -492,13 +549,20 @@ window_(window) create_logical_device(); create_swapchain(desired_present_mode); create_image_views(); + create_render_pass(); create_graphycs_pipleline(); } RenderEngine::~RenderEngine() { + if (graphycs_pipeline_ != VK_NULL_HANDLE) + vkDestroyPipeline(device_, graphycs_pipeline_, nullptr); + if (pipeline_layout_ != VK_NULL_HANDLE) vkDestroyPipelineLayout(device_, pipeline_layout_, nullptr); + + if (render_pass_ != VK_NULL_HANDLE) + vkDestroyRenderPass(device_, render_pass_, nullptr); for (auto image_view : swapchain_image_views_) vkDestroyImageView(device_, image_view, nullptr); diff --git a/Core/Core/RenderEngine.h b/Core/Core/RenderEngine.h index 17cc08f..aac5ed3 100644 --- a/Core/Core/RenderEngine.h +++ b/Core/Core/RenderEngine.h @@ -48,7 +48,9 @@ class RenderEngine VkFormat swapchain_image_format_; VkExtent2D swapchain_extent_; std::vector swapchain_image_views_; + VkRenderPass render_pass_ = VK_NULL_HANDLE; VkPipelineLayout pipeline_layout_ = VK_NULL_HANDLE; + VkPipeline graphycs_pipeline_ = VK_NULL_HANDLE; #ifdef _DEBUG VkResult enable_layer_validation(VkDebugUtilsMessengerCreateInfoEXT* create_info); @@ -71,6 +73,7 @@ class RenderEngine void create_logical_device(); void create_swapchain(VkPresentModeKHR desired_present_mode); void create_image_views(); + void create_render_pass(); void create_graphycs_pipleline(); public: // Can throw the exception From 958e13c6f55e11919c0aaf8a6f6b1bc5b397a67c Mon Sep 17 00:00:00 2001 From: Jiga228 Date: Sun, 28 Sep 2025 18:56:12 +0700 Subject: [PATCH 12/17] Add create framebuffer --- Core/Core/RenderEngine.cpp | 26 ++++++++++++++++++++++++-- Core/Core/RenderEngine.h | 5 ++++- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/Core/Core/RenderEngine.cpp b/Core/Core/RenderEngine.cpp index 9db638e..752d866 100644 --- a/Core/Core/RenderEngine.cpp +++ b/Core/Core/RenderEngine.cpp @@ -394,7 +394,7 @@ void RenderEngine::create_render_pass() VK_CHECK(vkCreateRenderPass(device_, &render_pass_info, nullptr, &render_pass_)); } -void RenderEngine::create_graphycs_pipleline() +void RenderEngine::create_graphycs_pipeline() { std::ifstream vertex_shader_file("Shaders/vertex.spv", std::ios::binary); if (!vertex_shader_file.is_open()) @@ -531,6 +531,25 @@ void RenderEngine::create_graphycs_pipleline() vkDestroyShaderModule(device_, fragment_shader, nullptr); } +void RenderEngine::create_framebuffers() +{ + framebuffers_.resize(swapchain_images_.size()); + + VkFramebufferCreateInfo framebuffer_info{}; + framebuffer_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + framebuffer_info.renderPass = render_pass_; + framebuffer_info.attachmentCount = 1; + framebuffer_info.width = swapchain_extent_.width; + framebuffer_info.height = swapchain_extent_.height; + framebuffer_info.layers = 1; + + for (size_t i = 0; i < framebuffers_.size(); ++i) + { + framebuffer_info.pAttachments = &swapchain_image_views_[i]; + VK_CHECK(vkCreateFramebuffer(device_, &framebuffer_info, nullptr, &framebuffers_[i])); + } +} + void RenderEngine::create_surface() { VK_CHECK(glfwCreateWindowSurface(instance_, window_, nullptr, &surface_)); @@ -550,11 +569,14 @@ window_(window) create_swapchain(desired_present_mode); create_image_views(); create_render_pass(); - create_graphycs_pipleline(); + create_graphycs_pipeline(); } RenderEngine::~RenderEngine() { + for (auto& i : framebuffers_) + vkDestroyFramebuffer(device_, i, nullptr); + if (graphycs_pipeline_ != VK_NULL_HANDLE) vkDestroyPipeline(device_, graphycs_pipeline_, nullptr); diff --git a/Core/Core/RenderEngine.h b/Core/Core/RenderEngine.h index aac5ed3..7f4dd0c 100644 --- a/Core/Core/RenderEngine.h +++ b/Core/Core/RenderEngine.h @@ -51,6 +51,7 @@ class RenderEngine VkRenderPass render_pass_ = VK_NULL_HANDLE; VkPipelineLayout pipeline_layout_ = VK_NULL_HANDLE; VkPipeline graphycs_pipeline_ = VK_NULL_HANDLE; + std::vector framebuffers_; #ifdef _DEBUG VkResult enable_layer_validation(VkDebugUtilsMessengerCreateInfoEXT* create_info); @@ -74,7 +75,9 @@ class RenderEngine void create_swapchain(VkPresentModeKHR desired_present_mode); void create_image_views(); void create_render_pass(); - void create_graphycs_pipleline(); + void create_graphycs_pipeline(); + void create_framebuffers(); + public: // Can throw the exception RenderEngine(CoreInstance& core, GLFWwindow* window, VkPresentModeKHR desired_present_mode = VK_PRESENT_MODE_MAILBOX_KHR); From 47bb1541efb4c8f8be0cc15d83e80bce3f033737 Mon Sep 17 00:00:00 2001 From: Jiga228 Date: Mon, 29 Sep 2025 20:00:42 +0700 Subject: [PATCH 13/17] Add create comand_pool and command_buffers. Fix CMake file for TestGame --- Core/Core/RenderEngine.cpp | 35 +++++++++++++++++++++++++++++++++-- Core/Core/RenderEngine.h | 9 ++++++++- TestGame/CMakeLists.txt | 2 -- 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/Core/Core/RenderEngine.cpp b/Core/Core/RenderEngine.cpp index 752d866..2577bc9 100644 --- a/Core/Core/RenderEngine.cpp +++ b/Core/Core/RenderEngine.cpp @@ -394,7 +394,7 @@ void RenderEngine::create_render_pass() VK_CHECK(vkCreateRenderPass(device_, &render_pass_info, nullptr, &render_pass_)); } -void RenderEngine::create_graphycs_pipeline() +void RenderEngine::create_graphics_pipeline() { std::ifstream vertex_shader_file("Shaders/vertex.spv", std::ios::binary); if (!vertex_shader_file.is_open()) @@ -550,6 +550,31 @@ void RenderEngine::create_framebuffers() } } +void RenderEngine::create_command_pool() +{ + QueueFamilyIndices queue_family_indices = find_queue_family_indices(physical_device_, surface_); + + VkCommandPoolCreateInfo command_pool_info{}; + command_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + command_pool_info.queueFamilyIndex = queue_family_indices.graphycs_family.value(); + command_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + + VK_CHECK(vkCreateCommandPool(device_, &command_pool_info, nullptr, &command_pool_)); +} + +void RenderEngine::allocate_command_buffers() +{ + command_buffers_.resize(MAX_FRAMES_IN_FLIGHT); + + VkCommandBufferAllocateInfo command_buffer_allocate_info{}; + command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + command_buffer_allocate_info.commandPool = command_pool_; + command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + command_buffer_allocate_info.commandBufferCount = static_cast(command_buffers_.size()); + + VK_CHECK(vkAllocateCommandBuffers(device_, &command_buffer_allocate_info, command_buffers_.data())); +} + void RenderEngine::create_surface() { VK_CHECK(glfwCreateWindowSurface(instance_, window_, nullptr, &surface_)); @@ -569,11 +594,17 @@ window_(window) create_swapchain(desired_present_mode); create_image_views(); create_render_pass(); - create_graphycs_pipeline(); + create_graphics_pipeline(); } RenderEngine::~RenderEngine() { + if (command_buffers_.size() > 0) + vkFreeCommandBuffers(device_, command_pool_, static_cast(command_buffers_.size()), command_buffers_.data()); + + if (command_pool_ != VK_NULL_HANDLE) + vkDestroyCommandPool(device_, command_pool_, nullptr); + for (auto& i : framebuffers_) vkDestroyFramebuffer(device_, i, nullptr); diff --git a/Core/Core/RenderEngine.h b/Core/Core/RenderEngine.h index 7f4dd0c..6857c86 100644 --- a/Core/Core/RenderEngine.h +++ b/Core/Core/RenderEngine.h @@ -35,6 +35,9 @@ class RenderEngine static const std::vector deviceExtensions; + const int MAX_FRAMES_IN_FLIGHT = 2; + int current_frame_ = 0; + CoreInstance& core_; GLFWwindow* window_; VkInstance instance_ = VK_NULL_HANDLE; @@ -52,6 +55,8 @@ class RenderEngine VkPipelineLayout pipeline_layout_ = VK_NULL_HANDLE; VkPipeline graphycs_pipeline_ = VK_NULL_HANDLE; std::vector framebuffers_; + VkCommandPool command_pool_ = VK_NULL_HANDLE; + std::vector command_buffers_; #ifdef _DEBUG VkResult enable_layer_validation(VkDebugUtilsMessengerCreateInfoEXT* create_info); @@ -75,8 +80,10 @@ class RenderEngine void create_swapchain(VkPresentModeKHR desired_present_mode); void create_image_views(); void create_render_pass(); - void create_graphycs_pipeline(); + void create_graphics_pipeline(); void create_framebuffers(); + void create_command_pool(); + void allocate_command_buffers(); public: // Can throw the exception diff --git a/TestGame/CMakeLists.txt b/TestGame/CMakeLists.txt index ae41ece..8a6a218 100644 --- a/TestGame/CMakeLists.txt +++ b/TestGame/CMakeLists.txt @@ -59,7 +59,6 @@ add_custom_command( COMMAND $ENV{VULKAN_SDK}/Bin/glslc.exe ${CMAKE_CURRENT_SOURCE_DIR}/Shaders/vertex.vert -o ${OUTPUT_PATH}/Shaders/vertex.spv - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/Shaders/vertex.vert COMMENT "Building vertex shader" ) @@ -69,6 +68,5 @@ add_custom_command( COMMAND $ENV{VULKAN_SDK}/Bin/glslc.exe ${CMAKE_CURRENT_SOURCE_DIR}/Shaders/fragment.frag -o ${OUTPUT_PATH}/Shaders/fragment.spv - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/Shaders/fragment.frag COMMENT "Building fragment shader" ) From 8f9dd52548ecb88a9f14a2a240a871f56c32413f Mon Sep 17 00:00:00 2001 From: Jiga228 Date: Mon, 29 Sep 2025 21:02:18 +0700 Subject: [PATCH 14/17] Add draw triangle --- Core/Core/RenderEngine.cpp | 131 +++++++++++++++++++++++++++++++++++-- Core/Core/RenderEngine.h | 9 ++- TestGame/CMakeLists.txt | 2 +- 3 files changed, 135 insertions(+), 7 deletions(-) diff --git a/Core/Core/RenderEngine.cpp b/Core/Core/RenderEngine.cpp index 2577bc9..b31458d 100644 --- a/Core/Core/RenderEngine.cpp +++ b/Core/Core/RenderEngine.cpp @@ -383,6 +383,14 @@ void RenderEngine::create_render_pass() subpass_description.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; subpass_description.colorAttachmentCount = 1; subpass_description.pColorAttachments = &attachment_reference; + + VkSubpassDependency dependency{}; + dependency.srcSubpass = VK_SUBPASS_EXTERNAL; + dependency.dstSubpass = 0; + dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependency.srcAccessMask = 0; + dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; VkRenderPassCreateInfo render_pass_info{}; render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; @@ -390,6 +398,8 @@ void RenderEngine::create_render_pass() render_pass_info.pAttachments = &attachment_description; render_pass_info.subpassCount = 1; render_pass_info.pSubpasses = &subpass_description; + render_pass_info.dependencyCount = 1; + render_pass_info.pDependencies = &dependency; VK_CHECK(vkCreateRenderPass(device_, &render_pass_info, nullptr, &render_pass_)); } @@ -483,7 +493,7 @@ void RenderEngine::create_graphics_pipeline() multisample_info.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; VkPipelineColorBlendAttachmentState color_blend_attachment_state{}; - color_blend_attachment_state.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + color_blend_attachment_state.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; color_blend_attachment_state.blendEnable = VK_TRUE; color_blend_attachment_state.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; color_blend_attachment_state.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; @@ -564,7 +574,7 @@ void RenderEngine::create_command_pool() void RenderEngine::allocate_command_buffers() { - command_buffers_.resize(MAX_FRAMES_IN_FLIGHT); + command_buffers_.resize(swapchain_images_.size()); VkCommandBufferAllocateInfo command_buffer_allocate_info{}; command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; @@ -575,6 +585,104 @@ void RenderEngine::allocate_command_buffers() VK_CHECK(vkAllocateCommandBuffers(device_, &command_buffer_allocate_info, command_buffers_.data())); } +void RenderEngine::create_sync_objects() +{ + image_available_semaphores_.resize(swapchain_images_.size()); + render_finished_semaphores_.resize(swapchain_images_.size()); + in_flight_fences_.resize(swapchain_images_.size()); + + VkSemaphoreCreateInfo semaphore_info{}; + semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + + VkFenceCreateInfo fence_info{}; + fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT; + + for (size_t i = 0; i < swapchain_images_.size(); ++i) + { + VK_CHECK(vkCreateSemaphore(device_, &semaphore_info, nullptr, &image_available_semaphores_[i])); + VK_CHECK(vkCreateSemaphore(device_, &semaphore_info, nullptr, &render_finished_semaphores_[i])); + VK_CHECK(vkCreateFence(device_, &fence_info, nullptr, &in_flight_fences_[i])); + } +} + +void RenderEngine::record_command_buffer(VkCommandBuffer command_buffer, uint32_t image_index) +{ + VkCommandBufferBeginInfo command_buffer_begin_info{}; + command_buffer_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + VK_CHECK(vkBeginCommandBuffer(command_buffer, &command_buffer_begin_info)); + + const VkClearValue clear_color = {{{0.0f, 0.0f, 0.0f, 1.0f}}}; + VkRenderPassBeginInfo render_pass_begin_info{}; + render_pass_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + render_pass_begin_info.renderPass = render_pass_; + render_pass_begin_info.framebuffer = framebuffers_[image_index]; + render_pass_begin_info.renderArea.offset = {0, 0}; + render_pass_begin_info.renderArea.extent = swapchain_extent_; + render_pass_begin_info.clearValueCount = 1; + render_pass_begin_info.pClearValues = &clear_color; + vkCmdBeginRenderPass(command_buffer, &render_pass_begin_info, VK_SUBPASS_CONTENTS_INLINE); + + vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphycs_pipeline_); + + VkViewport viewport{}; + viewport.x = 0.0f; + viewport.y = 0.0f; + viewport.width = static_cast(swapchain_extent_.width); + viewport.height = static_cast(swapchain_extent_.height); + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + vkCmdSetViewport(command_buffer, 0, 1, &viewport); + + VkRect2D scissor{}; + scissor.offset = {0, 0}; + scissor.extent = swapchain_extent_; + vkCmdSetScissor(command_buffer, 0, 1, &scissor); + + vkCmdDraw(command_buffer, 3, 1, 0, 0); + + vkCmdEndRenderPass(command_buffer); + VK_CHECK(vkEndCommandBuffer(command_buffer)); +} + +void RenderEngine::draw_frame() +{ + vkWaitForFences(device_, 1, &in_flight_fences_[current_frame_], VK_TRUE, UINT64_MAX); + vkResetFences(device_, 1, &in_flight_fences_[current_frame_]); + + uint32_t image_index; + vkAcquireNextImageKHR(device_, swapchain_, UINT64_MAX, image_available_semaphores_[current_frame_], VK_NULL_HANDLE, &image_index); + + vkResetCommandBuffer(command_buffers_[current_frame_], 0); + record_command_buffer(command_buffers_[current_frame_], image_index); + + VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + VkSubmitInfo submit_info{}; + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &command_buffers_[current_frame_]; + submit_info.waitSemaphoreCount = 1; + submit_info.pWaitSemaphores = &image_available_semaphores_[current_frame_]; + submit_info.pWaitDstStageMask = &wait_stage; + submit_info.signalSemaphoreCount = 1; + submit_info.pSignalSemaphores = &render_finished_semaphores_[current_frame_]; + + VK_CHECK(vkQueueSubmit(graphics_queue_, 1, &submit_info, in_flight_fences_[current_frame_])); + + VkPresentInfoKHR present_info{}; + present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; + present_info.waitSemaphoreCount = 1; + present_info.pWaitSemaphores = &render_finished_semaphores_[current_frame_]; + present_info.swapchainCount = 1; + present_info.pSwapchains = &swapchain_; + present_info.pImageIndices = &image_index; + present_info.pResults = nullptr; + + vkQueuePresentKHR(present_queue_, &present_info); + + current_frame_ = (current_frame_ + 1) % swapchain_images_.size(); +} + void RenderEngine::create_surface() { VK_CHECK(glfwCreateWindowSurface(instance_, window_, nullptr, &surface_)); @@ -595,11 +703,26 @@ window_(window) create_image_views(); create_render_pass(); create_graphics_pipeline(); + create_framebuffers(); + create_command_pool(); + allocate_command_buffers(); + create_sync_objects(); } RenderEngine::~RenderEngine() { - if (command_buffers_.size() > 0) + vkDeviceWaitIdle(device_); + + for (auto& i : image_available_semaphores_) + vkDestroySemaphore(device_, i, nullptr); + + for (auto& i : render_finished_semaphores_) + vkDestroySemaphore(device_, i, nullptr); + + for (auto& i : in_flight_fences_) + vkDestroyFence(device_, i, nullptr); + + if (command_buffers_.empty() == false) vkFreeCommandBuffers(device_, command_pool_, static_cast(command_buffers_.size()), command_buffers_.data()); if (command_pool_ != VK_NULL_HANDLE) @@ -649,8 +772,8 @@ void RenderEngine::start() { while (!glfwWindowShouldClose(window_)) { - glfwSwapBuffers(window_); glfwPollEvents(); + draw_frame(); } } diff --git a/Core/Core/RenderEngine.h b/Core/Core/RenderEngine.h index 6857c86..5dddb5e 100644 --- a/Core/Core/RenderEngine.h +++ b/Core/Core/RenderEngine.h @@ -35,7 +35,6 @@ class RenderEngine static const std::vector deviceExtensions; - const int MAX_FRAMES_IN_FLIGHT = 2; int current_frame_ = 0; CoreInstance& core_; @@ -58,6 +57,9 @@ class RenderEngine VkCommandPool command_pool_ = VK_NULL_HANDLE; std::vector command_buffers_; + std::vector image_available_semaphores_, render_finished_semaphores_; + std::vector in_flight_fences_; + #ifdef _DEBUG VkResult enable_layer_validation(VkDebugUtilsMessengerCreateInfoEXT* create_info); VkDebugUtilsMessengerEXT debug_messenger_; @@ -84,7 +86,10 @@ class RenderEngine void create_framebuffers(); void create_command_pool(); void allocate_command_buffers(); - + void create_sync_objects(); + + void record_command_buffer(VkCommandBuffer command_buffer, uint32_t image_index); + void draw_frame(); public: // Can throw the exception RenderEngine(CoreInstance& core, GLFWwindow* window, VkPresentModeKHR desired_present_mode = VK_PRESENT_MODE_MAILBOX_KHR); diff --git a/TestGame/CMakeLists.txt b/TestGame/CMakeLists.txt index 8a6a218..3b3abba 100644 --- a/TestGame/CMakeLists.txt +++ b/TestGame/CMakeLists.txt @@ -2,7 +2,7 @@ set(GAME_NAME TestGame) set(CMAKE_CXX_STANDARD 20) -file(GLOB_RECURSE SRC "*.cpp" "*.c" "*.h" "*.hpp" "*.res" "*.world" "*.conf") +file(GLOB_RECURSE SRC "*.cpp" "*.c" "*.h" "*.hpp" "*.res" "*.world" "*.conf" "*.frag" "*.vert") add_executable(${GAME_NAME} ${SRC}) target_link_libraries(${GAME_NAME} PRIVATE Core) From 2e483c8230ceeb2a4f56b51fdf464b2265110ded Mon Sep 17 00:00:00 2001 From: Jiga228 Date: Fri, 3 Oct 2025 21:23:25 +0700 Subject: [PATCH 15/17] Add vertex buffer --- Core/Core/RenderEngine.cpp | 97 ++++++++++++++++++++++++++++++++---- Core/Core/RenderEngine.h | 25 +++++++++- TestGame/Shaders/vertex.vert | 22 +++----- 3 files changed, 118 insertions(+), 26 deletions(-) diff --git a/Core/Core/RenderEngine.cpp b/Core/Core/RenderEngine.cpp index b31458d..0043dd4 100644 --- a/Core/Core/RenderEngine.cpp +++ b/Core/Core/RenderEngine.cpp @@ -73,6 +73,30 @@ bool RenderEngine::QueueFamilyIndices::is_complete() return graphycs_family.has_value() && present_family.has_value(); } +VkVertexInputBindingDescription RenderEngine::Vertex::get_binding_description() +{ + VkVertexInputBindingDescription description{}; + description.binding = 0; + description.stride = sizeof(Vertex); + description.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + return description; +} + +std::array RenderEngine::Vertex::get_vertex_attribute_descriptions() +{ + std::array descriptions; + descriptions[0].binding = 0; + descriptions[0].location = 0; + descriptions[0].format = VK_FORMAT_R32G32_SFLOAT; + descriptions[0].offset = offsetof(Vertex, pos); + descriptions[1].binding = 0; + descriptions[1].location = 1; + descriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT; + descriptions[1].offset = offsetof(Vertex, color); + + return descriptions; +} + bool RenderEngine::is_device_suitable(VkPhysicalDevice device, VkSurfaceKHR surface) { VkPhysicalDeviceProperties device_properties; @@ -446,12 +470,15 @@ void RenderEngine::create_graphics_pipeline() dynamic_state_info.dynamicStateCount = static_cast(dynamic_states.size()); dynamic_state_info.pDynamicStates = dynamic_states.data(); + VkVertexInputBindingDescription binding_description = Vertex::get_binding_description(); + std::array attribute_descriptions = Vertex::get_vertex_attribute_descriptions(); + VkPipelineVertexInputStateCreateInfo vertex_input_info{}; vertex_input_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; - vertex_input_info.vertexAttributeDescriptionCount = 0; - vertex_input_info.pVertexAttributeDescriptions = nullptr; - vertex_input_info.vertexBindingDescriptionCount = 0; - vertex_input_info.pVertexBindingDescriptions = nullptr; + vertex_input_info.vertexBindingDescriptionCount = 1; + vertex_input_info.pVertexBindingDescriptions = &binding_description; + vertex_input_info.vertexAttributeDescriptionCount = static_cast(attribute_descriptions.size()); + vertex_input_info.pVertexAttributeDescriptions = attribute_descriptions.data(); VkPipelineInputAssemblyStateCreateInfo input_assembly_info{}; input_assembly_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; @@ -535,7 +562,7 @@ void RenderEngine::create_graphics_pipeline() graphics_pipeline_info.basePipelineHandle = nullptr; graphics_pipeline_info.basePipelineIndex = -1; - VK_CHECK(vkCreateGraphicsPipelines(device_, nullptr, 1, &graphics_pipeline_info, nullptr, &graphycs_pipeline_)); + VK_CHECK(vkCreateGraphicsPipelines(device_, nullptr, 1, &graphics_pipeline_info, nullptr, &graphics_pipeline_)); vkDestroyShaderModule(device_, vertex_shader, nullptr); vkDestroyShaderModule(device_, fragment_shader, nullptr); @@ -572,6 +599,47 @@ void RenderEngine::create_command_pool() VK_CHECK(vkCreateCommandPool(device_, &command_pool_info, nullptr, &command_pool_)); } +uint32_t RenderEngine::find_memory_type(uint32_t typeFilter, VkMemoryPropertyFlags properties) +{ + VkPhysicalDeviceMemoryProperties memory_properties{}; + vkGetPhysicalDeviceMemoryProperties(physical_device_, &memory_properties); + + for (uint32_t i = 0; i < memory_properties.memoryTypeCount; ++i) + { + if (typeFilter & (1 << i) && (memory_properties.memoryTypes[i].propertyFlags & properties) == properties) + return i; + } + + throw std::runtime_error("failed to find suitable memory type!"); +} + +void RenderEngine::allocate_vertex_buffer() +{ + VkBufferCreateInfo buffer_info{}; + buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + buffer_info.size = sizeof(vertices[0]) * vertices.size(); + buffer_info.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; + buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + VK_CHECK(vkCreateBuffer(device_, &buffer_info, nullptr, &vertex_buffer_)); + + VkMemoryRequirements requirements{}; + vkGetBufferMemoryRequirements(device_, vertex_buffer_, &requirements); + + VkMemoryAllocateInfo allocate_info{}; + allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocate_info.allocationSize = requirements.size; + allocate_info.memoryTypeIndex = find_memory_type(requirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + + VK_CHECK(vkAllocateMemory(device_, &allocate_info, nullptr, &vertex_buffer_memory_)); + VK_CHECK(vkBindBufferMemory(device_, vertex_buffer_, vertex_buffer_memory_, 0)); + + void* data; + VK_CHECK(vkMapMemory(device_, vertex_buffer_memory_, 0, buffer_info.size, 0, &data)); + memcpy(data, vertices.data(), (size_t) buffer_info.size); + vkUnmapMemory(device_, vertex_buffer_memory_); +} + void RenderEngine::allocate_command_buffers() { command_buffers_.resize(swapchain_images_.size()); @@ -623,7 +691,11 @@ void RenderEngine::record_command_buffer(VkCommandBuffer command_buffer, uint32_ render_pass_begin_info.pClearValues = &clear_color; vkCmdBeginRenderPass(command_buffer, &render_pass_begin_info, VK_SUBPASS_CONTENTS_INLINE); - vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphycs_pipeline_); + vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipeline_); + + VkBuffer vertex_buffers[] = {vertex_buffer_}; + VkDeviceSize offset[] = {0}; + vkCmdBindVertexBuffers(command_buffer, 0, 1, vertex_buffers, offset); VkViewport viewport{}; viewport.x = 0.0f; @@ -639,7 +711,7 @@ void RenderEngine::record_command_buffer(VkCommandBuffer command_buffer, uint32_ scissor.extent = swapchain_extent_; vkCmdSetScissor(command_buffer, 0, 1, &scissor); - vkCmdDraw(command_buffer, 3, 1, 0, 0); + vkCmdDraw(command_buffer, static_cast(vertices.size()), 1, 0, 0); vkCmdEndRenderPass(command_buffer); VK_CHECK(vkEndCommandBuffer(command_buffer)); @@ -705,6 +777,7 @@ window_(window) create_graphics_pipeline(); create_framebuffers(); create_command_pool(); + allocate_vertex_buffer(); allocate_command_buffers(); create_sync_objects(); } @@ -712,6 +785,12 @@ window_(window) RenderEngine::~RenderEngine() { vkDeviceWaitIdle(device_); + + if (vertex_buffer_memory_ != VK_NULL_HANDLE) + vkFreeMemory(device_, vertex_buffer_memory_, nullptr); + + if (vertex_buffer_ != VK_NULL_HANDLE) + vkDestroyBuffer(device_, vertex_buffer_, nullptr); for (auto& i : image_available_semaphores_) vkDestroySemaphore(device_, i, nullptr); @@ -731,8 +810,8 @@ RenderEngine::~RenderEngine() for (auto& i : framebuffers_) vkDestroyFramebuffer(device_, i, nullptr); - if (graphycs_pipeline_ != VK_NULL_HANDLE) - vkDestroyPipeline(device_, graphycs_pipeline_, nullptr); + if (graphics_pipeline_ != VK_NULL_HANDLE) + vkDestroyPipeline(device_, graphics_pipeline_, nullptr); if (pipeline_layout_ != VK_NULL_HANDLE) vkDestroyPipelineLayout(device_, pipeline_layout_, nullptr); diff --git a/Core/Core/RenderEngine.h b/Core/Core/RenderEngine.h index 5dddb5e..5cae440 100644 --- a/Core/Core/RenderEngine.h +++ b/Core/Core/RenderEngine.h @@ -1,13 +1,15 @@ #pragma once +#include #include #include +#include #define GLFW_INCLUDE_VULKAN -#include #include #include +#include #ifdef _DEBUG #include @@ -33,6 +35,25 @@ class RenderEngine std::vector present_modes; }; +#pragma region Experemental + struct Vertex + { + glm::vec2 pos; + glm::vec3 color; + static VkVertexInputBindingDescription get_binding_description(); + static std::array get_vertex_attribute_descriptions(); + }; + const std::vector vertices = { + {{0.0f, -0.5f}, {1.0f, 0.0f, 0.0f}}, + {{0.5f, 0.5f}, {0.0f, 1.0f, 0.0f}}, + {{-0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}} + }; + VkBuffer vertex_buffer_ = VK_NULL_HANDLE; + VkDeviceMemory vertex_buffer_memory_ = VK_NULL_HANDLE; + uint32_t find_memory_type(uint32_t typeFilter, VkMemoryPropertyFlags properties); + void allocate_vertex_buffer(); +#pragma endregion + static const std::vector deviceExtensions; int current_frame_ = 0; @@ -52,7 +73,7 @@ class RenderEngine std::vector swapchain_image_views_; VkRenderPass render_pass_ = VK_NULL_HANDLE; VkPipelineLayout pipeline_layout_ = VK_NULL_HANDLE; - VkPipeline graphycs_pipeline_ = VK_NULL_HANDLE; + VkPipeline graphics_pipeline_ = VK_NULL_HANDLE; std::vector framebuffers_; VkCommandPool command_pool_ = VK_NULL_HANDLE; std::vector command_buffers_; diff --git a/TestGame/Shaders/vertex.vert b/TestGame/Shaders/vertex.vert index fe613ef..92ceacd 100644 --- a/TestGame/Shaders/vertex.vert +++ b/TestGame/Shaders/vertex.vert @@ -1,20 +1,12 @@ #version 450 +layout(location = 0) in vec2 inPosition; +layout(location = 1) in vec3 inColor; + layout(location = 0) out vec3 fragColor; -vec3 colors[3] = vec3[]( - vec3(1.0, 0.0, 0.0), - vec3(0.0, 1.0, 0.0), - vec3(0.0, 0.0, 1.0) -); - -vec2 positions[3] = vec2[]( - vec2(0.0, -0.5), - vec2(0.5, 0.5), - vec2(-0.5, 0.5) -); - -void main() { - gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0); - fragColor = colors[gl_VertexIndex]; +void main() +{ + gl_Position = vec4(inPosition, 0.0, 1.0); + fragColor = inColor; } \ No newline at end of file From 86dfc28a6c1172ee4707982d62d66c1edef89594 Mon Sep 17 00:00:00 2001 From: Jiga228 Date: Sat, 4 Oct 2025 15:34:40 +0700 Subject: [PATCH 16/17] Refactor --- Core/Core/RenderEngine.cpp | 51 +++++++++++++++++++------------------- Core/Core/RenderEngine.h | 18 +++++++------- 2 files changed, 34 insertions(+), 35 deletions(-) diff --git a/Core/Core/RenderEngine.cpp b/Core/Core/RenderEngine.cpp index 0043dd4..ed2cc7a 100644 --- a/Core/Core/RenderEngine.cpp +++ b/Core/Core/RenderEngine.cpp @@ -1,6 +1,5 @@ #include "RenderEngine.h" -#include #include #include #include @@ -29,14 +28,14 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback( return VK_FALSE; } -VkResult RenderEngine::enable_layer_validation(VkDebugUtilsMessengerCreateInfoEXT* create_info) +VkResult RenderEngine::enable_layer_validation(const VkDebugUtilsMessengerCreateInfoEXT* create_info) { PFN_vkCreateDebugUtilsMessengerEXT debug_creator = reinterpret_cast(vkGetInstanceProcAddr(instance_, "vkCreateDebugUtilsMessengerEXT")); return debug_creator(instance_, create_info, nullptr, &debug_messenger_); } #endif -RenderEngine::SwapchainSupportDetails RenderEngine::query_swapchain_details() +RenderEngine::SwapchainSupportDetails RenderEngine::query_swapchain_details() const { SwapchainSupportDetails details; @@ -68,14 +67,14 @@ std::vector RenderEngine::get_required_extensions() } -bool RenderEngine::QueueFamilyIndices::is_complete() +bool RenderEngine::QueueFamilyIndices::is_complete() const { - return graphycs_family.has_value() && present_family.has_value(); + return graphics_family.has_value() && present_family.has_value(); } VkVertexInputBindingDescription RenderEngine::Vertex::get_binding_description() { - VkVertexInputBindingDescription description{}; + VkVertexInputBindingDescription description; description.binding = 0; description.stride = sizeof(Vertex); description.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; @@ -139,13 +138,13 @@ RenderEngine::QueueFamilyIndices RenderEngine::find_queue_family_indices(VkPhysi uint32_t queueFamilyCount = 0; vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queueFamilyCount, nullptr); - std::vector family_propertieses(queueFamilyCount); - vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queueFamilyCount, family_propertieses.data()); + std::vector family_properties(queueFamilyCount); + vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queueFamilyCount, family_properties.data()); - for (uint32_t i = 0; i < family_propertieses.size(); ++i) + for (uint32_t i = 0; i < family_properties.size(); ++i) { - if (family_propertieses[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) - queue_family_indices.graphycs_family = i; + if (family_properties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) + queue_family_indices.graphics_family = i; VkBool32 present_support = false; VK_CHECK(vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, i, surface, &present_support)); @@ -195,7 +194,7 @@ VkExtent2D RenderEngine::choose_extent(const VkSurfaceCapabilitiesKHR& capabilit } } -VkShaderModule RenderEngine::create_shader_module(const std::string code) +VkShaderModule RenderEngine::create_shader_module(const std::string& code) const { VkShaderModuleCreateInfo shader_module_info{}; shader_module_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; @@ -275,7 +274,7 @@ void RenderEngine::create_logical_device() VkPhysicalDeviceFeatures device_features{}; std::vector queue_create_infos; - std::set unique_queue_families = {indices.graphycs_family.value(), indices.present_family.value()}; + std::set unique_queue_families = {indices.graphics_family.value(), indices.present_family.value()}; float queue_priority = 1.0f; VkDeviceQueueCreateInfo device_queue_create_info{}; @@ -308,7 +307,7 @@ void RenderEngine::create_logical_device() #endif VK_CHECK(vkCreateDevice(physical_device_, &device_create_info, nullptr, &device_)); - vkGetDeviceQueue(device_, indices.graphycs_family.value(), 0, &graphics_queue_); + vkGetDeviceQueue(device_, indices.graphics_family.value(), 0, &graphics_queue_); vkGetDeviceQueue(device_, indices.present_family.value(), 0, &present_queue_); } @@ -339,8 +338,8 @@ void RenderEngine::create_swapchain(VkPresentModeKHR desired_present_mode) swapchain_create_info.oldSwapchain = VK_NULL_HANDLE; QueueFamilyIndices family_indices = find_queue_family_indices(physical_device_, surface_); - uint32_t queue_family_indices[] = {family_indices.graphycs_family.value(), family_indices.present_family.value()}; - if (family_indices.graphycs_family != family_indices.present_family) + uint32_t queue_family_indices[] = {family_indices.graphics_family.value(), family_indices.present_family.value()}; + if (family_indices.graphics_family != family_indices.present_family) { swapchain_create_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT; swapchain_create_info.queueFamilyIndexCount = 2; @@ -399,7 +398,7 @@ void RenderEngine::create_render_pass() attachment_description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; attachment_description.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - VkAttachmentReference attachment_reference{}; + VkAttachmentReference attachment_reference; attachment_reference.attachment = 0; attachment_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; @@ -593,13 +592,13 @@ void RenderEngine::create_command_pool() VkCommandPoolCreateInfo command_pool_info{}; command_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - command_pool_info.queueFamilyIndex = queue_family_indices.graphycs_family.value(); + command_pool_info.queueFamilyIndex = queue_family_indices.graphics_family.value(); command_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; VK_CHECK(vkCreateCommandPool(device_, &command_pool_info, nullptr, &command_pool_)); } -uint32_t RenderEngine::find_memory_type(uint32_t typeFilter, VkMemoryPropertyFlags properties) +uint32_t RenderEngine::find_memory_type(uint32_t typeFilter, VkMemoryPropertyFlags properties) const { VkPhysicalDeviceMemoryProperties memory_properties{}; vkGetPhysicalDeviceMemoryProperties(physical_device_, &memory_properties); @@ -636,7 +635,7 @@ void RenderEngine::allocate_vertex_buffer() void* data; VK_CHECK(vkMapMemory(device_, vertex_buffer_memory_, 0, buffer_info.size, 0, &data)); - memcpy(data, vertices.data(), (size_t) buffer_info.size); + memcpy(data, vertices.data(), buffer_info.size); vkUnmapMemory(device_, vertex_buffer_memory_); } @@ -674,13 +673,13 @@ void RenderEngine::create_sync_objects() } } -void RenderEngine::record_command_buffer(VkCommandBuffer command_buffer, uint32_t image_index) +void RenderEngine::record_command_buffer(VkCommandBuffer command_buffer, uint32_t image_index) const { VkCommandBufferBeginInfo command_buffer_begin_info{}; command_buffer_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; VK_CHECK(vkBeginCommandBuffer(command_buffer, &command_buffer_begin_info)); - const VkClearValue clear_color = {{{0.0f, 0.0f, 0.0f, 1.0f}}}; + constexpr VkClearValue clear_color = {{{0.0f, 0.0f, 0.0f, 1.0f}}}; VkRenderPassBeginInfo render_pass_begin_info{}; render_pass_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; render_pass_begin_info.renderPass = render_pass_; @@ -697,7 +696,7 @@ void RenderEngine::record_command_buffer(VkCommandBuffer command_buffer, uint32_ VkDeviceSize offset[] = {0}; vkCmdBindVertexBuffers(command_buffer, 0, 1, vertex_buffers, offset); - VkViewport viewport{}; + VkViewport viewport; viewport.x = 0.0f; viewport.y = 0.0f; viewport.width = static_cast(swapchain_extent_.width); @@ -706,7 +705,7 @@ void RenderEngine::record_command_buffer(VkCommandBuffer command_buffer, uint32_ viewport.maxDepth = 1.0f; vkCmdSetViewport(command_buffer, 0, 1, &viewport); - VkRect2D scissor{}; + VkRect2D scissor; scissor.offset = {0, 0}; scissor.extent = swapchain_extent_; vkCmdSetScissor(command_buffer, 0, 1, &scissor); @@ -752,7 +751,7 @@ void RenderEngine::draw_frame() vkQueuePresentKHR(present_queue_, &present_info); - current_frame_ = (current_frame_ + 1) % swapchain_images_.size(); + current_frame_ = (current_frame_ + 1) % static_cast(swapchain_images_.size()); } void RenderEngine::create_surface() @@ -856,7 +855,7 @@ void RenderEngine::start() } } -void RenderEngine::stop_render() +void RenderEngine::stop_render() const { if (window_ != nullptr && !glfwWindowShouldClose(window_)) glfwSetWindowShouldClose(window_, true); diff --git a/Core/Core/RenderEngine.h b/Core/Core/RenderEngine.h index 5cae440..b2b808c 100644 --- a/Core/Core/RenderEngine.h +++ b/Core/Core/RenderEngine.h @@ -24,9 +24,9 @@ class RenderEngine { struct QueueFamilyIndices { - std::optional graphycs_family; + std::optional graphics_family; std::optional present_family; - bool is_complete(); + bool is_complete() const; }; struct SwapchainSupportDetails { @@ -43,14 +43,14 @@ class RenderEngine static VkVertexInputBindingDescription get_binding_description(); static std::array get_vertex_attribute_descriptions(); }; - const std::vector vertices = { + std::vector vertices = { {{0.0f, -0.5f}, {1.0f, 0.0f, 0.0f}}, {{0.5f, 0.5f}, {0.0f, 1.0f, 0.0f}}, {{-0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}} }; VkBuffer vertex_buffer_ = VK_NULL_HANDLE; VkDeviceMemory vertex_buffer_memory_ = VK_NULL_HANDLE; - uint32_t find_memory_type(uint32_t typeFilter, VkMemoryPropertyFlags properties); + uint32_t find_memory_type(uint32_t typeFilter, VkMemoryPropertyFlags properties) const; void allocate_vertex_buffer(); #pragma endregion @@ -82,10 +82,10 @@ class RenderEngine std::vector in_flight_fences_; #ifdef _DEBUG - VkResult enable_layer_validation(VkDebugUtilsMessengerCreateInfoEXT* create_info); + VkResult enable_layer_validation(const VkDebugUtilsMessengerCreateInfoEXT* create_info); VkDebugUtilsMessengerEXT debug_messenger_; #endif - SwapchainSupportDetails query_swapchain_details(); + SwapchainSupportDetails query_swapchain_details() const; static std::vector get_required_extensions(); static bool is_device_suitable(VkPhysicalDevice device, VkSurfaceKHR surface); @@ -94,7 +94,7 @@ class RenderEngine static VkSurfaceFormatKHR choose_surface_format(const std::vector& surface_formats); static VkPresentModeKHR choose_present_mode(const std::vector& present_modes, VkPresentModeKHR desired_present_mode); static VkExtent2D choose_extent(const VkSurfaceCapabilitiesKHR& capabilities, GLFWwindow* window); - VkShaderModule create_shader_module(const std::string code); + VkShaderModule create_shader_module(const std::string& code) const; void create_instance(); void create_surface(); @@ -109,7 +109,7 @@ class RenderEngine void allocate_command_buffers(); void create_sync_objects(); - void record_command_buffer(VkCommandBuffer command_buffer, uint32_t image_index); + void record_command_buffer(VkCommandBuffer command_buffer, uint32_t image_index) const; void draw_frame(); public: // Can throw the exception @@ -117,5 +117,5 @@ public: ~RenderEngine(); void start(); - void stop_render(); + void stop_render() const; }; \ No newline at end of file From 3fbc8f09c03315f00951aeec362751803c51d049 Mon Sep 17 00:00:00 2001 From: Jiga228 Date: Sat, 4 Oct 2025 18:34:20 +0700 Subject: [PATCH 17/17] Add "copy_memory" --- Core/Core/RenderEngine.cpp | 212 ++++++++++++++++++++++++++++++------- Core/Core/RenderEngine.h | 7 +- 2 files changed, 178 insertions(+), 41 deletions(-) diff --git a/Core/Core/RenderEngine.cpp b/Core/Core/RenderEngine.cpp index ed2cc7a..d4c4d5c 100644 --- a/Core/Core/RenderEngine.cpp +++ b/Core/Core/RenderEngine.cpp @@ -66,12 +66,6 @@ std::vector RenderEngine::get_required_extensions() return extensions; } - -bool RenderEngine::QueueFamilyIndices::is_complete() const -{ - return graphics_family.has_value() && present_family.has_value(); -} - VkVertexInputBindingDescription RenderEngine::Vertex::get_binding_description() { VkVertexInputBindingDescription description; @@ -103,9 +97,13 @@ bool RenderEngine::is_device_suitable(VkPhysicalDevice device, VkSurfaceKHR surf vkGetPhysicalDeviceProperties(device, &device_properties); vkGetPhysicalDeviceFeatures(device, &device_features); - QueueFamilyIndices indices = find_queue_family_indices(device, surface); + try { + QueueFamilyIndices indices = find_queue_family_indices(device, surface); + } catch (...) { + return false; + } - return indices.is_complete() && check_device_extensions_support(device); + return check_device_extensions_support(device); } bool RenderEngine::check_device_extensions_support(VkPhysicalDevice device) @@ -141,19 +139,50 @@ RenderEngine::QueueFamilyIndices RenderEngine::find_queue_family_indices(VkPhysi std::vector family_properties(queueFamilyCount); vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queueFamilyCount, family_properties.data()); - for (uint32_t i = 0; i < family_properties.size(); ++i) + // Find graphics + for(uint32_t i = 0; i < family_properties.size(); ++i) { if (family_properties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) + { queue_family_indices.graphics_family = i; - - VkBool32 present_support = false; - VK_CHECK(vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, i, surface, &present_support)); - if (present_support) - queue_family_indices.present_family = i; - if(queue_family_indices.is_complete()) break; + } } + if (queue_family_indices.graphics_family.has_value() == false) + throw std::runtime_error("Failed to find a graphics queue family"); + + // Find present + VkBool32 present_support = false; + VK_CHECK(vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, queue_family_indices.graphics_family.value(), surface, &present_support)); + if (present_support == VK_TRUE) + queue_family_indices.present_family = queue_family_indices.graphics_family; + else + { + for(uint32_t i = 0; i < family_properties.size(); ++i) + { + present_support = false; + VK_CHECK(vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, i, surface, &present_support)); + if (present_support == VK_TRUE) + { + queue_family_indices.present_family = i; + break; + } + } + } + + if (queue_family_indices.present_family.has_value() == false) + throw std::runtime_error("Failed to find a present queue family"); + + for(uint32_t i = 0; i < family_properties.size(); ++i) + { + if (i == queue_family_indices.graphics_family.value()) + continue; + if (family_properties[i].queueFlags & VK_QUEUE_TRANSFER_BIT) + queue_family_indices.transfer_family = i; + } + if (queue_family_indices.transfer_family.has_value() == false) + queue_family_indices.transfer_family = queue_family_indices.graphics_family; return queue_family_indices; } @@ -206,6 +235,43 @@ VkShaderModule RenderEngine::create_shader_module(const std::string& code) const return shader_module; } +void RenderEngine::create_buffer(VkDeviceSize size, VkBufferUsageFlags usage, + VkBuffer* buffer, const std::vector& queue_families) +{ + VkBufferCreateInfo buffer_info{}; + buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + buffer_info.size = size; + buffer_info.usage = usage; + + if (queue_families.size() > 1) + { + buffer_info.sharingMode = VK_SHARING_MODE_CONCURRENT; + buffer_info.queueFamilyIndexCount = static_cast(queue_families.size()); + buffer_info.pQueueFamilyIndices = queue_families.data(); + } + else + { + buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + buffer_info.queueFamilyIndexCount = 0; + buffer_info.pQueueFamilyIndices = nullptr; + } + + VK_CHECK(vkCreateBuffer(device_, &buffer_info, nullptr, buffer)); +} + +void RenderEngine::allocate_memory(VkBuffer buffer, VkMemoryPropertyFlags property, VkDeviceMemory* device_memory) +{ + VkMemoryRequirements requirements{}; + vkGetBufferMemoryRequirements(device_, buffer, &requirements); + + VkMemoryAllocateInfo allocate_info{}; + allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocate_info.allocationSize = requirements.size; + allocate_info.memoryTypeIndex = find_memory_type(requirements.memoryTypeBits, property); + + VK_CHECK(vkAllocateMemory(device_, &allocate_info, nullptr, device_memory)); +} + void RenderEngine::create_instance() { std::vector extensions = get_required_extensions(); @@ -274,7 +340,9 @@ void RenderEngine::create_logical_device() VkPhysicalDeviceFeatures device_features{}; std::vector queue_create_infos; - std::set unique_queue_families = {indices.graphics_family.value(), indices.present_family.value()}; + std::set unique_queue_families = {indices.graphics_family.value(), + indices.present_family.value(), + indices.transfer_family.value()}; float queue_priority = 1.0f; VkDeviceQueueCreateInfo device_queue_create_info{}; @@ -309,6 +377,7 @@ void RenderEngine::create_logical_device() VK_CHECK(vkCreateDevice(physical_device_, &device_create_info, nullptr, &device_)); vkGetDeviceQueue(device_, indices.graphics_family.value(), 0, &graphics_queue_); vkGetDeviceQueue(device_, indices.present_family.value(), 0, &present_queue_); + vkGetDeviceQueue(device_, indices.transfer_family.value(), 0, &transfer_queue_); } void RenderEngine::create_swapchain(VkPresentModeKHR desired_present_mode) @@ -338,12 +407,20 @@ void RenderEngine::create_swapchain(VkPresentModeKHR desired_present_mode) swapchain_create_info.oldSwapchain = VK_NULL_HANDLE; QueueFamilyIndices family_indices = find_queue_family_indices(physical_device_, surface_); - uint32_t queue_family_indices[] = {family_indices.graphics_family.value(), family_indices.present_family.value()}; - if (family_indices.graphics_family != family_indices.present_family) + const std::set queue_family_indices = { family_indices.graphics_family.value(), + family_indices.present_family.value(), + family_indices.transfer_family.value() }; + std::vector arr_families; + if (queue_family_indices.size() > 1) { + arr_families.reserve(queue_family_indices.size()); + for(auto& i : queue_family_indices) + arr_families.push_back(i); + + swapchain_create_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT; - swapchain_create_info.queueFamilyIndexCount = 2; - swapchain_create_info.pQueueFamilyIndices = queue_family_indices; + swapchain_create_info.queueFamilyIndexCount = static_cast(arr_families.size()); + swapchain_create_info.pQueueFamilyIndices = arr_families.data(); } else { @@ -614,29 +691,84 @@ uint32_t RenderEngine::find_memory_type(uint32_t typeFilter, VkMemoryPropertyFla void RenderEngine::allocate_vertex_buffer() { - VkBufferCreateInfo buffer_info{}; - buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - buffer_info.size = sizeof(vertices[0]) * vertices.size(); - buffer_info.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; - buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + QueueFamilyIndices indices = find_queue_family_indices(physical_device_, surface_); + std::set set_indices = {indices.graphics_family.value(), + indices.present_family.value(), + indices.transfer_family.value()}; + std::vector arr_indices; + std::vector transfer_index = {indices.transfer_family.value()}; + arr_indices.reserve(set_indices.size()); + for (auto& i : set_indices) + arr_indices.push_back(i); - VK_CHECK(vkCreateBuffer(device_, &buffer_info, nullptr, &vertex_buffer_)); - - VkMemoryRequirements requirements{}; - vkGetBufferMemoryRequirements(device_, vertex_buffer_, &requirements); - - VkMemoryAllocateInfo allocate_info{}; - allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - allocate_info.allocationSize = requirements.size; - allocate_info.memoryTypeIndex = find_memory_type(requirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - - VK_CHECK(vkAllocateMemory(device_, &allocate_info, nullptr, &vertex_buffer_memory_)); + + VkBuffer staging_buffer = VK_NULL_HANDLE; + VkDeviceMemory staging_buffer_memory = VK_NULL_HANDLE; + + VkDeviceSize size_buffer = sizeof(vertices[0]) * vertices.size(); + create_buffer(size_buffer, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, &staging_buffer, transfer_index); + allocate_memory(staging_buffer, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &staging_buffer_memory); + + create_buffer(size_buffer, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, &vertex_buffer_, arr_indices); + allocate_memory(vertex_buffer_, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &vertex_buffer_memory_); + + VK_CHECK(vkBindBufferMemory(device_, staging_buffer, staging_buffer_memory, 0)); VK_CHECK(vkBindBufferMemory(device_, vertex_buffer_, vertex_buffer_memory_, 0)); void* data; - VK_CHECK(vkMapMemory(device_, vertex_buffer_memory_, 0, buffer_info.size, 0, &data)); - memcpy(data, vertices.data(), buffer_info.size); - vkUnmapMemory(device_, vertex_buffer_memory_); + VK_CHECK(vkMapMemory(device_, staging_buffer_memory, 0, size_buffer, 0, &data)); + memcpy(data, vertices.data(), size_buffer); + vkUnmapMemory(device_, staging_buffer_memory); + + copy_memory(staging_buffer, vertex_buffer_, size_buffer); + + vkFreeMemory(device_, staging_buffer_memory, nullptr); + vkDestroyBuffer(device_, staging_buffer, nullptr); +} + +void RenderEngine::copy_memory(VkBuffer src, VkBuffer dst, VkDeviceSize size) +{ + QueueFamilyIndices indices = find_queue_family_indices(physical_device_, surface_); + VkCommandPool copy_pool; + VkCommandPoolCreateInfo copy_pool_info{}; + copy_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + copy_pool_info.queueFamilyIndex = indices.transfer_family.value(); + copy_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + VK_CHECK(vkCreateCommandPool(device_, ©_pool_info, nullptr, ©_pool)); + + VkCommandBufferAllocateInfo command_buffer_allocate_info{}; + command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + command_buffer_allocate_info.commandPool = copy_pool; + command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + command_buffer_allocate_info.commandBufferCount = 1; + + VkCommandBuffer copy_buffer; + VK_CHECK(vkAllocateCommandBuffers(device_, &command_buffer_allocate_info, ©_buffer)); + + VkCommandBufferBeginInfo command_buffer_begin_info{}; + command_buffer_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + command_buffer_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + + VK_CHECK(vkBeginCommandBuffer(copy_buffer, &command_buffer_begin_info)); + + VkBufferCopy buffer_copy{}; + buffer_copy.srcOffset = 0; + buffer_copy.dstOffset = 0; + buffer_copy.size = size; + vkCmdCopyBuffer(copy_buffer, src, dst, 1, &buffer_copy); + + vkEndCommandBuffer(copy_buffer); + + VkSubmitInfo submit_info{}; + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = ©_buffer; + + vkQueueSubmit(transfer_queue_, 1, &submit_info, VK_NULL_HANDLE); + vkQueueWaitIdle(transfer_queue_); + + vkFreeCommandBuffers(device_, copy_pool, 1, ©_buffer); + vkDestroyCommandPool(device_, copy_pool, nullptr); } void RenderEngine::allocate_command_buffers() @@ -784,7 +916,7 @@ window_(window) RenderEngine::~RenderEngine() { vkDeviceWaitIdle(device_); - + if (vertex_buffer_memory_ != VK_NULL_HANDLE) vkFreeMemory(device_, vertex_buffer_memory_, nullptr); diff --git a/Core/Core/RenderEngine.h b/Core/Core/RenderEngine.h index b2b808c..cdef903 100644 --- a/Core/Core/RenderEngine.h +++ b/Core/Core/RenderEngine.h @@ -26,7 +26,7 @@ class RenderEngine { std::optional graphics_family; std::optional present_family; - bool is_complete() const; + std::optional transfer_family; }; struct SwapchainSupportDetails { @@ -52,6 +52,7 @@ class RenderEngine VkDeviceMemory vertex_buffer_memory_ = VK_NULL_HANDLE; uint32_t find_memory_type(uint32_t typeFilter, VkMemoryPropertyFlags properties) const; void allocate_vertex_buffer(); + void copy_memory(VkBuffer src, VkBuffer dst, VkDeviceSize size); #pragma endregion static const std::vector deviceExtensions; @@ -66,6 +67,7 @@ class RenderEngine VkDevice device_ = VK_NULL_HANDLE; VkQueue graphics_queue_ = VK_NULL_HANDLE; VkQueue present_queue_ = VK_NULL_HANDLE; + VkQueue transfer_queue_ = VK_NULL_HANDLE; VkSwapchainKHR swapchain_ = VK_NULL_HANDLE; std::vector swapchain_images_; VkFormat swapchain_image_format_; @@ -95,6 +97,9 @@ class RenderEngine static VkPresentModeKHR choose_present_mode(const std::vector& present_modes, VkPresentModeKHR desired_present_mode); static VkExtent2D choose_extent(const VkSurfaceCapabilitiesKHR& capabilities, GLFWwindow* window); VkShaderModule create_shader_module(const std::string& code) const; + void create_buffer(VkDeviceSize size, VkBufferUsageFlags usage, + VkBuffer* buffer, const std::vector& queue_families); + void allocate_memory(VkBuffer buffer, VkMemoryPropertyFlags property, VkDeviceMemory* device_memory); void create_instance(); void create_surface();