Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,13 @@ if(ARMADILLO_FOUND)
target_link_libraries(fps OpenGL::GL glfw Freetype::Freetype)
endif()

add_executable(fps_with_profiler fps_with_profiler.cpp)
if(OpenMP_CXX_FOUND)
target_link_libraries(fps_with_profiler OpenMP::OpenMP_CXX OpenGL::GL glfw Freetype::Freetype)
else()
target_link_libraries(fps_with_profiler OpenGL::GL glfw Freetype::Freetype)
endif()

add_executable(cartgrid cartgrid.cpp)
target_link_libraries(cartgrid OpenGL::GL glfw Freetype::Freetype)

Expand Down
3 changes: 2 additions & 1 deletion examples/fps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ int main()
all_dur += sc::now() - t00;
t00 = sc::now();

v.waitevents (0.00001);
v.poll();
if (k > 8.0f) { k = 1.0f; }

t0 = sc::now();
Expand Down Expand Up @@ -109,6 +109,7 @@ int main()
update_dur = sc::duration{0};
all_dur = sc::duration{0};
fcount = 0;
v.waitevents (0.00001);
}

v.render();
Expand Down
95 changes: 95 additions & 0 deletions examples/fps_with_profiler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* An example mplot::Visual scene, containing a HexGrid.
*
* Using mplot::fps::profiler for the FPS profile
*/

#include <iostream>
#include <vector>
#include <cmath>
#include <sstream>

#include <sm/vec>
#include <sm/hexgrid>

#include <mplot/Visual.h>
#include <mplot/VisualDataModel.h>
#include <mplot/VisualTextModel.h>
#include <mplot/HexGridVisual.h>

#include <mplot/fps/profiler.h>

int main()
{
mplot::Visual v(1600, 1000, "mplot::Visual");
v.fov = 15.0f;
v.zFar = 200.0f;
v.lightingEffects();
mplot::VisualTextModel<>* fps_tm;
v.addLabel ("0 FPS", {0.13f, -0.23f, 0.0f}, fps_tm); // With fps_tm can update the VisualTextModel with fps_tm->setupText("new text")

// Create a hexgrid to show in the scene
constexpr float hex_to_hex = 0.02f;

sm::hexgrid hg(hex_to_hex, 15.0f, 0.0f);
hg.setEllipticalBoundary (4.0f, 4.0f);
std::cout << "Number of hexes in grid:" << hg.num() << std::endl;
std::stringstream sss;
sss << "Surface evaluated at " << hg.num() << " coordinates";
v.addLabel (sss.str(), {0.0f, 0.0f, 0.0f});

// Make some dummy data (a radially symmetric Bessel fn) to make an interesting surface
std::vector<float> data(hg.num(), 0.0f);
std::vector<float> r(hg.num(), 0.0f);
float k = 1.0f;
for (unsigned int hi = 0; hi < hg.num(); ++hi) {
// x/y: hg.d_x[hi] hg.d_y[hi]
r[hi] = std::sqrt (hg.d_x[hi] * hg.d_x[hi] + hg.d_y[hi] * hg.d_y[hi]);
data[hi] = std::sin (k * r[hi]) / k * r[hi];
}

// Add a HexGridVisual to display the HexGrid within the mplot::Visual scene
sm::vec<float, 3> offset = { 0.0f, -0.05f, 0.0f };
auto hgv = std::make_unique<mplot::HexGridVisual<float>>(&hg, offset);
v.bindmodel (hgv);
hgv->setScalarData (&data);
hgv->hexVisMode = mplot::HexVisMode::Triangles;
hgv->finalize();
auto hgvp = v.addVisualModel (hgv);

unsigned int fcount = 0u;

// Our profiler object
mplot::fps::profiler fps_profiler;

while (v.readyToFinish() == false) {

v.poll();

fps_profiler.at_begin (1000);

if (k > 8.0f) { k = 1.0f; }

#pragma omp parallel for shared(r,k,data)
for (unsigned int hi = 0; hi < hg.num(); ++hi) {
data[hi] = std::sin (k * r[hi]) / k * r[hi];
}
if (v.validVisualModel (hgvp) != nullptr) { // Test hgvp is still valid
hgvp->updateData (&data);
}
k += 0.02f;

if (fcount == 500) { // Update FPS text
fps_tm->setupText (fps_profiler.fps_txt);
fcount = 0;
v.waitevents (0.00001);
}

v.render();
fcount++;

fps_profiler.at_end();
}

return 0;
}
3 changes: 3 additions & 0 deletions mplot/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,9 @@ add_subdirectory(wx)
# Compound ray glue code
add_subdirectory(compoundray)

# FPS profiling
add_subdirectory(fps)

# Install the EXPORT so that mathplot has its own .cmake file and find_package(mathplot) should work
install(FILES mathplot-config.cmake DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/cmake/mathplot)
#install(EXPORT mathplot DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/cmake/mathplot)
1 change: 1 addition & 0 deletions mplot/fps/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
install(FILES profiler.h DESTINATION ${CMAKE_INSTALL_PREFIX}/include/mplot/fps)
65 changes: 65 additions & 0 deletions mplot/fps/profiler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* A profiler that computes FPS and manages an std::string that can be used on a graphical info
* screen.
*
* Author: Seb James
* Date: 2024-2025
*/
#pragma once

#include <chrono>
#include <deque>
#include <string>
#include <sstream>
#include <cmath>

namespace mplot::fps
{
using namespace std::chrono;
using sc = std::chrono::steady_clock;

struct profiler
{
sc::time_point t0 = sc::now();
sc::time_point t1 = sc::now();

std::deque<double> fps;
double fps_mean = 0.0; // a running-mean of fps
unsigned int fps_mean_over_n_samples_last = 0;

// Current FPS text
std::string fps_txt;

// Call at the start of the loop that you're timing
void at_begin (unsigned int fps_mean_over_n_samples)
{
sc::duration t_d = this->t1 - this->t0;
if (fps_mean_over_n_samples != fps_mean_over_n_samples_last) {
// Reset counters
this->fps.clear();
this->fps_mean = 0.0;
this->fps_mean_over_n_samples_last = fps_mean_over_n_samples;
}
double fps_mean_period = 1.0 / fps_mean_over_n_samples;
double fps_now = 0.0;
double usecs = static_cast<double>(duration_cast<microseconds>(t_d).count());
if (usecs > 0.0) { fps_now = 1000000.0 / usecs; }
this->fps.push_back (fps_now * fps_mean_period);
this->fps_mean += this->fps.back();
if (this->fps.size() > fps_mean_over_n_samples) {
this->fps_mean -= this->fps.front();
this->fps.pop_front();
}
std::stringstream ss;
// Stream into ss ready for display
ss << static_cast<int>(std::round(this->fps_mean)) << " FPS";
this->fps_txt = ss.str();

this->t0 = sc::now();
}

// Call at the end of the loop that you're timing
void at_end () { this->t1 = sc::now(); }
};

} // namespace
Loading