@@ -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