From c237dfe750e60971366a0a173a82383022160117 Mon Sep 17 00:00:00 2001 From: YasInvolved Date: Thu, 28 May 2026 15:11:15 +0200 Subject: [PATCH 01/32] convenience wrapper --- Engine/src/delta/core/ThreadContext.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Engine/src/delta/core/ThreadContext.h b/Engine/src/delta/core/ThreadContext.h index cc5dc17..572dcc8 100644 --- a/Engine/src/delta/core/ThreadContext.h +++ b/Engine/src/delta/core/ThreadContext.h @@ -20,4 +20,10 @@ namespace delta::core // Engine Arena API void* ThreadArena_Allocate(ThreadArena* arena, size_t size, size_t alignment = 8); void ThreadArena_Reset(ThreadArena* arena); + + template + inline T* ThreadArena_AllocateForType(ThreadArena* arena, size_t alignment = 8) + { + return reinterpret_cast(ThreadArena_Allocate(arena, sizeof(T), alignment); + } } From e7fdd2f4144d73e901dc99c6723f005d3de1d291 Mon Sep 17 00:00:00 2001 From: YasInvolved Date: Thu, 28 May 2026 17:16:22 +0200 Subject: [PATCH 02/32] current thread id getter --- Engine/src/delta/platform/os_internal.h | 3 +++ Engine/src/delta/platform/os_win32.cpp | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/Engine/src/delta/platform/os_internal.h b/Engine/src/delta/platform/os_internal.h index f39bb45..5de835f 100644 --- a/Engine/src/delta/platform/os_internal.h +++ b/Engine/src/delta/platform/os_internal.h @@ -41,4 +41,7 @@ namespace delta::platform int64_t Timer_GetTimestamp(); double Timer_TicksToMilliseconds(const Timer* timer, int64_t startTicks, int64_t endTicks); double Timer_TicksToMicroseconds(const Timer* timer, int64_t startTicks, int64_t endTicks); + + // Thread API + uint32_t Thread_GetCurrentId(); } diff --git a/Engine/src/delta/platform/os_win32.cpp b/Engine/src/delta/platform/os_win32.cpp index fd3984e..86e70d2 100644 --- a/Engine/src/delta/platform/os_win32.cpp +++ b/Engine/src/delta/platform/os_win32.cpp @@ -288,6 +288,11 @@ namespace delta::platform return (static_cast(elapsedTicks) * 1000000.0) / static_cast(internal->freq); } + + uint32_t Thread_GetCurrentId() + { + return GetCurrentThreadId(); + } } #endif From cf0eaecc5f04ac3565b1d1b8421ed684495c4dc7 Mon Sep 17 00:00:00 2001 From: YasInvolved Date: Thu, 28 May 2026 18:15:44 +0200 Subject: [PATCH 03/32] remove logic that shouldn't be in the platform namespace --- Engine/include/delta/platform/os.h | 1 - Engine/src/delta/platform/os_win32.cpp | 5 ----- 2 files changed, 6 deletions(-) diff --git a/Engine/include/delta/platform/os.h b/Engine/include/delta/platform/os.h index 1eae07d..75e1525 100644 --- a/Engine/include/delta/platform/os.h +++ b/Engine/include/delta/platform/os.h @@ -24,7 +24,6 @@ namespace delta::platform uint32_t cpuPhysicalCoreCount; uint32_t cpuLogicalProcessorCount; - uint32_t maxEngineWorkerCount; uint32_t osPageSize; char cpuBrandString[sizeof(int) * 12 + 1]; diff --git a/Engine/src/delta/platform/os_win32.cpp b/Engine/src/delta/platform/os_win32.cpp index 86e70d2..a1a7ca8 100644 --- a/Engine/src/delta/platform/os_win32.cpp +++ b/Engine/src/delta/platform/os_win32.cpp @@ -178,11 +178,6 @@ namespace delta::platform g_osInfo.cpuLogicalProcessorCount = logicalProcessors; g_osInfo.cpuHasSMT = (logicalProcessors > physicalCores); - if (physicalCores > 1) - g_osInfo.maxEngineWorkerCount = physicalCores - 1; - else - g_osInfo.maxEngineWorkerCount = 1; - bool privilegesSet = SetProcessPrivileges(); if (!privilegesSet) std::cout << "[DeltaEngine-Warning] Failed to elevate SE_INC_WORKING_SET_NAME privilege. You may want to run the game as an administrator.\n"; From 7716a74cc480d165b1bd1a91d0b65d6aa53ffa3e Mon Sep 17 00:00:00 2001 From: YasInvolved Date: Thu, 28 May 2026 18:32:27 +0200 Subject: [PATCH 04/32] disable RTTI --- Engine/CMakeLists.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Engine/CMakeLists.txt b/Engine/CMakeLists.txt index 7991388..14df4a5 100644 --- a/Engine/CMakeLists.txt +++ b/Engine/CMakeLists.txt @@ -42,3 +42,9 @@ target_include_directories(ProjectDelta PUBLIC "include" PRIVATE "src" ) + +if (MSVC) + target_compile_options(ProjectDelta PRIVATE /GR-) +else() + target_compile_options(ProjectDelta PRIVATE -fno-rtti) +endif() From de72566c2ee59e401b5dbcaadd10963838e74c7e Mon Sep 17 00:00:00 2001 From: YasInvolved Date: Thu, 28 May 2026 18:32:41 +0200 Subject: [PATCH 05/32] distinguish thread types --- Engine/src/delta/core/EngineTypes.h | 72 +++++++++++++++++++++++- Engine/src/delta/core/MemoryConfig.cpp | 10 ++-- Engine/src/delta/core/MemoryConfig.h | 73 ++++++++++++++----------- Engine/src/delta/core/ThreadContext.cpp | 57 +++++++++++-------- Engine/src/delta/core/ThreadContext.h | 10 ++-- Engine/src/delta/core/engine.cpp | 5 +- Engine/src/delta/pch.h | 2 + 7 files changed, 162 insertions(+), 67 deletions(-) diff --git a/Engine/src/delta/core/EngineTypes.h b/Engine/src/delta/core/EngineTypes.h index f01716e..e3914e3 100644 --- a/Engine/src/delta/core/EngineTypes.h +++ b/Engine/src/delta/core/EngineTypes.h @@ -4,6 +4,8 @@ namespace delta::core { + struct Empty_t{}; + // TODO: revise this structure and its purpose struct ThreadPageCoordinator { @@ -36,6 +38,38 @@ namespace delta::core static inline constexpr size_t FIELD_SIZE = sizeof(task_t) + sizeof(payload_t); }; + enum class ThreadType : uint8_t { MAIN, WORKER }; + + struct alignas(64) GenericExecutionContext + { + // SHARED TRAITS + ThreadType type; + uint32_t threadIx; + uint32_t threadId; + + ThreadPageCoordinator pageCoordinator; + ThreadArena transientArena; + delta::platform::Timer perThreadTimer; + }; + + struct alignas(64) MainExecutionContext + { + // SHARED TRAITS + GenericExecutionContext generic; + + // ROLE TRAITS + // TODO: persistent storage + }; + + struct alignas(64) WorkerExecutionContext + { + GenericExecutionContext generic; + + // ROLE TRAITS + TaskQueue taskQueue; + }; + + // TODO: Remove, obsolete type. struct alignas(64) ThreadExecutionContext { uint32_t threadIx; @@ -53,7 +87,41 @@ namespace delta::core uint8_t hardwarePadding[32]; }; - extern thread_local ThreadExecutionContext* tl_CurrentThreadContext; + // COMPILE TIME CONSTANTS + inline constexpr size_t THREAD_EXECUTION_CONTEXT_STRIDE = std::max(sizeof(MainExecutionContext), sizeof(WorkerExecutionContext)); + inline constexpr size_t THREAD_EXECUTION_CONTEXT_SIZE = (THREAD_EXECUTION_CONTEXT_STRIDE + 63) & ~(63); + + // EXTERN VARIABLES + extern thread_local GenericExecutionContext* tl_CurrentThreadContext; - static_assert((sizeof(ThreadExecutionContext) % 64) == 0); + // INLINE HELPER FUNCTIONS + template + [[nodiscard]] inline TargetType* ThreadContextCast(GenericExecutionContext* ctx) + { + if (!ctx) return nullptr; + + if constexpr (std::is_same_v) + { + if (ctx->type == ThreadType::MAIN) + return reinterpret_cast(ctx); + } + else if constexpr (std::is_same_v) + { + if (ctx->type == ThreadType::WORKER) + return reinterpret_cast(ctx); + } + + assert(false); // CRITICAL: Casting to invalid type + return nullptr; + } + + inline bool IsMainThread() + { + return tl_CurrentThreadContext && tl_CurrentThreadContext->type == ThreadType::MAIN; + } + + inline bool IsWorkerThread() + { + return tl_CurrentThreadContext && tl_CurrentThreadContext->type == ThreadType::WORKER; + } } diff --git a/Engine/src/delta/core/MemoryConfig.cpp b/Engine/src/delta/core/MemoryConfig.cpp index 7d1982e..2b7b074 100644 --- a/Engine/src/delta/core/MemoryConfig.cpp +++ b/Engine/src/delta/core/MemoryConfig.cpp @@ -7,17 +7,19 @@ namespace delta::core { EngineMemoryConfig g_MemoryConfig{}; - void MemoryConfig_Initialize(size_t physicalRamInstalled, size_t pageSize, uint32_t maxEngineWorkers) + void MemoryConfig_Initialize(size_t physicalRamInstalled, size_t pageSize, uint32_t totalThreads) { g_MemoryConfig.totalPhysicalRam = physicalRamInstalled; g_MemoryConfig.maxAllowedPhysical = (physicalRamInstalled / 10) * 7; // 70% of total capacity + // TODO: Change this. "Environment" has changed. // calculate soft baseline (ideal case, no stealing from the global pool) g_MemoryConfig.threadSoftBaseline = MemoryMap::VIRT_ZONE_TA_BASELINE; - size_t totalControlTrackBytes = maxEngineWorkers * (sizeof(ThreadExecutionContext) + MemoryMap::VIRT_ZONE_QUEUE_SIZE); - size_t totalPrivateArenaBytes = maxEngineWorkers * MemoryMap::VIRT_ZONE_BASELINE_SUM; - size_t rawLockBudget = totalControlTrackBytes + totalPrivateArenaBytes; + // formula optimized on paper to limit arithmetic that has to be done + // precompute whats possible to save some runtime + static constexpr size_t PRECOMPUTABLE_CONST = THREAD_EXECUTION_CONTEXT_SIZE + MemoryMap::VIRT_ZONE_TA_BASELINE + MemoryMap::Worker::VIRT_ZONE_BASELINE_SUM; + size_t rawLockBudget = totalThreads * PRECOMPUTABLE_CONST - MemoryMap::Worker::VIRT_ZONE_BASELINE_SUM; g_MemoryConfig.activeLockAllocation = (rawLockBudget + (pageSize - 1)) & ~(pageSize - 1); g_MemoryConfig.globalPoolSize = g_MemoryConfig.maxAllowedPhysical - g_MemoryConfig.activeLockAllocation; diff --git a/Engine/src/delta/core/MemoryConfig.h b/Engine/src/delta/core/MemoryConfig.h index f03f888..75c46de 100644 --- a/Engine/src/delta/core/MemoryConfig.h +++ b/Engine/src/delta/core/MemoryConfig.h @@ -2,42 +2,53 @@ namespace delta::core { - // FUTURE TODO: Make it configurable via compile definitions namespace MemoryMap { + // Generic inline constexpr size_t VIRT_ZONE_SPACE_LENGTH = (1ull << 35); - // COMPONENTS: - // QUEUE - inline constexpr size_t VIRT_ZONE_QUEUE_OFFSET = 0ull; - inline constexpr size_t VIRT_ZONE_QUEUE_SIZE = (1ull << 16); // 64KB - inline constexpr size_t VIRT_ZONE_QUEUE_BASELINE = UINT64_MAX; // No baseline, we commit it all - - // TRANSIENT ARENA - inline constexpr size_t VIRT_ZONE_TA_OFFSET = VIRT_ZONE_QUEUE_OFFSET + VIRT_ZONE_QUEUE_SIZE; + inline constexpr size_t VIRT_ZONE_TA_OFFSET = 0ull; inline constexpr size_t VIRT_ZONE_TA_SIZE = (1ull << 30); // 1GB - inline constexpr size_t VIRT_ZONE_TA_BASELINE = (1ull << 26); // 64MB - - // COMPONENT POOL ARENA - inline constexpr size_t VIRT_ZONE_CPA_OFFSET = VIRT_ZONE_TA_OFFSET + VIRT_ZONE_TA_SIZE; - inline constexpr size_t VIRT_ZONE_CPA_SIZE = (1ull << 33); // 8GB - inline constexpr size_t VIRT_ZONE_CPA_BASELINE = (1ull << 27); // 128MB - - // SCENE ARENA - inline constexpr size_t VIRT_ZONE_SA_OFFSET = VIRT_ZONE_CPA_OFFSET + VIRT_ZONE_CPA_SIZE; - inline constexpr size_t VIRT_ZONE_SA_SIZE = (1ull << 32); // 4GB - inline constexpr size_t VIRT_ZONE_SA_BASELINE = (1ull << 26); // 64MB - - // IO STREAMING SPACE - inline constexpr size_t VIRT_ZONE_IO_OFFSET = VIRT_ZONE_SA_OFFSET + VIRT_ZONE_SA_SIZE; - inline constexpr size_t VIRT_ZONE_IO_SIZE = (1ull << 30); // 1GB (to be reconsidered) - inline constexpr size_t VIRT_ZONE_IO_BASELINE = UINT64_MAX; // No memory commited, thus no baseline - - // BASELINE SUMMARY - inline constexpr size_t VIRT_ZONE_BASELINE_SUM = - VIRT_ZONE_TA_BASELINE + - VIRT_ZONE_CPA_BASELINE + - VIRT_ZONE_SA_BASELINE; + inline constexpr size_t VIRT_ZONE_TA_BASELINE = (1ull << 26); + + namespace Main + { + + } + + namespace Worker + { + // QUEUE + inline constexpr size_t VIRT_ZONE_QUEUE_OFFSET = 0ull; + inline constexpr size_t VIRT_ZONE_QUEUE_SIZE = (1ull << 16); // 64KB + inline constexpr size_t VIRT_ZONE_QUEUE_BASELINE = UINT64_MAX; // No baseline, we commit it all + + // TRANSIENT ARENA + inline constexpr size_t VIRT_ZONE_TA_OFFSET = VIRT_ZONE_QUEUE_OFFSET + VIRT_ZONE_QUEUE_SIZE; + inline constexpr size_t VIRT_ZONE_TA_SIZE = (1ull << 30); // 1GB + inline constexpr size_t VIRT_ZONE_TA_BASELINE = (1ull << 26); // 64MB + + // COMPONENT POOL ARENA + inline constexpr size_t VIRT_ZONE_CPA_OFFSET = VIRT_ZONE_TA_OFFSET + VIRT_ZONE_TA_SIZE; + inline constexpr size_t VIRT_ZONE_CPA_SIZE = (1ull << 33); // 8GB + inline constexpr size_t VIRT_ZONE_CPA_BASELINE = (1ull << 27); // 128MB + + // SCENE ARENA + inline constexpr size_t VIRT_ZONE_SA_OFFSET = VIRT_ZONE_CPA_OFFSET + VIRT_ZONE_CPA_SIZE; + inline constexpr size_t VIRT_ZONE_SA_SIZE = (1ull << 32); // 4GB + inline constexpr size_t VIRT_ZONE_SA_BASELINE = (1ull << 26); // 64MB + + // IO STREAMING SPACE + inline constexpr size_t VIRT_ZONE_IO_OFFSET = VIRT_ZONE_SA_OFFSET + VIRT_ZONE_SA_SIZE; + inline constexpr size_t VIRT_ZONE_IO_SIZE = (1ull << 30); // 1GB (to be reconsidered) + inline constexpr size_t VIRT_ZONE_IO_BASELINE = UINT64_MAX; // No memory commited, thus no baseline + + // BASELINE SUMMARY + inline constexpr size_t VIRT_ZONE_BASELINE_SUM = + VIRT_ZONE_TA_BASELINE + + VIRT_ZONE_CPA_BASELINE + + VIRT_ZONE_SA_BASELINE; + } } struct EngineMemoryConfig diff --git a/Engine/src/delta/core/ThreadContext.cpp b/Engine/src/delta/core/ThreadContext.cpp index f9f3b2b..65212d9 100644 --- a/Engine/src/delta/core/ThreadContext.cpp +++ b/Engine/src/delta/core/ThreadContext.cpp @@ -8,8 +8,8 @@ namespace delta::core { static uint32_t g_ThreadCount = 0; static uint32_t g_WorkerCount = 0; - static ThreadExecutionContext* g_ThreadContexts = nullptr; - thread_local ThreadExecutionContext* tl_CurrentThreadContext = nullptr; + static GenericExecutionContext* g_ThreadContexts = nullptr; + thread_local GenericExecutionContext* tl_CurrentThreadContext = nullptr; DLT_FORCE_INLINE static void InitializePageCoordinator(ThreadPageCoordinator& pageCoord, size_t pageSize, uint8_t* baseAddress) { @@ -50,25 +50,24 @@ namespace delta::core arena.offset = 0; } - void ThreadContext_Initialize(uint32_t workerCount, size_t pageSize) + void ThreadContext_Initialize(uint32_t threadCount, size_t pageSize) { - uint32_t totalThreads = workerCount + 1; // include main thread + g_ThreadCount = threadCount; + g_WorkerCount = threadCount - 1; // assign 32Gb of address space per thread // master pool size is rounded up to page size constexpr size_t ADDR_SLICE_PER_THREAD = (1ull << 35); - size_t contextArraySize = sizeof(ThreadExecutionContext) * totalThreads; + size_t contextArraySize = THREAD_EXECUTION_CONTEXT_SIZE * threadCount; size_t alignedContextArraySize = ALIGN(contextArraySize, pageSize); - size_t masterPoolSize = (ADDR_SLICE_PER_THREAD * totalThreads) + alignedContextArraySize; + size_t masterPoolSize = (ADDR_SLICE_PER_THREAD * threadCount) + alignedContextArraySize; uint8_t* masterPoolBase = reinterpret_cast( delta::platform::Memory_Reserve(masterPoolSize) ); assert(masterPoolBase != nullptr && "Failed to reserve master pool"); - g_ThreadCount = workerCount; - g_WorkerCount = workerCount - 1; - g_ThreadContexts = reinterpret_cast( + g_ThreadContexts = reinterpret_cast( delta::platform::Memory_Commit(masterPoolBase, alignedContextArraySize) ); assert(g_ThreadContexts != nullptr && "Failed to commit thread context array"); @@ -76,21 +75,31 @@ namespace delta::core if (!delta::platform::Memory_Lock(masterPoolBase, alignedContextArraySize)) std::cout << "[DeltaEngine-Warning] Failed to lock memory resource: Master Thread Context Pool\n"; - uint8_t* virtualRunwayCursor = masterPoolBase + alignedContextArraySize; - for (uint32_t i = 0; i < totalThreads; i++) + // pre-initialize generics + uint8_t* runwayCursor = masterPoolBase + alignedContextArraySize; + for (uint32_t i = 0; i < threadCount; i++) { - ThreadExecutionContext& ctx = g_ThreadContexts[i]; - ctx.threadIx = i; - ctx.threadId = 0; // to be set later - - InitializePageCoordinator(ctx.pageCoordinator, pageSize, virtualRunwayCursor); - InitializeQueue(ctx.pageCoordinator, ctx.taskQueue, MemoryMap::VIRT_ZONE_QUEUE_OFFSET, MemoryMap::VIRT_ZONE_QUEUE_SIZE); + GenericExecutionContext& ctx = g_ThreadContexts[i]; + InitializePageCoordinator(ctx.pageCoordinator, pageSize, runwayCursor); InitializeArena(ctx.pageCoordinator, ctx.transientArena, MemoryMap::VIRT_ZONE_TA_OFFSET, MemoryMap::VIRT_ZONE_TA_BASELINE); - InitializeArena(ctx.pageCoordinator, ctx.componentPoolArena, MemoryMap::VIRT_ZONE_CPA_OFFSET, MemoryMap::VIRT_ZONE_CPA_BASELINE); - InitializeArena(ctx.pageCoordinator, ctx.sceneArena, MemoryMap::VIRT_ZONE_SA_OFFSET, MemoryMap::VIRT_ZONE_SA_BASELINE); - delta::platform::Timer_Initialize(&ctx.perThreadTimer); - virtualRunwayCursor += ADDR_SLICE_PER_THREAD; + runwayCursor += MemoryMap::VIRT_ZONE_SPACE_LENGTH; + } + + // Finish initializing main thread context + { + MainExecutionContext& ctx = reinterpret_cast(g_ThreadContexts[0]); + ctx.generic.type = ThreadType::MAIN; + ctx.generic.threadIx = 0; + ctx.generic.threadId = delta::platform::Thread_GetCurrentId(); + } + + for (uint32_t i = 1; i < threadCount; i++) + { + WorkerExecutionContext& ctx = reinterpret_cast(g_ThreadContexts[i]); + ctx.generic.type = ThreadType::WORKER; + ctx.generic.threadIx = i; + ctx.generic.threadId = 0xDEADBEEFu; // Initialized when thread starts } tl_CurrentThreadContext = &g_ThreadContexts[0]; @@ -181,7 +190,8 @@ namespace delta::core for (size_t i = 0; i < length; i++) { size_t targetIx = 1 + (i % g_WorkerCount); - TaskQueue_Push(&g_ThreadContexts[targetIx].taskQueue, tasks[i], payloads[i]); + WorkerExecutionContext& ctx = reinterpret_cast(g_ThreadContexts[targetIx]); + TaskQueue_Push(&ctx.taskQueue, tasks[i], payloads[i]); } } @@ -194,10 +204,11 @@ namespace delta::core while (consecutiveEmptyQueues < g_ThreadCount) { + WorkerExecutionContext& ctx = reinterpret_cast(g_ThreadContexts[workerIx]); task_t task = nullptr; payload_t payload = nullptr; - if (TaskQueue_Steal(&g_ThreadContexts[workerIx].taskQueue, &task, &payload)) + if (TaskQueue_Steal(&ctx.taskQueue, &task, &payload)) { consecutiveEmptyQueues = 0; assert(task && payload); diff --git a/Engine/src/delta/core/ThreadContext.h b/Engine/src/delta/core/ThreadContext.h index 572dcc8..79b95e4 100644 --- a/Engine/src/delta/core/ThreadContext.h +++ b/Engine/src/delta/core/ThreadContext.h @@ -21,9 +21,9 @@ namespace delta::core void* ThreadArena_Allocate(ThreadArena* arena, size_t size, size_t alignment = 8); void ThreadArena_Reset(ThreadArena* arena); - template - inline T* ThreadArena_AllocateForType(ThreadArena* arena, size_t alignment = 8) - { - return reinterpret_cast(ThreadArena_Allocate(arena, sizeof(T), alignment); - } + //template + //inline T* ThreadArena_AllocateForType(ThreadArena* arena, size_t alignment = 8) + //{ + // return reinterpret_cast(ThreadArena_Allocate(arena, sizeof(T), alignment); + //} } diff --git a/Engine/src/delta/core/engine.cpp b/Engine/src/delta/core/engine.cpp index b12fbbe..1302014 100644 --- a/Engine/src/delta/core/engine.cpp +++ b/Engine/src/delta/core/engine.cpp @@ -28,8 +28,9 @@ void delta::Engine::Initialize(Context& context) const auto* osInfo = delta::platform::getOSInfo(); const auto memStatus = delta::platform::getMemoryStatus(); - delta::core::MemoryConfig_Initialize(memStatus.physicalInstalled, osInfo->osPageSize, osInfo->maxEngineWorkerCount); - delta::core::ThreadContext_Initialize(osInfo->maxEngineWorkerCount, osInfo->osPageSize); + uint32_t totalThreads = osInfo->cpuPhysicalCoreCount; + delta::core::MemoryConfig_Initialize(memStatus.physicalInstalled, osInfo->osPageSize, totalThreads); + delta::core::ThreadContext_Initialize(totalThreads, osInfo->osPageSize); } void delta::Engine::Shutdown(Context& context) diff --git a/Engine/src/delta/pch.h b/Engine/src/delta/pch.h index 32f55a2..57c4f95 100644 --- a/Engine/src/delta/pch.h +++ b/Engine/src/delta/pch.h @@ -6,5 +6,7 @@ #include #include #include +#include +#include #include "internal_definitions.h" From 9db854cd6626672b64c36a5a92fe4cba9b7dc758 Mon Sep 17 00:00:00 2001 From: YasInvolved Date: Fri, 29 May 2026 01:06:58 +0200 Subject: [PATCH 06/32] persistent storage on the main thread --- Engine/src/delta/core/EngineTypes.h | 2 +- Engine/src/delta/core/MemoryConfig.cpp | 2 +- Engine/src/delta/core/MemoryConfig.h | 4 ++++ Engine/src/delta/core/ThreadContext.cpp | 2 ++ Engine/src/delta/core/engine.cpp | 5 +++-- 5 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Engine/src/delta/core/EngineTypes.h b/Engine/src/delta/core/EngineTypes.h index e3914e3..facada1 100644 --- a/Engine/src/delta/core/EngineTypes.h +++ b/Engine/src/delta/core/EngineTypes.h @@ -58,7 +58,7 @@ namespace delta::core GenericExecutionContext generic; // ROLE TRAITS - // TODO: persistent storage + ThreadArena persistentStorage; }; struct alignas(64) WorkerExecutionContext diff --git a/Engine/src/delta/core/MemoryConfig.cpp b/Engine/src/delta/core/MemoryConfig.cpp index 2b7b074..c926336 100644 --- a/Engine/src/delta/core/MemoryConfig.cpp +++ b/Engine/src/delta/core/MemoryConfig.cpp @@ -19,7 +19,7 @@ namespace delta::core // formula optimized on paper to limit arithmetic that has to be done // precompute whats possible to save some runtime static constexpr size_t PRECOMPUTABLE_CONST = THREAD_EXECUTION_CONTEXT_SIZE + MemoryMap::VIRT_ZONE_TA_BASELINE + MemoryMap::Worker::VIRT_ZONE_BASELINE_SUM; - size_t rawLockBudget = totalThreads * PRECOMPUTABLE_CONST - MemoryMap::Worker::VIRT_ZONE_BASELINE_SUM; + size_t rawLockBudget = (totalThreads * PRECOMPUTABLE_CONST) + MemoryMap::Main::VIRT_ZONE_BASELINE_SUM - MemoryMap::Worker::VIRT_ZONE_BASELINE_SUM; g_MemoryConfig.activeLockAllocation = (rawLockBudget + (pageSize - 1)) & ~(pageSize - 1); g_MemoryConfig.globalPoolSize = g_MemoryConfig.maxAllowedPhysical - g_MemoryConfig.activeLockAllocation; diff --git a/Engine/src/delta/core/MemoryConfig.h b/Engine/src/delta/core/MemoryConfig.h index 75c46de..6a3b65b 100644 --- a/Engine/src/delta/core/MemoryConfig.h +++ b/Engine/src/delta/core/MemoryConfig.h @@ -13,7 +13,11 @@ namespace delta::core namespace Main { + inline constexpr size_t VIRT_ZONE_PS_OFFSET = VIRT_ZONE_TA_OFFSET + VIRT_ZONE_TA_SIZE; + inline constexpr size_t VIRT_ZONE_PS_SIZE = (1ull << 31); // 2GB + inline constexpr size_t VIRT_ZONE_PS_BASELINE = (1ull << 26); // 64MB + inline constexpr size_t VIRT_ZONE_BASELINE_SUM = VIRT_ZONE_PS_SIZE; } namespace Worker diff --git a/Engine/src/delta/core/ThreadContext.cpp b/Engine/src/delta/core/ThreadContext.cpp index 65212d9..9d91a34 100644 --- a/Engine/src/delta/core/ThreadContext.cpp +++ b/Engine/src/delta/core/ThreadContext.cpp @@ -92,6 +92,8 @@ namespace delta::core ctx.generic.type = ThreadType::MAIN; ctx.generic.threadIx = 0; ctx.generic.threadId = delta::platform::Thread_GetCurrentId(); + + InitializeArena(ctx.generic.pageCoordinator, ctx.persistentStorage, MemoryMap::Main::VIRT_ZONE_PS_OFFSET, MemoryMap::Main::VIRT_ZONE_PS_BASELINE); } for (uint32_t i = 1; i < threadCount; i++) diff --git a/Engine/src/delta/core/engine.cpp b/Engine/src/delta/core/engine.cpp index 1302014..7ce9ca3 100644 --- a/Engine/src/delta/core/engine.cpp +++ b/Engine/src/delta/core/engine.cpp @@ -29,8 +29,9 @@ void delta::Engine::Initialize(Context& context) const auto memStatus = delta::platform::getMemoryStatus(); uint32_t totalThreads = osInfo->cpuPhysicalCoreCount; - delta::core::MemoryConfig_Initialize(memStatus.physicalInstalled, osInfo->osPageSize, totalThreads); - delta::core::ThreadContext_Initialize(totalThreads, osInfo->osPageSize); + uint32_t pageSize = osInfo->osPageSize; + delta::core::MemoryConfig_Initialize(memStatus.physicalInstalled, pageSize, totalThreads); + delta::core::ThreadContext_Initialize(totalThreads, pageSize); } void delta::Engine::Shutdown(Context& context) From 828ae21b7f64f0eb53deb3cf1f3c06ab90637179 Mon Sep 17 00:00:00 2001 From: YasInvolved Date: Fri, 29 May 2026 01:21:35 +0200 Subject: [PATCH 07/32] handle arena overflow --- Engine/src/delta/core/EngineTypes.h | 1 + Engine/src/delta/core/ThreadContext.cpp | 11 +++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Engine/src/delta/core/EngineTypes.h b/Engine/src/delta/core/EngineTypes.h index facada1..e6e8faa 100644 --- a/Engine/src/delta/core/EngineTypes.h +++ b/Engine/src/delta/core/EngineTypes.h @@ -20,6 +20,7 @@ namespace delta::core uint8_t* backingMemory; size_t capacity; size_t offset; + size_t maxCapacity; }; using task_t = void (*)(void*); diff --git a/Engine/src/delta/core/ThreadContext.cpp b/Engine/src/delta/core/ThreadContext.cpp index 9d91a34..ee9bdfa 100644 --- a/Engine/src/delta/core/ThreadContext.cpp +++ b/Engine/src/delta/core/ThreadContext.cpp @@ -37,7 +37,7 @@ namespace delta::core queue.payloads = reinterpret_cast(payloadsArrayPtr); } - DLT_FORCE_INLINE static void InitializeArena(const ThreadPageCoordinator& pageCoord, ThreadArena& arena, size_t offset, size_t baseline) + DLT_FORCE_INLINE static void InitializeArena(const ThreadPageCoordinator& pageCoord, ThreadArena& arena, size_t offset, size_t baseline, size_t maxCapacity) { uint8_t* pTarget = pageCoord.virtualAddressBase + offset; void* res = delta::platform::Memory_Commit(pTarget, baseline); @@ -48,6 +48,7 @@ namespace delta::core arena.backingMemory = pTarget; arena.capacity = baseline; arena.offset = 0; + arena.maxCapacity = maxCapacity; } void ThreadContext_Initialize(uint32_t threadCount, size_t pageSize) @@ -93,7 +94,7 @@ namespace delta::core ctx.generic.threadIx = 0; ctx.generic.threadId = delta::platform::Thread_GetCurrentId(); - InitializeArena(ctx.generic.pageCoordinator, ctx.persistentStorage, MemoryMap::Main::VIRT_ZONE_PS_OFFSET, MemoryMap::Main::VIRT_ZONE_PS_BASELINE); + InitializeArena(ctx.generic.pageCoordinator, ctx.persistentStorage, MemoryMap::Main::VIRT_ZONE_PS_OFFSET, MemoryMap::Main::VIRT_ZONE_PS_BASELINE, MemoryMap::Main::VIRT_ZONE_PS_SIZE); } for (uint32_t i = 1; i < threadCount; i++) @@ -235,6 +236,12 @@ namespace delta::core size_t padding = alignedAddress - currentAddress; size_t totalSpace = padding + size; + if (arena->offset + totalSpace > arena->maxCapacity) + { + // TODO: Handle it better. I don't know how yet, but I will know soon. + assert(false); // arena overflown + } + if (totalSpace > arena->capacity) { // the slow path: assign more pages From 62b4cd84681aa1472f43b8bd2f33845ffe8d5409 Mon Sep 17 00:00:00 2001 From: YasInvolved Date: Fri, 29 May 2026 02:00:55 +0200 Subject: [PATCH 08/32] expose allocation api to the client and fix a bug --- Engine/CMakeLists.txt | 2 +- Engine/include/delta/core/engine.h | 9 +++- Engine/src/delta/core/EngineTypes.h | 10 ++++- Engine/src/delta/core/ThreadContext.cpp | 8 +++- Engine/src/delta/core/engine.cpp | 60 ++++++++++++++++++------- 5 files changed, 68 insertions(+), 21 deletions(-) diff --git a/Engine/CMakeLists.txt b/Engine/CMakeLists.txt index 14df4a5..8aae816 100644 --- a/Engine/CMakeLists.txt +++ b/Engine/CMakeLists.txt @@ -27,7 +27,7 @@ add_library(ProjectDelta SHARED "src/delta/core/ThreadContext.cpp" "src/delta/core/MemoryConfig.h" "src/delta/core/MemoryConfig.cpp" -) + ) target_compile_definitions(ProjectDelta PRIVATE DLT_EXPORT_SYMBOLS diff --git a/Engine/include/delta/core/engine.h b/Engine/include/delta/core/engine.h index 98a1bea..a39f050 100644 --- a/Engine/include/delta/core/engine.h +++ b/Engine/include/delta/core/engine.h @@ -18,6 +18,8 @@ namespace delta::Engine { + enum class AllocationType : uint8_t { TRANSIENT, PERSISTENT }; + struct Context { bool isRunning; @@ -27,6 +29,9 @@ namespace delta::Engine typedef void (*GameUpdateFunc)(Context*); typedef void (*GameShutdownFunc)(Context*); - void DLT_API Initialize(Context& context); - void DLT_API Shutdown(Context& context); + DLT_API void Initialize(Context& context); + DLT_API void Shutdown(Context& context); + + [[nodiscard]] DLT_API void* Allocate(size_t size, AllocationType type, size_t alignment = 8) noexcept; + DLT_API void Free(void* ptr) noexcept; } diff --git a/Engine/src/delta/core/EngineTypes.h b/Engine/src/delta/core/EngineTypes.h index e6e8faa..c1befb0 100644 --- a/Engine/src/delta/core/EngineTypes.h +++ b/Engine/src/delta/core/EngineTypes.h @@ -4,8 +4,6 @@ namespace delta::core { - struct Empty_t{}; - // TODO: revise this structure and its purpose struct ThreadPageCoordinator { @@ -93,6 +91,8 @@ namespace delta::core inline constexpr size_t THREAD_EXECUTION_CONTEXT_SIZE = (THREAD_EXECUTION_CONTEXT_STRIDE + 63) & ~(63); // EXTERN VARIABLES + extern uintptr_t g_MasterSlabStart; + extern uintptr_t g_MasterSlabEnd; extern thread_local GenericExecutionContext* tl_CurrentThreadContext; // INLINE HELPER FUNCTIONS @@ -116,6 +116,12 @@ namespace delta::core return nullptr; } + inline bool IsCustomAllocated(void* ptr) + { + // range scan + return g_MasterSlabStart <= reinterpret_cast(ptr) && reinterpret_cast(ptr) <= g_MasterSlabEnd; + } + inline bool IsMainThread() { return tl_CurrentThreadContext && tl_CurrentThreadContext->type == ThreadType::MAIN; diff --git a/Engine/src/delta/core/ThreadContext.cpp b/Engine/src/delta/core/ThreadContext.cpp index ee9bdfa..a324f16 100644 --- a/Engine/src/delta/core/ThreadContext.cpp +++ b/Engine/src/delta/core/ThreadContext.cpp @@ -6,6 +6,9 @@ namespace delta::core { + uintptr_t g_MasterSlabStart = 0; + uintptr_t g_MasterSlabEnd = 0; + static uint32_t g_ThreadCount = 0; static uint32_t g_WorkerCount = 0; static GenericExecutionContext* g_ThreadContexts = nullptr; @@ -68,6 +71,9 @@ namespace delta::core ); assert(masterPoolBase != nullptr && "Failed to reserve master pool"); + g_MasterSlabStart = reinterpret_cast(masterPoolBase); + g_MasterSlabEnd = g_MasterSlabStart + masterPoolSize; + g_ThreadContexts = reinterpret_cast( delta::platform::Memory_Commit(masterPoolBase, alignedContextArraySize) ); @@ -82,7 +88,7 @@ namespace delta::core { GenericExecutionContext& ctx = g_ThreadContexts[i]; InitializePageCoordinator(ctx.pageCoordinator, pageSize, runwayCursor); - InitializeArena(ctx.pageCoordinator, ctx.transientArena, MemoryMap::VIRT_ZONE_TA_OFFSET, MemoryMap::VIRT_ZONE_TA_BASELINE); + InitializeArena(ctx.pageCoordinator, ctx.transientArena, MemoryMap::VIRT_ZONE_TA_OFFSET, MemoryMap::VIRT_ZONE_TA_BASELINE, MemoryMap::VIRT_ZONE_TA_SIZE); delta::platform::Timer_Initialize(&ctx.perThreadTimer); runwayCursor += MemoryMap::VIRT_ZONE_SPACE_LENGTH; } diff --git a/Engine/src/delta/core/engine.cpp b/Engine/src/delta/core/engine.cpp index 7ce9ca3..75e418d 100644 --- a/Engine/src/delta/core/engine.cpp +++ b/Engine/src/delta/core/engine.cpp @@ -21,21 +21,51 @@ #include #include -void delta::Engine::Initialize(Context& context) +namespace delta::Engine { - context.isRunning = true; - delta::platform::Initialize(); - const auto* osInfo = delta::platform::getOSInfo(); - const auto memStatus = delta::platform::getMemoryStatus(); - - uint32_t totalThreads = osInfo->cpuPhysicalCoreCount; - uint32_t pageSize = osInfo->osPageSize; - delta::core::MemoryConfig_Initialize(memStatus.physicalInstalled, pageSize, totalThreads); - delta::core::ThreadContext_Initialize(totalThreads, pageSize); -} + void Initialize(Context& context) + { + context.isRunning = true; + delta::platform::Initialize(); + const auto* osInfo = delta::platform::getOSInfo(); + const auto memStatus = delta::platform::getMemoryStatus(); -void delta::Engine::Shutdown(Context& context) -{ - delta::core::ThreadContext_Shutdown(); - delta::core::MemoryConfig_Shutdown(); + uint32_t totalThreads = osInfo->cpuPhysicalCoreCount; + uint32_t pageSize = osInfo->osPageSize; + delta::core::MemoryConfig_Initialize(memStatus.physicalInstalled, pageSize, totalThreads); + delta::core::ThreadContext_Initialize(totalThreads, pageSize); + } + + void Shutdown(Context& context) + { + delta::core::ThreadContext_Shutdown(); + delta::core::MemoryConfig_Shutdown(); + } + + [[nodiscard]] void* Allocate(size_t size, AllocationType type, size_t alignment) noexcept + { + if (!core::tl_CurrentThreadContext) + { + return ::malloc(size); + } + + if (type == AllocationType::TRANSIENT) + { + return core::ThreadArena_Allocate(&core::tl_CurrentThreadContext->transientArena, size, alignment); + } + else if (type == AllocationType::PERSISTENT && core::IsMainThread()) + { + core::MainExecutionContext* ctx = reinterpret_cast(core::tl_CurrentThreadContext); + return core::ThreadArena_Allocate(&ctx->persistentStorage, size, alignment); + } + + assert(false); // CRITICAL FAILURE: Workers cannot allocate persistent memory! + return nullptr; + } + + void Free(void* ptr) noexcept + { + if (!core::IsCustomAllocated(ptr)) + ::free(ptr); + } } From a57a7ec50cc6d68f5f172b3870b18a489a3b5624 Mon Sep 17 00:00:00 2001 From: YasInvolved Date: Sat, 30 May 2026 20:50:42 +0200 Subject: [PATCH 09/32] add a concept for execution context types to prevent mistakes and move inline helpers to ThreadContext.h --- Engine/src/delta/core/EngineTypes.h | 62 +++------------------------ Engine/src/delta/core/ThreadContext.h | 43 ++++++++++++++++--- 2 files changed, 44 insertions(+), 61 deletions(-) diff --git a/Engine/src/delta/core/EngineTypes.h b/Engine/src/delta/core/EngineTypes.h index c1befb0..ced4a78 100644 --- a/Engine/src/delta/core/EngineTypes.h +++ b/Engine/src/delta/core/EngineTypes.h @@ -68,67 +68,17 @@ namespace delta::core TaskQueue taskQueue; }; - // TODO: Remove, obsolete type. - struct alignas(64) ThreadExecutionContext - { - uint32_t threadIx; - uint32_t threadId; - - ThreadPageCoordinator pageCoordinator; - TaskQueue taskQueue; - - alignas(64) ThreadArena transientArena; - ThreadArena componentPoolArena; - ThreadArena sceneArena; - - alignas(64) delta::platform::Timer perThreadTimer; - - uint8_t hardwarePadding[32]; - }; + template + concept ExecutionContext = + std::is_same_v, GenericExecutionContext> || + std::is_same_v, MainExecutionContext> || + std::is_same_v, WorkerExecutionContext>; // COMPILE TIME CONSTANTS inline constexpr size_t THREAD_EXECUTION_CONTEXT_STRIDE = std::max(sizeof(MainExecutionContext), sizeof(WorkerExecutionContext)); inline constexpr size_t THREAD_EXECUTION_CONTEXT_SIZE = (THREAD_EXECUTION_CONTEXT_STRIDE + 63) & ~(63); - // EXTERN VARIABLES + // EXTERN VARIABLES & FUNCTIONS extern uintptr_t g_MasterSlabStart; extern uintptr_t g_MasterSlabEnd; - extern thread_local GenericExecutionContext* tl_CurrentThreadContext; - - // INLINE HELPER FUNCTIONS - template - [[nodiscard]] inline TargetType* ThreadContextCast(GenericExecutionContext* ctx) - { - if (!ctx) return nullptr; - - if constexpr (std::is_same_v) - { - if (ctx->type == ThreadType::MAIN) - return reinterpret_cast(ctx); - } - else if constexpr (std::is_same_v) - { - if (ctx->type == ThreadType::WORKER) - return reinterpret_cast(ctx); - } - - assert(false); // CRITICAL: Casting to invalid type - return nullptr; - } - - inline bool IsCustomAllocated(void* ptr) - { - // range scan - return g_MasterSlabStart <= reinterpret_cast(ptr) && reinterpret_cast(ptr) <= g_MasterSlabEnd; - } - - inline bool IsMainThread() - { - return tl_CurrentThreadContext && tl_CurrentThreadContext->type == ThreadType::MAIN; - } - - inline bool IsWorkerThread() - { - return tl_CurrentThreadContext && tl_CurrentThreadContext->type == ThreadType::WORKER; - } } diff --git a/Engine/src/delta/core/ThreadContext.h b/Engine/src/delta/core/ThreadContext.h index 79b95e4..887fd20 100644 --- a/Engine/src/delta/core/ThreadContext.h +++ b/Engine/src/delta/core/ThreadContext.h @@ -21,9 +21,42 @@ namespace delta::core void* ThreadArena_Allocate(ThreadArena* arena, size_t size, size_t alignment = 8); void ThreadArena_Reset(ThreadArena* arena); - //template - //inline T* ThreadArena_AllocateForType(ThreadArena* arena, size_t alignment = 8) - //{ - // return reinterpret_cast(ThreadArena_Allocate(arena, sizeof(T), alignment); - //} + // Inline Helpers + template + [[nodiscard]] inline TargetType* ThreadContextCast(GenericExecutionContext* ctx) + { + if (!ctx) return nullptr; + + if constexpr (std::is_same_v) + { + if (ctx->type == ThreadType::MAIN) + return reinterpret_cast(ctx); + } + else if constexpr (std::is_same_v) + { + if (ctx->type == ThreadType::WORKER) + return reinterpret_cast(ctx); + } + + assert(false); // CRITICAL: Casting to invalid type + return nullptr; + } + + inline bool IsCustomAllocated(void* ptr) + { + // range scan + return g_MasterSlabStart <= reinterpret_cast(ptr) && reinterpret_cast(ptr) <= g_MasterSlabEnd; + } + + inline bool IsMainThread() + { + auto* ctx = ThreadContext_GetCurrent(); + return ctx && ctx->type == ThreadType::MAIN; + } + + inline bool IsWorkerThread() + { + auto* ctx = ThreadContext_GetCurrent(); + return ctx && ctx->type == ThreadType::WORKER; + } } From 9fd3134caef50bf0fec9e157bc3fb29522409fe9 Mon Sep 17 00:00:00 2001 From: YasInvolved Date: Sat, 30 May 2026 20:52:28 +0200 Subject: [PATCH 10/32] make a getter for current thread context --- Engine/src/delta/core/ThreadContext.cpp | 7 ++++++- Engine/src/delta/core/ThreadContext.h | 3 +++ Engine/src/delta/core/engine.cpp | 10 +++++++--- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/Engine/src/delta/core/ThreadContext.cpp b/Engine/src/delta/core/ThreadContext.cpp index a324f16..37baf28 100644 --- a/Engine/src/delta/core/ThreadContext.cpp +++ b/Engine/src/delta/core/ThreadContext.cpp @@ -12,7 +12,7 @@ namespace delta::core static uint32_t g_ThreadCount = 0; static uint32_t g_WorkerCount = 0; static GenericExecutionContext* g_ThreadContexts = nullptr; - thread_local GenericExecutionContext* tl_CurrentThreadContext = nullptr; + static thread_local GenericExecutionContext* tl_CurrentThreadContext = nullptr; DLT_FORCE_INLINE static void InitializePageCoordinator(ThreadPageCoordinator& pageCoord, size_t pageSize, uint8_t* baseAddress) { @@ -119,6 +119,11 @@ namespace delta::core delta::platform::Memory_Release(g_ThreadContexts); } + GenericExecutionContext* ThreadContext_GetCurrent() noexcept + { + return tl_CurrentThreadContext; + } + void TaskQueue_Push(TaskQueue* queue, task_t task, payload_t payload) { uint64_t b = queue->bottom.load(std::memory_order_relaxed); diff --git a/Engine/src/delta/core/ThreadContext.h b/Engine/src/delta/core/ThreadContext.h index 887fd20..613ae10 100644 --- a/Engine/src/delta/core/ThreadContext.h +++ b/Engine/src/delta/core/ThreadContext.h @@ -8,6 +8,9 @@ namespace delta::core void ThreadContext_Initialize(uint32_t workerCount, size_t pageSize); void ThreadContext_Shutdown(); + // Getters + GenericExecutionContext* ThreadContext_GetCurrent() noexcept; + // Thread Task Queue API void TaskQueue_Push(TaskQueue* queue, task_t task, payload_t payload); bool TaskQueue_Pop(TaskQueue* queue, task_t* outTask, payload_t* outPayload); diff --git a/Engine/src/delta/core/engine.cpp b/Engine/src/delta/core/engine.cpp index 75e418d..1fef31e 100644 --- a/Engine/src/delta/core/engine.cpp +++ b/Engine/src/delta/core/engine.cpp @@ -23,6 +23,8 @@ namespace delta::Engine { + using GenericExecutionContext = delta::core::GenericExecutionContext; + void Initialize(Context& context) { context.isRunning = true; @@ -44,18 +46,20 @@ namespace delta::Engine [[nodiscard]] void* Allocate(size_t size, AllocationType type, size_t alignment) noexcept { - if (!core::tl_CurrentThreadContext) + GenericExecutionContext* threadContext = delta::core::ThreadContext_GetCurrent(); + + if (!threadContext) { return ::malloc(size); } if (type == AllocationType::TRANSIENT) { - return core::ThreadArena_Allocate(&core::tl_CurrentThreadContext->transientArena, size, alignment); + return core::ThreadArena_Allocate(&threadContext->transientArena, size, alignment); } else if (type == AllocationType::PERSISTENT && core::IsMainThread()) { - core::MainExecutionContext* ctx = reinterpret_cast(core::tl_CurrentThreadContext); + core::MainExecutionContext* ctx = reinterpret_cast(threadContext); return core::ThreadArena_Allocate(&ctx->persistentStorage, size, alignment); } From 722b35ef4371d388de32bc57bdfeb4d39a5e77e3 Mon Sep 17 00:00:00 2001 From: YasInvolved Date: Sat, 30 May 2026 20:53:38 +0200 Subject: [PATCH 11/32] add new and delete operator overloads --- Engine/include/delta/core/engine.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Engine/include/delta/core/engine.h b/Engine/include/delta/core/engine.h index a39f050..32ab1df 100644 --- a/Engine/include/delta/core/engine.h +++ b/Engine/include/delta/core/engine.h @@ -35,3 +35,13 @@ namespace delta::Engine [[nodiscard]] DLT_API void* Allocate(size_t size, AllocationType type, size_t alignment = 8) noexcept; DLT_API void Free(void* ptr) noexcept; } + +[[nodiscard]] inline void* operator new(size_t size) { return delta::Engine::Allocate(size, delta::Engine::AllocationType::PERSISTENT); } +[[nodiscard]] inline void* operator new(size_t size, delta::Engine::AllocationType type) { return delta::Engine::Allocate(size, type); } +[[nodiscard]] inline void* operator new[](size_t size) { return delta::Engine::Allocate(size, delta::Engine::AllocationType::PERSISTENT); } +[[nodiscard]] inline void* operator new[](size_t size, delta::Engine::AllocationType type) { return delta::Engine::Allocate(size, type); } + +inline void operator delete(void* ptr) { return delta::Engine::Free(ptr); } +inline void operator delete(void* ptr, delta::Engine::AllocationType) { return delta::Engine::Free(ptr); } +inline void operator delete[](void* ptr) { return delta::Engine::Free(ptr); } +inline void operator delete[](void* ptr, delta::Engine::AllocationType) { return delta::Engine::Free(ptr); } From d2296a1fc3b023f79f075c30407ad730a94fee48 Mon Sep 17 00:00:00 2001 From: YasInvolved Date: Sat, 30 May 2026 20:53:51 +0200 Subject: [PATCH 12/32] fix memory aliasing bug --- Engine/src/delta/core/ThreadContext.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/Engine/src/delta/core/ThreadContext.cpp b/Engine/src/delta/core/ThreadContext.cpp index 37baf28..cc875ce 100644 --- a/Engine/src/delta/core/ThreadContext.cpp +++ b/Engine/src/delta/core/ThreadContext.cpp @@ -54,6 +54,12 @@ namespace delta::core arena.maxCapacity = maxCapacity; } + template + DLT_FORCE_INLINE ContextType& GetExecutionContext(size_t i) + { + return reinterpret_cast(*(reinterpret_cast(g_ThreadContexts) + i * THREAD_EXECUTION_CONTEXT_SIZE)); + } + void ThreadContext_Initialize(uint32_t threadCount, size_t pageSize) { g_ThreadCount = threadCount; @@ -86,7 +92,7 @@ namespace delta::core uint8_t* runwayCursor = masterPoolBase + alignedContextArraySize; for (uint32_t i = 0; i < threadCount; i++) { - GenericExecutionContext& ctx = g_ThreadContexts[i]; + GenericExecutionContext& ctx = GetExecutionContext(i); InitializePageCoordinator(ctx.pageCoordinator, pageSize, runwayCursor); InitializeArena(ctx.pageCoordinator, ctx.transientArena, MemoryMap::VIRT_ZONE_TA_OFFSET, MemoryMap::VIRT_ZONE_TA_BASELINE, MemoryMap::VIRT_ZONE_TA_SIZE); delta::platform::Timer_Initialize(&ctx.perThreadTimer); @@ -95,7 +101,7 @@ namespace delta::core // Finish initializing main thread context { - MainExecutionContext& ctx = reinterpret_cast(g_ThreadContexts[0]); + MainExecutionContext& ctx = GetExecutionContext(0); ctx.generic.type = ThreadType::MAIN; ctx.generic.threadIx = 0; ctx.generic.threadId = delta::platform::Thread_GetCurrentId(); @@ -105,7 +111,7 @@ namespace delta::core for (uint32_t i = 1; i < threadCount; i++) { - WorkerExecutionContext& ctx = reinterpret_cast(g_ThreadContexts[i]); + WorkerExecutionContext& ctx = GetExecutionContext(i); ctx.generic.type = ThreadType::WORKER; ctx.generic.threadIx = i; ctx.generic.threadId = 0xDEADBEEFu; // Initialized when thread starts From 3d62d255974f3ef1cda4d92fca1c4e5dd2a8e823 Mon Sep 17 00:00:00 2001 From: YasInvolved Date: Sat, 30 May 2026 21:02:33 +0200 Subject: [PATCH 13/32] cosmetics: add missing license notices --- Engine/src/delta/core/EngineTypes.h | 16 ++++++++++++++++ Engine/src/delta/core/MemoryConfig.cpp | 16 ++++++++++++++++ Engine/src/delta/core/MemoryConfig.h | 16 ++++++++++++++++ Engine/src/delta/core/ThreadContext.cpp | 16 ++++++++++++++++ Engine/src/delta/core/ThreadContext.h | 16 ++++++++++++++++ 5 files changed, 80 insertions(+) diff --git a/Engine/src/delta/core/EngineTypes.h b/Engine/src/delta/core/EngineTypes.h index ced4a78..c08b3f6 100644 --- a/Engine/src/delta/core/EngineTypes.h +++ b/Engine/src/delta/core/EngineTypes.h @@ -1,3 +1,19 @@ +/* + * Copyright 2026 Jakub Bączyk + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #pragma once #include diff --git a/Engine/src/delta/core/MemoryConfig.cpp b/Engine/src/delta/core/MemoryConfig.cpp index c926336..7858fca 100644 --- a/Engine/src/delta/core/MemoryConfig.cpp +++ b/Engine/src/delta/core/MemoryConfig.cpp @@ -1,3 +1,19 @@ +/* + * Copyright 2026 Jakub Bączyk + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #include "MemoryConfig.h" #include "EngineTypes.h" #include diff --git a/Engine/src/delta/core/MemoryConfig.h b/Engine/src/delta/core/MemoryConfig.h index 6a3b65b..2f77080 100644 --- a/Engine/src/delta/core/MemoryConfig.h +++ b/Engine/src/delta/core/MemoryConfig.h @@ -1,3 +1,19 @@ +/* + * Copyright 2026 Jakub Bączyk + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #pragma once namespace delta::core diff --git a/Engine/src/delta/core/ThreadContext.cpp b/Engine/src/delta/core/ThreadContext.cpp index cc875ce..12fd191 100644 --- a/Engine/src/delta/core/ThreadContext.cpp +++ b/Engine/src/delta/core/ThreadContext.cpp @@ -1,3 +1,19 @@ +/* + * Copyright 2026 Jakub Bączyk + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #include #include "ThreadContext.h" #include "MemoryConfig.h" diff --git a/Engine/src/delta/core/ThreadContext.h b/Engine/src/delta/core/ThreadContext.h index 613ae10..21ce537 100644 --- a/Engine/src/delta/core/ThreadContext.h +++ b/Engine/src/delta/core/ThreadContext.h @@ -1,3 +1,19 @@ +/* + * Copyright 2026 Jakub Bączyk + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #pragma once #include "EngineTypes.h" From 7319a340ab012f1c1e8bef708d126dbd49458350 Mon Sep 17 00:00:00 2001 From: YasInvolved Date: Sat, 30 May 2026 21:11:09 +0200 Subject: [PATCH 14/32] move operator overloads to the separate header included in pch --- Engine/CMakeLists.txt | 1 + Engine/include/delta/core/engine.h | 15 --------------- Engine/include/delta/core/memory.h | 21 +++++++++++++++++++++ Engine/include/delta/pch.h | 1 + Engine/src/delta/core/engine.cpp | 1 + 5 files changed, 24 insertions(+), 15 deletions(-) create mode 100644 Engine/include/delta/core/memory.h diff --git a/Engine/CMakeLists.txt b/Engine/CMakeLists.txt index 8aae816..6ed64a6 100644 --- a/Engine/CMakeLists.txt +++ b/Engine/CMakeLists.txt @@ -15,6 +15,7 @@ add_library(ProjectDelta SHARED "src/delta/core/engine.cpp" "include/delta/core/engine.h" + "include/delta/core/memory.h" "include/delta/definitions.h" "src/delta/platform/os_internal.h" "src/delta/platform/os_win32.cpp" diff --git a/Engine/include/delta/core/engine.h b/Engine/include/delta/core/engine.h index 32ab1df..74dccf1 100644 --- a/Engine/include/delta/core/engine.h +++ b/Engine/include/delta/core/engine.h @@ -18,8 +18,6 @@ namespace delta::Engine { - enum class AllocationType : uint8_t { TRANSIENT, PERSISTENT }; - struct Context { bool isRunning; @@ -31,17 +29,4 @@ namespace delta::Engine DLT_API void Initialize(Context& context); DLT_API void Shutdown(Context& context); - - [[nodiscard]] DLT_API void* Allocate(size_t size, AllocationType type, size_t alignment = 8) noexcept; - DLT_API void Free(void* ptr) noexcept; } - -[[nodiscard]] inline void* operator new(size_t size) { return delta::Engine::Allocate(size, delta::Engine::AllocationType::PERSISTENT); } -[[nodiscard]] inline void* operator new(size_t size, delta::Engine::AllocationType type) { return delta::Engine::Allocate(size, type); } -[[nodiscard]] inline void* operator new[](size_t size) { return delta::Engine::Allocate(size, delta::Engine::AllocationType::PERSISTENT); } -[[nodiscard]] inline void* operator new[](size_t size, delta::Engine::AllocationType type) { return delta::Engine::Allocate(size, type); } - -inline void operator delete(void* ptr) { return delta::Engine::Free(ptr); } -inline void operator delete(void* ptr, delta::Engine::AllocationType) { return delta::Engine::Free(ptr); } -inline void operator delete[](void* ptr) { return delta::Engine::Free(ptr); } -inline void operator delete[](void* ptr, delta::Engine::AllocationType) { return delta::Engine::Free(ptr); } diff --git a/Engine/include/delta/core/memory.h b/Engine/include/delta/core/memory.h new file mode 100644 index 0000000..5048291 --- /dev/null +++ b/Engine/include/delta/core/memory.h @@ -0,0 +1,21 @@ +#pragma once + +#include + +namespace delta::Engine +{ + enum class AllocationType : uint8_t { TRANSIENT, PERSISTENT }; + + [[nodiscard]] DLT_API void* Allocate(size_t size, AllocationType type, size_t alignment = 8) noexcept; + DLT_API void Free(void* ptr) noexcept; +} + +[[nodiscard]] inline void* operator new(size_t size) { return delta::Engine::Allocate(size, delta::Engine::AllocationType::PERSISTENT); } +[[nodiscard]] inline void* operator new(size_t size, delta::Engine::AllocationType type) { return delta::Engine::Allocate(size, type); } +[[nodiscard]] inline void* operator new[](size_t size) { return delta::Engine::Allocate(size, delta::Engine::AllocationType::PERSISTENT); } +[[nodiscard]] inline void* operator new[](size_t size, delta::Engine::AllocationType type) { return delta::Engine::Allocate(size, type); } + +inline void operator delete(void* ptr) { return delta::Engine::Free(ptr); } +inline void operator delete(void* ptr, delta::Engine::AllocationType) { return delta::Engine::Free(ptr); } +inline void operator delete[](void* ptr) { return delta::Engine::Free(ptr); } +inline void operator delete[](void* ptr, delta::Engine::AllocationType) { return delta::Engine::Free(ptr); } diff --git a/Engine/include/delta/pch.h b/Engine/include/delta/pch.h index 1f841dc..7141abf 100644 --- a/Engine/include/delta/pch.h +++ b/Engine/include/delta/pch.h @@ -4,3 +4,4 @@ #include #include +#include diff --git a/Engine/src/delta/core/engine.cpp b/Engine/src/delta/core/engine.cpp index 1fef31e..ba8a902 100644 --- a/Engine/src/delta/core/engine.cpp +++ b/Engine/src/delta/core/engine.cpp @@ -15,6 +15,7 @@ */ #include +#include #include #include #include From 73e7ea192ba06a7f5f87f9a8ed55f9fc60f6d4ee Mon Sep 17 00:00:00 2001 From: YasInvolved Date: Sat, 30 May 2026 21:34:26 +0200 Subject: [PATCH 15/32] wrappers for thread creation --- Engine/src/delta/platform/os_internal.h | 13 +++++++ Engine/src/delta/platform/os_win32.cpp | 47 +++++++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/Engine/src/delta/platform/os_internal.h b/Engine/src/delta/platform/os_internal.h index 5de835f..ffd1b42 100644 --- a/Engine/src/delta/platform/os_internal.h +++ b/Engine/src/delta/platform/os_internal.h @@ -21,6 +21,15 @@ namespace delta::platform struct BrandStringCall; struct Timer_Internal; + struct ThreadCreateInfo + { + void (*fn)(void*); + void* args; + }; + + struct Thread; + using ThreadHandle = Thread*; + struct Timer { alignas(8) uint8_t opaqueData[32]; @@ -44,4 +53,8 @@ namespace delta::platform // Thread API uint32_t Thread_GetCurrentId(); + uint32_t Thread_GetId(ThreadHandle thread); + ThreadHandle Thread_Create(ThreadCreateInfo* createInfo); + void Thread_Join(ThreadHandle thread); + void Thread_JoinMultiple(ThreadHandle* threads, uint32_t count); } diff --git a/Engine/src/delta/platform/os_win32.cpp b/Engine/src/delta/platform/os_win32.cpp index a1a7ca8..3d64b11 100644 --- a/Engine/src/delta/platform/os_win32.cpp +++ b/Engine/src/delta/platform/os_win32.cpp @@ -43,6 +43,14 @@ namespace delta::platform int64_t baseStartTime; }; + struct Thread + { + HANDLE hThread; + }; + + static_assert(std::is_standard_layout_v, "PAL layout broken: Must be standard layout!"); + static_assert(sizeof(Thread) == sizeof(HANDLE), "PAL layout broken: Size mismatch!"); + enum CpuArchitecture : WORD { INTEL = 0, @@ -284,10 +292,49 @@ namespace delta::platform return (static_cast(elapsedTicks) * 1000000.0) / static_cast(internal->freq); } + static DWORD WINAPI DeltaThreadProc(LPVOID lParam) + { + ThreadCreateInfo* createInfo = reinterpret_cast(lParam); + createInfo->fn(createInfo->args); + return 0; + } + uint32_t Thread_GetCurrentId() { return GetCurrentThreadId(); } + + uint32_t Thread_GetId(ThreadHandle thread) + { + return GetThreadId(thread->hThread); + } + + ThreadHandle Thread_Create(ThreadCreateInfo* createInfo) + { + ThreadHandle thread = new(delta::Engine::AllocationType::PERSISTENT) ThreadHandle{}; + thread->hThread = CreateThread(nullptr, 0, DeltaThreadProc, (void*)createInfo, 0, 0); + if (thread->hThread == 0) + return nullptr; + + return thread; + } + + void Thread_Join(ThreadHandle thread) + { + if (!thread) + return; + + DWORD waitResult = WaitForSingleObject(thread->hThread, INFINITE); + CloseHandle(thread->hThread); + } + + void Thread_JoinMultiple(ThreadHandle* threads, uint32_t count) + { + if (!threads) + return; + + WaitForMultipleObjects(count, reinterpret_cast(threads), TRUE, INFINITE); + } } #endif From 75f93be2c2f538dc1c7cd66e25fc3fec9f3aa5a5 Mon Sep 17 00:00:00 2001 From: YasInvolved Date: Sat, 30 May 2026 22:36:12 +0200 Subject: [PATCH 16/32] introduce semaphore sync primitive --- Engine/src/delta/platform/os_internal.h | 9 +++++++ Engine/src/delta/platform/os_win32.cpp | 33 +++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/Engine/src/delta/platform/os_internal.h b/Engine/src/delta/platform/os_internal.h index ffd1b42..c8446b6 100644 --- a/Engine/src/delta/platform/os_internal.h +++ b/Engine/src/delta/platform/os_internal.h @@ -30,6 +30,9 @@ namespace delta::platform struct Thread; using ThreadHandle = Thread*; + struct Semaphore; + using SemaphoreHandle = Semaphore*; + struct Timer { alignas(8) uint8_t opaqueData[32]; @@ -57,4 +60,10 @@ namespace delta::platform ThreadHandle Thread_Create(ThreadCreateInfo* createInfo); void Thread_Join(ThreadHandle thread); void Thread_JoinMultiple(ThreadHandle* threads, uint32_t count); + + // Sync API + SemaphoreHandle Sync_CreateSemaphore(); + void Sync_DestroySemaphore(SemaphoreHandle sem); + void Sync_SignalSemaphore(SemaphoreHandle sem); + void Sync_WaitSemaphore(SemaphoreHandle sem); } diff --git a/Engine/src/delta/platform/os_win32.cpp b/Engine/src/delta/platform/os_win32.cpp index 3d64b11..c42bc21 100644 --- a/Engine/src/delta/platform/os_win32.cpp +++ b/Engine/src/delta/platform/os_win32.cpp @@ -48,6 +48,11 @@ namespace delta::platform HANDLE hThread; }; + struct Semaphore + { + HANDLE hSemaphore; + }; + static_assert(std::is_standard_layout_v, "PAL layout broken: Must be standard layout!"); static_assert(sizeof(Thread) == sizeof(HANDLE), "PAL layout broken: Size mismatch!"); @@ -335,6 +340,34 @@ namespace delta::platform WaitForMultipleObjects(count, reinterpret_cast(threads), TRUE, INFINITE); } + + SemaphoreHandle Sync_CreateSemaphore() + { + Semaphore* s = new(delta::Engine::AllocationType::PERSISTENT) Semaphore{}; + s->hSemaphore = CreateSemaphoreA(nullptr, 0, 1000000, nullptr); + if (s->hSemaphore == nullptr) + return nullptr; + + return s; + } + + void Sync_DestroySemaphore(SemaphoreHandle sem) + { + if (!sem) + return; + + CloseHandle(sem->hSemaphore); + } + + void Sync_SignalSemaphore(SemaphoreHandle handle) + { + ReleaseSemaphore(handle->hSemaphore, 1, nullptr); + } + + void Sync_WaitSemaphore(SemaphoreHandle handle) + { + WaitForSingleObject(handle->hSemaphore, INFINITE); + } } #endif From 1d426eee3fc7dd145aac7b44377a5b0fb76c679d Mon Sep 17 00:00:00 2001 From: YasInvolved Date: Sat, 30 May 2026 22:53:36 +0200 Subject: [PATCH 17/32] fix memory config and add a semaphore to the worker context --- Engine/src/delta/core/EngineTypes.h | 3 +++ Engine/src/delta/core/MemoryConfig.h | 2 +- Engine/src/delta/core/ThreadContext.cpp | 4 ++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Engine/src/delta/core/EngineTypes.h b/Engine/src/delta/core/EngineTypes.h index c08b3f6..b677918 100644 --- a/Engine/src/delta/core/EngineTypes.h +++ b/Engine/src/delta/core/EngineTypes.h @@ -82,6 +82,9 @@ namespace delta::core // ROLE TRAITS TaskQueue taskQueue; + delta::platform::SemaphoreHandle sleepSemaphore; + std::atomic isAsleep; + std::atomic shouldClose; }; template diff --git a/Engine/src/delta/core/MemoryConfig.h b/Engine/src/delta/core/MemoryConfig.h index 2f77080..8f98b4c 100644 --- a/Engine/src/delta/core/MemoryConfig.h +++ b/Engine/src/delta/core/MemoryConfig.h @@ -39,7 +39,7 @@ namespace delta::core namespace Worker { // QUEUE - inline constexpr size_t VIRT_ZONE_QUEUE_OFFSET = 0ull; + inline constexpr size_t VIRT_ZONE_QUEUE_OFFSET = VIRT_ZONE_TA_OFFSET + VIRT_ZONE_TA_SIZE; inline constexpr size_t VIRT_ZONE_QUEUE_SIZE = (1ull << 16); // 64KB inline constexpr size_t VIRT_ZONE_QUEUE_BASELINE = UINT64_MAX; // No baseline, we commit it all diff --git a/Engine/src/delta/core/ThreadContext.cpp b/Engine/src/delta/core/ThreadContext.cpp index 12fd191..6f2e7cf 100644 --- a/Engine/src/delta/core/ThreadContext.cpp +++ b/Engine/src/delta/core/ThreadContext.cpp @@ -131,6 +131,10 @@ namespace delta::core ctx.generic.type = ThreadType::WORKER; ctx.generic.threadIx = i; ctx.generic.threadId = 0xDEADBEEFu; // Initialized when thread starts + ctx.isAsleep.store(false, std::memory_order_relaxed); + ctx.shouldClose.store(false, std::memory_order_relaxed); + + InitializeQueue(ctx.generic.pageCoordinator, ctx.taskQueue, MemoryMap::Worker::VIRT_ZONE_QUEUE_OFFSET, MemoryMap::Worker::VIRT_ZONE_QUEUE_SIZE); } tl_CurrentThreadContext = &g_ThreadContexts[0]; From ca2abc1a1388ff6179cd0d2abdf749563080b62d Mon Sep 17 00:00:00 2001 From: YasInvolved Date: Sat, 30 May 2026 23:05:47 +0200 Subject: [PATCH 18/32] implement a basic worker loop --- Engine/src/delta/core/ThreadContext.cpp | 9 ++- Engine/src/delta/core/Worker.cpp | 74 +++++++++++++++++++++++++ Engine/src/delta/core/Worker.h | 25 +++++++++ 3 files changed, 105 insertions(+), 3 deletions(-) create mode 100644 Engine/src/delta/core/Worker.cpp create mode 100644 Engine/src/delta/core/Worker.h diff --git a/Engine/src/delta/core/ThreadContext.cpp b/Engine/src/delta/core/ThreadContext.cpp index 6f2e7cf..fda266f 100644 --- a/Engine/src/delta/core/ThreadContext.cpp +++ b/Engine/src/delta/core/ThreadContext.cpp @@ -225,13 +225,16 @@ namespace delta::core void Scheduler_ProcessTaskBatch(task_t* tasks, payload_t* payloads, size_t length) { - assert(tl_CurrentThreadContext->threadIx == 0); // CAN BE EXECUTED ONLY ON MAIN THREAD! + assert(IsMainThread()); // CAN BE EXECUTED ONLY ON MAIN THREAD! for (size_t i = 0; i < length; i++) { size_t targetIx = 1 + (i % g_WorkerCount); - WorkerExecutionContext& ctx = reinterpret_cast(g_ThreadContexts[targetIx]); + WorkerExecutionContext& ctx = GetExecutionContext(targetIx); TaskQueue_Push(&ctx.taskQueue, tasks[i], payloads[i]); + + if (ctx.isAsleep.load(std::memory_order_acquire)) + delta::platform::Sync_SignalSemaphore(ctx.sleepSemaphore); } } @@ -244,7 +247,7 @@ namespace delta::core while (consecutiveEmptyQueues < g_ThreadCount) { - WorkerExecutionContext& ctx = reinterpret_cast(g_ThreadContexts[workerIx]); + WorkerExecutionContext& ctx = GetExecutionContext(workerIx); task_t task = nullptr; payload_t payload = nullptr; diff --git a/Engine/src/delta/core/Worker.cpp b/Engine/src/delta/core/Worker.cpp new file mode 100644 index 0000000..0c40ff2 --- /dev/null +++ b/Engine/src/delta/core/Worker.cpp @@ -0,0 +1,74 @@ +/* + * Copyright 2026 Jakub Bączyk + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Worker.h" +#include +#include + +namespace delta::core +{ + using ThreadHandle = delta::platform::Thread*; + using ThreadCreateInfo = delta::platform::ThreadCreateInfo; + + using SemaphoreHandle = delta::platform::SemaphoreHandle; + + static uint32_t s_WorkerCount; + static ThreadHandle* s_Threads; + + static void WorkerProc(void* args) + { + WorkerExecutionContext& ctx = *ThreadContextCast(ThreadContext_GetCurrent()); + + task_t task; + payload_t payload; + while (!ctx.shouldClose.load(std::memory_order_acquire)) + { + // TODO: Figure out how to select a worker to steal some work from. + // I'll probably utilize modulo n cyclic groups. (algebra - group theory) + + if (TaskQueue_Pop(&ctx.taskQueue, &task, &payload)) + { + task(payload); + continue; + } + + ctx.isAsleep.store(true, std::memory_order_release); + + if (!ctx.shouldClose.load(std::memory_order_acquire)) + { + delta::platform::Sync_WaitSemaphore(ctx.sleepSemaphore); + } + + ctx.isAsleep.store(false, std::memory_order_release); + } + } + + void Worker_Init(uint32_t count) + { + s_WorkerCount = count; + + ThreadCreateInfo c = { .fn = WorkerProc, .args = nullptr }; + s_Threads = new(delta::Engine::AllocationType::PERSISTENT) ThreadHandle[count]; + + for (uint32_t i = 0; i < count; i++) + s_Threads[i] = delta::platform::Thread_Create(&c); + } + + void Worker_Shutdown() + { + delta::platform::Thread_JoinMultiple(s_Threads, s_WorkerCount); + } +} diff --git a/Engine/src/delta/core/Worker.h b/Engine/src/delta/core/Worker.h new file mode 100644 index 0000000..6ec2a8b --- /dev/null +++ b/Engine/src/delta/core/Worker.h @@ -0,0 +1,25 @@ +/* + * Copyright 2026 Jakub Bączyk + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +namespace delta::core +{ + void Worker_Init(uint32_t count); + void Worker_Shutdown(); +} From a933140b1bbe0d45cae4a868cb0a21214be1417a Mon Sep 17 00:00:00 2001 From: YasInvolved Date: Sat, 30 May 2026 23:28:15 +0200 Subject: [PATCH 19/32] little compilation fixes --- Engine/CMakeLists.txt | 4 +++- Engine/src/delta/platform/os_win32.cpp | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Engine/CMakeLists.txt b/Engine/CMakeLists.txt index 6ed64a6..9202467 100644 --- a/Engine/CMakeLists.txt +++ b/Engine/CMakeLists.txt @@ -28,7 +28,9 @@ add_library(ProjectDelta SHARED "src/delta/core/ThreadContext.cpp" "src/delta/core/MemoryConfig.h" "src/delta/core/MemoryConfig.cpp" - ) + "src/delta/core/Worker.h" + "src/delta/core/Worker.cpp" +) target_compile_definitions(ProjectDelta PRIVATE DLT_EXPORT_SYMBOLS diff --git a/Engine/src/delta/platform/os_win32.cpp b/Engine/src/delta/platform/os_win32.cpp index c42bc21..b059ddc 100644 --- a/Engine/src/delta/platform/os_win32.cpp +++ b/Engine/src/delta/platform/os_win32.cpp @@ -316,12 +316,12 @@ namespace delta::platform ThreadHandle Thread_Create(ThreadCreateInfo* createInfo) { - ThreadHandle thread = new(delta::Engine::AllocationType::PERSISTENT) ThreadHandle{}; + Thread* thread = new(delta::Engine::AllocationType::PERSISTENT) Thread{}; thread->hThread = CreateThread(nullptr, 0, DeltaThreadProc, (void*)createInfo, 0, 0); if (thread->hThread == 0) return nullptr; - return thread; + return static_cast(thread); } void Thread_Join(ThreadHandle thread) @@ -348,7 +348,7 @@ namespace delta::platform if (s->hSemaphore == nullptr) return nullptr; - return s; + return static_cast(s); } void Sync_DestroySemaphore(SemaphoreHandle sem) From 0438c0e05d249ca9bf81b9d6778e174e4d96687d Mon Sep 17 00:00:00 2001 From: YasInvolved Date: Sat, 30 May 2026 23:29:15 +0200 Subject: [PATCH 20/32] Extend ThreadContext API to fix a subtle bug --- Engine/src/delta/core/ThreadContext.cpp | 10 ++++++++++ Engine/src/delta/core/ThreadContext.h | 2 ++ 2 files changed, 12 insertions(+) diff --git a/Engine/src/delta/core/ThreadContext.cpp b/Engine/src/delta/core/ThreadContext.cpp index fda266f..a3aac84 100644 --- a/Engine/src/delta/core/ThreadContext.cpp +++ b/Engine/src/delta/core/ThreadContext.cpp @@ -150,6 +150,16 @@ namespace delta::core return tl_CurrentThreadContext; } + GenericExecutionContext* ThreadContext_GetForIndex(uint32_t i) noexcept + { + return &GetExecutionContext(i); + } + + void ThreadContext_SetCurrent(GenericExecutionContext* ctx) noexcept + { + tl_CurrentThreadContext = ctx; + } + void TaskQueue_Push(TaskQueue* queue, task_t task, payload_t payload) { uint64_t b = queue->bottom.load(std::memory_order_relaxed); diff --git a/Engine/src/delta/core/ThreadContext.h b/Engine/src/delta/core/ThreadContext.h index 21ce537..864a9b6 100644 --- a/Engine/src/delta/core/ThreadContext.h +++ b/Engine/src/delta/core/ThreadContext.h @@ -26,6 +26,8 @@ namespace delta::core // Getters GenericExecutionContext* ThreadContext_GetCurrent() noexcept; + GenericExecutionContext* ThreadContext_GetForIndex(uint32_t ix) noexcept; + void ThreadContext_SetCurrent(GenericExecutionContext* ctx) noexcept; // Thread Task Queue API void TaskQueue_Push(TaskQueue* queue, task_t task, payload_t payload); From 92ec9ab01f4054067a166206125119bda5c1807b Mon Sep 17 00:00:00 2001 From: YasInvolved Date: Sat, 30 May 2026 23:29:40 +0200 Subject: [PATCH 21/32] correct workers initialization --- Engine/src/delta/core/Worker.cpp | 9 ++++++++- Engine/src/delta/core/engine.cpp | 10 +++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/Engine/src/delta/core/Worker.cpp b/Engine/src/delta/core/Worker.cpp index 0c40ff2..f7dfd39 100644 --- a/Engine/src/delta/core/Worker.cpp +++ b/Engine/src/delta/core/Worker.cpp @@ -30,7 +30,10 @@ namespace delta::core static void WorkerProc(void* args) { - WorkerExecutionContext& ctx = *ThreadContextCast(ThreadContext_GetCurrent()); + GenericExecutionContext* generic = reinterpret_cast(args); + ThreadContext_SetCurrent(generic); + + WorkerExecutionContext& ctx = *ThreadContextCast(generic); task_t task; payload_t payload; @@ -64,7 +67,11 @@ namespace delta::core s_Threads = new(delta::Engine::AllocationType::PERSISTENT) ThreadHandle[count]; for (uint32_t i = 0; i < count; i++) + { + // looping through thread indices, workers start from ix=1 + c.args = ThreadContext_GetForIndex(i+1); s_Threads[i] = delta::platform::Thread_Create(&c); + } } void Worker_Shutdown() diff --git a/Engine/src/delta/core/engine.cpp b/Engine/src/delta/core/engine.cpp index ba8a902..76eebbd 100644 --- a/Engine/src/delta/core/engine.cpp +++ b/Engine/src/delta/core/engine.cpp @@ -18,9 +18,11 @@ #include #include #include -#include -#include -#include + +#include "EngineTypes.h" +#include "MemoryConfig.h" +#include "ThreadContext.h" +#include "Worker.h" namespace delta::Engine { @@ -37,10 +39,12 @@ namespace delta::Engine uint32_t pageSize = osInfo->osPageSize; delta::core::MemoryConfig_Initialize(memStatus.physicalInstalled, pageSize, totalThreads); delta::core::ThreadContext_Initialize(totalThreads, pageSize); + delta::core::Worker_Init(totalThreads-1); } void Shutdown(Context& context) { + delta::core::Worker_Shutdown(); delta::core::ThreadContext_Shutdown(); delta::core::MemoryConfig_Shutdown(); } From c7fc252a581f291d9fcd415998217c713bc83074 Mon Sep 17 00:00:00 2001 From: YasInvolved Date: Sat, 30 May 2026 23:51:35 +0200 Subject: [PATCH 22/32] fix task queue --- Engine/src/delta/core/EngineTypes.h | 9 +++++---- Engine/src/delta/core/ThreadContext.cpp | 20 ++++++++++---------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/Engine/src/delta/core/EngineTypes.h b/Engine/src/delta/core/EngineTypes.h index b677918..d42300a 100644 --- a/Engine/src/delta/core/EngineTypes.h +++ b/Engine/src/delta/core/EngineTypes.h @@ -39,13 +39,14 @@ namespace delta::core using task_t = void (*)(void*); using payload_t = void*; + using queue_index_t = int64_t; struct TaskQueue // SoA structure, Chase-Lev queue { - alignas(64) std::atomic top; - alignas(64) std::atomic bottom; + alignas(64) std::atomic top; + alignas(64) std::atomic bottom; - alignas(64) uint64_t size; - uint64_t mask; + alignas(64) queue_index_t size; + queue_index_t mask; task_t* tasks; payload_t* payloads; diff --git a/Engine/src/delta/core/ThreadContext.cpp b/Engine/src/delta/core/ThreadContext.cpp index a3aac84..94ba947 100644 --- a/Engine/src/delta/core/ThreadContext.cpp +++ b/Engine/src/delta/core/ThreadContext.cpp @@ -162,8 +162,8 @@ namespace delta::core void TaskQueue_Push(TaskQueue* queue, task_t task, payload_t payload) { - uint64_t b = queue->bottom.load(std::memory_order_relaxed); - uint64_t t = queue->top.load(std::memory_order_acquire); + queue_index_t b = queue->bottom.load(std::memory_order_relaxed); + queue_index_t t = queue->top.load(std::memory_order_acquire); if (b - t > queue->size) { @@ -172,7 +172,7 @@ namespace delta::core return; } - uint64_t ix = b & queue->mask; + queue_index_t ix = b & queue->mask; queue->tasks[ix] = task; queue->payloads[ix] = payload; @@ -182,11 +182,11 @@ namespace delta::core bool TaskQueue_Pop(TaskQueue* queue, task_t* outTask, payload_t* outPayload) { - uint64_t b = queue->bottom.load(std::memory_order_relaxed) - 1; + queue_index_t b = queue->bottom.load(std::memory_order_relaxed) - 1; queue->bottom.store(b, std::memory_order_relaxed); std::atomic_thread_fence(std::memory_order_seq_cst); - uint64_t t = queue->top.load(std::memory_order_relaxed); + queue_index_t t = queue->top.load(std::memory_order_relaxed); if (t > b) { @@ -194,13 +194,13 @@ namespace delta::core return false; } - uint64_t ix = b & queue->mask; + queue_index_t ix = b & queue->mask; *outTask = queue->tasks[ix]; *outPayload = queue->payloads[ix]; if (t == b) { - uint64_t expectedTop = t; + queue_index_t expectedTop = t; if (!queue->top.compare_exchange_strong(expectedTop, expectedTop + 1, std::memory_order_seq_cst, std::memory_order_relaxed)) { queue->bottom.store(b + 1, std::memory_order_relaxed); @@ -215,15 +215,15 @@ namespace delta::core bool TaskQueue_Steal(TaskQueue* queue, task_t* outTask, payload_t* outPayload) { - uint64_t t = queue->top.load(std::memory_order_acquire); + queue_index_t t = queue->top.load(std::memory_order_acquire); std::atomic_thread_fence(std::memory_order_seq_cst); - uint64_t b = queue->bottom.load(std::memory_order_acquire); + queue_index_t b = queue->bottom.load(std::memory_order_acquire); if (t >= b) return false; - uint64_t ix = t & queue->mask; + queue_index_t ix = t & queue->mask; *outTask = queue->tasks[ix]; *outPayload = queue->payloads[ix]; From 783022193f1c93e63dd8b2f7e1cfff0fd9f1fdb9 Mon Sep 17 00:00:00 2001 From: YasInvolved Date: Sat, 30 May 2026 23:57:39 +0200 Subject: [PATCH 23/32] initialize semaphores in contexts and fix thread creation --- Engine/src/delta/core/ThreadContext.cpp | 1 + Engine/src/delta/core/Worker.cpp | 11 ++++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Engine/src/delta/core/ThreadContext.cpp b/Engine/src/delta/core/ThreadContext.cpp index 94ba947..51ca09c 100644 --- a/Engine/src/delta/core/ThreadContext.cpp +++ b/Engine/src/delta/core/ThreadContext.cpp @@ -133,6 +133,7 @@ namespace delta::core ctx.generic.threadId = 0xDEADBEEFu; // Initialized when thread starts ctx.isAsleep.store(false, std::memory_order_relaxed); ctx.shouldClose.store(false, std::memory_order_relaxed); + ctx.sleepSemaphore = delta::platform::Sync_CreateSemaphore(); InitializeQueue(ctx.generic.pageCoordinator, ctx.taskQueue, MemoryMap::Worker::VIRT_ZONE_QUEUE_OFFSET, MemoryMap::Worker::VIRT_ZONE_QUEUE_SIZE); } diff --git a/Engine/src/delta/core/Worker.cpp b/Engine/src/delta/core/Worker.cpp index f7dfd39..6cc4c83 100644 --- a/Engine/src/delta/core/Worker.cpp +++ b/Engine/src/delta/core/Worker.cpp @@ -31,6 +31,7 @@ namespace delta::core static void WorkerProc(void* args) { GenericExecutionContext* generic = reinterpret_cast(args); + generic->threadId = delta::platform::Thread_GetCurrentId(); ThreadContext_SetCurrent(generic); WorkerExecutionContext& ctx = *ThreadContextCast(generic); @@ -63,14 +64,18 @@ namespace delta::core { s_WorkerCount = count; - ThreadCreateInfo c = { .fn = WorkerProc, .args = nullptr }; + // TODO: Take a look at native thread api and figure out how this could be done better + // TODO: Set thread affinity mask s_Threads = new(delta::Engine::AllocationType::PERSISTENT) ThreadHandle[count]; + ThreadCreateInfo* cs = new(delta::Engine::AllocationType::TRANSIENT) ThreadCreateInfo[count]; for (uint32_t i = 0; i < count; i++) { // looping through thread indices, workers start from ix=1 - c.args = ThreadContext_GetForIndex(i+1); - s_Threads[i] = delta::platform::Thread_Create(&c); + ThreadCreateInfo& info = cs[i]; + info.fn = WorkerProc; + info.args = ThreadContext_GetForIndex(i + 1); + s_Threads[i] = delta::platform::Thread_Create(&info); } } From b72bd4911e15027b4a5ab7f3b79a45e424d4ef2b Mon Sep 17 00:00:00 2001 From: YasInvolved Date: Sun, 31 May 2026 00:28:52 +0200 Subject: [PATCH 24/32] reset transient arenas in time --- Engine/include/delta/core/engine.h | 1 + Engine/src/delta/core/ThreadContext.cpp | 7 +++++++ Engine/src/delta/core/ThreadContext.h | 6 ++++-- Engine/src/delta/core/Worker.cpp | 2 +- Engine/src/delta/core/engine.cpp | 7 +++++++ Launcher/main.cpp | 1 + 6 files changed, 21 insertions(+), 3 deletions(-) diff --git a/Engine/include/delta/core/engine.h b/Engine/include/delta/core/engine.h index 74dccf1..40fc429 100644 --- a/Engine/include/delta/core/engine.h +++ b/Engine/include/delta/core/engine.h @@ -28,5 +28,6 @@ namespace delta::Engine typedef void (*GameShutdownFunc)(Context*); DLT_API void Initialize(Context& context); + DLT_API void Update(Context& context); DLT_API void Shutdown(Context& context); } diff --git a/Engine/src/delta/core/ThreadContext.cpp b/Engine/src/delta/core/ThreadContext.cpp index 51ca09c..45f5eb5 100644 --- a/Engine/src/delta/core/ThreadContext.cpp +++ b/Engine/src/delta/core/ThreadContext.cpp @@ -280,6 +280,13 @@ namespace delta::core } } + ThreadArena* GetTransientArena() noexcept + { + auto* ctx = tl_CurrentThreadContext; + assert(ctx); + return &ctx->transientArena; + } + void* ThreadArena_Allocate(ThreadArena* arena, size_t size, size_t alignment) { uintptr_t currentAddress = reinterpret_cast(arena->backingMemory) + arena->offset; diff --git a/Engine/src/delta/core/ThreadContext.h b/Engine/src/delta/core/ThreadContext.h index 864a9b6..bc6b815 100644 --- a/Engine/src/delta/core/ThreadContext.h +++ b/Engine/src/delta/core/ThreadContext.h @@ -39,8 +39,10 @@ namespace delta::core void Scheduler_Sync(); // Engine Arena API - void* ThreadArena_Allocate(ThreadArena* arena, size_t size, size_t alignment = 8); - void ThreadArena_Reset(ThreadArena* arena); + ThreadArena* GetTransientArena() noexcept; + void* ThreadArena_Allocate(ThreadArena* arena, size_t size, size_t alignment = 8); + void ThreadArena_Reset(ThreadArena* arena); + void ThreadArena_Reset(ThreadArena* arena); // Inline Helpers template diff --git a/Engine/src/delta/core/Worker.cpp b/Engine/src/delta/core/Worker.cpp index 6cc4c83..7343b49 100644 --- a/Engine/src/delta/core/Worker.cpp +++ b/Engine/src/delta/core/Worker.cpp @@ -49,8 +49,8 @@ namespace delta::core continue; } + ThreadArena_Reset(GetTransientArena()); ctx.isAsleep.store(true, std::memory_order_release); - if (!ctx.shouldClose.load(std::memory_order_acquire)) { delta::platform::Sync_WaitSemaphore(ctx.sleepSemaphore); diff --git a/Engine/src/delta/core/engine.cpp b/Engine/src/delta/core/engine.cpp index 76eebbd..5febdf4 100644 --- a/Engine/src/delta/core/engine.cpp +++ b/Engine/src/delta/core/engine.cpp @@ -42,6 +42,13 @@ namespace delta::Engine delta::core::Worker_Init(totalThreads-1); } + void Update(Context& context) + { + // blah blah blah + // do something + delta::core::ThreadArena_Reset(delta::core::GetTransientArena()); + } + void Shutdown(Context& context) { delta::core::Worker_Shutdown(); diff --git a/Launcher/main.cpp b/Launcher/main.cpp index 0a24556..d1525ae 100644 --- a/Launcher/main.cpp +++ b/Launcher/main.cpp @@ -172,6 +172,7 @@ int main(int argc, char** argv) continue; } + delta::Engine::Update(g_context); game.updateFn(&g_context); } From 66f400436daea266972351a12ad1185f4e65c8f5 Mon Sep 17 00:00:00 2001 From: YasInvolved Date: Sun, 31 May 2026 00:29:39 +0200 Subject: [PATCH 25/32] remove switch-case from hello world game --- Examples/HelloWorldGame/game.cpp | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/Examples/HelloWorldGame/game.cpp b/Examples/HelloWorldGame/game.cpp index a59d077..44bb162 100644 --- a/Examples/HelloWorldGame/game.cpp +++ b/Examples/HelloWorldGame/game.cpp @@ -58,22 +58,11 @@ extern "C" void GAME_API Game_OnUpdate(delta::Engine::Context* context) { - char input; - std::cout << "\"1\" to continue and \"2\" to exit: "; - std::cin >> input; - - switch (input) - { - case '1': - break; - case '2': - context->isRunning = false; - break; - } + } void GAME_API Game_OnShutdown(delta::Engine::Context* context) { - std::cout << "Shutdown\n"; + } } From 9d08653097a99dd846982b1306125aa59236c4a0 Mon Sep 17 00:00:00 2001 From: YasInvolved Date: Sun, 31 May 2026 12:04:33 +0200 Subject: [PATCH 26/32] sleep func --- Engine/src/delta/core/engine.cpp | 1 + Engine/src/delta/platform/os_internal.h | 1 + Engine/src/delta/platform/os_win32.cpp | 5 +++++ 3 files changed, 7 insertions(+) diff --git a/Engine/src/delta/core/engine.cpp b/Engine/src/delta/core/engine.cpp index 5febdf4..521c852 100644 --- a/Engine/src/delta/core/engine.cpp +++ b/Engine/src/delta/core/engine.cpp @@ -46,6 +46,7 @@ namespace delta::Engine { // blah blah blah // do something + delta::platform::Sync_Sleep(100); delta::core::ThreadArena_Reset(delta::core::GetTransientArena()); } diff --git a/Engine/src/delta/platform/os_internal.h b/Engine/src/delta/platform/os_internal.h index c8446b6..3b6cfe1 100644 --- a/Engine/src/delta/platform/os_internal.h +++ b/Engine/src/delta/platform/os_internal.h @@ -66,4 +66,5 @@ namespace delta::platform void Sync_DestroySemaphore(SemaphoreHandle sem); void Sync_SignalSemaphore(SemaphoreHandle sem); void Sync_WaitSemaphore(SemaphoreHandle sem); + void Sync_Sleep(uint32_t milliseconds); } diff --git a/Engine/src/delta/platform/os_win32.cpp b/Engine/src/delta/platform/os_win32.cpp index b059ddc..15bd46a 100644 --- a/Engine/src/delta/platform/os_win32.cpp +++ b/Engine/src/delta/platform/os_win32.cpp @@ -368,6 +368,11 @@ namespace delta::platform { WaitForSingleObject(handle->hSemaphore, INFINITE); } + + void Sync_Sleep(uint32_t milliseconds) + { + Sleep(milliseconds); + } } #endif From af08e2d6834df3a3f3a3a29671029f40a59d956e Mon Sep 17 00:00:00 2001 From: YasInvolved Date: Sun, 31 May 2026 13:11:36 +0200 Subject: [PATCH 27/32] some utilities to name threads --- Engine/src/delta/platform/os_internal.h | 22 +++++++----- Engine/src/delta/platform/os_win32.cpp | 45 +++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 9 deletions(-) diff --git a/Engine/src/delta/platform/os_internal.h b/Engine/src/delta/platform/os_internal.h index 3b6cfe1..f4c3a70 100644 --- a/Engine/src/delta/platform/os_internal.h +++ b/Engine/src/delta/platform/os_internal.h @@ -21,15 +21,6 @@ namespace delta::platform struct BrandStringCall; struct Timer_Internal; - struct ThreadCreateInfo - { - void (*fn)(void*); - void* args; - }; - - struct Thread; - using ThreadHandle = Thread*; - struct Semaphore; using SemaphoreHandle = Semaphore*; @@ -55,9 +46,22 @@ namespace delta::platform double Timer_TicksToMicroseconds(const Timer* timer, int64_t startTicks, int64_t endTicks); // Thread API + struct Thread; + using ThreadHandle = Thread*; + inline constexpr ThreadHandle INVALID_THREAD_HANDLE = nullptr; // random number 696767 + + struct ThreadCreateInfo + { + void (*fn)(void*); + void* args; + }; + uint32_t Thread_GetCurrentId(); uint32_t Thread_GetId(ThreadHandle thread); + ThreadHandle Thread_GetCurrentHandle(); ThreadHandle Thread_Create(ThreadCreateInfo* createInfo); + void Thread_AssignPhysicalCore(ThreadHandle thread, uint32_t coreIndex); + void Thread_SetName(ThreadHandle handle, const char* name); void Thread_Join(ThreadHandle thread); void Thread_JoinMultiple(ThreadHandle* threads, uint32_t count); diff --git a/Engine/src/delta/platform/os_win32.cpp b/Engine/src/delta/platform/os_win32.cpp index 15bd46a..8dbd0ab 100644 --- a/Engine/src/delta/platform/os_win32.cpp +++ b/Engine/src/delta/platform/os_win32.cpp @@ -53,6 +53,14 @@ namespace delta::platform HANDLE hSemaphore; }; + struct THREADNAME_INFO + { + DWORD dwType; + LPCSTR szName; + DWORD dwThreadID; + DWORD dwFlags; + }; + static_assert(std::is_standard_layout_v, "PAL layout broken: Must be standard layout!"); static_assert(sizeof(Thread) == sizeof(HANDLE), "PAL layout broken: Size mismatch!"); @@ -314,6 +322,43 @@ namespace delta::platform return GetThreadId(thread->hThread); } + ThreadHandle Thread_GetCurrentHandle() + { + Thread* t = new(delta::Engine::AllocationType::PERSISTENT) Thread(); + t->hThread = GetCurrentThread(); + if (!t->hThread) + return nullptr; + + return t; + } + + void Thread_AssignPhysicalCore(ThreadHandle thread, uint32_t coreIndex) + { + uint32_t logicalCore = coreIndex * 2; + DWORD_PTR affinityMask = (DWORD_PTR)(1ull << logicalCore); + DWORD_PTR prevMask = SetThreadAffinityMask(thread->hThread, affinityMask); + } + + void Thread_SetName(ThreadHandle handle, const char* name) + { + const THREADNAME_INFO info = + { + .dwType = 0x1000, + .szName = name, + .dwThreadID = GetThreadId(handle->hThread), + .dwFlags = 0 + }; + + __try + { + ::RaiseException(0x406D1388, 0, sizeof(info) / sizeof(DWORD), reinterpret_cast(&info)); + } + __except(EXCEPTION_CONTINUE_EXECUTION) + { + + } + } + ThreadHandle Thread_Create(ThreadCreateInfo* createInfo) { Thread* thread = new(delta::Engine::AllocationType::PERSISTENT) Thread{}; From 54ddab0bbe412222a507fb01da99f03deeec07f2 Mon Sep 17 00:00:00 2001 From: YasInvolved Date: Sun, 31 May 2026 13:12:29 +0200 Subject: [PATCH 28/32] I'm too bored to describe this commit lol --- Engine/src/delta/core/EngineTypes.h | 2 +- Engine/src/delta/core/ThreadContext.cpp | 4 ++-- Engine/src/delta/core/Worker.cpp | 12 ++++++++---- Engine/src/delta/core/engine.cpp | 3 +++ 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/Engine/src/delta/core/EngineTypes.h b/Engine/src/delta/core/EngineTypes.h index d42300a..d5247f3 100644 --- a/Engine/src/delta/core/EngineTypes.h +++ b/Engine/src/delta/core/EngineTypes.h @@ -61,7 +61,7 @@ namespace delta::core // SHARED TRAITS ThreadType type; uint32_t threadIx; - uint32_t threadId; + delta::platform::ThreadHandle threadHandle; ThreadPageCoordinator pageCoordinator; ThreadArena transientArena; diff --git a/Engine/src/delta/core/ThreadContext.cpp b/Engine/src/delta/core/ThreadContext.cpp index 45f5eb5..a732d7d 100644 --- a/Engine/src/delta/core/ThreadContext.cpp +++ b/Engine/src/delta/core/ThreadContext.cpp @@ -120,7 +120,7 @@ namespace delta::core MainExecutionContext& ctx = GetExecutionContext(0); ctx.generic.type = ThreadType::MAIN; ctx.generic.threadIx = 0; - ctx.generic.threadId = delta::platform::Thread_GetCurrentId(); + ctx.generic.threadHandle = delta::platform::Thread_GetCurrentHandle(); InitializeArena(ctx.generic.pageCoordinator, ctx.persistentStorage, MemoryMap::Main::VIRT_ZONE_PS_OFFSET, MemoryMap::Main::VIRT_ZONE_PS_BASELINE, MemoryMap::Main::VIRT_ZONE_PS_SIZE); } @@ -130,7 +130,7 @@ namespace delta::core WorkerExecutionContext& ctx = GetExecutionContext(i); ctx.generic.type = ThreadType::WORKER; ctx.generic.threadIx = i; - ctx.generic.threadId = 0xDEADBEEFu; // Initialized when thread starts + ctx.generic.threadHandle = delta::platform::INVALID_THREAD_HANDLE; // Initialized when thread starts ctx.isAsleep.store(false, std::memory_order_relaxed); ctx.shouldClose.store(false, std::memory_order_relaxed); ctx.sleepSemaphore = delta::platform::Sync_CreateSemaphore(); diff --git a/Engine/src/delta/core/Worker.cpp b/Engine/src/delta/core/Worker.cpp index 7343b49..01ec2aa 100644 --- a/Engine/src/delta/core/Worker.cpp +++ b/Engine/src/delta/core/Worker.cpp @@ -20,7 +20,7 @@ namespace delta::core { - using ThreadHandle = delta::platform::Thread*; + using ThreadHandle = delta::platform::ThreadHandle; using ThreadCreateInfo = delta::platform::ThreadCreateInfo; using SemaphoreHandle = delta::platform::SemaphoreHandle; @@ -31,7 +31,6 @@ namespace delta::core static void WorkerProc(void* args) { GenericExecutionContext* generic = reinterpret_cast(args); - generic->threadId = delta::platform::Thread_GetCurrentId(); ThreadContext_SetCurrent(generic); WorkerExecutionContext& ctx = *ThreadContextCast(generic); @@ -73,9 +72,14 @@ namespace delta::core { // looping through thread indices, workers start from ix=1 ThreadCreateInfo& info = cs[i]; + ThreadHandle& handle = s_Threads[i]; + auto* ctx = ThreadContext_GetForIndex(i + 1); info.fn = WorkerProc; - info.args = ThreadContext_GetForIndex(i + 1); - s_Threads[i] = delta::platform::Thread_Create(&info); + info.args = (void*)ctx; + handle = delta::platform::Thread_Create(&info); + ctx->threadHandle = handle; + delta::platform::Thread_AssignPhysicalCore(handle, i + 1); + delta::platform::Thread_SetName(handle, "Worker"); } } diff --git a/Engine/src/delta/core/engine.cpp b/Engine/src/delta/core/engine.cpp index 521c852..bfdcdc7 100644 --- a/Engine/src/delta/core/engine.cpp +++ b/Engine/src/delta/core/engine.cpp @@ -39,6 +39,9 @@ namespace delta::Engine uint32_t pageSize = osInfo->osPageSize; delta::core::MemoryConfig_Initialize(memStatus.physicalInstalled, pageSize, totalThreads); delta::core::ThreadContext_Initialize(totalThreads, pageSize); + + delta::platform::ThreadHandle th = delta::platform::Thread_GetCurrentHandle(); + delta::platform::Thread_AssignPhysicalCore(th, 0); delta::core::Worker_Init(totalThreads-1); } From 6e91861dcd72e8483da1317236431e27ce3c0f1f Mon Sep 17 00:00:00 2001 From: YasInvolved Date: Mon, 1 Jun 2026 21:55:22 +0200 Subject: [PATCH 29/32] introduce DependencyCounter structure and make a small cleanup in function calls --- Engine/src/delta/core/EngineTypes.h | 8 +++++ Engine/src/delta/core/ThreadContext.cpp | 47 +++++++++++++++++++++---- 2 files changed, 48 insertions(+), 7 deletions(-) diff --git a/Engine/src/delta/core/EngineTypes.h b/Engine/src/delta/core/EngineTypes.h index d5247f3..2cf292a 100644 --- a/Engine/src/delta/core/EngineTypes.h +++ b/Engine/src/delta/core/EngineTypes.h @@ -37,6 +37,12 @@ namespace delta::core size_t maxCapacity; }; + struct DependencyCounter + { + uint32_t target; + std::atomic count; + }; + using task_t = void (*)(void*); using payload_t = void*; using queue_index_t = int64_t; @@ -50,6 +56,7 @@ namespace delta::core task_t* tasks; payload_t* payloads; + DependencyCounter* depCounterPtr; static inline constexpr size_t FIELD_SIZE = sizeof(task_t) + sizeof(payload_t); }; @@ -75,6 +82,7 @@ namespace delta::core // ROLE TRAITS ThreadArena persistentStorage; + DependencyCounter depCounter; }; struct alignas(64) WorkerExecutionContext diff --git a/Engine/src/delta/core/ThreadContext.cpp b/Engine/src/delta/core/ThreadContext.cpp index a732d7d..1653192 100644 --- a/Engine/src/delta/core/ThreadContext.cpp +++ b/Engine/src/delta/core/ThreadContext.cpp @@ -38,7 +38,12 @@ namespace delta::core pageCoord.reservedCapacity = MemoryMap::VIRT_ZONE_SPACE_LENGTH; } - DLT_FORCE_INLINE static void InitializeQueue(const ThreadPageCoordinator& pageCoord, TaskQueue& queue, size_t offset, size_t memSize) + DLT_FORCE_INLINE static void InitializeQueue( + const ThreadPageCoordinator& pageCoord, + TaskQueue& queue, + DependencyCounter* depCounter, + size_t offset, + size_t memSize) { queue.size = memSize / TaskQueue::FIELD_SIZE; queue.mask = queue.size - 1; @@ -56,7 +61,12 @@ namespace delta::core queue.payloads = reinterpret_cast(payloadsArrayPtr); } - DLT_FORCE_INLINE static void InitializeArena(const ThreadPageCoordinator& pageCoord, ThreadArena& arena, size_t offset, size_t baseline, size_t maxCapacity) + DLT_FORCE_INLINE static void InitializeArena( + const ThreadPageCoordinator& pageCoord, + ThreadArena& arena, + size_t offset, + size_t baseline, + size_t maxCapacity) { uint8_t* pTarget = pageCoord.virtualAddressBase + offset; void* res = delta::platform::Memory_Commit(pTarget, baseline); @@ -109,20 +119,37 @@ namespace delta::core for (uint32_t i = 0; i < threadCount; i++) { GenericExecutionContext& ctx = GetExecutionContext(i); - InitializePageCoordinator(ctx.pageCoordinator, pageSize, runwayCursor); - InitializeArena(ctx.pageCoordinator, ctx.transientArena, MemoryMap::VIRT_ZONE_TA_OFFSET, MemoryMap::VIRT_ZONE_TA_BASELINE, MemoryMap::VIRT_ZONE_TA_SIZE); delta::platform::Timer_Initialize(&ctx.perThreadTimer); + InitializePageCoordinator(ctx.pageCoordinator, pageSize, runwayCursor); + InitializeArena( + ctx.pageCoordinator, + ctx.transientArena, + MemoryMap::VIRT_ZONE_TA_OFFSET, + MemoryMap::VIRT_ZONE_TA_BASELINE, + MemoryMap::VIRT_ZONE_TA_SIZE + ); + runwayCursor += MemoryMap::VIRT_ZONE_SPACE_LENGTH; } // Finish initializing main thread context + DependencyCounter* depCounterPtr = nullptr; { MainExecutionContext& ctx = GetExecutionContext(0); ctx.generic.type = ThreadType::MAIN; ctx.generic.threadIx = 0; ctx.generic.threadHandle = delta::platform::Thread_GetCurrentHandle(); - - InitializeArena(ctx.generic.pageCoordinator, ctx.persistentStorage, MemoryMap::Main::VIRT_ZONE_PS_OFFSET, MemoryMap::Main::VIRT_ZONE_PS_BASELINE, MemoryMap::Main::VIRT_ZONE_PS_SIZE); + ctx.depCounter.target = 0; + ctx.depCounter.count.store(0, std::memory_order_relaxed); + depCounterPtr = &ctx.depCounter; + + InitializeArena( + ctx.generic.pageCoordinator, + ctx.persistentStorage, + MemoryMap::Main::VIRT_ZONE_PS_OFFSET, + MemoryMap::Main::VIRT_ZONE_PS_BASELINE, + MemoryMap::Main::VIRT_ZONE_PS_SIZE + ); } for (uint32_t i = 1; i < threadCount; i++) @@ -135,7 +162,13 @@ namespace delta::core ctx.shouldClose.store(false, std::memory_order_relaxed); ctx.sleepSemaphore = delta::platform::Sync_CreateSemaphore(); - InitializeQueue(ctx.generic.pageCoordinator, ctx.taskQueue, MemoryMap::Worker::VIRT_ZONE_QUEUE_OFFSET, MemoryMap::Worker::VIRT_ZONE_QUEUE_SIZE); + InitializeQueue( + ctx.generic.pageCoordinator, + ctx.taskQueue, + depCounterPtr, + MemoryMap::Worker::VIRT_ZONE_QUEUE_OFFSET, + MemoryMap::Worker::VIRT_ZONE_QUEUE_SIZE + ); } tl_CurrentThreadContext = &g_ThreadContexts[0]; From b409f152c43fdd28d2e81215c208024006f67b25 Mon Sep 17 00:00:00 2001 From: YasInvolved Date: Mon, 1 Jun 2026 22:23:58 +0200 Subject: [PATCH 30/32] make depcounter work "in theory" --- Engine/src/delta/core/EngineTypes.h | 1 - Engine/src/delta/core/ThreadContext.cpp | 2 +- Engine/src/delta/core/ThreadContext.h | 20 +++++++++++++++++++- Engine/src/delta/core/Worker.cpp | 7 +++---- 4 files changed, 23 insertions(+), 7 deletions(-) diff --git a/Engine/src/delta/core/EngineTypes.h b/Engine/src/delta/core/EngineTypes.h index 2cf292a..98db880 100644 --- a/Engine/src/delta/core/EngineTypes.h +++ b/Engine/src/delta/core/EngineTypes.h @@ -39,7 +39,6 @@ namespace delta::core struct DependencyCounter { - uint32_t target; std::atomic count; }; diff --git a/Engine/src/delta/core/ThreadContext.cpp b/Engine/src/delta/core/ThreadContext.cpp index 1653192..8e3019c 100644 --- a/Engine/src/delta/core/ThreadContext.cpp +++ b/Engine/src/delta/core/ThreadContext.cpp @@ -139,7 +139,6 @@ namespace delta::core ctx.generic.type = ThreadType::MAIN; ctx.generic.threadIx = 0; ctx.generic.threadHandle = delta::platform::Thread_GetCurrentHandle(); - ctx.depCounter.target = 0; ctx.depCounter.count.store(0, std::memory_order_relaxed); depCounterPtr = &ctx.depCounter; @@ -270,6 +269,7 @@ namespace delta::core void Scheduler_ProcessTaskBatch(task_t* tasks, payload_t* payloads, size_t length) { assert(IsMainThread()); // CAN BE EXECUTED ONLY ON MAIN THREAD! + GetMainContext().depCounter.count.store(length, std::memory_order_relaxed); for (size_t i = 0; i < length; i++) { diff --git a/Engine/src/delta/core/ThreadContext.h b/Engine/src/delta/core/ThreadContext.h index bc6b815..3a5bad4 100644 --- a/Engine/src/delta/core/ThreadContext.h +++ b/Engine/src/delta/core/ThreadContext.h @@ -46,7 +46,7 @@ namespace delta::core // Inline Helpers template - [[nodiscard]] inline TargetType* ThreadContextCast(GenericExecutionContext* ctx) + [[deprecated]] [[nodiscard]] inline TargetType* ThreadContextCast(GenericExecutionContext* ctx) { if (!ctx) return nullptr; @@ -77,9 +77,27 @@ namespace delta::core return ctx && ctx->type == ThreadType::MAIN; } + inline MainExecutionContext& GetMainContext() + { + auto* ctx = ThreadContext_GetCurrent(); + if (ctx->type == ThreadType::MAIN) + return reinterpret_cast(ctx); + + assert(false); // this shouldn't ever happen + } + inline bool IsWorkerThread() { auto* ctx = ThreadContext_GetCurrent(); return ctx && ctx->type == ThreadType::WORKER; } + + inline WorkerExecutionContext& GetWorkerContext() + { + auto* ctx = ThreadContext_GetCurrent(); + if (ctx->type == ThreadType::WORKER) + return reinterpret_cast(ctx); + + assert(false); + } } diff --git a/Engine/src/delta/core/Worker.cpp b/Engine/src/delta/core/Worker.cpp index 01ec2aa..c10e275 100644 --- a/Engine/src/delta/core/Worker.cpp +++ b/Engine/src/delta/core/Worker.cpp @@ -30,13 +30,11 @@ namespace delta::core static void WorkerProc(void* args) { - GenericExecutionContext* generic = reinterpret_cast(args); - ThreadContext_SetCurrent(generic); - - WorkerExecutionContext& ctx = *ThreadContextCast(generic); + WorkerExecutionContext& ctx = GetWorkerContext(); task_t task; payload_t payload; + DependencyCounter& depCounter = reinterpret_cast(ctx.taskQueue.depCounterPtr); while (!ctx.shouldClose.load(std::memory_order_acquire)) { // TODO: Figure out how to select a worker to steal some work from. @@ -45,6 +43,7 @@ namespace delta::core if (TaskQueue_Pop(&ctx.taskQueue, &task, &payload)) { task(payload); + depCounter.count.fetch_sub(1, std::memory_order_release); continue; } From d234fcc7cfc1f12719f6ef4cc9c554db5b79b6b6 Mon Sep 17 00:00:00 2001 From: YasInvolved Date: Mon, 1 Jun 2026 22:43:09 +0200 Subject: [PATCH 31/32] add header with compiler-specific macros and fix compilation warnings and fix some bugs --- Engine/CMakeLists.txt | 1 + Engine/src/delta/core/ThreadContext.h | 20 ++++++++++-------- Engine/src/delta/core/Worker.cpp | 17 ++++++++-------- Engine/src/delta/internal_definitions.h | 7 ------- Engine/src/delta/pch.h | 2 -- Engine/src/delta/platform/compiler.h | 27 +++++++++++++++++++++++++ Engine/src/delta/platform/os_win32.cpp | 1 + 7 files changed, 50 insertions(+), 25 deletions(-) delete mode 100644 Engine/src/delta/internal_definitions.h create mode 100644 Engine/src/delta/platform/compiler.h diff --git a/Engine/CMakeLists.txt b/Engine/CMakeLists.txt index 9202467..d056fcf 100644 --- a/Engine/CMakeLists.txt +++ b/Engine/CMakeLists.txt @@ -13,6 +13,7 @@ # limitations under the License. add_library(ProjectDelta SHARED + "src/delta/platform/compiler.h" "src/delta/core/engine.cpp" "include/delta/core/engine.h" "include/delta/core/memory.h" diff --git a/Engine/src/delta/core/ThreadContext.h b/Engine/src/delta/core/ThreadContext.h index 3a5bad4..c33659d 100644 --- a/Engine/src/delta/core/ThreadContext.h +++ b/Engine/src/delta/core/ThreadContext.h @@ -16,6 +16,7 @@ #pragma once +#include #include "EngineTypes.h" namespace delta::core @@ -77,27 +78,30 @@ namespace delta::core return ctx && ctx->type == ThreadType::MAIN; } - inline MainExecutionContext& GetMainContext() + inline bool IsWorkerThread() { auto* ctx = ThreadContext_GetCurrent(); - if (ctx->type == ThreadType::MAIN) - return reinterpret_cast(ctx); - - assert(false); // this shouldn't ever happen + return ctx && ctx->type == ThreadType::WORKER; } - inline bool IsWorkerThread() + DLT_DISABLE_WARNING_PUSH + DLT_DISABLE_MISSING_RETURN + inline MainExecutionContext& GetMainContext() { auto* ctx = ThreadContext_GetCurrent(); - return ctx && ctx->type == ThreadType::WORKER; + if (ctx->type == ThreadType::MAIN) + return reinterpret_cast(*ctx); + + assert(false); // this shouldn't ever happen } inline WorkerExecutionContext& GetWorkerContext() { auto* ctx = ThreadContext_GetCurrent(); if (ctx->type == ThreadType::WORKER) - return reinterpret_cast(ctx); + return reinterpret_cast(*ctx); assert(false); } + DLT_DISABLE_WARNING_POP } diff --git a/Engine/src/delta/core/Worker.cpp b/Engine/src/delta/core/Worker.cpp index c10e275..7cded61 100644 --- a/Engine/src/delta/core/Worker.cpp +++ b/Engine/src/delta/core/Worker.cpp @@ -30,17 +30,18 @@ namespace delta::core static void WorkerProc(void* args) { - WorkerExecutionContext& ctx = GetWorkerContext(); + WorkerExecutionContext* ctx = reinterpret_cast(args); + ThreadContext_SetCurrent((GenericExecutionContext*)ctx); task_t task; payload_t payload; - DependencyCounter& depCounter = reinterpret_cast(ctx.taskQueue.depCounterPtr); - while (!ctx.shouldClose.load(std::memory_order_acquire)) + DependencyCounter& depCounter = reinterpret_cast(*ctx->taskQueue.depCounterPtr); + while (!ctx->shouldClose.load(std::memory_order_acquire)) { // TODO: Figure out how to select a worker to steal some work from. // I'll probably utilize modulo n cyclic groups. (algebra - group theory) - if (TaskQueue_Pop(&ctx.taskQueue, &task, &payload)) + if (TaskQueue_Pop(&ctx->taskQueue, &task, &payload)) { task(payload); depCounter.count.fetch_sub(1, std::memory_order_release); @@ -48,13 +49,13 @@ namespace delta::core } ThreadArena_Reset(GetTransientArena()); - ctx.isAsleep.store(true, std::memory_order_release); - if (!ctx.shouldClose.load(std::memory_order_acquire)) + ctx->isAsleep.store(true, std::memory_order_release); + if (!ctx->shouldClose.load(std::memory_order_acquire)) { - delta::platform::Sync_WaitSemaphore(ctx.sleepSemaphore); + delta::platform::Sync_WaitSemaphore(ctx->sleepSemaphore); } - ctx.isAsleep.store(false, std::memory_order_release); + ctx->isAsleep.store(false, std::memory_order_release); } } diff --git a/Engine/src/delta/internal_definitions.h b/Engine/src/delta/internal_definitions.h deleted file mode 100644 index 0166698..0000000 --- a/Engine/src/delta/internal_definitions.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#ifdef _MSC_VER - #define DLT_FORCE_INLINE __forceinline -#else - #define DLT_FORCE_INLINE __attribute__((always_inline)) -#endif diff --git a/Engine/src/delta/pch.h b/Engine/src/delta/pch.h index 57c4f95..a8b39f2 100644 --- a/Engine/src/delta/pch.h +++ b/Engine/src/delta/pch.h @@ -8,5 +8,3 @@ #include #include #include - -#include "internal_definitions.h" diff --git a/Engine/src/delta/platform/compiler.h b/Engine/src/delta/platform/compiler.h new file mode 100644 index 0000000..f668e75 --- /dev/null +++ b/Engine/src/delta/platform/compiler.h @@ -0,0 +1,27 @@ +#pragma once + +#if defined(_MSC_VER) + #define DLT_DISABLE_WARNING_PUSH __pragma(warning(push)) + #define DLT_DISABLE_WARNING_POP __pragma(warning(pop)) + #define DLT_DISABLE_MISSING_RETURN __pragma(warning(disable : 4715)) + + #define DLT_FORCE_INLINE __forceinline +#elif defined(__clang__) + #define DLT_DISABLE_WARNING_PUSH _Pragma("clang diagnostic push") + #define DLT_DISABLE_WARNING_POP _Pragma("clang diagnostic pop") + #define DLT_DISABLE_MISSING_RETURN _Pragma("clang diagnostic ignored \"-Wreturn-type\"") + + #define DLT_FORCE_INLINE __attribute__((always_inline)) +#elif defined(__GNUC__) || defined(__GNUG__) + #define DLT_DISABLE_WARNING_PUSH _Pragma("GCC diagnostic push") + #define DLT_DISABLE_WARNING_POP _Pragma("GCC diagnostic pop") + #define DLT_DISABLE_MISSING_RETURN _Pragma("GCC diagnostic ignored \"-Wreturn-type\"") + + #define DLT_FORCE_INLINE __attribute__((always_inline)) +#else + #define DLT_DISABLE_WARNING_PUSH + #define DLT_DISABLE_WARNING_POP + #define DLT_DISABLE_MISSING_RETURN + + #define DLT_FORCE_INLINE +#endif diff --git a/Engine/src/delta/platform/os_win32.cpp b/Engine/src/delta/platform/os_win32.cpp index 8dbd0ab..df4806b 100644 --- a/Engine/src/delta/platform/os_win32.cpp +++ b/Engine/src/delta/platform/os_win32.cpp @@ -16,6 +16,7 @@ #ifdef _WIN32 +#include #include #include "os_internal.h" #include From c6f6730bb360e6d9e974ec8892b53af3b2c6bc0f Mon Sep 17 00:00:00 2001 From: YasInvolved Date: Mon, 1 Jun 2026 22:59:50 +0200 Subject: [PATCH 32/32] add unreachable compiler hint for possibly better optimization --- Engine/src/delta/core/ThreadContext.h | 2 ++ Engine/src/delta/platform/compiler.h | 12 ++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Engine/src/delta/core/ThreadContext.h b/Engine/src/delta/core/ThreadContext.h index c33659d..a4aa6a9 100644 --- a/Engine/src/delta/core/ThreadContext.h +++ b/Engine/src/delta/core/ThreadContext.h @@ -93,6 +93,7 @@ namespace delta::core return reinterpret_cast(*ctx); assert(false); // this shouldn't ever happen + DLT_UNREACHABLE; } inline WorkerExecutionContext& GetWorkerContext() @@ -102,6 +103,7 @@ namespace delta::core return reinterpret_cast(*ctx); assert(false); + DLT_UNREACHABLE; } DLT_DISABLE_WARNING_POP } diff --git a/Engine/src/delta/platform/compiler.h b/Engine/src/delta/platform/compiler.h index f668e75..b53804c 100644 --- a/Engine/src/delta/platform/compiler.h +++ b/Engine/src/delta/platform/compiler.h @@ -6,22 +6,30 @@ #define DLT_DISABLE_MISSING_RETURN __pragma(warning(disable : 4715)) #define DLT_FORCE_INLINE __forceinline + + #define DLT_UNREACHABLE __assume(0) #elif defined(__clang__) #define DLT_DISABLE_WARNING_PUSH _Pragma("clang diagnostic push") #define DLT_DISABLE_WARNING_POP _Pragma("clang diagnostic pop") #define DLT_DISABLE_MISSING_RETURN _Pragma("clang diagnostic ignored \"-Wreturn-type\"") - #define DLT_FORCE_INLINE __attribute__((always_inline)) + #define DLT_FORCE_INLINE __attribute__((always_inline)) + + #define DLT_UNREACHABLE __builtin_unreachable() #elif defined(__GNUC__) || defined(__GNUG__) #define DLT_DISABLE_WARNING_PUSH _Pragma("GCC diagnostic push") #define DLT_DISABLE_WARNING_POP _Pragma("GCC diagnostic pop") #define DLT_DISABLE_MISSING_RETURN _Pragma("GCC diagnostic ignored \"-Wreturn-type\"") - #define DLT_FORCE_INLINE __attribute__((always_inline)) + #define DLT_FORCE_INLINE __attribute__((always_inline)) + + #define DLT_UNREACHABLE __builtin_unreachable() #else #define DLT_DISABLE_WARNING_PUSH #define DLT_DISABLE_WARNING_POP #define DLT_DISABLE_MISSING_RETURN #define DLT_FORCE_INLINE + + #define DLT_UNREACHABLE do {} while(0) #endif