From 69980b55405dadf38db19b8b54c105f31989e9be Mon Sep 17 00:00:00 2001 From: maj00r Date: Sat, 24 Oct 2026 19:23:01 +0200 Subject: [PATCH] perf(editor): the top view draws the terrain lighter: the cells of its grid some 16 pixels across, not 10, the chunks streamed only as far as the screen reaches, not the range of the 3D view, and the cube map of the reflections not made anew while it's shown, nothing in it reflecting On test2 at an extent of 300 m: 55 chunks in place of 106, 204 thousand triangles of the terrain in place of 895 thousand (all drawn 0.82 million in place of 2.34), the GPU 1.46 ms a frame in place of 2.33, and 3.6 ms of the CPU less a frame for the reflections. The 3D view stays as it was; the range of 50 km of the tracks work area in 3D cost nothing measurable on l053. Selftest perf logs the chunks of the terrain, their triangles and the steps of their grids. --- application/editormodeselftestscene.cpp | 1 + editor/editorTerrainStreamer.cpp | 27 ++++++++++++++++++++++--- editor/editorTerrainStreamer.hpp | 3 +++ rendering/opengl33renderer.cpp | 2 ++ rendering/openglrenderer.cpp | 2 ++ 5 files changed, 32 insertions(+), 3 deletions(-) diff --git a/application/editormodeselftestscene.cpp b/application/editormodeselftestscene.cpp index 771575bf..48b16c52 100644 --- a/application/editormodeselftestscene.cpp +++ b/application/editormodeselftestscene.cpp @@ -165,6 +165,7 @@ editor_mode::selftest_result editor_mode::selftest_scene(std::string const &comm auto const frames{editor_selftest::frames() - lastframe}; auto const elapsed{std::chrono::duration(now - last).count()}; WriteLog(format("SELFTEST perf %s: %zu frames, %.3f ms per frame, the longest %.1f ms, %zu over 33 ms | %s | %s", label.c_str(), frames, frames > 0 ? elapsed / frames : 0.0, editor_selftest::frame_longest(), editor_selftest::frames_slow(), editor_selftest::one_line(GfxRenderer->info_times()).c_str(), editor_selftest::one_line(GfxRenderer->info_stats()).c_str())); + WriteLog("SELFTEST perf " + label + " " + m_streamer.stats()); last = now; lastframe = editor_selftest::frames(); editor_selftest::frame_longest() = 0.0; diff --git a/editor/editorTerrainStreamer.cpp b/editor/editorTerrainStreamer.cpp index feec0a1a..151aab8d 100644 --- a/editor/editorTerrainStreamer.cpp +++ b/editor/editorTerrainStreamer.cpp @@ -34,7 +34,8 @@ double constexpr upload_budget{0.004}; // seconds of a frame for taking over fin int constexpr materials_per_frame{6}; double constexpr look_ahead{8.0}; // seconds; chunks are loaded around where the camera will be by then double constexpr look_ahead_limit{2000.0}; // metres -double constexpr pixel_distance{1300.0}; // m; a pixel of the top view is as big as one of the 3D view this far away +double constexpr pixel_distance{1920.0}; // m; a pixel of the top view is as big as one of the 3D view this far away: the cells + // of the grid some 16 pixels across at the usual detail, the relief a little coarser than the imagery over it int constexpr top_radius{200}; // chunks the top view of the tracks loads around its centre at most double constexpr settled_walk{1.0}; // seconds; the chunks around the camera are looked over this often when nothing is coming double constexpr region_half{scene::EU07_REGIONSIDESECTIONCOUNT * scene::EU07_SECTIONSIZE * 0.5 - heightmap::chunk_size}; @@ -603,8 +604,9 @@ void terrain_streamer::update(glm::dvec3 const &Camera) auto const reach{top ? Global.EditorOrthoExtent * std::sqrt(1.0 + aspect * aspect) : 0.0}; m_pixel = top ? 2.0 * Global.EditorOrthoExtent / std::max(1, Global.window_size.y) : 0.0; - // chunks wanted around the camera and around where it's heading - auto const range{std::max({m_radius * heightmap::chunk_size, static_cast(Global.BaseDrawRange) * std::max(1.0, static_cast(Global.fDistanceFactor)), reach}) + heightmap::chunk_size * 0.5}; + // chunks wanted around the camera and around where it's heading; the top view only as far as the screen reaches, not the + // range of the 3D view: zoomed in it would keep making anew the meshes of chunks far off the screen at each step of the zoom + auto const range{(top ? std::max(m_radius * heightmap::chunk_size, reach) : std::max({m_radius * heightmap::chunk_size, static_cast(Global.BaseDrawRange) * std::max(1.0, static_cast(Global.fDistanceFactor)), reach})) + heightmap::chunk_size * 0.5}; auto const radius{std::min(top ? top_radius : 64, static_cast(std::ceil(range / heightmap::chunk_size)))}; if (m_ringradius < radius) { @@ -773,6 +775,25 @@ void terrain_streamer::upload_shape_material(editor_terrain &Chunk) // queries +std::string terrain_streamer::stats() const +{ + std::size_t drawn{0}, triangles{0}; + std::map strides; + for (auto const &entry : m_chunks) + { + auto const &chunk{*entry.second}; + if (chunk.m_section == nullptr) + continue; + ++drawn; + triangles += chunk.m_triangles; + ++strides[chunk.m_stride]; + } + auto text{"terrain: " + std::to_string(m_chunks.size()) + " chunks, " + std::to_string(drawn) + " in the scene, " + std::to_string(triangles) + " triangles; strides"}; + for (auto const &[stride, count] : strides) + text += " " + std::to_string(stride) + ":" + std::to_string(count); + return text; +} + void terrain_streamer::collect(std::vector &Out) const { for (auto const &entry : m_chunks) diff --git a/editor/editorTerrainStreamer.hpp b/editor/editorTerrainStreamer.hpp index c5c5d381..b2df12e6 100644 --- a/editor/editorTerrainStreamer.hpp +++ b/editor/editorTerrainStreamer.hpp @@ -74,6 +74,9 @@ class terrain_streamer // true if the geometry belongs to the terrain (or its water) bool owns(gfx::geometry_handle const &Geometry) const; std::size_t resident() const { return m_chunks.size(); } + // the chunks in memory, those in the scene, their triangles and how many of them have each step of the grid, for the + // measurements of the editor + std::string stats() const; // chunks in the pack files and in memory, less the removed ones; the files known so far bool exists(chunk_key const &Key) const; diff --git a/rendering/opengl33renderer.cpp b/rendering/opengl33renderer.cpp index 3d6a3004..1de01345 100644 --- a/rendering/opengl33renderer.cpp +++ b/rendering/opengl33renderer.cpp @@ -1458,6 +1458,8 @@ bool opengl33_renderer::Render_coupler_adapter( TDynamicObject *Dynamic, float c bool opengl33_renderer::Render_reflections(viewport_config &vp) { if( Global.reflectiontune.update_interval == 0 ) { return false; } + // the top view of the editor shows nothing the reflections would be seen on: the cube map stays as it was + if( EditorModeFlag && Global.EditorOrtho ) { return false; } if( m_environmentupdateface >= 6 ) { // no update in progress, check whether it's time for another one diff --git a/rendering/openglrenderer.cpp b/rendering/openglrenderer.cpp index 3ce07491..52b79a28 100644 --- a/rendering/openglrenderer.cpp +++ b/rendering/openglrenderer.cpp @@ -937,6 +937,8 @@ bool opengl_renderer::Render_reflections() { if( Global.reflectiontune.update_interval == 0 ) { return false; } + // the top view of the editor shows nothing the reflections would be seen on: the cube map stays as it was + if( EditorModeFlag && Global.EditorOrtho ) { return false; } auto const timestamp { Timer::GetRenderTime() }; if( ( timestamp - m_environmentupdatetime < Global.reflectiontune.update_interval )