diff --git a/Engine/CMakeLists.txt b/Engine/CMakeLists.txt index dc10984..b2e144a 100644 --- a/Engine/CMakeLists.txt +++ b/Engine/CMakeLists.txt @@ -28,7 +28,11 @@ add_library(ProjectDelta SHARED "src/delta/core/FrameAllocator.h" "src/delta/core/FrameAllocator.cpp" "src/delta/internal_definitions.h" - "src/delta/core/FreeListAllocator.h" "src/delta/core/FreeListAllocator.cpp") + "src/delta/core/FreeListAllocator.h" + "src/delta/core/FreeListAllocator.cpp" + "src/delta/core/GameWorker.h" + "src/delta/core/GameWorker.cpp" +) target_compile_definitions(ProjectDelta PRIVATE DLT_EXPORT_SYMBOLS diff --git a/Engine/src/delta/core/GameWorker.cpp b/Engine/src/delta/core/GameWorker.cpp new file mode 100644 index 0000000..463e8b7 --- /dev/null +++ b/Engine/src/delta/core/GameWorker.cpp @@ -0,0 +1,50 @@ +#include "GameWorker.h" + +#include + +using namespace delta::core; +namespace os = delta::platform; + +// static pool for workers +static GameWorker s_workers[MAX_WORKERS]; +static std::atomic s_shutdown; + +static void workerLoop(void* data) +{ + bool shutdown = false; + while (!shutdown) + { + shutdown = s_shutdown.load(std::memory_order_acquire); + } +} + +static DLT_FORCE_INLINE void createWorker(uint32_t ix) noexcept +{ + static constexpr os::ThreadCreationInfo createInfo + { + .entryPoint = workerLoop, + .userData = nullptr, + .coreAffinityMask = 0, + .debugName = "Worker", + }; + + GameWorker& newWorker = s_workers[ix]; + newWorker.threadHandle = os::CreateEngineThread(createInfo); +} + +void delta::core::GameWorker_Init() +{ + memset(s_workers, 0u, sizeof(GameWorker) * MAX_WORKERS); + s_shutdown.store(false, std::memory_order_relaxed); + + for (uint32_t i = 0; i < MAX_WORKERS; i++) + createWorker(i); +} + +void delta::core::GameWorker_Shutdown() +{ + s_shutdown.store(true, std::memory_order_release); + + for (uint32_t i = 0; i < MAX_WORKERS; i++) + os::DestroyEngineThread(s_workers[i].threadHandle); +} diff --git a/Engine/src/delta/core/GameWorker.h b/Engine/src/delta/core/GameWorker.h new file mode 100644 index 0000000..39745a1 --- /dev/null +++ b/Engine/src/delta/core/GameWorker.h @@ -0,0 +1,20 @@ +#pragma once + +// forward def +namespace delta::platform +{ + struct OSThreadHandle; +} + +namespace delta::core +{ + inline constexpr uint32_t MAX_WORKERS = 8u; + + struct GameWorker + { + delta::platform::OSThreadHandle* threadHandle; + }; + + void GameWorker_Init(); + void GameWorker_Shutdown(); +} diff --git a/Engine/src/delta/core/engine.cpp b/Engine/src/delta/core/engine.cpp index df9c1ff..81b1d3e 100644 --- a/Engine/src/delta/core/engine.cpp +++ b/Engine/src/delta/core/engine.cpp @@ -18,16 +18,19 @@ #include #include -#include +#include +#include void delta::Engine::Initialize(Context& context) { context.isRunning = true; delta::platform::Initialize(); delta::core::MemoryManager::InitEngineMemory(); + delta::core::GameWorker_Init(); } void delta::Engine::Shutdown(Context& context) { delta::core::MemoryManager::ShutdownEngineMemory(); + delta::core::GameWorker_Shutdown(); } diff --git a/Engine/src/delta/platform/os_internal.h b/Engine/src/delta/platform/os_internal.h index 09c5ced..96afb0c 100644 --- a/Engine/src/delta/platform/os_internal.h +++ b/Engine/src/delta/platform/os_internal.h @@ -32,4 +32,23 @@ namespace delta::platform void* CommitMemory(void* mem, size_t commitSize); void DecommitMemory(void* mem, size_t decommitSize); void ReleaseMemory(void* mem); + + struct OSThreadHandle; + struct OSSemaphoreHandle; + + struct ThreadCreationInfo + { + void (*entryPoint)(void*); + void* userData; + uint32_t coreAffinityMask; + const char* debugName; + }; + + OSThreadHandle* CreateEngineThread(const ThreadCreationInfo& info); + void DestroyEngineThread(OSThreadHandle* thread); + void SetThreadAffinity(OSThreadHandle* thread, uint32_t mask); + + OSSemaphoreHandle* CreateEngineSemaphore(uint32_t initialCount); + void WaitOnSemaphore(OSSemaphoreHandle* sem); + void SignalSemaphore(OSSemaphoreHandle* sem, uint32_t count); } diff --git a/Engine/src/delta/platform/os_win32.cpp b/Engine/src/delta/platform/os_win32.cpp index f8cc81b..cec8efd 100644 --- a/Engine/src/delta/platform/os_win32.cpp +++ b/Engine/src/delta/platform/os_win32.cpp @@ -56,6 +56,24 @@ namespace delta::platform } } + struct OSThreadHandle + { + HANDLE handle; + DWORD osThreadId; + }; + + struct OSSemaphoreHandle + { + HANDLE handle; + }; + + static DWORD WINAPI ThreadWindowsEntry(LPVOID param) + { + auto* info = static_cast(param); + info->entryPoint(info->userData); + return 0; + } + inline static void fetchCpuidValues() { int cpuinfo[4]; @@ -136,6 +154,66 @@ namespace delta::platform return status; } + + OSThreadHandle* CreateEngineThread(const ThreadCreationInfo& info) + { + OSThreadHandle* thread = new OSThreadHandle(); // TODO: custom global allocator, or living on the main thread + thread->handle = CreateThread( + nullptr, 0, + ThreadWindowsEntry, + (void*)&info, + 0, + &thread->osThreadId + ); + + assert(thread->handle != 0); + + if (info.debugName) { + // TODO: Convert to wide string + } + + if (info.coreAffinityMask > 0) { + SetThreadAffinityMask(thread->handle, info.coreAffinityMask); + } + + return thread; + } + + void DestroyEngineThread(OSThreadHandle* thread) + { + if (!thread) + return; + + WaitForSingleObject(thread->handle, INFINITE); + CloseHandle(thread->handle); + + delete thread; + } + + void SetThreadAffinity(OSThreadHandle* thread, uint32_t mask) + { + if (!thread) + return; + + SetThreadAffinityMask(thread->handle, mask); + } + + OSSemaphoreHandle* CreateEngineSemaphore(uint32_t initialCount) + { + OSSemaphoreHandle* sem = new OSSemaphoreHandle(); + sem->handle = CreateSemaphoreA(nullptr, initialCount, LONG_MAX, nullptr); + return sem; + } + + void WaitOnSemaphore(OSSemaphoreHandle* sem) + { + WaitForSingleObject(sem->handle, INFINITE); + } + + void SignalSemaphore(OSSemaphoreHandle* sem, uint32_t count) + { + ReleaseSemaphore(sem->handle, count, nullptr); + } } #endif