diff --git a/Source/Core/VideoCommon/AVIDump.cpp b/Source/Core/VideoCommon/AVIDump.cpp index b442afd9fe..ce1b377045 100644 --- a/Source/Core/VideoCommon/AVIDump.cpp +++ b/Source/Core/VideoCommon/AVIDump.cpp @@ -260,6 +260,7 @@ void AVIDump::Stop() CloseFile(); s_file_index = 0; NOTICE_LOG(VIDEO, "Stopping frame dump"); + OSD::AddMessage("Stopped dumping frames"); } void AVIDump::CloseFile() diff --git a/Source/Core/VideoCommon/RenderBase.cpp b/Source/Core/VideoCommon/RenderBase.cpp index 65f716ba9e..b1823a9126 100644 --- a/Source/Core/VideoCommon/RenderBase.cpp +++ b/Source/Core/VideoCommon/RenderBase.cpp @@ -24,6 +24,7 @@ #include "Common/Flag.h" #include "Common/Profiler.h" #include "Common/StringUtil.h" +#include "Common/Thread.h" #include "Common/Timer.h" #include "Core/ConfigManager.h" @@ -118,14 +119,9 @@ Renderer::~Renderer() efb_scale_numeratorX = efb_scale_numeratorY = efb_scale_denominatorX = efb_scale_denominatorY = 1; -#if defined(HAVE_LIBAV) || defined(_WIN32) - // Stop frame dumping if it was left enabled at shutdown time. - if (m_AVI_dumping) - { - AVIDump::Stop(); - m_AVI_dumping = false; - } -#endif + ShutdownFrameDumping(); + if (m_frame_dump_thread.joinable()) + m_frame_dump_thread.join(); } void Renderer::RenderToXFB(u32 xfbAddr, const EFBRectangle& sourceRc, u32 fbStride, u32 fbHeight, @@ -654,63 +650,115 @@ bool Renderer::IsFrameDumping() #if defined(HAVE_LIBAV) || defined(_WIN32) if (SConfig::GetInstance().m_DumpFrames) return true; - - if (m_last_frame_dumped && m_AVI_dumping) - { - AVIDump::Stop(); - std::vector().swap(m_frame_data); - m_AVI_dumping = false; - OSD::AddMessage("Stop dumping frames"); - } - m_last_frame_dumped = false; #endif + + ShutdownFrameDumping(); return false; } +void Renderer::ShutdownFrameDumping() +{ + if (!m_frame_dump_thread_running.IsSet()) + return; + + FinishFrameData(); + m_frame_dump_thread_running.Clear(); + m_frame_dump_start.Set(); +} + void Renderer::DumpFrameData(const u8* data, int w, int h, int stride, const AVIDump::Frame& state, bool swap_upside_down) { - if (w == 0 || h == 0) - return; + FinishFrameData(); - // TODO: Refactor this. Right now it's needed for the implace flipping of the image. - m_frame_data.assign(data, data + stride * h); - if (swap_upside_down) - FlipImageData(m_frame_data.data(), w, h, 4); + m_frame_dump_config = FrameDumpConfig{data, w, h, stride, swap_upside_down, state}; - // Save screenshot - if (s_bScreenshot) + if (!m_frame_dump_thread_running.IsSet()) { - std::lock_guard lk(s_criticalScreenshot); - - if (TextureToPng(m_frame_data.data(), stride, s_sScreenshotName, w, h, false)) - OSD::AddMessage("Screenshot saved to " + s_sScreenshotName); - - // Reset settings - s_sScreenshotName.clear(); - s_bScreenshot = false; - s_screenshotCompleted.Set(); + if (m_frame_dump_thread.joinable()) + m_frame_dump_thread.join(); + m_frame_dump_thread_running.Set(); + m_frame_dump_thread = std::thread(&Renderer::RunFrameDumps, this); } -#if defined(HAVE_LIBAV) || defined(_WIN32) - if (SConfig::GetInstance().m_DumpFrames) - { - if (!m_last_frame_dumped) - { - m_AVI_dumping = AVIDump::Start(w, h); - } - if (m_AVI_dumping) - { - AVIDump::AddFrame(m_frame_data.data(), w, h, stride, state); - } - - m_last_frame_dumped = true; - } -#endif + m_frame_dump_start.Set(); + m_frame_dump_frame_running = true; } void Renderer::FinishFrameData() { + if (!m_frame_dump_frame_running) + return; + + m_frame_dump_done.Wait(); + m_frame_dump_frame_running = false; +} + +void Renderer::RunFrameDumps() +{ + Common::SetCurrentThreadName("FrameDumping"); + bool avi_dump_started = false; + std::vector data; + + while (true) + { + m_frame_dump_start.Wait(); + if (!m_frame_dump_thread_running.IsSet()) + break; + + const auto config = m_frame_dump_config; + + // TODO: Refactor this. Right now it's needed for the implace flipping of the image. + data.assign(config.data, config.data + config.stride * config.height); + + // As we've done a copy now, there is no need to block the GPU thread any longer. + m_frame_dump_done.Set(); + + if (config.upside_down) + FlipImageData(data.data(), config.width, config.height, 4); + + // Save screenshot + if (s_bScreenshot) + { + std::lock_guard lk(s_criticalScreenshot); + + if (TextureToPng(data.data(), config.stride, s_sScreenshotName, config.width, config.height, + false)) + OSD::AddMessage("Screenshot saved to " + s_sScreenshotName); + + // Reset settings + s_sScreenshotName.clear(); + s_bScreenshot = false; + s_screenshotCompleted.Set(); + } + +#if defined(HAVE_LIBAV) || defined(_WIN32) + if (SConfig::GetInstance().m_DumpFrames) + { + if (!avi_dump_started) + { + if (AVIDump::Start(config.width, config.height)) + { + avi_dump_started = true; + } + else + { + SConfig::GetInstance().m_DumpFrames = false; + } + } + + AVIDump::AddFrame(data.data(), config.width, config.height, config.stride, config.state); + } +#endif + } + +#if defined(HAVE_LIBAV) || defined(_WIN32) + if (avi_dump_started) + { + avi_dump_started = false; + AVIDump::Stop(); + } +#endif } void Renderer::FlipImageData(u8* data, int w, int h, int pixel_width) diff --git a/Source/Core/VideoCommon/RenderBase.h b/Source/Core/VideoCommon/RenderBase.h index f3526e8516..80b4a88161 100644 --- a/Source/Core/VideoCommon/RenderBase.h +++ b/Source/Core/VideoCommon/RenderBase.h @@ -14,9 +14,11 @@ #pragma once +#include #include #include #include +#include #include #include "Common/CommonTypes.h" @@ -181,16 +183,30 @@ protected: static void* s_new_surface_handle; private: + void RunFrameDumps(); + void ShutdownFrameDumping(); + static PEControl::PixelFormat prev_efb_format; static unsigned int efb_scale_numeratorX; static unsigned int efb_scale_numeratorY; static unsigned int efb_scale_denominatorX; static unsigned int efb_scale_denominatorY; - // framedumping - std::vector m_frame_data; - bool m_AVI_dumping = false; - bool m_last_frame_dumped = false; + // frame dumping + std::thread m_frame_dump_thread; + Common::Event m_frame_dump_start; + Common::Event m_frame_dump_done; + Common::Flag m_frame_dump_thread_running; + bool m_frame_dump_frame_running = false; + struct FrameDumpConfig + { + const u8* data; + int width; + int height; + int stride; + bool upside_down; + AVIDump::Frame state; + } m_frame_dump_config; }; extern std::unique_ptr g_renderer;