diff --git a/WickedEngine/wiJobSystem.cpp b/WickedEngine/wiJobSystem.cpp index 6d018de01..5feed8524 100644 --- a/WickedEngine/wiJobSystem.cpp +++ b/WickedEngine/wiJobSystem.cpp @@ -28,16 +28,17 @@ namespace wiJobSystem auto numCores = std::thread::hardware_concurrency(); // Calculate the actual number of worker threads we want: - numThreads = max(1, numCores); + numThreads = max(1, numCores - 1); for (unsigned int threadID = 0; threadID < numThreads; ++threadID) { - std::thread([] { + std::thread worker([] { while (true) { Job job; bool working = false; + std::unique_lock lock(wakeMutex); jobLock.lock(); { @@ -58,12 +59,33 @@ namespace wiJobSystem else { // no job, put thread to sleep - std::unique_lock lock(wakeMutex); wakeCondition.wait(lock); } } - }).detach(); + }); + +#ifdef _WIN32 + // Do Windows-specific thread setup: + HANDLE handle = (HANDLE)worker.native_handle(); + + // Put each thread on to dedicated core (but leave core 0 to main thread) + DWORD_PTR affinityMask = 1ull << (threadID + 1); + DWORD_PTR affinity_result = SetThreadAffinityMask(handle, affinityMask); + assert(affinity_result > 0); + + // Increase thread priority: + BOOL priority_result = SetThreadPriority(handle, THREAD_PRIORITY_HIGHEST); + assert(priority_result != 0); + + // Name the thread: + std::wstringstream wss; + wss << "wiJobSystem_" << threadID; + HRESULT hr = SetThreadDescription(handle, wss.str().c_str()); + assert(SUCCEEDED(hr)); +#endif // _WIN32 + + worker.detach(); } std::stringstream ss(""); @@ -71,7 +93,7 @@ namespace wiJobSystem wiBackLog::post(ss.str().c_str()); } - unsigned int GetThreadCount() + uint32_t GetThreadCount() { return numThreads; } @@ -80,56 +102,61 @@ namespace wiJobSystem { while (waitBarrier.load() == true) { std::this_thread::yield(); } // can't add jobs while Wait() is in progress - // This is important, and acts as a barrier for Wait(): remainingJobs.fetch_add(1); jobLock.lock(); jobPool.push_back(job); jobLock.unlock(); - wakeCondition.notify_one(); // only wake a single thread + wakeCondition.notify_one(); // wake one thread } - void Dispatch(uint32_t jobCount, uint32_t groupSize, const std::function& job) + void Dispatch(uint32_t jobCount, uint32_t groupSize, const std::function& job) { if (jobCount == 0 || groupSize == 0) { return; } + + // Calculate the amount of job groups to dispatch (overestimate, or "ceil"): + const uint32_t groupCount = (jobCount + groupSize - 1) / groupSize; + while (waitBarrier.load() == true) { std::this_thread::yield(); } // can't add jobs while Wait() is in progress - // Calculate the amount of job groups to dispatch: - const uint32_t jobGroupCount = (uint32_t)ceilf((float)jobCount / (float)groupSize); + remainingJobs.fetch_add(groupCount); - // This is important, and acts as a barrier for Wait(): - remainingJobs.fetch_add(jobGroupCount); - - jobLock.lock(); - for (uint32_t i = 0; i < jobGroupCount; ++i) + for (uint32_t groupIndex = 0; groupIndex < groupCount; ++groupIndex) { // Calculate the current group's offset into the jobs: - const uint32_t jobOffset = i * groupSize; + const uint32_t jobOffset = groupIndex * groupSize; // For each group, generate a real job: - jobPool.push_back([jobCount, groupSize, job, jobOffset]() { + jobLock.lock(); + jobPool.push_back([jobCount, groupSize, job, groupIndex, jobOffset]() { + + JobDispatchArgs args; + args.groupIndex = groupIndex; // Inside the group, loop through all sub-jobs and propagate sub-job index: for (uint32_t j = 0; j < groupSize; ++j) { - const uint32_t jobIndex = jobOffset + j; - if (jobIndex >= jobCount) + args.jobIndex = jobOffset + j; + if (args.jobIndex >= jobCount) { // The amount of sub-jobs can be larger than the jobCount, so if that happens, don't issue the sub-job: - break; + return; } - job(jobIndex); + // Issue the sub-job: + job(args); } }); + jobLock.unlock(); + + wakeCondition.notify_one(); // wake one thread so it can start working immediately } - jobLock.unlock(); - wakeCondition.notify_all(); // wake all threads + } bool IsBusy() diff --git a/WickedEngine/wiJobSystem.h b/WickedEngine/wiJobSystem.h index 4e474f0e1..f92ffa858 100644 --- a/WickedEngine/wiJobSystem.h +++ b/WickedEngine/wiJobSystem.h @@ -2,6 +2,12 @@ #include +struct JobDispatchArgs +{ + uint32_t jobIndex; + uint32_t groupIndex; +}; + namespace wiJobSystem { void Initialize(); @@ -14,8 +20,8 @@ namespace wiJobSystem // 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 the job invocation index (0, 1, ... jobCount) as lambda argument - void Dispatch(uint32_t jobCount, uint32_t groupSize, const std::function& job); + // func : receives a JobDispatchArgs as parameter + void Dispatch(uint32_t jobCount, uint32_t groupSize, const std::function& job); // Check if any threads are working currently or not bool IsBusy(); diff --git a/WickedEngine/wiPhysicsEngine_Bullet.cpp b/WickedEngine/wiPhysicsEngine_Bullet.cpp index ced057ab4..f22a2de52 100644 --- a/WickedEngine/wiPhysicsEngine_Bullet.cpp +++ b/WickedEngine/wiPhysicsEngine_Bullet.cpp @@ -316,10 +316,10 @@ 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(), 8, [&](uint32_t jobIndex) { + wiJobSystem::Dispatch((uint32_t)rigidbodies.GetCount(), 8, [&](JobDispatchArgs args) { - RigidBodyPhysicsComponent& physicscomponent = rigidbodies[jobIndex]; - Entity entity = rigidbodies.GetEntity(jobIndex); + RigidBodyPhysicsComponent& physicscomponent = rigidbodies[args.jobIndex]; + Entity entity = rigidbodies.GetEntity(args.jobIndex); if (physicscomponent.physicsobject == nullptr) { @@ -366,10 +366,10 @@ namespace wiPhysicsEngine }); // System will register softbodies to meshes and update physics engine state: - wiJobSystem::Dispatch((uint32_t)softbodies.GetCount(), 1, [&](uint32_t jobIndex) { + wiJobSystem::Dispatch((uint32_t)softbodies.GetCount(), 1, [&](JobDispatchArgs args) { - SoftBodyPhysicsComponent& physicscomponent = softbodies[jobIndex]; - Entity entity = softbodies.GetEntity(jobIndex); + SoftBodyPhysicsComponent& physicscomponent = softbodies[args.jobIndex]; + Entity entity = softbodies.GetEntity(args.jobIndex); MeshComponent& mesh = *meshes.GetComponent(entity); mesh.SetDynamic(true); diff --git a/WickedEngine/wiSceneSystem.cpp b/WickedEngine/wiSceneSystem.cpp index 0723ca61e..8ca693950 100644 --- a/WickedEngine/wiSceneSystem.cpp +++ b/WickedEngine/wiSceneSystem.cpp @@ -1334,17 +1334,17 @@ namespace wiSceneSystem } - const uint32_t small_subtask_groupsize = 32; + const uint32_t small_subtask_groupsize = 64; void RunPreviousFrameTransformUpdateSystem( const ComponentManager& transforms, ComponentManager& prev_transforms ) { - wiJobSystem::Dispatch((uint32_t)prev_transforms.GetCount(), small_subtask_groupsize, [&](uint32_t jobIndex) { + wiJobSystem::Dispatch((uint32_t)prev_transforms.GetCount(), small_subtask_groupsize, [&](JobDispatchArgs args) { - PreviousFrameTransformComponent& prev_transform = prev_transforms[jobIndex]; - Entity entity = prev_transforms.GetEntity(jobIndex); + PreviousFrameTransformComponent& prev_transform = prev_transforms[args.jobIndex]; + Entity entity = prev_transforms.GetEntity(args.jobIndex); const TransformComponent& transform = *transforms.GetComponent(entity); prev_transform.world_prev = transform.world; @@ -1475,9 +1475,9 @@ namespace wiSceneSystem } void RunTransformUpdateSystem(ComponentManager& transforms) { - wiJobSystem::Dispatch((uint32_t)transforms.GetCount(), small_subtask_groupsize, [&](uint32_t jobIndex) { + wiJobSystem::Dispatch((uint32_t)transforms.GetCount(), small_subtask_groupsize, [&](JobDispatchArgs args) { - TransformComponent& transform = transforms[jobIndex]; + TransformComponent& transform = transforms[args.jobIndex]; transform.UpdateTransform(); }); } @@ -1516,9 +1516,9 @@ namespace wiSceneSystem ComponentManager& armatures ) { - wiJobSystem::Dispatch((uint32_t)armatures.GetCount(), 1, [&](uint32_t jobIndex) { + wiJobSystem::Dispatch((uint32_t)armatures.GetCount(), 1, [&](JobDispatchArgs args) { - ArmatureComponent& armature = armatures[jobIndex]; + ArmatureComponent& armature = armatures[args.jobIndex]; if (armature.boneData.size() != armature.boneCollection.size()) { @@ -1543,9 +1543,9 @@ namespace wiSceneSystem } void RunMaterialUpdateSystem(ComponentManager& materials, float dt) { - wiJobSystem::Dispatch((uint32_t)materials.GetCount(), small_subtask_groupsize, [&](uint32_t jobIndex) { + wiJobSystem::Dispatch((uint32_t)materials.GetCount(), small_subtask_groupsize, [&](JobDispatchArgs args) { - MaterialComponent& material = materials[jobIndex]; + MaterialComponent& material = materials[args.jobIndex]; material.texAnimSleep -= dt * material.texAnimFrameRate; if (material.texAnimSleep <= 0) @@ -1566,9 +1566,9 @@ namespace wiSceneSystem } void RunImpostorUpdateSystem(ComponentManager& impostors) { - wiJobSystem::Dispatch((uint32_t)impostors.GetCount(), 1, [&](uint32_t jobIndex) { + wiJobSystem::Dispatch((uint32_t)impostors.GetCount(), 1, [&](JobDispatchArgs args) { - ImpostorComponent& impostor = impostors[jobIndex]; + ImpostorComponent& impostor = impostors[args.jobIndex]; impostor.aabb = AABB(); impostor.instanceMatrices.clear(); }); @@ -1591,10 +1591,10 @@ namespace wiSceneSystem sceneBounds = AABB(); static wiSpinLock lock; // contention for sceneBounds and waterPlane! - wiJobSystem::Dispatch((uint32_t)objects.GetCount(), small_subtask_groupsize, [&](uint32_t jobIndex) { + wiJobSystem::Dispatch((uint32_t)objects.GetCount(), small_subtask_groupsize, [&](JobDispatchArgs args) { - ObjectComponent& object = objects[jobIndex]; - AABB& aabb = aabb_objects[jobIndex]; + ObjectComponent& object = objects[args.jobIndex]; + AABB& aabb = aabb_objects[args.jobIndex]; aabb = AABB(); object.rendertypeMask = 0; @@ -1605,7 +1605,7 @@ namespace wiSceneSystem if (object.meshID != INVALID_ENTITY) { - Entity entity = objects.GetEntity(jobIndex); + Entity entity = objects.GetEntity(args.jobIndex); const MeshComponent* mesh = meshes.GetComponent(object.meshID); // These will only be valid for a single frame: @@ -1708,10 +1708,10 @@ namespace wiSceneSystem ComponentManager& cameras ) { - wiJobSystem::Dispatch((uint32_t)cameras.GetCount(), small_subtask_groupsize, [&](uint32_t jobIndex) { + wiJobSystem::Dispatch((uint32_t)cameras.GetCount(), small_subtask_groupsize, [&](JobDispatchArgs args) { - CameraComponent& camera = cameras[jobIndex]; - Entity entity = cameras.GetEntity(jobIndex); + CameraComponent& camera = cameras[args.jobIndex]; + Entity entity = cameras.GetEntity(args.jobIndex); const TransformComponent* transform = transforms.GetComponent(entity); if (transform != nullptr) { @@ -1729,10 +1729,10 @@ namespace wiSceneSystem { assert(decals.GetCount() == aabb_decals.GetCount()); - wiJobSystem::Dispatch((uint32_t)decals.GetCount(), small_subtask_groupsize, [&](uint32_t jobIndex) { + wiJobSystem::Dispatch((uint32_t)decals.GetCount(), small_subtask_groupsize, [&](JobDispatchArgs args) { - DecalComponent& decal = decals[jobIndex]; - Entity entity = decals.GetEntity(jobIndex); + DecalComponent& decal = decals[args.jobIndex]; + Entity entity = decals.GetEntity(args.jobIndex); const TransformComponent& transform = *transforms.GetComponent(entity); decal.world = transform.world; @@ -1748,7 +1748,7 @@ namespace wiSceneSystem XMStoreFloat3(&scale, S); decal.range = max(scale.x, max(scale.y, scale.z)) * 2; - AABB& aabb = aabb_decals[jobIndex]; + AABB& aabb = aabb_decals[args.jobIndex]; aabb.createFromHalfWidth(XMFLOAT3(0, 0, 0), XMFLOAT3(1, 1, 1)); aabb = aabb.get(transform.world); @@ -1767,10 +1767,10 @@ namespace wiSceneSystem { assert(probes.GetCount() == aabb_probes.GetCount()); - wiJobSystem::Dispatch((uint32_t)probes.GetCount(), small_subtask_groupsize, [&](uint32_t jobIndex) { + wiJobSystem::Dispatch((uint32_t)probes.GetCount(), small_subtask_groupsize, [&](JobDispatchArgs args) { - EnvironmentProbeComponent& probe = probes[jobIndex]; - Entity entity = probes.GetEntity(jobIndex); + EnvironmentProbeComponent& probe = probes[args.jobIndex]; + Entity entity = probes.GetEntity(args.jobIndex); const TransformComponent& transform = *transforms.GetComponent(entity); probe.position = transform.GetPosition(); @@ -1784,7 +1784,7 @@ namespace wiSceneSystem XMStoreFloat3(&scale, S); probe.range = max(scale.x, max(scale.y, scale.z)) * 2; - AABB& aabb = aabb_probes[jobIndex]; + AABB& aabb = aabb_probes[args.jobIndex]; aabb.createFromHalfWidth(XMFLOAT3(0, 0, 0), XMFLOAT3(1, 1, 1)); aabb = aabb.get(transform.world); }); @@ -1794,10 +1794,10 @@ namespace wiSceneSystem ComponentManager& forces ) { - wiJobSystem::Dispatch((uint32_t)forces.GetCount(), small_subtask_groupsize, [&](uint32_t jobIndex) { + wiJobSystem::Dispatch((uint32_t)forces.GetCount(), small_subtask_groupsize, [&](JobDispatchArgs args) { - ForceFieldComponent& force = forces[jobIndex]; - Entity entity = forces.GetEntity(jobIndex); + ForceFieldComponent& force = forces[args.jobIndex]; + Entity entity = forces.GetEntity(args.jobIndex); const TransformComponent& transform = *transforms.GetComponent(entity); force.position = transform.GetPosition(); XMStoreFloat3(&force.direction, XMVector3Normalize(XMVector3TransformNormal(XMVectorSet(0, -1, 0, 0), XMLoadFloat4x4(&transform.world)))); @@ -1811,12 +1811,12 @@ namespace wiSceneSystem { assert(lights.GetCount() == aabb_lights.GetCount()); - wiJobSystem::Dispatch((uint32_t)lights.GetCount(), small_subtask_groupsize, [&](uint32_t jobIndex) { + wiJobSystem::Dispatch((uint32_t)lights.GetCount(), small_subtask_groupsize, [&](JobDispatchArgs args) { - LightComponent& light = lights[jobIndex]; - Entity entity = lights.GetEntity(jobIndex); + LightComponent& light = lights[args.jobIndex]; + Entity entity = lights.GetEntity(args.jobIndex); const TransformComponent& transform = *transforms.GetComponent(entity); - AABB& aabb = aabb_lights[jobIndex]; + AABB& aabb = aabb_lights[args.jobIndex]; XMMATRIX W = XMLoadFloat4x4(&transform.world); XMVECTOR S, R, T; @@ -1858,16 +1858,16 @@ namespace wiSceneSystem float dt ) { - wiJobSystem::Dispatch((uint32_t)emitters.GetCount(), small_subtask_groupsize, [&](uint32_t jobIndex) { + wiJobSystem::Dispatch((uint32_t)emitters.GetCount(), small_subtask_groupsize, [&](JobDispatchArgs args) { - wiEmittedParticle& emitter = emitters[jobIndex]; + wiEmittedParticle& emitter = emitters[args.jobIndex]; emitter.Update(dt); }); - wiJobSystem::Dispatch((uint32_t)hairs.GetCount(), small_subtask_groupsize, [&](uint32_t jobIndex) { + wiJobSystem::Dispatch((uint32_t)hairs.GetCount(), small_subtask_groupsize, [&](JobDispatchArgs args) { - wiHairParticle& hair = hairs[jobIndex]; - Entity entity = hairs.GetEntity(jobIndex); + wiHairParticle& hair = hairs[args.jobIndex]; + Entity entity = hairs.GetEntity(args.jobIndex); const TransformComponent& transform = *transforms.GetComponent(entity); hair.world = transform.world; diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index b97e5b3cf..39c012171 100644 --- a/WickedEngine/wiVersion.cpp +++ b/WickedEngine/wiVersion.cpp @@ -9,7 +9,7 @@ namespace wiVersion // minor features, major updates const int minor = 22; // minor bug fixes, alterations, refactors, updates - const int revision = 5; + const int revision = 6; long GetVersion()