mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-02-10 21:40:43 +00:00
rsx/qt: add recording to game window
This commit is contained in:
parent
a3bcb6c15a
commit
b0e376ae76
@ -1,9 +1,12 @@
|
||||
#include "stdafx.h"
|
||||
#include "GLGSRender.h"
|
||||
#include "Emu/Cell/Modules/cellVideoOut.h"
|
||||
#include "util/video_provider.h"
|
||||
|
||||
LOG_CHANNEL(screenshot_log, "SCREENSHOT");
|
||||
|
||||
extern atomic_t<recording_mode> g_recording_mode;
|
||||
|
||||
namespace gl
|
||||
{
|
||||
namespace debug
|
||||
@ -232,10 +235,8 @@ void GLGSRender::flip(const rsx::display_flip_info_t& info)
|
||||
|
||||
if (image_to_flip)
|
||||
{
|
||||
if (m_frame->screenshot_toggle)
|
||||
if (m_frame->screenshot_toggle || (g_recording_mode != recording_mode::stopped && m_frame->can_consume_frame()))
|
||||
{
|
||||
m_frame->screenshot_toggle = false;
|
||||
|
||||
std::vector<u8> sshot_frame(buffer_height * buffer_width * 4);
|
||||
|
||||
gl::pixel_pack_settings pack_settings{};
|
||||
@ -246,10 +247,19 @@ void GLGSRender::flip(const rsx::display_flip_info_t& info)
|
||||
else
|
||||
glGetTextureImageEXT(image_to_flip, GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, sshot_frame.data());
|
||||
|
||||
if (GLenum err; (err = glGetError()) != GL_NO_ERROR)
|
||||
if (GLenum err = glGetError(); err != GL_NO_ERROR)
|
||||
{
|
||||
screenshot_log.error("Failed to capture image: 0x%x", err);
|
||||
else
|
||||
}
|
||||
else if (m_frame->screenshot_toggle)
|
||||
{
|
||||
m_frame->screenshot_toggle = false;
|
||||
m_frame->take_screenshot(std::move(sshot_frame), buffer_width, buffer_height, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_frame->present_frame(sshot_frame, buffer_width, buffer_height, false);
|
||||
}
|
||||
}
|
||||
|
||||
const areai screen_area = coordi({}, { static_cast<int>(buffer_width), static_cast<int>(buffer_height) });
|
||||
|
@ -30,5 +30,7 @@ public:
|
||||
virtual display_handle_t handle() const = 0;
|
||||
|
||||
atomic_t<bool> screenshot_toggle = false;
|
||||
virtual bool can_consume_frame() const = 0;
|
||||
virtual void present_frame(std::vector<u8>& data, const u32 width, const u32 height, bool is_bgra) const = 0;
|
||||
virtual void take_screenshot(const std::vector<u8> sshot_data, const u32 sshot_width, const u32 sshot_height, bool is_bgra) = 0;
|
||||
};
|
||||
|
@ -7,6 +7,9 @@
|
||||
#include "upscalers/bilinear_pass.hpp"
|
||||
#include "upscalers/fsr_pass.h"
|
||||
#include "util/asm.hpp"
|
||||
#include "util/video_provider.h"
|
||||
|
||||
extern atomic_t<recording_mode> g_recording_mode;
|
||||
|
||||
void VKGSRender::reinitialize_swapchain()
|
||||
{
|
||||
@ -667,10 +670,8 @@ void VKGSRender::flip(const rsx::display_flip_info_t& info)
|
||||
m_upscaler->scale_output(*m_current_command_buffer, image_to_flip, target_image, target_layout, rgn, UPSCALE_AND_COMMIT | UPSCALE_DEFAULT_VIEW);
|
||||
}
|
||||
|
||||
if (m_frame->screenshot_toggle)
|
||||
if (m_frame->screenshot_toggle || (g_recording_mode != recording_mode::stopped && m_frame->can_consume_frame()))
|
||||
{
|
||||
m_frame->screenshot_toggle = false;
|
||||
|
||||
const usz sshot_size = buffer_height * buffer_width * 4;
|
||||
|
||||
vk::buffer sshot_vkbuf(*m_device, utils::align(sshot_size, 0x100000), m_device->get_memory_mapping().host_visible_coherent,
|
||||
@ -702,7 +703,16 @@ void VKGSRender::flip(const rsx::display_flip_info_t& info)
|
||||
sshot_vkbuf.unmap();
|
||||
|
||||
const bool is_bgra = image_to_flip->format() == VK_FORMAT_B8G8R8A8_UNORM;
|
||||
m_frame->take_screenshot(std::move(sshot_frame), buffer_width, buffer_height, is_bgra);
|
||||
|
||||
if (m_frame->screenshot_toggle)
|
||||
{
|
||||
m_frame->screenshot_toggle = false;
|
||||
m_frame->take_screenshot(std::move(sshot_frame), buffer_width, buffer_height, is_bgra);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_frame->present_frame(sshot_frame, buffer_width, buffer_height, is_bgra);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "Utilities/Timer.h"
|
||||
#include "Utilities/date_time.h"
|
||||
#include "Utilities/File.h"
|
||||
#include "util/video_provider.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/system_config.h"
|
||||
#include "Emu/system_progress.hpp"
|
||||
@ -13,6 +14,7 @@
|
||||
#include "Emu/Cell/Modules/cellVideoOut.h"
|
||||
#include "Emu/RSX/rsx_utils.h"
|
||||
#include "Emu/RSX/Overlays/overlay_message.h"
|
||||
#include "Emu/Io/recording_config.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDateTime>
|
||||
@ -54,6 +56,7 @@ LOG_CHANNEL(gui_log, "GUI");
|
||||
|
||||
extern atomic_t<bool> g_user_asked_for_frame_capture;
|
||||
extern atomic_t<bool> g_disable_frame_limit;
|
||||
extern atomic_t<recording_mode> g_recording_mode;
|
||||
|
||||
atomic_t<bool> g_game_window_focused = false;
|
||||
|
||||
@ -78,6 +81,14 @@ gs_frame::gs_frame(QScreen* screen, const QRect& geometry, const QIcon& appIcon,
|
||||
|
||||
m_window_title = Emu.GetFormattedTitle(0);
|
||||
|
||||
if (!g_cfg_recording.load())
|
||||
{
|
||||
gui_log.notice("Could not load recording config. Using defaults.");
|
||||
}
|
||||
|
||||
g_fxo->need<utils::video_provider>();
|
||||
m_video_encoder = std::make_shared<utils::video_encoder>();
|
||||
|
||||
if (!appIcon.isNull())
|
||||
{
|
||||
setIcon(appIcon);
|
||||
@ -322,6 +333,94 @@ void gs_frame::keyPressEvent(QKeyEvent *keyEvent)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Qt::Key_F11:
|
||||
{
|
||||
utils::video_provider& video_provider = g_fxo->get<utils::video_provider>();
|
||||
|
||||
if (g_recording_mode == recording_mode::cell)
|
||||
{
|
||||
gui_log.warning("A video recorder is already in use by cell. Regular recording can not proceed.");
|
||||
m_video_encoder->stop();
|
||||
break;
|
||||
}
|
||||
|
||||
if (g_recording_mode.exchange(recording_mode::stopped) == recording_mode::rpcs3)
|
||||
{
|
||||
m_video_encoder->stop();
|
||||
|
||||
if (!video_provider.set_image_sink(nullptr, recording_mode::rpcs3))
|
||||
{
|
||||
gui_log.warning("The video provider could not release the image sink. A sink with higher priority must have been set.");
|
||||
}
|
||||
|
||||
rsx::overlays::queue_message(tr("Recording stopped: %0").arg(QString::fromStdString(m_video_encoder->path())).toStdString());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_video_encoder->stop();
|
||||
|
||||
const std::string& id = Emu.GetTitleID();
|
||||
std::string video_path = fs::get_config_dir() + "recordings/";
|
||||
if (!id.empty())
|
||||
{
|
||||
video_path += id + "/";
|
||||
}
|
||||
|
||||
if (!fs::create_path(video_path) && fs::g_tls_error != fs::error::exist)
|
||||
{
|
||||
screenshot_log.error("Failed to create recordings path \"%s\" : %s", video_path, fs::g_tls_error);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!id.empty())
|
||||
{
|
||||
video_path += id + "_";
|
||||
}
|
||||
|
||||
video_path += "recording_" + date_time::current_time_narrow<'_'>() + ".mp4";
|
||||
|
||||
utils::video_encoder::frame_format output_format{};
|
||||
output_format.av_pixel_format = static_cast<AVPixelFormat>(g_cfg_recording.pixel_format.get());
|
||||
output_format.width = g_cfg_recording.width;
|
||||
output_format.height = g_cfg_recording.height;
|
||||
output_format.pitch = g_cfg_recording.width * 4;
|
||||
|
||||
m_video_encoder->set_path(video_path);
|
||||
m_video_encoder->set_framerate(g_cfg_recording.framerate);
|
||||
m_video_encoder->set_video_bitrate(g_cfg_recording.video_bps);
|
||||
m_video_encoder->set_video_codec(g_cfg_recording.video_codec);
|
||||
m_video_encoder->set_max_b_frames(g_cfg_recording.max_b_frames);
|
||||
m_video_encoder->set_gop_size(g_cfg_recording.gop_size);
|
||||
m_video_encoder->set_output_format(output_format);
|
||||
m_video_encoder->set_sample_rate(0); // TODO
|
||||
m_video_encoder->set_audio_bitrate(0); // TODO
|
||||
m_video_encoder->set_audio_codec(0); // TODO
|
||||
m_video_encoder->encode();
|
||||
|
||||
if (m_video_encoder->has_error)
|
||||
{
|
||||
rsx::overlays::queue_message(tr("Recording not possible").toStdString());
|
||||
m_video_encoder->stop();
|
||||
break;
|
||||
}
|
||||
|
||||
if (!video_provider.set_image_sink(m_video_encoder, recording_mode::rpcs3))
|
||||
{
|
||||
gui_log.warning("The video provider could not set the image sink. A sink with higher priority must have been set.");
|
||||
rsx::overlays::queue_message(tr("Recording not possible").toStdString());
|
||||
m_video_encoder->stop();
|
||||
break;
|
||||
}
|
||||
|
||||
video_provider.set_pause_time(0);
|
||||
|
||||
g_recording_mode = recording_mode::rpcs3;
|
||||
|
||||
rsx::overlays::queue_message(tr("Recording started").toStdString());
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case Qt::Key_F12:
|
||||
{
|
||||
screenshot_toggle = true;
|
||||
@ -577,6 +676,18 @@ void gs_frame::flip(draw_context_t, bool /*skip_frame*/)
|
||||
}
|
||||
}
|
||||
|
||||
bool gs_frame::can_consume_frame() const
|
||||
{
|
||||
utils::video_provider& video_provider = g_fxo->get<utils::video_provider>();
|
||||
return video_provider.can_consume_frame();
|
||||
}
|
||||
|
||||
void gs_frame::present_frame(std::vector<u8>& data, const u32 width, const u32 height, bool is_bgra) const
|
||||
{
|
||||
utils::video_provider& video_provider = g_fxo->get<utils::video_provider>();
|
||||
video_provider.present_frame(data, width, height, is_bgra);
|
||||
}
|
||||
|
||||
void gs_frame::take_screenshot(std::vector<u8> data, const u32 sshot_width, const u32 sshot_height, bool is_bgra)
|
||||
{
|
||||
std::thread(
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
#include "util/types.hpp"
|
||||
#include "util/atomic.hpp"
|
||||
#include "util/media_utils.h"
|
||||
#include "util/video_provider.h"
|
||||
#include "Emu/RSX/GSFrameBase.h"
|
||||
|
||||
#include <QWindow>
|
||||
@ -52,6 +54,8 @@ private:
|
||||
u32 m_hide_mouse_idletime = 2000; // ms
|
||||
bool m_flip_showed_frame = false;
|
||||
|
||||
std::shared_ptr<utils::video_encoder> m_video_encoder{};
|
||||
|
||||
public:
|
||||
explicit gs_frame(QScreen* screen, const QRect& geometry, const QIcon& appIcon, std::shared_ptr<gui_settings> gui_settings);
|
||||
~gs_frame();
|
||||
@ -73,6 +77,8 @@ public:
|
||||
*/
|
||||
bool get_mouse_lock_state();
|
||||
|
||||
bool can_consume_frame() const override;
|
||||
void present_frame(std::vector<u8>& data, const u32 width, const u32 height, bool is_bgra) const override;
|
||||
void take_screenshot(std::vector<u8> data, const u32 sshot_width, const u32 sshot_height, bool is_bgra) override;
|
||||
|
||||
protected:
|
||||
|
Loading…
x
Reference in New Issue
Block a user