2727#include < iostream>
2828#include < iomanip>
2929#include < chrono>
30- #include < fstream>
30+ #include < filesystem>
31+
32+ #include < GL/wglew.h>
3133
3234#define ALWAYS_OUTDATE_THE_CURRENT_VR_RENDERER
3335
4345#define GL_GPU_MEM_INFO_CURRENT_AVAILABLE_MEM_NVX 0x9049
4446#endif
4547
46- #ifdef USING_FREEGLUT
47- double GetCurrentTimeFreeGLUT (void * data)
48+ double GetCurrentRenderTime ()
4849{
50+ #ifdef USING_FREEGLUT
4951 return glutGet (GLUT_ELAPSED_TIME);
50- }
51- #else
52- #ifdef USING_GLFW
53- #endif
52+ #elif USING_GLFW
53+ return glfwGetTime ();
5454#endif
55+ }
5556
5657RenderingManager *RenderingManager::crr_instance = 0 ;
5758
@@ -172,9 +173,18 @@ void RenderingManager::InitData ()
172173
173174void RenderingManager::Display ()
174175{
175- // Get the current render mode
176- UpdateFrameRate ();
177-
176+ // We always redraw during evaluation
177+ if (m_eval_running)
178+ {
179+ curr_vol_renderer->SetOutdated ();
180+ }
181+ else
182+ {
183+ // The frame rate display (console and ImGui) is only updated when not evaluating.
184+ // Evaluation computes the frame rate after a given fixed number of frames.
185+ UpdateFrameRate ();
186+ }
187+
178188 if (curr_rdr_parameters.GetCamera ()->UpdatePositionAndRotations ())
179189 {
180190 curr_vol_renderer->SetOutdated ();
@@ -246,7 +256,66 @@ void RenderingManager::Display ()
246256
247257 curr_rdr_parameters.GetCamera ()->SetData (&sdata);
248258 curr_vol_renderer->SetOutdated ();
249- }
259+ }
260+
261+ if (m_eval_running)
262+ {
263+ // We shoot a number of frames for each evaluation sample
264+ m_eval_currframe++; // go to the next frame
265+ if (m_eval_currframe >= m_eval_numframes)
266+ {
267+ // Compute the rendering speed for that sample point
268+ const double currenttime = GetCurrentRenderTime ();
269+ const double time_per_frame = (currenttime - m_eval_lasttime) / m_eval_numframes;
270+ const double frames_per_second = 1000.0 / time_per_frame;
271+
272+ // Save the last rendered image
273+ std::string imagefilename = std::to_string (m_eval_currsample);
274+ size_t n_zero = 4 ;
275+ imagefilename = std::string (n_zero - std::min (n_zero, imagefilename.length ()), ' 0' ) + imagefilename + " .png" ;
276+ SaveScreenshot (m_eval_imgdirectory + " /" + imagefilename);
277+
278+ // Store evaluation results in csv file
279+ for (int i=0 ;i<m_eval_paramspace.GetNumDimensions ();i++)
280+ {
281+ m_eval_csvfile << m_eval_paramspace.GetDimensionValue (i) << " ," ;
282+ }
283+ m_eval_csvfile << std::to_string (time_per_frame) << " ,"
284+ << std::to_string (frames_per_second) << " ,"
285+ << imagefilename << " \n " ;
286+
287+
288+ // We go to the next sample point in the parameter space.
289+ if (m_eval_paramspace.IncrEvaluation ())
290+ {
291+ // The ID of the new sample point
292+ m_eval_currsample++;
293+ // ... and we shoot as many frames there as for the other samples.
294+ m_eval_currframe = 0 ;
295+ // Restart time taking
296+ m_eval_lasttime = GetCurrentRenderTime ();
297+ }
298+ else
299+ {
300+ // We reached the end of the evaluation.
301+ m_eval_paramspace.EndEvaluation ();
302+ m_eval_running = false ;
303+ m_eval_csvfile.close ();
304+ // Enable or disable vsync according to user prefs
305+ if (m_vsync)
306+ {
307+ wglSwapIntervalEXT (1 );
308+ }
309+ else
310+ {
311+ wglSwapIntervalEXT (0 );
312+ }
313+ // Restore UI
314+ m_imgui_render_ui = true ;
315+ }
316+ }
317+ }
318+
250319}
251320
252321void RenderingManager::Reshape (int w, int h)
@@ -337,12 +406,15 @@ void RenderingManager::UpdateDataAndResetCurrentVRMode ()
337406 curr_vol_renderer->Init (curr_rdr_parameters.GetScreenWidth (), curr_rdr_parameters.GetScreenHeight ());
338407}
339408
340- void RenderingManager::SaveScreenshot ()
409+ void RenderingManager::SaveScreenshot (std::string filename )
341410{
342411 // Get pixel data without alpha
343412 GLubyte* rgb_data = GetFrontBufferPixelData (false );
344- std::string out_str = AddAbreviationName (curr_rdr_parameters.GetDefaultScreenshotName ());
345- GenerateImgFile (out_str, curr_rdr_parameters.GetScreenWidth (), curr_rdr_parameters.GetScreenHeight (), rgb_data, false );
413+ if (filename.empty ())
414+ {
415+ filename = AddAbreviationName (curr_rdr_parameters.GetDefaultScreenshotName ());
416+ }
417+ GenerateImgFile (filename, curr_rdr_parameters.GetScreenWidth (), curr_rdr_parameters.GetScreenHeight (), rgb_data, false );
346418 delete[] rgb_data;
347419}
348420
@@ -381,9 +453,15 @@ bool RenderingManager::GenerateImgFile (std::string out_str, int w, int h, unsig
381453 int error;
382454
383455#ifdef USING_IM_EXT
384- std::string path_to_data = CPPVOLREND_DATA_DIR;
385- std::string c_out_str = path_to_data + out_str;
386- imFile* ifile = imFileNew (c_out_str.c_str (), image_type.c_str (), &error);
456+ // Deal with absolute and relative paths
457+ if (std::filesystem::path (out_str).is_relative ())
458+ {
459+ std::string path_to_data = CPPVOLREND_DATA_DIR;
460+ out_str = path_to_data + out_str;
461+ }
462+
463+ // Create the file and save it
464+ imFile* ifile = imFileNew (out_str.c_str (), image_type.c_str (), &error);
387465 int user_color_mode = alpha ? IM_RGB | IM_ALPHA | IM_PACKED : IM_RGB | IM_PACKED;
388466 error = imFileWriteImageInfo (ifile, w, h, user_color_mode, IM_BYTE);
389467 error = imFileWriteImageData (ifile, gl_data);
@@ -456,6 +534,9 @@ void RenderingManager::SetCurrentVolumeRenderer ()
456534 curr_vol_renderer = m_vtr_vr_methods[m_current_vr_method_id];
457535 UpdateDataAndResetCurrentVRMode ();
458536 }
537+
538+ // Let the volume renderer define some parameters for evaluation
539+ curr_vol_renderer->FillParameterSpace (m_eval_paramspace);
459540}
460541
461542void RenderingManager::SetImGuiInterface ()
@@ -517,6 +598,17 @@ void RenderingManager::SetImGuiInterface ()
517598 {
518599 ImGui::Begin (" Rendering Manager" , &m_imgui_render_manager);
519600 ImGui::BulletText (" OpenGL Version %s" , glGetString (GL_VERSION));
601+ if (ImGui::Checkbox (" VSync" , &m_vsync))
602+ {
603+ if (m_vsync)
604+ {
605+ wglSwapIntervalEXT (1 );
606+ }
607+ else
608+ {
609+ wglSwapIntervalEXT (0 );
610+ }
611+ };
520612 if (ImGui::Checkbox (" Idle Redraw" , &m_idle_rendering));
521613 ImGui::SameLine ();
522614 ImGui::Text (" - %.3f ms/frame (%.1f FPS)" , m_ts_window_ms, m_ts_window_fps);
@@ -695,6 +787,8 @@ void RenderingManager::SetImGuiInterface ()
695787 delete[] tf_rgb_img;
696788 }
697789
790+
791+
698792 ImGui::PushID (" Viewport Data" );
699793 ImGui::Text (" - Viewport:" );
700794 int v_size[2 ] = { curr_rdr_parameters.GetScreenWidth (), curr_rdr_parameters.GetScreenHeight () };
@@ -710,6 +804,69 @@ void RenderingManager::SetImGuiInterface ()
710804 }
711805 ImGui::PopID ();
712806
807+ if (ImGui::CollapsingHeader (" Evaluation###EvaluationHeader" ))
808+ {
809+ const int numsamples = m_eval_paramspace.GetNumSamplePoints ();
810+ ImGui::Text (" %d parameters with %d total samples" , m_eval_paramspace.GetNumDimensions (), numsamples);
811+
812+ ImGui::PushItemWidth (100 );
813+ ImGui::InputInt (" Eval Frames per Sample" , &m_eval_numframes, 1 , 10 );
814+ ImGui::PopItemWidth ();
815+ m_eval_numframes = std::max (std::min (m_eval_numframes, 500 ), 1 );
816+
817+ const double neededtime = ceil (m_ts_window_ms * numsamples * m_eval_numframes / 1000 .);
818+ ImGui::Text (" approx. %.0f seconds for evaluation at current FPS" , neededtime);
819+ if (ImGui::Button (" Start Evaluation" ))
820+ {
821+ // Name of a directory containing all the evaluation files - naming is datetime-based
822+ auto t = std::time (nullptr );
823+ auto tm = *std::localtime (&t);
824+ std::ostringstream oss;
825+ oss << std::put_time (&tm, " eval_%d-%m-%Y_%H-%M-%S" );
826+ const std::string path_to_data = CPPVOLREND_DATA_DIR;
827+ m_eval_basedirectory = path_to_data + oss.str ();
828+ // - and an image subsirectory
829+ m_eval_imgdirectory = m_eval_basedirectory + " /img" ;
830+
831+ // Create the new directories
832+ std::filesystem::create_directory (m_eval_basedirectory);
833+ std::filesystem::create_directory (m_eval_imgdirectory);
834+
835+ // Open a CSV file to record the results of the evaluation.
836+ if (m_eval_csvfile.is_open ()) m_eval_csvfile.close (); // Should really not happen, but better be save.
837+ m_eval_csvfile.open (m_eval_basedirectory + " /eval.csv" , std::ios_base::out);
838+
839+ // Start the evaluation if everything is fine
840+ if (m_eval_csvfile.is_open ())
841+ {
842+ // Reset parameter space to the beginning
843+ m_eval_paramspace.StartEvaluation ();
844+
845+ // Initialize the csv file
846+ for (int i=0 ;i<m_eval_paramspace.GetNumDimensions ();i++)
847+ {
848+ m_eval_csvfile << m_eval_paramspace.GetDimensionName (i) << " ," ;
849+ }
850+ m_eval_csvfile << " TimePerFrame (ms),FramesPerSecond,ImageFile\n " ;
851+
852+ // Set a bool to trigger evaluation action in Display().
853+ m_eval_running = true ;
854+ m_eval_currframe = 0 ;
855+ m_eval_currsample = 0 ;
856+ m_eval_lasttime = GetCurrentRenderTime ();
857+ curr_vol_renderer->SetOutdated ();
858+ // Careful: Not rendering the ImGui may have unintended consequences,
859+ // namely if they Gui code changes parameters based on the parameters
860+ // that we are setting during the eval.
861+ // On the other hand, we want to measure the speed of the volume renderer and not of ImGui.
862+ m_imgui_render_ui = false ;
863+
864+ // Disable VSync for full speed
865+ wglSwapIntervalEXT (0 );
866+ }
867+ }
868+ }
869+
713870 // int u_cam_beha = m_camera.GetCameraBehaviour();
714871 if (ImGui::CollapsingHeader (" Camera###CameraSettingsHeader" ))
715872 {
@@ -1019,10 +1176,9 @@ void RenderingManager::DrawImGuiInterface ()
10191176void RenderingManager::UpdateFrameRate ()
10201177{
10211178 // Measure speed
1022- #ifdef USING_FREEGLUT
1023- m_ts_current_time = glutGet (GLUT_ELAPSED_TIME);
1179+ m_ts_current_time = GetCurrentRenderTime ();
10241180 m_ts_n_frames++;
1025- // After 1 second , compute frames per second...
1181+ // After X seconds , compute frames per second...
10261182 if ((m_ts_current_time - m_ts_last_time) > RENDERING_MANAGER_TIME_PER_FPS_COUNT_MS)
10271183 {
10281184 m_ts_window_fps = double (m_ts_n_frames) * 1000.0 / (m_ts_current_time - m_ts_last_time);
@@ -1032,21 +1188,6 @@ void RenderingManager::UpdateFrameRate ()
10321188 m_ts_n_frames = 0 ;
10331189 printf (" %.2lf frames per second\n " , m_ts_window_fps);
10341190 }
1035- #else
1036- #ifdef USING_GLFW
1037- currentTime = glfwGetTime ();
1038- nbFrames++;
1039- if ((currentTime - lastTime) > 1.0 )
1040- {
1041- double milisec = (currentTime - lastTime) * 1000.0 ;
1042- window_fps = double (nbFrames) * 1000.0 / (currentTime - lastTime);
1043- window_ms = 1000.0 / window_fps;
1044-
1045- lastTime = currentTime;
1046- nbFrames = 0 ;
1047- }
1048- #endif
1049- #endif
10501191}
10511192
10521193void RenderingManager::SingleSampleRender (void * data)
@@ -1096,10 +1237,15 @@ RenderingManager::RenderingManager ()
10961237
10971238 animate_camera_rotation = false ;
10981239
1240+ m_eval_running = false ;
1241+ m_eval_numframes = 100 ;
1242+ m_eval_currframe = 0 ;
1243+
10991244 m_imgui_render_ui = true ;
11001245
11011246 m_imgui_render_manager = true ;
11021247 m_idle_rendering = true ;
1248+ m_vsync = true ;
11031249 m_ts_current_time = 0.0 ;
11041250#ifdef USING_FREEGLUT
11051251 m_ts_last_time = glutGet (GLUT_ELAPSED_TIME);
0 commit comments