Add draw call sorting keys generation during draw calls collection (async)
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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++;
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user