@@ -1409,17 +1409,13 @@ void Renderer::DumpCurrentFrame(const AbstractTexture* src_texture,
copy_rect = src_texture->GetRect ();
}
// Index 0 was just sent to FFMPEG dump. Swap with the second texture.
if (m_frame_dump_readback_textures[0 ])
std::swap (m_frame_dump_readback_textures[0 ], m_frame_dump_readback_textures[1 ]);
if (!CheckFrameDumpReadbackTexture (target_width, target_height))
return ;
m_frame_dump_readback_textures[ 0 ] ->CopyFromTexture (src_texture, copy_rect, 0 , 0 ,
m_frame_dump_readback_textures[ 0 ] ->GetRect ());
m_last_frame_state = FrameDump:: FetchState (ticks);
m_last_frame_exported = true ;
m_frame_dump_readback_texture ->CopyFromTexture (src_texture, copy_rect, 0 , 0 ,
m_frame_dump_readback_texture ->GetRect ());
m_last_frame_state = m_frame_dump. FetchState (ticks);
m_frame_dump_needs_flush = true ;
}
bool Renderer::CheckFrameDumpRenderTexture (u32 target_width, u32 target_height)
@@ -1450,7 +1446,7 @@ bool Renderer::CheckFrameDumpRenderTexture(u32 target_width, u32 target_height)
bool Renderer::CheckFrameDumpReadbackTexture (u32 target_width, u32 target_height)
{
std::unique_ptr<AbstractStagingTexture>& rbtex = m_frame_dump_readback_textures[ 0 ] ;
std::unique_ptr<AbstractStagingTexture>& rbtex = m_frame_dump_readback_texture ;
if (rbtex && rbtex->GetWidth () == target_width && rbtex->GetHeight () == target_height)
return true ;
@@ -1466,24 +1462,28 @@ bool Renderer::CheckFrameDumpReadbackTexture(u32 target_width, u32 target_height
void Renderer::FlushFrameDump ()
{
if (!m_last_frame_exported )
if (!m_frame_dump_needs_flush )
return ;
// Ensure the previously-queued frame was encoded .
// Ensure dumping thread is done with output texture before swapping .
FinishFrameData ();
std::swap (m_frame_dump_output_texture, m_frame_dump_readback_texture);
// Queue encoding of the last frame dumped.
std::unique_ptr<AbstractStagingTexture>& rbtex = m_frame_dump_readback_textures[0 ];
rbtex->Flush ();
if (rbtex->Map ())
auto & output = m_frame_dump_output_texture;
output->Flush ();
if (output->Map ())
{
DumpFrameData (reinterpret_cast <u8*>(output->GetMappedPointer ()), output->GetConfig ().width ,
output->GetConfig ().height , static_cast <int >(output->GetMappedStride ()));
}
else
{
DumpFrameData (reinterpret_cast <u8*>(rbtex->GetMappedPointer ()), rbtex->GetConfig ().width ,
rbtex->GetConfig ().height , static_cast <int >(rbtex->GetMappedStride ()),
m_last_frame_state);
rbtex->Unmap ();
ERROR_LOG (VIDEO, " Failed to map texture for dumping." );
}
m_last_frame_exported = false ;
m_frame_dump_needs_flush = false ;
// Shutdown frame dumping if it is no longer active.
if (!IsFrameDumping ())
@@ -1508,21 +1508,21 @@ void Renderer::ShutdownFrameDumping()
m_frame_dump_thread.join ();
m_frame_dump_render_framebuffer.reset ();
m_frame_dump_render_texture.reset ();
for (auto & tex : m_frame_dump_readback_textures)
tex.reset ();
m_frame_dump_readback_texture.reset ();
m_frame_dump_output_texture.reset ();
}
void Renderer::DumpFrameData (const u8* data, int w, int h, int stride,
const FrameDump::Frame& state)
void Renderer::DumpFrameData (const u8* data, int w, int h, int stride)
{
m_frame_dump_config = FrameDumpConfig {data, w, h, stride, state };
m_frame_dump_data = FrameDump::FrameData {data, w, h, stride, m_last_frame_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_thread = std::thread (&Renderer::FrameDumpThreadFunc , this );
}
// Wake worker thread up.
@@ -1537,11 +1537,14 @@ void Renderer::FinishFrameData()
m_frame_dump_done.Wait ();
m_frame_dump_frame_running = false ;
m_frame_dump_output_texture->Unmap ();
}
void Renderer::RunFrameDumps ()
void Renderer::FrameDumpThreadFunc ()
{
Common::SetCurrentThreadName (" FrameDumping" );
bool dump_to_ffmpeg = !g_ActiveConfig.bDumpFramesAsImages ;
bool frame_dump_started = false ;
@@ -1561,14 +1564,14 @@ void Renderer::RunFrameDumps()
if (!m_frame_dump_thread_running.IsSet ())
break ;
auto config = m_frame_dump_config ;
auto frame = m_frame_dump_data ;
// Save screenshot
if (m_screenshot_request.TestAndClear ())
{
std::lock_guard<std::mutex> lk (m_screenshot_lock);
if (TextureToPng (config .data , config .stride , m_screenshot_name, config .width , config .height ,
if (TextureToPng (frame .data , frame .stride , m_screenshot_name, frame .width , frame .height ,
false ))
OSD::AddMessage (" Screenshot saved to " + m_screenshot_name);
@@ -1582,9 +1585,9 @@ void Renderer::RunFrameDumps()
if (!frame_dump_started)
{
if (dump_to_ffmpeg)
frame_dump_started = StartFrameDumpToFFMPEG (config );
frame_dump_started = StartFrameDumpToFFMPEG (frame );
else
frame_dump_started = StartFrameDumpToImage (config );
frame_dump_started = StartFrameDumpToImage (frame );
// Stop frame dumping if we fail to start.
if (!frame_dump_started)
@@ -1595,9 +1598,9 @@ void Renderer::RunFrameDumps()
if (frame_dump_started)
{
if (dump_to_ffmpeg)
DumpFrameToFFMPEG (config );
DumpFrameToFFMPEG (frame );
else
DumpFrameToImage (config );
DumpFrameToImage (frame );
}
}
@@ -1614,29 +1617,29 @@ void Renderer::RunFrameDumps()
#if defined(HAVE_FFMPEG)
bool Renderer::StartFrameDumpToFFMPEG (const FrameDumpConfig& config )
bool Renderer::StartFrameDumpToFFMPEG (const FrameDump::FrameData& frame )
{
return FrameDump:: Start (config .width , config .height );
return m_frame_dump. Start (frame .width , frame .height );
}
void Renderer::DumpFrameToFFMPEG (const FrameDumpConfig& config )
void Renderer::DumpFrameToFFMPEG (const FrameDump::FrameData& frame )
{
FrameDump:: AddFrame (config. data , config. width , config. height , config. stride , config. state );
m_frame_dump. AddFrame (frame );
}
void Renderer::StopFrameDumpToFFMPEG ()
{
FrameDump:: Stop ();
m_frame_dump. Stop ();
}
#else
bool Renderer::StartFrameDumpToFFMPEG (const FrameDumpConfig& config )
bool Renderer::StartFrameDumpToFFMPEG (const FrameDump::FrameData& )
{
return false ;
}
void Renderer::DumpFrameToFFMPEG (const FrameDumpConfig& config )
void Renderer::DumpFrameToFFMPEG (const FrameDump::FrameData& )
{
}
@@ -1652,7 +1655,7 @@ std::string Renderer::GetFrameDumpNextImageFileName() const
m_frame_dump_image_counter);
}
bool Renderer::StartFrameDumpToImage (const FrameDumpConfig& config )
bool Renderer::StartFrameDumpToImage (const FrameDump::FrameData& )
{
m_frame_dump_image_counter = 1 ;
if (!SConfig::GetInstance ().m_DumpFramesSilent )
@@ -1671,10 +1674,10 @@ bool Renderer::StartFrameDumpToImage(const FrameDumpConfig& config)
return true ;
}
void Renderer::DumpFrameToImage (const FrameDumpConfig& config )
void Renderer::DumpFrameToImage (const FrameDump::FrameData& frame )
{
std::string filename = GetFrameDumpNextImageFileName ();
TextureToPng (config .data , config .stride , filename, config .width , config .height , false );
TextureToPng (frame .data , frame .stride , filename, frame .width , frame .height , false );
m_frame_dump_image_counter++;
}
@@ -1718,6 +1721,10 @@ void Renderer::DoState(PointerWrap& p)
// And actually display it.
Swap (m_last_xfb_addr, m_last_xfb_width, m_last_xfb_stride, m_last_xfb_height, m_last_xfb_ticks);
}
#if defined(HAVE_FFMPEG)
m_frame_dump.DoState (p);
#endif
}
std::unique_ptr<VideoCommon::AsyncShaderCompiler> Renderer::CreateAsyncShaderCompiler ()