From d79840078f8384c36c61533b9642215a0c491341 Mon Sep 17 00:00:00 2001 From: degasus Date: Sat, 8 Oct 2016 03:11:37 +0200 Subject: [PATCH 1/2] Renderer: Threaded frame dumping. --- Source/Core/VideoCommon/AVIDump.cpp | 1 + Source/Core/VideoCommon/RenderBase.cpp | 146 ++++++++++++++++--------- Source/Core/VideoCommon/RenderBase.h | 24 +++- 3 files changed, 118 insertions(+), 53 deletions(-) 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; From a47332bf8a0f2b98a0b7043088d13d9fc0f44b30 Mon Sep 17 00:00:00 2001 From: degasus Date: Mon, 7 Nov 2016 22:16:34 +0100 Subject: [PATCH 2/2] VideoCommon/Render: Use a flag for screenshot. --- Source/Core/VideoCommon/RenderBase.cpp | 10 ++++------ Source/Core/VideoCommon/RenderBase.h | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/Source/Core/VideoCommon/RenderBase.cpp b/Source/Core/VideoCommon/RenderBase.cpp index b1823a9126..94d51ee481 100644 --- a/Source/Core/VideoCommon/RenderBase.cpp +++ b/Source/Core/VideoCommon/RenderBase.cpp @@ -62,8 +62,7 @@ std::mutex Renderer::s_criticalScreenshot; std::string Renderer::s_sScreenshotName; Common::Event Renderer::s_screenshotCompleted; - -volatile bool Renderer::s_bScreenshot; +Common::Flag Renderer::s_screenshot; // The framebuffer size int Renderer::s_target_width; @@ -303,7 +302,7 @@ void Renderer::SetScreenshot(const std::string& filename) { std::lock_guard lk(s_criticalScreenshot); s_sScreenshotName = filename; - s_bScreenshot = true; + s_screenshot.Set(); } // Create On-Screen-Messages @@ -644,7 +643,7 @@ void Renderer::Swap(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const bool Renderer::IsFrameDumping() { - if (s_bScreenshot) + if (s_screenshot.IsSet()) return true; #if defined(HAVE_LIBAV) || defined(_WIN32) @@ -718,7 +717,7 @@ void Renderer::RunFrameDumps() FlipImageData(data.data(), config.width, config.height, 4); // Save screenshot - if (s_bScreenshot) + if (s_screenshot.TestAndClear()) { std::lock_guard lk(s_criticalScreenshot); @@ -728,7 +727,6 @@ void Renderer::RunFrameDumps() // Reset settings s_sScreenshotName.clear(); - s_bScreenshot = false; s_screenshotCompleted.Set(); } diff --git a/Source/Core/VideoCommon/RenderBase.h b/Source/Core/VideoCommon/RenderBase.h index 80b4a88161..2de4034bdf 100644 --- a/Source/Core/VideoCommon/RenderBase.h +++ b/Source/Core/VideoCommon/RenderBase.h @@ -153,7 +153,7 @@ protected: bool swap_upside_down = false); void FinishFrameData(); - static volatile bool s_bScreenshot; + static Common::Flag s_screenshot; static std::mutex s_criticalScreenshot; static std::string s_sScreenshotName;