Skip to content

Commit b9528b8

Browse files
committed
Fix MapSubresource usage
1 parent 0ca49fa commit b9528b8

1 file changed

Lines changed: 47 additions & 71 deletions

File tree

sources/engine/Stride.Graphics/BatchBase.cs

Lines changed: 47 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ public ElementInfo(int vertexCount, int indexCount, in TDrawInfo drawInfo, float
9191
private ElementInfo[] drawsQueue;
9292
private int drawsQueueCount;
9393
private Texture[] drawTextures;
94+
private List<Buffer> lastFrameBuffers;
9495

9596
private readonly int vertexStructSize;
9697
private readonly int indexStructSize;
@@ -141,6 +142,8 @@ protected BatchBase(GraphicsDevice device, EffectBytecode defaultEffectByteCode,
141142
// Creates the vertex buffer (shared by within a device context).
142143
// TODO: find a better way to do that, and check resource disposal
143144
ResourceContextPool = graphicsDevice.GetOrCreateSharedData(resourceBufferInfo.ResourceKey, d => new ThreadLocal<DeviceResourceContext>(() => new DeviceResourceContext(graphicsDevice, vertexDeclaration, resourceBufferInfo), true));
145+
146+
lastFrameBuffers = new();
144147
}
145148

146149
protected override void Destroy()
@@ -172,6 +175,10 @@ protected void Begin(GraphicsContext graphicsContext, EffectInstance effect, Spr
172175
{
173176
CheckEndHasBeenCalled("begin");
174177

178+
foreach (var buffer in lastFrameBuffers)
179+
GraphicsContext.Allocator.ReleaseReference(buffer);
180+
lastFrameBuffers.Clear();
181+
175182
ResourceContext = ResourceContextPool.Value;
176183

177184
GraphicsContext = graphicsContext;
@@ -416,103 +423,72 @@ private void DrawBatchPerTexture(Texture texture, ElementInfo[] sprites, int off
416423
DrawBatchPerTextureAndPass(sprites, offset, count);
417424
}
418425

419-
private unsafe void DrawBatchPerTextureAndPass(ElementInfo[] sprites, int offset, int count)
426+
private void DrawBatchPerTextureAndPass(ElementInfo[] sprites, int offset, int count)
420427
{
421-
while (count > 0)
428+
ResourceContext.VertexBufferPosition = ResourceContext.VertexCount;
429+
ResourceContext.IndexBufferPosition = ResourceContext.IndexCount;
430+
for (int end = offset + count; offset < end;)
422431
{
423-
// How many index/vertex do we want to draw?
424-
var indexCount = 0;
425-
var vertexCount = 0;
426-
var batchSize = 0;
427-
428-
while (batchSize < count)
432+
if (ResourceContext.VertexBufferPosition == ResourceContext.VertexCount || ResourceContext.IndexBufferPosition == ResourceContext.IndexCount) // Buffer is full, fetch the next ones
429433
{
430-
var spriteIndex = offset + batchSize;
431-
ref var spriteElementInfo = ref sprites[spriteIndex];
434+
ResourceContext.VertexBufferPosition = 0;
435+
ResourceContext.IndexBufferPosition = 0;
432436

433-
// How many sprites does the D3D vertex buffer have room for?
434-
var remainingVertexSpace = ResourceContext.VertexCount - ResourceContext.VertexBufferPosition - vertexCount;
435-
var remainingIndexSpace = ResourceContext.IndexCount - ResourceContext.IndexBufferPosition - indexCount;
437+
ResourceContext.VertexBuffer = GraphicsContext.Allocator.GetTemporaryBuffer(new BufferDescription(ResourceContext.VertexCount * vertexStructSize, BufferFlags.VertexBuffer, GraphicsResourceUsage.Dynamic));
438+
GraphicsContext.CommandList.SetVertexBuffer(0, ResourceContext.VertexBuffer, 0, vertexStructSize);
439+
lastFrameBuffers.Add(ResourceContext.VertexBuffer);
436440

437-
// if there is not enough place left for either the indices or vertices of the current element...,
438-
if (spriteElementInfo.IndexCount > remainingIndexSpace || spriteElementInfo.VertexCount > remainingVertexSpace)
441+
if (ResourceContext.IsIndexBufferDynamic)
439442
{
440-
// if we haven't started the current batch yet, we restart at the beginning of the buffers.
441-
if (batchSize == 0)
442-
{
443-
ResourceContext.VertexBufferPosition = 0;
444-
ResourceContext.IndexBufferPosition = 0;
445-
continue;
446-
}
447-
448-
// else we perform the draw call and batch remaining elements in next draw call.
449-
break;
443+
ResourceContext.IndexBuffer = GraphicsContext.Allocator.GetTemporaryBuffer(new BufferDescription(ResourceContext.IndexCount * indexStructSize, BufferFlags.IndexBuffer, GraphicsResourceUsage.Dynamic));
444+
GraphicsContext.CommandList.SetIndexBuffer(ResourceContext.IndexBuffer, 0, indexStructSize == sizeof(int));
445+
lastFrameBuffers.Add(ResourceContext.IndexBuffer);
450446
}
451-
452-
++batchSize;
447+
}
448+
449+
int indexCount = 0, vertexCount = 0;
450+
int batchStart = offset;
451+
for (int vertexLeft = ResourceContext.VertexCount - ResourceContext.VertexBufferPosition, indexLeft = ResourceContext.IndexCount - ResourceContext.IndexBufferPosition;
452+
offset < end && vertexCount < vertexLeft && indexCount < indexLeft;
453+
offset++)
454+
{
455+
ref var spriteElementInfo = ref sprites[offset];
456+
453457
vertexCount += spriteElementInfo.VertexCount;
454458
indexCount += spriteElementInfo.IndexCount;
455459
}
456460

457-
// Sets the data directly to the buffer in memory
458461
var offsetVertexInBytes = ResourceContext.VertexBufferPosition * vertexStructSize;
459462
var offsetIndexInBytes = ResourceContext.IndexBufferPosition * indexStructSize;
460463

461-
if (ResourceContext.VertexBufferPosition == 0)
462-
{
463-
if (ResourceContext.VertexBuffer != null)
464-
GraphicsContext.Allocator.ReleaseReference(ResourceContext.VertexBuffer);
465-
ResourceContext.VertexBuffer = GraphicsContext.Allocator.GetTemporaryBuffer(new BufferDescription(ResourceContext.VertexCount * vertexStructSize, BufferFlags.VertexBuffer, GraphicsResourceUsage.Default));
466-
GraphicsContext.CommandList.SetVertexBuffer(0, ResourceContext.VertexBuffer, 0, vertexStructSize);
467-
}
464+
var mappedIndices = new MappedResource();
465+
var mappedVertices = GraphicsContext.CommandList.MapSubresource(ResourceContext.VertexBuffer, 0, MapMode.WriteNoOverwrite, false, offsetVertexInBytes, vertexCount * vertexStructSize);
466+
if (ResourceContext.IsIndexBufferDynamic)
467+
mappedIndices = GraphicsContext.CommandList.MapSubresource(ResourceContext.IndexBuffer, 0, MapMode.WriteNoOverwrite, false, offsetIndexInBytes, indexCount * indexStructSize);
468468

469-
if (ResourceContext.IsIndexBufferDynamic && ResourceContext.IndexBufferPosition == 0)
470-
{
471-
if (ResourceContext.IndexBuffer != null)
472-
GraphicsContext.Allocator.ReleaseReference(ResourceContext.IndexBuffer);
473-
ResourceContext.IndexBuffer = GraphicsContext.Allocator.GetTemporaryBuffer(new BufferDescription(ResourceContext.IndexCount * indexStructSize, BufferFlags.IndexBuffer, GraphicsResourceUsage.Default));
474-
GraphicsContext.CommandList.SetIndexBuffer(ResourceContext.IndexBuffer, 0, indexStructSize == sizeof(int));
475-
}
469+
var vertexPointer = mappedVertices.DataBox.DataPointer;
470+
var indexPointer = mappedIndices.DataBox.DataPointer;
476471

472+
for (var i = batchStart; i < offset; i++)
477473
{
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);
474+
ref var spriteElementInfo = ref sprites[i];
482475

483-
fixed (void* vertexPointer2 = vSpan, indexPointer2 = iSpan)
484-
{
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];
491-
492-
UpdateBufferValuesFromElementInfo(ref spriteElementInfo, vertexPointer, indexPointer, ResourceContext.VertexBufferPosition);
493-
494-
ResourceContext.VertexBufferPosition += spriteElementInfo.VertexCount;
495-
vertexPointer += vertexStructSize * spriteElementInfo.VertexCount;
496-
indexPointer += indexStructSize * spriteElementInfo.IndexCount;
497-
}
498-
}
476+
UpdateBufferValuesFromElementInfo(ref spriteElementInfo, vertexPointer, indexPointer, ResourceContext.VertexBufferPosition);
499477

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);
502-
if (ResourceContext.IsIndexBufferDynamic)
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);
478+
ResourceContext.VertexBufferPosition += spriteElementInfo.VertexCount;
479+
vertexPointer += vertexStructSize * spriteElementInfo.VertexCount;
480+
indexPointer += indexStructSize * spriteElementInfo.IndexCount;
507481
}
508482

483+
GraphicsContext.CommandList.UnmapSubresource(mappedVertices);
484+
if (ResourceContext.IsIndexBufferDynamic)
485+
GraphicsContext.CommandList.UnmapSubresource(mappedIndices);
486+
509487
// Draw from the specified index
510488
GraphicsContext.CommandList.DrawIndexed(indexCount, ResourceContext.IndexBufferPosition);
511489

512490
// Update position, offset and remaining count
513491
ResourceContext.IndexBufferPosition += indexCount;
514-
offset += batchSize;
515-
count -= batchSize;
516492
}
517493
}
518494

0 commit comments

Comments
 (0)