diff --git a/CMakeLists.txt b/CMakeLists.txt index bc1f0bc..70d2044 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,7 +39,6 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_CURRENT_SOURCE_DIR}/bi find_package(Vulkan REQUIRED) find_package(assimp CONFIG REQUIRED) find_package(Stb REQUIRED) -find_package(thread-pool CONFIG REQUIRED) find_package(EnTT CONFIG REQUIRED) find_package(FreeType CONFIG REQUIRED) find_package(glfw3 CONFIG REQUIRED) @@ -67,7 +66,6 @@ target_link_libraries(Engine PUBLIC freetype) target_link_libraries(Engine PUBLIC assimp::assimp) target_link_libraries(Engine PUBLIC KTX::ktx) target_link_libraries(Engine PUBLIC nlohmann_json::nlohmann_json) -target_link_libraries(Engine PUBLIC dp::thread-pool) target_link_libraries(Engine PUBLIC crcpp) target_link_libraries(Engine PUBLIC shader-slang) if(UNIX) diff --git a/src/Editor/Window/SceneView.h b/src/Editor/Window/SceneView.h index d3ce57f..b98ecbf 100644 --- a/src/Editor/Window/SceneView.h +++ b/src/Editor/Window/SceneView.h @@ -1,5 +1,5 @@ #pragma once -#include +#include "ThreadPool.h" #include "Window/View.h" #include "Graphics/RenderPass/DepthPrepass.h" #include "Graphics/RenderPass/LightCullingPass.h" @@ -34,7 +34,7 @@ private: LightCullingPass, BasePass> renderGraph; - dp::thread_pool<> pool; + ThreadPool pool; ViewportControl cameraSystem; virtual void keyCallback(KeyCode code, InputAction action, KeyModifier modifier) override; diff --git a/src/Engine/CMakeLists.txt b/src/Engine/CMakeLists.txt index 286b318..b083a6c 100644 --- a/src/Engine/CMakeLists.txt +++ b/src/Engine/CMakeLists.txt @@ -3,7 +3,9 @@ target_sources(Engine Concepts.h EngineTypes.h Game.h - MinimalEngine.h) + MinimalEngine.h + ThreadPool.h + ThreadPool.cpp) target_sources(Engine PUBLIC FILE_SET HEADERS @@ -11,7 +13,8 @@ target_sources(Engine Concepts.h Game.h EngineTypes.h - MinimalEngine.h) + MinimalEngine.h + ThreadPool.h) add_subdirectory(Actor/) add_subdirectory(Asset/) diff --git a/src/Engine/Containers/List.h b/src/Engine/Containers/List.h index 426637d..dc56f38 100644 --- a/src/Engine/Containers/List.h +++ b/src/Engine/Containers/List.h @@ -179,6 +179,7 @@ public: , _size(std::move(other._size)) , allocator(std::move(other.allocator)) { + other._size = 0; } List(List&& other, const Allocator& alloc) : root(std::move(other.root)) @@ -188,7 +189,7 @@ public: , _size(std::move(other._size)) , allocator(allocator) { - other.clear(); + other._size = 0; } ~List() { diff --git a/src/Engine/Graphics/VertexData.cpp b/src/Engine/Graphics/VertexData.cpp index 81dc59d..3a6e7e5 100644 --- a/src/Engine/Graphics/VertexData.cpp +++ b/src/Engine/Graphics/VertexData.cpp @@ -14,6 +14,7 @@ constexpr static uint64 NUM_DEFAULT_ELEMENTS = 1024 * 1024; void VertexData::resetMeshData() { + std::unique_lock l(materialDataLock); for (auto& [_, mat] : materialData) { mat.material->getDescriptorLayout()->reset(); @@ -28,11 +29,12 @@ void VertexData::resetMeshData() void VertexData::updateMesh(PMesh mesh, Component::Transform& transform) { + std::unique_lock l(materialDataLock); PMaterial mat = mesh->referencedMaterial->getHandle()->getBaseMaterial(); MaterialData& matData = materialData[mat->getName()]; matData.material = mat; MaterialInstanceData& matInstanceData = matData.instances[mesh->referencedMaterial->getHandle()->getId()]; - for (auto& data : meshData[mesh->id]) + for (const auto& data : meshData[mesh->id]) { matInstanceData.meshes.add(MeshInstanceData{ .instance = InstanceData { @@ -46,6 +48,7 @@ void VertexData::updateMesh(PMesh mesh, Component::Transform& transform) void VertexData::createDescriptors() { + std::unique_lock l(materialDataLock); instanceDataLayout->reset(); for (const auto& [_, mat] : materialData) { diff --git a/src/Engine/Graphics/VertexData.h b/src/Engine/Graphics/VertexData.h index fec4d54..10578fa 100644 --- a/src/Engine/Graphics/VertexData.h +++ b/src/Engine/Graphics/VertexData.h @@ -100,6 +100,7 @@ protected: uint32_t vertexOffset; uint32_t primitiveOffset; }; + std::mutex materialDataLock; Map materialData; Map> meshData; Map meshOffsets; diff --git a/src/Engine/System/ComponentSystem.h b/src/Engine/System/ComponentSystem.h index 7f922a7..86bcebc 100644 --- a/src/Engine/System/ComponentSystem.h +++ b/src/Engine/System/ComponentSystem.h @@ -28,25 +28,29 @@ public: { return (deps | ...); } - void setupView(Dependencies<>, dp::thread_pool<>&) + void setupView(Dependencies<>, ThreadPool& pool) { + List> work; registry.view().each([&](Components&... comp){ - //pool.enqueue_detach([&](){ + work.add([&](){ update(comp...); - //}); + }); }); + pool.runAndWait(std::move(work)); } template - void setupView(Dependencies, dp::thread_pool<>&) + void setupView(Dependencies, ThreadPool& pool) { + List> work; registry.view().each([&](Components&... comp, Deps&... deps){ - //pool.enqueue_detach([&](){ + work.add([&]() { (accessComponent(deps) + ...); update((comp,...)); - //}); + }); }); + pool.runAndWait(std::move(work)); } - virtual void run(dp::thread_pool<>& pool, double delta) override + virtual void run(ThreadPool& pool, double delta) override { SystemBase::run(pool, delta); setupView(mergeDependencies((getDependencies(),...)), pool); diff --git a/src/Engine/System/Executor.h b/src/Engine/System/Executor.h index 9312950..cc6014c 100644 --- a/src/Engine/System/Executor.h +++ b/src/Engine/System/Executor.h @@ -1,7 +1,6 @@ #pragma once #include "MinimalEngine.h" #include "SystemBase.h" -#include namespace Seele { @@ -13,7 +12,7 @@ public: Executor(); ~Executor(); private: - dp::thread_pool<> pool; + ThreadPool pool; }; } // namespace System } // namespace Seele diff --git a/src/Engine/System/SystemBase.h b/src/Engine/System/SystemBase.h index 86383ac..9b7880b 100644 --- a/src/Engine/System/SystemBase.h +++ b/src/Engine/System/SystemBase.h @@ -1,6 +1,6 @@ #pragma once -#include #include +#include "ThreadPool.h" #include "Scene/Scene.h" namespace Seele @@ -12,7 +12,7 @@ class SystemBase public: SystemBase(PScene scene) : registry(scene->registry), scene(scene) {} virtual ~SystemBase() {} - virtual void run(dp::thread_pool<>&, double delta) + virtual void run(ThreadPool& pool, double delta) { deltaTime = delta; update(); diff --git a/src/Engine/System/SystemGraph.cpp b/src/Engine/System/SystemGraph.cpp index 51f53d5..047d5d3 100644 --- a/src/Engine/System/SystemGraph.cpp +++ b/src/Engine/System/SystemGraph.cpp @@ -7,7 +7,7 @@ void SystemGraph::addSystem(System::OSystemBase system) systems.add(std::move(system)); } -void SystemGraph::run(dp::thread_pool<>& threadPool, float deltaTime) +void SystemGraph::run(ThreadPool& threadPool, float deltaTime) { for(auto& system : systems) { system->run(threadPool, deltaTime); diff --git a/src/Engine/System/SystemGraph.h b/src/Engine/System/SystemGraph.h index d38e817..d294350 100644 --- a/src/Engine/System/SystemGraph.h +++ b/src/Engine/System/SystemGraph.h @@ -1,4 +1,5 @@ #pragma once +#include "ThreadPool.h" #include "Containers/Array.h" #include "SystemBase.h" @@ -8,7 +9,7 @@ class SystemGraph { public: void addSystem(System::OSystemBase system); - void run(dp::thread_pool<>& threadPool, float deltaTime); + void run(ThreadPool& threadPool, float deltaTime); private: Array systems; }; diff --git a/src/Engine/ThreadPool.cpp b/src/Engine/ThreadPool.cpp index 840273d..ee1f121 100644 --- a/src/Engine/ThreadPool.cpp +++ b/src/Engine/ThreadPool.cpp @@ -1,224 +1,66 @@ #include "ThreadPool.h" -#include using namespace Seele; -std::mutex Seele::promisesLock; -List Seele::promises; - -//Event::Event(nullptr_t) -//{ -//} - -Event::Event(const std::string &name, const std::source_location &location) - : state(std::make_shared()) +ThreadPool::ThreadPool(uint32 numWorkers) { - state->name = name; - state->location = location; -} - -Event::Event(const std::source_location &location) - : state(std::make_shared()) -{ - state->name = location.function_name(); - state->location = location; -} - -Event::Event(const Event& other) -{ - std::scoped_lock lock(other.eventLock); - state = other.state; -} - -Event::Event(Event&& other) -{ - std::scoped_lock lock(other.eventLock); - state = std::move(other.state); -} - -Event& Event::operator=(const Event& other) -{ - if(this != &other) + for (uint32 i = 0; i < numWorkers; ++i) { - std::scoped_lock lock(eventLock, other.eventLock); - state = other.state; - } - return *this; -} -Event& Event::operator=(Event&& other) -{ - if(this != &other) - { - std::scoped_lock lock(eventLock, other.eventLock); - state = std::move(other.state); - } - return *this; -} - -void Event::raise() -{ - std::scoped_lock lock(eventLock); - state->data = true; - if(state->waitingJobs.size() > 0) - { - getGlobalThreadPool().scheduleBatch(state->waitingJobs); - state->waitingJobs.clear(); - } - if(state->waitingMainJobs.size() > 0) - { - getGlobalThreadPool().scheduleBatch(state->waitingMainJobs); - state->waitingMainJobs.clear(); - } -} -void Event::reset() -{ - std::scoped_lock lock(eventLock); - state->data = false; -} - -bool Event::await_ready() -{ - eventLock.lock(); - bool result = state->data; - if(result) - { - eventLock.unlock(); - } - return result; -} - -void Event::await_suspend(std::coroutine_handle> h) -{ - state->waitingJobs.add(JobBase(&h.promise())); - eventLock.unlock(); -} - -void Event::await_suspend(std::coroutine_handle> h) -{ - state->waitingMainJobs.add(JobBase(&h.promise())); - eventLock.unlock(); -} - -ThreadPool::ThreadPool(uint32 threadCount) - : workers(threadCount) -{ - running.store(true); - for (uint32 i = 0; i < threadCount; ++i) - { - workers[i] = std::thread(&ThreadPool::threadLoop, this); + workers.add(std::thread(&ThreadPool::work, this)); } } ThreadPool::~ThreadPool() { - running.store(false); { - std::unique_lock lock(mainJobLock); - mainJobCV.notify_all(); + std::unique_lock l(taskLock); + running = false; + taskCV.notify_all(); } - { - std::unique_lock lock(jobQueueLock); - jobQueueCV.notify_all(); - } - for(auto& worker : workers) + for (auto& worker : workers) { worker.join(); } } -void ThreadPool::waitIdle() +void ThreadPool::runAndWait(List> functions) { - while(true) { - std::unique_lock lock(numIdlingLock); - if(numIdling == workers.size()) - { - assert(promises.size() == 0); - return; - } - numIdlingIncr.wait(lock); + std::unique_lock l(taskLock); + currentTask.numRemaining = functions.size(); + currentTask.functions = std::move(functions); + taskCV.notify_all(); } -} -void ThreadPool::scheduleJob(Job job) -{ - assert(!job.done()); - std::scoped_lock lock(jobQueueLock); - jobQueue.add(std::move(job)); - jobQueueCV.notify_one(); -} -void ThreadPool::scheduleJob(MainJob job) -{ - assert(!job.done()); - std::scoped_lock lock(mainJobLock); - mainJobs.add(std::move(job)); - mainJobCV.notify_one(); -} -void ThreadPool::mainLoop() -{ - while(running.load()) + while (currentTask.numRemaining > 0) { - MainJob job; - { - std::unique_lock lock(mainJobLock); - if(mainJobs.empty()) - { - mainJobCV.wait(lock); - } - [[likely]] - if(!mainJobs.empty()) - { - job = mainJobs.front(); - mainJobs.popFront(); - } - else - { - continue; - } - } - job.resume(); + std::unique_lock l2(completedLock); + completedCV.wait(l2); } } -void ThreadPool::threadLoop() +void ThreadPool::work() { - List localQueue; - while (running.load()) + while (true) { - [[likely]] - if(!localQueue.empty()) + std::unique_lock l(taskLock); + while(currentTask.functions.empty()) { - Job job = localQueue.retrieve(); - job.resume(); + taskCV.wait(l); + if (!running) + { + return; + } } - else + auto func = std::move(currentTask.functions.front()); + currentTask.functions.popFront(); + l.unlock(); + func(); + l.lock(); + currentTask.numRemaining--; + if (currentTask.numRemaining == 0) { - std::unique_lock lock(jobQueueLock); - if (jobQueue.empty()) - { - { - std::unique_lock lock2(numIdlingLock); - numIdling++; - numIdlingIncr.notify_one(); - } - jobQueueCV.wait(lock); - { - std::unique_lock lock2(numIdlingLock); - numIdling--; - } - } - // take 1/numThreads jobs, maybe make this a parameter that - // adjusts based on past workload - uint32 partitionedWorkload = (uint32)(jobQueue.size() / workers.size()); - uint32 numTaken = std::clamp(partitionedWorkload, 1u, localQueueSize); - while (!jobQueue.empty() && localQueue.size() < numTaken) - { - localQueue.add(jobQueue.retrieve()); - } + std::unique_lock l2(completedLock); + completedCV.notify_one(); } } } -ThreadPool &Seele::getGlobalThreadPool() -{ - static ThreadPool threadPool; - return threadPool; -} \ No newline at end of file diff --git a/src/Engine/ThreadPool.h b/src/Engine/ThreadPool.h index fa67145..0a0d786 100644 --- a/src/Engine/ThreadPool.h +++ b/src/Engine/ThreadPool.h @@ -1,459 +1,29 @@ #pragma once #include -#include -#include "MinimalEngine.h" +#include "Containers/Array.h" #include "Containers/List.h" -#include "Concepts.h" -#include namespace Seele { -extern class ThreadPool& getGlobalThreadPool(); -template -struct JobBase; -template -struct JobPromiseBase; -struct Event -{ -public: - //Event(nullptr_t); - Event(const std::string& name, const std::source_location& location = std::source_location::current()); - Event(const std::source_location& location = std::source_location::current()); - Event(const Event& other); - Event(Event&& other); - ~Event() = default; - Event& operator=(const Event& other); - Event& operator=(Event&& other); - auto operator<=>(const Event& other) const - { - return state->name <=> other.state->name; - } - bool operator==(const Event& other) const - { - return state->name == other.state->name; - } - operator bool() - { - std::scoped_lock lock(eventLock); - return state->data; - } - - friend std::ostream& operator<<(std::ostream& stream, const Event& event) - { - stream - << event.state->location.file_name() - << "(" - << event.state->location.line() - << ":" - << event.state->location.column() - << "): " - << event.state->location.function_name(); - return stream; - } - - void raise(); - void reset(); - bool await_ready(); - void await_suspend(std::coroutine_handle> h); - void await_suspend(std::coroutine_handle> h); - constexpr void await_resume() {} -private: - mutable std::mutex eventLock; - struct EventState - { - std::string name; - std::source_location location; - bool data = false; - Array> waitingJobs; - Array> waitingMainJobs; - }; - std::shared_ptr state; - friend class ThreadPool; -}; - -extern std::mutex promisesLock; -extern List*> promises; -template -struct JobPromiseBase -{ - enum class State - { - READY, - WAITING, - SCHEDULED, - EXECUTING, - DONE - }; - JobPromiseBase(const std::source_location& location = std::source_location::current()) - : pad0(12345)//0x7472617453) - , handle(std::coroutine_handle>::from_promise(*this)) - , waitingFor(nullptr) - , continuation(nullptr) - , numRefs(0) - , finishedEvent(location) - , state(State::READY) - , pad1(12345)//0x646E45) - { - if constexpr(!MainJob) - { - std::scoped_lock lock(promisesLock); - promises.add(this); - } - } - ~JobPromiseBase() - { - if constexpr (!MainJob) - { - std::scoped_lock lock(promisesLock); - promises.remove(promises.find(this)); - } - } - - JobBase get_return_object() noexcept; - - inline auto initial_suspend() noexcept; - inline auto final_suspend() noexcept; - - void return_void() noexcept {} - void unhandled_exception() { - std::exception_ptr exception = std::current_exception(); - std::cerr << "Unhandled exception!" << std::endl; - throw exception; - }; - - void resume() - { - std::scoped_lock lock(promiseLock); - validate(); - if(!handle || handle.done() || executing()) - { - return; - } - state = State::EXECUTING; - handle.resume(); - } - void setContinuation(JobPromiseBase* cont) - { - std::scoped_lock lock(promiseLock, cont->promiseLock); - validate(); - assert(cont->ready()); - continuation = cont; - cont->state = State::SCHEDULED; - cont->waitingFor = &finishedEvent; - cont->addRef(); - } - bool done() - { - validate(); - return state == State::DONE; - } - bool scheduled() - { - validate(); - return state == State::SCHEDULED; - } - bool waiting() - { - validate(); - return state == State::WAITING; - } - bool executing() - { - validate(); - return state == State::EXECUTING; - } - bool ready() - { - validate(); - return state == State::READY; - } - void enqueue(Event* event); - bool schedule(); - void addRef() - { - validate(); - numRefs++; - } - void removeRef() - { - { - std::scoped_lock lock(promiseLock); - validate(); - numRefs--; - if(numRefs != 0) - { - return; - } - if(schedule()) - { - return; - } - } - handle.destroy(); - } - void validate() - { - assert(pad0 == 12345); - assert(pad1 == 12345); - } - uint64 pad0; - std::mutex promiseLock; - std::coroutine_handle handle; - Event* waitingFor; - JobPromiseBase* continuation; - std::atomic_uint64_t numRefs; - Event finishedEvent; - State state; - uint64 pad1; -}; - -template -struct JobBase -{ -public: - using promise_type = JobPromiseBase; - - explicit JobBase() - : promise(nullptr) - { - } - explicit JobBase(JobPromiseBase* promise) - : promise(promise) - { - promise->addRef(); - } - JobBase(const JobBase& other) - { - promise = other.promise; - if(promise != nullptr) - { - promise->addRef(); - } - } - JobBase(JobBase&& other) - { - promise = other.promise; - other.promise = nullptr; - } - ~JobBase() - { - if(promise) - { - //promise->schedule(); - promise->removeRef(); - } - } - JobBase& operator=(const JobBase& other) - { - if(this != &other) - { - if(promise != nullptr) - { - promise->removeRef(); - } - promise = other.promise; - if(promise != nullptr) - { - promise->addRef(); - } - } - return *this; - } - JobBase& operator=(JobBase&& other) - { - if(this != &other) - { - if(promise != nullptr) - { - promise->removeRef(); - } - promise = other.promise; - other.promise = nullptr; - } - return *this; - } - void resume() - { - promise->resume(); - } - template - inline JobBase then(Callable callable) - { - return then(callable()); - } - JobBase then(JobBase continuation) - { - promise->setContinuation(continuation.promise); - continuation.promise->state = JobPromiseBase::State::SCHEDULED; - return continuation; - } - bool done() - { - return promise->done(); - } - Event& operator co_await() - { - // the co_await operator keeps a reference to this, it won't - // be scheduled from the destructor - std::scoped_lock lock(promise->promiseLock); - promise->schedule(); - return promise->finishedEvent; - } - static JobBase all() = delete; - - template - requires std::same_as, JobBase> - static JobBase all(Iterable collection); - - template - static JobBase all(Iterable collection) - { - for(auto it : collection) - { - co_await it; - } - } - - template - static JobBase all(Awaitable... jobs) - { - std::vector vec{jobs...}; - return std::move(JobBase::all(std::move(vec))); - } - template - requires std::invocable> - static JobBase launchJobs(JobFunc&& func, Iterable params); -private: - JobPromiseBase* promise; - friend class ThreadPool; -}; - -using MainJob = JobBase; -using Job = JobBase; -using MainPromise = JobPromiseBase; -using Promise = JobPromiseBase; - class ThreadPool { public: - ThreadPool(uint32 threadCount = std::thread::hardware_concurrency()); - virtual ~ThreadPool(); - void waitIdle(); - void scheduleJob(Job job); - void scheduleJob(MainJob job); - template - requires std::same_as, MainJob> - void scheduleBatch(Iterable jobs) - { - std::scoped_lock lock(mainJobLock); - for(auto job : jobs) - { - std::scoped_lock l(job.promise->promiseLock); - job.promise->validate(); - job.promise->state = JobPromiseBase::State::SCHEDULED; - mainJobs.add(job); - } - mainJobCV.notify_one(); - } - template - requires std::same_as, Job> - void scheduleBatch(Iterable jobs) - { - std::scoped_lock lock(jobQueueLock); - for(auto job : jobs) - { - std::scoped_lock l(job.promise->promiseLock); - job.promise->validate(); - job.promise->state = JobPromiseBase::State::SCHEDULED; - jobQueue.add(job); - } - jobQueueCV.notify_all(); - } - void notify(Event* event); - void mainLoop(); - void threadLoop(); + ThreadPool(uint32 numWorkers = std::thread::hardware_concurrency()); + ~ThreadPool(); + void runAndWait(List> functions); private: - std::atomic_bool running; - std::mutex numIdlingLock; - std::condition_variable numIdlingIncr; - uint32 numIdling; + struct Task + { + uint64 numRemaining = 0; + List> functions; + }; + void work(); Array workers; - - List mainJobs; - std::mutex mainJobLock; - std::condition_variable mainJobCV; - - List jobQueue; - std::mutex jobQueueLock; - std::condition_variable jobQueueCV; - - uint32 localQueueSize = 50; + std::mutex taskLock; + std::condition_variable taskCV; + std::mutex completedLock; + std::condition_variable completedCV; + Task currentTask; + bool running = true; }; - -template -inline JobBase JobPromiseBase::get_return_object() noexcept -{ - return JobBase(this); -} - -template -inline auto JobPromiseBase::initial_suspend() noexcept -{ - validate(); - return std::suspend_always{}; -} - -template -inline auto JobPromiseBase::final_suspend() noexcept -{ - validate(); - state = State::DONE; - finishedEvent.raise(); - if(continuation) - { - getGlobalThreadPool().scheduleJob(JobBase(continuation)); - continuation->removeRef(); - } - return std::suspend_always{}; -} -template -inline bool JobPromiseBase::schedule() -{ - validate(); - if(!handle || done() || !ready()) - { - return false; - } - state = State::SCHEDULED; - getGlobalThreadPool().scheduleJob(std::move(JobBase(this))); - return true; -} -template -template -requires std::same_as, JobBase> -inline JobBase JobBase::all(Iterable collection) -{ - getGlobalThreadPool().scheduleBatch(collection); - for(auto it : collection) - { - co_await it; - } - collection.clear(); -} -template -template -requires std::invocable> -inline JobBase JobBase::launchJobs(JobFunc&& func, Iterable params) -{ - Array> jobs; - for(auto&& param : params) - { - jobs.add(func(param)); - } - getGlobalThreadPool().scheduleBatch(jobs); - for(auto job : jobs) - { - co_await job; - } -} -} // namespace Seele +} \ No newline at end of file diff --git a/src/Engine/Window/GameView.h b/src/Engine/Window/GameView.h index 9d88635..12956e2 100644 --- a/src/Engine/Window/GameView.h +++ b/src/Engine/Window/GameView.h @@ -40,7 +40,7 @@ private: PSystemGraph systemGraph; System::PKeyboardInput keyboardSystem; - dp::thread_pool<> threadPool; + ThreadPool threadPool; float updateTime = 0; virtual void keyCallback(Seele::KeyCode code, Seele::InputAction action, Seele::KeyModifier modifier) override; diff --git a/vcpkg.json b/vcpkg.json index c2c2a96..4664e2b 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -3,7 +3,6 @@ "assimp", "entt", "stb", - "dp-thread-pool", "entt", "freetype", "glfw3",