@ -1,4 +1,4 @@
/ / SPDX - FileCopyrightText : Copyright 2025 Eden Emulator Project
/ / SPDX - FileCopyrightText : Copyright 2026 Eden Emulator Project
/ / SPDX - License - Identifier : GPL - 3.0 - or - later
/ / SPDX - License - Identifier : GPL - 3.0 - or - later
/ / SPDX - FileCopyrightText : Copyright 2022 yuzu Emulator Project
/ / SPDX - FileCopyrightText : Copyright 2022 yuzu Emulator Project
@ -382,6 +382,10 @@ void BufferCache<P>::BindHostComputeBuffers() {
BindHostComputeUniformBuffers ( ) ;
BindHostComputeUniformBuffers ( ) ;
BindHostComputeStorageBuffers ( ) ;
BindHostComputeStorageBuffers ( ) ;
BindHostComputeTextureBuffers ( ) ;
BindHostComputeTextureBuffers ( ) ;
if ( any_buffer_uploaded ) {
runtime . PostCopyBarrier ( ) ;
any_buffer_uploaded = false ;
}
}
}
template < class P >
template < class P >
@ -763,45 +767,85 @@ void BufferCache<P>::BindHostIndexBuffer() {
}
}
}
}
template < class P >
void BufferCache < P > : : BindHostVertexBuffer ( u32 index , Buffer & buffer , u32 offset , u32 size ,
u32 stride ) {
if constexpr ( IS_OPENGL ) {
runtime . BindVertexBuffer ( index , buffer , offset , size , stride ) ;
} else {
runtime . BindVertexBuffer ( index , buffer . Handle ( ) , offset , size , stride ) ;
}
}
template < class P >
Binding & BufferCache < P > : : VertexBufferSlot ( u32 index ) {
ASSERT ( index < NUM_VERTEX_BUFFERS ) ;
return v_buffer [ index ] ;
}
template < class P >
const Binding & BufferCache < P > : : VertexBufferSlot ( u32 index ) const {
ASSERT ( index < NUM_VERTEX_BUFFERS ) ;
return v_buffer [ index ] ;
}
template < class P >
void BufferCache < P > : : UpdateVertexBufferSlot ( u32 index , const Binding & binding ) {
Binding & slot = VertexBufferSlot ( index ) ;
if ( slot . device_addr ! = binding . device_addr | | slot . size ! = binding . size ) {
+ + vertex_buffers_serial ;
}
slot = binding ;
if ( binding . buffer_id ! = NULL_BUFFER_ID & & binding . size ! = 0 ) {
enabled_vertex_buffers_mask | = ( 1u < < index ) ;
} else {
enabled_vertex_buffers_mask & = ~ ( 1u < < index ) ;
}
}
template < class P >
template < class P >
void BufferCache < P > : : BindHostVertexBuffers ( ) {
void BufferCache < P > : : BindHostVertexBuffers ( ) {
HostBindings < typename P : : Buffer > host_bindings ;
bool any_valid { false } ;
auto & flags = maxwell3d - > dirty . flags ;
auto & flags = maxwell3d - > dirty . flags ;
for ( u32 index = 0 ; index < NUM_VERTEX_BUFFERS ; + + index ) {
const Binding & binding = channel_state - > vertex_buffers [ index ] ;
u32 enabled_mask = enabled_vertex_buffers_mask ;
HostBindings < Buffer > bindings { } ;
u32 last_index = std : : numeric_limits < u32 > : : max ( ) ;
const auto flush_bindings = [ & ] ( ) {
if ( bindings . buffers . empty ( ) ) {
return ;
}
bindings . max_index = bindings . min_index + static_cast < u32 > ( bindings . buffers . size ( ) ) ;
runtime . BindVertexBuffers ( bindings ) ;
bindings = HostBindings < Buffer > { } ;
last_index = std : : numeric_limits < u32 > : : max ( ) ;
} ;
while ( enabled_mask ! = 0 ) {
const u32 index = std : : countr_zero ( enabled_mask ) ;
enabled_mask & = ( enabled_mask - 1 ) ;
const Binding & binding = VertexBufferSlot ( index ) ;
Buffer & buffer = slot_buffers [ binding . buffer_id ] ;
Buffer & buffer = slot_buffers [ binding . buffer_id ] ;
TouchBuffer ( buffer , binding . buffer_id ) ;
TouchBuffer ( buffer , binding . buffer_id ) ;
SynchronizeBuffer ( buffer , binding . device_addr , binding . size ) ;
SynchronizeBuffer ( buffer , binding . device_addr , binding . size ) ;
if ( ! flags [ Dirty : : VertexBuffer0 + index ] ) {
if ( ! flags [ Dirty : : VertexBuffer0 + index ] ) {
flush_bindings ( ) ;
continue ;
continue ;
}
}
flags [ Dirty : : VertexBuffer0 + index ] = false ;
flags [ Dirty : : VertexBuffer0 + index ] = false ;
host_bindings . min_index = ( std : : min ) ( host_bindings . min_index , index ) ;
host_bindings . max_index = ( std : : max ) ( host_bindings . max_index , index ) ;
any_valid = true ;
}
if ( any_valid ) {
host_bindings . max_index + + ;
for ( u32 index = host_bindings . min_index ; index < host_bindings . max_index ; index + + ) {
flags [ Dirty : : VertexBuffer0 + index ] = false ;
const Binding & binding = channel_state - > vertex_buffers [ index ] ;
Buffer & buffer = slot_buffers [ binding . buffer_id ] ;
const u32 stride = maxwell3d - > regs . vertex_streams [ index ] . stride ;
const u32 offset = buffer . Offset ( binding . device_addr ) ;
buffer . MarkUsage ( offset , binding . size ) ;
host_bindings . buffers . push_back ( & buffer ) ;
host_bindings . offsets . push_back ( offset ) ;
host_bindings . sizes . push_back ( binding . size ) ;
host_bindings . strides . push_back ( stride ) ;
const u32 stride = maxwell3d - > regs . vertex_streams [ index ] . stride ;
const u32 offset = buffer . Offset ( binding . device_addr ) ;
buffer . MarkUsage ( offset , binding . size ) ;
if ( ! bindings . buffers . empty ( ) & & index ! = last_index + 1 ) {
flush_bindings ( ) ;
}
}
runtime . BindVertexBuffers ( host_bindings ) ;
if ( bindings . buffers . empty ( ) ) {
bindings . min_index = index ;
}
bindings . buffers . push_back ( & buffer ) ;
bindings . offsets . push_back ( offset ) ;
bindings . sizes . push_back ( binding . size ) ;
bindings . strides . push_back ( stride ) ;
last_index = index ;
}
}
flush_bindings ( ) ;
}
}
template < class P >
template < class P >
@ -1205,17 +1249,20 @@ void BufferCache<P>::UpdateVertexBuffer(u32 index) {
u32 size = address_size ; / / TODO : Analyze stride and number of vertices
u32 size = address_size ; / / TODO : Analyze stride and number of vertices
if ( array . enable = = 0 | | size = = 0 | | ! device_addr ) {
if ( array . enable = = 0 | | size = = 0 | | ! device_addr ) {
channel_state - > vertex_buffers [ index ] = NULL_BINDING ;
channel_state - > vertex_buffers [ index ] = NULL_BINDING ;
UpdateVertexBufferSlot ( index , NULL_BINDING ) ;
return ;
return ;
}
}
if ( ! gpu_memory - > IsWithinGPUAddressRange ( gpu_addr_end ) | | size > = 64 _MiB ) {
if ( ! gpu_memory - > IsWithinGPUAddressRange ( gpu_addr_end ) | | size > = 64 _MiB ) {
size = static_cast < u32 > ( gpu_memory - > MaxContinuousRange ( gpu_addr_begin , size ) ) ;
size = static_cast < u32 > ( gpu_memory - > MaxContinuousRange ( gpu_addr_begin , size ) ) ;
}
}
const BufferId buffer_id = FindBuffer ( * device_addr , size ) ;
const BufferId buffer_id = FindBuffer ( * device_addr , size ) ;
channel_state - > vertex_buffers [ index ] = B inding{
const Binding b inding{
. device_addr = * device_addr ,
. device_addr = * device_addr ,
. size = size ,
. size = size ,
. buffer_id = buffer_id ,
. buffer_id = buffer_id ,
} ;
} ;
channel_state - > vertex_buffers [ index ] = binding ;
UpdateVertexBufferSlot ( index , binding ) ;
}
}
template < class P >
template < class P >
@ -1528,12 +1575,12 @@ void BufferCache<P>::TouchBuffer(Buffer& buffer, BufferId buffer_id) noexcept {
template < class P >
template < class P >
bool BufferCache < P > : : SynchronizeBuffer ( Buffer & buffer , DAddr device_addr , u32 size ) {
bool BufferCache < P > : : SynchronizeBuffer ( Buffer & buffer , DAddr device_addr , u32 size ) {
boost : : container : : small_vector < BufferCopy , 4 > copies ;
upload_copies . clear ( ) ;
u64 total_size_bytes = 0 ;
u64 total_size_bytes = 0 ;
u64 largest_copy = 0 ;
u64 largest_copy = 0 ;
DAddr buffer_start = buffer . CpuAddr ( ) ;
const DAddr buffer_start = buffer . cpu_addr_cached ;
memory_tracker . ForEachUploadRange ( device_addr , size , [ & ] ( u64 device_addr_out , u64 range_size ) {
memory_tracker . ForEachUploadRange ( device_addr , size , [ & ] ( u64 device_addr_out , u64 range_size ) {
copies . push_back ( BufferCopy {
upload_ copies. push_back ( BufferCopy {
. src_offset = total_size_bytes ,
. src_offset = total_size_bytes ,
. dst_offset = device_addr_out - buffer_start ,
. dst_offset = device_addr_out - buffer_start ,
. size = range_size ,
. size = range_size ,
@ -1544,8 +1591,9 @@ bool BufferCache<P>::SynchronizeBuffer(Buffer& buffer, DAddr device_addr, u32 si
if ( total_size_bytes = = 0 ) {
if ( total_size_bytes = = 0 ) {
return true ;
return true ;
}
}
const std : : span < BufferCopy > copies_span ( copies . data ( ) , copies . size ( ) ) ;
const std : : span < BufferCopy > copies_span ( upload_ copies. data ( ) , upload_ copies. size ( ) ) ;
UploadMemory ( buffer , total_size_bytes , largest_copy , copies_span ) ;
UploadMemory ( buffer , total_size_bytes , largest_copy , copies_span ) ;
any_buffer_uploaded = true ;
return false ;
return false ;
}
}
@ -1735,6 +1783,7 @@ void BufferCache<P>::DeleteBuffer(BufferId buffer_id, bool do_not_mark) {
auto & binding = channel_state - > vertex_buffers [ index ] ;
auto & binding = channel_state - > vertex_buffers [ index ] ;
if ( binding . buffer_id = = buffer_id ) {
if ( binding . buffer_id = = buffer_id ) {
binding . buffer_id = BufferId { } ;
binding . buffer_id = BufferId { } ;
UpdateVertexBufferSlot ( index , binding ) ;
dirty_vertex_buffers . push_back ( index ) ;
dirty_vertex_buffers . push_back ( index ) ;
}
}
}
}