17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-10-26 15:54:53 +01:00

fix(editor): a track dragged around no longer piles copies of its geometry up in the graphics memory

The geometry of a track made anew, ten times a second while it's
dragged, only forgot the chunks it had: the bank kept them all, so the
buffer of the section grew by the whole track and its neighbours each
time and was sent to the gpu in full again. Ten rebuilds of a test
scenery took the bank from 2 to 29 MB; a long session would run the
card out of memory. The old chunks are erased from the bank now, but
for those of a moving nose, laid again in place, and a moved traction
wire drops its old one too.

A chunk swapped for one without the extra vertex data kept the flag of
having it and the upload read from an empty array; the buffer is made
again when that changes.
This commit is contained in:
maj00r
2026-10-21 08:41:50 +02:00
parent 33892c1936
commit 8903d15b94
10 changed files with 55 additions and 1 deletions

View File

@@ -292,6 +292,7 @@ void move_traction(TTraction *Traction, std::array<glm::dvec3, 4> const &Points)
Traction->location(glm::mix(Points[1], Points[0], 0.5));
Traction->m_area.radius = -1.f;
simulation::Region->insert_and_register(Traction);
GfxRenderer->Erase(Traction->m_geometry);
Traction->m_geometry = gfx::geometry_handle{};
auto &section{simulation::Region->section(Traction->location())};
if (section.m_geometrycreated)

View File

@@ -318,6 +318,20 @@ geometry_bank::append( gfx::vertex_array &Vertices, userdata_array &Userdata, gf
return replace( Vertices, Userdata, Geometry, gfx::geometry_bank::chunk( Geometry ).vertices.size() );
}
void
geometry_bank::erase( gfx::geometry_handle const &Geometry ) {
if( ( Geometry.chunk == 0 ) || ( Geometry.chunk > m_chunks.size() ) ) { return; }
auto &chunk = gfx::geometry_bank::chunk( Geometry );
if( chunk.vertices.empty() && chunk.indices.empty() ) { return; }
gfx::vertex_array().swap( chunk.vertices );
gfx::index_array().swap( chunk.indices );
gfx::userdata_array().swap( chunk.userdata );
replace_( Geometry );
}
// draws geometry stored in specified chunk
std::size_t
geometry_bank::draw( gfx::geometry_handle const &Geometry, gfx::stream_units const &Units, unsigned int const Streams ) {
@@ -425,6 +439,14 @@ geometrybank_manager::append( gfx::vertex_array &Vertices, userdata_array &Userd
return bank( Geometry ).first->append( Vertices, Userdata, Geometry );
}
void
geometrybank_manager::erase( gfx::geometry_handle const &Geometry ) {
if( ( Geometry.bank == 0 ) || ( Geometry.bank > m_geometrybanks.size() ) ) { return; }
bank( Geometry ).first->erase( Geometry );
}
// draws geometry stored in specified chunk
void
geometrybank_manager::draw( gfx::geometry_handle const &Geometry, unsigned int const Streams ) {

View File

@@ -117,6 +117,7 @@ public:
auto replace( gfx::vertex_array &Vertices, gfx::userdata_array& Userdata, gfx::geometry_handle const &Geometry, std::size_t const Offset = 0 ) -> bool;
// adds supplied vertex data at the end of specified chunk
auto append( gfx::vertex_array &Vertices, gfx::userdata_array& Userdata, gfx::geometry_handle const &Geometry ) -> bool;
void erase( gfx::geometry_handle const &Geometry );
// draws geometry stored in specified chunk
auto draw( gfx::geometry_handle const &Geometry, gfx::stream_units const &Units, unsigned int const Streams = basic_streams ) -> std::size_t;
// draws geometry stored in specified chunk N times via glDrawElementsInstanced*
@@ -222,6 +223,7 @@ public:
auto replace( gfx::vertex_array &Vertices, gfx::userdata_array &Userdata, gfx::geometry_handle const &Geometry, std::size_t const Offset = 0 ) -> bool;
// adds supplied vertex data at the end of specified chunk
auto append( gfx::vertex_array &Vertices, gfx::userdata_array &Userdata, gfx::geometry_handle const &Geometry ) -> bool;
void erase( gfx::geometry_handle const &Geometry );
// draws geometry stored in specified chunk
void draw( gfx::geometry_handle const &Geometry, unsigned int const Streams = basic_streams );
// draws geometry stored in specified chunk InstanceCount times via GPU instancing.

View File

@@ -33,7 +33,8 @@ opengl33_vaogeometrybank::replace_( gfx::geometry_handle const &Geometry ) {
auto &chunkrecord = m_chunkrecords[ Geometry.chunk - 1 ];
chunkrecord.is_good = false;
// if the overall length of the chunk didn't change we can get away with reusing the old buffer...
if( geometry_bank::chunk( Geometry ).vertices.size() != chunkrecord.vertex_count ) {
if( ( geometry_bank::chunk( Geometry ).vertices.size() != chunkrecord.vertex_count )
|| ( geometry_bank::chunk( Geometry ).userdata.empty() == chunkrecord.has_userdata ) ) {
// ...but otherwise we'll need to allocate a new one
// TBD: we could keep and reuse the old buffer also if the new chunk is smaller than the old one,
// but it'd require some extra tracking and work to keep all chunks up to date; also wasting vram; may be not worth it?

View File

@@ -2217,6 +2217,11 @@ bool opengl33_renderer::Append(gfx::vertex_array &Vertices, gfx::userdata_array
return m_geometry.append(Vertices, Userdata, Geometry);
}
void opengl33_renderer::Erase(gfx::geometry_handle const &Geometry)
{
m_geometry.erase(Geometry);
}
// provides direct access to index data of specfied chunk
gfx::index_array const & opengl33_renderer::Indices(gfx::geometry_handle const &Geometry) const
{

View File

@@ -67,6 +67,7 @@ class opengl33_renderer : public gfx_renderer {
bool Replace(gfx::vertex_array &Vertices, gfx::userdata_array &Userdata, gfx::geometry_handle const &Geometry, int const Type, const std::size_t Offset = 0) override;
// adds supplied vertex data at the end of specified chunk
bool Append(gfx::vertex_array &Vertices, gfx::userdata_array &Userdata, gfx::geometry_handle const &Geometry, int const Type) override;
void Erase( gfx::geometry_handle const &Geometry ) override;
// provides direct access to index data of specfied chunk
gfx::index_array const &
Indices( gfx::geometry_handle const &Geometry ) const override;

View File

@@ -1767,6 +1767,11 @@ bool opengl_renderer::Append(gfx::vertex_array &Vertices, gfx::userdata_array &U
return m_geometry.append( Vertices, Userdata, Geometry );
}
void opengl_renderer::Erase( gfx::geometry_handle const &Geometry )
{
m_geometry.erase( Geometry );
}
// provides direct access to vertex data of specfied chunk
gfx::index_array const &
opengl_renderer::Indices( gfx::geometry_handle const &Geometry ) const {

View File

@@ -65,6 +65,7 @@ public:
bool Replace(gfx::vertex_array &Vertices, gfx::userdata_array &Userdata, gfx::geometry_handle const &Geometry, int const Type, const std::size_t Offset = 0) override;
// adds supplied vertex data at the end of specified chunk
bool Append(gfx::vertex_array &Vertices, gfx::userdata_array &Userdata, gfx::geometry_handle const &Geometry, int const Type) override;
void Erase( gfx::geometry_handle const &Geometry ) override;
// provides direct access to index data of specfied chunk
gfx::index_array const &
Indices( gfx::geometry_handle const &Geometry ) const override;

View File

@@ -59,6 +59,7 @@ public:
virtual auto Replace(gfx::vertex_array &Vertices, gfx::userdata_array &Userdata, gfx::geometry_handle const &Geometry, int const Type, const std::size_t Offset = 0) -> bool = 0;
// adds supplied vertex data at the end of specified chunk
virtual auto Append(gfx::vertex_array &Vertices, gfx::userdata_array &Userdata, gfx::geometry_handle const &Geometry, int const Type) -> bool = 0;
virtual void Erase( gfx::geometry_handle const &Geometry ) {}
// provides direct access to index data of specfied chunk
virtual auto Indices( gfx::geometry_handle const &Geometry ) const->gfx::index_array const & = 0;
// provides direct access to vertex data of specfied chunk

View File

@@ -1471,12 +1471,27 @@ glm::vec3 TTrack::get_nearest_point(const glm::dvec3 &point) const
void TTrack::rebuild_geometry( gfx::geometrybank_handle const &Bank ) {
track_rails::forget();
auto const erase = [ this ]( gfx::geometry_handle const &Chunk ) {
if( SwitchExtension
&& std::any_of( SwitchExtension->m_nosechunks.begin(), SwitchExtension->m_nosechunks.end(), [ & ]( auto const &Pooled ) { return Pooled.handle == Chunk; } ) ) {
return;
}
GfxRenderer->Erase( Chunk );
};
for( auto const *geometry : { &Geometry1, &Geometry2, &GeometryCut1, &GeometryCut2 } ) {
std::for_each( geometry->begin(), geometry->end(), erase );
}
for( auto const &tread : GeometryTreads ) {
std::for_each( tread.geometry.begin(), tread.geometry.end(), erase );
std::for_each( tread.cuts.begin(), tread.cuts.end(), erase );
}
Geometry1.clear();
Geometry2.clear();
GeometryCut1.clear();
GeometryCut2.clear();
GeometryTreads.clear();
if( SwitchExtension ) {
erase( SwitchExtension->Geometry3 );
SwitchExtension->Geometry3 = gfx::geometry_handle{};
}
m_sleeper_local_transforms.clear();