mirror of
https://github.com/Kbz-8/42_vox.git
synced 2026-01-10 22:23:35 +00:00
fixing multithreading
This commit is contained in:
@@ -1,37 +0,0 @@
|
|||||||
#include <ThreadPool.h>
|
|
||||||
#include <ScopCore.h>
|
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
ThreadPool::ThreadPool() : m_concurency(std::max(std::thread::hardware_concurrency(), DEFAULT_CONCURENCY)), m_waiting_count(m_concurency)
|
|
||||||
{
|
|
||||||
for(std::size_t i = 0; i < m_concurency; i++)
|
|
||||||
{
|
|
||||||
m_pool.emplace_back([this]
|
|
||||||
{
|
|
||||||
using namespace std::chrono_literals;
|
|
||||||
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
if(m_stop)
|
|
||||||
return;
|
|
||||||
if(!m_tasks.IsEmpty())
|
|
||||||
{
|
|
||||||
std::function<void()> task = std::move(m_tasks.Pop());
|
|
||||||
m_waiting_count--;
|
|
||||||
task();
|
|
||||||
m_waiting_count++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
std::this_thread::sleep_for(10ms);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Scop::Message("ThreadPool started with a capacity of %", m_concurency);
|
|
||||||
}
|
|
||||||
|
|
||||||
ThreadPool::~ThreadPool()
|
|
||||||
{
|
|
||||||
m_stop = true;
|
|
||||||
for(auto& thread : m_pool)
|
|
||||||
thread.join();
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
#ifndef THREAD_POOL_H
|
|
||||||
#define THREAD_POOL_H
|
|
||||||
|
|
||||||
#include <thread>
|
|
||||||
#include <vector>
|
|
||||||
#include <functional>
|
|
||||||
#include <Utils.h>
|
|
||||||
|
|
||||||
constexpr std::uint32_t DEFAULT_CONCURENCY = 6;
|
|
||||||
|
|
||||||
class ThreadPool
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ThreadPool();
|
|
||||||
inline void EnqueueTask(std::function<void()> task) { m_tasks.Push(std::move(task)); }
|
|
||||||
inline void WaitForAllTasks() const
|
|
||||||
{
|
|
||||||
using namespace std::chrono_literals;
|
|
||||||
for(; m_waiting_count != m_concurency && !m_tasks.IsEmpty();)
|
|
||||||
std::this_thread::sleep_for(10ms);
|
|
||||||
}
|
|
||||||
~ThreadPool();
|
|
||||||
|
|
||||||
private:
|
|
||||||
ThreadSafeQueue<std::function<void()>> m_tasks;
|
|
||||||
std::vector<std::thread> m_pool;
|
|
||||||
std::uint32_t m_concurency;
|
|
||||||
std::atomic_uint32_t m_waiting_count;
|
|
||||||
std::atomic_bool m_stop = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -128,7 +128,6 @@ World::~World()
|
|||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
std::this_thread::sleep_for(16ms);
|
std::this_thread::sleep_for(16ms);
|
||||||
}
|
}
|
||||||
m_thread_pool.WaitForAllTasks();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] Scop::NonOwningPtr<const Chunk> World::GetChunk(Scop::Vec2i position) const
|
[[nodiscard]] Scop::NonOwningPtr<const Chunk> World::GetChunk(Scop::Vec2i position) const
|
||||||
@@ -166,7 +165,7 @@ void World::UnloadChunks()
|
|||||||
#define QUIT_CHECK() if(m_generation_status == GenerationState::Quitting) goto quit
|
#define QUIT_CHECK() if(m_generation_status == GenerationState::Quitting) goto quit
|
||||||
void World::GenerateWorld()
|
void World::GenerateWorld()
|
||||||
{
|
{
|
||||||
constexpr float LIMIT = 80.0f;
|
std::vector<std::thread> pool;
|
||||||
|
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
@@ -179,7 +178,7 @@ void World::GenerateWorld()
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::queue<std::reference_wrapper<Chunk>> mesh_generation_queue;
|
ThreadSafeQueue<std::reference_wrapper<Chunk>> mesh_generation_queue;
|
||||||
Scop::Vec2i current_chunk = m_current_chunk_position.load();
|
Scop::Vec2i current_chunk = m_current_chunk_position.load();
|
||||||
|
|
||||||
Scop::Vec2i x_range{
|
Scop::Vec2i x_range{
|
||||||
@@ -191,7 +190,7 @@ void World::GenerateWorld()
|
|||||||
current_chunk.y + RENDER_DISTANCE + 1
|
current_chunk.y + RENDER_DISTANCE + 1
|
||||||
};
|
};
|
||||||
|
|
||||||
std::size_t range = (RENDER_DISTANCE + RENDER_DISTANCE + 2) * 2;
|
std::size_t range = ((x_range.y - x_range.x) * (z_range.y - z_range.x));
|
||||||
|
|
||||||
m_loading_progress = 0.0f;
|
m_loading_progress = 0.0f;
|
||||||
|
|
||||||
@@ -201,39 +200,67 @@ void World::GenerateWorld()
|
|||||||
{
|
{
|
||||||
QUIT_CHECK();
|
QUIT_CHECK();
|
||||||
|
|
||||||
std::unordered_map<Scop::Vec2i, Chunk>::iterator chunk_data;
|
|
||||||
{
|
{
|
||||||
std::unique_lock guard(m_chunk_mutex);
|
std::unique_lock guard(m_chunk_mutex);
|
||||||
chunk_data = m_chunks.try_emplace(Scop::Vec2i{ x, z }, *this, Scop::Vec2i{ x, z }).first;
|
m_chunks.try_emplace(Scop::Vec2i{ x, z }, *this, Scop::Vec2i{ x, z });
|
||||||
}
|
}
|
||||||
chunk_data->second.GenerateChunk();
|
|
||||||
if(!chunk_data->second.GetActor() && !chunk_data->second.GetWaterActor() && x > x_range.x && x < x_range.y && z > z_range.x && z < z_range.y)
|
|
||||||
mesh_generation_queue.push(std::ref(chunk_data->second));
|
|
||||||
|
|
||||||
m_loading_progress = std::min(m_loading_progress + (1.0f / LIMIT) * range, LIMIT);
|
if(pool.size() >= std::max(std::thread::hardware_concurrency(), 4u))
|
||||||
|
{
|
||||||
|
for(auto& thread : pool)
|
||||||
|
thread.join();
|
||||||
|
pool.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
Chunk& chunk = m_chunks.at(Scop::Vec2i{ x, z });
|
||||||
|
pool.emplace_back([this, &chunk, range, x, z, x_range, z_range, &mesh_generation_queue]
|
||||||
|
{
|
||||||
|
chunk.GenerateChunk();
|
||||||
|
if(!chunk.GetActor() && !chunk.GetWaterActor() && x > x_range.x && x < x_range.y && z > z_range.x && z < z_range.y)
|
||||||
|
mesh_generation_queue.Push(std::ref(chunk));
|
||||||
|
m_loading_progress = std::min(m_loading_progress + ((1.0f / range) * 50.0f), 50.0f);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for(auto& thread : pool)
|
||||||
|
thread.join();
|
||||||
|
pool.clear();
|
||||||
|
|
||||||
QUIT_CHECK();
|
QUIT_CHECK();
|
||||||
|
|
||||||
while(!mesh_generation_queue.empty())
|
while(!mesh_generation_queue.IsEmpty())
|
||||||
{
|
{
|
||||||
auto& chunk = mesh_generation_queue.front().get();
|
QUIT_CHECK();
|
||||||
mesh_generation_queue.pop();
|
auto& chunk = mesh_generation_queue.Pop().get();
|
||||||
|
|
||||||
m_thread_pool.EnqueueTask([this, &chunk, range]
|
if(pool.size() >= std::max(std::thread::hardware_concurrency(), 4u))
|
||||||
|
{
|
||||||
|
for(auto& thread : pool)
|
||||||
|
thread.join();
|
||||||
|
pool.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
pool.emplace_back([this, &chunk, range]
|
||||||
{
|
{
|
||||||
chunk.GenerateMesh();
|
chunk.GenerateMesh();
|
||||||
m_chunks_to_upload.Push(chunk);
|
m_chunks_to_upload.Push(chunk);
|
||||||
m_loading_progress = std::min(m_loading_progress + (1.0f / (100.0f - LIMIT)) * range, 100.0f);
|
m_loading_progress = std::min(m_loading_progress + ((1.0f / range) * 50.0f), 99.0f);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
m_thread_pool.WaitForAllTasks();
|
for(auto& thread : pool)
|
||||||
|
thread.join();
|
||||||
|
pool.clear();
|
||||||
|
|
||||||
|
m_loading_progress = 100.0f;
|
||||||
|
|
||||||
m_generation_status = GenerationState::Finished;
|
m_generation_status = GenerationState::Finished;
|
||||||
}
|
}
|
||||||
|
|
||||||
quit:
|
quit:
|
||||||
|
for(auto& thread : pool)
|
||||||
|
thread.join();
|
||||||
m_generation_status = GenerationState::Finished;
|
m_generation_status = GenerationState::Finished;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
#include <Chunk.h>
|
#include <Chunk.h>
|
||||||
#include <Utils.h>
|
#include <Utils.h>
|
||||||
#include <FpsCounter.h>
|
#include <FpsCounter.h>
|
||||||
#include <ThreadPool.h>
|
|
||||||
#include <NoiseCollection.h>
|
#include <NoiseCollection.h>
|
||||||
|
|
||||||
constexpr std::uint8_t RENDER_DISTANCE = 15;
|
constexpr std::uint8_t RENDER_DISTANCE = 15;
|
||||||
@@ -53,7 +52,6 @@ class World
|
|||||||
private:
|
private:
|
||||||
NoiseCollection m_noisecollection;
|
NoiseCollection m_noisecollection;
|
||||||
FpsCounter m_fps_counter;
|
FpsCounter m_fps_counter;
|
||||||
ThreadPool m_thread_pool;
|
|
||||||
std::unordered_map<Scop::Vec2i, Chunk> m_chunks;
|
std::unordered_map<Scop::Vec2i, Chunk> m_chunks;
|
||||||
ThreadSafeQueue<std::reference_wrapper<Chunk>> m_chunks_to_upload;
|
ThreadSafeQueue<std::reference_wrapper<Chunk>> m_chunks_to_upload;
|
||||||
std::shared_ptr<Scop::Material> p_block_material;
|
std::shared_ptr<Scop::Material> p_block_material;
|
||||||
|
|||||||
7
Makefile
7
Makefile
@@ -19,6 +19,7 @@ CXXFLAGS = -std=c++20 -I ScopEngine/Runtime/Includes -I Application -I ScopEngin
|
|||||||
LDFLAGS = -lSDL2 ScopEngine/Bin/engine.a -latomic
|
LDFLAGS = -lSDL2 ScopEngine/Bin/engine.a -latomic
|
||||||
|
|
||||||
DEBUG ?= false
|
DEBUG ?= false
|
||||||
|
VOX_DEBUG ?= false
|
||||||
TSAN ?= false
|
TSAN ?= false
|
||||||
MODE = "release"
|
MODE = "release"
|
||||||
|
|
||||||
@@ -36,7 +37,11 @@ _GRAY := $(shell $(TPUT) setaf 8)
|
|||||||
_PURPLE := $(shell $(TPUT) setaf 5)
|
_PURPLE := $(shell $(TPUT) setaf 5)
|
||||||
|
|
||||||
ifeq ($(DEBUG), true)
|
ifeq ($(DEBUG), true)
|
||||||
CXXFLAGS += -g -D DEBUG
|
CXXFLAGS += -g -D VOX_DEBUG
|
||||||
|
MODE := $(_RESET)$(_PURPLE)$(_BOLD)Debug$(_RESET)$(_PURPLE)
|
||||||
|
COLOR := $(_PURPLE)
|
||||||
|
else ifeq ($(VOX_DEBUG), true)
|
||||||
|
CXXFLAGS += -g -D VOX_DEBUG
|
||||||
MODE := $(_RESET)$(_PURPLE)$(_BOLD)Debug$(_RESET)$(_PURPLE)
|
MODE := $(_RESET)$(_PURPLE)$(_BOLD)Debug$(_RESET)$(_PURPLE)
|
||||||
COLOR := $(_PURPLE)
|
COLOR := $(_PURPLE)
|
||||||
else
|
else
|
||||||
|
|||||||
Reference in New Issue
Block a user