Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
c237dfe
convenience wrapper
YasInvolved May 28, 2026
e7fdd2f
current thread id getter
YasInvolved May 28, 2026
cf0eaec
remove logic that shouldn't be in the platform namespace
YasInvolved May 28, 2026
7716a74
disable RTTI
YasInvolved May 28, 2026
de72566
distinguish thread types
YasInvolved May 28, 2026
9db854c
persistent storage on the main thread
YasInvolved May 28, 2026
828ae21
handle arena overflow
YasInvolved May 28, 2026
62b4cd8
expose allocation api to the client and fix a bug
YasInvolved May 29, 2026
a57a7ec
add a concept for execution context types to prevent mistakes and mov…
YasInvolved May 30, 2026
9fd3134
make a getter for current thread context
YasInvolved May 30, 2026
722b35e
add new and delete operator overloads
YasInvolved May 30, 2026
d2296a1
fix memory aliasing bug
YasInvolved May 30, 2026
3d62d25
cosmetics: add missing license notices
YasInvolved May 30, 2026
7319a34
move operator overloads to the separate header included in pch
YasInvolved May 30, 2026
73e7ea1
wrappers for thread creation
YasInvolved May 30, 2026
75f93be
introduce semaphore sync primitive
YasInvolved May 30, 2026
1d426ee
fix memory config and add a semaphore to the worker context
YasInvolved May 30, 2026
ca2abc1
implement a basic worker loop
YasInvolved May 30, 2026
a933140
little compilation fixes
YasInvolved May 30, 2026
0438c0e
Extend ThreadContext API to fix a subtle bug
YasInvolved May 30, 2026
92ec9ab
correct workers initialization
YasInvolved May 30, 2026
c7fc252
fix task queue
YasInvolved May 30, 2026
7830221
initialize semaphores in contexts and fix thread creation
YasInvolved May 30, 2026
b72bd49
reset transient arenas in time
YasInvolved May 30, 2026
66f4004
remove switch-case from hello world game
YasInvolved May 30, 2026
9d08653
sleep func
YasInvolved May 31, 2026
af08e2d
some utilities to name threads
YasInvolved May 31, 2026
54ddab0
I'm too bored to describe this commit lol
YasInvolved May 31, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions Engine/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -27,6 +28,8 @@ 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
Expand All @@ -42,3 +45,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()
5 changes: 3 additions & 2 deletions Engine/include/delta/core/engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ 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 Update(Context& context);
DLT_API void Shutdown(Context& context);
}
21 changes: 21 additions & 0 deletions Engine/include/delta/core/memory.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#pragma once

#include <delta/definitions.h>

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); }
1 change: 1 addition & 0 deletions Engine/include/delta/pch.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
#include <cstddef>

#include <delta/definitions.h>
#include <delta/core/memory.h>
1 change: 0 additions & 1 deletion Engine/include/delta/platform/os.h
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down
73 changes: 59 additions & 14 deletions Engine/src/delta/core/EngineTypes.h
Original file line number Diff line number Diff line change
@@ -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 <delta/platform/os_internal.h>
Expand All @@ -18,42 +34,71 @@ namespace delta::core
uint8_t* backingMemory;
size_t capacity;
size_t offset;
size_t maxCapacity;
};

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<uint64_t> top;
alignas(64) std::atomic<uint64_t> bottom;
alignas(64) std::atomic<queue_index_t> top;
alignas(64) std::atomic<queue_index_t> 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;

static inline constexpr size_t FIELD_SIZE = sizeof(task_t) + sizeof(payload_t);
};

struct alignas(64) ThreadExecutionContext
enum class ThreadType : uint8_t { MAIN, WORKER };

struct alignas(64) GenericExecutionContext
{
// SHARED TRAITS
ThreadType type;
uint32_t threadIx;
uint32_t threadId;
delta::platform::ThreadHandle threadHandle;

ThreadPageCoordinator pageCoordinator;
TaskQueue taskQueue;
ThreadArena transientArena;
delta::platform::Timer perThreadTimer;
};

struct alignas(64) MainExecutionContext
{
// SHARED TRAITS
GenericExecutionContext generic;

alignas(64) ThreadArena transientArena;
ThreadArena componentPoolArena;
ThreadArena sceneArena;
// ROLE TRAITS
ThreadArena persistentStorage;
};

alignas(64) delta::platform::Timer perThreadTimer;
struct alignas(64) WorkerExecutionContext
{
GenericExecutionContext generic;

uint8_t hardwarePadding[32];
// ROLE TRAITS
TaskQueue taskQueue;
delta::platform::SemaphoreHandle sleepSemaphore;
std::atomic<bool> isAsleep;
std::atomic<bool> shouldClose;
};

extern thread_local ThreadExecutionContext* tl_CurrentThreadContext;
template <typename T>
concept ExecutionContext =
std::is_same_v<std::remove_cvref_t<T>, GenericExecutionContext> ||
std::is_same_v<std::remove_cvref_t<T>, MainExecutionContext> ||
std::is_same_v<std::remove_cvref_t<T>, WorkerExecutionContext>;

// COMPILE TIME CONSTANTS
inline constexpr size_t THREAD_EXECUTION_CONTEXT_STRIDE = std::max<size_t>(sizeof(MainExecutionContext), sizeof(WorkerExecutionContext));
inline constexpr size_t THREAD_EXECUTION_CONTEXT_SIZE = (THREAD_EXECUTION_CONTEXT_STRIDE + 63) & ~(63);

static_assert((sizeof(ThreadExecutionContext) % 64) == 0);
// EXTERN VARIABLES & FUNCTIONS
extern uintptr_t g_MasterSlabStart;
extern uintptr_t g_MasterSlabEnd;
}
26 changes: 22 additions & 4 deletions Engine/src/delta/core/MemoryConfig.cpp
Original file line number Diff line number Diff line change
@@ -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 <delta/platform/os.h>
Expand All @@ -7,17 +23,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::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;
Expand Down
93 changes: 62 additions & 31 deletions Engine/src/delta/core/MemoryConfig.h
Original file line number Diff line number Diff line change
@@ -1,43 +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.
*/

#pragma once

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
{
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
{
// QUEUE
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

// 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
Expand Down
Loading