From 4bdd89e79f1b1b191bd8943a94c6c3be077ec6c0 Mon Sep 17 00:00:00 2001 From: turanszkij Date: Sat, 29 Jun 2019 15:02:23 +0100 Subject: [PATCH 1/2] jobsystem update: context to separate workloads; now jobs are able to spawn other jobs; --- Editor/ObjectWindow.cpp | 6 +- Tests/Tests.cpp | 17 +- WickedEngine/LoadingScreen.cpp | 76 +--- WickedEngine/LoadingScreen.h | 28 +- WickedEngine/wiInitializer.cpp | 31 +- WickedEngine/wiJobSystem.cpp | 78 ++-- WickedEngine/wiJobSystem.h | 15 +- WickedEngine/wiPhysicsEngine.h | 2 + WickedEngine/wiPhysicsEngine_Bullet.cpp | 7 +- WickedEngine/wiRenderer.cpp | 516 ++++++++++++------------ WickedEngine/wiSceneSystem.cpp | 91 +++-- WickedEngine/wiSceneSystem.h | 28 +- 12 files changed, 445 insertions(+), 450 deletions(-) diff --git a/Editor/ObjectWindow.cpp b/Editor/ObjectWindow.cpp index 8c941b46b..263b65eaf 100644 --- a/Editor/ObjectWindow.cpp +++ b/Editor/ObjectWindow.cpp @@ -488,6 +488,8 @@ ObjectWindow::ObjectWindow(EditorComponent* editor) : editor(editor) } + wiJobSystem::context ctx; + for (auto& it : gen_meshes) { MeshComponent& mesh = *it.first; @@ -503,12 +505,12 @@ ObjectWindow::ObjectWindow(EditorComponent* editor) : editor(editor) } else if (gen_type == UV_GEN_GENERATE_ATLAS) { - wiJobSystem::Execute([&] { + wiJobSystem::Execute(ctx, [&] { it.second = GenerateMeshAtlas(mesh, (uint32_t)lightmapResolutionSlider->GetValue()); }); } } - wiJobSystem::Wait(); + wiJobSystem::Wait(ctx); for (auto& x : gen_objects) { diff --git a/Tests/Tests.cpp b/Tests/Tests.cpp index abbad6007..d8b32d50e 100644 --- a/Tests/Tests.cpp +++ b/Tests/Tests.cpp @@ -198,6 +198,9 @@ void TestsRenderer::RunJobSystemTest() { wiTimer timer; + // This is created to be able to wait on the workload independently from other workload: + wiJobSystem::context ctx; + // This will simulate going over a big dataset first in a simple loop, then with the Job System and compare timings uint32_t itemCount = 1000000; std::stringstream ss(""); @@ -221,11 +224,11 @@ void TestsRenderer::RunJobSystemTest() // Execute test { timer.record(); - wiJobSystem::Execute([]{ wiHelper::Spin(100); }); - wiJobSystem::Execute([]{ wiHelper::Spin(100); }); - wiJobSystem::Execute([]{ wiHelper::Spin(100); }); - wiJobSystem::Execute([]{ wiHelper::Spin(100); }); - wiJobSystem::Wait(); + wiJobSystem::Execute(ctx, []{ wiHelper::Spin(100); }); + wiJobSystem::Execute(ctx, []{ wiHelper::Spin(100); }); + wiJobSystem::Execute(ctx, []{ wiHelper::Spin(100); }); + wiJobSystem::Execute(ctx, []{ wiHelper::Spin(100); }); + wiJobSystem::Wait(ctx); double time = timer.elapsed(); ss << "wiJobSystem::Execute() took " << time << " milliseconds" << std::endl; } @@ -249,10 +252,10 @@ void TestsRenderer::RunJobSystemTest() { std::vector dataSet(itemCount); timer.record(); - wiJobSystem::Dispatch(itemCount, 1000, [&](wiJobDispatchArgs args) { + wiJobSystem::Dispatch(ctx, itemCount, 1000, [&](wiJobDispatchArgs args) { dataSet[args.jobIndex].UpdateCamera(); }); - wiJobSystem::Wait(); + wiJobSystem::Wait(ctx); double time = timer.elapsed(); ss << "wiJobSystem::Dispatch() took " << time << " milliseconds" << std::endl; } diff --git a/WickedEngine/LoadingScreen.cpp b/WickedEngine/LoadingScreen.cpp index 535f6659f..019b7d416 100644 --- a/WickedEngine/LoadingScreen.cpp +++ b/WickedEngine/LoadingScreen.cpp @@ -3,34 +3,16 @@ using namespace std; -LoadingScreen::LoadingScreen() : RenderPath2D() -{ - loaders.clear(); - finish = nullptr; -} - - -LoadingScreen::~LoadingScreen() -{ -} - bool LoadingScreen::isActive() { - for (LoaderTask& x : loaders) - { - if (x.active.load()) - { - return true; - } - } - return false; + return wiJobSystem::IsBusy(ctx_main) || wiJobSystem::IsBusy(ctx_finish); } void LoadingScreen::addLoadingFunction(function loadingFunction) { if (loadingFunction != nullptr) { - loaders.push_back(LoaderTask(loadingFunction)); + tasks.push_back(loadingFunction); } } @@ -50,48 +32,6 @@ void LoadingScreen::onFinished(function finishFunction) finish = finishFunction; } -void LoadingScreen::waitForFinish() -{ - worker.join(); - if (finish != nullptr) - finish(); -} - -void LoadingScreen::doLoadingTasks() -{ - std::vector loaderThreads(0); - - for (LoaderTask& x : loaders) - { - x.active.store(true); - loaderThreads.push_back(thread(x.functionBody)); - } - - int i = 0; - for (thread& x : loaderThreads) - { - x.join(); - loaders[i].active.store(false); - i++; - } -} - -int LoadingScreen::getPercentageComplete() -{ - const int numberOfLoaders = (int)loaders.size(); - int completed = 0; - - for (LoaderTask& x : loaders) - { - if (!x.active.load()) - { - completed++; - } - } - - return (int)(((float)completed / (float)numberOfLoaders)*100.f); -} - void LoadingScreen::Unload() { RenderPath2D::Unload(); @@ -99,15 +39,21 @@ void LoadingScreen::Unload() void LoadingScreen::Start() { - worker = thread(&LoadingScreen::doLoadingTasks, this); - thread(&LoadingScreen::waitForFinish, this).detach(); + for (auto& x : tasks) + { + wiJobSystem::Execute(ctx_main, x); + } + wiJobSystem::Execute(ctx_finish, [this] { + wiJobSystem::Wait(ctx_main); + finish(); + }); RenderPath2D::Start(); } void LoadingScreen::Stop() { - loaders.clear(); + tasks.clear(); finish = nullptr; RenderPath2D::Stop(); diff --git a/WickedEngine/LoadingScreen.h b/WickedEngine/LoadingScreen.h index 91d362910..1d5366da5 100644 --- a/WickedEngine/LoadingScreen.h +++ b/WickedEngine/LoadingScreen.h @@ -1,10 +1,9 @@ #pragma once #include "RenderPath2D.h" #include "wiColor.h" +#include "wiJobSystem.h" -#include #include -#include class MainComponent; @@ -12,30 +11,11 @@ class LoadingScreen : public RenderPath2D { private: - struct LoaderTask - { - std::function functionBody; - std::atomic_bool active; - - LoaderTask(std::function functionBody) :functionBody(functionBody) - { - active.store(false); - } - LoaderTask(const LoaderTask& l) - { - functionBody = l.functionBody; - active.store(l.active.load()); - } - }; - std::vector loaders; - void doLoadingTasks(); - - void waitForFinish(); + wiJobSystem::context ctx_main; + wiJobSystem::context ctx_finish; + std::vector> tasks; std::function finish; - std::thread worker; public: - LoadingScreen(); - virtual ~LoadingScreen(); //Add a loading task which should be executed //use std::bind( YourFunctionPointer ) diff --git a/WickedEngine/wiInitializer.cpp b/WickedEngine/wiInitializer.cpp index 14ac99783..d32d84161 100644 --- a/WickedEngine/wiInitializer.cpp +++ b/WickedEngine/wiInitializer.cpp @@ -9,11 +9,12 @@ using namespace std; namespace wiInitializer { bool initializationStarted = false; + wiJobSystem::context ctx; void InitializeComponentsImmediate() { InitializeComponentsAsync(); - wiJobSystem::Wait(); + wiJobSystem::Wait(ctx); } void InitializeComponentsAsync() { @@ -23,24 +24,24 @@ namespace wiInitializer wiJobSystem::Initialize(); - wiJobSystem::Execute([] { wiFont::Initialize(); }); - wiJobSystem::Execute([] { wiImage::Initialize(); }); - wiJobSystem::Execute([] { wiInputManager::Initialize(); }); - wiJobSystem::Execute([] { wiRenderer::Initialize(); wiWidget::LoadShaders(); }); - wiJobSystem::Execute([] { wiSoundEffect::Initialize(); wiMusic::Initialize(); }); - wiJobSystem::Execute([] { wiTextureHelper::Initialize(); }); - wiJobSystem::Execute([] { wiSceneSystem::wiHairParticle::Initialize(); }); - wiJobSystem::Execute([] { wiSceneSystem::wiEmittedParticle::Initialize(); }); - wiJobSystem::Execute([] { wiLensFlare::Initialize(); }); - wiJobSystem::Execute([] { wiOcean::Initialize(); }); - wiJobSystem::Execute([] { wiGPUSortLib::LoadShaders(); }); - wiJobSystem::Execute([] { wiGPUBVH::LoadShaders(); }); - wiJobSystem::Execute([] { wiPhysicsEngine::Initialize(); }); + wiJobSystem::Execute(ctx, [] { wiFont::Initialize(); }); + wiJobSystem::Execute(ctx, [] { wiImage::Initialize(); }); + wiJobSystem::Execute(ctx, [] { wiInputManager::Initialize(); }); + wiJobSystem::Execute(ctx, [] { wiRenderer::Initialize(); wiWidget::LoadShaders(); }); + wiJobSystem::Execute(ctx, [] { wiSoundEffect::Initialize(); wiMusic::Initialize(); }); + wiJobSystem::Execute(ctx, [] { wiTextureHelper::Initialize(); }); + wiJobSystem::Execute(ctx, [] { wiSceneSystem::wiHairParticle::Initialize(); }); + wiJobSystem::Execute(ctx, [] { wiSceneSystem::wiEmittedParticle::Initialize(); }); + wiJobSystem::Execute(ctx, [] { wiLensFlare::Initialize(); }); + wiJobSystem::Execute(ctx, [] { wiOcean::Initialize(); }); + wiJobSystem::Execute(ctx, [] { wiGPUSortLib::LoadShaders(); }); + wiJobSystem::Execute(ctx, [] { wiGPUBVH::LoadShaders(); }); + wiJobSystem::Execute(ctx, [] { wiPhysicsEngine::Initialize(); }); } bool IsInitializeFinished() { - return initializationStarted && !wiJobSystem::IsBusy(); + return initializationStarted && !wiJobSystem::IsBusy(ctx); } } \ No newline at end of file diff --git a/WickedEngine/wiJobSystem.cpp b/WickedEngine/wiJobSystem.cpp index 8c20e80ee..de9f4083f 100644 --- a/WickedEngine/wiJobSystem.cpp +++ b/WickedEngine/wiJobSystem.cpp @@ -3,31 +3,50 @@ #include "wiBackLog.h" #include "wiContainers.h" -#include #include #include -#include #include #include namespace wiJobSystem { + struct Job + { + std::function task; + context* ctx; + }; + uint32_t numThreads = 0; - wiContainers::ThreadSafeRingBuffer, 256> jobPool; + wiContainers::ThreadSafeRingBuffer jobPool; std::condition_variable wakeCondition; std::mutex wakeMutex; - uint64_t currentLabel = 0; - std::atomic finishedLabel; + + // This function executes the next item from the job queue. Returns true if successful, false if there was no job available + inline bool work() + { + Job job; + if (jobPool.pop_front(job)) + { + job.task(); // execute job + job.ctx->counter.fetch_sub(1); + return true; + } + return false; + } + // This little function will not let the system to be deadlocked while the issuing thread is waiting for something + inline void poll() + { + wakeCondition.notify_one(); // wake one worker thread + std::this_thread::yield(); // allow this thread to be rescheduled + } void Initialize() { - finishedLabel.store(0); - // Retrieve the number of hardware threads in this system: auto numCores = std::thread::hardware_concurrency(); - // Calculate the actual number of worker threads we want: - numThreads = std::max(1u, numCores); + // Calculate the actual number of worker threads we want (-1 main thread): + numThreads = std::max(1u, numCores - 1); for (uint32_t threadID = 0; threadID < numThreads; ++threadID) { @@ -37,12 +56,7 @@ namespace wiJobSystem while (true) { - if (jobPool.pop_front(job)) - { - job(); // execute job - finishedLabel.fetch_add(1); // update worker label state - } - else + if (!work()) { // no job, put thread to sleep std::unique_lock lock(wakeMutex); @@ -80,30 +94,23 @@ namespace wiJobSystem wiBackLog::post(ss.str().c_str()); } - // This little function will not let the system to be deadlocked while the main thread is waiting for something - inline void poll() - { - wakeCondition.notify_one(); // wake one worker thread - std::this_thread::yield(); // allow this thread to be rescheduled - } - uint32_t GetThreadCount() { return numThreads; } - void Execute(const std::function& job) + void Execute(context& ctx, const std::function& job) { - // The main thread label state is updated: - currentLabel += 1; + // Context state is updated: + ctx.counter.fetch_add(1); // Try to push a new job until it is pushed successfully: - while (!jobPool.push_back(job)) { poll(); } + while (!jobPool.push_back({ job, &ctx })) { poll(); } wakeCondition.notify_one(); // wake one thread } - void Dispatch(uint32_t jobCount, uint32_t groupSize, const std::function& job) + void Dispatch(context& ctx, uint32_t jobCount, uint32_t groupSize, const std::function& job) { if (jobCount == 0 || groupSize == 0) { @@ -113,8 +120,8 @@ namespace wiJobSystem // Calculate the amount of job groups to dispatch (overestimate, or "ceil"): const uint32_t groupCount = (jobCount + groupSize - 1) / groupSize; - // The main thread label state is updated: - currentLabel += groupCount; + // Context state is updated: + ctx.counter.fetch_add(groupCount); for (uint32_t groupIndex = 0; groupIndex < groupCount; ++groupIndex) { @@ -137,7 +144,7 @@ namespace wiJobSystem }; // Try to push a new job until it is pushed successfully: - while (!jobPool.push_back(jobGroup)) { poll(); } + while (!jobPool.push_back({ jobGroup, &ctx })) { poll(); } wakeCondition.notify_one(); // wake one thread } @@ -145,14 +152,15 @@ namespace wiJobSystem } - bool IsBusy() + bool IsBusy(const context& ctx) { - // Whenever the main thread label is not reached by the workers, it indicates that some worker is still alive - return finishedLabel.load() < currentLabel; + // Whenever the context label is greater than zero, it means that there is still work that needs to be done + return ctx.counter.load() > 0; } - void Wait() + void Wait(const context& ctx) { - while (IsBusy()) { poll(); } + // Waiting will also put the current thread to good use by working on an other job if it can: + while (IsBusy(ctx)) { work(); poll(); } } } diff --git a/WickedEngine/wiJobSystem.h b/WickedEngine/wiJobSystem.h index f0a86f783..7b966aced 100644 --- a/WickedEngine/wiJobSystem.h +++ b/WickedEngine/wiJobSystem.h @@ -1,6 +1,7 @@ #pragma once #include +#include struct wiJobDispatchArgs { @@ -14,18 +15,24 @@ namespace wiJobSystem uint32_t GetThreadCount(); + // Defines a state of execution, can be waited on + struct context + { + std::atomic counter = 0; + }; + // Add a job to execute asynchronously. Any idle thread will execute this job. - void Execute(const std::function& job); + void Execute(context& ctx, const std::function& job); // Divide a job onto multiple jobs and execute in parallel. // jobCount : how many jobs to generate for this task. // groupSize : how many jobs to execute per thread. Jobs inside a group execute serially. It might be worth to increase for small jobs // func : receives a wiJobDispatchArgs as parameter - void Dispatch(uint32_t jobCount, uint32_t groupSize, const std::function& job); + void Dispatch(context& ctx, uint32_t jobCount, uint32_t groupSize, const std::function& job); // Check if any threads are working currently or not - bool IsBusy(); + bool IsBusy(const context& ctx); // Wait until all threads become idle - void Wait(); + void Wait(const context& ctx); } diff --git a/WickedEngine/wiPhysicsEngine.h b/WickedEngine/wiPhysicsEngine.h index f0fe64897..e544c2211 100644 --- a/WickedEngine/wiPhysicsEngine.h +++ b/WickedEngine/wiPhysicsEngine.h @@ -1,6 +1,7 @@ #pragma once #include "wiECS.h" #include "wiSceneSystem_Decl.h" +#include "wiJobSystem.h" namespace wiPhysicsEngine { @@ -11,6 +12,7 @@ namespace wiPhysicsEngine void SetEnabled(bool value); void RunPhysicsUpdateSystem( + wiJobSystem::context& ctx, const wiSceneSystem::WeatherComponent& weather, const wiECS::ComponentManager& armatures, wiECS::ComponentManager& transforms, diff --git a/WickedEngine/wiPhysicsEngine_Bullet.cpp b/WickedEngine/wiPhysicsEngine_Bullet.cpp index 920974b62..798e2ef69 100644 --- a/WickedEngine/wiPhysicsEngine_Bullet.cpp +++ b/WickedEngine/wiPhysicsEngine_Bullet.cpp @@ -298,6 +298,7 @@ namespace wiPhysicsEngine } void RunPhysicsUpdateSystem( + wiJobSystem::context& ctx, const WeatherComponent& weather, const ComponentManager& armatures, ComponentManager& transforms, @@ -318,7 +319,7 @@ namespace wiPhysicsEngine btVector3 wind = btVector3(weather.windDirection.x, weather.windDirection.y, weather.windDirection.z); // System will register rigidbodies to objects, and update physics engine state for kinematics: - wiJobSystem::Dispatch((uint32_t)rigidbodies.GetCount(), 256, [&](wiJobDispatchArgs args) { + wiJobSystem::Dispatch(ctx, (uint32_t)rigidbodies.GetCount(), 256, [&](wiJobDispatchArgs args) { RigidBodyPhysicsComponent& physicscomponent = rigidbodies[args.jobIndex]; Entity entity = rigidbodies.GetEntity(args.jobIndex); @@ -368,7 +369,7 @@ namespace wiPhysicsEngine }); // System will register softbodies to meshes and update physics engine state: - wiJobSystem::Dispatch((uint32_t)softbodies.GetCount(), 1, [&](wiJobDispatchArgs args) { + wiJobSystem::Dispatch(ctx, (uint32_t)softbodies.GetCount(), 1, [&](wiJobDispatchArgs args) { SoftBodyPhysicsComponent& physicscomponent = softbodies[args.jobIndex]; Entity entity = softbodies.GetEntity(args.jobIndex); @@ -411,7 +412,7 @@ namespace wiPhysicsEngine } }); - wiJobSystem::Wait(); + wiJobSystem::Wait(ctx); // Perform internal simulation step: dynamicsWorld->stepSimulation(dt, 10); diff --git a/WickedEngine/wiRenderer.cpp b/WickedEngine/wiRenderer.cpp index 0a3ef6846..c1bb77a49 100644 --- a/WickedEngine/wiRenderer.cpp +++ b/WickedEngine/wiRenderer.cpp @@ -2116,6 +2116,7 @@ void LoadShaders() domainShaders[DSTYPE_OBJECT] = static_cast(wiResourceManager::GetShaderManager().add(SHADERPATH + "objectDS.cso", wiResourceManager::DOMAINSHADER)); + wiJobSystem::context ctx; // default objectshaders: for (int renderPass = 0; renderPass < RENDERPASS_COUNT; ++renderPass) @@ -2134,187 +2135,189 @@ void LoadShaders() { for (int pom = 0; pom < OBJECTRENDERING_POM_COUNT; ++pom) { - const bool transparency = blendMode != BLENDMODE_OPAQUE; - VSTYPES realVS = GetVSTYPE((RENDERPASS)renderPass, tessellation, alphatest, transparency); - VLTYPES realVL = GetVLTYPE((RENDERPASS)renderPass, tessellation, alphatest, transparency); - HSTYPES realHS = GetHSTYPE((RENDERPASS)renderPass, tessellation); - DSTYPES realDS = GetDSTYPE((RENDERPASS)renderPass, tessellation); - GSTYPES realGS = GetGSTYPE((RENDERPASS)renderPass, alphatest); - PSTYPES realPS = GetPSTYPE((RENDERPASS)renderPass, alphatest, transparency, normalmap, planarreflection, pom); + wiJobSystem::Execute(ctx, [device, renderPass, blendMode, doublesided, tessellation, alphatest, normalmap, planarreflection,pom] { + const bool transparency = blendMode != BLENDMODE_OPAQUE; + VSTYPES realVS = GetVSTYPE((RENDERPASS)renderPass, tessellation, alphatest, transparency); + VLTYPES realVL = GetVLTYPE((RENDERPASS)renderPass, tessellation, alphatest, transparency); + HSTYPES realHS = GetHSTYPE((RENDERPASS)renderPass, tessellation); + DSTYPES realDS = GetDSTYPE((RENDERPASS)renderPass, tessellation); + GSTYPES realGS = GetGSTYPE((RENDERPASS)renderPass, alphatest); + PSTYPES realPS = GetPSTYPE((RENDERPASS)renderPass, alphatest, transparency, normalmap, planarreflection, pom); - if (tessellation && (realHS == HSTYPE_NULL || realDS == DSTYPE_NULL)) - { - continue; - } - - GraphicsPSODesc desc; - desc.vs = vertexShaders[realVS]; - desc.il = &vertexLayouts[realVL]; - desc.hs = hullShaders[realHS]; - desc.ds = domainShaders[realDS]; - desc.gs = geometryShaders[realGS]; - desc.ps = pixelShaders[realPS]; - - switch (blendMode) - { - case BLENDMODE_OPAQUE: - desc.bs = &blendStates[BSTYPE_OPAQUE]; - break; - case BLENDMODE_ALPHA: - desc.bs = &blendStates[BSTYPE_TRANSPARENT]; - break; - case BLENDMODE_ADDITIVE: - desc.bs = &blendStates[BSTYPE_ADDITIVE]; - break; - case BLENDMODE_PREMULTIPLIED: - desc.bs = &blendStates[BSTYPE_PREMULTIPLIED]; - break; - default: - assert(0); - break; - } - - switch (renderPass) - { - case RENDERPASS_DEPTHONLY: - case RENDERPASS_SHADOW: - case RENDERPASS_SHADOWCUBE: - desc.bs = &blendStates[transparency ? BSTYPE_TRANSPARENTSHADOWMAP : BSTYPE_COLORWRITEDISABLE]; - break; - default: - break; - } - - switch (renderPass) - { - case RENDERPASS_SHADOW: - case RENDERPASS_SHADOWCUBE: - desc.dss = &depthStencils[transparency ? DSSTYPE_DEPTHREAD : DSSTYPE_SHADOW]; - break; - case RENDERPASS_TILEDFORWARD: - if (blendMode == BLENDMODE_ADDITIVE) + if (tessellation && (realHS == HSTYPE_NULL || realDS == DSTYPE_NULL)) { - desc.dss = &depthStencils[DSSTYPE_DEPTHREAD]; + return; // if no job, this must be continue!! } - else - { - desc.dss = &depthStencils[transparency ? DSSTYPE_DEFAULT : DSSTYPE_DEPTHREADEQUAL]; - } - break; - case RENDERPASS_ENVMAPCAPTURE: - desc.dss = &depthStencils[DSSTYPE_ENVMAP]; - break; - case RENDERPASS_VOXELIZE: - desc.dss = &depthStencils[DSSTYPE_XRAY]; - break; - default: - if (blendMode == BLENDMODE_ADDITIVE) - { - desc.dss = &depthStencils[DSSTYPE_DEPTHREAD]; - } - else - { - desc.dss = &depthStencils[DSSTYPE_DEFAULT]; - } - break; - } - switch (renderPass) - { - case RENDERPASS_SHADOW: - case RENDERPASS_SHADOWCUBE: - desc.rs = &rasterizers[doublesided ? RSTYPE_SHADOW_DOUBLESIDED : RSTYPE_SHADOW]; - break; - case RENDERPASS_VOXELIZE: - desc.rs = &rasterizers[RSTYPE_VOXELIZE]; - break; - default: - desc.rs = &rasterizers[doublesided ? RSTYPE_DOUBLESIDED : RSTYPE_FRONT]; - break; - } + GraphicsPSODesc desc; + desc.vs = vertexShaders[realVS]; + desc.il = &vertexLayouts[realVL]; + desc.hs = hullShaders[realHS]; + desc.ds = domainShaders[realDS]; + desc.gs = geometryShaders[realGS]; + desc.ps = pixelShaders[realPS]; - switch (renderPass) - { - case RENDERPASS_TEXTURE: - desc.numRTs = 1; - desc.RTFormats[0] = RTFormat_hdr; - desc.DSFormat = DSFormat_full; - break; - case RENDERPASS_DEFERRED: - desc.numRTs = 5; - desc.RTFormats[0] = RTFormat_gbuffer_0; - desc.RTFormats[1] = RTFormat_gbuffer_1; - desc.RTFormats[2] = RTFormat_gbuffer_2; - desc.RTFormats[3] = RTFormat_deferred_lightbuffer; - desc.RTFormats[4] = RTFormat_deferred_lightbuffer; - desc.DSFormat = DSFormat_full; - break; - case RENDERPASS_FORWARD: - if (transparency) + switch (blendMode) { + case BLENDMODE_OPAQUE: + desc.bs = &blendStates[BSTYPE_OPAQUE]; + break; + case BLENDMODE_ALPHA: + desc.bs = &blendStates[BSTYPE_TRANSPARENT]; + break; + case BLENDMODE_ADDITIVE: + desc.bs = &blendStates[BSTYPE_ADDITIVE]; + break; + case BLENDMODE_PREMULTIPLIED: + desc.bs = &blendStates[BSTYPE_PREMULTIPLIED]; + break; + default: + assert(0); + break; + } + + switch (renderPass) + { + case RENDERPASS_DEPTHONLY: + case RENDERPASS_SHADOW: + case RENDERPASS_SHADOWCUBE: + desc.bs = &blendStates[transparency ? BSTYPE_TRANSPARENTSHADOWMAP : BSTYPE_COLORWRITEDISABLE]; + break; + default: + break; + } + + switch (renderPass) + { + case RENDERPASS_SHADOW: + case RENDERPASS_SHADOWCUBE: + desc.dss = &depthStencils[transparency ? DSSTYPE_DEPTHREAD : DSSTYPE_SHADOW]; + break; + case RENDERPASS_TILEDFORWARD: + if (blendMode == BLENDMODE_ADDITIVE) + { + desc.dss = &depthStencils[DSSTYPE_DEPTHREAD]; + } + else + { + desc.dss = &depthStencils[transparency ? DSSTYPE_DEFAULT : DSSTYPE_DEPTHREADEQUAL]; + } + break; + case RENDERPASS_ENVMAPCAPTURE: + desc.dss = &depthStencils[DSSTYPE_ENVMAP]; + break; + case RENDERPASS_VOXELIZE: + desc.dss = &depthStencils[DSSTYPE_XRAY]; + break; + default: + if (blendMode == BLENDMODE_ADDITIVE) + { + desc.dss = &depthStencils[DSSTYPE_DEPTHREAD]; + } + else + { + desc.dss = &depthStencils[DSSTYPE_DEFAULT]; + } + break; + } + + switch (renderPass) + { + case RENDERPASS_SHADOW: + case RENDERPASS_SHADOWCUBE: + desc.rs = &rasterizers[doublesided ? RSTYPE_SHADOW_DOUBLESIDED : RSTYPE_SHADOW]; + break; + case RENDERPASS_VOXELIZE: + desc.rs = &rasterizers[RSTYPE_VOXELIZE]; + break; + default: + desc.rs = &rasterizers[doublesided ? RSTYPE_DOUBLESIDED : RSTYPE_FRONT]; + break; + } + + switch (renderPass) + { + case RENDERPASS_TEXTURE: desc.numRTs = 1; - } - else - { - desc.numRTs = 2; - } - desc.RTFormats[0] = RTFormat_hdr; - desc.RTFormats[1] = RTFormat_gbuffer_1; - desc.DSFormat = DSFormat_full; - break; - case RENDERPASS_TILEDFORWARD: - if (transparency) - { - desc.numRTs = 1; - } - else - { - desc.numRTs = 2; - } - desc.RTFormats[0] = RTFormat_hdr; - desc.RTFormats[1] = RTFormat_gbuffer_1; - desc.DSFormat = DSFormat_full; - break; - case RENDERPASS_DEPTHONLY: - desc.numRTs = 0; - desc.DSFormat = DSFormat_full; - break; - case RENDERPASS_ENVMAPCAPTURE: - desc.numRTs = 1; - desc.RTFormats[0] = RTFormat_envprobe; - desc.DSFormat = DSFormat_small; - break; - case RENDERPASS_SHADOW: - if (transparency) - { - desc.numRTs = 1; - desc.RTFormats[0] = RTFormat_ldr; - } - else - { + desc.RTFormats[0] = RTFormat_hdr; + desc.DSFormat = DSFormat_full; + break; + case RENDERPASS_DEFERRED: + desc.numRTs = 5; + desc.RTFormats[0] = RTFormat_gbuffer_0; + desc.RTFormats[1] = RTFormat_gbuffer_1; + desc.RTFormats[2] = RTFormat_gbuffer_2; + desc.RTFormats[3] = RTFormat_deferred_lightbuffer; + desc.RTFormats[4] = RTFormat_deferred_lightbuffer; + desc.DSFormat = DSFormat_full; + break; + case RENDERPASS_FORWARD: + if (transparency) + { + desc.numRTs = 1; + } + else + { + desc.numRTs = 2; + } + desc.RTFormats[0] = RTFormat_hdr; + desc.RTFormats[1] = RTFormat_gbuffer_1; + desc.DSFormat = DSFormat_full; + break; + case RENDERPASS_TILEDFORWARD: + if (transparency) + { + desc.numRTs = 1; + } + else + { + desc.numRTs = 2; + } + desc.RTFormats[0] = RTFormat_hdr; + desc.RTFormats[1] = RTFormat_gbuffer_1; + desc.DSFormat = DSFormat_full; + break; + case RENDERPASS_DEPTHONLY: desc.numRTs = 0; + desc.DSFormat = DSFormat_full; + break; + case RENDERPASS_ENVMAPCAPTURE: + desc.numRTs = 1; + desc.RTFormats[0] = RTFormat_envprobe; + desc.DSFormat = DSFormat_small; + break; + case RENDERPASS_SHADOW: + if (transparency) + { + desc.numRTs = 1; + desc.RTFormats[0] = RTFormat_ldr; + } + else + { + desc.numRTs = 0; + } + desc.DSFormat = DSFormat_small; + break; + case RENDERPASS_SHADOWCUBE: + desc.numRTs = 0; + desc.DSFormat = DSFormat_small; + break; + case RENDERPASS_VOXELIZE: + desc.numRTs = 0; + break; } - desc.DSFormat = DSFormat_small; - break; - case RENDERPASS_SHADOWCUBE: - desc.numRTs = 0; - desc.DSFormat = DSFormat_small; - break; - case RENDERPASS_VOXELIZE: - desc.numRTs = 0; - break; - } - if (tessellation) - { - desc.pt = PATCHLIST; - } - else - { - desc.pt = TRIANGLELIST; - } + if (tessellation) + { + desc.pt = PATCHLIST; + } + else + { + desc.pt = TRIANGLELIST; + } - device->CreateGraphicsPSO(&desc, &PSO_object[renderPass][blendMode][doublesided][tessellation][alphatest][normalmap][planarreflection][pom]); + device->CreateGraphicsPSO(&desc, &PSO_object[renderPass][blendMode][doublesided][tessellation][alphatest][normalmap][planarreflection][pom]); + }); } } } @@ -2328,7 +2331,7 @@ void LoadShaders() customShaders.clear(); // Hologram sample shader will be registered as custom shader: - { + wiJobSystem::Execute(ctx, [device] { VSTYPES realVS = GetVSTYPE(RENDERPASS_FORWARD, false, false, true); VLTYPES realVL = GetVLTYPE(RENDERPASS_FORWARD, false, false, true); @@ -2353,10 +2356,10 @@ void LoadShaders() customShader.passes[RENDERPASS_FORWARD].pso = &PSO_object_hologram; customShader.passes[RENDERPASS_TILEDFORWARD].pso = &PSO_object_hologram; RegisterCustomShader(customShader); - } + }); - { + wiJobSystem::Execute(ctx, [device] { GraphicsPSODesc desc; desc.vs = vertexShaders[VSTYPE_WATER]; desc.rs = &rasterizers[RSTYPE_DOUBLESIDED]; @@ -2381,8 +2384,8 @@ void LoadShaders() desc.ps = pixelShaders[PSTYPE_SHADOW_WATER]; device->CreateGraphicsPSO(&desc, &PSO_object_water[RENDERPASS_SHADOW]); - } - { + }); + wiJobSystem::Execute(ctx, [device] { GraphicsPSODesc desc; desc.vs = vertexShaders[VSTYPE_OBJECT_SIMPLE]; desc.ps = pixelShaders[PSTYPE_OBJECT_SIMPLEST]; @@ -2396,8 +2399,8 @@ void LoadShaders() desc.DSFormat = DSFormat_full; device->CreateGraphicsPSO(&desc, &PSO_object_wire); - } - { + }); + wiJobSystem::Execute(ctx, [device] { GraphicsPSODesc desc; desc.vs = vertexShaders[VSTYPE_DECAL]; desc.ps = pixelShaders[PSTYPE_DECAL]; @@ -2411,8 +2414,8 @@ void LoadShaders() //desc.RTFormats[1] = RTFormat_gbuffer_1; device->CreateGraphicsPSO(&desc, &PSO_decal); - } - { + }); + wiJobSystem::Execute(ctx, [device] { GraphicsPSODesc desc; desc.vs = vertexShaders[VSTYPE_CUBE]; desc.rs = &rasterizers[RSTYPE_OCCLUDEE]; @@ -2423,26 +2426,25 @@ void LoadShaders() desc.DSFormat = DSFormat_small; device->CreateGraphicsPSO(&desc, &PSO_occlusionquery); - } - for (int renderPass = 0; renderPass < RENDERPASS_COUNT; ++renderPass) - { + }); + wiJobSystem::Dispatch(ctx, RENDERPASS_COUNT, 1, [device](wiJobDispatchArgs args) { const bool impostorRequest = - renderPass != RENDERPASS_VOXELIZE && - renderPass != RENDERPASS_SHADOW && - renderPass != RENDERPASS_SHADOWCUBE && - renderPass != RENDERPASS_ENVMAPCAPTURE; + args.jobIndex != RENDERPASS_VOXELIZE && + args.jobIndex != RENDERPASS_SHADOW && + args.jobIndex != RENDERPASS_SHADOWCUBE && + args.jobIndex != RENDERPASS_ENVMAPCAPTURE; if (!impostorRequest) { - continue; + return; // if no job, this must be continue!! } GraphicsPSODesc desc; desc.rs = &rasterizers[RSTYPE_DOUBLESIDED]; // well, we don't need double sided impostors, but might be helpful if something breaks desc.bs = &blendStates[BSTYPE_OPAQUE]; - desc.dss = &depthStencils[renderPass == RENDERPASS_TILEDFORWARD ? DSSTYPE_DEPTHREADEQUAL : DSSTYPE_DEFAULT]; + desc.dss = &depthStencils[args.jobIndex == RENDERPASS_TILEDFORWARD ? DSSTYPE_DEPTHREADEQUAL : DSSTYPE_DEFAULT]; desc.il = nullptr; - switch (renderPass) + switch (args.jobIndex) { case RENDERPASS_DEFERRED: desc.vs = vertexShaders[VSTYPE_IMPOSTOR]; @@ -2479,9 +2481,9 @@ void LoadShaders() } desc.DSFormat = DSFormat_full; - device->CreateGraphicsPSO(&desc, &PSO_impostor[renderPass]); - } - { + device->CreateGraphicsPSO(&desc, &PSO_impostor[args.jobIndex]); + }); + wiJobSystem::Execute(ctx, [device] { GraphicsPSODesc desc; desc.vs = vertexShaders[VSTYPE_IMPOSTOR]; desc.ps = pixelShaders[PSTYPE_IMPOSTOR_WIRE]; @@ -2495,8 +2497,8 @@ void LoadShaders() desc.DSFormat = DSFormat_full; device->CreateGraphicsPSO(&desc, &PSO_impostor_wire); - } - { + }); + wiJobSystem::Execute(ctx, [device] { GraphicsPSODesc desc; desc.vs = vertexShaders[VSTYPE_OBJECT_COMMON]; desc.rs = &rasterizers[RSTYPE_FRONT]; @@ -2516,10 +2518,9 @@ void LoadShaders() desc.ps = pixelShaders[PSTYPE_CAPTUREIMPOSTOR_SURFACE]; device->CreateGraphicsPSO(&desc, &PSO_captureimpostor_surface); - } + }); - for (int type = 0; type < LightComponent::LIGHTTYPE_COUNT; ++type) - { + wiJobSystem::Dispatch(ctx, LightComponent::LIGHTTYPE_COUNT, 1, [device](wiJobDispatchArgs args) { GraphicsPSODesc desc; // deferred lights: @@ -2528,7 +2529,7 @@ void LoadShaders() desc.rs = &rasterizers[RSTYPE_BACK]; desc.bs = &blendStates[BSTYPE_DEFERREDLIGHT]; - switch (type) + switch (args.jobIndex) { case LightComponent::DIRECTIONAL: desc.vs = vertexShaders[VSTYPE_DIRLIGHT]; @@ -2572,18 +2573,18 @@ void LoadShaders() desc.RTFormats[1] = RTFormat_deferred_lightbuffer; desc.DSFormat = DSFormat_full; - device->CreateGraphicsPSO(&desc, &PSO_deferredlight[type]); + device->CreateGraphicsPSO(&desc, &PSO_deferredlight[args.jobIndex]); // light visualizers: - if (type != LightComponent::DIRECTIONAL) + if (args.jobIndex != LightComponent::DIRECTIONAL) { desc.dss = &depthStencils[DSSTYPE_DEPTHREAD]; desc.ps = pixelShaders[PSTYPE_LIGHTVISUALIZER]; - switch (type) + switch (args.jobIndex) { case LightComponent::POINT: desc.bs = &blendStates[BSTYPE_ADDITIVE]; @@ -2621,18 +2622,18 @@ void LoadShaders() desc.RTFormats[0] = RTFormat_hdr; desc.DSFormat = DSFormat_full; - device->CreateGraphicsPSO(&desc, &PSO_lightvisualizer[type]); + device->CreateGraphicsPSO(&desc, &PSO_lightvisualizer[args.jobIndex]); } // volumetric lights: - if (type <= LightComponent::SPOT) + if (args.jobIndex <= LightComponent::SPOT) { desc.dss = &depthStencils[DSSTYPE_XRAY]; desc.bs = &blendStates[BSTYPE_ADDITIVE]; desc.rs = &rasterizers[RSTYPE_BACK]; - switch (type) + switch (args.jobIndex) { case LightComponent::DIRECTIONAL: desc.vs = vertexShaders[VSTYPE_DIRLIGHT]; @@ -2652,12 +2653,12 @@ void LoadShaders() desc.RTFormats[0] = RTFormat_hdr; desc.DSFormat = FORMAT_UNKNOWN; - device->CreateGraphicsPSO(&desc, &PSO_volumetriclight[type]); + device->CreateGraphicsPSO(&desc, &PSO_volumetriclight[args.jobIndex]); } - } - { + }); + wiJobSystem::Execute(ctx, [device] { GraphicsPSODesc desc; desc.vs = vertexShaders[VSTYPE_DIRLIGHT]; desc.ps = pixelShaders[PSTYPE_ENVIRONMENTALLIGHT]; @@ -2671,8 +2672,8 @@ void LoadShaders() desc.DSFormat = DSFormat_full; device->CreateGraphicsPSO(&desc, &PSO_enviromentallight); - } - { + }); + wiJobSystem::Execute(ctx, [device] { GraphicsPSODesc desc; desc.il = &vertexLayouts[VLTYPE_RENDERLIGHTMAP]; desc.vs = vertexShaders[VSTYPE_RENDERLIGHTMAP]; @@ -2686,8 +2687,8 @@ void LoadShaders() desc.DSFormat = FORMAT_UNKNOWN; device->CreateGraphicsPSO(&desc, &PSO_renderlightmap_indirect); - } - { + }); + wiJobSystem::Execute(ctx, [device] { GraphicsPSODesc desc; desc.il = &vertexLayouts[VLTYPE_RENDERLIGHTMAP]; desc.vs = vertexShaders[VSTYPE_RENDERLIGHTMAP]; @@ -2701,14 +2702,13 @@ void LoadShaders() desc.DSFormat = FORMAT_UNKNOWN; device->CreateGraphicsPSO(&desc, &PSO_renderlightmap_direct); - } - for (int type = 0; type < SKYRENDERING_COUNT; ++type) - { + }); + wiJobSystem::Dispatch(ctx, SKYRENDERING_COUNT, 1, [device](wiJobDispatchArgs args) { GraphicsPSODesc desc; desc.rs = &rasterizers[RSTYPE_SKY]; desc.dss = &depthStencils[DSSTYPE_DEPTHREAD]; - switch (type) + switch (args.jobIndex) { case SKYRENDERING_STATIC: desc.bs = &blendStates[BSTYPE_OPAQUE]; @@ -2756,17 +2756,16 @@ void LoadShaders() break; } - device->CreateGraphicsPSO(&desc, &PSO_sky[type]); - } - for (int debug = 0; debug < DEBUGRENDERING_COUNT; ++debug) - { + device->CreateGraphicsPSO(&desc, &PSO_sky[args.jobIndex]); + }); + wiJobSystem::Dispatch(ctx, DEBUGRENDERING_COUNT, 1, [device](wiJobDispatchArgs args) { GraphicsPSODesc desc; desc.numRTs = 1; desc.RTFormats[0] = RTFormat_hdr; desc.DSFormat = DSFormat_full; - switch (debug) + switch (args.jobIndex) { case DEBUGRENDERING_ENVPROBE: desc.vs = vertexShaders[VSTYPE_SPHERE]; @@ -2848,9 +2847,9 @@ void LoadShaders() break; } - HRESULT hr = device->CreateGraphicsPSO(&desc, &PSO_debug[debug]); + HRESULT hr = device->CreateGraphicsPSO(&desc, &PSO_debug[args.jobIndex]); assert(SUCCEEDED(hr)); - } + }); for (int i = 0; i < TILEDLIGHTING_TYPE_COUNT; ++i) @@ -2859,37 +2858,40 @@ void LoadShaders() { for (int k = 0; k < TILEDLIGHTING_DEBUG_COUNT; ++k) { - string name = "lightCullingCS"; - if (i == TILEDLIGHTING_TYPE_DEFERRED) - { - name += "_DEFERRED"; - } - if (j == TILEDLIGHTING_CULLING_ADVANCED) - { - name += "_ADVANCED"; - } - if (k == TILEDLIGHTING_DEBUG_ENABLED) - { - name += "_DEBUG"; - } - name += ".cso"; + wiJobSystem::Execute(ctx, [device, i, j, k] { + string name = "lightCullingCS"; + if (i == TILEDLIGHTING_TYPE_DEFERRED) + { + name += "_DEFERRED"; + } + if (j == TILEDLIGHTING_CULLING_ADVANCED) + { + name += "_ADVANCED"; + } + if (k == TILEDLIGHTING_DEBUG_ENABLED) + { + name += "_DEBUG"; + } + name += ".cso"; - ComputePSODesc desc; - desc.cs = static_cast(wiResourceManager::GetShaderManager().add(SHADERPATH + name, wiResourceManager::COMPUTESHADER)); - - device->CreateComputePSO(&desc, &CPSO_tiledlighting[i][j][k]); + ComputePSODesc desc; + desc.cs = static_cast(wiResourceManager::GetShaderManager().add(SHADERPATH + name, wiResourceManager::COMPUTESHADER)); + + device->CreateComputePSO(&desc, &CPSO_tiledlighting[i][j][k]); + }); } } } - for (int i = 0; i < CSTYPE_LAST; ++i) - { + wiJobSystem::Dispatch(ctx, CSTYPE_LAST, 1, [device](wiJobDispatchArgs args) { ComputePSODesc desc; - desc.cs = computeShaders[i]; - device->CreateComputePSO(&desc, &CPSO[i]); - } + desc.cs = computeShaders[args.jobIndex]; + device->CreateComputePSO(&desc, &CPSO[args.jobIndex]); + }); + wiJobSystem::Wait(ctx); + } void LoadBuffers() { @@ -3495,6 +3497,8 @@ void UpdatePerFrameData(float dt, uint32_t layerMask) scene.Update(deltaTime); + wiJobSystem::context ctx; + // Because main camera is not part of the scene, update it if it is attached to an entity here: if (cameraTransform != INVALID_ENTITY) { @@ -3508,7 +3512,7 @@ void UpdatePerFrameData(float dt, uint32_t layerMask) } // See which materials will need to update their GPU render data: - wiJobSystem::Execute([&] { + wiJobSystem::Execute(ctx, [&] { pendingMaterialUpdates.clear(); for (size_t i = 0; i < scene.materials.GetCount(); ++i) { @@ -3536,7 +3540,7 @@ void UpdatePerFrameData(float dt, uint32_t layerMask) // Need to swap prev and current vertex buffers for any dynamic meshes BEFORE render threads are kicked // and also create skinning bone buffers: - wiJobSystem::Execute([&] { + wiJobSystem::Execute(ctx, [&] { for (size_t i = 0; i < scene.meshes.GetCount(); ++i) { MeshComponent& mesh = scene.meshes[i]; @@ -3587,7 +3591,7 @@ void UpdatePerFrameData(float dt, uint32_t layerMask) // Update Voxelization parameters: if (scene.objects.GetCount() > 0) { - wiJobSystem::Execute([&] { + wiJobSystem::Execute(ctx, [&] { // We don't update it if the scene is empty, this even makes it easier to debug const float f = 0.05f / voxelSceneData.voxelsize; XMFLOAT3 center = XMFLOAT3(floorf(GetCamera().Eye.x * f) / f, floorf(GetCamera().Eye.y * f) / f, floorf(GetCamera().Eye.z * f) / f); @@ -3620,7 +3624,7 @@ void UpdatePerFrameData(float dt, uint32_t layerMask) } // Cull objects for each camera: - wiJobSystem::Execute([&] { + wiJobSystem::Execute(ctx, [&] { for (size_t i = 0; i < scene.aabb_objects.GetCount(); ++i) { Entity entity = scene.aabb_objects.GetEntity(i); @@ -3652,7 +3656,7 @@ void UpdatePerFrameData(float dt, uint32_t layerMask) // the following cullings will be only for the main camera: if (camera == &GetCamera()) { - wiJobSystem::Execute([&] { + wiJobSystem::Execute(ctx, [&] { // Cull decals: for (size_t i = 0; i < scene.aabb_decals.GetCount(); ++i) { @@ -3672,7 +3676,7 @@ void UpdatePerFrameData(float dt, uint32_t layerMask) } }); - wiJobSystem::Execute([&] { + wiJobSystem::Execute(ctx, [&] { // Cull probes: for (size_t i = 0; i < scene.aabb_probes.GetCount(); ++i) { @@ -3692,7 +3696,7 @@ void UpdatePerFrameData(float dt, uint32_t layerMask) } }); - wiJobSystem::Execute([&] { + wiJobSystem::Execute(ctx, [&] { // Cull lights: for (size_t i = 0; i < scene.aabb_lights.GetCount(); ++i) { @@ -3712,7 +3716,7 @@ void UpdatePerFrameData(float dt, uint32_t layerMask) } }); - wiJobSystem::Execute([&] { + wiJobSystem::Execute(ctx, [&] { // Cull emitters: for (size_t i = 0; i < scene.emitters.GetCount(); ++i) { @@ -3726,7 +3730,7 @@ void UpdatePerFrameData(float dt, uint32_t layerMask) } }); - wiJobSystem::Execute([&] { + wiJobSystem::Execute(ctx, [&] { // Cull hairs: for (size_t i = 0; i < scene.hairs.GetCount(); ++i) { @@ -3740,7 +3744,7 @@ void UpdatePerFrameData(float dt, uint32_t layerMask) } }); - wiJobSystem::Wait(); + wiJobSystem::Wait(ctx); // Sort lights based on distance so that closer lights will receive shadow map priority: const size_t lightCount = culling.culledLights.size(); @@ -3848,7 +3852,7 @@ void UpdatePerFrameData(float dt, uint32_t layerMask) ManageEnvProbes(); ManageWaterRipples(); - wiJobSystem::Wait(); + wiJobSystem::Wait(ctx); } void UpdateRenderData(GRAPHICSTHREAD threadID) { diff --git a/WickedEngine/wiSceneSystem.cpp b/WickedEngine/wiSceneSystem.cpp index 47430dd16..a3c7a5b4b 100644 --- a/WickedEngine/wiSceneSystem.cpp +++ b/WickedEngine/wiSceneSystem.cpp @@ -996,46 +996,47 @@ namespace wiSceneSystem UpdateCamera(); } - void Scene::Update(float dt) { - RunPreviousFrameTransformUpdateSystem(transforms, prev_transforms); + wiJobSystem::context ctx; - RunAnimationUpdateSystem(animations, transforms, dt); + RunPreviousFrameTransformUpdateSystem(ctx, transforms, prev_transforms); - wiPhysicsEngine::RunPhysicsUpdateSystem(weather, armatures, transforms, meshes, objects, rigidbodies, softbodies, dt); + RunAnimationUpdateSystem(ctx, animations, transforms, dt); - RunTransformUpdateSystem(transforms); + wiPhysicsEngine::RunPhysicsUpdateSystem(ctx, weather, armatures, transforms, meshes, objects, rigidbodies, softbodies, dt); - wiJobSystem::Wait(); // dependecies + RunTransformUpdateSystem(ctx, transforms); - RunHierarchyUpdateSystem(hierarchy, transforms, layers); + wiJobSystem::Wait(ctx); // dependecies - RunArmatureUpdateSystem(transforms, armatures); + RunHierarchyUpdateSystem(ctx, hierarchy, transforms, layers); - RunMaterialUpdateSystem(materials, dt); + RunArmatureUpdateSystem(ctx, transforms, armatures); - RunImpostorUpdateSystem(impostors); + RunMaterialUpdateSystem(ctx, materials, dt); - wiJobSystem::Wait(); // dependecies + RunImpostorUpdateSystem(ctx, impostors); - RunObjectUpdateSystem(prev_transforms, transforms, meshes, materials, objects, aabb_objects, impostors, softbodies, bounds, waterPlane); + wiJobSystem::Wait(ctx); // dependecies - RunCameraUpdateSystem(transforms, cameras); + RunObjectUpdateSystem(ctx, prev_transforms, transforms, meshes, materials, objects, aabb_objects, impostors, softbodies, bounds, waterPlane); - RunDecalUpdateSystem(transforms, materials, aabb_decals, decals); + RunCameraUpdateSystem(ctx, transforms, cameras); - RunProbeUpdateSystem(transforms, aabb_probes, probes); + RunDecalUpdateSystem(ctx, transforms, materials, aabb_decals, decals); - RunForceUpdateSystem(transforms, forces); + RunProbeUpdateSystem(ctx, transforms, aabb_probes, probes); - RunLightUpdateSystem(transforms, aabb_lights, lights); + RunForceUpdateSystem(ctx, transforms, forces); - RunParticleUpdateSystem(transforms, meshes, emitters, hairs, dt); + RunLightUpdateSystem(ctx, transforms, aabb_lights, lights); - wiJobSystem::Wait(); // dependecies + RunParticleUpdateSystem(ctx, transforms, meshes, emitters, hairs, dt); - RunWeatherUpdateSystem(weathers, lights, weather); + wiJobSystem::Wait(ctx); // dependecies + + RunWeatherUpdateSystem(ctx, weathers, lights, weather); } void Scene::Clear() { @@ -1481,11 +1482,12 @@ namespace wiSceneSystem const uint32_t small_subtask_groupsize = 1024; void RunPreviousFrameTransformUpdateSystem( + wiJobSystem::context& ctx, const ComponentManager& transforms, ComponentManager& prev_transforms ) { - wiJobSystem::Dispatch((uint32_t)prev_transforms.GetCount(), small_subtask_groupsize, [&](wiJobDispatchArgs args) { + wiJobSystem::Dispatch(ctx, (uint32_t)prev_transforms.GetCount(), small_subtask_groupsize, [&](wiJobDispatchArgs args) { PreviousFrameTransformComponent& prev_transform = prev_transforms[args.jobIndex]; Entity entity = prev_transforms.GetEntity(args.jobIndex); @@ -1495,6 +1497,7 @@ namespace wiSceneSystem }); } void RunAnimationUpdateSystem( + wiJobSystem::context& ctx, ComponentManager& animations, ComponentManager& transforms, float dt @@ -1617,15 +1620,18 @@ namespace wiSceneSystem } } } - void RunTransformUpdateSystem(ComponentManager& transforms) + void RunTransformUpdateSystem( + wiJobSystem::context& ctx, + ComponentManager& transforms) { - wiJobSystem::Dispatch((uint32_t)transforms.GetCount(), small_subtask_groupsize, [&](wiJobDispatchArgs args) { + wiJobSystem::Dispatch(ctx, (uint32_t)transforms.GetCount(), small_subtask_groupsize, [&](wiJobDispatchArgs args) { TransformComponent& transform = transforms[args.jobIndex]; transform.UpdateTransform(); }); } void RunHierarchyUpdateSystem( + wiJobSystem::context& ctx, const ComponentManager& hierarchy, ComponentManager& transforms, ComponentManager& layers @@ -1656,11 +1662,12 @@ namespace wiSceneSystem } } void RunArmatureUpdateSystem( + wiJobSystem::context& ctx, const ComponentManager& transforms, ComponentManager& armatures ) { - wiJobSystem::Dispatch((uint32_t)armatures.GetCount(), 1, [&](wiJobDispatchArgs args) { + wiJobSystem::Dispatch(ctx, (uint32_t)armatures.GetCount(), 1, [&](wiJobDispatchArgs args) { ArmatureComponent& armature = armatures[args.jobIndex]; Entity entity = armatures.GetEntity(args.jobIndex); @@ -1697,9 +1704,11 @@ namespace wiSceneSystem }); } - void RunMaterialUpdateSystem(ComponentManager& materials, float dt) + void RunMaterialUpdateSystem( + wiJobSystem::context& ctx, + ComponentManager& materials, float dt) { - wiJobSystem::Dispatch((uint32_t)materials.GetCount(), small_subtask_groupsize, [&](wiJobDispatchArgs args) { + wiJobSystem::Dispatch(ctx, (uint32_t)materials.GetCount(), small_subtask_groupsize, [&](wiJobDispatchArgs args) { MaterialComponent& material = materials[args.jobIndex]; @@ -1720,9 +1729,11 @@ namespace wiSceneSystem } }); } - void RunImpostorUpdateSystem(ComponentManager& impostors) + void RunImpostorUpdateSystem( + wiJobSystem::context& ctx, + ComponentManager& impostors) { - wiJobSystem::Dispatch((uint32_t)impostors.GetCount(), 1, [&](wiJobDispatchArgs args) { + wiJobSystem::Dispatch(ctx, (uint32_t)impostors.GetCount(), 1, [&](wiJobDispatchArgs args) { ImpostorComponent& impostor = impostors[args.jobIndex]; impostor.aabb = AABB(); @@ -1730,6 +1741,7 @@ namespace wiSceneSystem }); } void RunObjectUpdateSystem( + wiJobSystem::context& ctx, const ComponentManager& prev_transforms, const ComponentManager& transforms, const ComponentManager& meshes, @@ -1747,7 +1759,7 @@ namespace wiSceneSystem sceneBounds = AABB(); // Instead of Dispatching, this will be one big job, because there is contention for several resources (sceneBounds, waterPlane, impostors) - wiJobSystem::Execute([&] { + wiJobSystem::Execute(ctx, [&] { for (size_t i = 0; i < objects.GetCount(); ++i) { @@ -1868,11 +1880,12 @@ namespace wiSceneSystem }); } void RunCameraUpdateSystem( + wiJobSystem::context& ctx, const ComponentManager& transforms, ComponentManager& cameras ) { - wiJobSystem::Dispatch((uint32_t)cameras.GetCount(), small_subtask_groupsize, [&](wiJobDispatchArgs args) { + wiJobSystem::Dispatch(ctx, (uint32_t)cameras.GetCount(), small_subtask_groupsize, [&](wiJobDispatchArgs args) { CameraComponent& camera = cameras[args.jobIndex]; Entity entity = cameras.GetEntity(args.jobIndex); @@ -1885,6 +1898,7 @@ namespace wiSceneSystem }); } void RunDecalUpdateSystem( + wiJobSystem::context& ctx, const ComponentManager& transforms, const ComponentManager& materials, ComponentManager& aabb_decals, @@ -1893,7 +1907,7 @@ namespace wiSceneSystem { assert(decals.GetCount() == aabb_decals.GetCount()); - wiJobSystem::Dispatch((uint32_t)decals.GetCount(), small_subtask_groupsize, [&](wiJobDispatchArgs args) { + wiJobSystem::Dispatch(ctx, (uint32_t)decals.GetCount(), small_subtask_groupsize, [&](wiJobDispatchArgs args) { DecalComponent& decal = decals[args.jobIndex]; Entity entity = decals.GetEntity(args.jobIndex); @@ -1924,6 +1938,7 @@ namespace wiSceneSystem }); } void RunProbeUpdateSystem( + wiJobSystem::context& ctx, const ComponentManager& transforms, ComponentManager& aabb_probes, ComponentManager& probes @@ -1931,7 +1946,7 @@ namespace wiSceneSystem { assert(probes.GetCount() == aabb_probes.GetCount()); - wiJobSystem::Dispatch((uint32_t)probes.GetCount(), small_subtask_groupsize, [&](wiJobDispatchArgs args) { + wiJobSystem::Dispatch(ctx, (uint32_t)probes.GetCount(), small_subtask_groupsize, [&](wiJobDispatchArgs args) { EnvironmentProbeComponent& probe = probes[args.jobIndex]; Entity entity = probes.GetEntity(args.jobIndex); @@ -1954,11 +1969,12 @@ namespace wiSceneSystem }); } void RunForceUpdateSystem( + wiJobSystem::context& ctx, const ComponentManager& transforms, ComponentManager& forces ) { - wiJobSystem::Dispatch((uint32_t)forces.GetCount(), small_subtask_groupsize, [&](wiJobDispatchArgs args) { + wiJobSystem::Dispatch(ctx, (uint32_t)forces.GetCount(), small_subtask_groupsize, [&](wiJobDispatchArgs args) { ForceFieldComponent& force = forces[args.jobIndex]; Entity entity = forces.GetEntity(args.jobIndex); @@ -1975,6 +1991,7 @@ namespace wiSceneSystem }); } void RunLightUpdateSystem( + wiJobSystem::context& ctx, const ComponentManager& transforms, ComponentManager& aabb_lights, ComponentManager& lights @@ -1982,7 +1999,7 @@ namespace wiSceneSystem { assert(lights.GetCount() == aabb_lights.GetCount()); - wiJobSystem::Dispatch((uint32_t)lights.GetCount(), small_subtask_groupsize, [&](wiJobDispatchArgs args) { + wiJobSystem::Dispatch(ctx, (uint32_t)lights.GetCount(), small_subtask_groupsize, [&](wiJobDispatchArgs args) { LightComponent& light = lights[args.jobIndex]; Entity entity = lights.GetEntity(args.jobIndex); @@ -2025,6 +2042,7 @@ namespace wiSceneSystem }); } void RunParticleUpdateSystem( + wiJobSystem::context& ctx, const ComponentManager& transforms, const ComponentManager& meshes, ComponentManager& emitters, @@ -2032,7 +2050,7 @@ namespace wiSceneSystem float dt ) { - wiJobSystem::Dispatch((uint32_t)emitters.GetCount(), small_subtask_groupsize, [&](wiJobDispatchArgs args) { + wiJobSystem::Dispatch(ctx, (uint32_t)emitters.GetCount(), small_subtask_groupsize, [&](wiJobDispatchArgs args) { wiEmittedParticle& emitter = emitters[args.jobIndex]; Entity entity = emitters.GetEntity(args.jobIndex); @@ -2040,7 +2058,7 @@ namespace wiSceneSystem emitter.UpdateCPU(transform, dt); }); - wiJobSystem::Dispatch((uint32_t)hairs.GetCount(), small_subtask_groupsize, [&](wiJobDispatchArgs args) { + wiJobSystem::Dispatch(ctx, (uint32_t)hairs.GetCount(), small_subtask_groupsize, [&](wiJobDispatchArgs args) { wiHairParticle& hair = hairs[args.jobIndex]; Entity entity = hairs.GetEntity(args.jobIndex); @@ -2059,6 +2077,7 @@ namespace wiSceneSystem }); } void RunWeatherUpdateSystem( + wiJobSystem::context& ctx, const ComponentManager& weathers, const ComponentManager& lights, WeatherComponent& weather) diff --git a/WickedEngine/wiSceneSystem.h b/WickedEngine/wiSceneSystem.h index ebe9803f4..7880767d4 100644 --- a/WickedEngine/wiSceneSystem.h +++ b/WickedEngine/wiSceneSystem.h @@ -5,6 +5,7 @@ #include "wiEmittedParticle.h" #include "wiHairParticle.h" #include "ShaderInterop_Renderer.h" +#include "wiJobSystem.h" #include "wiECS.h" #include "wiSceneSystem_Decl.h" @@ -1058,27 +1059,41 @@ namespace wiSceneSystem }; void RunPreviousFrameTransformUpdateSystem( + wiJobSystem::context& ctx, const wiECS::ComponentManager& transforms, wiECS::ComponentManager& prev_transforms ); void RunAnimationUpdateSystem( + wiJobSystem::context& ctx, wiECS::ComponentManager& animations, wiECS::ComponentManager& transforms, float dt ); - void RunTransformUpdateSystem(wiECS::ComponentManager& transforms); + void RunTransformUpdateSystem( + wiJobSystem::context& ctx, + wiECS::ComponentManager& transforms + ); void RunHierarchyUpdateSystem( + wiJobSystem::context& ctx, const wiECS::ComponentManager& hierarchy, wiECS::ComponentManager& transforms, wiECS::ComponentManager& layers ); void RunArmatureUpdateSystem( + wiJobSystem::context& ctx, const wiECS::ComponentManager& transforms, wiECS::ComponentManager& armatures ); - void RunMaterialUpdateSystem(wiECS::ComponentManager& materials, float dt); - void RunImpostorUpdateSystem(wiECS::ComponentManager& impostors); + void RunMaterialUpdateSystem( + wiJobSystem::context& ctx, + wiECS::ComponentManager& materials, float dt + ); + void RunImpostorUpdateSystem( + wiJobSystem::context& ctx, + wiECS::ComponentManager& impostors + ); void RunObjectUpdateSystem( + wiJobSystem::context& ctx, const wiECS::ComponentManager& prev_transforms, const wiECS::ComponentManager& transforms, const wiECS::ComponentManager& meshes, @@ -1091,30 +1106,36 @@ namespace wiSceneSystem XMFLOAT4& waterPlane ); void RunCameraUpdateSystem( + wiJobSystem::context& ctx, const wiECS::ComponentManager& transforms, wiECS::ComponentManager& cameras ); void RunDecalUpdateSystem( + wiJobSystem::context& ctx, const wiECS::ComponentManager& transforms, const wiECS::ComponentManager& materials, wiECS::ComponentManager& aabb_decals, wiECS::ComponentManager& decals ); void RunProbeUpdateSystem( + wiJobSystem::context& ctx, const wiECS::ComponentManager& transforms, wiECS::ComponentManager& aabb_probes, wiECS::ComponentManager& probes ); void RunForceUpdateSystem( + wiJobSystem::context& ctx, const wiECS::ComponentManager& transforms, wiECS::ComponentManager& forces ); void RunLightUpdateSystem( + wiJobSystem::context& ctx, const wiECS::ComponentManager& transforms, wiECS::ComponentManager& aabb_lights, wiECS::ComponentManager& lights ); void RunParticleUpdateSystem( + wiJobSystem::context& ctx, const wiECS::ComponentManager& transforms, const wiECS::ComponentManager& meshes, wiECS::ComponentManager& emitters, @@ -1122,6 +1143,7 @@ namespace wiSceneSystem float dt ); void RunWeatherUpdateSystem( + wiJobSystem::context& ctx, const wiECS::ComponentManager& weathers, const wiECS::ComponentManager& lights, WeatherComponent& weather From 63246ace63638900bbbcf69ca79abd2884f2b527 Mon Sep 17 00:00:00 2001 From: turanszkij Date: Sat, 29 Jun 2019 16:53:34 +0100 Subject: [PATCH 2/2] jobsystem update: polling doesn't yield any more --- WickedEngine/wiJobSystem.cpp | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/WickedEngine/wiJobSystem.cpp b/WickedEngine/wiJobSystem.cpp index de9f4083f..86b9f3024 100644 --- a/WickedEngine/wiJobSystem.cpp +++ b/WickedEngine/wiJobSystem.cpp @@ -33,12 +33,6 @@ namespace wiJobSystem } return false; } - // This little function will not let the system to be deadlocked while the issuing thread is waiting for something - inline void poll() - { - wakeCondition.notify_one(); // wake one worker thread - std::this_thread::yield(); // allow this thread to be rescheduled - } void Initialize() { @@ -105,9 +99,10 @@ namespace wiJobSystem ctx.counter.fetch_add(1); // Try to push a new job until it is pushed successfully: - while (!jobPool.push_back({ job, &ctx })) { poll(); } + while (!jobPool.push_back({ job, &ctx })) { wakeCondition.notify_all(); } - wakeCondition.notify_one(); // wake one thread + // Wake any one thread that might be sleeping: + wakeCondition.notify_one(); } void Dispatch(context& ctx, uint32_t jobCount, uint32_t groupSize, const std::function& job) @@ -144,12 +139,11 @@ namespace wiJobSystem }; // Try to push a new job until it is pushed successfully: - while (!jobPool.push_back({ jobGroup, &ctx })) { poll(); } - - wakeCondition.notify_one(); // wake one thread + while (!jobPool.push_back({ jobGroup, &ctx })) { wakeCondition.notify_all(); } } - + // Wake any threads that might be sleeping: + wakeCondition.notify_all(); } bool IsBusy(const context& ctx) @@ -160,7 +154,10 @@ namespace wiJobSystem void Wait(const context& ctx) { + // Wake any threads that might be sleeping: + wakeCondition.notify_all(); + // Waiting will also put the current thread to good use by working on an other job if it can: - while (IsBusy(ctx)) { work(); poll(); } + while (IsBusy(ctx)) { work(); } } }