From 9a20f0b3db5648e7378e0887d4ba4510c2462f92 Mon Sep 17 00:00:00 2001 From: HappyTanuki Date: Mon, 26 May 2025 19:36:50 +0900 Subject: [PATCH] initial commit --- Client/include/asset/object/material.h | 1 - Client/include/precomp.h | 26 ++++++++ Client/include/utils/thread_pool.h | 78 ++++++++++++++++++++++++ Client/include/vulkan/engine.h | 6 +- Client/include/vulkan/physics.h | 3 +- Client/src/main.cpp | 11 ++++ Client/src/utils/thread_pool.cpp | 82 ++++++++++++++++++++++++++ Client/src/vulkan/engine.cpp | 19 ++---- Client/src/vulkan/physics.cpp | 19 ++++-- 9 files changed, 224 insertions(+), 21 deletions(-) create mode 100644 Client/include/utils/thread_pool.h create mode 100644 Client/src/utils/thread_pool.cpp diff --git a/Client/include/asset/object/material.h b/Client/include/asset/object/material.h index 2fdfbbc..6149499 100644 --- a/Client/include/asset/object/material.h +++ b/Client/include/asset/object/material.h @@ -5,6 +5,5 @@ namespace veng { struct Material { TextureHandle texture_handle; - std::vector texture_image; }; } // namespace veng diff --git a/Client/include/precomp.h b/Client/include/precomp.h index 6104642..2e82590 100644 --- a/Client/include/precomp.h +++ b/Client/include/precomp.h @@ -9,8 +9,34 @@ #include #include #include +#include +#include #include "spdlog/spdlog.h" #include "utilities.h" +#ifdef _WIN32 +#define NOMINMAX +#include +#include +#include +#include +#include +#define in_addr_t ULONG +#elif __linux__ +#include +#include +#include +#include +#include +#include +#include +#include +#define SOCKET int +#define INVALID_SOCKET -1 +#define SOCKET_ERROR -1 +#else +#error "이 플랫폼은 지원되지 않습니다." +#endif + #define MAX_BUFFERED_FRAMES (2) diff --git a/Client/include/utils/thread_pool.h b/Client/include/utils/thread_pool.h new file mode 100644 index 0000000..44e4bb0 --- /dev/null +++ b/Client/include/utils/thread_pool.h @@ -0,0 +1,78 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include + +namespace utils { + +class ThreadPool { + public: + ThreadPool(); + ThreadPool(std::uint32_t numThreads); + ~ThreadPool(); + + void init(std::uint32_t numThreads); + void terminate(); + + void respawnWorker(std::uint32_t numThreads); + + template + requires( + !std::is_void_v>) + int enqueueJob(_Callable&& __job, + std::invoke_result_t<_Callable, _Args...>& retVal, + _Args&&... __args) { + if (terminate_) { + spdlog::error("Cannot run jobs on threads that terminating..."); + return -1; + } + + std::lock_guard lock(jobQueueMutex); + auto boundFunc = [this, &retVal, __job, + ... __args = std::move(__args)]() mutable { + retVal = __job(this, std::move(__args)...); + }; + auto task = std::packaged_task(std::move(boundFunc)); + jobs_.push(std::move(task)); + jobQueueCV_.notify_one(); + + return 0; + } + template + requires std::is_void_v< + std::invoke_result_t<_Callable, ThreadPool*, _Args...>> + int enqueueJob(_Callable&& __job, _Args&&... __args) { + if (terminate_) { + spdlog::error("Cannot run jobs on threads that terminating..."); + return -1; + } + + std::lock_guard lock(jobQueueMutex); + auto boundFunc = [this, __job, ... __args = std::move(__args)]() mutable { + __job(this, std::move(__args)...); + }; + auto task = std::packaged_task(std::move(boundFunc)); + jobs_.push(std::move(task)); + jobQueueCV_.notify_one(); + + return 0; + } + + int threadCount = 0; + + private: + void* Worker(); + + std::condition_variable jobQueueCV_; + std::mutex jobQueueMutex; + std::queue> jobs_; + std::vector workers_; + bool terminate_ = false; +}; + +} // namespace Chattr diff --git a/Client/include/vulkan/engine.h b/Client/include/vulkan/engine.h index c22bd87..7b9902e 100644 --- a/Client/include/vulkan/engine.h +++ b/Client/include/vulkan/engine.h @@ -1,8 +1,9 @@ #pragma once #include "asset/loader.h" -#include "physics.h" #include "graphics.h" +#include "physics.h" +#include "utils/thread_pool.h" namespace veng { @@ -34,10 +35,11 @@ class Engine { glm::perspective(glm::radians(103.f), 800.f / 600.f, 0.1f, 1000.f); gsl::not_null vulkan_graphics; + private: Loader asset_loader_; - Physics physics_controller_; + utils::ThreadPool thread_pool_; glm::ivec2 window_size_ = {0, 0}; std::double_t last_frame_time_ = 0.0; diff --git a/Client/include/vulkan/physics.h b/Client/include/vulkan/physics.h index 24906e8..3506cc4 100644 --- a/Client/include/vulkan/physics.h +++ b/Client/include/vulkan/physics.h @@ -2,11 +2,12 @@ #include "asset/object/model.h" #include "vulkan/vertex.h" +#include "utils/thread_pool.h" namespace veng { class Physics { public: - void invokeOnColisionEvent(gsl::span models); + void invokeOnColisionEvent(gsl::not_null thread_pool, gsl::span models); bool RayTrace(const glm::vec3& rayOrigin, const glm::vec3& rayDir, const glm::vec3& v0, const glm::vec3& v1, const glm::vec3& v2, diff --git a/Client/src/main.cpp b/Client/src/main.cpp index 27402f2..7411e58 100644 --- a/Client/src/main.cpp +++ b/Client/src/main.cpp @@ -18,6 +18,17 @@ void BeginPlay(veng::Engine& engine) { veng::Model* const player = engine.SpawnModel("player", "player"); player->scale = glm::vec3(.02f); player->colision = true; + player->OnColision = [](veng::Model* self, veng::Model* other) { + if (other->owner == self) return; + std::cout << self << " and " << other << " is Nearby." << std::endl; + + std::cout << self << "'s owner: " << self->owner << std::endl; + std::cout << other << "'s owner: " << other->owner << std::endl; + + std::cout << "Colided." << std::endl; + other->colision = false; + other->visible = false; + }; veng::Model* const player_flame = engine.SpawnModel("player_flame", "player_flame"); player_flame->scale = player->scale; diff --git a/Client/src/utils/thread_pool.cpp b/Client/src/utils/thread_pool.cpp new file mode 100644 index 0000000..9a98004 --- /dev/null +++ b/Client/src/utils/thread_pool.cpp @@ -0,0 +1,82 @@ +#include "utils/thread_pool.h" +#include "precomp.h" + +namespace utils { + +ThreadPool::ThreadPool() : ThreadPool(0) {} + +ThreadPool::ThreadPool(std::uint32_t numThreads) { init(numThreads); } + +ThreadPool::~ThreadPool() { terminate(); } + +void ThreadPool::init(std::uint32_t numThreads) { + int numCPU = numThreads; + if (numThreads == 0) { +#ifdef _WIN32 + SYSTEM_INFO sysinfo; + GetSystemInfo(&sysinfo); + numCPU = sysinfo.dwNumberOfProcessors; +#elif __linux__ + numCPU = sysconf(_SC_NPROCESSORS_ONLN); +#endif + spdlog::info("Auto-detected cpu count: {}", numCPU); + if (numCPU == 1 || numCPU == 2) { + numCPU = 4; + spdlog::info( + "Set ThreadPool Worker count to: {} due to program to oprate " + "concurrently", + numCPU); + } else { + spdlog::info("Set ThreadPool Worker count to: {}", numCPU); + } + } + threadCount = numCPU; + workers_.reserve(numCPU); + + while (numCPU--) workers_.emplace_back([this]() { this->Worker(); }); +} + +void ThreadPool::terminate() { + terminate_ = true; + jobQueueCV_.notify_all(); + + spdlog::debug("waiting for threads to end their jobs..."); + for (auto& t : workers_) t.join(); +} + +void ThreadPool::respawnWorker(std::uint32_t numThreads) { + terminate(); + terminate_ = false; + init(numThreads); +} + +void* ThreadPool::Worker() { +#ifdef _WIN32 + DWORD pid = GetCurrentThreadId(); +#elif __linux__ + pthread_t pid = pthread_self(); +#endif + spdlog::trace("ThreadPool Worker : {} up", pid); + while (!terminate_) { + std::unique_lock lock(jobQueueMutex); + jobQueueCV_.wait(lock, + [this]() { return !this->jobs_.empty() || terminate_; }); + if (this->jobs_.empty() || terminate_) { + jobs_ = std::queue>(); + break; + } + if (this->jobs_.empty()) continue; + + auto job = std::move(jobs_.front()); + jobs_.pop(); + lock.unlock(); + + spdlog::trace("ThreadPool Worker : {} Executing a job", pid); + job(); + } + spdlog::trace("ThreadPool Worker : {} down", pid); + + return nullptr; +} + +} // namespace Chattr diff --git a/Client/src/vulkan/engine.cpp b/Client/src/vulkan/engine.cpp index bc08521..bdfcde6 100644 --- a/Client/src/vulkan/engine.cpp +++ b/Client/src/vulkan/engine.cpp @@ -14,17 +14,6 @@ void Engine::init() { 1000.f); vulkan_graphics->SetViewProjection(view, projection); - for (auto it = model_assets_.begin(); it != model_assets_.end();) { - it->second.vertex_buffer = - vulkan_graphics->CreateVertexBuffer(it->second.vertices); - it->second.index_buffer = - vulkan_graphics->CreateIndexBuffer(it->second.indices); - it->second.material.texture_handle = - vulkan_graphics->CreateTexture(it->second.material.texture_image); - - ++it; - } - if (BeginPlay != nullptr) BeginPlay(*this); } @@ -32,7 +21,11 @@ void Engine::LoadModelAsset(std::string path, std::string name) { veng::Model model(vulkan_graphics); asset_loader_.setPath(path); asset_loader_.loadModel(model); - model.material.texture_image = asset_loader_.readTexture(); + + model.vertex_buffer = vulkan_graphics->CreateVertexBuffer(model.vertices); + model.index_buffer = vulkan_graphics->CreateIndexBuffer(model.indices); + model.material.texture_handle = + vulkan_graphics->CreateTexture(asset_loader_.readTexture()); model_assets_[name] = std::move(model); } @@ -175,7 +168,7 @@ void Engine::Update() { vulkan_graphics->RenderModel(it); } - physics_controller_.invokeOnColisionEvent({models.data(), models.size()}); + physics_controller_.invokeOnColisionEvent(&thread_pool_, {models.data(), models.size()}); vulkan_graphics->EndFrame(); } diff --git a/Client/src/vulkan/physics.cpp b/Client/src/vulkan/physics.cpp index 8376c38..533a1c0 100644 --- a/Client/src/vulkan/physics.cpp +++ b/Client/src/vulkan/physics.cpp @@ -6,8 +6,9 @@ #include "precomp.h" namespace veng { -void Physics::invokeOnColisionEvent(gsl::span models) { - const std::float_t EPSILON = std::numeric_limits::epsilon(); +void Physics::invokeOnColisionEvent( + gsl::not_null thread_pool, gsl::span models) { + constexpr std::float_t EPSILON = std::numeric_limits::epsilon(); for (int first = 0; first < models.size(); first++) { if (!models[first]->colision) continue; @@ -21,9 +22,19 @@ void Physics::invokeOnColisionEvent(gsl::span models) { models[second]->radius * models[second]->scale.x; if (distance <= model1_radius + model2_radius) { if (models[first]->OnColision != nullptr) - models[first]->OnColision(models[first], models[second]); + thread_pool->enqueueJob( + [OnColision = models[first]->OnColision]( + utils::ThreadPool* thread_pool, Model* self, Model* other) { + OnColision(self, other); + }, + models[first], models[second]); if (models[second]->OnColision != nullptr) - models[second]->OnColision(models[second], models[first]); + thread_pool->enqueueJob( + [OnColision = models[second]->OnColision]( + utils::ThreadPool* thread_pool, Model* self, Model* other) { + OnColision(self, other); + }, + models[second], models[first]); break; } }