Optimize depth pass rendering to batch simple materials together
This commit is contained in:
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
@@ -551,26 +551,21 @@ void RenderList::AddDrawCall(const RenderContextBatch& renderContextBatch, DrawP
|
||||
|
||||
namespace
|
||||
{
|
||||
/// <summary>
|
||||
/// Checks if this draw call be batched together with the other one.
|
||||
/// </summary>
|
||||
/// <param name="a">The first draw call.</param>
|
||||
/// <param name="b">The second draw call.</param>
|
||||
/// <returns>True if can merge them, otherwise false.</returns>
|
||||
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<DrawCall>& drawCalls)
|
||||
void RenderList::SortDrawCalls(const RenderContext& renderContext, bool reverseDistance, DrawCallsList& list, const RenderListBuffer<DrawCall>& 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)
|
||||
|
||||
@@ -480,9 +480,10 @@ public:
|
||||
/// <param name="renderContext">The rendering context.</param>
|
||||
/// <param name="reverseDistance">If set to <c>true</c> reverse draw call distance to the view. Results in back to front sorting.</param>
|
||||
/// <param name="listType">The collected draw calls list type.</param>
|
||||
API_FUNCTION() FORCE_INLINE void SortDrawCalls(API_PARAM(Ref) const RenderContext& renderContext, bool reverseDistance, DrawCallsListType listType)
|
||||
/// <param name="pass">The draw pass (optional).</param>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -492,7 +493,8 @@ public:
|
||||
/// <param name="reverseDistance">If set to <c>true</c> reverse draw call distance to the view. Results in back to front sorting.</param>
|
||||
/// <param name="list">The collected draw calls indices list.</param>
|
||||
/// <param name="drawCalls">The collected draw calls list.</param>
|
||||
void SortDrawCalls(const RenderContext& renderContext, bool reverseDistance, DrawCallsList& list, const RenderListBuffer<DrawCall>& drawCalls);
|
||||
/// <param name="pass">The draw pass (optional).</param>
|
||||
void SortDrawCalls(const RenderContext& renderContext, bool reverseDistance, DrawCallsList& list, const RenderListBuffer<DrawCall>& drawCalls, DrawPass pass = DrawPass::All);
|
||||
|
||||
/// <summary>
|
||||
/// 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);
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user