Merge pull request #4345 from degasus/framedump_threaded
Renderer: Threaded frame dumping.
This commit is contained in:
commit
5378b6ab85
|
@ -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()
|
||||
|
|
|
@ -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"
|
||||
|
@ -61,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;
|
||||
|
@ -118,14 +118,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,
|
||||
|
@ -307,7 +302,7 @@ void Renderer::SetScreenshot(const std::string& filename)
|
|||
{
|
||||
std::lock_guard<std::mutex> lk(s_criticalScreenshot);
|
||||
s_sScreenshotName = filename;
|
||||
s_bScreenshot = true;
|
||||
s_screenshot.Set();
|
||||
}
|
||||
|
||||
// Create On-Screen-Messages
|
||||
|
@ -648,69 +643,120 @@ 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)
|
||||
if (SConfig::GetInstance().m_DumpFrames)
|
||||
return true;
|
||||
|
||||
if (m_last_frame_dumped && m_AVI_dumping)
|
||||
{
|
||||
AVIDump::Stop();
|
||||
std::vector<u8>().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)
|
||||
FinishFrameData();
|
||||
|
||||
m_frame_dump_config = FrameDumpConfig{data, w, h, stride, swap_upside_down, state};
|
||||
|
||||
if (!m_frame_dump_thread_running.IsSet())
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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<u8> 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.
|
||||
m_frame_data.assign(data, data + stride * h);
|
||||
if (swap_upside_down)
|
||||
FlipImageData(m_frame_data.data(), w, h, 4);
|
||||
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)
|
||||
if (s_screenshot.TestAndClear())
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(s_criticalScreenshot);
|
||||
|
||||
if (TextureToPng(m_frame_data.data(), stride, s_sScreenshotName, w, h, false))
|
||||
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 (!m_last_frame_dumped)
|
||||
if (!avi_dump_started)
|
||||
{
|
||||
m_AVI_dumping = AVIDump::Start(w, h);
|
||||
if (AVIDump::Start(config.width, config.height))
|
||||
{
|
||||
avi_dump_started = true;
|
||||
}
|
||||
if (m_AVI_dumping)
|
||||
else
|
||||
{
|
||||
AVIDump::AddFrame(m_frame_data.data(), w, h, stride, state);
|
||||
SConfig::GetInstance().m_DumpFrames = false;
|
||||
}
|
||||
}
|
||||
|
||||
m_last_frame_dumped = true;
|
||||
AVIDump::AddFrame(data.data(), config.width, config.height, config.stride, config.state);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::FinishFrameData()
|
||||
{
|
||||
#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)
|
||||
|
|
|
@ -14,9 +14,11 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <condition_variable>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
|
@ -151,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;
|
||||
|
||||
|
@ -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<u8> 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<Renderer> g_renderer;
|
||||
|
|
Loading…
Reference in New Issue