Skip to content

Commit ac0a880

Browse files
committed
Add support for user global constant buffers
1 parent 4f8556e commit ac0a880

10 files changed

Lines changed: 378 additions & 22 deletions

src/vrhi_backend.cpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -735,6 +735,49 @@ bool vhCmdBackendState::BE_PreSubmitCommon_FindResource(
735735
return true;
736736
}
737737

738+
// Check for User Globals ($Globals)
739+
// These aren't explicitly bound in vhState::buffers, so we must find them via reflection.
740+
// TODO: Move this to the cache, to avoid O(N^3) loop here.
741+
for ( const auto* shader : scache.bshaders )
742+
{
743+
for ( const auto& res : shader->reflection )
744+
{
745+
if ( res.slot == item.slot && res.type == nvrhi::ResourceType::ConstantBuffer && ( res.name == "$Globals" || res.name == "_Globals" || res.name == "globalParams" ) )
746+
{
747+
if ( state.debugFlags & VRHI_STATE_DEBUG_LOG_ALL_BINDINGS )
748+
{
749+
VRHI_LOG( "FindResource: Found User Globals '%s' at slot %u. Size: %u\n", res.name.c_str(), res.slot, res.sizeInBytes );
750+
for( auto& m : res.members ) VRHI_LOG( " Member: %s ( Offset: %u )\n", m.name.c_str(), m.offset );
751+
}
752+
if ( res.sizeInBytes == 0 ) continue;
753+
754+
static std::vector< uint8_t > s_globalPackBuffer;
755+
uint32_t packSize = res.sizeInBytes;
756+
if ( ( state.debugFlags & VRHI_STATE_DEBUG_LOG_ALL_BINDINGS ) && packSize > 65536 )
757+
{
758+
VRHI_LOG( "FindResource: Large Globals CB size %u\n", packSize );
759+
}
760+
761+
uint32_t alignedSize = ( uint32_t ) VRHI_ROUND_UP( packSize, VRHI_CBUF_ALIGN );
762+
if ( s_globalPackBuffer.size() < alignedSize ) s_globalPackBuffer.resize( alignedSize, 0 );
763+
vhPackUserGlobals( state.uniforms, res.members, s_globalPackBuffer.data(), packSize );
764+
765+
int64_t offset = m_userUniformBuffer.Write( s_globalPackBuffer.data(), alignedSize );
766+
if ( offset < 0 )
767+
{
768+
if ( state.debugFlags & VRHI_STATE_DEBUG_LOG_BINDING_MISMATCH ) VRHI_ERR( "FindResource: Failed to write UserGlobals ($Globals)\n" );
769+
return false;
770+
}
771+
772+
nvrhi::BufferRange range( offset, alignedSize );
773+
outItem = nvrhi::BindingSetItem::ConstantBuffer( item.slot, m_userUniformBuffer.handle[ m_userUniformBuffer.frameIdx ], range );
774+
outItem.type = item.type;
775+
if ( state.debugFlags & VRHI_STATE_DEBUG_LOG_ALL_BINDINGS ) VRHI_LOG( "FindResource: UserGlobals bound to slot %d\n", item.slot );
776+
return true;
777+
}
778+
}
779+
}
780+
738781
auto it = stageTable.bufferTable.find( item.slot );
739782
if ( it == stageTable.bufferTable.end() )
740783
{
@@ -1363,6 +1406,14 @@ void vhCmdBackendState::init()
13631406
descWorld.setCpuAccess( nvrhi::CpuAccessMode::Write );
13641407
descWorld.setDebugName( "WorldUniforms" );
13651408
m_worldUniformBuffer.Init_DeviceStateLocked( descWorld );
1409+
1410+
nvrhi::BufferDesc descUser;
1411+
descUser.setByteSize( g_vhInit.maxUserGlobals );
1412+
descUser.setIsConstantBuffer( true );
1413+
descUser.setCpuAccess( nvrhi::CpuAccessMode::Write );
1414+
descUser.setDebugName( "UserUniforms" );
1415+
m_userUniformBuffer.Init_DeviceStateLocked( descUser );
1416+
assert( g_vhInit.maxUserGlobals % VRHI_CBUF_ALIGN == 0 );
13661417
}
13671418
}
13681419

@@ -1373,6 +1424,7 @@ void vhCmdBackendState::shutdown()
13731424

13741425
m_globalUniformBuffer.Shutdown_DeviceStateLocked();
13751426
m_worldUniformBuffer.Shutdown_DeviceStateLocked();
1427+
m_userUniformBuffer.Shutdown_DeviceStateLocked();
13761428

13771429
backendTextures.clear();
13781430
backendBuffers.clear();
@@ -2169,6 +2221,7 @@ void vhCmdBackendState::Handle_vhFlushInternal( VIDL_vhFlushInternal* cmd )
21692221

21702222
// Flush and step transient buffer maps here.
21712223
// This needs to be done *before* we flush the command lists to GPU!!
2224+
21722225
m_globalUniformBuffer.Unmap_DeviceStateLocked();
21732226
m_globalUniformBuffer.Step();
21742227
m_globalUniformBufferLastHash = 0;
@@ -2177,6 +2230,9 @@ void vhCmdBackendState::Handle_vhFlushInternal( VIDL_vhFlushInternal* cmd )
21772230
m_worldUniformBuffer.Step();
21782231
m_worldUniformBufferLastHash = 0;
21792232

2233+
m_userUniformBuffer.Unmap_DeviceStateLocked();
2234+
m_userUniformBuffer.Step();
2235+
21802236
// Send it!!
21812237
vhCmdListFlushAll_DeviceStateLocked();
21822238

src/vrhi_backend.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ class vhCmdBackendState : public VIDLHandler
135135
uint64_t m_globalUniformBufferLastHash = 0;
136136
vhTransientBuffer m_worldUniformBuffer;
137137
uint64_t m_worldUniformBufferLastHash = 0;
138+
vhTransientBuffer m_userUniformBuffer;
138139

139140
// RAII for vhMem, takes ownership of the pointer and auto-destructs it.
140141
inline std::unique_ptr< vhMem > BE_MemRAII( const vhMem* mem )

src/vrhi_device.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,21 +75,21 @@ void vhEnableRenderDoc()
7575

7676
if ( !mod )
7777
{
78-
VRHI_LOG( "Failed to load renderdoc.dll module.\n" );
78+
VRHI_LOG( " No renderdoc.dll module. This is OK.\n" );
7979
return;
8080
}
8181

8282
pRENDERDOC_GetAPI RENDERDOC_GetAPI = ( pRENDERDOC_GetAPI ) GetProcAddress( mod, "RENDERDOC_GetAPI" );
8383
if ( !RENDERDOC_GetAPI )
8484
{
85-
VRHI_LOG( "Failed to get RENDERDOC_GetAPI address.\n" );
85+
VRHI_LOG( " Failed to get RENDERDOC_GetAPI address.\n" );
8686
return;
8787
}
8888

8989
int ret = RENDERDOC_GetAPI( eRENDERDOC_API_Version_1_1_2, ( void** ) &g_vhRenderDoc );
9090
if ( ret != 1 )
9191
{
92-
VRHI_LOG( "Failed to initialise RenderDoc API.\n" );
92+
VRHI_LOG( " Failed to initialise RenderDoc API.\n" );
9393
return;
9494
}
9595
VRHI_LOG( " RenderDoc API loaded successfully.\n" );

src/vrhi_internal.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,13 @@ bool vhReflectSpirv(
260260
std::vector< vhVertexLayoutDef >* outInputLayout = nullptr
261261
);
262262

263+
void vhPackUserGlobals(
264+
const std::vector< vhState::UniformBufferValue >& uniforms,
265+
const std::vector< vhReflectionMember >& members,
266+
uint8_t* outData,
267+
uint64_t dataSize
268+
);
269+
263270
bool vhShaderValidateBinding( const vhShaderReflectionResource& reflection, const nvrhi::BindingLayoutItem& binding, bool logError );
264271
bool vhDebugLayoutDiffCheck( const nvrhi::BindingLayoutVector& layouts, const nvrhi::BindingSetVector& bindings );
265272
uint64_t vhHashGraphicsPipeline( const nvrhi::GraphicsPipelineDesc& desc, const nvrhi::FramebufferInfo& fbInfo );

src/vrhi_shader.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,15 @@ bool vhReflectSpirv(
213213
res.arraySize = binding->count;
214214
res.sizeInBytes = binding->block.size;
215215

216+
if ( res.type == nvrhi::ResourceType::ConstantBuffer && ( res.name == "$Globals" || res.name == "_Globals" || res.name == "globalParams" ) )
217+
{
218+
for ( uint32_t j = 0; j < binding->block.member_count; ++j )
219+
{
220+
const auto& m = binding->block.members[j];
221+
res.members.push_back( { m.name ? m.name : "", m.offset, m.size } );
222+
}
223+
}
224+
216225
outResources.push_back( res );
217226
}
218227
}
@@ -578,3 +587,45 @@ bool vhShaderValidateBinding( const vhShaderReflectionResource& reflection, cons
578587

579588
return true;
580589
}
590+
591+
void vhPackUserGlobals(
592+
const std::vector< vhState::UniformBufferValue >& uniforms,
593+
const std::vector< vhReflectionMember >& members,
594+
uint8_t* outData,
595+
uint64_t dataSize
596+
)
597+
{
598+
if ( !outData || dataSize == 0 )
599+
return;
600+
601+
memset( outData, 0, dataSize );
602+
603+
for ( const auto& member : members )
604+
{
605+
const vhState::UniformBufferValue* match = nullptr;
606+
for ( const auto& u : uniforms )
607+
{
608+
if ( u.name == member.name )
609+
{
610+
match = &u;
611+
break;
612+
}
613+
}
614+
615+
if ( match )
616+
{
617+
if ( member.offset >= dataSize )
618+
continue;
619+
620+
uint64_t copySize = member.size;
621+
if ( member.offset + copySize > dataSize )
622+
{
623+
copySize = dataSize - member.offset;
624+
}
625+
626+
uint64_t srcSizeBytes = match->data.size() * sizeof( glm::vec4 );
627+
uint64_t actualCopy = std::min( copySize, srcSizeBytes );
628+
memcpy( outData + member.offset, match->data.data(), actualCopy );
629+
}
630+
}
631+
}

src/vrhi_utils.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626

2727
// -------------------------------------------------------- Utils --------------------------------------------------------
2828

29+
#define VRHI_ROUND_UP( x, alignment ) ( ( ( x ) + ( alignment ) - 1 ) & ~( ( alignment ) - 1 ) )
30+
2931
// Allocator for list of object IDs.
3032
// Works be using a free list.
3133
class vhAllocatorObjectFreeList
@@ -112,3 +114,5 @@ inline uint32_t vhNextPow2( uint32_t v )
112114
v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++;
113115
return v;
114116
}
117+
118+

test/test_buffer.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -759,3 +759,5 @@ UTEST_F( Buffer, SubAllocator )
759759
EXPECT_LE( available, 1024 * 1024 );
760760
EXPECT_EQ( used + available, 1024 * 1024 );
761761
}
762+
763+

0 commit comments

Comments
 (0)