Skip to content

Commit d9fb896

Browse files
committed
[*] Implement fps limiter and add maxfps command line argument
1 parent b646e4d commit d9fb896

File tree

9 files changed

+106
-63
lines changed

9 files changed

+106
-63
lines changed

documentation/source/engine-overview/debugging/cla.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,7 @@ You can start vulkan-renderer with the following command line arguments:
1919
.. warning:: Vsync is currently not implemented. The command line argument will be ignored.
2020

2121
Enables `vertical synchronization <https://en.wikipedia.org/wiki/Analog_television#Vertical_synchronization>`__ (limits FPS to monitor refresh rate).
22+
23+
.. option:: --maxfps <fps>
24+
25+
Limits the max frames per seconds to a specified value. The command line argument will be clamped in between the values `1 fps` and `2000 fps` as lower and higher bounds.

include/inexor/vulkan-renderer/renderer.hpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
#include "inexor/vulkan-renderer/imgui.hpp"
44
#include "inexor/vulkan-renderer/octree_gpu_vertex.hpp"
55
#include "inexor/vulkan-renderer/tools/camera.hpp"
6-
#include "inexor/vulkan-renderer/tools/fps_counter.hpp"
6+
#include "inexor/vulkan-renderer/tools/fps_limiter.hpp"
77
#include "inexor/vulkan-renderer/tools/time_step.hpp"
88
#include "inexor/vulkan-renderer/wrapper/debug_callback.hpp"
99
#include "inexor/vulkan-renderer/wrapper/instance.hpp"
@@ -43,8 +43,6 @@ class VulkanRenderer {
4343

4444
std::string m_window_title;
4545

46-
tools::FPSCounter m_fps_counter;
47-
4846
bool m_vsync_enabled{false};
4947

5048
std::unique_ptr<tools::Camera> m_camera;
@@ -75,6 +73,7 @@ class VulkanRenderer {
7573
void render_frame();
7674

7775
public:
76+
tools::FPSLimiter m_fps_limiter;
7877
~VulkanRenderer();
7978

8079
bool m_window_resized{false};

include/inexor/vulkan-renderer/tools/fps_counter.hpp

Lines changed: 0 additions & 21 deletions
This file was deleted.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#pragma once
2+
3+
#include <chrono>
4+
#include <cstdint>
5+
#include <optional>
6+
7+
namespace inexor::vulkan_renderer::tools {
8+
9+
/// A wrapper class for counting and limiting frames per second.
10+
class FPSLimiter {
11+
private:
12+
static constexpr std::uint32_t DEFAULT_FPS{60};
13+
std::uint32_t m_max_fps{DEFAULT_FPS};
14+
std::chrono::milliseconds m_frame_time{DEFAULT_FPS / 1000};
15+
std::chrono::time_point<std::chrono::high_resolution_clock> m_last_time;
16+
std::chrono::time_point<std::chrono::high_resolution_clock> m_last_fps_update_time;
17+
std::chrono::milliseconds m_fps_update_interval{1000};
18+
std::uint32_t m_frames{0};
19+
20+
// The requested max_fps will be clamped in between these limits.
21+
static constexpr std::uint32_t MIN_FPS{1};
22+
static constexpr std::uint32_t MAX_FPS{2000};
23+
24+
public:
25+
FPSLimiter(std::uint32_t max_fps = DEFAULT_FPS);
26+
27+
void set_max_fps(std::uint32_t max_fps);
28+
29+
/// Ask if the next frame is allowed to be rendered.
30+
[[nodiscard]] bool is_next_frame_allowed();
31+
32+
/// Return the fps every second, std::nullopt otherwise.
33+
[[nodiscard]] std::optional<std::uint32_t> get_fps();
34+
};
35+
36+
} // namespace inexor::vulkan_renderer::tools

src/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ set(INEXOR_SOURCE_FILES
1313
vulkan-renderer/tools/enumerate.cpp
1414
vulkan-renderer/tools/exception.cpp
1515
vulkan-renderer/tools/file.cpp
16-
vulkan-renderer/tools/fps_counter.cpp
16+
vulkan-renderer/tools/fps_limiter.cpp
1717
vulkan-renderer/tools/queue_selection.cpp
1818
vulkan-renderer/tools/representation.cpp
1919
vulkan-renderer/tools/time_step.cpp

src/vulkan-renderer/application.cpp

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -282,8 +282,12 @@ Application::Application(int argc, char **argv) {
282282
app.add_flag("--vsync", m_vsync_enabled);
283283
std::optional<std::uint32_t> preferred_gpu;
284284
app.add_option("--gpu", preferred_gpu);
285+
std::uint32_t max_fps = 60;
286+
app.add_option("--maxfps", max_fps);
285287
app.parse(argc, argv);
286288

289+
m_fps_limiter.set_max_fps(max_fps);
290+
287291
load_toml_configuration_file("configuration/renderer.toml");
288292

289293
spdlog::trace("Creating Vulkan instance");
@@ -516,20 +520,22 @@ void Application::run() {
516520

517521
while (!m_window->should_close()) {
518522
m_window->poll();
519-
m_input->update_gamepad_data();
520-
update_uniform_buffers();
521-
update_imgui_overlay();
522-
render_frame();
523-
process_input();
524-
if (m_input->kbm_data().was_key_pressed_once(GLFW_KEY_N)) {
525-
load_octree_geometry(false);
526-
generate_octree_indices();
527-
m_index_buffer->upload_data(m_octree_indices);
528-
m_vertex_buffer->upload_data(m_octree_vertices);
523+
if (m_fps_limiter.is_next_frame_allowed()) {
524+
m_input->update_gamepad_data();
525+
update_uniform_buffers();
526+
update_imgui_overlay();
527+
render_frame();
528+
process_input();
529+
if (m_input->kbm_data().was_key_pressed_once(GLFW_KEY_N)) {
530+
load_octree_geometry(false);
531+
generate_octree_indices();
532+
m_index_buffer->upload_data(m_octree_indices);
533+
m_vertex_buffer->upload_data(m_octree_vertices);
534+
}
535+
m_camera->update(m_time_passed);
536+
m_time_passed = m_stopwatch.time_step();
537+
check_octree_collisions();
529538
}
530-
m_camera->update(m_time_passed);
531-
m_time_passed = m_stopwatch.time_step();
532-
check_octree_collisions();
533539
}
534540
}
535541

src/vulkan-renderer/renderer.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ void VulkanRenderer::render_frame() {
112112

113113
m_swapchain->present(image_index);
114114

115-
if (auto fps_value = m_fps_counter.update()) {
115+
if (auto fps_value = m_fps_limiter.get_fps()) {
116116
m_window->set_title("Inexor Vulkan API renderer demo - " + std::to_string(*fps_value) + " FPS");
117117
spdlog::trace("FPS: {}, window size: {} x {}", *fps_value, m_window->width(), m_window->height());
118118
}

src/vulkan-renderer/tools/fps_counter.cpp

Lines changed: 0 additions & 24 deletions
This file was deleted.
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#include "inexor/vulkan-renderer/tools/fps_limiter.hpp"
2+
3+
#include <spdlog/spdlog.h>
4+
5+
#include <algorithm>
6+
7+
namespace inexor::vulkan_renderer::tools {
8+
9+
FPSLimiter::FPSLimiter(const std::uint32_t max_fps) {
10+
set_max_fps(max_fps);
11+
}
12+
13+
void FPSLimiter::set_max_fps(std::uint32_t max_fps) {
14+
m_max_fps = std::clamp(max_fps, MIN_FPS, MAX_FPS);
15+
m_frame_time = std::chrono::milliseconds(1000) / m_max_fps;
16+
}
17+
18+
bool FPSLimiter::is_next_frame_allowed() {
19+
const auto current_time = std::chrono::high_resolution_clock::now();
20+
const auto elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(current_time - m_last_time);
21+
if (elapsed_ms >= m_frame_time) {
22+
m_last_time = current_time;
23+
return true;
24+
}
25+
return false;
26+
}
27+
28+
std::optional<std::uint32_t> FPSLimiter::get_fps() {
29+
m_frames++;
30+
const auto current_time = std::chrono::high_resolution_clock::now();
31+
const auto elapsed_ms =
32+
std::chrono::duration_cast<std::chrono::milliseconds>(current_time - m_last_fps_update_time);
33+
if (elapsed_ms >= m_fps_update_interval) {
34+
m_last_fps_update_time = current_time;
35+
auto fps_value = static_cast<std::uint32_t>(m_frames * 1000.0f / elapsed_ms.count());
36+
m_frames = 0;
37+
return fps_value;
38+
}
39+
40+
return std::nullopt;
41+
}
42+
43+
} // namespace inexor::vulkan_renderer::tools

0 commit comments

Comments
 (0)