summaryrefslogtreecommitdiff
path: root/Source
diff options
context:
space:
mode:
authorAdmiral H. Curtiss <pikachu025@gmail.com>2024-04-13 03:39:37 +0200
committerGitHub <noreply@github.com>2024-04-13 03:39:37 +0200
commitb3939052b4319e7c93de6ce424bf1c5d71ea2d41 (patch)
treea0f6e071f265953f1fd0829763151bb32020d53b /Source
parent107379bf74c1daf212c669abaa1d21f335abc62a (diff)
parent2f13be5a2d05b41ba91a2abfa4af2c79a85bb34f (diff)
Merge pull request #12436 from Filoppi/frame-dump-raw-internal-resolution
Frame dump at raw internal resolution
Diffstat (limited to 'Source')
-rw-r--r--Source/Core/Core/Config/GraphicsSettings.cpp5
-rw-r--r--Source/Core/Core/Config/GraphicsSettings.h3
-rw-r--r--Source/Core/DolphinQt/Config/Graphics/AdvancedWidget.cpp41
-rw-r--r--Source/Core/DolphinQt/Config/Graphics/AdvancedWidget.h2
-rw-r--r--Source/Core/VideoCommon/FrameDumper.cpp10
-rw-r--r--Source/Core/VideoCommon/FrameDumper.h1
-rw-r--r--Source/Core/VideoCommon/Present.cpp90
-rw-r--r--Source/Core/VideoCommon/Present.h3
-rw-r--r--Source/Core/VideoCommon/VideoConfig.cpp2
-rw-r--r--Source/Core/VideoCommon/VideoConfig.h13
10 files changed, 117 insertions, 53 deletions
diff --git a/Source/Core/Core/Config/GraphicsSettings.cpp b/Source/Core/Core/Config/GraphicsSettings.cpp
index 4d18bd17ac..4dfe819beb 100644
--- a/Source/Core/Core/Config/GraphicsSettings.cpp
+++ b/Source/Core/Core/Config/GraphicsSettings.cpp
@@ -70,8 +70,9 @@ const Info<std::string> GFX_DUMP_PIXEL_FORMAT{{System::GFX, "Settings", "DumpPix
const Info<std::string> GFX_DUMP_ENCODER{{System::GFX, "Settings", "DumpEncoder"}, ""};
const Info<std::string> GFX_DUMP_PATH{{System::GFX, "Settings", "DumpPath"}, ""};
const Info<int> GFX_BITRATE_KBPS{{System::GFX, "Settings", "BitrateKbps"}, 25000};
-const Info<bool> GFX_INTERNAL_RESOLUTION_FRAME_DUMPS{
- {System::GFX, "Settings", "InternalResolutionFrameDumps"}, false};
+const Info<FrameDumpResolutionType> GFX_FRAME_DUMPS_RESOLUTION_TYPE{
+ {System::GFX, "Settings", "FrameDumpsResolutionType"},
+ FrameDumpResolutionType::XFBAspectRatioCorrectedResolution};
const Info<int> GFX_PNG_COMPRESSION_LEVEL{{System::GFX, "Settings", "PNGCompressionLevel"}, 6};
const Info<bool> GFX_ENABLE_GPU_TEXTURE_DECODING{
{System::GFX, "Settings", "EnableGPUTextureDecoding"}, false};
diff --git a/Source/Core/Core/Config/GraphicsSettings.h b/Source/Core/Core/Config/GraphicsSettings.h
index d641ce4aaa..bccc5ae293 100644
--- a/Source/Core/Core/Config/GraphicsSettings.h
+++ b/Source/Core/Core/Config/GraphicsSettings.h
@@ -14,6 +14,7 @@ enum class TextureFilteringMode : int;
enum class OutputResamplingMode : int;
enum class ColorCorrectionRegion : int;
enum class TriState : int;
+enum class FrameDumpResolutionType : int;
namespace Config
{
@@ -67,7 +68,7 @@ extern const Info<std::string> GFX_DUMP_PIXEL_FORMAT;
extern const Info<std::string> GFX_DUMP_ENCODER;
extern const Info<std::string> GFX_DUMP_PATH;
extern const Info<int> GFX_BITRATE_KBPS;
-extern const Info<bool> GFX_INTERNAL_RESOLUTION_FRAME_DUMPS;
+extern const Info<FrameDumpResolutionType> GFX_FRAME_DUMPS_RESOLUTION_TYPE;
extern const Info<int> GFX_PNG_COMPRESSION_LEVEL;
extern const Info<bool> GFX_ENABLE_GPU_TEXTURE_DECODING;
extern const Info<bool> GFX_ENABLE_PIXEL_LIGHTING;
diff --git a/Source/Core/DolphinQt/Config/Graphics/AdvancedWidget.cpp b/Source/Core/DolphinQt/Config/Graphics/AdvancedWidget.cpp
index 298c79832b..bad83a6947 100644
--- a/Source/Core/DolphinQt/Config/Graphics/AdvancedWidget.cpp
+++ b/Source/Core/DolphinQt/Config/Graphics/AdvancedWidget.cpp
@@ -137,21 +137,24 @@ void AdvancedWidget::CreateWidgets()
auto* dump_layout = new QGridLayout();
dump_box->setLayout(dump_layout);
- m_use_fullres_framedumps = new ConfigBool(tr("Dump at Internal Resolution"),
- Config::GFX_INTERNAL_RESOLUTION_FRAME_DUMPS);
+ m_frame_dumps_resolution_type =
+ new ConfigChoice({tr("Window Resolution"), tr("Aspect Ratio Corrected Internal Resolution"),
+ tr("Raw Internal Resolution")},
+ Config::GFX_FRAME_DUMPS_RESOLUTION_TYPE);
m_dump_use_ffv1 = new ConfigBool(tr("Use Lossless Codec (FFV1)"), Config::GFX_USE_FFV1);
m_dump_bitrate = new ConfigInteger(0, 1000000, Config::GFX_BITRATE_KBPS, 1000);
m_png_compression_level = new ConfigInteger(0, 9, Config::GFX_PNG_COMPRESSION_LEVEL);
- dump_layout->addWidget(m_use_fullres_framedumps, 0, 0);
+ dump_layout->addWidget(new QLabel(tr("Resolution Type:")), 0, 0);
+ dump_layout->addWidget(m_frame_dumps_resolution_type, 0, 1);
#if defined(HAVE_FFMPEG)
- dump_layout->addWidget(m_dump_use_ffv1, 0, 1);
- dump_layout->addWidget(new QLabel(tr("Bitrate (kbps):")), 1, 0);
- dump_layout->addWidget(m_dump_bitrate, 1, 1);
+ dump_layout->addWidget(m_dump_use_ffv1, 1, 0);
+ dump_layout->addWidget(new QLabel(tr("Bitrate (kbps):")), 2, 0);
+ dump_layout->addWidget(m_dump_bitrate, 2, 1);
#endif
- dump_layout->addWidget(new QLabel(tr("PNG Compression Level:")), 2, 0);
+ dump_layout->addWidget(new QLabel(tr("PNG Compression Level:")), 3, 0);
m_png_compression_level->SetTitle(tr("PNG Compression Level"));
- dump_layout->addWidget(m_png_compression_level, 2, 1);
+ dump_layout->addWidget(m_png_compression_level, 3, 1);
// Misc.
auto* misc_box = new QGroupBox(tr("Misc"));
@@ -340,11 +343,21 @@ void AdvancedWidget::AddDescriptions()
static const char TR_LOAD_GRAPHICS_MODS_DESCRIPTION[] =
QT_TR_NOOP("Loads graphics mods from User/Load/GraphicsMods/.<br><br><dolphin_emphasis>If "
"unsure, leave this unchecked.</dolphin_emphasis>");
- static const char TR_INTERNAL_RESOLUTION_FRAME_DUMPING_DESCRIPTION[] = QT_TR_NOOP(
- "Creates frame dumps and screenshots at the internal resolution of the renderer, rather than "
- "the size of the window it is displayed within.<br><br>If the aspect ratio is widescreen, "
- "the output image will be scaled horizontally to preserve the vertical resolution.<br><br>"
- "<dolphin_emphasis>If unsure, leave this unchecked.</dolphin_emphasis>");
+ static const char TR_FRAME_DUMPS_RESOLUTION_TYPE_DESCRIPTION[] = QT_TR_NOOP(
+ "Selects how frame dumps (videos) and screenshots are going to be captured.<br>If the game "
+ "or window resolution change during a recording, multiple video files might be created.<br>"
+ "Note that color correction and cropping are always ignored by the captures."
+ "<br><br><b>Window Resolution</b>: Uses the output window resolution (without black bars)."
+ "<br>This is a simple dumping option that will capture the image more or less as you see it."
+ "<br><b>Aspect Ratio Corrected Internal Resolution</b>: "
+ "Uses the Internal Resolution (XFB size), and corrects it by the target aspect ratio.<br>"
+ "This option will consistently dump at the specified Internal Resolution "
+ "regardless of how the image is displayed during recording."
+ "<br><b>Raw Internal Resolution</b>: Uses the Internal Resolution (XFB size) "
+ "without correcting it with the target aspect ratio.<br>"
+ "This will provide a clean dump without any aspect ratio correction so users have as raw as "
+ "possible input for external editing software.<br><br><dolphin_emphasis>If unsure, leave "
+ "this at \"Aspect Ratio Corrected Internal Resolution\".</dolphin_emphasis>");
#if defined(HAVE_FFMPEG)
static const char TR_USE_FFV1_DESCRIPTION[] =
QT_TR_NOOP("Encodes frame dumps using the FFV1 codec.<br><br><dolphin_emphasis>If "
@@ -435,7 +448,7 @@ void AdvancedWidget::AddDescriptions()
m_dump_xfb_target->SetDescription(tr(TR_DUMP_XFB_DESCRIPTION));
m_disable_vram_copies->SetDescription(tr(TR_DISABLE_VRAM_COPIES_DESCRIPTION));
m_enable_graphics_mods->SetDescription(tr(TR_LOAD_GRAPHICS_MODS_DESCRIPTION));
- m_use_fullres_framedumps->SetDescription(tr(TR_INTERNAL_RESOLUTION_FRAME_DUMPING_DESCRIPTION));
+ m_frame_dumps_resolution_type->SetDescription(tr(TR_FRAME_DUMPS_RESOLUTION_TYPE_DESCRIPTION));
#ifdef HAVE_FFMPEG
m_dump_use_ffv1->SetDescription(tr(TR_USE_FFV1_DESCRIPTION));
#endif
diff --git a/Source/Core/DolphinQt/Config/Graphics/AdvancedWidget.h b/Source/Core/DolphinQt/Config/Graphics/AdvancedWidget.h
index 3d89b04ef0..6cd0e18fdb 100644
--- a/Source/Core/DolphinQt/Config/Graphics/AdvancedWidget.h
+++ b/Source/Core/DolphinQt/Config/Graphics/AdvancedWidget.h
@@ -60,7 +60,7 @@ private:
// Frame dumping
ConfigBool* m_dump_use_ffv1;
- ConfigBool* m_use_fullres_framedumps;
+ ConfigChoice* m_frame_dumps_resolution_type;
ConfigInteger* m_dump_bitrate;
ConfigInteger* m_png_compression_level;
diff --git a/Source/Core/VideoCommon/FrameDumper.cpp b/Source/Core/VideoCommon/FrameDumper.cpp
index db4ef5205e..30f6a40e10 100644
--- a/Source/Core/VideoCommon/FrameDumper.cpp
+++ b/Source/Core/VideoCommon/FrameDumper.cpp
@@ -18,6 +18,9 @@
#include "VideoCommon/Present.h"
#include "VideoCommon/VideoConfig.h"
+// The video encoder needs the image to be a multiple of x samples.
+static constexpr int VIDEO_ENCODER_LCM = 4;
+
static bool DumpFrameToPNG(const FrameData& frame, const std::string& file_name)
{
return Common::ConvertRGBAToRGBAndSavePNG(file_name, frame.data, frame.width, frame.height,
@@ -354,6 +357,13 @@ bool FrameDumper::IsFrameDumping() const
return false;
}
+int FrameDumper::GetRequiredResolutionLeastCommonMultiple() const
+{
+ if (Config::Get(Config::MAIN_MOVIE_DUMP_FRAMES))
+ return VIDEO_ENCODER_LCM;
+ return 1;
+}
+
void FrameDumper::DoState(PointerWrap& p)
{
#ifdef HAVE_FFMPEG
diff --git a/Source/Core/VideoCommon/FrameDumper.h b/Source/Core/VideoCommon/FrameDumper.h
index 859a4140e3..abf3bac38a 100644
--- a/Source/Core/VideoCommon/FrameDumper.h
+++ b/Source/Core/VideoCommon/FrameDumper.h
@@ -33,6 +33,7 @@ public:
void SaveScreenshot(std::string filename);
bool IsFrameDumping() const;
+ int GetRequiredResolutionLeastCommonMultiple() const;
void DoState(PointerWrap& p);
diff --git a/Source/Core/VideoCommon/Present.cpp b/Source/Core/VideoCommon/Present.cpp
index 0cc19d6e14..d6794a5d54 100644
--- a/Source/Core/VideoCommon/Present.cpp
+++ b/Source/Core/VideoCommon/Present.cpp
@@ -25,9 +25,6 @@
std::unique_ptr<VideoCommon::Presenter> g_presenter;
-// The video encoder needs the image to be a multiple of x samples.
-static constexpr int VIDEO_ENCODER_LCM = 4;
-
namespace VideoCommon
{
// Stretches the native/internal analog resolution aspect ratio from ~4:3 to ~16:9
@@ -212,18 +209,61 @@ void Presenter::ProcessFrameDumping(u64 ticks) const
if (g_frame_dumper->IsFrameDumping() && m_xfb_entry)
{
MathUtil::Rectangle<int> target_rect;
- if (!g_ActiveConfig.bInternalResolutionFrameDumps && !g_gfx->IsHeadless())
+ switch (g_ActiveConfig.frame_dumps_resolution_type)
+ {
+ default:
+ case FrameDumpResolutionType::WindowResolution:
{
- target_rect = GetTargetRectangle();
+ if (!g_gfx->IsHeadless())
+ {
+ target_rect = GetTargetRectangle();
+ break;
+ }
+ [[fallthrough]];
}
- else
+ case FrameDumpResolutionType::XFBAspectRatioCorrectedResolution:
+ {
+ target_rect = m_xfb_rect;
+ const bool allow_stretch = false;
+ auto [float_width, float_height] =
+ ScaleToDisplayAspectRatio(m_xfb_rect.GetWidth(), m_xfb_rect.GetHeight(), allow_stretch);
+ const float draw_aspect_ratio = CalculateDrawAspectRatio(allow_stretch);
+ auto [int_width, int_height] =
+ FindClosestIntegerResolution(float_width, float_height, draw_aspect_ratio);
+ target_rect = MathUtil::Rectangle<int>(0, 0, int_width, int_height);
+ break;
+ }
+ case FrameDumpResolutionType::XFBRawResolution:
{
- int width, height;
- std::tie(width, height) =
- CalculateOutputDimensions(m_xfb_rect.GetWidth(), m_xfb_rect.GetHeight());
- target_rect = MathUtil::Rectangle<int>(0, 0, width, height);
+ target_rect = m_xfb_rect;
+ break;
+ }
}
+ int width = target_rect.GetWidth();
+ int height = target_rect.GetHeight();
+
+ const int resolution_lcm = g_frame_dumper->GetRequiredResolutionLeastCommonMultiple();
+
+ // Ensure divisibility by the dumper LCM and a min of 1 to make it compatible with all the
+ // video encoders. Note that this is theoretically only necessary when recording videos and not
+ // screenshots.
+ // We always scale positively to make sure the least amount of information is lost.
+ //
+ // TODO: this should be added as black padding on the edges by the frame dumper.
+ if ((width % resolution_lcm) != 0 || width == 0)
+ width += resolution_lcm - (width % resolution_lcm);
+ if ((height % resolution_lcm) != 0 || height == 0)
+ height += resolution_lcm - (height % resolution_lcm);
+
+ // Remove any black borders, there would be no point in including them in the recording
+ target_rect.left = 0;
+ target_rect.top = 0;
+ target_rect.right = width;
+ target_rect.bottom = height;
+
+ // TODO: any scaling done by this won't be gamma corrected,
+ // we should either apply post processing as well, or port its gamma correction code
g_frame_dumper->DumpCurrentFrame(m_xfb_entry->texture.get(), m_xfb_rect, target_rect, ticks,
m_frame_count);
}
@@ -347,7 +387,8 @@ float Presenter::CalculateDrawAspectRatio(bool allow_stretch) const
if (aspect_mode == AspectMode::Stretch)
return (static_cast<float>(m_backbuffer_width) / static_cast<float>(m_backbuffer_height));
- auto& vi = Core::System::GetInstance().GetVideoInterface();
+ // The actual aspect ratio of the XFB texture is irrelevant, the VI one is the one that matters
+ const auto& vi = Core::System::GetInstance().GetVideoInterface();
const float source_aspect_ratio = vi.GetAspectRatio();
// This will scale up the source ~4:3 resolution to its equivalent ~16:9 resolution
@@ -538,7 +579,7 @@ void Presenter::UpdateDrawRectangle()
// Don't know if there is a better place for this code so there isn't a 1 frame delay
if (g_ActiveConfig.bWidescreenHack)
{
- auto& vi = Core::System::GetInstance().GetVideoInterface();
+ const auto& vi = Core::System::GetInstance().GetVideoInterface();
float source_aspect_ratio = vi.GetAspectRatio();
// If the game is meant to be in widescreen (or forced to),
// scale the source aspect ratio to it.
@@ -582,9 +623,10 @@ void Presenter::UpdateDrawRectangle()
// Crop the picture to a standard aspect ratio. (if enabled)
auto [crop_width, crop_height] = ApplyStandardAspectCrop(draw_width, draw_height);
+ const float crop_aspect_ratio = crop_width / crop_height;
// scale the picture to fit the rendering window
- if (win_aspect_ratio >= crop_width / crop_height)
+ if (win_aspect_ratio >= crop_aspect_ratio)
{
// the window is flatter than the picture
draw_width *= win_height / crop_height;
@@ -604,18 +646,7 @@ void Presenter::UpdateDrawRectangle()
int int_draw_width;
int int_draw_height;
- if (g_frame_dumper->IsFrameDumping())
- {
- // ensure divisibility by "VIDEO_ENCODER_LCM" to make it compatible with all the video encoders.
- // Note that this is theoretically only necessary when recording videos and not screenshots.
- draw_width =
- std::ceil(draw_width) - static_cast<int>(std::ceil(draw_width)) % VIDEO_ENCODER_LCM;
- draw_height =
- std::ceil(draw_height) - static_cast<int>(std::ceil(draw_height)) % VIDEO_ENCODER_LCM;
- int_draw_width = static_cast<int>(draw_width);
- int_draw_height = static_cast<int>(draw_height);
- }
- else if (g_ActiveConfig.aspect_mode != AspectMode::Raw || !m_xfb_entry)
+ if (g_ActiveConfig.aspect_mode != AspectMode::Raw || !m_xfb_entry)
{
// Find the best integer resolution: the closest aspect ratio with the least black bars.
// This should have no influence if "AspectMode::Stretch" is active.
@@ -666,6 +697,7 @@ std::tuple<float, float> Presenter::ScaleToDisplayAspectRatio(const int width, c
std::tuple<int, int> Presenter::CalculateOutputDimensions(int width, int height,
bool allow_stretch) const
{
+ // Protect against zero width and height, a minimum of 1 will do
width = std::max(width, 1);
height = std::max(height, 1);
@@ -700,14 +732,6 @@ std::tuple<int, int> Presenter::CalculateOutputDimensions(int width, int height,
height = static_cast<int>(std::ceil(scaled_height));
}
- if (g_frame_dumper->IsFrameDumping())
- {
- // UpdateDrawRectangle() makes sure that the rendered image is divisible by "VIDEO_ENCODER_LCM"
- // for video encoders, so do that here too to match it
- width -= width % VIDEO_ENCODER_LCM;
- height -= height % VIDEO_ENCODER_LCM;
- }
-
return std::make_tuple(width, height);
}
diff --git a/Source/Core/VideoCommon/Present.h b/Source/Core/VideoCommon/Present.h
index 9723e1aa19..3f8f43a687 100644
--- a/Source/Core/VideoCommon/Present.h
+++ b/Source/Core/VideoCommon/Present.h
@@ -107,10 +107,13 @@ private:
void OnBackBufferSizeChanged();
+ // Scales a raw XFB resolution to the target (display) aspect ratio,
+ // also accounting for crop and other minor adjustments
std::tuple<int, int> CalculateOutputDimensions(int width, int height,
bool allow_stretch = true) const;
std::tuple<float, float> ApplyStandardAspectCrop(float width, float height,
bool allow_stretch = true) const;
+ // Scales a raw XFB resolution to the target (display) aspect ratio
std::tuple<float, float> ScaleToDisplayAspectRatio(int width, int height,
bool allow_stretch = true) const;
diff --git a/Source/Core/VideoCommon/VideoConfig.cpp b/Source/Core/VideoCommon/VideoConfig.cpp
index e11776d356..0266cb9c19 100644
--- a/Source/Core/VideoCommon/VideoConfig.cpp
+++ b/Source/Core/VideoCommon/VideoConfig.cpp
@@ -128,7 +128,7 @@ void VideoConfig::Refresh()
sDumpEncoder = Config::Get(Config::GFX_DUMP_ENCODER);
sDumpPath = Config::Get(Config::GFX_DUMP_PATH);
iBitrateKbps = Config::Get(Config::GFX_BITRATE_KBPS);
- bInternalResolutionFrameDumps = Config::Get(Config::GFX_INTERNAL_RESOLUTION_FRAME_DUMPS);
+ frame_dumps_resolution_type = Config::Get(Config::GFX_FRAME_DUMPS_RESOLUTION_TYPE);
bEnableGPUTextureDecoding = Config::Get(Config::GFX_ENABLE_GPU_TEXTURE_DECODING);
bPreferVSForLinePointExpansion = Config::Get(Config::GFX_PREFER_VS_FOR_LINE_POINT_EXPANSION);
bEnablePixelLighting = Config::Get(Config::GFX_ENABLE_PIXEL_LIGHTING);
diff --git a/Source/Core/VideoCommon/VideoConfig.h b/Source/Core/VideoCommon/VideoConfig.h
index d7ab34f142..1e5f03d0e5 100644
--- a/Source/Core/VideoCommon/VideoConfig.h
+++ b/Source/Core/VideoCommon/VideoConfig.h
@@ -80,6 +80,16 @@ enum class TriState : int
Auto
};
+enum class FrameDumpResolutionType : int
+{
+ // Window resolution (not including potential back buffer black borders)
+ WindowResolution,
+ // The aspect ratio corrected XFB resolution (XFB pixels might not have been square)
+ XFBAspectRatioCorrectedResolution,
+ // The raw unscaled XFB resolution (based on "internal resolution" scale)
+ XFBRawResolution,
+};
+
// Bitmask containing information about which configuration has changed for the backend.
enum ConfigChangeBits : u32
{
@@ -189,7 +199,8 @@ struct VideoConfig final
std::string sDumpEncoder;
std::string sDumpFormat;
std::string sDumpPath;
- bool bInternalResolutionFrameDumps = false;
+ FrameDumpResolutionType frame_dumps_resolution_type =
+ FrameDumpResolutionType::XFBAspectRatioCorrectedResolution;
bool bBorderlessFullscreen = false;
bool bEnableGPUTextureDecoding = false;
bool bPreferVSForLinePointExpansion = false;