Performance optimization
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
cmake_minimum_required(VERSION 3.28)
|
cmake_minimum_required(VERSION 3.18..3.28)
|
||||||
project(DemoGame
|
project(DemoGame
|
||||||
VERSION 1.0
|
VERSION 1.0
|
||||||
LANGUAGES CXX
|
LANGUAGES CXX
|
||||||
@@ -19,7 +19,12 @@ CPMAddPackage(
|
|||||||
|
|
||||||
CPMAddPackage(
|
CPMAddPackage(
|
||||||
NAME ReWindow
|
NAME ReWindow
|
||||||
URL https://git.redacted.cc/Redacted/ReWindow/archive/Prerelease-31.zip
|
URL https://git.redacted.cc/Redacted/ReWindow/archive/Prerelease-32.zip
|
||||||
|
)
|
||||||
|
|
||||||
|
CPMAddPackage(
|
||||||
|
NAME MultiThreading
|
||||||
|
URL https://git.redacted.cc/Redacted/MultiThreading/archive/prerelease-1.zip
|
||||||
)
|
)
|
||||||
|
|
||||||
#set(CMAKE_CXX_FLAGS "-O3 -Wall -Wextra")
|
#set(CMAKE_CXX_FLAGS "-O3 -Wall -Wextra")
|
||||||
@@ -30,9 +35,10 @@ file(COPY "assets" DESTINATION "${PROJECT_BINARY_DIR}")
|
|||||||
|
|
||||||
add_executable(DemoGame ${SOURCES} main.cpp)
|
add_executable(DemoGame ${SOURCES} main.cpp)
|
||||||
target_include_directories(DemoGame PUBLIC
|
target_include_directories(DemoGame PUBLIC
|
||||||
|
${MultiThreading_SOURCE_DIR}/include
|
||||||
${JGL_SOURCE_DIR}/include
|
${JGL_SOURCE_DIR}/include
|
||||||
${ReWindow_SOURCE_DIR}/include
|
${ReWindow_SOURCE_DIR}/include
|
||||||
${PROJECT_SOURCE_DIR}/include
|
${PROJECT_SOURCE_DIR}/include
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(DemoGame PUBLIC JGL ReWindowLibrary)
|
target_link_libraries(DemoGame PUBLIC JGL ReWindowLibrary MultiThreading)
|
||||||
|
@@ -1,24 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <thread>
|
|
||||||
#include <utility>
|
|
||||||
#include <atomic>
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
namespace Engine {
|
|
||||||
class ConcurrentWorker;
|
|
||||||
}
|
|
||||||
|
|
||||||
class Engine::ConcurrentWorker {
|
|
||||||
private:
|
|
||||||
std::atomic<bool> work_complete{ false };
|
|
||||||
std::thread worker_thread;
|
|
||||||
public:
|
|
||||||
[[nodiscard]] bool Done();
|
|
||||||
public:
|
|
||||||
~ConcurrentWorker();
|
|
||||||
|
|
||||||
template <typename Function, typename... Args>
|
|
||||||
explicit ConcurrentWorker(Function&& func, Args&&... args) : worker_thread([this, func = std::forward<Function>(func),
|
|
||||||
...args = std::forward<Args>(args)]() mutable { func(std::forward<Args>(args) ...); work_complete = true; })
|
|
||||||
{ worker_thread.detach(); }
|
|
||||||
};
|
|
@@ -1,24 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <vector>
|
|
||||||
#include <JGL/types/Texture.h>
|
|
||||||
|
|
||||||
namespace Engine {
|
|
||||||
class InstancedTexture;
|
|
||||||
class InstancedSprite;
|
|
||||||
}
|
|
||||||
|
|
||||||
class Engine::InstancedTexture {
|
|
||||||
protected:
|
|
||||||
JGL::Texture* texture = nullptr;
|
|
||||||
std::vector<const InstancedSprite*> users{};
|
|
||||||
public:
|
|
||||||
[[nodiscard]] size_t ReferenceCount() { return users.size(); }
|
|
||||||
[[nodiscard]] bool InUseBy(const InstancedSprite* rhs);
|
|
||||||
[[nodiscard]] JGL::Texture* GetTexture() const { return texture; }
|
|
||||||
public:
|
|
||||||
void AddUser(const InstancedSprite* user);
|
|
||||||
void RemoveUser(const InstancedSprite* user);
|
|
||||||
public:
|
|
||||||
InstancedTexture(JGL::Texture* texture, const InstancedSprite* creator) : texture(texture) { users.push_back(creator); }
|
|
||||||
~InstancedTexture();
|
|
||||||
};
|
|
@@ -1,13 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <Engine/types/InstancedTexture.h>
|
|
||||||
#include <Engine/types/entity/Entity.h>
|
#include <Engine/types/entity/Entity.h>
|
||||||
#include <Engine/types/entity/Hud.h>
|
#include <Engine/types/entity/Hud.h>
|
||||||
#include <JGL/types/RenderTarget.h>
|
#include <JGL/types/RenderTarget.h>
|
||||||
#include <Engine/types/ConcurrentWorker.h>
|
#include <MultiThreading/Thread.h>
|
||||||
#include <rewindow/types/window.h>
|
#include <rewindow/types/window.h>
|
||||||
|
#include <unordered_map>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
#include "Engine/types/entity/InstancedSprite.h"
|
||||||
|
|
||||||
namespace Engine {
|
namespace Engine {
|
||||||
class Camera;
|
class Camera;
|
||||||
@@ -24,12 +25,11 @@ protected:
|
|||||||
// 25ms.
|
// 25ms.
|
||||||
u8 tick_rate = 40;
|
u8 tick_rate = 40;
|
||||||
bool should_tick = true;
|
bool should_tick = true;
|
||||||
ConcurrentWorker* update_worker;
|
MultiThreading::Thread* update_worker;
|
||||||
std::string name;
|
std::string name;
|
||||||
Camera* active_camera = nullptr;
|
Camera* active_camera = nullptr;
|
||||||
Entity* entity_list = nullptr;
|
Entity* entity_list = nullptr;
|
||||||
std::vector<InstancedTexture*> instanced_textures{};
|
std::unordered_map<size_t, JGL::Texture*> instanced_textures{};
|
||||||
std::vector<InstancedTexture*> instanced_alpha_masks{};
|
|
||||||
protected:
|
protected:
|
||||||
virtual void Update();
|
virtual void Update();
|
||||||
virtual void Render();
|
virtual void Render();
|
||||||
@@ -38,8 +38,7 @@ public:
|
|||||||
[[nodiscard]] size_t EntityCount() const;
|
[[nodiscard]] size_t EntityCount() const;
|
||||||
[[nodiscard]] std::string GetName() const;
|
[[nodiscard]] std::string GetName() const;
|
||||||
[[nodiscard]] Camera* GetActiveCamera() const;
|
[[nodiscard]] Camera* GetActiveCamera() const;
|
||||||
[[nodiscard]] InstancedTexture* GetInstancedTexture(const InstancedSprite* user);
|
[[nodiscard]] JGL::Texture* GetInstancedTexture(const InstancedSprite* user);
|
||||||
[[nodiscard]] InstancedTexture* GetInstancedAlphaMask(const InstancedSprite* user);
|
|
||||||
[[nodiscard]] bool ShouldTick() const;
|
[[nodiscard]] bool ShouldTick() const;
|
||||||
[[nodiscard]] float TickDeltaTime() const;
|
[[nodiscard]] float TickDeltaTime() const;
|
||||||
[[nodiscard]] float FrameDeltaTime() const;
|
[[nodiscard]] float FrameDeltaTime() const;
|
||||||
@@ -49,8 +48,7 @@ public:
|
|||||||
public:
|
public:
|
||||||
void ShouldTick(bool state);
|
void ShouldTick(bool state);
|
||||||
void SetActiveCamera(Camera* camera) { active_camera = camera; };
|
void SetActiveCamera(Camera* camera) { active_camera = camera; };
|
||||||
void DestroyInstancedTexture(const InstancedTexture* itx);
|
void DestroyInstancedTexture(const InstancedSprite* itx);
|
||||||
void DestroyInstancedAlphaMask(const InstancedTexture* alpha_mask);
|
|
||||||
virtual void Unload();
|
virtual void Unload();
|
||||||
virtual void Init() {};
|
virtual void Init() {};
|
||||||
void Run();
|
void Run();
|
||||||
|
@@ -8,12 +8,9 @@ namespace Engine {
|
|||||||
class Engine::InstancedSprite : public Sprite {
|
class Engine::InstancedSprite : public Sprite {
|
||||||
private:
|
private:
|
||||||
std::string texture_path;
|
std::string texture_path;
|
||||||
std::string alpha_mask_path;
|
|
||||||
public:
|
public:
|
||||||
[[nodiscard]] std::string GetTextureFilesystemPath() const { return texture_path; }
|
[[nodiscard]] std::string GetTextureFilesystemPath() const { return texture_path; }
|
||||||
[[nodiscard]] std::string GetAlphaMaskFilesystemPath() const { return alpha_mask_path; }
|
|
||||||
[[nodiscard]] Texture* GetTexture() const override;
|
[[nodiscard]] Texture* GetTexture() const override;
|
||||||
[[nodiscard]] Texture* GetAlphaMask() const override;
|
|
||||||
public:
|
public:
|
||||||
/** The Texture *must* be instanced. The alpha-mask *can* be instanced.
|
/** The Texture *must* be instanced. The alpha-mask *can* be instanced.
|
||||||
* You can use SetAlphaMask() to change to a unique one.
|
* You can use SetAlphaMask() to change to a unique one.
|
||||||
@@ -24,6 +21,5 @@ public:
|
|||||||
~InstancedSprite() override;
|
~InstancedSprite() override;
|
||||||
InstancedSprite(const Vector2& position, unsigned int layer, const std::string& instanced_texture_filesystem_path,
|
InstancedSprite(const Vector2& position, unsigned int layer, const std::string& instanced_texture_filesystem_path,
|
||||||
const Vector2& origin = {0, 0}, float face_angle = 0.0f, const Color4& base_color = Colors::White, Texture* unique_alpha_mask = nullptr, const std::string& instanced_alpha_mask_filesystem_path = "")
|
const Vector2& origin = {0, 0}, float face_angle = 0.0f, const Color4& base_color = Colors::White, Texture* unique_alpha_mask = nullptr, const std::string& instanced_alpha_mask_filesystem_path = "")
|
||||||
: Sprite(position, origin, layer, face_angle, base_color, nullptr, unique_alpha_mask), texture_path(instanced_texture_filesystem_path),
|
: Sprite(position, origin, layer, face_angle, base_color, nullptr, unique_alpha_mask), texture_path(instanced_texture_filesystem_path) {}
|
||||||
alpha_mask_path(instanced_alpha_mask_filesystem_path) {}
|
|
||||||
};
|
};
|
||||||
|
@@ -5,7 +5,7 @@ class ControllableBox final : public Engine::Scene {
|
|||||||
public:
|
public:
|
||||||
void Init() final;
|
void Init() final;
|
||||||
public:
|
public:
|
||||||
explicit ControllableBox(const std::string& name) : Scene(name) {}
|
explicit ControllableBox(const std::string& name) : Scene(name, 64) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@@ -1,14 +0,0 @@
|
|||||||
#include <Engine/types/ConcurrentWorker.h>
|
|
||||||
#include <Engine/Logger.h>
|
|
||||||
|
|
||||||
using namespace Engine;
|
|
||||||
ConcurrentWorker::~ConcurrentWorker() {
|
|
||||||
if (!work_complete) {
|
|
||||||
std::stringstream thread_id; thread_id << worker_thread.get_id();
|
|
||||||
Logger::Fatal("ConcurrentWorker was destroyed for thread " + thread_id.str() + " but the work wasn't finished?");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ConcurrentWorker::Done() {
|
|
||||||
return work_complete;
|
|
||||||
}
|
|
@@ -1,31 +0,0 @@
|
|||||||
#include <Engine/types/InstancedTexture.h>
|
|
||||||
#include <Engine/types/entity/InstancedSprite.h>
|
|
||||||
|
|
||||||
using namespace Engine;
|
|
||||||
void InstancedTexture::AddUser(const InstancedSprite* user) {
|
|
||||||
// Prevent double references.
|
|
||||||
if (!InUseBy(user))
|
|
||||||
users.push_back(user);
|
|
||||||
}
|
|
||||||
|
|
||||||
void InstancedTexture::RemoveUser(const InstancedSprite* user) {
|
|
||||||
auto it = std::find(users.begin(), users.end(), user);
|
|
||||||
if (it != users.end())
|
|
||||||
users.erase(it);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool InstancedTexture::InUseBy(const InstancedSprite* rhs) {
|
|
||||||
if (users.empty())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (typeid(*users[0]) == typeid(*rhs))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
InstancedTexture::~InstancedTexture() {
|
|
||||||
delete texture;
|
|
||||||
for (const auto* is: users)
|
|
||||||
delete is;
|
|
||||||
}
|
|
@@ -2,6 +2,7 @@
|
|||||||
#include <Engine/types/Scene.h>
|
#include <Engine/types/Scene.h>
|
||||||
#include <Engine/types/entity/Camera.h>
|
#include <Engine/types/entity/Camera.h>
|
||||||
#include <Engine/types/entity/InstancedSprite.h>
|
#include <Engine/types/entity/InstancedSprite.h>
|
||||||
|
#include <MultiThreading/Thread.h>
|
||||||
#include <Engine/Logger.h>
|
#include <Engine/Logger.h>
|
||||||
#include <JGL/JGL.h>
|
#include <JGL/JGL.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@@ -93,15 +94,11 @@ Scene::~Scene() {
|
|||||||
|
|
||||||
void Scene::Unload() {
|
void Scene::Unload() {
|
||||||
destroying = true;
|
destroying = true;
|
||||||
while (!update_worker->Done()) {}
|
|
||||||
|
for (auto& itx : instanced_textures)
|
||||||
|
delete itx.second;
|
||||||
|
|
||||||
delete update_worker;
|
delete update_worker;
|
||||||
|
|
||||||
for (auto* itx : instanced_textures)
|
|
||||||
delete itx;
|
|
||||||
|
|
||||||
for (auto* a : instanced_alpha_masks)
|
|
||||||
delete a;
|
|
||||||
|
|
||||||
delete entity_list;
|
delete entity_list;
|
||||||
delete active_camera;
|
delete active_camera;
|
||||||
}
|
}
|
||||||
@@ -114,45 +111,26 @@ Camera* Scene::GetActiveCamera() const {
|
|||||||
return active_camera;
|
return active_camera;
|
||||||
}
|
}
|
||||||
|
|
||||||
InstancedTexture* Scene::GetInstancedTexture(const InstancedSprite* user) {
|
Texture* Scene::GetInstancedTexture(const InstancedSprite* user) {
|
||||||
for (auto* itx : instanced_textures)
|
auto it = instanced_textures.find(typeid(user).hash_code());
|
||||||
if (itx->InUseBy(user))
|
if (it != instanced_textures.end())
|
||||||
return itx;
|
return it->second;
|
||||||
|
|
||||||
auto* t = new Texture(user->GetTextureFilesystemPath());
|
auto* t = new Texture(user->GetTextureFilesystemPath());
|
||||||
auto* itx = new InstancedTexture(t, user);
|
instanced_textures.insert(std::make_pair(typeid(user).hash_code(), t));
|
||||||
instanced_textures.push_back(itx);
|
return t;
|
||||||
return itx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
InstancedTexture* Scene::GetInstancedAlphaMask(const InstancedSprite* user) {
|
void Scene::DestroyInstancedTexture(const InstancedSprite* user) {
|
||||||
for (auto* itx : instanced_alpha_masks)
|
auto it = instanced_textures.find(typeid(user).hash_code());
|
||||||
if (itx->InUseBy(user))
|
if (it != instanced_textures.end()) {
|
||||||
return itx;
|
delete it->second;
|
||||||
|
instanced_textures.erase(it);
|
||||||
if (!user->GetAlphaMaskFilesystemPath().empty()) {
|
|
||||||
auto *t = new Texture(user->GetAlphaMaskFilesystemPath());
|
|
||||||
auto *itx = new InstancedTexture(t, user);
|
|
||||||
instanced_alpha_masks.push_back(itx);
|
|
||||||
return itx;
|
|
||||||
}
|
}
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Scene::DestroyInstancedTexture(const InstancedTexture* itx) {
|
|
||||||
auto it = std::find(instanced_textures.begin(), instanced_textures.end(), itx);
|
|
||||||
if (it != instanced_textures.end())
|
|
||||||
delete *it, instanced_textures.erase(it);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Scene::DestroyInstancedAlphaMask(const Engine::InstancedTexture* alpha_mask) {
|
|
||||||
auto it = std::find(instanced_alpha_masks.begin(), instanced_alpha_masks.end(), alpha_mask);
|
|
||||||
if (it != instanced_alpha_masks.end())
|
|
||||||
delete *it, instanced_alpha_masks.erase(it);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scene::Run() {
|
void Scene::Run() {
|
||||||
update_worker = new ConcurrentWorker([this] { UpdateLoop(); });
|
update_worker = new MultiThreading::Thread([this] { UpdateLoop(); } );
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Scene::ShouldTick() const {
|
bool Scene::ShouldTick() const {
|
||||||
|
@@ -3,31 +3,9 @@
|
|||||||
|
|
||||||
using namespace Engine;
|
using namespace Engine;
|
||||||
Texture* InstancedSprite::GetTexture() const {
|
Texture* InstancedSprite::GetTexture() const {
|
||||||
auto* itx = GetScene()->GetInstancedTexture(this);
|
return GetScene()->GetInstancedTexture(this);
|
||||||
if (itx)
|
|
||||||
return itx->GetTexture();
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
Texture* InstancedSprite::GetAlphaMask() const {
|
|
||||||
auto* ita = GetScene()->GetInstancedAlphaMask(this);
|
|
||||||
if (ita)
|
|
||||||
return ita->GetTexture();
|
|
||||||
return Sprite::GetAlphaMask();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
InstancedSprite::~InstancedSprite() {
|
InstancedSprite::~InstancedSprite() {
|
||||||
auto* itx = GetScene()->GetInstancedTexture(this);
|
GetScene()->DestroyInstancedTexture(this);
|
||||||
if (itx) {
|
|
||||||
itx->RemoveUser(this);
|
|
||||||
if (itx->ReferenceCount() == 0)
|
|
||||||
GetScene()->DestroyInstancedTexture(itx);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto* ita = GetScene()->GetInstancedAlphaMask(this);
|
|
||||||
if (ita) {
|
|
||||||
ita->RemoveUser(this);
|
|
||||||
if (ita->ReferenceCount() == 0)
|
|
||||||
GetScene()->DestroyInstancedAlphaMask(ita);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
void ControllableBox::Init() {
|
void ControllableBox::Init() {
|
||||||
auto* hud = new Game::DemoGameHud();
|
auto* hud = new Game::DemoGameHud();
|
||||||
for (int i = 0; i < 1; i++) {
|
for (int i = 0; i < 10000; i++) {
|
||||||
auto *b = new Game::Box({0, 0});
|
auto *b = new Game::Box({0, 0});
|
||||||
entity_list->AppendChild(b);
|
entity_list->AppendChild(b);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user