From a560b19cbceb5a015099d52662b8970885ddc5da Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 3 Feb 2021 09:33:48 +0100 Subject: [PATCH] Refactor draw calls and instancing logic to be more modular --- Source/Engine/Content/Assets/Material.cpp | 4 +- Source/Engine/Content/Assets/Material.h | 2 +- .../Content/Assets/MaterialInstance.cpp | 4 +- .../Engine/Content/Assets/MaterialInstance.h | 2 +- .../Materials/DeferredMaterialShader.cpp | 28 ++--- .../Materials/DeferredMaterialShader.h | 2 +- .../Materials/ForwardMaterialShader.cpp | 18 +-- .../Materials/ForwardMaterialShader.h | 2 +- Source/Engine/Graphics/Materials/IMaterial.h | 32 ++---- .../Materials/ParticleMaterialShader.cpp | 54 ++++----- .../Materials/TerrainMaterialShader.cpp | 26 ++--- Source/Engine/Graphics/Models/Mesh.cpp | 24 ++-- Source/Engine/Graphics/Models/SkinnedMesh.cpp | 12 +- Source/Engine/Level/Actors/Skybox.cpp | 2 +- Source/Engine/Particles/ParticleManager.cpp | 11 +- Source/Engine/Renderer/DrawCall.h | 108 ++++++------------ .../Renderer/Editor/LightmapUVsDensity.cpp | 2 +- Source/Engine/Renderer/GBufferPass.cpp | 8 +- Source/Engine/Renderer/RenderList.cpp | 74 ++++++++---- Source/Engine/Renderer/RenderList.h | 33 ++++-- Source/Engine/Renderer/Renderer.cpp | 3 - Source/Engine/Terrain/TerrainChunk.cpp | 60 +++++----- Source/Engine/UI/TextRender.cpp | 12 +- 23 files changed, 255 insertions(+), 268 deletions(-) diff --git a/Source/Engine/Content/Assets/Material.cpp b/Source/Engine/Content/Assets/Material.cpp index b40e1e9c0..571e46243 100644 --- a/Source/Engine/Content/Assets/Material.cpp +++ b/Source/Engine/Content/Assets/Material.cpp @@ -61,9 +61,9 @@ bool Material::CanUseLightmap() const return _materialShader && _materialShader->CanUseLightmap(); } -bool Material::CanUseInstancing() const +bool Material::CanUseInstancing(InstancingHandler& handler) const { - return _materialShader && _materialShader->CanUseInstancing(); + return _materialShader && _materialShader->CanUseInstancing(handler); } void Material::Bind(BindParameters& params) diff --git a/Source/Engine/Content/Assets/Material.h b/Source/Engine/Content/Assets/Material.h index bdaba7abb..0a9ad1dbc 100644 --- a/Source/Engine/Content/Assets/Material.h +++ b/Source/Engine/Content/Assets/Material.h @@ -48,7 +48,7 @@ public: bool IsReady() const override; DrawPass GetDrawModes() const override; bool CanUseLightmap() const override; - bool CanUseInstancing() const override; + bool CanUseInstancing(InstancingHandler& handler) const override; void Bind(BindParameters& params) override; // [ShaderAssetBase] diff --git a/Source/Engine/Content/Assets/MaterialInstance.cpp b/Source/Engine/Content/Assets/MaterialInstance.cpp index ace2fcee9..0678f9992 100644 --- a/Source/Engine/Content/Assets/MaterialInstance.cpp +++ b/Source/Engine/Content/Assets/MaterialInstance.cpp @@ -167,9 +167,9 @@ bool MaterialInstance::CanUseLightmap() const return _baseMaterial && _baseMaterial->CanUseLightmap(); } -bool MaterialInstance::CanUseInstancing() const +bool MaterialInstance::CanUseInstancing(InstancingHandler& handler) const { - return _baseMaterial && _baseMaterial->CanUseInstancing(); + return _baseMaterial && _baseMaterial->CanUseInstancing(handler); } void MaterialInstance::Bind(BindParameters& params) diff --git a/Source/Engine/Content/Assets/MaterialInstance.h b/Source/Engine/Content/Assets/MaterialInstance.h index 9fe92e39c..3cf74db03 100644 --- a/Source/Engine/Content/Assets/MaterialInstance.h +++ b/Source/Engine/Content/Assets/MaterialInstance.h @@ -64,7 +64,7 @@ public: bool IsReady() const override; DrawPass GetDrawModes() const override; bool CanUseLightmap() const override; - bool CanUseInstancing() const override; + bool CanUseInstancing(InstancingHandler& handler) const override; void Bind(BindParameters& params) override; protected: diff --git a/Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp b/Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp index 049484459..5a460079d 100644 --- a/Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp @@ -5,6 +5,7 @@ #include "Engine/Graphics/RenderBuffers.h" #include "Engine/Graphics/RenderView.h" #include "Engine/Renderer/DrawCall.h" +#include "Engine/Renderer/RenderList.h" #include "Engine/Level/Scene/Lightmap.h" #include "Engine/Graphics/GPUContext.h" #include "Engine/Graphics/Shaders/GPUConstantBuffer.h" @@ -48,8 +49,9 @@ bool DeferredMaterialShader::CanUseLightmap() const return true; } -bool DeferredMaterialShader::CanUseInstancing() const +bool DeferredMaterialShader::CanUseInstancing(InstancingHandler& handler) const { + handler = { SurfaceDrawCallHandler::GetHash, SurfaceDrawCallHandler::CanBatch, SurfaceDrawCallHandler::WriteDrawCall, }; return true; } @@ -79,7 +81,7 @@ void DeferredMaterialShader::Bind(BindParameters& params) Matrix::Transpose(view.Frustum.GetMatrix(), materialData->ViewProjectionMatrix); Matrix::Transpose(drawCall.World, materialData->WorldMatrix); Matrix::Transpose(view.View, materialData->ViewMatrix); - Matrix::Transpose(drawCall.PrevWorld, materialData->PrevWorldMatrix); + Matrix::Transpose(drawCall.Surface.PrevWorld, materialData->PrevWorldMatrix); Matrix::Transpose(view.PrevViewProjection, materialData->PrevViewProjectionMatrix); materialData->ViewPos = view.Position; @@ -100,40 +102,40 @@ void DeferredMaterialShader::Bind(BindParameters& params) materialData->WorldInvScale = worldInvScale; materialData->WorldDeterminantSign = drawCall.WorldDeterminantSign; - materialData->LODDitherFactor = drawCall.LODDitherFactor; + materialData->LODDitherFactor = drawCall.Surface.LODDitherFactor; materialData->PerInstanceRandom = drawCall.PerInstanceRandom; materialData->TemporalAAJitter = view.TemporalAAJitter; - materialData->GeometrySize = drawCall.GeometrySize; + materialData->GeometrySize = drawCall.Surface.GeometrySize; } const bool useLightmap = view.Flags & ViewFlags::GI #if USE_EDITOR && EnableLightmapsUsage #endif - && drawCall.Lightmap != nullptr; + && drawCall.Surface.Lightmap != nullptr; if (useLightmap) { // Bind lightmap textures GPUTexture *lightmap0, *lightmap1, *lightmap2; - drawCall.Lightmap->GetTextures(&lightmap0, &lightmap1, &lightmap2); + drawCall.Surface.Lightmap->GetTextures(&lightmap0, &lightmap1, &lightmap2); context->BindSR(0, lightmap0); context->BindSR(1, lightmap1); context->BindSR(2, lightmap2); // Set lightmap data - materialData->LightmapArea = drawCall.LightmapUVsArea; + materialData->LightmapArea = drawCall.Surface.LightmapUVsArea; } // Check if is using mesh skinning - const bool useSkinning = drawCall.Skinning != nullptr; + const bool useSkinning = drawCall.Surface.Skinning != nullptr; bool perBoneMotionBlur = false; if (useSkinning) { // Bind skinning buffer - ASSERT(drawCall.Skinning->IsReady()); - context->BindSR(0, drawCall.Skinning->BoneMatrices->View()); - if (drawCall.Skinning->PrevBoneMatrices && drawCall.Skinning->PrevBoneMatrices->IsAllocated()) + ASSERT(drawCall.Surface.Skinning->IsReady()); + context->BindSR(0, drawCall.Surface.Skinning->BoneMatrices->View()); + if (drawCall.Surface.Skinning->PrevBoneMatrices && drawCall.Surface.Skinning->PrevBoneMatrices->IsAllocated()) { - context->BindSR(1, drawCall.Skinning->PrevBoneMatrices->View()); + context->BindSR(1, drawCall.Surface.Skinning->PrevBoneMatrices->View()); perBoneMotionBlur = true; } } @@ -152,7 +154,7 @@ void DeferredMaterialShader::Bind(BindParameters& params) if (IsRunningRadiancePass) cullMode = CullMode::TwoSided; #endif - if (cullMode != CullMode::TwoSided && drawCall.IsNegativeScale()) + if (cullMode != CullMode::TwoSided && drawCall.WorldDeterminantSign < 0) { // Invert culling when scale is negative if (cullMode == CullMode::Normal) diff --git a/Source/Engine/Graphics/Materials/DeferredMaterialShader.h b/Source/Engine/Graphics/Materials/DeferredMaterialShader.h index f8df968c9..537547c6a 100644 --- a/Source/Engine/Graphics/Materials/DeferredMaterialShader.h +++ b/Source/Engine/Graphics/Materials/DeferredMaterialShader.h @@ -66,7 +66,7 @@ public: // [MaterialShader] DrawPass GetDrawModes() const override; bool CanUseLightmap() const override; - bool CanUseInstancing() const override; + bool CanUseInstancing(InstancingHandler& handler) const override; void Bind(BindParameters& params) override; void Unload() override; diff --git a/Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp b/Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp index 863af34e1..39e39a7d4 100644 --- a/Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp @@ -10,6 +10,7 @@ #include "Engine/Renderer/DepthOfFieldPass.h" #include "Engine/Renderer/DrawCall.h" #include "Engine/Renderer/ShadowsPass.h" +#include "Engine/Renderer/RenderList.h" #if USE_EDITOR #include "Engine/Renderer/Lightmaps.h" #endif @@ -54,8 +55,9 @@ DrawPass ForwardMaterialShader::GetDrawModes() const return _drawModes; } -bool ForwardMaterialShader::CanUseInstancing() const +bool ForwardMaterialShader::CanUseInstancing(InstancingHandler& handler) const { + handler = { SurfaceDrawCallHandler::GetHash, SurfaceDrawCallHandler::CanBatch, SurfaceDrawCallHandler::WriteDrawCall, }; return true; } @@ -82,12 +84,12 @@ void ForwardMaterialShader::Bind(BindParameters& params) MaterialParams::Bind(params.ParamsLink, bindMeta); // Check if is using mesh skinning - const bool useSkinning = drawCall.Skinning != nullptr; + const bool useSkinning = drawCall.Surface.Skinning != nullptr; if (useSkinning) { // Bind skinning buffer - ASSERT(drawCall.Skinning->IsReady()); - context->BindSR(0, drawCall.Skinning->BoneMatrices->View()); + ASSERT(drawCall.Surface.Skinning->IsReady()); + context->BindSR(0, drawCall.Surface.Skinning->BoneMatrices->View()); } // Setup material constants data @@ -97,7 +99,7 @@ void ForwardMaterialShader::Bind(BindParameters& params) Matrix::Transpose(view.Frustum.GetMatrix(), materialData->ViewProjectionMatrix); Matrix::Transpose(drawCall.World, materialData->WorldMatrix); Matrix::Transpose(view.View, materialData->ViewMatrix); - Matrix::Transpose(drawCall.PrevWorld, materialData->PrevWorldMatrix); + Matrix::Transpose(drawCall.Surface.PrevWorld, materialData->PrevWorldMatrix); Matrix::Transpose(view.PrevViewProjection, materialData->PrevViewProjectionMatrix); materialData->ViewPos = view.Position; @@ -118,9 +120,9 @@ void ForwardMaterialShader::Bind(BindParameters& params) materialData->WorldInvScale = worldInvScale; materialData->WorldDeterminantSign = drawCall.WorldDeterminantSign; - materialData->LODDitherFactor = drawCall.LODDitherFactor; + materialData->LODDitherFactor = drawCall.Surface.LODDitherFactor; materialData->PerInstanceRandom = drawCall.PerInstanceRandom; - materialData->GeometrySize = drawCall.GeometrySize; + materialData->GeometrySize = drawCall.Surface.GeometrySize; } // Setup lighting constants data @@ -249,7 +251,7 @@ void ForwardMaterialShader::Bind(BindParameters& params) if (IsRunningRadiancePass) cullMode = CullMode::TwoSided; #endif - if (cullMode != CullMode::TwoSided && drawCall.IsNegativeScale()) + if (cullMode != CullMode::TwoSided && drawCall.WorldDeterminantSign < 0) { // Invert culling when scale is negative if (cullMode == CullMode::Normal) diff --git a/Source/Engine/Graphics/Materials/ForwardMaterialShader.h b/Source/Engine/Graphics/Materials/ForwardMaterialShader.h index d39fcea54..bcba48259 100644 --- a/Source/Engine/Graphics/Materials/ForwardMaterialShader.h +++ b/Source/Engine/Graphics/Materials/ForwardMaterialShader.h @@ -67,7 +67,7 @@ public: // [MaterialShader] DrawPass GetDrawModes() const override; - bool CanUseInstancing() const override; + bool CanUseInstancing(InstancingHandler& handler) const override; void Bind(BindParameters& params) override; void Unload() override; diff --git a/Source/Engine/Graphics/Materials/IMaterial.h b/Source/Engine/Graphics/Materials/IMaterial.h index 09796c04b..f1e7856af 100644 --- a/Source/Engine/Graphics/Materials/IMaterial.h +++ b/Source/Engine/Graphics/Materials/IMaterial.h @@ -2,7 +2,6 @@ #pragma once -#include "Engine/Threading/Task.h" #include "MaterialInfo.h" struct MaterialParamsLink; @@ -81,24 +80,6 @@ public: return GetInfo().Domain == MaterialDomain::Particle; } - /// - /// Checks if material needs vertex color vertex buffer data for rendering. - /// - /// True if mesh renderer have to provide vertex color buffer to render that material - FORCE_INLINE bool RequireVertexColor() const - { - return (GetInfo().UsageFlags & MaterialUsageFlags::UseVertexColor) != 0; - } - - /// - /// Checks if material supports dithered LOD transitions. - /// - /// True if material supports dithered LOD transitions, otherwise false. - FORCE_INLINE bool IsDitheredLODTransition() const - { - return (GetInfo().FeaturesFlags & MaterialFeaturesFlags::DitheredLODTransition) != 0; - } - /// /// Returns true if material is ready for rendering. /// @@ -123,11 +104,22 @@ public: return false; } + /// + /// The instancing handling used to hash, batch and write draw calls. + /// + struct InstancingHandler + { + void (*GetHash)(const DrawCall& drawCall, int32& batchKey); + bool (*CanBatch)(const DrawCall& a, const DrawCall& b); + void (*WriteDrawCall)(struct InstanceData* instanceData, const DrawCall& drawCall); + }; + /// /// Returns true if material can use draw calls instancing. /// + /// The output data for the instancing handling used to hash, batch and write draw calls. Valid only when function returns true. /// True if can use instancing, otherwise false. - virtual bool CanUseInstancing() const + virtual bool CanUseInstancing(InstancingHandler& handler) const { return false; } diff --git a/Source/Engine/Graphics/Materials/ParticleMaterialShader.cpp b/Source/Engine/Graphics/Materials/ParticleMaterialShader.cpp index 8c1c065ab..210c81e7d 100644 --- a/Source/Engine/Graphics/Materials/ParticleMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/ParticleMaterialShader.cpp @@ -76,7 +76,7 @@ void ParticleMaterialShader::Bind(BindParameters& params) const bool hasCb0 = cb0->GetSize() != 0; const auto cb1 = _shader->GetCB(1); const bool hasCb1 = cb1->GetSize() != 0; - const uint32 sortedIndicesOffset = drawCall.Module->SortedIndicesOffset; + const uint32 sortedIndicesOffset = drawCall.Particle.Module->SortedIndicesOffset; // Setup parameters MaterialParameter::BindMeta bindMeta; @@ -90,9 +90,9 @@ void ParticleMaterialShader::Bind(BindParameters& params) // Setup particles data and attributes binding info { - context->BindSR(0, drawCall.Particles->GPU.Buffer->View()); - if (drawCall.Particles->GPU.SortedIndices) - context->BindSR(1, drawCall.Particles->GPU.SortedIndices->View()); + context->BindSR(0, drawCall.Particle.Particles->GPU.Buffer->View()); + if (drawCall.Particle.Particles->GPU.SortedIndices) + context->BindSR(1, drawCall.Particle.Particles->GPU.SortedIndices->View()); if (hasCb0) { @@ -104,7 +104,7 @@ void ParticleMaterialShader::Bind(BindParameters& params) { auto name = StringView(param.GetName().Get() + 9); - const int32 offset = drawCall.Particles->Layout->FindAttributeOffset(name); + const int32 offset = drawCall.Particle.Particles->Layout->FindAttributeOffset(name); *((int32*)(bindMeta.Buffer0 + param.GetBindOffset())) = offset; } } @@ -115,7 +115,7 @@ void ParticleMaterialShader::Bind(BindParameters& params) const bool wireframe = (_info.FeaturesFlags & MaterialFeaturesFlags::Wireframe) != 0 || view.Mode == ViewMode::Wireframe; CullMode cullMode = view.Pass == DrawPass::Depth ? CullMode::TwoSided : _info.CullMode; PipelineStateCache* psCache = nullptr; - switch (drawCall.Module->TypeID) + switch (drawCall.Particle.Module->TypeID) { // Sprite Rendering case 400: @@ -142,20 +142,20 @@ void ParticleMaterialShader::Bind(BindParameters& params) { const auto materialData = reinterpret_cast(_cb0Data.Get()); - materialData->RibbonWidthOffset = drawCall.Particles->Layout->FindAttributeOffset(ParticleRibbonWidth, ParticleAttribute::ValueTypes::Float, -1); - materialData->RibbonTwistOffset = drawCall.Particles->Layout->FindAttributeOffset(ParticleRibbonTwist, ParticleAttribute::ValueTypes::Float, -1); - materialData->RibbonFacingVectorOffset = drawCall.Particles->Layout->FindAttributeOffset(ParticleRibbonFacingVector, ParticleAttribute::ValueTypes::Vector3, -1); + materialData->RibbonWidthOffset = drawCall.Particle.Particles->Layout->FindAttributeOffset(ParticleRibbonWidth, ParticleAttribute::ValueTypes::Float, -1); + materialData->RibbonTwistOffset = drawCall.Particle.Particles->Layout->FindAttributeOffset(ParticleRibbonTwist, ParticleAttribute::ValueTypes::Float, -1); + materialData->RibbonFacingVectorOffset = drawCall.Particle.Particles->Layout->FindAttributeOffset(ParticleRibbonFacingVector, ParticleAttribute::ValueTypes::Vector3, -1); - materialData->RibbonUVTilingDistance = drawCall.Ribbon.UVTilingDistance; - materialData->RibbonUVScale.X = drawCall.Ribbon.UVScaleX; - materialData->RibbonUVScale.Y = drawCall.Ribbon.UVScaleY; - materialData->RibbonUVOffset.X = drawCall.Ribbon.UVOffsetX; - materialData->RibbonUVOffset.Y = drawCall.Ribbon.UVOffsetY; - materialData->RibbonSegmentCount = drawCall.Ribbon.SegmentCount; + materialData->RibbonUVTilingDistance = drawCall.Particle.Ribbon.UVTilingDistance; + materialData->RibbonUVScale.X = drawCall.Particle.Ribbon.UVScaleX; + materialData->RibbonUVScale.Y = drawCall.Particle.Ribbon.UVScaleY; + materialData->RibbonUVOffset.X = drawCall.Particle.Ribbon.UVOffsetX; + materialData->RibbonUVOffset.Y = drawCall.Particle.Ribbon.UVOffsetY; + materialData->RibbonSegmentCount = drawCall.Particle.Ribbon.SegmentCount; } - if (drawCall.Ribbon.SegmentDistances) - context->BindSR(1, drawCall.Ribbon.SegmentDistances->View()); + if (drawCall.Particle.Ribbon.SegmentDistances) + context->BindSR(1, drawCall.Particle.Ribbon.SegmentDistances->View()); break; } @@ -186,17 +186,17 @@ void ParticleMaterialShader::Bind(BindParameters& params) materialData->TimeParam = Time::Draw.UnscaledTime.GetTotalSeconds(); materialData->ViewInfo = view.ViewInfo; materialData->ScreenSize = view.ScreenSize; - materialData->SortedIndicesOffset = drawCall.Particles->GPU.SortedIndices && params.RenderContext.View.Pass != DrawPass::Depth ? sortedIndicesOffset : 0xFFFFFFFF; + materialData->SortedIndicesOffset = drawCall.Particle.Particles->GPU.SortedIndices && params.RenderContext.View.Pass != DrawPass::Depth ? sortedIndicesOffset : 0xFFFFFFFF; materialData->PerInstanceRandom = drawCall.PerInstanceRandom; - materialData->ParticleStride = drawCall.Particles->Stride; - materialData->PositionOffset = drawCall.Particles->Layout->FindAttributeOffset(ParticlePosition, ParticleAttribute::ValueTypes::Vector3); - materialData->SpriteSizeOffset = drawCall.Particles->Layout->FindAttributeOffset(ParticleSpriteSize, ParticleAttribute::ValueTypes::Vector2); - materialData->SpriteFacingModeOffset = drawCall.Particles->Layout->FindAttributeOffset(ParticleSpriteFacingMode, ParticleAttribute::ValueTypes::Int, -1); - materialData->SpriteFacingVectorOffset = drawCall.Particles->Layout->FindAttributeOffset(ParticleSpriteFacingVector, ParticleAttribute::ValueTypes::Vector3); - materialData->VelocityOffset = drawCall.Particles->Layout->FindAttributeOffset(ParticleVelocityOffset, ParticleAttribute::ValueTypes::Vector3); - materialData->RotationOffset = drawCall.Particles->Layout->FindAttributeOffset(ParticleRotationOffset, ParticleAttribute::ValueTypes::Vector3, -1); - materialData->ScaleOffset = drawCall.Particles->Layout->FindAttributeOffset(ParticleScaleOffset, ParticleAttribute::ValueTypes::Vector3, -1); - materialData->ModelFacingModeOffset = drawCall.Particles->Layout->FindAttributeOffset(ParticleModelFacingModeOffset, ParticleAttribute::ValueTypes::Int, -1); + materialData->ParticleStride = drawCall.Particle.Particles->Stride; + materialData->PositionOffset = drawCall.Particle.Particles->Layout->FindAttributeOffset(ParticlePosition, ParticleAttribute::ValueTypes::Vector3); + materialData->SpriteSizeOffset = drawCall.Particle.Particles->Layout->FindAttributeOffset(ParticleSpriteSize, ParticleAttribute::ValueTypes::Vector2); + materialData->SpriteFacingModeOffset = drawCall.Particle.Particles->Layout->FindAttributeOffset(ParticleSpriteFacingMode, ParticleAttribute::ValueTypes::Int, -1); + materialData->SpriteFacingVectorOffset = drawCall.Particle.Particles->Layout->FindAttributeOffset(ParticleSpriteFacingVector, ParticleAttribute::ValueTypes::Vector3); + materialData->VelocityOffset = drawCall.Particle.Particles->Layout->FindAttributeOffset(ParticleVelocityOffset, ParticleAttribute::ValueTypes::Vector3); + materialData->RotationOffset = drawCall.Particle.Particles->Layout->FindAttributeOffset(ParticleRotationOffset, ParticleAttribute::ValueTypes::Vector3, -1); + materialData->ScaleOffset = drawCall.Particle.Particles->Layout->FindAttributeOffset(ParticleScaleOffset, ParticleAttribute::ValueTypes::Vector3, -1); + materialData->ModelFacingModeOffset = drawCall.Particle.Particles->Layout->FindAttributeOffset(ParticleModelFacingModeOffset, ParticleAttribute::ValueTypes::Int, -1); Matrix::Invert(drawCall.World, materialData->WorldMatrixInverseTransposed); } diff --git a/Source/Engine/Graphics/Materials/TerrainMaterialShader.cpp b/Source/Engine/Graphics/Materials/TerrainMaterialShader.cpp index 212e27d87..37f932a5a 100644 --- a/Source/Engine/Graphics/Materials/TerrainMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/TerrainMaterialShader.cpp @@ -93,36 +93,36 @@ void TerrainMaterialShader::Bind(BindParameters& params) data->WorldDeterminantSign = drawCall.WorldDeterminantSign; data->PerInstanceRandom = drawCall.PerInstanceRandom; - data->CurrentLOD = drawCall.TerrainData.CurrentLOD; - data->ChunkSizeNextLOD = drawCall.TerrainData.ChunkSizeNextLOD; - data->TerrainChunkSizeLOD0 = drawCall.TerrainData.TerrainChunkSizeLOD0; - data->HeightmapUVScaleBias = drawCall.TerrainData.HeightmapUVScaleBias; - data->NeighborLOD = drawCall.TerrainData.NeighborLOD; - data->OffsetUV = drawCall.TerrainData.OffsetUV; + data->CurrentLOD = drawCall.Terrain.CurrentLOD; + data->ChunkSizeNextLOD = drawCall.Terrain.ChunkSizeNextLOD; + data->TerrainChunkSizeLOD0 = drawCall.Terrain.TerrainChunkSizeLOD0; + data->HeightmapUVScaleBias = drawCall.Terrain.HeightmapUVScaleBias; + data->NeighborLOD = drawCall.Terrain.NeighborLOD; + data->OffsetUV = drawCall.Terrain.OffsetUV; } const bool useLightmap = view.Flags & ViewFlags::GI #if USE_EDITOR && EnableLightmapsUsage #endif && view.Pass == DrawPass::GBuffer - && drawCall.Lightmap != nullptr; + && drawCall.Terrain.Lightmap != nullptr; if (useLightmap) { // Bind lightmap textures GPUTexture *lightmap0, *lightmap1, *lightmap2; - drawCall.Lightmap->GetTextures(&lightmap0, &lightmap1, &lightmap2); + drawCall.Terrain.Lightmap->GetTextures(&lightmap0, &lightmap1, &lightmap2); context->BindSR(0, lightmap0); context->BindSR(1, lightmap1); context->BindSR(2, lightmap2); // Set lightmap data - data->LightmapArea = drawCall.LightmapUVsArea; + data->LightmapArea = drawCall.Terrain.LightmapUVsArea; } // Bind terrain textures - const auto heightmap = drawCall.TerrainData.Patch->Heightmap.Get()->GetTexture(); - const auto splatmap0 = drawCall.TerrainData.Patch->Splatmap[0] ? drawCall.TerrainData.Patch->Splatmap[0]->GetTexture() : nullptr; - const auto splatmap1 = drawCall.TerrainData.Patch->Splatmap[1] ? drawCall.TerrainData.Patch->Splatmap[1]->GetTexture() : nullptr; + const auto heightmap = drawCall.Terrain.Patch->Heightmap.Get()->GetTexture(); + const auto splatmap0 = drawCall.Terrain.Patch->Splatmap[0] ? drawCall.Terrain.Patch->Splatmap[0]->GetTexture() : nullptr; + const auto splatmap1 = drawCall.Terrain.Patch->Splatmap[1] ? drawCall.Terrain.Patch->Splatmap[1]->GetTexture() : nullptr; context->BindSR(3, heightmap); context->BindSR(4, splatmap0); context->BindSR(5, splatmap1); @@ -141,7 +141,7 @@ void TerrainMaterialShader::Bind(BindParameters& params) if (IsRunningRadiancePass) cullMode = CullMode::TwoSided; #endif - if (cullMode != CullMode::TwoSided && drawCall.IsNegativeScale()) + if (cullMode != CullMode::TwoSided && drawCall.WorldDeterminantSign < 0) { // Invert culling when scale is negative if (cullMode == CullMode::Normal) diff --git a/Source/Engine/Graphics/Models/Mesh.cpp b/Source/Engine/Graphics/Models/Mesh.cpp index 444d60540..99262cd51 100644 --- a/Source/Engine/Graphics/Models/Mesh.cpp +++ b/Source/Engine/Graphics/Models/Mesh.cpp @@ -393,15 +393,15 @@ void Mesh::Draw(const RenderContext& renderContext, MaterialBase* material, cons drawCall.IndirectArgsOffset = 0; drawCall.Material = material; drawCall.World = world; - drawCall.PrevWorld = world; drawCall.ObjectPosition = drawCall.World.GetTranslation(); - drawCall.GeometrySize = _box.GetSize(); - drawCall.Lightmap = nullptr; - drawCall.LightmapUVsArea = Rectangle::Empty; - drawCall.Skinning = nullptr; + drawCall.Surface.GeometrySize = _box.GetSize(); + drawCall.Surface.PrevWorld = world; + drawCall.Surface.Lightmap = nullptr; + drawCall.Surface.LightmapUVsArea = Rectangle::Empty; + drawCall.Surface.Skinning = nullptr; + drawCall.Surface.LODDitherFactor = 0.0f; drawCall.WorldDeterminantSign = Math::FloatSelect(world.RotDeterminant(), 1, -1); drawCall.PerInstanceRandom = 0.0f; - drawCall.LODDitherFactor = 0.0f; renderContext.List->AddDrawCall(DrawPass::Default, flags, drawCall, receiveDecals); } @@ -456,15 +456,15 @@ void Mesh::Draw(const RenderContext& renderContext, const DrawInfo& info, float drawCall.IndirectArgsOffset = 0; drawCall.Material = material; drawCall.World = *info.World; - drawCall.PrevWorld = info.DrawState->PrevWorld; drawCall.ObjectPosition = drawCall.World.GetTranslation(); - drawCall.GeometrySize = _box.GetSize(); - drawCall.Lightmap = info.Flags & StaticFlags::Lightmap ? info.Lightmap : nullptr; - drawCall.LightmapUVsArea = info.LightmapUVs ? *info.LightmapUVs : Rectangle::Empty; - drawCall.Skinning = nullptr; + drawCall.Surface.GeometrySize = _box.GetSize(); + drawCall.Surface.PrevWorld = info.DrawState->PrevWorld; + drawCall.Surface.Lightmap = info.Flags & StaticFlags::Lightmap ? info.Lightmap : nullptr; + drawCall.Surface.LightmapUVsArea = info.LightmapUVs ? *info.LightmapUVs : Rectangle::Empty; + drawCall.Surface.Skinning = nullptr; + drawCall.Surface.LODDitherFactor = lodDitherFactor; drawCall.WorldDeterminantSign = Math::FloatSelect(drawCall.World.RotDeterminant(), 1, -1); drawCall.PerInstanceRandom = info.PerInstanceRandom; - drawCall.LODDitherFactor = lodDitherFactor; renderContext.List->AddDrawCall(drawModes, info.Flags, drawCall, entry.ReceiveDecals); } diff --git a/Source/Engine/Graphics/Models/SkinnedMesh.cpp b/Source/Engine/Graphics/Models/SkinnedMesh.cpp index 90aa03d86..e9e7f8438 100644 --- a/Source/Engine/Graphics/Models/SkinnedMesh.cpp +++ b/Source/Engine/Graphics/Models/SkinnedMesh.cpp @@ -193,15 +193,15 @@ void SkinnedMesh::Draw(const RenderContext& renderContext, const DrawInfo& info, drawCall.IndirectArgsOffset = 0; drawCall.Material = material; drawCall.World = *info.World; - drawCall.PrevWorld = info.DrawState->PrevWorld; drawCall.ObjectPosition = drawCall.World.GetTranslation(); - drawCall.GeometrySize = _box.GetSize(); - drawCall.Lightmap = nullptr; - drawCall.LightmapUVsArea = Rectangle::Empty; - drawCall.Skinning = info.Skinning; + drawCall.Surface.GeometrySize = _box.GetSize(); + drawCall.Surface.PrevWorld = info.DrawState->PrevWorld; + drawCall.Surface.Lightmap = nullptr; + drawCall.Surface.LightmapUVsArea = Rectangle::Empty; + drawCall.Surface.Skinning = info.Skinning; + drawCall.Surface.LODDitherFactor = lodDitherFactor; drawCall.WorldDeterminantSign = Math::FloatSelect(drawCall.World.RotDeterminant(), 1, -1); drawCall.PerInstanceRandom = info.PerInstanceRandom; - drawCall.LODDitherFactor = lodDitherFactor; renderContext.List->AddDrawCall(drawModes, StaticFlags::None, drawCall, entry.ReceiveDecals); } diff --git a/Source/Engine/Level/Actors/Skybox.cpp b/Source/Engine/Level/Actors/Skybox.cpp index 48c19191f..e8ea08c89 100644 --- a/Source/Engine/Level/Actors/Skybox.cpp +++ b/Source/Engine/Level/Actors/Skybox.cpp @@ -93,7 +93,7 @@ void Skybox::ApplySky(GPUContext* context, RenderContext& renderContext, const M Platform::MemoryClear(&drawCall, sizeof(DrawCall)); drawCall.World = world; drawCall.ObjectPosition = drawCall.World.GetTranslation(); - drawCall.GeometrySize = _box.GetSize(); + drawCall.Surface.GeometrySize = _box.GetSize(); drawCall.WorldDeterminantSign = Math::FloatSelect(world.RotDeterminant(), 1, -1); drawCall.PerInstanceRandom = GetPerInstanceRandom(); MaterialBase::BindParameters bindParams(context, renderContext, drawCall); diff --git a/Source/Engine/Particles/ParticleManager.cpp b/Source/Engine/Particles/ParticleManager.cpp index 40cebd892..c83aacbbf 100644 --- a/Source/Engine/Particles/ParticleManager.cpp +++ b/Source/Engine/Particles/ParticleManager.cpp @@ -423,7 +423,7 @@ void DrawEmitterCPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCa { const int32 moduleIndex = renderModulesIndices[index]; auto module = emitter->Graph.RenderModules[moduleIndex]; - drawCall.Module = module; + drawCall.Particle.Module = module; switch (module->TypeID) { @@ -486,7 +486,7 @@ void DrawEmitterCPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCa int32 count = buffer->CPU.Count; // Setup ribbon data - auto& ribbon = drawCall.Ribbon; + auto& ribbon = drawCall.Particle.Ribbon; ribbon.UVTilingDistance = uvTilingDistance; ribbon.SegmentCount = ribbonModulesSegmentCount[ribbonModuleIndex]; ribbon.UVScaleX = uvScale.X; @@ -788,7 +788,7 @@ void DrawEmitterGPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCa { int32 moduleIndex = renderModulesIndices[index]; auto module = emitter->Graph.RenderModules[moduleIndex]; - drawCall.Module = module; + drawCall.Particle.Module = module; switch (module->TypeID) { @@ -875,9 +875,7 @@ void ParticleManager::DrawParticles(RenderContext& renderContext, ParticleEffect // Setup a draw call common data DrawCall drawCall; - drawCall.LightmapUVsArea = Rectangle::Empty; drawCall.PerInstanceRandom = effect->GetPerInstanceRandom(); - drawCall.LODDitherFactor = 1.0f; drawCall.ObjectPosition = world.GetTranslation(); // Draw all emitters @@ -890,9 +888,8 @@ void ParticleManager::DrawParticles(RenderContext& renderContext, ParticleEffect auto emitter = buffer->Emitter; drawCall.World = emitter->SimulationSpace == ParticlesSimulationSpace::World ? Matrix::Identity : world; - drawCall.PrevWorld = drawCall.World; drawCall.WorldDeterminantSign = Math::FloatSelect(drawCall.World.RotDeterminant(), 1, -1); - drawCall.Particles = buffer; + drawCall.Particle.Particles = buffer; // Check if need to render any module RenderModulesIndices renderModulesIndices; diff --git a/Source/Engine/Renderer/DrawCall.h b/Source/Engine/Renderer/DrawCall.h index cc35b2627..31656145b 100644 --- a/Source/Engine/Renderer/DrawCall.h +++ b/Source/Engine/Renderer/DrawCall.h @@ -113,6 +113,11 @@ public: /// struct DrawCall { + /// + /// The material to use for rendering. + /// + IMaterial* Material; + struct { /// @@ -156,53 +161,18 @@ struct DrawCall /// GPUBuffer* IndirectArgsBuffer; - /// - /// The target material to use. - /// - IMaterial* Material; - - // Particles don't use skinning nor lightmaps so pack those stuff together + // Per-material shader data packed into union union { struct { - /// - /// Pointer to lightmap for static object with prebaked lighting. - /// const Lightmap* Lightmap; - - /// - /// The skinning data. If set then material should use GPU skinning during rendering. - /// SkinnedMeshDrawData* Skinning; - }; - - struct - { - /// - /// The particles data. Used only by the particles shaders. - /// - class ParticleBuffer* Particles; - - /// - /// The particle module to draw. - /// - class ParticleEmitterGraphCPUNode* Module; - }; - }; - - /// - /// Object world transformation matrix. - /// - Matrix World; - - // Terrain and particles don't use previous world matrix so pack those stuff together - union - { - /// - /// Object world transformation matrix using during previous frame. - /// - Matrix PrevWorld; + Rectangle LightmapUVsArea; + Vector3 GeometrySize; // Object geometry size in the world (unscaled). + float LODDitherFactor; // The model LOD transition dither progress. + Matrix PrevWorld; + } Surface; struct { @@ -212,26 +182,39 @@ struct DrawCall float CurrentLOD; float ChunkSizeNextLOD; float TerrainChunkSizeLOD0; + Rectangle LightmapUVsArea; const class TerrainPatch* Patch; - } TerrainData; + const Lightmap* Lightmap; + } Terrain; struct { - int32 RibbonOrderOffset; - float UVTilingDistance; - float UVScaleX; - float UVScaleY; - float UVOffsetX; - float UVOffsetY; - uint32 SegmentCount; - GPUBuffer* SegmentDistances; - } Ribbon; + class ParticleBuffer* Particles; + class ParticleEmitterGraphCPUNode* Module; + + struct + { + int32 OrderOffset; + float UVTilingDistance; + float UVScaleX; + float UVScaleY; + float UVOffsetX; + float UVOffsetY; + uint32 SegmentCount; + GPUBuffer* SegmentDistances; + } Ribbon; + } Particle; + + struct + { + byte Raw[96]; + } Custom; }; /// - /// Lightmap UVs area that entry occupies. + /// Object world transformation matrix. /// - Rectangle LightmapUVsArea; + Matrix World; /// /// Object location in the world used for draw calls sorting. @@ -243,36 +226,17 @@ struct DrawCall /// float WorldDeterminantSign; - /// - /// Object geometry size in the world (unscaled). - /// - Vector3 GeometrySize; - /// /// The random per-instance value (normalized to range 0-1). /// float PerInstanceRandom; - /// - /// The model LOD transition dither factor. - /// - float LODDitherFactor; - /// /// Does nothing. /// DrawCall() { } - - /// - /// Determines whether world transform matrix is performing negative scale (then model culling should be inverted). - /// - /// true if world matrix contains negative scale; otherwise, false. - FORCE_INLINE bool IsNegativeScale() const - { - return WorldDeterminantSign < 0; - } }; template<> diff --git a/Source/Engine/Renderer/Editor/LightmapUVsDensity.cpp b/Source/Engine/Renderer/Editor/LightmapUVsDensity.cpp index 152b43d50..9ba9f1a0d 100644 --- a/Source/Engine/Renderer/Editor/LightmapUVsDensity.cpp +++ b/Source/Engine/Renderer/Editor/LightmapUVsDensity.cpp @@ -178,7 +178,7 @@ void LightmapUVsDensityMaterialShader::Bind(BindParameters& params) scaleZ > 0.00001f ? 1.0f / scaleZ : 0.0f); data.LightmapTexelsPerWorldUnit = ShadowsOfMordor::LightmapTexelsPerWorldUnit; data.LightmapSize = 1024.0f; - data.LightmapArea = drawCall.LightmapUVsArea; + data.LightmapArea = drawCall.Surface.LightmapUVsArea; if (drawCallModel) { // Calculate current lightmap slot size for the object (matches the ShadowsOfMordor calculations when baking the lighting) diff --git a/Source/Engine/Renderer/GBufferPass.cpp b/Source/Engine/Renderer/GBufferPass.cpp index 5c6f76905..b9e91ee01 100644 --- a/Source/Engine/Renderer/GBufferPass.cpp +++ b/Source/Engine/Renderer/GBufferPass.cpp @@ -145,7 +145,8 @@ void GBufferPass::Fill(RenderContext& renderContext, GPUTextureView* lightBuffer drawCall.Material = _lightmapUVsDensityMaterialShader; } } - if (!_lightmapUVsDensityMaterialShader->CanUseInstancing()) + IMaterial::InstancingHandler handler; + if (!_lightmapUVsDensityMaterialShader->CanUseInstancing(handler)) { drawCallsList.CanUseInstancing = false; } @@ -166,7 +167,8 @@ void GBufferPass::Fill(RenderContext& renderContext, GPUTextureView* lightBuffer drawCall.Material = _vertexColorsMaterialShader; } } - if (!_vertexColorsMaterialShader->CanUseInstancing()) + IMaterial::InstancingHandler handler; + if (!_vertexColorsMaterialShader->CanUseInstancing(handler)) { drawCallsList.CanUseInstancing = false; } @@ -311,8 +313,6 @@ void GBufferPass::DrawDecals(RenderContext& renderContext, GPUTextureView* light DrawCall drawCall; MaterialBase::BindParameters bindParams(gpuContext, renderContext, drawCall); drawCall.Material = nullptr; - drawCall.Lightmap = nullptr; - drawCall.Skinning = nullptr; drawCall.WorldDeterminantSign = 1.0f; // Draw all decals diff --git a/Source/Engine/Renderer/RenderList.cpp b/Source/Engine/Renderer/RenderList.cpp index c78931416..dd711a5e0 100644 --- a/Source/Engine/Renderer/RenderList.cpp +++ b/Source/Engine/Renderer/RenderList.cpp @@ -19,6 +19,11 @@ #define BATCH_KEY_BITS 32 #define BATCH_KEY_MASK ((1 << BATCH_KEY_BITS) - 1) +static_assert(sizeof(DrawCall) <= 280, "Too big draw call data size."); +static_assert(sizeof(DrawCall::Surface) >= sizeof(DrawCall::Terrain), "Wrong draw call data size."); +static_assert(sizeof(DrawCall::Surface) >= sizeof(DrawCall::Particle), "Wrong draw call data size."); +static_assert(sizeof(DrawCall::Surface) >= sizeof(DrawCall::Custom), "Wrong draw call data size."); + namespace { // Cached data for the draw calls sorting @@ -495,24 +500,24 @@ end: } } -/// -/// Checks if this draw call be batched together with the other one. -/// -/// The first draw call. -/// The second draw call. -/// True if can merge them, otherwise false. -FORCE_INLINE bool CanBatchWith(const DrawCall& a, const DrawCall& b) +namespace { - return Platform::MemoryCompare(&a.Geometry, &b.Geometry, sizeof(a.Geometry)) == 0 && - a.Material == b.Material && - a.Lightmap == b.Lightmap && - // TODO: add batch.CanBatch flag computed in AddDrawCall to remove those checks here for Skinning and IndirectDrawArgs - a.Skinning == nullptr && - b.Skinning == nullptr && - a.IndirectArgsBuffer == nullptr && - b.IndirectArgsBuffer == nullptr && - a.WorldDeterminantSign == b.WorldDeterminantSign && - a.Material->CanUseInstancing(); + /// + /// Checks if this draw call be batched together with the other one. + /// + /// The first draw call. + /// The second draw call. + /// True if can merge them, otherwise false. + FORCE_INLINE bool CanBatchWith(const DrawCall& a, const DrawCall& b) + { + IMaterial::InstancingHandler handler; + return a.Material == b.Material && + a.Material->CanUseInstancing(handler) && + Platform::MemoryCompare(&a.Geometry, &b.Geometry, sizeof(a.Geometry)) == 0 && + a.IndirectArgsBuffer == nullptr && + b.IndirectArgsBuffer == nullptr && + a.WorldDeterminantSign == b.WorldDeterminantSign; + } } void RenderList::SortDrawCalls(const RenderContext& renderContext, bool reverseDistance, DrawCallsList& list) @@ -540,7 +545,9 @@ void RenderList::SortDrawCalls(const RenderContext& renderContext, bool reverseD batchKey = (batchKey * 397) ^ GetHash(drawCall.Geometry.VertexBuffers[1]); batchKey = (batchKey * 397) ^ GetHash(drawCall.Geometry.VertexBuffers[2]); batchKey = (batchKey * 397) ^ GetHash(drawCall.Material); - batchKey = (batchKey * 397) ^ GetHash(drawCall.Lightmap); + IMaterial::InstancingHandler handler; + if (drawCall.Material->CanUseInstancing(handler)) + handler.GetHash(drawCall, batchKey); batchKey += (int32)(471 * drawCall.WorldDeterminantSign); #if USE_BATCH_KEY_MASK const uint32 batchHashKey = (uint32)batchKey & BATCH_KEY_MASK; @@ -635,14 +642,12 @@ void RenderList::ExecuteDrawCalls(const RenderContext& renderContext, DrawCallsL auto& batch = list.Batches[i]; if (batch.BatchSize > 1) { + IMaterial::InstancingHandler handler; + DrawCalls[list.Indices[batch.StartIndex]].Material->CanUseInstancing(handler); for (int32 j = 0; j < batch.BatchSize; j++) { auto& drawCall = DrawCalls[list.Indices[batch.StartIndex + j]]; - instanceData->InstanceOrigin = Vector4(drawCall.World.M41, drawCall.World.M42, drawCall.World.M43, drawCall.PerInstanceRandom); - instanceData->InstanceTransform1 = Vector4(drawCall.World.M11, drawCall.World.M12, drawCall.World.M13, drawCall.LODDitherFactor); - instanceData->InstanceTransform2 = Vector3(drawCall.World.M21, drawCall.World.M22, drawCall.World.M23); - instanceData->InstanceTransform3 = Vector3(drawCall.World.M31, drawCall.World.M32, drawCall.World.M33); - instanceData->InstanceLightmapArea = Half4(drawCall.LightmapUVsArea); + handler.WriteDrawCall(instanceData, drawCall); instanceData++; } } @@ -742,3 +747,26 @@ DRAW: } } } + +void SurfaceDrawCallHandler::GetHash(const DrawCall& drawCall, int32& batchKey) +{ + batchKey = (batchKey * 397) ^ ::GetHash(drawCall.Surface.Lightmap); +} + +bool SurfaceDrawCallHandler::CanBatch(const DrawCall& a, const DrawCall& b) +{ + return a.Surface.Lightmap == b.Surface.Lightmap && + a.Surface.Skinning == nullptr && + b.Surface.Skinning == nullptr; +} + +void SurfaceDrawCallHandler::WriteDrawCall(InstanceData* instanceData, const DrawCall& drawCall) +{ + instanceData->InstanceOrigin = Vector3(drawCall.World.M41, drawCall.World.M42, drawCall.World.M43); + instanceData->PerInstanceRandom = drawCall.PerInstanceRandom; + instanceData->InstanceTransform1 = Vector3(drawCall.World.M11, drawCall.World.M12, drawCall.World.M13); + instanceData->LODDitherFactor = drawCall.Surface.LODDitherFactor; + instanceData->InstanceTransform2 = Vector3(drawCall.World.M21, drawCall.World.M22, drawCall.World.M23); + instanceData->InstanceTransform3 = Vector3(drawCall.World.M31, drawCall.World.M32, drawCall.World.M33); + instanceData->InstanceLightmapArea = Half4(drawCall.Surface.LightmapUVsArea); +} diff --git a/Source/Engine/Renderer/RenderList.h b/Source/Engine/Renderer/RenderList.h index dffbbd2d1..69ef0c33d 100644 --- a/Source/Engine/Renderer/RenderList.h +++ b/Source/Engine/Renderer/RenderList.h @@ -357,18 +357,6 @@ public: private: - /// - /// Represents data per instance element used for instanced rendering. - /// - struct InstanceData - { - Vector4 InstanceOrigin; // .w contains PerInstanceRandom - Vector4 InstanceTransform1; // .w contains LODDitherFactor - Vector3 InstanceTransform2; - Vector3 InstanceTransform3; - Half4 InstanceLightmapArea; - }; - DynamicVertexBuffer _instanceBuffer; public: @@ -475,3 +463,24 @@ public: /// The collected draw calls list. void ExecuteDrawCalls(const RenderContext& renderContext, DrawCallsList& list); }; + +/// +/// Represents data per instance element used for instanced rendering. +/// +struct FLAXENGINE_API InstanceData +{ + Vector3 InstanceOrigin; + float PerInstanceRandom; + Vector3 InstanceTransform1; + float LODDitherFactor; + Vector3 InstanceTransform2; + Vector3 InstanceTransform3; + Half4 InstanceLightmapArea; +}; + +struct SurfaceDrawCallHandler +{ + static void GetHash(const DrawCall& drawCall, int32& batchKey); + static bool CanBatch(const DrawCall& a, const DrawCall& b); + static void WriteDrawCall(InstanceData* instanceData, const DrawCall& drawCall); +}; diff --git a/Source/Engine/Renderer/Renderer.cpp b/Source/Engine/Renderer/Renderer.cpp index 4d3241375..89efef74c 100644 --- a/Source/Engine/Renderer/Renderer.cpp +++ b/Source/Engine/Renderer/Renderer.cpp @@ -31,9 +31,6 @@ #include "Editor/Editor.h" #endif -// It must use less or the same amount of memory -static_assert(sizeof(DrawCall::TerrainData) <= sizeof(DrawCall::PrevWorld), "Invalid size of the terrain data in the draw call."); - #if USE_EDITOR // Additional options used in editor for lightmaps baking bool IsRunningRadiancePass = false; diff --git a/Source/Engine/Terrain/TerrainChunk.cpp b/Source/Engine/Terrain/TerrainChunk.cpp index 1241935e5..6cff541f3 100644 --- a/Source/Engine/Terrain/TerrainChunk.cpp +++ b/Source/Engine/Terrain/TerrainChunk.cpp @@ -88,33 +88,31 @@ void TerrainChunk::Draw(const RenderContext& renderContext) const drawCall.Material = _cachedDrawMaterial; drawCall.World = _world; drawCall.ObjectPosition = drawCall.World.GetTranslation(); - drawCall.TerrainData.Patch = _patch; - drawCall.TerrainData.HeightmapUVScaleBias = _heightmapUVScaleBias; - drawCall.TerrainData.OffsetUV = Vector2((float)(_patch->_x * TerrainPatch::CHUNKS_COUNT_EDGE + _x), (float)(_patch->_z * TerrainPatch::CHUNKS_COUNT_EDGE + _z)); - drawCall.TerrainData.CurrentLOD = (float)lod; - drawCall.TerrainData.ChunkSizeNextLOD = (float)(((chunkSize + 1) >> (lod + 1)) - 1); - drawCall.TerrainData.TerrainChunkSizeLOD0 = TERRAIN_UNITS_PER_VERTEX * chunkSize; + drawCall.Terrain.Patch = _patch; + drawCall.Terrain.HeightmapUVScaleBias = _heightmapUVScaleBias; + drawCall.Terrain.OffsetUV = Vector2((float)(_patch->_x * TerrainPatch::CHUNKS_COUNT_EDGE + _x), (float)(_patch->_z * TerrainPatch::CHUNKS_COUNT_EDGE + _z)); + drawCall.Terrain.CurrentLOD = (float)lod; + drawCall.Terrain.ChunkSizeNextLOD = (float)(((chunkSize + 1) >> (lod + 1)) - 1); + drawCall.Terrain.TerrainChunkSizeLOD0 = TERRAIN_UNITS_PER_VERTEX * chunkSize; // TODO: try using SIMD clamping for 4 chunks at once - drawCall.TerrainData.NeighborLOD.X = (float)Math::Clamp(_neighbors[0]->_cachedDrawLOD, lod, minLod); - drawCall.TerrainData.NeighborLOD.Y = (float)Math::Clamp(_neighbors[1]->_cachedDrawLOD, lod, minLod); - drawCall.TerrainData.NeighborLOD.Z = (float)Math::Clamp(_neighbors[2]->_cachedDrawLOD, lod, minLod); - drawCall.TerrainData.NeighborLOD.W = (float)Math::Clamp(_neighbors[3]->_cachedDrawLOD, lod, minLod); + drawCall.Terrain.NeighborLOD.X = (float)Math::Clamp(_neighbors[0]->_cachedDrawLOD, lod, minLod); + drawCall.Terrain.NeighborLOD.Y = (float)Math::Clamp(_neighbors[1]->_cachedDrawLOD, lod, minLod); + drawCall.Terrain.NeighborLOD.Z = (float)Math::Clamp(_neighbors[2]->_cachedDrawLOD, lod, minLod); + drawCall.Terrain.NeighborLOD.W = (float)Math::Clamp(_neighbors[3]->_cachedDrawLOD, lod, minLod); const auto scene = _patch->_terrain->GetScene(); const auto flags = _patch->_terrain->_staticFlags; if (flags & StaticFlags::Lightmap && scene) { - drawCall.Lightmap = scene->LightmapsData.GetReadyLightmap(Lightmap.TextureIndex); - drawCall.LightmapUVsArea = Lightmap.UVsArea; + drawCall.Terrain.Lightmap = scene->LightmapsData.GetReadyLightmap(Lightmap.TextureIndex); + drawCall.Terrain.LightmapUVsArea = Lightmap.UVsArea; } else { - drawCall.Lightmap = nullptr; - drawCall.LightmapUVsArea = Rectangle::Empty; + drawCall.Terrain.Lightmap = nullptr; + drawCall.Terrain.LightmapUVsArea = Rectangle::Empty; } - drawCall.Skinning = nullptr; drawCall.WorldDeterminantSign = Math::FloatSelect(drawCall.World.RotDeterminant(), 1, -1); drawCall.PerInstanceRandom = _perInstanceRandom; - drawCall.LODDitherFactor = 0.0f; // Add half-texel offset for heightmap sampling in vertex shader //const float lodHeightmapSize = Math::Max(1, drawCall.TerrainData.Heightmap->Width() >> lod); @@ -147,32 +145,30 @@ void TerrainChunk::Draw(const RenderContext& renderContext, MaterialBase* materi drawCall.Material = material; drawCall.World = _world; drawCall.ObjectPosition = drawCall.World.GetTranslation(); - drawCall.TerrainData.Patch = _patch; - drawCall.TerrainData.HeightmapUVScaleBias = _heightmapUVScaleBias; - drawCall.TerrainData.OffsetUV = Vector2((float)(_patch->_x * TerrainPatch::CHUNKS_COUNT_EDGE + _x), (float)(_patch->_z * TerrainPatch::CHUNKS_COUNT_EDGE + _z)); - drawCall.TerrainData.CurrentLOD = (float)lod; - drawCall.TerrainData.ChunkSizeNextLOD = (float)(((chunkSize + 1) >> (lod + 1)) - 1); - drawCall.TerrainData.TerrainChunkSizeLOD0 = TERRAIN_UNITS_PER_VERTEX * chunkSize; - drawCall.TerrainData.NeighborLOD.X = (float)lod; - drawCall.TerrainData.NeighborLOD.Y = (float)lod; - drawCall.TerrainData.NeighborLOD.Z = (float)lod; - drawCall.TerrainData.NeighborLOD.W = (float)lod; + drawCall.Terrain.Patch = _patch; + drawCall.Terrain.HeightmapUVScaleBias = _heightmapUVScaleBias; + drawCall.Terrain.OffsetUV = Vector2((float)(_patch->_x * TerrainPatch::CHUNKS_COUNT_EDGE + _x), (float)(_patch->_z * TerrainPatch::CHUNKS_COUNT_EDGE + _z)); + drawCall.Terrain.CurrentLOD = (float)lod; + drawCall.Terrain.ChunkSizeNextLOD = (float)(((chunkSize + 1) >> (lod + 1)) - 1); + drawCall.Terrain.TerrainChunkSizeLOD0 = TERRAIN_UNITS_PER_VERTEX * chunkSize; + drawCall.Terrain.NeighborLOD.X = (float)lod; + drawCall.Terrain.NeighborLOD.Y = (float)lod; + drawCall.Terrain.NeighborLOD.Z = (float)lod; + drawCall.Terrain.NeighborLOD.W = (float)lod; const auto scene = _patch->_terrain->GetScene(); const auto flags = _patch->_terrain->_staticFlags; if (flags & StaticFlags::Lightmap && scene) { - drawCall.Lightmap = scene->LightmapsData.GetReadyLightmap(Lightmap.TextureIndex); - drawCall.LightmapUVsArea = Lightmap.UVsArea; + drawCall.Terrain.Lightmap = scene->LightmapsData.GetReadyLightmap(Lightmap.TextureIndex); + drawCall.Terrain.LightmapUVsArea = Lightmap.UVsArea; } else { - drawCall.Lightmap = nullptr; - drawCall.LightmapUVsArea = Rectangle::Empty; + drawCall.Terrain.Lightmap = nullptr; + drawCall.Terrain.LightmapUVsArea = Rectangle::Empty; } - drawCall.Skinning = nullptr; drawCall.WorldDeterminantSign = Math::FloatSelect(drawCall.World.RotDeterminant(), 1, -1); drawCall.PerInstanceRandom = _perInstanceRandom; - drawCall.LODDitherFactor = 0.0f; // Add half-texel offset for heightmap sampling in vertex shader //const float lodHeightmapSize = Math::Max(1, drawCall.TerrainData.Heightmap->Width() >> lod); diff --git a/Source/Engine/UI/TextRender.cpp b/Source/Engine/UI/TextRender.cpp index 958aced8b..5707b4461 100644 --- a/Source/Engine/UI/TextRender.cpp +++ b/Source/Engine/UI/TextRender.cpp @@ -319,15 +319,15 @@ void TextRender::Draw(RenderContext& renderContext) // Setup draw call DrawCall drawCall; drawCall.World = _world; - drawCall.PrevWorld = _drawState.PrevWorld; drawCall.ObjectPosition = drawCall.World.GetTranslation(); - drawCall.GeometrySize = _localBox.GetSize(); - drawCall.Lightmap = nullptr; - drawCall.LightmapUVsArea = Rectangle::Empty; - drawCall.Skinning = nullptr; + drawCall.Surface.GeometrySize = _localBox.GetSize(); + drawCall.Surface.PrevWorld = _drawState.PrevWorld; + drawCall.Surface.Lightmap = nullptr; + drawCall.Surface.LightmapUVsArea = Rectangle::Empty; + drawCall.Surface.Skinning = nullptr; + drawCall.Surface.LODDitherFactor = 0.0f; drawCall.WorldDeterminantSign = Math::FloatSelect(_world.RotDeterminant(), 1, -1); drawCall.PerInstanceRandom = GetPerInstanceRandom(); - drawCall.LODDitherFactor = 0.0f; drawCall.Geometry.IndexBuffer = _ib.GetBuffer(); drawCall.Geometry.VertexBuffers[0] = _vb0.GetBuffer(); drawCall.Geometry.VertexBuffers[1] = _vb1.GetBuffer();