From 79ced0a30f4173ddd4e8d22102f6f2376bf8d250 Mon Sep 17 00:00:00 2001 From: Dynamitos Date: Wed, 22 Dec 2021 11:42:07 +0100 Subject: [PATCH] Then chaining still kinda broken --- src/Engine/Asset/MeshLoader.cpp | 3 +- src/Engine/Asset/MeshLoader.h | 2 +- src/Engine/Graphics/RenderPass/BasePass.cpp | 2 + .../Graphics/RenderPass/DepthPrepass.cpp | 5 ++ src/Engine/Graphics/RenderPass/DepthPrepass.h | 2 - .../Graphics/RenderPass/MeshProcessor.h | 1 + .../Graphics/Vulkan/VulkanAllocator.cpp | 2 +- .../Graphics/Vulkan/VulkanCommandBuffer.cpp | 3 +- src/Engine/ThreadPool.cpp | 15 +++- src/Engine/ThreadPool.h | 33 ++++----- src/Engine/Window/InspectorView.cpp | 13 ++-- src/Engine/Window/SceneView.cpp | 25 +++---- test/Engine/CMakeLists.txt | 4 +- test/Engine/ThreadPool.cpp | 74 +++++++++++++++++++ 14 files changed, 131 insertions(+), 53 deletions(-) create mode 100644 test/Engine/ThreadPool.cpp diff --git a/src/Engine/Asset/MeshLoader.cpp b/src/Engine/Asset/MeshLoader.cpp index a25ad29..e97b2ae 100644 --- a/src/Engine/Asset/MeshLoader.cpp +++ b/src/Engine/Asset/MeshLoader.cpp @@ -229,7 +229,7 @@ void MeshLoader::loadTextures(const aiScene* scene, const std::filesystem::path& AssetRegistry::importFile(texPngPath.string()); } } -Job MeshLoader::import(std::filesystem::path path, PMeshAsset meshAsset) +void MeshLoader::import(std::filesystem::path path, PMeshAsset meshAsset) { std::cout << "Starting to import "<setStatus(Asset::Status::Loading); @@ -264,5 +264,4 @@ Job MeshLoader::import(std::filesystem::path path, PMeshAsset meshAsset) meshAsset->setStatus(Asset::Status::Ready); meshAsset->save(); std::cout << "Finished loading " << path << std::endl; - co_return; } diff --git a/src/Engine/Asset/MeshLoader.h b/src/Engine/Asset/MeshLoader.h index edae908..d97abf3 100644 --- a/src/Engine/Asset/MeshLoader.h +++ b/src/Engine/Asset/MeshLoader.h @@ -26,7 +26,7 @@ private: void loadGlobalMeshes(const aiScene* scene, Array& globalMeshes, const Array& materials, Gfx::PGraphics graphics); void convertAssimpARGB(unsigned char* dst, aiTexel* src, uint32 numPixels); - Job import(std::filesystem::path path, PMeshAsset meshAsset); + void import(std::filesystem::path path, PMeshAsset meshAsset); List> futures; Gfx::PGraphics graphics; }; diff --git a/src/Engine/Graphics/RenderPass/BasePass.cpp b/src/Engine/Graphics/RenderPass/BasePass.cpp index 7637cae..0a7687a 100644 --- a/src/Engine/Graphics/RenderPass/BasePass.cpp +++ b/src/Engine/Graphics/RenderPass/BasePass.cpp @@ -63,6 +63,7 @@ Job BasePassMeshProcessor::processMeshBatch( collection->fragmentShader, false); } + std::unique_lock lock(commandLock); renderCommands.add(renderCommand); co_return; } @@ -160,6 +161,7 @@ MainJob BasePass::render() co_await Job::all(jobs); graphics->executeCommands(processor->getRenderCommands()); graphics->endRenderPass(); + co_return; } MainJob BasePass::endFrame() diff --git a/src/Engine/Graphics/RenderPass/DepthPrepass.cpp b/src/Engine/Graphics/RenderPass/DepthPrepass.cpp index 8a76ff7..20888c6 100644 --- a/src/Engine/Graphics/RenderPass/DepthPrepass.cpp +++ b/src/Engine/Graphics/RenderPass/DepthPrepass.cpp @@ -27,6 +27,7 @@ Job DepthPrepassMeshProcessor::processMeshBatch( Array descriptorSets, int32 /*staticMeshId*/) { + std::cout << "Depth job started" << std::endl; PMaterialAsset material = batch.material; //const Gfx::MaterialShadingModel shadingModel = material->getShadingModel(); @@ -60,7 +61,9 @@ Job DepthPrepassMeshProcessor::processMeshBatch( collection->fragmentShader, true); } + std::unique_lock lock(commandLock); renderCommands.add(renderCommand); + std::cout << "Finished depth job" << std::endl; co_return; } @@ -127,8 +130,10 @@ MainJob DepthPrepass::render() jobs.add(processor->processMeshBatch(meshBatch, renderPass, depthPrepassLayout, primitiveLayout, descriptorSets)); } co_await Job::all(jobs); + std::cout << "Finished waiting depth jobs " << std::endl; graphics->executeCommands(processor->getRenderCommands()); graphics->endRenderPass(); + co_return; } MainJob DepthPrepass::endFrame() diff --git a/src/Engine/Graphics/RenderPass/DepthPrepass.h b/src/Engine/Graphics/RenderPass/DepthPrepass.h index f6c386f..6be5163 100644 --- a/src/Engine/Graphics/RenderPass/DepthPrepass.h +++ b/src/Engine/Graphics/RenderPass/DepthPrepass.h @@ -20,9 +20,7 @@ public: int32 staticMeshId = -1) override; private: - //Array cachedPrimitiveSets; Gfx::PViewport target; - //uint32 cachedPrimitiveIndex; }; DEFINE_REF(DepthPrepassMeshProcessor) DECLARE_REF(CameraActor) diff --git a/src/Engine/Graphics/RenderPass/MeshProcessor.h b/src/Engine/Graphics/RenderPass/MeshProcessor.h index 18ae91e..24010ec 100644 --- a/src/Engine/Graphics/RenderPass/MeshProcessor.h +++ b/src/Engine/Graphics/RenderPass/MeshProcessor.h @@ -38,6 +38,7 @@ protected: Gfx::PGeometryShader geometryShader, Gfx::PFragmentShader fragmentShader, bool positionOnly); + std::mutex commandLock; Array renderCommands; }; } // namespace Seele diff --git a/src/Engine/Graphics/Vulkan/VulkanAllocator.cpp b/src/Engine/Graphics/Vulkan/VulkanAllocator.cpp index 2d09cd2..472830e 100644 --- a/src/Engine/Graphics/Vulkan/VulkanAllocator.cpp +++ b/src/Engine/Graphics/Vulkan/VulkanAllocator.cpp @@ -233,7 +233,7 @@ PSubAllocation Allocator::allocate(const VkMemoryRequirements2 &memRequirements2 PAllocation newAllocation = new Allocation(graphics, this, requirements.size, memoryTypeIndex, properties, dedicatedInfo); heaps[heapIndex].allocations.add(newAllocation); return newAllocation->getSuballocation(requirements.size, requirements.alignment); - } + } } for (auto alloc : heaps[heapIndex].allocations) { diff --git a/src/Engine/Graphics/Vulkan/VulkanCommandBuffer.cpp b/src/Engine/Graphics/Vulkan/VulkanCommandBuffer.cpp index 0f06be9..c06303c 100644 --- a/src/Engine/Graphics/Vulkan/VulkanCommandBuffer.cpp +++ b/src/Engine/Graphics/Vulkan/VulkanCommandBuffer.cpp @@ -74,6 +74,7 @@ void CmdBuffer::beginRenderPass(PRenderPass newRenderPass, PFramebuffer newFrame beginInfo.framebuffer = framebuffer->getHandle(); vkCmdBeginRenderPass(handle, &beginInfo, renderPass->getSubpassContents()); state = State::RenderPassActive; + std::cout << "Beginning renderPass" << std::endl; } void CmdBuffer::endRenderPass() @@ -81,6 +82,7 @@ void CmdBuffer::endRenderPass() std::unique_lock lock(handleLock); vkCmdEndRenderPass(handle); state = State::InsideBegin; + std::cout << "Ending renderPass" << std::endl; } void CmdBuffer::executeCommands(const Array& commands) @@ -88,7 +90,6 @@ void CmdBuffer::executeCommands(const Array& commands) assert(state == State::RenderPassActive); if(commands.size() == 0) { - std::cout << "No commands!" << std::endl; return; } std::unique_lock lock(handleLock); diff --git a/src/Engine/ThreadPool.cpp b/src/Engine/ThreadPool.cpp index 90f01f5..1a8f232 100644 --- a/src/Engine/ThreadPool.cpp +++ b/src/Engine/ThreadPool.cpp @@ -54,35 +54,42 @@ ThreadPool::~ThreadPool() void ThreadPool::enqueueWaiting(Event &event, Promise* job) { assert(!job->done()); + assert(job->schedulable); if(event == nullptr) { std::unique_lock lock(jobQueueLock); + //std::cout << "Queueing job " << job->finishedEvent.name << std::endl; jobQueue.add(job); jobQueueCV.notify_one(); } else { std::unique_lock lock(waitingLock); + //std::cout << "Job " << job->finishedEvent.name << " waiting on event " << event.name << std::endl; waitingJobs[event].add(job); } } void ThreadPool::enqueueWaiting(Event &event, MainPromise* job) { assert(!job->done()); + assert(job->schedulable); if(event == nullptr) { std::unique_lock lock(mainJobLock); + //std::cout << "Queueing job " << job->finishedEvent.name << std::endl; mainJobs.add(job); mainJobCV.notify_one(); } else { std::unique_lock lock(waitingMainLock); + //std::cout << job->finishedEvent.name << " waiting on event " << event.name << std::endl; waitingMainJobs[event].add(job); } } void ThreadPool::notify(Event &event) { + //std::cout << "Event " << event.name << " raised" << std::endl; { std::unique_lock lock(jobQueueLock); std::unique_lock lock2(waitingLock); @@ -90,11 +97,11 @@ void ThreadPool::notify(Event &event) for (auto &job : jobs) { //assert(job.id != -1ull); - //std::cout << "Waking up job " << job.id << std::endl; + //std::cout << "Waking up " << job->finishedEvent.name << std::endl; jobQueue.add(job); jobQueueCV.notify_one(); } - jobs.clear(); + waitingJobs.erase(event); } { std::unique_lock lock(mainJobLock); @@ -103,11 +110,11 @@ void ThreadPool::notify(Event &event) for (auto &job : jobs) { //assert(job.id != -1ull); - //std::cout << "Waking up main job " << job.id << std::endl; + //std::cout << "Waking up main " << job->finishedEvent.name << std::endl; mainJobs.add(job); mainJobCV.notify_one(); } - jobs.clear(); + waitingMainJobs.erase(event); } } void ThreadPool::threadLoop(const bool mainThread) diff --git a/src/Engine/ThreadPool.h b/src/Engine/ThreadPool.h index b9244e3..af261eb 100644 --- a/src/Engine/ThreadPool.h +++ b/src/Engine/ThreadPool.h @@ -74,6 +74,7 @@ struct JobPromiseBase if(handle && !handle.done()) { handle.resume(); + schedulable = true; } } void setContinuation(JobPromiseBase* cont) @@ -99,16 +100,22 @@ struct JobPromiseBase } void enqueue(Event& event) { + if(!handle || handle.done() || !schedulable) + { + return; + } getGlobalThreadPool().enqueueWaiting(event, this); + schedulable = false; } void schedule() { std::unique_lock lock(promiseLock); - if(!handle || handle.done()) + if(!handle || handle.done() || !schedulable) { return; } getGlobalThreadPool().enqueueWaiting(precondition, this); + schedulable = false; } std::mutex promiseLock; @@ -117,6 +124,7 @@ struct JobPromiseBase uint64 id; Event finishedEvent; Event precondition = nullptr; + bool schedulable = true; }; template @@ -145,14 +153,14 @@ public: promise->resume(); } template - inline JobBase then(Callable callable) + inline JobBase&& then(Callable callable) { return then(callable()); } - JobBase then(JobBase&& continuation) + JobBase&& then(JobBase&& continuation) { promise->setContinuation(continuation.promise); - return continuation; + return std::move(continuation); } bool done() { @@ -168,7 +176,6 @@ public: } Event operator co_await() { - promise->resume(); return promise->finishedEvent; } static JobBase all() = delete; @@ -230,10 +237,10 @@ private: std::mutex jobQueueLock; std::condition_variable jobQueueCV; - Map> waitingMainJobs; + std::map> waitingMainJobs; std::mutex waitingMainLock; - Map> waitingJobs; + std::map> waitingJobs; std::mutex waitingLock; }; @@ -246,18 +253,6 @@ inline JobBase JobPromiseBase::get_return_object() noexcept template inline auto JobPromiseBase::initial_suspend() noexcept { - /*struct JobAwaitable - { - constexpr bool await_ready() { return false; } - constexpr void await_suspend(std::coroutine_handle> h) - { - getGlobalThreadPool().addJob(std::move(JobBase(h, id, event))); - } - constexpr void await_resume() {} - uint64 id; - Event& event; - }; - return JobAwaitable{id, finishedEvent};*/ return std::suspend_always{}; } template diff --git a/src/Engine/Window/InspectorView.cpp b/src/Engine/Window/InspectorView.cpp index d9fb946..83b1c9c 100644 --- a/src/Engine/Window/InspectorView.cpp +++ b/src/Engine/Window/InspectorView.cpp @@ -40,14 +40,11 @@ void InspectorView::prepareRender() MainJob InspectorView::render() { - return uiPass.beginFrame() - .then(uiPass.render()) - .then(uiPass.endFrame()) - .then([=]() -> MainJob - { - renderFinishedEvent.raise(); - co_return; - }); + co_await uiPass.beginFrame(); + co_await uiPass.render(); + co_await uiPass.endFrame(); + renderFinishedEvent.raise(); + co_return; } void InspectorView::keyCallback(KeyCode, InputAction, KeyModifier) diff --git a/src/Engine/Window/SceneView.cpp b/src/Engine/Window/SceneView.cpp index bc096ea..a742ce6 100644 --- a/src/Engine/Window/SceneView.cpp +++ b/src/Engine/Window/SceneView.cpp @@ -84,20 +84,17 @@ void SceneView::prepareRender() MainJob SceneView::render() { - return depthPrepass.beginFrame() - .then(lightCullingPass.beginFrame()) - .then(basePass.beginFrame()) - .then(depthPrepass.render()) - .then(lightCullingPass.render()) - .then(basePass.render()) - .then(depthPrepass.endFrame()) - .then(lightCullingPass.endFrame()) - .then(basePass.endFrame()) - .then([&](Event& event) -> MainJob - { - event.raise(); - co_return; - }(renderFinishedEvent)); + co_await depthPrepass.beginFrame(); + co_await lightCullingPass.beginFrame(); + co_await basePass.beginFrame(); + co_await depthPrepass.render(); + co_await lightCullingPass.render(); + co_await basePass.render(); + co_await depthPrepass.endFrame(); + co_await lightCullingPass.endFrame(); + co_await basePass.endFrame(); + renderFinishedEvent.raise(); + co_return; } void SceneView::keyCallback(KeyCode code, InputAction action, KeyModifier) diff --git a/test/Engine/CMakeLists.txt b/test/Engine/CMakeLists.txt index 86f8b74..0b7e60b 100644 --- a/test/Engine/CMakeLists.txt +++ b/test/Engine/CMakeLists.txt @@ -1,8 +1,10 @@ target_sources(Seele_unit_tests PRIVATE ../../src/Engine/MinimalEngine.cpp + ../../src/Engine/ThreadPool.cpp EngineTest.h - EngineTest.cpp) + EngineTest.cpp + ThreadPool.cpp) target_include_directories(Seele_unit_tests PUBLIC ./) add_subdirectory(Containers/) add_subdirectory(Graphics/) diff --git a/test/Engine/ThreadPool.cpp b/test/Engine/ThreadPool.cpp new file mode 100644 index 0000000..a19da35 --- /dev/null +++ b/test/Engine/ThreadPool.cpp @@ -0,0 +1,74 @@ +#include "EngineTest.h" +#include "ThreadPool.h" +#include + +BOOST_AUTO_TEST_SUITE(ThreadPool) + +uint64 basicJobState = 0; + +Job basicThenFirst() +{ + basicJobState = 10; + co_return; +} +Job basicThenSecond() +{ + BOOST_REQUIRE_EQUAL(basicJobState, 10); + basicJobState = 20; + co_return; +} +Job basicThenThird() +{ + BOOST_REQUIRE_EQUAL(basicJobState, 20); + co_return; +} + +BOOST_AUTO_TEST_CASE(basic_then) +{ + basicThenFirst() + .then(basicThenSecond()) + .then(basicThenThird()); +} + +uint64 basicAllState1 = 0; +uint64 basicAllState2 = 0; +Job basicAllFirst() +{ + basicAllState1 = 10; + co_return; +} +Job basicAllSecond() +{ + basicAllState2 = 10; + co_return; +} +Job basicAllThen() +{ + BOOST_REQUIRE_EQUAL(basicAllState1, 10); + BOOST_REQUIRE_EQUAL(basicAllState2, 10); + co_return; +} + +BOOST_AUTO_TEST_CASE(basic_all) +{ + Job::all(basicAllFirst(), basicAllSecond()).then(basicAllThen()); +} + +uint64 basicCallable = 0; + +Job basicCallableFunc() +{ + basicCallable = 10; + co_return; +} + +BOOST_AUTO_TEST_CASE(basic_callable) +{ + basicCallableFunc() + .then([=]() -> Job{ + BOOST_REQUIRE_EQUAL(basicCallable, 10); + co_return; + }); +} + +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file