@@ -34,7 +34,7 @@ std::unordered_map< uint64_t, const vhVertexLayoutDef* > vhCmdBackendState::s_la
3434std::vector< nvrhi::VertexAttributeDesc > vhCmdBackendState::s_attributes;
3535
3636// --------------------------------------------------------------------------
37- // Implementation
37+ // Backend :: Utils & Helpers
3838// --------------------------------------------------------------------------
3939
4040static const char * vhResourceTypeToString ( nvrhi::ResourceType type )
@@ -91,6 +91,42 @@ bool vhCmdBackendState::BE_Util_ShaderStageMatches( uint64_t flags, bool useComp
9191 return false ;
9292}
9393
94+ int64_t vhCmdBackendState::BE_Util_WriteGlobalUniform ( const vhState& state, vhBackendTransientBuffer& tbuf, uint64_t & lastHash )
95+ {
96+ vhGlobalUniform u;
97+ vhWriteStateToGlobalUniform ( state, u );
98+ uint64_t hash = vhHashGlobalUniform ( u );
99+
100+ if ( hash == lastHash && tbuf.offset >= sizeof ( vhGlobalUniform ) )
101+ return tbuf.offset - sizeof ( vhGlobalUniform );
102+
103+ if ( ( tbuf.offset % VRHI_CBUF_ALIGN ) != 0 )
104+ return -1 ;
105+
106+ int64_t offset = tbuf.Alloc ( sizeof ( vhGlobalUniform ) );
107+ if ( offset < 0 )
108+ return -1 ;
109+
110+ {
111+ std::lock_guard<std::mutex> lock ( g_nvRHIStateMutex );
112+ uint8_t * ptr = tbuf.Map_DeviceStateLocked ();
113+ if ( !ptr )
114+ {
115+ VRHI_ERR (" BE_Util_WriteGlobalUniform: Failed to map global uniform buffer!\n " );
116+ return -1 ;
117+ }
118+ memcpy ( ptr + offset, &u, sizeof ( u ) );
119+ // Unmap is deferred until Frame/Flush boundary
120+ }
121+
122+ lastHash = hash;
123+ return offset;
124+ }
125+
126+ // --------------------------------------------------------------------------
127+ // Backend :: Complex BE Low Level NVRHI Device Functions
128+ // --------------------------------------------------------------------------
129+
94130void vhCmdBackendState::BE_UpdateTexture ( vhBackendTexture& btex, const vhMem* data, glm::ivec4 arrayMipUpdateRange )
95131{
96132 if ( !btex.handle || !data || !data->size () ) return ;
@@ -637,6 +673,47 @@ bool vhCmdBackendState::BE_PreSubmitCommon_FindResource(
637673
638674 switch ( item.type )
639675 {
676+ case nvrhi::ResourceType::ConstantBuffer:
677+ case nvrhi::ResourceType::VolatileConstantBuffer:
678+ {
679+ if ( item.slot == 0 )
680+ {
681+ // TODO: Implement global uniform buffer binding.
682+ return false ;
683+ }
684+
685+ auto it = stageTable.bufferTable .find ( item.slot );
686+ if ( it == stageTable.bufferTable .end () )
687+ {
688+ if ( state.debugFlags & VRHI_STATE_DEBUG_LOG_BINDING_MISMATCH ) VRHI_ERR ( " FindResource: ConstantBuffer not found in cache at slot %d\n " , item.slot );
689+ return false ;
690+ }
691+ const auto result = &it->second ;
692+ assert ( result );
693+ if ( !result->handle )
694+ {
695+ if ( state.debugFlags & VRHI_STATE_DEBUG_LOG_BINDING_MISMATCH ) VRHI_ERR ( " FindResource: ConstantBuffer found in cache at slot %d but null handle.\n " , item.slot );
696+ return false ;
697+ }
698+ if ( !result->handle ->getDesc ().isConstantBuffer )
699+ {
700+ if ( state.debugFlags & VRHI_STATE_DEBUG_LOG_BINDING_MISMATCH ) VRHI_ERR ( " FindResource: ConstantBuffer found in cache at slot %d but NOT a ConstantBuffer.\n " , item.slot );
701+ return false ;
702+ }
703+
704+ uint64_t size = result->binding ->byteSize ? result->binding ->byteSize : result->handle ->getDesc ().byteSize ;
705+ nvrhi::BufferRange range ( result->binding ->byteOffset , size );
706+ outItem = nvrhi::BindingSetItem::ConstantBuffer ( item.slot , result->handle , range );
707+ if ( result->handle ->getDesc ().isVolatile && item.type != nvrhi::ResourceType::VolatileConstantBuffer )
708+ {
709+ if ( state.debugFlags & VRHI_STATE_DEBUG_LOG_BINDING_MISMATCH ) VRHI_ERR ( " FindResource: Volatile Buffer bound to Static ConstantBuffer slot %d. This may be unsafe!\n " , item.slot );
710+ return false ;
711+ }
712+ outItem.type = item.type ;
713+ if ( state.debugFlags & VRHI_STATE_DEBUG_LOG_ALL_BINDINGS ) VRHI_LOG ( " FindResource: ConstantBuffer found in cache at slot %d\n " , item.slot );
714+ return true ;
715+ }
716+
640717 case nvrhi::ResourceType::Texture_SRV:
641718 case nvrhi::ResourceType::Texture_UAV:
642719 {
@@ -1029,29 +1106,17 @@ void vhCmdBackendState::init()
10291106{
10301107 std::lock_guard< std::mutex > lock ( backendMutex );
10311108
1032- if ( !m_globalUniformBuffer )
1109+ if ( !m_globalUniformBuffer. handle [ 0 ] )
10331110 {
10341111 // Called from vhInit which already holds g_nvRHIStateMutex lock, and before RHI thread even starts.
10351112 // So we don't need to lock g_nvRHIStateMutex here.
1036-
1113+
10371114 nvrhi::BufferDesc desc;
1038- desc.setByteSize ( sizeof ( vhGlobalUniform ) );
1115+ desc.setByteSize ( 16 * 1024 * sizeof ( vhGlobalUniform ) ); // 16MB
10391116 desc.setIsConstantBuffer ( true );
1117+ desc.setCpuAccess ( nvrhi::CpuAccessMode::Write );
10401118 desc.setDebugName ( " GlobalUniforms" );
1041- nvrhi::BufferHandle bhandle = g_vhDevice->createBuffer ( desc );
1042- if ( !bhandle )
1043- {
1044- VRHI_ERR ( " vhCmdBackendState::init() : Failed to create Global Uniform Buffer!\n " );
1045- assert ( !" Failed to create Global Uniform Buffer." );
1046- return ;
1047- }
1048-
1049- m_globalUniformBuffer = std::make_unique< vhBackendBuffer >();
1050- m_globalUniformBuffer->handle = bhandle;
1051- m_globalUniformBuffer->name = " GlobalUniforms" ;
1052- m_globalUniformBuffer->desc = desc;
1053- m_globalUniformBuffer->stride = sizeof ( vhGlobalUniform );
1054- m_globalUniformBuffer->flags = VRHI_BUFFER_NONE ;
1119+ m_globalUniformBuffer.Init_DeviceStateLocked ( desc );
10551120 }
10561121}
10571122
@@ -1060,7 +1125,7 @@ void vhCmdBackendState::shutdown()
10601125 std::lock_guard< std::mutex > lock ( backendMutex );
10611126 std::lock_guard< std::mutex > lock2 ( g_nvRHIStateMutex );
10621127
1063- m_globalUniformBuffer.reset ();
1128+ m_globalUniformBuffer.Shutdown_DeviceStateLocked ();
10641129
10651130 backendTextures.clear ();
10661131 backendBuffers.clear ();
@@ -1821,17 +1886,22 @@ void vhCmdBackendState::Handle_vhCmdSetStateAttachments( VIDL_vhCmdSetStateAttac
18211886void vhCmdBackendState::Handle_vhFlushInternal ( VIDL_vhFlushInternal* cmd )
18221887{
18231888 BE_CmdRAII cmdRAII ( cmd );
1889+
1890+ // TODO: Flush all transient buffer maps here.
1891+ {
1892+ std::lock_guard<std::mutex> lock ( g_nvRHIStateMutex );
1893+ m_globalUniformBuffer.Unmap_DeviceStateLocked ();
1894+ }
1895+
1896+
18241897 // Free all cmd memory allocations, because hitting this flush means all previous commands have been processed.
18251898 {
18261899 std::lock_guard<std::mutex> lock ( g_vhMemListMutex );
18271900 g_vhMemList.clear ();
18281901 }
18291902
1830- if ( cmd->waitForGPU )
1831- {
1832- // This uses g_nvRHIStateMutex then gives it up, we need to avoid double-locking.
1833- vhCmdListFlushAll ();
1834- }
1903+ // This uses g_nvRHIStateMutex then gives it up, we need to avoid double-locking.
1904+ vhCmdListFlushAll ();
18351905
18361906 {
18371907 std::lock_guard< std::mutex > lock ( g_nvRHIStateMutex );
@@ -1840,6 +1910,8 @@ void vhCmdBackendState::Handle_vhFlushInternal( VIDL_vhFlushInternal* cmd )
18401910 g_vhDevice->waitForIdle ();
18411911 }
18421912 g_vhDevice->runGarbageCollection ();
1913+ m_globalUniformBuffer.Step ();
1914+ m_globalUniformBufferLastHash = 0 ;
18431915 }
18441916
18451917 // Notify caller that we're done.
0 commit comments