diff --git a/Source/Core/VideoBackends/D3D/Render.cpp b/Source/Core/VideoBackends/D3D/Render.cpp index fa0fe3581e..7ee261d912 100644 --- a/Source/Core/VideoBackends/D3D/Render.cpp +++ b/Source/Core/VideoBackends/D3D/Render.cpp @@ -745,22 +745,6 @@ bool Renderer::SaveScreenshot(const std::string& filename, const TargetRectangle return saved_png; } -void formatBufferDump(const u8* in, u8* out, int w, int h, int p) -{ - for (int y = 0; y < h; ++y) - { - auto line = (in + (h - y - 1) * p); - for (int x = 0; x < w; ++x) - { - out[0] = line[2]; - out[1] = line[1]; - out[2] = line[0]; - out += 3; - line += 4; - } - } -} - // This function has the final picture. We adjust the aspect ratio here. void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const EFBRectangle& rc, float Gamma) @@ -768,7 +752,6 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, if (Fifo::WillSkipCurrentFrame() || (!XFBWrited && !g_ActiveConfig.RealXFBEnabled()) || !fbWidth || !fbHeight) { - RepeatFrameDumpFrame(); Core::Callback_VideoCopiedToXFB(false); return; } @@ -778,7 +761,6 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, FramebufferManager::GetXFBSource(xfbAddr, fbStride, fbHeight, &xfbCount); if ((!xfbSourceList || xfbCount == 0) && g_ActiveConfig.bUseXFB && !g_ActiveConfig.bUseRealXFB) { - RepeatFrameDumpFrame(); Core::Callback_VideoCopiedToXFB(false); return; } @@ -888,11 +870,9 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, D3D11_MAPPED_SUBRESOURCE map; D3D::context->Map(s_screenshot_texture, 0, D3D11_MAP_READ, 0, &map); - // TODO: This convertion is not needed. Get rid of it. - std::vector image(source_width * source_height * 3); - formatBufferDump((u8*)map.pData, image.data(), source_width, source_height, map.RowPitch); - - DumpFrameData(image.data(), source_width, source_height, AVIDump::DumpFormat::FORMAT_BGR, true); + DumpFrameData(reinterpret_cast(map.pData), source_width, source_height, map.RowPitch, + AVIDump::DumpFormat::FORMAT_RGBA); + FinishFrameData(); D3D::context->Unmap(s_screenshot_texture, 0); } diff --git a/Source/Core/VideoBackends/D3D12/Render.cpp b/Source/Core/VideoBackends/D3D12/Render.cpp index fb1740d9ac..53d6eb3d7f 100644 --- a/Source/Core/VideoBackends/D3D12/Render.cpp +++ b/Source/Core/VideoBackends/D3D12/Render.cpp @@ -688,22 +688,6 @@ bool Renderer::SaveScreenshot(const std::string& filename, const TargetRectangle return saved_png; } -void formatBufferDump(const u8* in, u8* out, int w, int h, int p) -{ - for (int y = 0; y < h; ++y) - { - auto line = (in + (h - y - 1) * p); - for (int x = 0; x < w; ++x) - { - out[0] = line[2]; - out[1] = line[1]; - out[2] = line[0]; - out += 3; - line += 4; - } - } -} - // This function has the final picture. We adjust the aspect ratio here. void Renderer::SwapImpl(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height, const EFBRectangle& rc, float gamma) @@ -711,7 +695,6 @@ void Renderer::SwapImpl(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height if (Fifo::WillSkipCurrentFrame() || (!XFBWrited && !g_ActiveConfig.RealXFBEnabled()) || !fb_width || !fb_height) { - RepeatFrameDumpFrame(); Core::Callback_VideoCopiedToXFB(false); return; } @@ -721,7 +704,6 @@ void Renderer::SwapImpl(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height FramebufferManager::GetXFBSource(xfb_addr, fb_stride, fb_height, &xfb_count); if ((!xfb_source_list || xfb_count == 0) && g_ActiveConfig.bUseXFB && !g_ActiveConfig.bUseRealXFB) { - RepeatFrameDumpFrame(); Core::Callback_VideoCopiedToXFB(false); return; } @@ -865,12 +847,10 @@ void Renderer::SwapImpl(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height D3D12_RANGE read_range = {0, dst_location.PlacedFootprint.Footprint.RowPitch * source_height}; CheckHR(s_screenshot_texture->Map(0, &read_range, &screenshot_texture_map)); - // TODO: This convertion is not needed. Get rid of it. - std::vector image(source_width * source_height * 3); - formatBufferDump(static_cast(screenshot_texture_map), image.data(), source_width, - source_height, dst_location.PlacedFootprint.Footprint.RowPitch); - - DumpFrameData(image.data(), source_width, source_height, AVIDump::DumpFormat::FORMAT_BGR, true); + DumpFrameData(reinterpret_cast(screenshot_texture_map), source_width, source_height, + dst_location.PlacedFootprint.Footprint.RowPitch, + AVIDump::DumpFormat::FORMAT_RGBA); + FinishFrameData(); D3D12_RANGE write_range = {}; s_screenshot_texture->Unmap(0, &write_range); diff --git a/Source/Core/VideoBackends/OGL/Render.cpp b/Source/Core/VideoBackends/OGL/Render.cpp index 2f53d0e9a6..4b8b638212 100644 --- a/Source/Core/VideoBackends/OGL/Render.cpp +++ b/Source/Core/VideoBackends/OGL/Render.cpp @@ -1353,7 +1353,6 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, if (Fifo::WillSkipCurrentFrame() || (!XFBWrited && !g_ActiveConfig.RealXFBEnabled()) || !fbWidth || !fbHeight) { - RepeatFrameDumpFrame(); Core::Callback_VideoCopiedToXFB(false); return; } @@ -1363,7 +1362,6 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, FramebufferManager::GetXFBSource(xfbAddr, fbStride, fbHeight, &xfbCount); if (g_ActiveConfig.VirtualXFBEnabled() && (!xfbSourceList || xfbCount == 0)) { - RepeatFrameDumpFrame(); Core::Callback_VideoCopiedToXFB(false); return; } @@ -1471,7 +1469,8 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, flipped_trc.GetHeight(), GL_RGBA, GL_UNSIGNED_BYTE, image.data()); DumpFrameData(image.data(), flipped_trc.GetWidth(), flipped_trc.GetHeight(), - AVIDump::DumpFormat::FORMAT_RGBA, true); + flipped_trc.GetWidth() * 4, AVIDump::DumpFormat::FORMAT_RGBA, true); + FinishFrameData(); } // Finish up the current frame, print some stats diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.cpp b/Source/Core/VideoBackends/Vulkan/Renderer.cpp index e149e17118..f164f132a7 100644 --- a/Source/Core/VideoBackends/Vulkan/Renderer.cpp +++ b/Source/Core/VideoBackends/Vulkan/Renderer.cpp @@ -496,7 +496,9 @@ void Renderer::SwapImpl(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height DumpFrameData(reinterpret_cast(m_screenshot_readback_texture->GetMapPointer()), static_cast(m_screenshot_render_texture->GetWidth()), static_cast(m_screenshot_render_texture->GetHeight()), + static_cast(m_screenshot_readback_texture->GetRowStride()), AVIDump::DumpFormat::FORMAT_RGBA); + FinishFrameData(); } } diff --git a/Source/Core/VideoCommon/AVIDump.cpp b/Source/Core/VideoCommon/AVIDump.cpp index d31601d545..ab5b99c993 100644 --- a/Source/Core/VideoCommon/AVIDump.cpp +++ b/Source/Core/VideoCommon/AVIDump.cpp @@ -37,7 +37,6 @@ static AVStream* s_stream = nullptr; static AVFrame* s_src_frame = nullptr; static AVFrame* s_scaled_frame = nullptr; static AVPixelFormat s_pix_fmt = AV_PIX_FMT_BGR24; -static int s_bytes_per_pixel; static SwsContext* s_sws_context = nullptr; static int s_width; static int s_height; @@ -52,6 +51,7 @@ static AVIDump::DumpFormat s_current_format; static const u8* s_stored_frame_data; static int s_stored_frame_width; static int s_stored_frame_height; +static int s_stored_frame_stride; static void InitAVCodec() { @@ -68,12 +68,10 @@ bool AVIDump::Start(int w, int h, DumpFormat format) if (format == DumpFormat::FORMAT_BGR) { s_pix_fmt = AV_PIX_FMT_BGR24; - s_bytes_per_pixel = 3; } else { s_pix_fmt = AV_PIX_FMT_RGBA; - s_bytes_per_pixel = 4; } s_current_format = format; @@ -181,18 +179,18 @@ static void PreparePacket(AVPacket* pkt) pkt->size = 0; } -void AVIDump::AddFrame(const u8* data, int width, int height) +void AVIDump::AddFrame(const u8* data, int width, int height, int stride) { // Store current frame data in case frame dumping stops before next frame update, // but make sure that you don't store the last stored frame and check the resolution upon // closing the file or else you store recursion, and dolphins don't like recursion. if (!s_stop_dumping) { - StoreFrameData(data, width, height); + StoreFrameData(data, width, height, stride); CheckResolution(width, height); } s_src_frame->data[0] = const_cast(data); - s_src_frame->linesize[0] = width * s_bytes_per_pixel; + s_src_frame->linesize[0] = stride; s_src_frame->format = s_pix_fmt; s_src_frame->width = s_width; s_src_frame->height = s_height; @@ -267,7 +265,7 @@ void AVIDump::Stop() { s_stop_dumping = true; // Write the last stored frame just in case frame dumping stops before the next frame update - AddFrame(s_stored_frame_data, s_stored_frame_width, s_stored_frame_height); + AddFrame(s_stored_frame_data, s_stored_frame_width, s_stored_frame_height, s_stored_frame_stride); av_write_trailer(s_format_context); CloseFile(); s_file_index = 0; @@ -328,9 +326,10 @@ void AVIDump::CheckResolution(int width, int height) } } -void AVIDump::StoreFrameData(const u8* data, int width, int height) +void AVIDump::StoreFrameData(const u8* data, int width, int height, int stride) { s_stored_frame_data = data; s_stored_frame_width = width; s_stored_frame_height = height; + s_stored_frame_stride = stride; } diff --git a/Source/Core/VideoCommon/AVIDump.h b/Source/Core/VideoCommon/AVIDump.h index 6b0837f789..a3b2ef4bd5 100644 --- a/Source/Core/VideoCommon/AVIDump.h +++ b/Source/Core/VideoCommon/AVIDump.h @@ -12,7 +12,7 @@ private: static bool CreateFile(); static void CloseFile(); static void CheckResolution(int width, int height); - static void StoreFrameData(const u8* data, int width, int height); + static void StoreFrameData(const u8* data, int width, int height, int stride); public: enum class DumpFormat @@ -22,7 +22,7 @@ public: }; static bool Start(int w, int h, DumpFormat format); - static void AddFrame(const u8* data, int width, int height); + static void AddFrame(const u8* data, int width, int height, int stride); static void Stop(); static void DoState(); }; diff --git a/Source/Core/VideoCommon/RenderBase.cpp b/Source/Core/VideoCommon/RenderBase.cpp index 1dd07c905b..e523fd8a67 100644 --- a/Source/Core/VideoCommon/RenderBase.cpp +++ b/Source/Core/VideoCommon/RenderBase.cpp @@ -555,31 +555,20 @@ bool Renderer::IsFrameDumping() return false; } -void Renderer::DumpFrameData(const u8* data, int w, int h, AVIDump::DumpFormat format, +void Renderer::DumpFrameData(const u8* data, int w, int h, int stride, AVIDump::DumpFormat format, bool swap_upside_down) { #if defined(HAVE_LIBAV) || defined(_WIN32) if (w == 0 || h == 0) return; - size_t image_size; - switch (format) - { - case AVIDump::DumpFormat::FORMAT_BGR: - image_size = 3 * w * h; - break; - case AVIDump::DumpFormat::FORMAT_RGBA: - image_size = 4 * w * h; - break; - } - m_last_framedump_width = w; m_last_framedump_height = h; m_last_framedump_format = format; + m_last_framedump_stride = stride; // TODO: Refactor this. Right now it's needed for the implace flipping of the image. - // It's also used to repeat the last frame. - m_frame_data.assign(data, data + image_size); + m_frame_data.assign(data, data + stride * h); if (!m_last_frame_dumped) { @@ -599,21 +588,15 @@ void Renderer::DumpFrameData(const u8* data, int w, int h, AVIDump::DumpFormat f { if (swap_upside_down) FlipImageData(m_frame_data.data(), w, h, 4); - AVIDump::AddFrame(m_frame_data.data(), w, h); + AVIDump::AddFrame(m_frame_data.data(), w, h, stride); } m_last_frame_dumped = true; #endif } -void Renderer::RepeatFrameDumpFrame() +void Renderer::FinishFrameData() { -#if defined(HAVE_LIBAV) || defined(_WIN32) - if (SConfig::GetInstance().m_DumpFrames && m_AVI_dumping && !m_frame_data.empty()) - { - AVIDump::AddFrame(m_frame_data.data(), m_last_framedump_width, m_last_framedump_height); - } -#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 1f648bb17b..9a78ce4a4b 100644 --- a/Source/Core/VideoCommon/RenderBase.h +++ b/Source/Core/VideoCommon/RenderBase.h @@ -148,9 +148,9 @@ protected: static void RecordVideoMemory(); bool IsFrameDumping(); - void DumpFrameData(const u8* data, int w, int h, AVIDump::DumpFormat format, + void DumpFrameData(const u8* data, int w, int h, int stride, AVIDump::DumpFormat format, bool swap_upside_down = false); - void RepeatFrameDumpFrame(); + void FinishFrameData(); static volatile bool s_bScreenshot; static std::mutex s_criticalScreenshot; @@ -194,6 +194,7 @@ private: bool m_last_frame_dumped = false; int m_last_framedump_width = 0; int m_last_framedump_height = 0; + int m_last_framedump_stride = 0; AVIDump::DumpFormat m_last_framedump_format; };