@@ -46,6 +46,10 @@ public unsafe class Renderer
46
46
private VkBuffer [ ] _materialInfoGPUBuffer ;
47
47
private GpuFrameDataWriter _gpuFrameDataWriter = new ( MaxObjectsPerScene , MaxMaterialInstances ) ;
48
48
49
+ public const int MaxCommands = 150_000 ;
50
+ private VkDrawIndexedIndirectCommand [ ] _cpuDrawCommandsBuffer ;
51
+ private VkBuffer [ ] _drawCommandBuffer ;
52
+
49
53
public static readonly Format RenderTextureImageFormat = Format . B8G8R8A8Srgb ;
50
54
public static Format DepthTextureFormat { get ; private set ; }
51
55
@@ -109,6 +113,10 @@ public unsafe Renderer(uint viewportWidth, uint viewportHeight)
109
113
{
110
114
throw new Exception ( "SizeOf<Pixlit4UvNmapVertex>() != 36. Required for shaders to work." ) ;
111
115
}
116
+ if ( Unsafe . SizeOf < VkDrawIndexedIndirectCommand > ( ) != 20 )
117
+ {
118
+ throw new Exception ( "SizeOf<VkDrawIndexedIndirectCommand>() != 20. Required for shaders to work." ) ;
119
+ }
112
120
113
121
Context = new RenderContext ( ) ;
114
122
//Load global textures like 1x1 white texture & setup default texture sampler
@@ -118,6 +126,7 @@ public unsafe Renderer(uint viewportWidth, uint viewportHeight)
118
126
CreateUniformBuffers ( ) ;
119
127
CreatePerObjectConstantBuffers ( ) ;
120
128
CreateMaterialInfoBuffers ( ) ;
129
+ CreateDrawCommandBuffers ( ) ;
121
130
MaterialHelper . Init ( Context , _renderPass , _perFrameUniformBuffers ! , _perObjectConstantsGPUBuffer , _materialInfoGPUBuffer ) ;
122
131
CreateSyncObjects ( ) ;
123
132
}
@@ -331,6 +340,22 @@ private void CreateMaterialInfoBuffers()
331
340
MemoryPropertyFlags . HostVisibleBit | MemoryPropertyFlags . HostCoherentBit ) ;
332
341
}
333
342
}
343
+
344
+ [ MemberNotNull ( nameof ( _drawCommandBuffer ) ) ]
345
+ [ MemberNotNull ( nameof ( _cpuDrawCommandsBuffer ) ) ]
346
+ private void CreateDrawCommandBuffers ( )
347
+ {
348
+ _cpuDrawCommandsBuffer = new VkDrawIndexedIndirectCommand [ MaxCommands ] ;
349
+
350
+ int bufferSize = MaxCommands * Unsafe . SizeOf < VkDrawIndexedIndirectCommand > ( ) ;
351
+ _drawCommandBuffer = new VkBuffer [ MaxFramesInFlight ] ;
352
+ for ( int i = 0 ; i < MaxFramesInFlight ; i ++ )
353
+ {
354
+ _drawCommandBuffer [ i ] = new VkBuffer ( Context , ( ulong ) bufferSize ,
355
+ BufferUsageFlags . TransferDstBit | BufferUsageFlags . StorageBufferBit | BufferUsageFlags . IndirectBufferBit ,
356
+ MemoryPropertyFlags . HostVisibleBit | MemoryPropertyFlags . HostCoherentBit ) ;
357
+ }
358
+ }
334
359
335
360
private void UpdatePerObjectConstantBuffers ( uint currentImage )
336
361
{
@@ -442,15 +467,33 @@ private void RecordCommands(Scene scene, uint index)
442
467
443
468
MaterialPipeline unifiedPipeline = MaterialHelper . GetMaterialPipeline ( "UnifiedMaterial" ) ?? throw new NullReferenceException ( "Failed to get unified material pipeline!" ) ;
444
469
unifiedPipeline . Bind ( commandBuffer , ( int ) index ) ;
470
+ int totalNumCommands = 0 ;
445
471
foreach ( IGrouping < Mesh , RenderCommand > meshGrouping in _commands . GroupBy ( command => command . Mesh ) )
446
472
{
447
473
Mesh mesh = meshGrouping . Key ;
448
474
mesh . Bind ( Context , commandBuffer ) ;
449
475
476
+ int batchFirstCommand = totalNumCommands ;
477
+ int batchNumCommands = 0 ;
450
478
foreach ( RenderCommand command in meshGrouping )
451
479
{
452
- Context . Vk . CmdDrawIndexed ( commandBuffer , command . IndexCount , 1 , command . StartIndex , 0 , command . ObjectIndex ) ;
480
+ if ( totalNumCommands >= MaxCommands )
481
+ throw new Exception ( $ "Exceeded max draw command count of { MaxCommands } . Please increase Renderer.MaxCommands and recompile Nanoforge to fix this.") ;
482
+
483
+ _cpuDrawCommandsBuffer [ totalNumCommands ++ ] = new VkDrawIndexedIndirectCommand ( command . IndexCount , 1 , command . StartIndex , 0 , command . ObjectIndex ) ;
484
+ batchNumCommands ++ ;
453
485
}
486
+
487
+ ulong batchOffset = ( ulong ) batchFirstCommand * ( ulong ) Unsafe . SizeOf < VkDrawIndexedIndirectCommand > ( ) ;
488
+ fixed ( VkDrawIndexedIndirectCommand * commandsPtr = _cpuDrawCommandsBuffer )
489
+ {
490
+ var commandsSpan = new Span < VkDrawIndexedIndirectCommand > ( commandsPtr + batchFirstCommand , batchNumCommands ) ;
491
+ _drawCommandBuffer [ index ] . SetData ( commandsSpan , batchOffset ) ;
492
+ }
493
+
494
+ uint drawCount = ( uint ) batchNumCommands ;
495
+ uint drawCommandStride = ( uint ) Unsafe . SizeOf < VkDrawIndexedIndirectCommand > ( ) ;
496
+ Context . Vk . CmdDrawIndexedIndirect ( commandBuffer , _drawCommandBuffer [ index ] . VkHandle , batchOffset , drawCount , drawCommandStride ) ;
454
497
}
455
498
456
499
scene . PrimitiveRenderer . RenderPrimitives ( Context , commandBuffer , index ) ;
0 commit comments