Skip to content

Commit 0ca49fa

Browse files
committed
perf: Improve UI batch performance
1 parent 4903592 commit 0ca49fa

1 file changed

Lines changed: 25 additions & 44 deletions

File tree

sources/engine/Stride.Graphics/BatchBase.cs

Lines changed: 25 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@ private void DrawBatchPerTexture(Texture texture, ElementInfo[] sprites, int off
416416
DrawBatchPerTextureAndPass(sprites, offset, count);
417417
}
418418

419-
private void DrawBatchPerTextureAndPass(ElementInfo[] sprites, int offset, int count)
419+
private unsafe void DrawBatchPerTextureAndPass(ElementInfo[] sprites, int offset, int count)
420420
{
421421
while (count > 0)
422422
{
@@ -462,67 +462,48 @@ private void DrawBatchPerTextureAndPass(ElementInfo[] sprites, int offset, int c
462462
{
463463
if (ResourceContext.VertexBuffer != null)
464464
GraphicsContext.Allocator.ReleaseReference(ResourceContext.VertexBuffer);
465-
ResourceContext.VertexBuffer = GraphicsContext.Allocator.GetTemporaryBuffer(new BufferDescription(ResourceContext.VertexCount * vertexStructSize, BufferFlags.VertexBuffer, GraphicsResourceUsage.Dynamic));
465+
ResourceContext.VertexBuffer = GraphicsContext.Allocator.GetTemporaryBuffer(new BufferDescription(ResourceContext.VertexCount * vertexStructSize, BufferFlags.VertexBuffer, GraphicsResourceUsage.Default));
466466
GraphicsContext.CommandList.SetVertexBuffer(0, ResourceContext.VertexBuffer, 0, vertexStructSize);
467467
}
468468

469469
if (ResourceContext.IsIndexBufferDynamic && ResourceContext.IndexBufferPosition == 0)
470470
{
471471
if (ResourceContext.IndexBuffer != null)
472472
GraphicsContext.Allocator.ReleaseReference(ResourceContext.IndexBuffer);
473-
ResourceContext.IndexBuffer = GraphicsContext.Allocator.GetTemporaryBuffer(new BufferDescription(ResourceContext.IndexCount * indexStructSize, BufferFlags.IndexBuffer, GraphicsResourceUsage.Dynamic));
473+
ResourceContext.IndexBuffer = GraphicsContext.Allocator.GetTemporaryBuffer(new BufferDescription(ResourceContext.IndexCount * indexStructSize, BufferFlags.IndexBuffer, GraphicsResourceUsage.Default));
474474
GraphicsContext.CommandList.SetIndexBuffer(ResourceContext.IndexBuffer, 0, indexStructSize == sizeof(int));
475475
}
476476

477-
// ------------------------------------------------------------------------------------------------------------
478-
// CAUTION: Performance problem under x64 resolved by this special codepath:
479-
// For some unknown reasons, It seems that writing directly to the pointer returned by the MapSubresource is
480-
// extremely inefficient using x64 but using a temporary buffer and performing a mempcy to the locked region
481-
// seems to be running at the same speed than x86
482-
// ------------------------------------------------------------------------------------------------------------
483-
// TODO Check again why we need this code
484-
//if (IntPtr.Size == 8)
485-
//{
486-
// if (x64TempBuffer == null)
487-
// {
488-
// x64TempBuffer = ToDispose(new DataBuffer(Utilities.SizeOf<VertexPositionColorTexture>() * MaxBatchSize * VerticesPerSprite));
489-
// }
490-
491-
// // Perform the update of all vertices on a temporary buffer
492-
// var texturePtr = (VertexPositionColorTexture*)x64TempBuffer.DataPointer;
493-
// for (int i = 0; i < batchSize; i++)
494-
// {
495-
// UpdateBufferValuesFromElementInfo(ref sprites[offset + i], ref texturePtr, deltaX, deltaY);
496-
// }
497-
498-
// // Then copy this buffer in one shot
499-
// resourceContext.VertexBuffer.SetData(GraphicsDevice, new DataPointer(x64TempBuffer.DataPointer, batchSize * VerticesPerSprite * Utilities.SizeOf<VertexPositionColorTexture>()), offsetInBytes, noOverwrite);
500-
//}
501-
//else
502477
{
503-
var mappedIndices = new MappedResource();
504-
var mappedVertices = GraphicsContext.CommandList.MapSubresource(ResourceContext.VertexBuffer, 0, MapMode.WriteNoOverwrite, false, offsetVertexInBytes, vertexCount * vertexStructSize);
505-
if (ResourceContext.IsIndexBufferDynamic)
506-
mappedIndices = GraphicsContext.CommandList.MapSubresource(ResourceContext.IndexBuffer, 0, MapMode.WriteNoOverwrite, false, offsetIndexInBytes, indexCount * indexStructSize);
507-
508-
var vertexPointer = mappedVertices.DataBox.DataPointer;
509-
var indexPointer = mappedIndices.DataBox.DataPointer;
478+
byte[] vArr = System.Buffers.ArrayPool<byte>.Shared.Rent(vertexCount * vertexStructSize);
479+
byte[] iArr = ResourceContext.IsIndexBufferDynamic == false ? null : System.Buffers.ArrayPool<byte>.Shared.Rent(indexCount * indexStructSize);
480+
var vSpan = vArr.AsSpan(0, vertexCount * vertexStructSize);
481+
var iSpan = ResourceContext.IsIndexBufferDynamic == false ? default : iArr.AsSpan(0, indexCount * indexStructSize);
510482

511-
for (var i = 0; i < batchSize; i++)
483+
fixed (void* vertexPointer2 = vSpan, indexPointer2 = iSpan)
512484
{
513-
var spriteIndex = offset + i;
514-
ref var spriteElementInfo = ref sprites[spriteIndex];
485+
nint vertexPointer = (nint)vertexPointer2;
486+
nint indexPointer = (nint)indexPointer2;
487+
for (var i = 0; i < batchSize; i++)
488+
{
489+
var spriteIndex = offset + i;
490+
ref var spriteElementInfo = ref sprites[spriteIndex];
515491

516-
UpdateBufferValuesFromElementInfo(ref spriteElementInfo, vertexPointer, indexPointer, ResourceContext.VertexBufferPosition);
492+
UpdateBufferValuesFromElementInfo(ref spriteElementInfo, vertexPointer, indexPointer, ResourceContext.VertexBufferPosition);
517493

518-
ResourceContext.VertexBufferPosition += spriteElementInfo.VertexCount;
519-
vertexPointer += vertexStructSize * spriteElementInfo.VertexCount;
520-
indexPointer += indexStructSize * spriteElementInfo.IndexCount;
494+
ResourceContext.VertexBufferPosition += spriteElementInfo.VertexCount;
495+
vertexPointer += vertexStructSize * spriteElementInfo.VertexCount;
496+
indexPointer += indexStructSize * spriteElementInfo.IndexCount;
497+
}
521498
}
522499

523-
GraphicsContext.CommandList.UnmapSubresource(mappedVertices);
500+
// TODO: Should be faster to Map, write and Unmap instead of UpdateSubresource - tried memcopy instead of random writes as well as double-buffer but doesn't seem to matter
501+
ResourceContext.VertexBuffer.SetData<byte>(GraphicsContext.CommandList, vSpan, offsetVertexInBytes);
524502
if (ResourceContext.IsIndexBufferDynamic)
525-
GraphicsContext.CommandList.UnmapSubresource(mappedIndices);
503+
ResourceContext.IndexBuffer.SetData<byte>(GraphicsContext.CommandList, iSpan, offsetIndexInBytes);
504+
System.Buffers.ArrayPool<byte>.Shared.Return(vArr);
505+
if (iArr is not null)
506+
System.Buffers.ArrayPool<byte>.Shared.Return(iArr);
526507
}
527508

528509
// Draw from the specified index

0 commit comments

Comments
 (0)