17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-10-17 03:59:19 +02:00

perf(reflections): environment map drawn one face per frame from the place the update began at, the first update in one go; cells beyond the range of reflected instances left out; time of the reflection pass in the renderer statistics; tracks skipped in shadow passes no longer counted as drawn

This commit is contained in:
2026-10-07 16:17:13 +02:00
parent 7b15b9a017
commit bc99b80191
2 changed files with 46 additions and 13 deletions

View File

@@ -635,12 +635,16 @@ void opengl33_renderer::SwapBuffers()
m_debugtimestext.clear(); m_debugtimestext.clear();
m_debugtimestext = m_debugtimestext =
"cpu frame total: " + to_string( Timer::subsystem.gfx_color.average() + Timer::subsystem.gfx_shadows.average() + Timer::subsystem.gfx_swap.average(), 2 ) + " ms\n" "cpu frame total: " + to_string( Timer::subsystem.gfx_color.average() + Timer::subsystem.gfx_shadows.average() + ( Global.gfx_envmap_enabled ? Timer::subsystem.gfx_reflections.average() : 0.f ) + Timer::subsystem.gfx_swap.average(), 2 ) + " ms\n"
+ " color: " + to_string( Timer::subsystem.gfx_color.average(), 2 ) + " ms (" + std::to_string( m_cellqueue.size() ) + " sectors)\n"; + " color: " + to_string( Timer::subsystem.gfx_color.average(), 2 ) + " ms (" + std::to_string( m_cellqueue.size() ) + " sectors)\n";
if( Global.gfx_shadowmap_enabled ) { if( Global.gfx_shadowmap_enabled ) {
m_debugtimestext += m_debugtimestext +=
" shadows: " + to_string( Timer::subsystem.gfx_shadows.average(), 2 ) + " ms\n"; " shadows: " + to_string( Timer::subsystem.gfx_shadows.average(), 2 ) + " ms\n";
} }
if( Global.gfx_envmap_enabled ) {
m_debugtimestext +=
" reflections: " + to_string( Timer::subsystem.gfx_reflections.average(), 2 ) + " ms\n";
}
m_debugtimestext += " swap: " + to_string( Timer::subsystem.gfx_swap.average(), 2 ) + " ms\n"; m_debugtimestext += " swap: " + to_string( Timer::subsystem.gfx_swap.average(), 2 ) + " ms\n";
if( !Global.gfx_usegles ) { if( !Global.gfx_usegles ) {
if (m_gllasttime) if (m_gllasttime)
@@ -825,8 +829,10 @@ void opengl33_renderer::Render_pass(viewport_config &vp, rendermode const Mode)
{ {
// potentially update environmental cube map // potentially update environmental cube map
m_renderpass.draw_stats = {}; m_renderpass.draw_stats = {};
Timer::subsystem.gfx_reflections.start();
if (Render_reflections(vp)) if (Render_reflections(vp))
m_renderpass = m_colorpass; // restore color pass settings m_renderpass = m_colorpass; // restore color pass settings
Timer::subsystem.gfx_reflections.stop();
setup_env_map(m_env_tex.get()); setup_env_map(m_env_tex.get());
} }
@@ -1385,23 +1391,36 @@ bool opengl33_renderer::Render_reflections(viewport_config &vp)
{ {
if( Global.reflectiontune.update_interval == 0 ) { return false; } if( Global.reflectiontune.update_interval == 0 ) { return false; }
auto const timestamp{ Timer::GetRenderTime() }; if( m_environmentupdateface >= 6 ) {
if( ( timestamp - m_environmentupdatetime < Global.reflectiontune.update_interval ) // no update in progress, check whether it's time for another one
&& ( glm::length2( m_renderpass.pass_camera.position() - m_environmentupdatelocation ) < sq(1000.0)) ) // length2 is better than length for comparing because it does not require sqrt function auto const timestamp{ Timer::GetRenderTime() };
{ if( ( timestamp - m_environmentupdatetime < Global.reflectiontune.update_interval )
// run update every 5+ mins of simulation time, or at least 1km from the last location && ( glm::length2( m_renderpass.pass_camera.position() - m_environmentupdatelocation ) < sq(1000.0)) ) // length2 is better than length for comparing because it does not require sqrt function
return false; {
// run update every 5+ mins of simulation time, or at least 1km from the last location
return false;
}
m_environmentupdatetime = timestamp;
m_environmentupdatelocation = m_renderpass.pass_camera.position();
m_environmentupdateface = 0;
} }
m_environmentupdatetime = timestamp; // an update draws the scene six times, which is too much for a single frame. its cost is spread
m_environmentupdatelocation = m_renderpass.pass_camera.position(); // by drawing one face of the map per frame, all of them as seen from the place the update began at.
// the first update is done in one go, as there's nothing to show in the meantime
auto const lastface{ m_environmentready ? m_environmentupdateface : 5 };
glViewport(0, 0, gl::ENVMAP_SIZE, gl::ENVMAP_SIZE); glViewport(0, 0, gl::ENVMAP_SIZE, gl::ENVMAP_SIZE);
for (m_environmentcubetextureface = 0; m_environmentcubetextureface < 6; ++m_environmentcubetextureface) for (; m_environmentupdateface <= lastface; ++m_environmentupdateface)
{ {
m_environmentcubetextureface = m_environmentupdateface;
m_env_fb->attach(*m_env_tex, m_environmentcubetextureface, GL_COLOR_ATTACHMENT0); m_env_fb->attach(*m_env_tex, m_environmentcubetextureface, GL_COLOR_ATTACHMENT0);
if (m_env_fb->is_complete()) if (m_env_fb->is_complete())
Render_pass(vp, rendermode::reflections); Render_pass(vp, rendermode::reflections);
} }
m_env_tex->generate_mipmaps(); if (m_environmentupdateface >= 6)
{
m_env_tex->generate_mipmaps();
m_environmentready = true;
}
m_env_fb->detach(GL_COLOR_ATTACHMENT0); m_env_fb->detach(GL_COLOR_ATTACHMENT0);
return true; return true;
@@ -1712,7 +1731,9 @@ void opengl33_renderer::setup_pass(viewport_config &Viewport, renderpass_config
case rendermode::reflections: case rendermode::reflections:
{ {
// modelview // modelview
camera.position() = (((true == DebugCameraFlag) && (false == Ignoredebug)) ? Global.pDebugCamera.Pos : Global.pCamera.Pos); // the faces of the map are drawn over a few frames. each is drawn from the place the camera was at
// when the update began, so they fit together along the edges when the camera moves in the meantime
camera.position() = m_environmentupdatelocation;
glm::dvec3 const cubefacetargetvectors[6] = {{1.0, 0.0, 0.0}, {-1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, -1.0, 0.0}, {0.0, 0.0, 1.0}, {0.0, 0.0, -1.0}}; glm::dvec3 const cubefacetargetvectors[6] = {{1.0, 0.0, 0.0}, {-1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, -1.0, 0.0}, {0.0, 0.0, 1.0}, {0.0, 0.0, -1.0}};
glm::dvec3 const cubefaceupvectors[6] = {{0.0, -1.0, 0.0}, {0.0, -1.0, 0.0}, {0.0, 0.0, 1.0}, {0.0, 0.0, -1.0}, {0.0, -1.0, 0.0}, {0.0, -1.0, 0.0}}; glm::dvec3 const cubefaceupvectors[6] = {{0.0, -1.0, 0.0}, {0.0, -1.0, 0.0}, {0.0, 0.0, 1.0}, {0.0, 0.0, -1.0}, {0.0, -1.0, 0.0}, {0.0, -1.0, 0.0}};
auto const cubefaceindex = m_environmentcubetextureface; auto const cubefaceindex = m_environmentcubetextureface;
@@ -2768,7 +2789,13 @@ void opengl33_renderer::Render(cell_sequence::iterator First, cell_sequence::ite
} }
case rendermode::reflections: case rendermode::reflections:
{ {
if( Global.reflectiontune.fidelity >= 1 ) { // a cell lying whole beyond the range the reflections draw model instances at is left out, as each
// of its instances would fail the range test done for it in Render_Instanced() and Render( TAnimModel * ).
// like the cull of the regular passes above, the test goes by the nearest point of the bounding sphere
// of the cell, which holds the locations of all its instances
auto const cellnearestdistance { std::max( 0.0, glm::length( cell->m_area.center - m_renderpass.pass_camera.position() ) - cell->m_area.radius ) };
if( ( Global.reflectiontune.fidelity >= 1 )
&& ( cellnearestdistance <= Global.reflectiontune.range_instances ) ) {
// opaque parts of instanced models -- accumulate into the // opaque parts of instanced models -- accumulate into the
// frame-level map; flushed once per unique model after the loop. // frame-level map; flushed once per unique model after the loop.
for( auto const &bucket : cell->m_instancebuckets_opaque ) { for( auto const &bucket : cell->m_instancebuckets_opaque ) {
@@ -4001,10 +4028,14 @@ void opengl33_renderer::Render(scene::basic_cell::path_sequence::const_iterator
if ((std::abs(track->fTexHeight1) < 0.35f) || (track->iCategoryFlag != 2)) if ((std::abs(track->fTexHeight1) < 0.35f) || (track->iCategoryFlag != 2))
{ {
// shadows are only calculated for high enough roads, typically meaning track platforms // shadows are only calculated for high enough roads, typically meaning track platforms
--m_renderpass.draw_stats.paths;
--m_renderpass.draw_stats.drawcalls;
continue; continue;
} }
if( Material( track->m_material1 ).shadow_rank > Global.gfx_shadow_rank_cutoff ) { if( Material( track->m_material1 ).shadow_rank > Global.gfx_shadow_rank_cutoff ) {
// skip if the shadow caster rank is too low for currently set threshold // skip if the shadow caster rank is too low for currently set threshold
--m_renderpass.draw_stats.paths;
--m_renderpass.draw_stats.drawcalls;
continue; continue;
} }
Bind_Material_Shadow(track->m_material1); Bind_Material_Shadow(track->m_material1);

View File

@@ -346,6 +346,8 @@ class opengl33_renderer : public gfx_renderer {
glm::mat4 m_shadowtexturematrix; // conversion from camera-centric world space to light-centric clip space glm::mat4 m_shadowtexturematrix; // conversion from camera-centric world space to light-centric clip space
int m_environmentcubetextureface{0}; // helper, currently processed cube map face int m_environmentcubetextureface{0}; // helper, currently processed cube map face
int m_environmentupdateface{6}; // cube map face the environment map update in progress draws next; 6: no update in progress
bool m_environmentready{false}; // the environment map was drawn whole at least once
double m_environmentupdatetime{0}; // time of the most recent environment map update double m_environmentupdatetime{0}; // time of the most recent environment map update
glm::dvec3 m_environmentupdatelocation; // coordinates of most recent environment map update glm::dvec3 m_environmentupdatelocation; // coordinates of most recent environment map update
opengl33_skydome m_skydomerenderer; opengl33_skydome m_skydomerenderer;