Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,6 @@
[submodule "3rdparty/SDL/SDL"]
path = 3rdparty/SDL/SDL
url = https://github.com/libsdl-org/SDL.git
[submodule "3rdparty/vgjs/vgjs"]
path = 3rdparty/vgjs/vgjs
url = https://github.com/tuguzT/ViennaGameJobSystem.git
1 change: 1 addition & 0 deletions 3rdparty/vgjs/vgjs
Submodule vgjs added at cd9aad
12 changes: 9 additions & 3 deletions GAME/source/GAME/Layers/MainGameLayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,19 @@ namespace soge_game
void MainGameLayer::OnUpdate()
{
const auto engine = soge::Engine::GetInstance();
if (const auto inputModule = engine->GetModule<soge::InputModule>(); inputModule->IsKeyPressed(soge::Keys::W))
const auto inputModule = engine->GetModule<soge::InputModule>();
if (inputModule == nullptr)
{
SOGE_APP_INFO_LOG("Key W pressed!");
return;
}

if (inputModule->IsKeyPressed(soge::Keys::W))
{
SOGE_APP_INFO_LOG("Key W pressed...");
}
else if (inputModule->IsKeyPressed(soge::Keys::Escape))
{
SOGE_APP_INFO_LOG("Key Escape pressed - shutting down!");
SOGE_APP_INFO_LOG("Key Escape pressed: shutting down...");
engine->RequestShutdown();
}
}
Expand Down
5 changes: 4 additions & 1 deletion SOGE/include/SOGE/Core/Engine.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#ifndef SOGE_CORE_ENGINE_HPP
#define SOGE_CORE_ENGINE_HPP

#include "SOGE/Core/JobSystem.hpp"
#include "SOGE/Core/LayerStack.hpp"
#include "SOGE/Core/ModuleManager.hpp"
#include "SOGE/DI/Container.hpp"
Expand All @@ -20,10 +21,12 @@ namespace soge
static UniquePtr<Engine> s_instance;
static std::mutex s_mutex;

LayerStack m_renderLayers;
bool m_isRunning;
std::atomic_bool m_shutdownRequested;

LayerStack m_renderLayers;
JobSystem* m_jobSystem;

di::Container m_container;
ModuleManager m_moduleManager;

Expand Down
21 changes: 21 additions & 0 deletions SOGE/include/SOGE/Core/EntryPoint.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,33 @@ namespace soge
[[nodiscard]]
inline int Launch(const std::span<char*> args)
{
class JobSystemGuard
{
public:
explicit JobSystemGuard(const std::uint16_t aThreadCount = 0)
{
JobSystem::Initialize(aThreadCount);
}

explicit JobSystemGuard(const JobSystemGuard&) = delete;
JobSystemGuard& operator=(const JobSystemGuard&) = delete;

explicit JobSystemGuard(JobSystemGuard&&) = delete;
JobSystemGuard& operator=(JobSystemGuard&&) = delete;

~JobSystemGuard()
{
JobSystem::Terminate();
}
};

if (!ConsoleInit(args))
{
return EXIT_FAILURE;
}

Logger::Init();
JobSystemGuard jobSystemGuard;

const auto app = CreateApplication();
app->Run();
Expand Down
41 changes: 41 additions & 0 deletions SOGE/include/SOGE/Core/JobSystem.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#ifndef SOGE_CORE_JOBSYSTEM_HPP
#define SOGE_CORE_JOBSYSTEM_HPP

#include "SOGE/DI/Dependency.hpp"
#include "SOGE/System/Memory.hpp"


namespace soge
{
class JobSystem final
{
private:
class Impl;

UniquePtr<Impl> m_impl;

public:
static void Initialize(std::uint16_t aThreadCount = 0);
static void Terminate();

explicit JobSystem();

explicit JobSystem(const JobSystem&) = delete;
JobSystem& operator=(const JobSystem&) = delete;

explicit JobSystem(JobSystem&&) noexcept = default;
JobSystem& operator=(JobSystem&&) noexcept = default;

~JobSystem();

[[nodiscard]]
std::uint16_t GetThreadCount();

void Schedule(std::function<void()> aJob);
void Wait();
};
}

SOGE_DI_REGISTER_NS(soge, JobSystem, df::Single<JobSystem>, tag::Final<JobSystem>)

#endif // SOGE_CORE_JOBSYSTEM_HPP
9 changes: 8 additions & 1 deletion SOGE/source/SOGE/Core/Engine.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "sogepch.hpp"

#include "SOGE/Core/Engine.hpp"

#include "SOGE/Core/Timestep.hpp"
#include "SOGE/Event/EventModule.hpp"
#include "SOGE/Input/InputModule.hpp"
Expand Down Expand Up @@ -37,7 +38,7 @@ namespace soge
return s_instance.get();
}

Engine::Engine(AccessTag) : m_isRunning(false), m_shutdownRequested(false)
Engine::Engine(AccessTag) : m_isRunning(false), m_shutdownRequested(false), m_jobSystem(nullptr)
{
SOGE_INFO_LOG("Initialize engine...");

Expand Down Expand Up @@ -70,6 +71,8 @@ namespace soge
std::lock_guard lock(s_mutex);
constexpr AccessTag tag;

m_jobSystem = &m_container.Provide<JobSystem>();

m_isRunning = true;
for (Module& module : m_moduleManager)
{
Expand All @@ -96,6 +99,9 @@ namespace soge
{
layer->OnUpdate();
}

m_jobSystem->Schedule([] { SOGE_INFO_LOG("Delta time is: {}", Timestep::DeltaTime()); });
m_jobSystem->Wait();
}

Unload(tag);
Expand All @@ -106,6 +112,7 @@ namespace soge
m_isRunning = false;
m_removedModules.clear();
m_container.Clear();
m_jobSystem = nullptr;
}

bool Engine::IsRunning() const
Expand Down
143 changes: 143 additions & 0 deletions SOGE/source/SOGE/Core/JobSystem.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
#include "sogepch.hpp"

#include "SOGE/Core/JobSystem.hpp"

#include <VGJS.h>
#include <VGJSCoro.h>


namespace
{
constexpr std::size_t g_jobSystemMaxBlocksPerChunk = 1 << 10;
constexpr std::size_t g_jobSystemLargestRequiredPoolBlock = 1 << 10;

std::pmr::synchronized_pool_resource g_jobSystemMemoryResource{
std::pmr::pool_options{
.max_blocks_per_chunk = g_jobSystemMaxBlocksPerChunk,
.largest_required_pool_block = g_jobSystemLargestRequiredPoolBlock,
},
std::pmr::new_delete_resource(),
};
}

namespace soge
{
class JobSystem::Impl
{
private:
friend JobSystem;

static std::uint64_t CreateInstanceId()
{
static std::uint64_t instanceId = 0;
return instanceId++;
}

const std::uint64_t m_instanceId;
std::atomic_uint64_t m_jobCount;
std::atomic_bool m_allJobsCompleted;

public:
explicit Impl();

explicit Impl(const Impl&) = delete;
Impl& operator=(const Impl&) = delete;

explicit Impl(Impl&&) = delete;
Impl& operator=(Impl&&) = delete;

~Impl() = default;
};

JobSystem::Impl::Impl() : m_instanceId(CreateInstanceId())
{
}

void JobSystem::Initialize(const std::uint16_t aThreadCount)
{
if (aThreadCount == 0)
{
SOGE_INFO_LOG("Initializing job system with default thread count...");
}
else
{
SOGE_INFO_LOG("Initializing job system with thread count of {}...", aThreadCount);
}

const vgjs::thread_count_t threadCount{aThreadCount};
const vgjs::thread_index_t threadIndex{0};
vgjs::JobSystem jobSystem{threadCount, threadIndex, &g_jobSystemMemoryResource};

SOGE_INFO_LOG("Job system initialized successfully with thread count of {}!",
jobSystem.get_thread_count().value);
}

void JobSystem::Terminate()
{
SOGE_INFO_LOG("Cleaning up job system...");

vgjs::JobSystem jobSystem;
jobSystem.terminate();
jobSystem.wait_for_termination();
}

JobSystem::JobSystem() : m_impl(CreateUnique<Impl>())
{
}

JobSystem::~JobSystem()
{
Wait();
}

std::uint16_t JobSystem::GetThreadCount()
{
vgjs::JobSystem jobSystem;
return static_cast<std::uint16_t>(jobSystem.get_thread_count().value);
}

void JobSystem::Schedule(std::function<void()> aJob)
{
// For better debugging experience
Impl& impl = *m_impl;

// Register job for this job system instance
++impl.m_jobCount;

vgjs::Function job{
[job = std::move(aJob), &impl] {
job();

// Unregister job from this job system instance
--impl.m_jobCount;

// Notify all waiting threads that all jobs were completed
if (impl.m_jobCount == 0)
{
impl.m_allJobsCompleted = true;
impl.m_allJobsCompleted.notify_all();
}
},
vgjs::thread_index_t{}, // could be useful
};

vgjs::JobSystem jobSystem;
jobSystem.schedule(std::move(job));
}

void JobSystem::Wait()
{
// For better debugging experience
Impl& impl = *m_impl;

// Fast path: nothing to wait
if (impl.m_jobCount == 0)
{
return;
}

// Slow path: atomic wait
impl.m_allJobsCompleted.wait(false);
impl.m_allJobsCompleted = false;
}
}
4 changes: 2 additions & 2 deletions dependencies.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

-- Include directories
IncludeThirdpartyDirs = {}
IncludeThirdpartyDirs["spdlog"] = "3rdparty/spdlog/spdlog/include"
Expand All @@ -9,6 +8,7 @@ IncludeThirdpartyDirs["UUID_v4"] = "3rdparty/uuid_v4/uuid_v4/include"
IncludeThirdpartyDirs["eventpp"] = "3rdparty/eventpp/eventpp/include"
IncludeThirdpartyDirs["kangaru"] = "3rdparty/kangaru/kangaru/include"
IncludeThirdpartyDirs["SDL3"] = "3rdparty/SDL/SDL/include"
IncludeThirdpartyDirs["vgjs"] = "3rdparty/vgjs/vgjs/include"

-- Include libs
Libraries = {}
Expand All @@ -18,4 +18,4 @@ Libraries["SDL3_LIB_D"] = "3rdparty/SDL/lib/Debug/SDL3.lib"

Libraries["SDL_UCLIB_R"] = "3rdparty/SDL/lib/Release/SDL_uclibc.lib"
Libraries["SDL3_DLL_R"] = "3rdparty/SDL/lib/Release/SDL3.dll"
Libraries["SDL3_LIB_R"] = "3rdparty/SDL/lib/Release/SDL3.lib"
Libraries["SDL3_LIB_R"] = "3rdparty/SDL/lib/Release/SDL3.lib"
6 changes: 4 additions & 2 deletions premake5.lua
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ workspace "SOGE"
"%{wks.location}/%{IncludeThirdpartyDirs.eventpp}",
"%{wks.location}/%{IncludeThirdpartyDirs.kangaru}",
"%{wks.location}/%{IncludeThirdpartyDirs.eventpp}",
"%{wks.location}/%{IncludeThirdpartyDirs.SDL3}"
"%{wks.location}/%{IncludeThirdpartyDirs.SDL3}",
"%{wks.location}/%{IncludeThirdpartyDirs.vgjs}"
}

defines
Expand Down Expand Up @@ -150,7 +151,8 @@ workspace "SOGE"
"%{wks.location}/%{IncludeThirdpartyDirs.eventpp}",
"%{wks.location}/%{IncludeThirdpartyDirs.kangaru}",
"%{wks.location}/%{IncludeThirdpartyDirs.eventpp}",
"%{wks.location}/%{IncludeThirdpartyDirs.SDL3}"
"%{wks.location}/%{IncludeThirdpartyDirs.SDL3}",
"%{wks.location}/%{IncludeThirdpartyDirs.vgjs}"
}

links
Expand Down