Graphics Preferences: Anti-aliasing + FPS (#13538)

* Expose Antialiasing velues

Expose Antialiasing multipliers.
Default to 4 as current implementation but enables the user to disable it to improve performante or increase sampling to improve quality.

* FXAA

* Improve descriptions

* Require restart when MSAA setting changes

Detect changes to the OpenGL MSAA (multisample anti-aliasing) preference when opening Preferences and prompt the user to restart the application to apply the change. Adds a constant key for the MSAA setting, stores the previous value, checks for changes (similar to the existing FXAA handling), and shows a warning dialog explaining the restart will close the current project without saving. If the user accepts, recreate_GUI is invoked to apply the MSAA change immediately.

* Revert "Require restart when MSAA setting changes"

This reverts commit dde134d346c3849598c91d025d2faed1b51c8a22.

* Menu and FPS options

* Fix FPS limiter and remove VSYNC

* Grouped FPS settings and mode up rigth fps counter

---------

Co-authored-by: Noisyfox <timemanager.rick@gmail.com>
This commit is contained in:
Ian Bassi
2026-05-17 02:31:51 -03:00
committed by GitHub
parent b3fe733bf2
commit 873d0ed26e
12 changed files with 393 additions and 7 deletions

View File

@@ -14,6 +14,7 @@
#include "libslic3r/Technologies.hpp"
#include "libslic3r/Tesselate.hpp"
#include "libslic3r/PresetBundle.hpp"
#include "libslic3r/AppConfig.hpp"
#include "3DScene.hpp"
#include "BackgroundSlicingProcess.hpp"
#include "GLShader.hpp"
@@ -1202,6 +1203,11 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D &bed)
GLCanvas3D::~GLCanvas3D()
{
if (m_fxaa_texture_id != 0 && _set_current()) {
glsafe(::glDeleteTextures(1, &m_fxaa_texture_id));
m_fxaa_texture_id = 0;
}
reset_volumes();
m_sel_plate_toolbar.del_all_item();
@@ -2082,9 +2088,16 @@ void GLCanvas3D::render(bool only_init)
if (m_picking_enabled && m_rectangle_selection.is_dragging())
m_rectangle_selection.render(*this);
if (_is_fxaa_enabled())
_render_fxaa_pass(static_cast<unsigned int>(cnv_size.get_width()), static_cast<unsigned int>(cnv_size.get_height()));
// draw overlays
_render_overlays();
const int current_fps = m_render_stats.get_fps_and_reset_if_needed();
if (_is_fps_overlay_enabled())
_render_fps_overlay(current_fps);
if (wxGetApp().plater()->is_render_statistic_dialog_visible()) {
ImGui::ShowMetricsWindow();
@@ -2092,7 +2105,7 @@ void GLCanvas3D::render(bool only_init)
imgui.begin(std::string("Render statistics"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse);
imgui.text("FPS (SwapBuffers() calls per second):");
ImGui::SameLine();
imgui.text(std::to_string(m_render_stats.get_fps_and_reset_if_needed()));
imgui.text(std::to_string(current_fps));
ImGui::Separator();
imgui.text("Compressed textures:");
ImGui::SameLine();
@@ -3194,6 +3207,22 @@ void GLCanvas3D::on_idle(wxIdleEvent& evt)
wxGetApp().imgui()->reset_requires_extra_frame();
#endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
const int fps_cap = _get_effective_fps_cap();
if (fps_cap > 0) {
const auto now = std::chrono::steady_clock::now();
const auto min_frame_time = std::chrono::duration<double>(1.0 / static_cast<double>(fps_cap));
const auto elapsed = now - m_last_frame_start_time;
if (elapsed < min_frame_time) {
const int wait_ms = std::max(1, static_cast<int>(std::ceil(std::chrono::duration<double, std::milli>(min_frame_time - elapsed).count())));
schedule_extra_frame(wait_ms);
evt.RequestMore();
return;
}
// Pace by frame-start interval so rendering time is part of the target budget.
m_last_frame_start_time = now;
}
_refresh_if_shown_on_screen();
#if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
@@ -7422,6 +7451,105 @@ void GLCanvas3D::_rectangular_selection_picking_pass()
_update_volumes_hover_state();
}
bool GLCanvas3D::_is_fxaa_enabled() const
{
return wxGetApp().app_config != nullptr && wxGetApp().app_config->get_bool(SETTING_OPENGL_FXAA_ENABLED);
}
int GLCanvas3D::_get_effective_fps_cap() const
{
if (wxGetApp().app_config == nullptr)
return 0;
int fps_cap = 0;
try {
fps_cap = std::stoi(wxGetApp().app_config->get(SETTING_OPENGL_FPS_CAP));
}
catch (...) {
fps_cap = 0;
}
fps_cap = std::max(0, std::min(fps_cap, 240));
return fps_cap;
}
bool GLCanvas3D::_is_fps_overlay_enabled() const
{
return wxGetApp().app_config != nullptr && wxGetApp().app_config->get_bool(SETTING_OPENGL_SHOW_FPS_OVERLAY);
}
void GLCanvas3D::_render_fps_overlay(int fps) const
{
if (fps < 0)
return;
ImGuiWrapper& imgui = *wxGetApp().imgui();
const float margin = 10.0f * get_scale();
const ImVec2 display_size = ImGui::GetIO().DisplaySize;
ImGui::SetNextWindowPos(ImVec2(display_size.x - margin, margin), ImGuiCond_Always, ImVec2(1.0f, 0.0f));
ImGui::SetNextWindowBgAlpha(0.35f);
imgui.begin(
std::string("###fps_overlay"),
ImGuiWindowFlags_AlwaysAutoResize |
ImGuiWindowFlags_NoResize |
ImGuiWindowFlags_NoCollapse |
ImGuiWindowFlags_NoTitleBar |
ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_NoSavedSettings |
ImGuiWindowFlags_NoInputs);
imgui.text(std::string("FPS: ") + std::to_string(fps));
imgui.end();
}
void GLCanvas3D::_render_fxaa_pass(unsigned int width, unsigned int height)
{
if (width == 0 || height == 0)
return;
GLShaderProgram* shader = wxGetApp().get_shader("fxaa");
if (shader == nullptr)
return;
if (m_fxaa_texture_id == 0) {
glsafe(::glGenTextures(1, &m_fxaa_texture_id));
glsafe(::glBindTexture(GL_TEXTURE_2D, m_fxaa_texture_id));
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
glsafe(::glBindTexture(GL_TEXTURE_2D, 0));
}
glsafe(::glBindTexture(GL_TEXTURE_2D, m_fxaa_texture_id));
if (m_fxaa_texture_size[0] != width || m_fxaa_texture_size[1] != height) {
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr));
m_fxaa_texture_size = { width, height };
}
glsafe(::glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, width, height));
glsafe(::glDisable(GL_DEPTH_TEST));
glsafe(::glDisable(GL_BLEND));
glsafe(::glClear(GL_COLOR_BUFFER_BIT));
shader->start_using();
shader->set_uniform("view_model_matrix", Transform3d::Identity());
shader->set_uniform("projection_matrix", Transform3d::Identity());
shader->set_uniform("uniform_texture", 0);
shader->set_uniform("inv_tex_size", Vec2f(1.0f / static_cast<float>(width), 1.0f / static_cast<float>(height)));
glsafe(::glActiveTexture(GL_TEXTURE0));
glsafe(::glBindTexture(GL_TEXTURE_2D, m_fxaa_texture_id));
m_background.render();
glsafe(::glBindTexture(GL_TEXTURE_2D, 0));
shader->stop_using();
glsafe(::glEnable(GL_DEPTH_TEST));
glsafe(::glEnable(GL_BLEND));
glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
}
void GLCanvas3D::_render_background()
{
bool use_error_color = false;