diff --git a/WickedEngine/RenderPath3D.cpp b/WickedEngine/RenderPath3D.cpp index ab553a38d..bf38be6fa 100644 --- a/WickedEngine/RenderPath3D.cpp +++ b/WickedEngine/RenderPath3D.cpp @@ -213,9 +213,9 @@ void RenderPath3D::FixedUpdate() void RenderPath3D::Update(float dt) { - wiRenderer::UpdatePerFrameData(dt); - RenderPath2D::Update(dt); + + wiRenderer::UpdatePerFrameData(dt); } void RenderPath3D::Compose() diff --git a/WickedEngine/wiEmittedParticle.cpp b/WickedEngine/wiEmittedParticle.cpp index c87d13a54..ea1ab2be4 100644 --- a/WickedEngine/wiEmittedParticle.cpp +++ b/WickedEngine/wiEmittedParticle.cpp @@ -225,12 +225,27 @@ uint32_t wiEmittedParticle::GetMemorySizeInBytes() const return retVal; } -void wiEmittedParticle::Update(float dt) +void wiEmittedParticle::UpdateCPU(const TransformComponent& transform, float dt) { if (IsPaused()) return; + emit = max(0, emit - floorf(emit)); + + CreateSelfBuffers(); + + center = transform.GetPosition(); + emit += (float)count*dt; + + // Swap CURRENT alivelist with NEW alivelist + aliveList[0].swap(aliveList[1]); + + + if (IsDebug()) + { + wiRenderer::GetDevice()->DownloadResource(counterBuffer.get(), debugDataReadbackBuffer.get(), &debugData, GRAPHICSTHREAD_IMMEDIATE); + } } void wiEmittedParticle::Burst(float num) { @@ -246,18 +261,17 @@ void wiEmittedParticle::Restart() } //#define DEBUG_SORTING // slow but great for debug!! -void wiEmittedParticle::UpdateRenderData(const TransformComponent& transform, const MaterialComponent& material, const MeshComponent* mesh, GRAPHICSTHREAD threadID) +void wiEmittedParticle::UpdateGPU(const TransformComponent& transform, const MaterialComponent& material, const MeshComponent* mesh, GRAPHICSTHREAD threadID) const { - center = transform.GetPosition(); - - CreateSelfBuffers(); + if (particleBuffer == nullptr) + { + return; + } GraphicsDevice* device = wiRenderer::GetDevice(); - if (!IsPaused()) { - device->EventBegin("UpdateEmittedParticles", threadID); EmittedParticleCB cb; @@ -568,16 +582,6 @@ void wiEmittedParticle::UpdateRenderData(const TransformComponent& transform, co device->UnbindUAVs(0, ARRAYSIZE(uavs), threadID); device->UnbindResources(0, ARRAYSIZE(res), threadID); device->EventEnd(threadID); - - - // Swap CURRENT alivelist with NEW alivelist - aliveList[0].swap(aliveList[1]); - emit -= (UINT)emit; - } - - if (IsDebug()) - { - device->DownloadResource(counterBuffer.get(), debugDataReadbackBuffer.get(), &debugData, threadID); } } @@ -601,7 +605,7 @@ void wiEmittedParticle::Draw(const CameraComponent& camera, const MaterialCompon GPUResource* res[] = { particleBuffer.get(), - aliveList[0].get() + aliveList[1].get() // NEW aliveList }; device->TransitionBarrier(res, ARRAYSIZE(res), RESOURCE_STATE_UNORDERED_ACCESS, RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, threadID); device->BindResources(VS, res, 0, ARRAYSIZE(res), threadID); diff --git a/WickedEngine/wiEmittedParticle.h b/WickedEngine/wiEmittedParticle.h index 4ab66dc06..f4859cec0 100644 --- a/WickedEngine/wiEmittedParticle.h +++ b/WickedEngine/wiEmittedParticle.h @@ -48,12 +48,12 @@ private: uint32_t MAX_PARTICLES = 1000; public: - void Update(float dt); + void UpdateCPU(const TransformComponent& transform, float dt); void Burst(float num); void Restart(); // Must have a transform and material component, but mesh is optional - void UpdateRenderData(const TransformComponent& transform, const MaterialComponent& material, const MeshComponent* mesh, GRAPHICSTHREAD threadID); + void UpdateGPU(const TransformComponent& transform, const MaterialComponent& material, const MeshComponent* mesh, GRAPHICSTHREAD threadID) const; void Draw(const CameraComponent& camera, const MaterialComponent& material, GRAPHICSTHREAD threadID) const; ParticleCounters GetDebugData() { return debugData; } diff --git a/WickedEngine/wiHairParticle.cpp b/WickedEngine/wiHairParticle.cpp index a382f6323..b8f8ee9b3 100644 --- a/WickedEngine/wiHairParticle.cpp +++ b/WickedEngine/wiHairParticle.cpp @@ -29,43 +29,64 @@ static GraphicsPSO PSO[RENDERPASS_COUNT][2]; static GraphicsPSO PSO_wire; static ComputePSO CPSO_simulate; -void wiHairParticle::UpdateRenderData(const MeshComponent& mesh, const MaterialComponent& material, GRAPHICSTHREAD threadID) +void wiHairParticle::UpdateCPU(const TransformComponent& transform, const MeshComponent& mesh, float dt) { - if (strandCount == 0) + world = transform.world; + + XMFLOAT3 _min = mesh.aabb.getMin(); + XMFLOAT3 _max = mesh.aabb.getMax(); + + _max.x += length; + _max.y += length; + _max.z += length; + + _min.x -= length; + _min.y -= length; + _min.z -= length; + + aabb = AABB(_min, _max); + aabb = aabb.get(world); + + if (dt > 0) { - return; + _flags &= ~REGENERATE_FRAME; + if (cb == nullptr || (strandCount * segmentCount) != particleBuffer->GetDesc().ByteWidth / sizeof(Patch)) + { + _flags |= REGENERATE_FRAME; + + cb.reset(new GPUBuffer); + particleBuffer.reset(new GPUBuffer); + simulationBuffer.reset(new GPUBuffer); + + GPUBufferDesc bd; + bd.Usage = USAGE_DEFAULT; + bd.BindFlags = BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS; + bd.CPUAccessFlags = 0; + bd.MiscFlags = RESOURCE_MISC_BUFFER_STRUCTURED; + + bd.StructureByteStride = sizeof(Patch); + bd.ByteWidth = bd.StructureByteStride * strandCount * segmentCount; + wiRenderer::GetDevice()->CreateBuffer(&bd, nullptr, particleBuffer.get()); + + bd.StructureByteStride = sizeof(PatchSimulationData); + bd.ByteWidth = bd.StructureByteStride * strandCount * segmentCount; + wiRenderer::GetDevice()->CreateBuffer(&bd, nullptr, simulationBuffer.get()); + + bd.Usage = USAGE_DYNAMIC; + bd.ByteWidth = sizeof(HairParticleCB); + bd.BindFlags = BIND_CONSTANT_BUFFER; + bd.CPUAccessFlags = CPU_ACCESS_WRITE; + bd.MiscFlags = 0; + wiRenderer::GetDevice()->CreateBuffer(&bd, nullptr, cb.get()); + } } - bool regenerate = false; - - if(cb == nullptr || (strandCount * segmentCount) != particleBuffer->GetDesc().ByteWidth / sizeof(Patch)) +} +void wiHairParticle::UpdateGPU(const MeshComponent& mesh, const MaterialComponent& material, GRAPHICSTHREAD threadID) const +{ + if (strandCount == 0 || particleBuffer == nullptr) { - regenerate = true; - - cb.reset(new GPUBuffer); - particleBuffer.reset(new GPUBuffer); - simulationBuffer.reset(new GPUBuffer); - - GPUBufferDesc bd; - bd.Usage = USAGE_DEFAULT; - bd.BindFlags = BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS; - bd.CPUAccessFlags = 0; - bd.MiscFlags = RESOURCE_MISC_BUFFER_STRUCTURED; - - bd.StructureByteStride = sizeof(Patch); - bd.ByteWidth = bd.StructureByteStride * strandCount * segmentCount; - wiRenderer::GetDevice()->CreateBuffer(&bd, nullptr, particleBuffer.get()); - - bd.StructureByteStride = sizeof(PatchSimulationData); - bd.ByteWidth = bd.StructureByteStride * strandCount * segmentCount; - wiRenderer::GetDevice()->CreateBuffer(&bd, nullptr, simulationBuffer.get()); - - bd.Usage = USAGE_DYNAMIC; - bd.ByteWidth = sizeof(HairParticleCB); - bd.BindFlags = BIND_CONSTANT_BUFFER; - bd.CPUAccessFlags = CPU_ACCESS_WRITE; - bd.MiscFlags = 0; - wiRenderer::GetDevice()->CreateBuffer(&bd, nullptr, cb.get()); + return; } GraphicsDevice* device = wiRenderer::GetDevice(); @@ -76,7 +97,7 @@ void wiHairParticle::UpdateRenderData(const MeshComponent& mesh, const MaterialC HairParticleCB hcb; hcb.xWorld = world; hcb.xColor = material.baseColor; - hcb.xHairRegenerate = regenerate ? 1 : 0; + hcb.xHairRegenerate = (_flags & REGENERATE_FRAME) ? 1 : 0; hcb.xLength = length; hcb.xStiffness = stiffness; hcb.xHairRandomness = randomness; diff --git a/WickedEngine/wiHairParticle.h b/WickedEngine/wiHairParticle.h index eae9ae42a..c5c990592 100644 --- a/WickedEngine/wiHairParticle.h +++ b/WickedEngine/wiHairParticle.h @@ -18,12 +18,14 @@ private: std::unique_ptr simulationBuffer; public: - void UpdateRenderData(const MeshComponent& mesh, const MaterialComponent& material, GRAPHICSTHREAD threadID); + void UpdateCPU(const TransformComponent& transform, const MeshComponent& mesh, float dt); + void UpdateGPU(const MeshComponent& mesh, const MaterialComponent& material, GRAPHICSTHREAD threadID) const; void Draw(const CameraComponent& camera, const MaterialComponent& material, RENDERPASS renderPass, bool transparent, GRAPHICSTHREAD threadID) const; enum FLAGS { EMPTY = 0, + REGENERATE_FRAME = 1 << 0, }; uint32_t _flags = EMPTY; diff --git a/WickedEngine/wiRenderer.cpp b/WickedEngine/wiRenderer.cpp index b53cd4beb..ba3fae065 100644 --- a/WickedEngine/wiRenderer.cpp +++ b/WickedEngine/wiRenderer.cpp @@ -264,6 +264,8 @@ struct FrameCulling }; unordered_map frameCullings; +vector pendingMaterialUpdates; + GFX_STRUCT Instance { XMFLOAT4A mat0; @@ -3510,7 +3512,35 @@ void UpdatePerFrameData(float dt) scene.Update(dt * GetGameSpeed()); - // Need to swap prev and current vertex buffers for any dynamic meshes BEFORE render threads are kicked: + // See which materials will need to update their GPU render data: + wiJobSystem::Execute([&] { + pendingMaterialUpdates.clear(); + for (size_t i = 0; i < scene.materials.GetCount(); ++i) + { + MaterialComponent& material = scene.materials[i]; + + if (material.IsDirty()) + { + material.SetDirty(false); + pendingMaterialUpdates.push_back(uint32_t(i)); + + if (material.constantBuffer == nullptr) + { + GPUBufferDesc desc; + desc.Usage = USAGE_DEFAULT; + desc.BindFlags = BIND_CONSTANT_BUFFER; + desc.ByteWidth = sizeof(MaterialCB); + + material.constantBuffer.reset(new GPUBuffer); + HRESULT hr = device->CreateBuffer(&desc, nullptr, material.constantBuffer.get()); + assert(SUCCEEDED(hr)); + } + } + } + }); + + // 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([&] { for (size_t i = 0; i < scene.meshes.GetCount(); ++i) { @@ -3518,6 +3548,23 @@ void UpdatePerFrameData(float dt) if (mesh.IsSkinned() && scene.armatures.Contains(mesh.armatureID)) { + ArmatureComponent& armature = *scene.armatures.GetComponent(mesh.armatureID); + + if (armature.boneBuffer == nullptr) + { + GPUBufferDesc bd; + bd.Usage = USAGE_DYNAMIC; + bd.CPUAccessFlags = CPU_ACCESS_WRITE; + + bd.ByteWidth = sizeof(ArmatureComponent::ShaderBoneType) * (UINT)armature.boneCollection.size(); + bd.BindFlags = BIND_SHADER_RESOURCE; + bd.MiscFlags = RESOURCE_MISC_BUFFER_STRUCTURED; + bd.StructureByteStride = sizeof(ArmatureComponent::ShaderBoneType); + + armature.boneBuffer.reset(new GPUBuffer); + HRESULT hr = device->CreateBuffer(&bd, nullptr, armature.boneBuffer.get()); + assert(SUCCEEDED(hr)); + } if (mesh.vertexBuffer_PRE == nullptr) { mesh.vertexBuffer_PRE.reset(new GPUBuffer); @@ -3738,7 +3785,7 @@ void UpdatePerFrameData(float dt) void UpdateRenderData(GRAPHICSTHREAD threadID) { GraphicsDevice* device = GetDevice(); - Scene& scene = GetScene(); // this is not const, so that means that later render passes will depend on this + const Scene& scene = GetScene(); // Process deferred MIP generation: deferredMIPGenLock.lock(); @@ -3751,45 +3798,22 @@ void UpdateRenderData(GRAPHICSTHREAD threadID) // Update material constant buffers: MaterialCB materialGPUData; - for (size_t i = 0; i < scene.materials.GetCount(); ++i) + for (auto& materialIndex : pendingMaterialUpdates) { - MaterialComponent& material = scene.materials[i]; + const MaterialComponent& material = scene.materials[materialIndex]; - if (material.IsDirty()) - { - material.SetDirty(false); - - materialGPUData.g_xMat_baseColor = material.baseColor; - materialGPUData.g_xMat_texMulAdd = material.texMulAdd; - materialGPUData.g_xMat_roughness = material.roughness; - materialGPUData.g_xMat_reflectance = material.reflectance; - materialGPUData.g_xMat_metalness = material.metalness; - materialGPUData.g_xMat_emissive = material.emissive; - materialGPUData.g_xMat_refractionIndex = material.refractionIndex; - materialGPUData.g_xMat_subsurfaceScattering = material.subsurfaceScattering; - materialGPUData.g_xMat_normalMapStrength = (material.normalMap == nullptr ? 0 : material.normalMapStrength); - materialGPUData.g_xMat_parallaxOcclusionMapping = material.parallaxOcclusionMapping; - - if (material.constantBuffer == nullptr) - { - GPUBufferDesc desc; - desc.Usage = USAGE_DEFAULT; - desc.BindFlags = BIND_CONSTANT_BUFFER; - desc.ByteWidth = sizeof(MaterialCB); - - SubresourceData InitData; - InitData.pSysMem = &materialGPUData; - - material.constantBuffer.reset(new GPUBuffer); - device->CreateBuffer(&desc, &InitData, material.constantBuffer.get()); - } - else - { - device->UpdateBuffer(material.constantBuffer.get(), &materialGPUData, threadID); - } - - } + materialGPUData.g_xMat_baseColor = material.baseColor; + materialGPUData.g_xMat_texMulAdd = material.texMulAdd; + materialGPUData.g_xMat_roughness = material.roughness; + materialGPUData.g_xMat_reflectance = material.reflectance; + materialGPUData.g_xMat_metalness = material.metalness; + materialGPUData.g_xMat_emissive = material.emissive; + materialGPUData.g_xMat_refractionIndex = material.refractionIndex; + materialGPUData.g_xMat_subsurfaceScattering = material.subsurfaceScattering; + materialGPUData.g_xMat_normalMapStrength = (material.normalMap == nullptr ? 0 : material.normalMapStrength); + materialGPUData.g_xMat_parallaxOcclusionMapping = material.parallaxOcclusionMapping; + device->UpdateBuffer(material.constantBuffer.get(), &materialGPUData, threadID); } @@ -4038,23 +4062,7 @@ void UpdateRenderData(GRAPHICSTHREAD threadID) if (mesh.IsSkinned() && scene.armatures.Contains(mesh.armatureID)) { - ArmatureComponent& armature = *scene.armatures.GetComponent(mesh.armatureID); - - if (armature.boneBuffer == nullptr) - { - GPUBufferDesc bd; - bd.Usage = USAGE_DYNAMIC; - bd.CPUAccessFlags = CPU_ACCESS_WRITE; - - bd.ByteWidth = sizeof(ArmatureComponent::ShaderBoneType) * (UINT)armature.boneCollection.size(); - bd.BindFlags = BIND_SHADER_RESOURCE; - bd.MiscFlags = RESOURCE_MISC_BUFFER_STRUCTURED; - bd.StructureByteStride = sizeof(ArmatureComponent::ShaderBoneType); - - armature.boneBuffer.reset(new GPUBuffer); - HRESULT hr = device->CreateBuffer(&bd, nullptr, armature.boneBuffer.get()); - assert(SUCCEEDED(hr)); - } + const ArmatureComponent& armature = *scene.armatures.GetComponent(mesh.armatureID); if (!streamOutSetUp) { @@ -4149,19 +4157,19 @@ void UpdateRenderData(GRAPHICSTHREAD threadID) // GPU Particle systems simulation/sorting/culling: for (size_t i = 0; i < scene.emitters.GetCount(); ++i) { - wiEmittedParticle& emitter = scene.emitters[i]; + const wiEmittedParticle& emitter = scene.emitters[i]; Entity entity = scene.emitters.GetEntity(i); const TransformComponent& transform = *scene.transforms.GetComponent(entity); const MaterialComponent& material = *scene.materials.GetComponent(entity); const MeshComponent* mesh = scene.meshes.GetComponent(emitter.meshID); - emitter.UpdateRenderData(transform, material, mesh, threadID); + emitter.UpdateGPU(transform, material, mesh, threadID); } - // Hair particle systems simulation: + // Hair particle systems GPU simulation: for (size_t i = 0; i < scene.hairs.GetCount(); ++i) { - wiHairParticle& hair = scene.hairs[i]; + const wiHairParticle& hair = scene.hairs[i]; if (hair.meshID != INVALID_ENTITY && GetCamera().frustum.CheckBox(hair.aabb)) { @@ -4172,7 +4180,7 @@ void UpdateRenderData(GRAPHICSTHREAD threadID) Entity entity = scene.hairs.GetEntity(i); const MaterialComponent& material = *scene.materials.GetComponent(entity); - hair.UpdateRenderData(*mesh, material, threadID); + hair.UpdateGPU(*mesh, material, threadID); } } } @@ -4237,6 +4245,7 @@ void OcclusionCulling_Render(GRAPHICSTHREAD threadID) device->BindGraphicsPSO(PSO_occlusionquery, threadID); + // TODO: This is not const, so not thread safe! Scene& scene = GetScene(); int queryID = 0; @@ -5809,6 +5818,7 @@ void DrawDebugWorld(const CameraComponent& camera, GRAPHICSTHREAD threadID) void DrawSky(GRAPHICSTHREAD threadID) { GraphicsDevice* device = GetDevice(); + const Scene& scene = GetScene(); device->EventBegin("DrawSky", threadID); @@ -5819,7 +5829,7 @@ void DrawSky(GRAPHICSTHREAD threadID) else { device->BindGraphicsPSO(PSO_sky[SKYRENDERING_DYNAMIC], threadID); - if (GetScene().weather.cloudiness > 0) + if (scene.weather.cloudiness > 0) { device->BindResource(PS, textures[TEXTYPE_2D_CLOUDS], TEXSLOT_ONDEMAND0, threadID); } @@ -6313,7 +6323,7 @@ void RefreshImpostors(GRAPHICSTHREAD threadID) { continue; } - MaterialComponent& material = *GetScene().materials.GetComponent(subset.materialID); + const MaterialComponent& material = *scene.materials.GetComponent(subset.materialID); device->BindConstantBuffer(PS, material.constantBuffer.get(), CB_GETBINDSLOT(MaterialCB), threadID); @@ -7690,7 +7700,7 @@ unordered_map packedLightmaps; void RenderObjectLightMap(ObjectComponent& object, bool updateBVHAndScene, GRAPHICSTHREAD threadID) { GraphicsDevice* device = GetDevice(); - Scene& scene = GetScene(); + const Scene& scene = GetScene(); HRESULT hr; device->EventBegin("RenderObjectLightMap", threadID); diff --git a/WickedEngine/wiSceneSystem.cpp b/WickedEngine/wiSceneSystem.cpp index 56e6434fd..5448a0bb2 100644 --- a/WickedEngine/wiSceneSystem.cpp +++ b/WickedEngine/wiSceneSystem.cpp @@ -1915,7 +1915,9 @@ namespace wiSceneSystem wiJobSystem::Dispatch((uint32_t)emitters.GetCount(), small_subtask_groupsize, [&](wiJobDispatchArgs args) { wiEmittedParticle& emitter = emitters[args.jobIndex]; - emitter.Update(dt); + Entity entity = emitters.GetEntity(args.jobIndex); + const TransformComponent& transform = *transforms.GetComponent(entity); + emitter.UpdateCPU(transform, dt); }); wiJobSystem::Dispatch((uint32_t)hairs.GetCount(), small_subtask_groupsize, [&](wiJobDispatchArgs args) { @@ -1923,7 +1925,6 @@ namespace wiSceneSystem wiHairParticle& hair = hairs[args.jobIndex]; Entity entity = hairs.GetEntity(args.jobIndex); const TransformComponent& transform = *transforms.GetComponent(entity); - hair.world = transform.world; if (hair.meshID != INVALID_ENTITY) { @@ -1931,19 +1932,7 @@ namespace wiSceneSystem if (mesh != nullptr) { - XMFLOAT3 min = mesh->aabb.getMin(); - XMFLOAT3 max = mesh->aabb.getMax(); - - max.x += hair.length; - max.y += hair.length; - max.z += hair.length; - - min.x -= hair.length; - min.y -= hair.length; - min.z -= hair.length; - - hair.aabb = AABB(min, max); - hair.aabb = hair.aabb.get(hair.world); + hair.UpdateCPU(transform, *mesh, dt); } } diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index 286770480..bdcbc8d30 100644 --- a/WickedEngine/wiVersion.cpp +++ b/WickedEngine/wiVersion.cpp @@ -9,7 +9,7 @@ namespace wiVersion // minor features, major updates const int minor = 24; // minor bug fixes, alterations, refactors, updates - const int revision = 42; + const int revision = 43; long GetVersion()