Optimize depth pass rendering to batch simple materials together
This commit is contained in:
@@ -119,7 +119,7 @@ public:
|
|||||||
struct InstancingHandler
|
struct InstancingHandler
|
||||||
{
|
{
|
||||||
void (*GetHash)(const DrawCall& drawCall, uint32& batchKey);
|
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);
|
void (*WriteDrawCall)(struct InstanceData* instanceData, const DrawCall& drawCall);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -551,26 +551,21 @@ void RenderList::AddDrawCall(const RenderContextBatch& renderContextBatch, DrawP
|
|||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
/// <summary>
|
FORCE_INLINE bool CanBatchWith(const DrawCall& a, const DrawCall& b, DrawPass pass)
|
||||||
/// 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)
|
|
||||||
{
|
{
|
||||||
IMaterial::InstancingHandler handler;
|
IMaterial::InstancingHandler handlerA, handlerB;
|
||||||
return a.Material == b.Material &&
|
return a.Material->CanUseInstancing(handlerA) &&
|
||||||
a.Material->CanUseInstancing(handler) &&
|
b.Material->CanUseInstancing(handlerB) &&
|
||||||
Platform::MemoryCompare(&a.Geometry, &b.Geometry, sizeof(a.Geometry)) == 0 &&
|
Platform::MemoryCompare(&a.Geometry, &b.Geometry, sizeof(a.Geometry)) == 0 &&
|
||||||
a.InstanceCount != 0 &&
|
a.InstanceCount != 0 &&
|
||||||
b.InstanceCount != 0 &&
|
b.InstanceCount != 0 &&
|
||||||
handler.CanBatch(a, b) &&
|
handlerA.CanBatch == handlerB.CanBatch &&
|
||||||
|
handlerA.CanBatch(a, b, pass) &&
|
||||||
a.WorldDeterminantSign * b.WorldDeterminantSign > 0;
|
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();
|
PROFILE_CPU();
|
||||||
const auto* drawCallsData = drawCalls.Get();
|
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++)
|
for (int32 j = i + 1; j < listSize; j++)
|
||||||
{
|
{
|
||||||
const DrawCall& other = drawCallsData[listData[j]];
|
const DrawCall& other = drawCallsData[listData[j]];
|
||||||
if (!CanBatchWith(drawCall, other))
|
if (!CanBatchWith(drawCall, other, pass))
|
||||||
break;
|
break;
|
||||||
batchSize++;
|
batchSize++;
|
||||||
instanceCount += other.InstanceCount;
|
instanceCount += other.InstanceCount;
|
||||||
@@ -917,13 +912,29 @@ void SurfaceDrawCallHandler::GetHash(const DrawCall& drawCall, uint32& batchKey)
|
|||||||
batchKey = (batchKey * 397) ^ ::GetHash(drawCall.Surface.Lightmap);
|
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)
|
// 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 &&
|
if (a.Surface.Lightmap == nullptr && b.Surface.Lightmap == nullptr &&
|
||||||
//return a.Surface.Lightmap == b.Surface.Lightmap &&
|
//return a.Surface.Lightmap == b.Surface.Lightmap &&
|
||||||
a.Surface.Skinning == nullptr &&
|
a.Surface.Skinning == nullptr &&
|
||||||
b.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)
|
void SurfaceDrawCallHandler::WriteDrawCall(InstanceData* instanceData, const DrawCall& drawCall)
|
||||||
|
|||||||
@@ -480,9 +480,10 @@ public:
|
|||||||
/// <param name="renderContext">The rendering context.</param>
|
/// <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="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>
|
/// <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>
|
/// <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="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="list">The collected draw calls indices list.</param>
|
||||||
/// <param name="drawCalls">The collected draw calls 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>
|
/// <summary>
|
||||||
/// Executes the collected draw calls.
|
/// Executes the collected draw calls.
|
||||||
@@ -543,6 +545,6 @@ PACK_STRUCT(struct FLAXENGINE_API InstanceData
|
|||||||
struct SurfaceDrawCallHandler
|
struct SurfaceDrawCallHandler
|
||||||
{
|
{
|
||||||
static void GetHash(const DrawCall& drawCall, uint32& batchKey);
|
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);
|
static void WriteDrawCall(InstanceData* instanceData, const DrawCall& drawCall);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -244,7 +244,7 @@ void Renderer::DrawSceneDepth(GPUContext* context, SceneRenderTask* task, GPUTex
|
|||||||
DrawActors(renderContext, customActors);
|
DrawActors(renderContext, customActors);
|
||||||
|
|
||||||
// Sort draw calls
|
// Sort draw calls
|
||||||
renderContext.List->SortDrawCalls(renderContext, false, DrawCallsListType::Depth);
|
renderContext.List->SortDrawCalls(renderContext, false, DrawCallsListType::Depth, DrawPass::Depth);
|
||||||
|
|
||||||
// Execute draw calls
|
// Execute draw calls
|
||||||
const float width = (float)output->Width();
|
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++)
|
for (int32 i = 1; i < renderContextBatch.Contexts.Count(); i++)
|
||||||
{
|
{
|
||||||
auto& shadowContext = renderContextBatch.Contexts[i];
|
auto& shadowContext = renderContextBatch.Contexts[i];
|
||||||
shadowContext.List->SortDrawCalls(shadowContext, false, DrawCallsListType::Depth);
|
shadowContext.List->SortDrawCalls(shadowContext, false, DrawCallsListType::Depth, DrawPass::Depth);
|
||||||
shadowContext.List->SortDrawCalls(shadowContext, false, shadowContext.List->ShadowDepthDrawCallsList, renderContext.List->DrawCalls);
|
shadowContext.List->SortDrawCalls(shadowContext, false, shadowContext.List->ShadowDepthDrawCallsList, renderContext.List->DrawCalls, DrawPass::Depth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user