Add draw call sorting keys generation during draw calls collection (async)

This commit is contained in:
Wojtek Figat
2022-11-16 09:20:56 +01:00
parent eb281a7574
commit 3b4d91924f
9 changed files with 62 additions and 36 deletions

View File

@@ -436,7 +436,7 @@ void Mesh::Draw(const RenderContext& renderContext, MaterialBase* material, cons
drawCall.PerInstanceRandom = perInstanceRandom;
// Push draw call to the render list
renderContext.List->AddDrawCall(drawModes, flags, drawCall, receiveDecals);
renderContext.List->AddDrawCall(renderContext, drawModes, flags, drawCall, receiveDecals);
}
void Mesh::Draw(const RenderContext& renderContext, const DrawInfo& info, float lodDitherFactor) const
@@ -497,7 +497,7 @@ void Mesh::Draw(const RenderContext& renderContext, const DrawInfo& info, float
drawCall.PerInstanceRandom = info.PerInstanceRandom;
// Push draw call to the render list
renderContext.List->AddDrawCall(drawModes, info.Flags, drawCall, entry.ReceiveDecals);
renderContext.List->AddDrawCall(renderContext, drawModes, info.Flags, drawCall, entry.ReceiveDecals);
}
void Mesh::Draw(const RenderContextBatch& renderContextBatch, const DrawInfo& info, float lodDitherFactor) const

View File

@@ -213,7 +213,7 @@ void SkinnedMesh::Draw(const RenderContext& renderContext, const DrawInfo& info,
drawCall.PerInstanceRandom = info.PerInstanceRandom;
// Push draw call to the render list
renderContext.List->AddDrawCall(drawModes, StaticFlags::None, drawCall, entry.ReceiveDecals);
renderContext.List->AddDrawCall(renderContext, drawModes, StaticFlags::None, drawCall, entry.ReceiveDecals);
}
void SkinnedMesh::Draw(const RenderContextBatch& renderContextBatch, const DrawInfo& info, float lodDitherFactor) const

View File

@@ -434,7 +434,7 @@ void SplineModel::Draw(RenderContext& renderContext)
mesh->GetDrawCallGeometry(drawCall);
drawCall.Material = material;
drawCall.WorldDeterminantSign = Math::FloatSelect(worldDeterminantSign * instance.RotDeterminant, 1, -1);
renderContext.List->AddDrawCall(drawModes, _staticFlags, drawCall, entry.ReceiveDecals);
renderContext.List->AddDrawCall(renderContext, drawModes, _staticFlags, drawCall, entry.ReceiveDecals);
}
}
}

View File

@@ -416,7 +416,7 @@ void DrawEmitterCPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCa
// Submit draw call
SpriteRenderer.SetupDrawCall(drawCall);
drawCall.InstanceCount = buffer->CPU.Count;
renderContext.List->AddDrawCall(dp, staticFlags, drawCall, false);
renderContext.List->AddDrawCall(renderContext, dp, staticFlags, drawCall, false);
break;
}
@@ -444,7 +444,7 @@ void DrawEmitterCPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCa
// Submit draw call
mesh.GetDrawCallGeometry(drawCall);
drawCall.InstanceCount = buffer->CPU.Count;
renderContext.List->AddDrawCall(dp, staticFlags, drawCall, false);
renderContext.List->AddDrawCall(renderContext, dp, staticFlags, drawCall, false);
}
break;
@@ -504,7 +504,7 @@ void DrawEmitterCPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCa
drawCall.Draw.StartIndex = ribbonModulesDrawIndicesStart[ribbonModuleIndex];
drawCall.Draw.IndicesCount = ribbonModulesDrawIndicesCount[ribbonModuleIndex];
drawCall.InstanceCount = 1;
renderContext.List->AddDrawCall(dp, staticFlags, drawCall, false);
renderContext.List->AddDrawCall(renderContext, dp, staticFlags, drawCall, false);
ribbonModuleIndex++;
@@ -828,7 +828,7 @@ void DrawEmitterGPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCa
drawCall.Draw.IndirectArgsBuffer = buffer->GPU.IndirectDrawArgsBuffer;
drawCall.Draw.IndirectArgsOffset = indirectDrawCallIndex * sizeof(GPUDrawIndexedIndirectArgs);
if (dp != DrawPass::None)
renderContext.List->AddDrawCall(dp, staticFlags, drawCall, false);
renderContext.List->AddDrawCall(renderContext, dp, staticFlags, drawCall, false);
indirectDrawCallIndex++;
break;
@@ -858,7 +858,7 @@ void DrawEmitterGPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCa
drawCall.Draw.IndirectArgsBuffer = buffer->GPU.IndirectDrawArgsBuffer;
drawCall.Draw.IndirectArgsOffset = indirectDrawCallIndex * sizeof(GPUDrawIndexedIndirectArgs);
if (dp != DrawPass::None)
renderContext.List->AddDrawCall(dp, staticFlags, drawCall, false);
renderContext.List->AddDrawCall(renderContext, dp, staticFlags, drawCall, false);
indirectDrawCallIndex++;
}

View File

@@ -269,6 +269,11 @@ struct DrawCall
/// </summary>
float PerInstanceRandom;
/// <summary>
/// The sorting key for the draw call calculate by RenderList.
/// </summary>
uint64 SortKey;
/// <summary>
/// Does nothing.
/// </summary>

View File

@@ -16,7 +16,7 @@
#include "Engine/Level/Scene/Lightmap.h"
#include "Engine/Level/Actors/PostFxVolume.h"
static_assert(sizeof(DrawCall) <= 280, "Too big draw call data size.");
static_assert(sizeof(DrawCall) <= 288, "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.");
@@ -408,7 +408,25 @@ void RenderList::Clear()
_instanceBuffer.Clear();
}
void RenderList::AddDrawCall(DrawPass drawModes, StaticFlags staticFlags, const DrawCall& drawCall, bool receivesDecals)
FORCE_INLINE void CalculateSortKey(const RenderContext& renderContext, DrawCall& drawCall)
{
const Float3 planeNormal = renderContext.View.Direction;
const float planePoint = -Float3::Dot(planeNormal, renderContext.View.Position);
const float distance = Float3::Dot(planeNormal, drawCall.ObjectPosition) - planePoint;
const uint32 sortKey = RenderTools::ComputeDistanceSortKey(distance);
uint32 batchKey = GetHash(drawCall.Geometry.IndexBuffer);
batchKey = (batchKey * 397) ^ GetHash(drawCall.Geometry.VertexBuffers[0]);
batchKey = (batchKey * 397) ^ GetHash(drawCall.Geometry.VertexBuffers[1]);
batchKey = (batchKey * 397) ^ GetHash(drawCall.Geometry.VertexBuffers[2]);
batchKey = (batchKey * 397) ^ GetHash(drawCall.Material);
IMaterial::InstancingHandler handler;
if (drawCall.Material->CanUseInstancing(handler))
handler.GetHash(drawCall, batchKey);
batchKey += (int32)(471 * drawCall.WorldDeterminantSign);
drawCall.SortKey = (uint64)batchKey << 32 | (uint64)sortKey;
}
void RenderList::AddDrawCall(const RenderContext& renderContext, DrawPass drawModes, StaticFlags staticFlags, DrawCall& drawCall, bool receivesDecals)
{
#if ENABLE_ASSERTION_LOW_LAYERS
// Ensure that draw modes are non-empty and in conjunction with material draw modes
@@ -417,6 +435,7 @@ void RenderList::AddDrawCall(DrawPass drawModes, StaticFlags staticFlags, const
#endif
// Append draw call data
CalculateSortKey(renderContext, drawCall);
const int32 index = DrawCalls.Add(drawCall);
// Add draw call to proper draw lists
@@ -445,19 +464,20 @@ void RenderList::AddDrawCall(DrawPass drawModes, StaticFlags staticFlags, const
}
}
void RenderList::AddDrawCall(const RenderContextBatch& renderContextBatch, DrawPass drawModes, StaticFlags staticFlags, ShadowsCastingMode shadowsMode, const BoundingSphere& bounds, const DrawCall& drawCall, bool receivesDecals)
void RenderList::AddDrawCall(const RenderContextBatch& renderContextBatch, DrawPass drawModes, StaticFlags staticFlags, ShadowsCastingMode shadowsMode, const BoundingSphere& bounds, DrawCall& drawCall, bool receivesDecals)
{
#if ENABLE_ASSERTION_LOW_LAYERS
// Ensure that draw modes are non-empty and in conjunction with material draw modes
auto materialDrawModes = drawCall.Material->GetDrawModes();
ASSERT_LOW_LAYER(drawModes != DrawPass::None && ((uint32)drawModes & ~(uint32)materialDrawModes) == 0);
#endif
const RenderContext& mainRenderContext = renderContextBatch.Contexts.Get()[0];
// Append draw call data
CalculateSortKey(mainRenderContext, drawCall);
const int32 index = DrawCalls.Add(drawCall);
// Add draw call to proper draw lists
const RenderContext& mainRenderContext = renderContextBatch.Contexts.Get()[0];
DrawPass modes = (DrawPass)(drawModes & mainRenderContext.View.GetShadowsDrawPassMask(shadowsMode));
drawModes = (DrawPass)(modes & mainRenderContext.View.Pass);
if (drawModes != DrawPass::None && mainRenderContext.View.CullingFrustum.Intersects(bounds))
@@ -525,8 +545,6 @@ void RenderList::SortDrawCalls(const RenderContext& renderContext, bool reverseD
const auto* drawCallsData = drawCalls.Get();
const auto* listData = list.Indices.Get();
const int32 listSize = list.Indices.Count();
const Float3 planeNormal = renderContext.View.Direction;
const float planePoint = -Float3::Dot(planeNormal, renderContext.View.Position);
// Peek shared memory
#define PREPARE_CACHE(list) (list).Clear(); (list).Resize(listSize)
@@ -537,22 +555,24 @@ void RenderList::SortDrawCalls(const RenderContext& renderContext, bool reverseD
uint64* sortedKeys = SortingKeys[0].Get();
// Generate sort keys (by depth) and batch keys (higher bits)
const uint32 sortKeyXor = reverseDistance ? MAX_uint32 : 0;
for (int32 i = 0; i < listSize; i++)
if (reverseDistance)
{
const DrawCall& drawCall = drawCallsData[listData[i]];
const float distance = Float3::Dot(planeNormal, drawCall.ObjectPosition) - planePoint;
const uint32 sortKey = RenderTools::ComputeDistanceSortKey(distance) ^ sortKeyXor;
uint32 batchKey = GetHash(drawCall.Geometry.IndexBuffer);
batchKey = (batchKey * 397) ^ GetHash(drawCall.Geometry.VertexBuffers[0]);
batchKey = (batchKey * 397) ^ GetHash(drawCall.Geometry.VertexBuffers[1]);
batchKey = (batchKey * 397) ^ GetHash(drawCall.Geometry.VertexBuffers[2]);
batchKey = (batchKey * 397) ^ GetHash(drawCall.Material);
IMaterial::InstancingHandler handler;
if (drawCall.Material->CanUseInstancing(handler))
handler.GetHash(drawCall, batchKey);
batchKey += (int32)(471 * drawCall.WorldDeterminantSign);
sortedKeys[i] = (uint64)batchKey << 32 | (uint64)sortKey;
const uint32 sortKeyXor = reverseDistance ? MAX_uint32 : 0;
for (int32 i = 0; i < listSize; i++)
{
const DrawCall& drawCall = drawCallsData[listData[i]];
const uint32 sortKey = (uint32)drawCall.SortKey ^ sortKeyXor;
const uint32 batchKey = (uint32)(drawCall.SortKey >> 32);
sortedKeys[i] = (uint64)batchKey << 32 | (uint64)sortKey;
}
}
else
{
for (int32 i = 0; i < listSize; i++)
{
const DrawCall& drawCall = drawCallsData[listData[i]];
sortedKeys[i] = drawCall.SortKey;
}
}
// Sort draw calls indices
@@ -867,7 +887,7 @@ bool SurfaceDrawCallHandler::CanBatch(const DrawCall& a, const DrawCall& b)
{
// 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 &&
//return a.Surface.Lightmap == b.Surface.Lightmap &&
a.Surface.Skinning == nullptr &&
b.Surface.Skinning == nullptr;
}

View File

@@ -478,11 +478,12 @@ public:
/// <summary>
/// Adds the draw call to the draw lists.
/// </summary>
/// <param name="renderContext">The rendering context.</param>
/// <param name="drawModes">The object draw modes.</param>
/// <param name="staticFlags">The object static flags.</param>
/// <param name="drawCall">The draw call data.</param>
/// <param name="receivesDecals">True if the rendered mesh can receive decals.</param>
void AddDrawCall(DrawPass drawModes, StaticFlags staticFlags, const DrawCall& drawCall, bool receivesDecals);
void AddDrawCall(const RenderContext& renderContext, DrawPass drawModes, StaticFlags staticFlags, DrawCall& drawCall, bool receivesDecals);
/// <summary>
/// Adds the draw call to the draw lists and references it in other render contexts. Performs additional per-context frustum culling.
@@ -494,7 +495,7 @@ public:
/// <param name="bounds">The object bounds.</param>
/// <param name="drawCall">The draw call data.</param>
/// <param name="receivesDecals">True if the rendered mesh can receive decals.</param>
void AddDrawCall(const RenderContextBatch& renderContextBatch, DrawPass drawModes, StaticFlags staticFlags, ShadowsCastingMode shadowsMode, const BoundingSphere& bounds, const DrawCall& drawCall, bool receivesDecals);
void AddDrawCall(const RenderContextBatch& renderContextBatch, DrawPass drawModes, StaticFlags staticFlags, ShadowsCastingMode shadowsMode, const BoundingSphere& bounds, DrawCall& drawCall, bool receivesDecals);
/// <summary>
/// Sorts the collected draw calls list.

View File

@@ -123,7 +123,7 @@ void TerrainChunk::Draw(const RenderContext& renderContext) const
// Submit draw call
auto drawModes = (DrawPass)(_patch->_terrain->DrawModes & renderContext.View.Pass & (uint32)drawCall.Material->GetDrawModes());
if (drawModes != DrawPass::None)
renderContext.List->AddDrawCall(drawModes, flags, drawCall, true);
renderContext.List->AddDrawCall(renderContext, drawModes, flags, drawCall, true);
}
void TerrainChunk::Draw(const RenderContext& renderContext, MaterialBase* material, int32 lodIndex) const
@@ -179,7 +179,7 @@ void TerrainChunk::Draw(const RenderContext& renderContext, MaterialBase* materi
// Submit draw call
auto drawModes = (DrawPass)(_patch->_terrain->DrawModes & renderContext.View.Pass & (uint32)drawCall.Material->GetDrawModes());
if (drawModes != DrawPass::None)
renderContext.List->AddDrawCall(drawModes, flags, drawCall, true);
renderContext.List->AddDrawCall(renderContext, drawModes, flags, drawCall, true);
}
bool TerrainChunk::Intersects(const Ray& ray, Real& distance)

View File

@@ -391,7 +391,7 @@ void TextRender::Draw(RenderContext& renderContext)
drawCall.Draw.IndicesCount = e.IndicesCount;
drawCall.Draw.StartIndex = e.StartIndex;
drawCall.Material = e.Material;
renderContext.List->AddDrawCall(drawModes, GetStaticFlags(), drawCall, true);
renderContext.List->AddDrawCall(renderContext, drawModes, GetStaticFlags(), drawCall, true);
}
}