@@ -102,7 +102,13 @@ void ProjectM::LoadPresetFile(const std::string& presetFilename, bool smoothTran
102102 }
103103
104104 // Asynchronous path — offload file I/O to the background thread.
105- m_textureManager->PurgeTextures ();
105+ {
106+ auto tPurge = std::chrono::steady_clock::now ();
107+ m_textureManager->PurgeTextures ();
108+ auto usPurge = std::chrono::duration_cast<std::chrono::microseconds>(
109+ std::chrono::steady_clock::now () - tPurge).count ();
110+ LOG_INFO (" [PresetSwitch] PurgeTextures=" + std::to_string (usPurge / 1000 .0f ) + " ms" );
111+ }
106112
107113 auto ctx = std::make_shared<PresetSwitchContext>();
108114 ctx->path = presetFilename;
@@ -170,12 +176,16 @@ void ProjectM::RenderFrame(uint32_t targetFramebufferObject /*= 0*/)
170176 return ;
171177 }
172178
179+ auto tFrameStart = std::chrono::steady_clock::now ();
180+
173181 // Drive the asynchronous preset switch state machine.
174182 if (m_activeSwitch)
175183 {
176184 ProcessPresetSwitch ();
177185 }
178186
187+ auto tAfterSwitch = std::chrono::steady_clock::now ();
188+
179189 // Update FPS and other timer values.
180190 m_timeKeeper->UpdateTimers ();
181191
@@ -230,9 +240,14 @@ void ProjectM::RenderFrame(uint32_t targetFramebufferObject /*= 0*/)
230240 {
231241 if (m_transition->IsDone (m_timeKeeper->GetFrameTime ()))
232242 {
243+ auto tTransEnd = std::chrono::steady_clock::now ();
233244 m_activePreset = std::move (m_transitioningPreset);
234245 m_transitioningPreset.reset ();
235246 m_transition.reset ();
247+ auto usTransEnd = std::chrono::duration_cast<std::chrono::microseconds>(
248+ std::chrono::steady_clock::now () - tTransEnd).count ();
249+ LOG_INFO (" [PresetSwitch] TransitionEnd=" + std::to_string (usTransEnd / 1000 .0f )
250+ + " ms (old preset destroyed)" );
236251 }
237252 else
238253 {
@@ -270,6 +285,35 @@ void ProjectM::RenderFrame(uint32_t targetFramebufferObject /*= 0*/)
270285
271286 m_frameCount++;
272287 m_previousFrameVolume = audioData.vol ;
288+
289+ // Frame-time spike detection. Log the first few frames after a
290+ // preset switch and any frame that exceeds a threshold.
291+ if (m_framesAfterSwitch >= 0 )
292+ {
293+ m_framesAfterSwitch++;
294+ }
295+
296+ auto usFrame = std::chrono::duration_cast<std::chrono::microseconds>(
297+ std::chrono::steady_clock::now () - tFrameStart).count ();
298+ auto usSwitch = std::chrono::duration_cast<std::chrono::microseconds>(
299+ tAfterSwitch - tFrameStart).count ();
300+ float msFrame = usFrame / 1000 .0f ;
301+ float msSwitch = usSwitch / 1000 .0f ;
302+ float msRender = (usFrame - usSwitch) / 1000 .0f ;
303+
304+ if (m_framesAfterSwitch >= 0 && m_framesAfterSwitch <= 5 )
305+ {
306+ LOG_INFO (" [FrameTime] after_switch=" + std::to_string (m_framesAfterSwitch)
307+ + " total=" + std::to_string (msFrame)
308+ + " ms switch=" + std::to_string (msSwitch)
309+ + " ms render=" + std::to_string (msRender) + " ms" );
310+ }
311+ else if (msFrame > 5 .0f )
312+ {
313+ LOG_INFO (" [FrameTime] SPIKE total=" + std::to_string (msFrame)
314+ + " ms switch=" + std::to_string (msSwitch)
315+ + " ms render=" + std::to_string (msRender) + " ms" );
316+ }
273317}
274318
275319void ProjectM::Initialize ()
@@ -365,7 +409,11 @@ void ProjectM::StartPresetTransition(std::unique_ptr<Preset>&& preset, bool hard
365409
366410 if (m_activePreset && !m_presetStartClean)
367411 {
412+ auto tDraw = std::chrono::steady_clock::now ();
368413 preset->DrawInitialImage (m_activePreset->OutputTexture (), GetRenderContext ());
414+ auto usDraw = std::chrono::duration_cast<std::chrono::microseconds>(
415+ std::chrono::steady_clock::now () - tDraw).count ();
416+ LOG_INFO (" [PresetSwitch] DrawInitialImage=" + std::to_string (usDraw / 1000 .0f ) + " ms" );
369417 }
370418
371419 if (hardCut)
@@ -377,7 +425,11 @@ void ProjectM::StartPresetTransition(std::unique_ptr<Preset>&& preset, bool hard
377425 {
378426 m_transitioningPreset = std::move (preset);
379427 m_timeKeeper->StartSmoothing ();
428+ auto tTransition = std::chrono::steady_clock::now ();
380429 m_transition = std::make_unique<Renderer::PresetTransition>(m_transitionShaderManager->RandomTransition (), m_softCutDuration, m_timeKeeper->GetFrameTime ());
430+ auto usTransition = std::chrono::duration_cast<std::chrono::microseconds>(
431+ std::chrono::steady_clock::now () - tTransition).count ();
432+ LOG_INFO (" [PresetSwitch] TransitionSetup=" + std::to_string (usTransition / 1000 .0f ) + " ms" );
381433 }
382434}
383435
@@ -859,7 +911,13 @@ void ProjectM::FinalizePresetActivation(std::shared_ptr<PresetSwitchContext>& ct
859911 }
860912
861913 // Hand the fully-initialized preset to the transition logic.
914+ auto tActivate = std::chrono::steady_clock::now ();
862915 StartPresetTransition (std::move (ctx->preset ), !ctx->smoothTransition );
916+ auto usActivate = std::chrono::duration_cast<std::chrono::microseconds>(
917+ std::chrono::steady_clock::now () - tActivate).count ();
918+ LOG_INFO (" [PresetSwitch] Activate=" + std::to_string (usActivate / 1000 .0f ) + " ms" );
919+
920+ m_framesAfterSwitch = 0 ;
863921
864922 ctx->state .store (PresetSwitchState::Completed, std::memory_order_release);
865923}
0 commit comments