diff --git a/Source/Engine/Graphics/Materials/IMaterial.h b/Source/Engine/Graphics/Materials/IMaterial.h
index 83b6abf52..5235dd59e 100644
--- a/Source/Engine/Graphics/Materials/IMaterial.h
+++ b/Source/Engine/Graphics/Materials/IMaterial.h
@@ -119,7 +119,7 @@ public:
struct InstancingHandler
{
void (*GetHash)(const DrawCall& drawCall, uint32& batchKey);
- bool (*CanBatch)(const DrawCall& a, const DrawCall& b);
+ bool (*CanBatch)(const DrawCall& a, const DrawCall& b, DrawPass pass);
void (*WriteDrawCall)(struct InstanceData* instanceData, const DrawCall& drawCall);
};
diff --git a/Source/Engine/Renderer/RenderList.cpp b/Source/Engine/Renderer/RenderList.cpp
index 29b9bd622..efe3edd2a 100644
--- a/Source/Engine/Renderer/RenderList.cpp
+++ b/Source/Engine/Renderer/RenderList.cpp
@@ -551,26 +551,21 @@ void RenderList::AddDrawCall(const RenderContextBatch& renderContextBatch, DrawP
namespace
{
- ///
- /// 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)
+ FORCE_INLINE bool CanBatchWith(const DrawCall& a, const DrawCall& b, DrawPass pass)
{
- IMaterial::InstancingHandler handler;
- return a.Material == b.Material &&
- a.Material->CanUseInstancing(handler) &&
+ IMaterial::InstancingHandler handlerA, handlerB;
+ return a.Material->CanUseInstancing(handlerA) &&
+ b.Material->CanUseInstancing(handlerB) &&
Platform::MemoryCompare(&a.Geometry, &b.Geometry, sizeof(a.Geometry)) == 0 &&
a.InstanceCount != 0 &&
b.InstanceCount != 0 &&
- handler.CanBatch(a, b) &&
+ handlerA.CanBatch == handlerB.CanBatch &&
+ handlerA.CanBatch(a, b, pass) &&
a.WorldDeterminantSign * b.WorldDeterminantSign > 0;
}
}
-void RenderList::SortDrawCalls(const RenderContext& renderContext, bool reverseDistance, DrawCallsList& list, const RenderListBuffer& drawCalls)
+void RenderList::SortDrawCalls(const RenderContext& renderContext, bool reverseDistance, DrawCallsList& list, const RenderListBuffer& drawCalls, DrawPass pass)
{
PROFILE_CPU();
const auto* drawCallsData = drawCalls.Get();
@@ -625,7 +620,7 @@ void RenderList::SortDrawCalls(const RenderContext& renderContext, bool reverseD
for (int32 j = i + 1; j < listSize; j++)
{
const DrawCall& other = drawCallsData[listData[j]];
- if (!CanBatchWith(drawCall, other))
+ if (!CanBatchWith(drawCall, other, pass))
break;
batchSize++;
instanceCount += other.InstanceCount;
@@ -917,13 +912,29 @@ void SurfaceDrawCallHandler::GetHash(const DrawCall& drawCall, uint32& batchKey)
batchKey = (batchKey * 397) ^ ::GetHash(drawCall.Surface.Lightmap);
}
-bool SurfaceDrawCallHandler::CanBatch(const DrawCall& a, const DrawCall& b)
+bool SurfaceDrawCallHandler::CanBatch(const DrawCall& a, const DrawCall& b, DrawPass pass)
{
// TODO: find reason why batching static meshes with lightmap causes problems with sampling in shader (flickering when meshes in batch order gets changes due to async draw calls collection)
- return a.Surface.Lightmap == nullptr && b.Surface.Lightmap == nullptr &&
- //return a.Surface.Lightmap == b.Surface.Lightmap &&
- a.Surface.Skinning == nullptr &&
- b.Surface.Skinning == nullptr;
+ if (a.Surface.Lightmap == nullptr && b.Surface.Lightmap == nullptr &&
+ //return a.Surface.Lightmap == b.Surface.Lightmap &&
+ a.Surface.Skinning == nullptr &&
+ b.Surface.Skinning == nullptr)
+ {
+ if (a.Material != b.Material)
+ {
+ // Batch simple materials during depth-only drawing (when using default vertex shader and no pixel shader)
+ if (pass == DrawPass::Depth)
+ {
+ constexpr MaterialUsageFlags complexUsageFlags = MaterialUsageFlags::UseMask | MaterialUsageFlags::UsePositionOffset | MaterialUsageFlags::UseDisplacement;
+ const bool aIsSimple = EnumHasNoneFlags(a.Material->GetInfo().UsageFlags, complexUsageFlags);
+ const bool bIsSimple = EnumHasNoneFlags(b.Material->GetInfo().UsageFlags, complexUsageFlags);
+ return aIsSimple && bIsSimple;
+ }
+ return false;
+ }
+ return true;
+ }
+ return false;
}
void SurfaceDrawCallHandler::WriteDrawCall(InstanceData* instanceData, const DrawCall& drawCall)
diff --git a/Source/Engine/Renderer/RenderList.h b/Source/Engine/Renderer/RenderList.h
index 5f2aecbd9..15b5a9842 100644
--- a/Source/Engine/Renderer/RenderList.h
+++ b/Source/Engine/Renderer/RenderList.h
@@ -480,9 +480,10 @@ public:
/// The rendering context.
/// If set to true reverse draw call distance to the view. Results in back to front sorting.
/// The collected draw calls list type.
- API_FUNCTION() FORCE_INLINE void SortDrawCalls(API_PARAM(Ref) const RenderContext& renderContext, bool reverseDistance, DrawCallsListType listType)
+ /// The draw pass (optional).
+ API_FUNCTION() FORCE_INLINE void SortDrawCalls(API_PARAM(Ref) const RenderContext& renderContext, bool reverseDistance, DrawCallsListType listType, DrawPass pass = DrawPass::All)
{
- SortDrawCalls(renderContext, reverseDistance, DrawCallsLists[(int32)listType], DrawCalls);
+ SortDrawCalls(renderContext, reverseDistance, DrawCallsLists[(int32)listType], DrawCalls, pass);
}
///
@@ -492,7 +493,8 @@ public:
/// If set to true reverse draw call distance to the view. Results in back to front sorting.
/// The collected draw calls indices list.
/// The collected draw calls list.
- void SortDrawCalls(const RenderContext& renderContext, bool reverseDistance, DrawCallsList& list, const RenderListBuffer& drawCalls);
+ /// The draw pass (optional).
+ void SortDrawCalls(const RenderContext& renderContext, bool reverseDistance, DrawCallsList& list, const RenderListBuffer& drawCalls, DrawPass pass = DrawPass::All);
///
/// Executes the collected draw calls.
@@ -543,6 +545,6 @@ PACK_STRUCT(struct FLAXENGINE_API InstanceData
struct SurfaceDrawCallHandler
{
static void GetHash(const DrawCall& drawCall, uint32& batchKey);
- static bool CanBatch(const DrawCall& a, const DrawCall& b);
+ static bool CanBatch(const DrawCall& a, const DrawCall& b, DrawPass pass);
static void WriteDrawCall(InstanceData* instanceData, const DrawCall& drawCall);
};
diff --git a/Source/Engine/Renderer/Renderer.cpp b/Source/Engine/Renderer/Renderer.cpp
index 0ef39bb30..7500b2f1e 100644
--- a/Source/Engine/Renderer/Renderer.cpp
+++ b/Source/Engine/Renderer/Renderer.cpp
@@ -244,7 +244,7 @@ void Renderer::DrawSceneDepth(GPUContext* context, SceneRenderTask* task, GPUTex
DrawActors(renderContext, customActors);
// Sort draw calls
- renderContext.List->SortDrawCalls(renderContext, false, DrawCallsListType::Depth);
+ renderContext.List->SortDrawCalls(renderContext, false, DrawCallsListType::Depth, DrawPass::Depth);
// Execute draw calls
const float width = (float)output->Width();
@@ -405,8 +405,8 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext, RenderCont
for (int32 i = 1; i < renderContextBatch.Contexts.Count(); i++)
{
auto& shadowContext = renderContextBatch.Contexts[i];
- shadowContext.List->SortDrawCalls(shadowContext, false, DrawCallsListType::Depth);
- shadowContext.List->SortDrawCalls(shadowContext, false, shadowContext.List->ShadowDepthDrawCallsList, renderContext.List->DrawCalls);
+ shadowContext.List->SortDrawCalls(shadowContext, false, DrawCallsListType::Depth, DrawPass::Depth);
+ shadowContext.List->SortDrawCalls(shadowContext, false, shadowContext.List->ShadowDepthDrawCallsList, renderContext.List->DrawCalls, DrawPass::Depth);
}
}