Qt: Redesign graphics settings panel

Add screenshot format/type.
This commit is contained in:
Stenzek
2024-03-02 19:08:38 +10:00
parent b8127facdc
commit 04b837a418
38 changed files with 2467 additions and 1572 deletions

View File

@ -2484,7 +2484,7 @@ void FullscreenUI::DrawSettingsWindow()
static constexpr std::array<const char*, static_cast<u32>(SettingsPage::Count)> titles = {
{FSUI_NSTR("Summary"), FSUI_NSTR("Interface Settings"), FSUI_NSTR("Console Settings"),
FSUI_NSTR("Emulation Settings"), FSUI_NSTR("BIOS Settings"), FSUI_NSTR("Controller Settings"),
FSUI_NSTR("Hotkey Settings"), FSUI_NSTR("Memory Card Settings"), FSUI_NSTR("Display Settings"),
FSUI_NSTR("Hotkey Settings"), FSUI_NSTR("Memory Card Settings"), FSUI_NSTR("Graphics Settings"),
FSUI_NSTR("Post-Processing Settings"), FSUI_NSTR("Audio Settings"), FSUI_NSTR("Achievements Settings"),
FSUI_NSTR("Advanced Settings")}};
@ -3898,7 +3898,7 @@ void FullscreenUI::DrawDisplaySettingsPage()
MenuHeading(FSUI_CSTR("Rendering"));
DrawIntListSetting(
bsi, FSUI_CSTR("Internal Resolution Scale"),
bsi, FSUI_CSTR("Internal Resolution"),
FSUI_CSTR("Scales internal VRAM resolution by the specified multiplier. Some games require 1x VRAM resolution."),
"GPU", "ResolutionScale", 1, resolution_scales.data(), resolution_scales.size(), true, 0, is_hardware);
@ -3975,9 +3975,19 @@ void FullscreenUI::DrawDisplaySettingsPage()
"Display", "Scaling", Settings::DEFAULT_DISPLAY_SCALING, &Settings::ParseDisplayScaling,
&Settings::GetDisplayScalingName, &Settings::GetDisplayScalingDisplayName, DisplayScalingMode::Count);
DrawToggleSetting(bsi, FSUI_CSTR("Internal Resolution Screenshots"),
FSUI_CSTR("Saves screenshots at internal render resolution and without postprocessing."), "Display",
"InternalResolutionScreenshots", false);
DrawEnumSetting(bsi, FSUI_CSTR("Screenshot Size"),
FSUI_CSTR("Determines the size of screenshots created by DuckStation."), "Display", "ScreenshotMode",
Settings::DEFAULT_DISPLAY_SCREENSHOT_MODE, &Settings::ParseDisplayScreenshotMode,
&Settings::GetDisplayScreenshotModeName, &Settings::GetDisplayScreenshotModeDisplayName,
DisplayScreenshotMode::Count);
DrawEnumSetting(bsi, FSUI_CSTR("Screenshot Format"),
FSUI_CSTR("Determines the format that screenshots will be saved/compressed with."), "Display",
"ScreenshotFormat", Settings::DEFAULT_DISPLAY_SCREENSHOT_FORMAT,
&Settings::ParseDisplayScreenshotFormat, &Settings::GetDisplayScreenshotFormatName,
&Settings::GetDisplayScreenshotFormatDisplayName, DisplayScreenshotFormat::Count);
DrawIntRangeSetting(bsi, FSUI_CSTR("Screenshot Quality"),
FSUI_CSTR("Selects the quality at which screenshots will be compressed."), "Display",
"ScreenshotQuality", Settings::DEFAULT_DISPLAY_SCREENSHOT_QUALITY, 1, 100, "%d%%");
MenuHeading(FSUI_CSTR("Enhancements"));
DrawToggleSetting(
@ -6651,7 +6661,9 @@ TRANSLATE_NOOP("FullscreenUI", "Determines quality of audio when not running at
TRANSLATE_NOOP("FullscreenUI", "Determines that field that the game list will be sorted by.");
TRANSLATE_NOOP("FullscreenUI", "Determines the amount of audio buffered before being pulled by the host API.");
TRANSLATE_NOOP("FullscreenUI", "Determines the emulated hardware type.");
TRANSLATE_NOOP("FullscreenUI", "Determines the format that screenshots will be saved/compressed with.");
TRANSLATE_NOOP("FullscreenUI", "Determines the position on the screen when black borders must be added.");
TRANSLATE_NOOP("FullscreenUI", "Determines the size of screenshots created by DuckStation.");
TRANSLATE_NOOP("FullscreenUI", "Determines whether a prompt will be displayed to confirm shutting down the emulator/game when the hotkey is pressed.");
TRANSLATE_NOOP("FullscreenUI", "Device Settings");
TRANSLATE_NOOP("FullscreenUI", "Disable All Enhancements");
@ -6754,6 +6766,7 @@ TRANSLATE_NOOP("FullscreenUI", "Genre: %s");
TRANSLATE_NOOP("FullscreenUI", "GitHub Repository");
TRANSLATE_NOOP("FullscreenUI", "Global Slot {0} - {1}##global_slot_{0}");
TRANSLATE_NOOP("FullscreenUI", "Global Slot {0}##global_slot_{0}");
TRANSLATE_NOOP("FullscreenUI", "Graphics Settings");
TRANSLATE_NOOP("FullscreenUI", "Hardcore Mode");
TRANSLATE_NOOP("FullscreenUI", "Hardcore mode will be enabled on next game restart.");
TRANSLATE_NOOP("FullscreenUI", "Hide Cursor In Fullscreen");
@ -6773,8 +6786,7 @@ TRANSLATE_NOOP("FullscreenUI", "Input profile '{}' loaded.");
TRANSLATE_NOOP("FullscreenUI", "Input profile '{}' saved.");
TRANSLATE_NOOP("FullscreenUI", "Integration");
TRANSLATE_NOOP("FullscreenUI", "Interface Settings");
TRANSLATE_NOOP("FullscreenUI", "Internal Resolution Scale");
TRANSLATE_NOOP("FullscreenUI", "Internal Resolution Screenshots");
TRANSLATE_NOOP("FullscreenUI", "Internal Resolution");
TRANSLATE_NOOP("FullscreenUI", "Issue Tracker");
TRANSLATE_NOOP("FullscreenUI", "Last Played");
TRANSLATE_NOOP("FullscreenUI", "Last Played: %s");
@ -6926,7 +6938,6 @@ TRANSLATE_NOOP("FullscreenUI", "Save Screenshot");
TRANSLATE_NOOP("FullscreenUI", "Save State");
TRANSLATE_NOOP("FullscreenUI", "Save State On Exit");
TRANSLATE_NOOP("FullscreenUI", "Saved {:%c}");
TRANSLATE_NOOP("FullscreenUI", "Saves screenshots at internal render resolution and without postprocessing.");
TRANSLATE_NOOP("FullscreenUI", "Saves state periodically so you can rewind any mistakes while playing.");
TRANSLATE_NOOP("FullscreenUI", "Scaled Dithering");
TRANSLATE_NOOP("FullscreenUI", "Scales internal VRAM resolution by the specified multiplier. Some games require 1x VRAM resolution.");
@ -6935,6 +6946,9 @@ TRANSLATE_NOOP("FullscreenUI", "Scaling");
TRANSLATE_NOOP("FullscreenUI", "Scan For New Games");
TRANSLATE_NOOP("FullscreenUI", "Scanning Subdirectories");
TRANSLATE_NOOP("FullscreenUI", "Screen Display");
TRANSLATE_NOOP("FullscreenUI", "Screenshot Format");
TRANSLATE_NOOP("FullscreenUI", "Screenshot Quality");
TRANSLATE_NOOP("FullscreenUI", "Screenshot Size");
TRANSLATE_NOOP("FullscreenUI", "Search Directories");
TRANSLATE_NOOP("FullscreenUI", "Seek Speedup");
TRANSLATE_NOOP("FullscreenUI", "Select Device");
@ -6942,6 +6956,7 @@ TRANSLATE_NOOP("FullscreenUI", "Select Disc Image");
TRANSLATE_NOOP("FullscreenUI", "Select Macro {} Binds");
TRANSLATE_NOOP("FullscreenUI", "Selects the GPU to use for rendering.");
TRANSLATE_NOOP("FullscreenUI", "Selects the percentage of the normal clock speed the emulated hardware will run at.");
TRANSLATE_NOOP("FullscreenUI", "Selects the quality at which screenshots will be compressed.");
TRANSLATE_NOOP("FullscreenUI", "Selects the resolution scale that will be applied to the final image. 1x will downsample to the original console resolution.");
TRANSLATE_NOOP("FullscreenUI", "Selects the resolution to use in fullscreen modes.");
TRANSLATE_NOOP("FullscreenUI", "Selects the view that the game list will open to.");

View File

@ -1906,8 +1906,8 @@ Common::Rectangle<s32> GPU::CalculateDrawRect(s32 window_width, s32 window_heigh
}
static bool CompressAndWriteTextureToFile(u32 width, u32 height, std::string filename, FileSystem::ManagedCFilePtr fp,
bool clear_alpha, bool flip_y, u32 resize_width, u32 resize_height,
std::vector<u8> texture_data, u32 texture_data_stride,
u8 quality, bool clear_alpha, bool flip_y, u32 resize_width,
u32 resize_height, std::vector<u8> texture_data, u32 texture_data_stride,
GPUTexture::Format texture_format)
{
@ -1964,12 +1964,13 @@ static bool CompressAndWriteTextureToFile(u32 width, u32 height, std::string fil
bool result = false;
if (StringUtil::Strcasecmp(extension, ".png") == 0)
{
// TODO: Use quality... libpng is better.
result =
(stbi_write_png_to_func(write_func, fp.get(), width, height, 4, texture_data.data(), texture_data_stride) != 0);
}
else if (StringUtil::Strcasecmp(extension, ".jpg") == 0)
{
result = (stbi_write_jpg_to_func(write_func, fp.get(), width, height, 4, texture_data.data(), 95) != 0);
result = (stbi_write_jpg_to_func(write_func, fp.get(), width, height, 4, texture_data.data(), quality) != 0);
}
else if (StringUtil::Strcasecmp(extension, ".tga") == 0)
{
@ -2072,14 +2073,16 @@ bool GPU::WriteDisplayTextureToFile(std::string filename, bool full_resolution /
if (!compress_on_thread)
{
return CompressAndWriteTextureToFile(read_width, read_height, std::move(filename), std::move(fp), clear_alpha,
flip_y, resize_width, resize_height, std::move(texture_data),
texture_data_stride, m_display_texture->GetFormat());
return CompressAndWriteTextureToFile(read_width, read_height, std::move(filename), std::move(fp),
g_settings.display_screenshot_quality, clear_alpha, flip_y, resize_width,
resize_height, std::move(texture_data), texture_data_stride,
m_display_texture->GetFormat());
}
std::thread compress_thread(CompressAndWriteTextureToFile, read_width, read_height, std::move(filename),
std::move(fp), clear_alpha, flip_y, resize_width, resize_height, std::move(texture_data),
texture_data_stride, m_display_texture->GetFormat());
std::move(fp), g_settings.display_screenshot_quality, clear_alpha, flip_y, resize_width,
resize_height, std::move(texture_data), texture_data_stride,
m_display_texture->GetFormat());
compress_thread.detach();
return true;
}
@ -2131,53 +2134,61 @@ bool GPU::RenderScreenshotToBuffer(u32 width, u32 height, const Common::Rectangl
return true;
}
bool GPU::RenderScreenshotToFile(std::string filename, bool internal_resolution /* = false */,
bool compress_on_thread /* = false */)
bool GPU::RenderScreenshotToFile(std::string filename, DisplayScreenshotMode mode, u8 quality, bool compress_on_thread)
{
u32 width = g_gpu_device->GetWindowWidth();
u32 height = g_gpu_device->GetWindowHeight();
Common::Rectangle<s32> draw_rect = CalculateDrawRect(width, height);
const bool internal_resolution = (mode != DisplayScreenshotMode::ScreenResolution);
if (internal_resolution && m_display_texture_view_width != 0 && m_display_texture_view_height != 0)
{
const u32 draw_width = static_cast<u32>(draw_rect.GetWidth());
const u32 draw_height = static_cast<u32>(draw_rect.GetHeight());
// If internal res, scale the computed draw rectangle to the internal res.
// We re-use the draw rect because it's already been AR corrected.
const float sar =
static_cast<float>(m_display_texture_view_width) / static_cast<float>(m_display_texture_view_height);
const float dar = static_cast<float>(draw_width) / static_cast<float>(draw_height);
if (sar >= dar)
if (mode == DisplayScreenshotMode::InternalResolution)
{
const u32 draw_width = static_cast<u32>(draw_rect.GetWidth());
const u32 draw_height = static_cast<u32>(draw_rect.GetHeight());
// If internal res, scale the computed draw rectangle to the internal res.
// We re-use the draw rect because it's already been AR corrected.
const float sar =
static_cast<float>(m_display_texture_view_width) / static_cast<float>(m_display_texture_view_height);
const float dar = static_cast<float>(draw_width) / static_cast<float>(draw_height);
if (sar >= dar)
{
// stretch height, preserve width
const float scale = static_cast<float>(m_display_texture_view_width) / static_cast<float>(draw_width);
width = m_display_texture_view_width;
height = static_cast<u32>(std::round(static_cast<float>(draw_height) * scale));
}
else
{
// stretch width, preserve height
const float scale = static_cast<float>(m_display_texture_view_height) / static_cast<float>(draw_height);
width = static_cast<u32>(std::round(static_cast<float>(draw_width) * scale));
height = m_display_texture_view_height;
}
// DX11 won't go past 16K texture size.
const u32 max_texture_size = g_gpu_device->GetMaxTextureSize();
if (width > max_texture_size)
{
height = static_cast<u32>(static_cast<float>(height) /
(static_cast<float>(width) / static_cast<float>(max_texture_size)));
width = max_texture_size;
}
if (height > max_texture_size)
{
height = max_texture_size;
width = static_cast<u32>(static_cast<float>(width) /
(static_cast<float>(height) / static_cast<float>(max_texture_size)));
}
}
else // if (mode == DisplayScreenshotMode::UncorrectedInternalResolution)
{
// stretch height, preserve width
const float scale = static_cast<float>(m_display_texture_view_width) / static_cast<float>(draw_width);
width = m_display_texture_view_width;
height = static_cast<u32>(std::round(static_cast<float>(draw_height) * scale));
}
else
{
// stretch width, preserve height
const float scale = static_cast<float>(m_display_texture_view_height) / static_cast<float>(draw_height);
width = static_cast<u32>(std::round(static_cast<float>(draw_width) * scale));
height = m_display_texture_view_height;
}
// DX11 won't go past 16K texture size.
constexpr u32 MAX_TEXTURE_SIZE = 16384;
if (width > MAX_TEXTURE_SIZE)
{
height = static_cast<u32>(static_cast<float>(height) /
(static_cast<float>(width) / static_cast<float>(MAX_TEXTURE_SIZE)));
width = MAX_TEXTURE_SIZE;
}
if (height > MAX_TEXTURE_SIZE)
{
height = MAX_TEXTURE_SIZE;
width = static_cast<u32>(static_cast<float>(width) /
(static_cast<float>(height) / static_cast<float>(MAX_TEXTURE_SIZE)));
}
// Remove padding, it's not part of the framebuffer.
draw_rect.Set(0, 0, static_cast<s32>(width), static_cast<s32>(height));
}
@ -2203,14 +2214,14 @@ bool GPU::RenderScreenshotToFile(std::string filename, bool internal_resolution
if (!compress_on_thread)
{
return CompressAndWriteTextureToFile(width, height, std::move(filename), std::move(fp), true,
return CompressAndWriteTextureToFile(width, height, std::move(filename), std::move(fp), quality, true,
g_gpu_device->UsesLowerLeftOrigin(), width, height, std::move(pixels),
pixels_stride, pixels_format);
}
std::thread compress_thread(CompressAndWriteTextureToFile, width, height, std::move(filename), std::move(fp), true,
g_gpu_device->UsesLowerLeftOrigin(), width, height, std::move(pixels), pixels_stride,
pixels_format);
std::thread compress_thread(CompressAndWriteTextureToFile, width, height, std::move(filename), std::move(fp), quality,
true, g_gpu_device->UsesLowerLeftOrigin(), width, height, std::move(pixels),
pixels_stride, pixels_format);
compress_thread.detach();
return true;
}

View File

@ -209,7 +209,7 @@ public:
std::vector<u8>* out_pixels, u32* out_stride, GPUTexture::Format* out_format);
/// Helper function to save screenshot to PNG.
bool RenderScreenshotToFile(std::string filename, bool internal_resolution = false, bool compress_on_thread = false);
bool RenderScreenshotToFile(std::string filename, DisplayScreenshotMode mode, u8 quality, bool compress_on_thread);
/// Draws the current display texture, with any post-processing.
bool PresentDisplay();

View File

@ -180,6 +180,12 @@ bool Host::RemoveValueFromBaseStringListSetting(const char* section, const char*
->RemoveFromStringList(section, key, value);
}
bool Host::ContainsBaseSettingValue(const char* section, const char* key)
{
std::unique_lock lock(s_settings_mutex);
return s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE)->ContainsValue(section, key);
}
void Host::DeleteBaseSettingValue(const char* section, const char* key)
{
std::unique_lock lock(s_settings_mutex);

View File

@ -47,6 +47,7 @@ void SetBaseStringSettingValue(const char* section, const char* key, const char*
void SetBaseStringListSettingValue(const char* section, const char* key, const std::vector<std::string>& values);
bool AddValueToBaseStringListSetting(const char* section, const char* key, const char* value);
bool RemoveValueFromBaseStringListSetting(const char* section, const char* key, const char* value);
bool ContainsBaseSettingValue(const char* section, const char* key);
void DeleteBaseSettingValue(const char* section, const char* key);
void CommitBaseSettingChanges();

View File

@ -249,6 +249,18 @@ void Settings::Load(SettingsInterface& si)
GetDisplayExclusiveFullscreenControlName(DEFAULT_DISPLAY_EXCLUSIVE_FULLSCREEN_CONTROL))
.c_str())
.value_or(DEFAULT_DISPLAY_EXCLUSIVE_FULLSCREEN_CONTROL);
display_screenshot_mode =
ParseDisplayScreenshotMode(
si.GetStringValue("Display", "ScreenshotMode", GetDisplayScreenshotModeName(DEFAULT_DISPLAY_SCREENSHOT_MODE))
.c_str())
.value_or(DEFAULT_DISPLAY_SCREENSHOT_MODE);
display_screenshot_format =
ParseDisplayScreenshotFormat(si.GetStringValue("Display", "ScreenshotFormat",
GetDisplayScreenshotFormatName(DEFAULT_DISPLAY_SCREENSHOT_FORMAT))
.c_str())
.value_or(DEFAULT_DISPLAY_SCREENSHOT_FORMAT);
display_screenshot_quality = static_cast<u8>(
std::clamp<u32>(si.GetUIntValue("Display", "ScreenshotQuality", DEFAULT_DISPLAY_SCREENSHOT_QUALITY), 1, 100));
display_force_4_3_for_24bit = si.GetBoolValue("Display", "Force4_3For24Bit", false);
display_active_start_offset = static_cast<s16>(si.GetIntValue("Display", "ActiveStartOffset", 0));
display_active_end_offset = static_cast<s16>(si.GetIntValue("Display", "ActiveEndOffset", 0));
@ -266,7 +278,6 @@ void Settings::Load(SettingsInterface& si)
display_show_inputs = si.GetBoolValue("Display", "ShowInputs", false);
display_show_enhancements = si.GetBoolValue("Display", "ShowEnhancements", false);
display_all_frames = si.GetBoolValue("Display", "DisplayAllFrames", false);
display_internal_resolution_screenshots = si.GetBoolValue("Display", "InternalResolutionScreenshots", false);
display_stretch_vertically = si.GetBoolValue("Display", "StretchVertically", false);
video_sync_enabled = si.GetBoolValue("Display", "VSync", DEFAULT_VSYNC_VALUE);
display_max_fps = si.GetFloatValue("Display", "MaxFPS", DEFAULT_DISPLAY_MAX_FPS);
@ -495,6 +506,9 @@ void Settings::Save(SettingsInterface& si) const
si.SetStringValue("Display", "Scaling", GetDisplayScalingName(display_scaling));
si.SetStringValue("Display", "ExclusiveFullscreenControl",
GetDisplayExclusiveFullscreenControlName(display_exclusive_fullscreen_control));
si.SetStringValue("Display", "ScreenshotMode", GetDisplayScreenshotModeName(display_screenshot_mode));
si.SetStringValue("Display", "ScreenshotFormat", GetDisplayScreenshotFormatName(display_screenshot_format));
si.SetUIntValue("Display", "ScreenshotQuality", display_screenshot_quality);
si.SetIntValue("Display", "CustomAspectRatioNumerator", display_aspect_ratio_custom_numerator);
si.GetIntValue("Display", "CustomAspectRatioDenominator", display_aspect_ratio_custom_denominator);
si.SetBoolValue("Display", "ShowOSDMessages", display_show_osd_messages);
@ -509,7 +523,6 @@ void Settings::Save(SettingsInterface& si) const
si.SetBoolValue("Display", "ShowInputs", display_show_inputs);
si.SetBoolValue("Display", "ShowEnhancements", display_show_enhancements);
si.SetBoolValue("Display", "DisplayAllFrames", display_all_frames);
si.SetBoolValue("Display", "InternalResolutionScreenshots", display_internal_resolution_screenshots);
si.SetBoolValue("Display", "StretchVertically", display_stretch_vertically);
si.SetBoolValue("Display", "VSync", video_sync_enabled);
si.SetFloatValue("Display", "MaxFPS", display_max_fps);
@ -945,16 +958,16 @@ static constexpr const std::array s_gpu_renderer_names = {
static constexpr const std::array s_gpu_renderer_display_names = {
TRANSLATE_NOOP("GPURenderer", "Automatic"),
#ifdef _WIN32
TRANSLATE_NOOP("GPURenderer", "Hardware (D3D11)"), TRANSLATE_NOOP("GPURenderer", "Hardware (D3D12)"),
TRANSLATE_NOOP("GPURenderer", "Direct3D 11"), TRANSLATE_NOOP("GPURenderer", "Direct3D 12"),
#endif
#ifdef __APPLE__
TRANSLATE_NOOP("GPURenderer", "Hardware (Metal)"),
TRANSLATE_NOOP("GPURenderer", "Metal"),
#endif
#ifdef ENABLE_VULKAN
TRANSLATE_NOOP("GPURenderer", "Hardware (Vulkan)"),
TRANSLATE_NOOP("GPURenderer", "Vulkan"),
#endif
#ifdef ENABLE_OPENGL
TRANSLATE_NOOP("GPURenderer", "Hardware (OpenGL)"),
TRANSLATE_NOOP("GPURenderer", "OpenGL"),
#endif
TRANSLATE_NOOP("GPURenderer", "Software"),
};
@ -1011,6 +1024,44 @@ RenderAPI Settings::GetRenderAPIForRenderer(GPURenderer renderer)
}
}
GPURenderer Settings::GetRendererForRenderAPI(RenderAPI api)
{
switch (api)
{
#ifdef _WIN32
case RenderAPI::D3D11:
return GPURenderer::HardwareD3D11;
case RenderAPI::D3D12:
return GPURenderer::HardwareD3D12;
#endif
#ifdef __APPLE__
case RenderAPI::Metal:
return GPURenderer::HardwareMetal;
#endif
#ifdef ENABLE_VULKAN
case RenderAPI::Vulkan:
return GPURenderer::HardwareVulkan;
#endif
#ifdef ENABLE_OPENGL
case RenderAPI::OpenGL:
case RenderAPI::OpenGLES:
return GPURenderer::HardwareOpenGL;
#endif
default:
return GPURenderer::Automatic;
}
}
GPURenderer Settings::GetAutomaticRenderer()
{
return GetRendererForRenderAPI(GPUDevice::GetPreferredAPI());
}
static constexpr const std::array s_texture_filter_names = {
"Nearest", "Bilinear", "BilinearBinAlpha", "JINC2", "JINC2BinAlpha", "xBR", "xBRBinAlpha",
};
@ -1312,7 +1363,7 @@ static constexpr const std::array s_display_exclusive_fullscreen_mode_names = {
"Allowed",
};
static constexpr const std::array s_display_exclusive_fullscreen_mode_display_names = {
TRANSLATE_NOOP("Settings", "Automatic (Default)"),
TRANSLATE_NOOP("Settings", "Automatic"),
TRANSLATE_NOOP("Settings", "Disallowed"),
TRANSLATE_NOOP("Settings", "Allowed"),
};
@ -1342,6 +1393,89 @@ const char* Settings::GetDisplayExclusiveFullscreenControlDisplayName(DisplayExc
s_display_exclusive_fullscreen_mode_display_names[static_cast<int>(mode)]);
}
static constexpr const std::array s_display_screenshot_mode_names = {
"ScreenResolution",
"InternalResolution",
"UncorrectedInternalResolution",
};
static constexpr const std::array s_display_screenshot_mode_display_names = {
TRANSLATE_NOOP("Settings", "Screen Resolution"),
TRANSLATE_NOOP("Settings", "Internal Resolution"),
TRANSLATE_NOOP("Settings", "Internal Resolution (Aspect Uncorrected)"),
};
std::optional<DisplayScreenshotMode> Settings::ParseDisplayScreenshotMode(const char* str)
{
int index = 0;
for (const char* name : s_display_screenshot_mode_names)
{
if (StringUtil::Strcasecmp(name, str) == 0)
return static_cast<DisplayScreenshotMode>(index);
index++;
}
return std::nullopt;
}
const char* Settings::GetDisplayScreenshotModeName(DisplayScreenshotMode mode)
{
return s_display_screenshot_mode_names[static_cast<size_t>(mode)];
}
const char* Settings::GetDisplayScreenshotModeDisplayName(DisplayScreenshotMode mode)
{
return Host::TranslateToCString("Settings", s_display_screenshot_mode_display_names[static_cast<size_t>(mode)]);
}
static constexpr const std::array s_display_screenshot_format_names = {
"PNG",
"JPEG",
"TGA",
"BMP",
};
static constexpr const std::array s_display_screenshot_format_display_names = {
TRANSLATE_NOOP("Settings", "PNG"),
TRANSLATE_NOOP("Settings", "JPEG"),
TRANSLATE_NOOP("Settings", "TGA"),
TRANSLATE_NOOP("Settings", "BMP"),
};
static constexpr const std::array s_display_screenshot_format_extensions = {
"png",
"jpg",
"tga",
"bmp",
};
std::optional<DisplayScreenshotFormat> Settings::ParseDisplayScreenshotFormat(const char* str)
{
int index = 0;
for (const char* name : s_display_screenshot_format_names)
{
if (StringUtil::Strcasecmp(name, str) == 0)
return static_cast<DisplayScreenshotFormat>(index);
index++;
}
return std::nullopt;
}
const char* Settings::GetDisplayScreenshotFormatName(DisplayScreenshotFormat format)
{
return s_display_screenshot_format_names[static_cast<size_t>(format)];
}
const char* Settings::GetDisplayScreenshotFormatDisplayName(DisplayScreenshotFormat mode)
{
return Host::TranslateToCString("Settings", s_display_screenshot_format_display_names[static_cast<size_t>(mode)]);
}
const char* Settings::GetDisplayScreenshotFormatExtension(DisplayScreenshotFormat format)
{
return s_display_screenshot_format_extensions[static_cast<size_t>(format)];
}
static constexpr const std::array s_audio_backend_names = {
"Null",
#ifdef ENABLE_CUBEB

View File

@ -135,6 +135,9 @@ struct Settings
DisplayAlignment display_alignment = DEFAULT_DISPLAY_ALIGNMENT;
DisplayScalingMode display_scaling = DEFAULT_DISPLAY_SCALING;
DisplayExclusiveFullscreenControl display_exclusive_fullscreen_control = DEFAULT_DISPLAY_EXCLUSIVE_FULLSCREEN_CONTROL;
DisplayScreenshotMode display_screenshot_mode = DEFAULT_DISPLAY_SCREENSHOT_MODE;
DisplayScreenshotFormat display_screenshot_format = DEFAULT_DISPLAY_SCREENSHOT_FORMAT;
u8 display_screenshot_quality = DEFAULT_DISPLAY_SCREENSHOT_QUALITY;
u16 display_aspect_ratio_custom_numerator = 0;
u16 display_aspect_ratio_custom_denominator = 0;
s16 display_active_start_offset = 0;
@ -155,7 +158,6 @@ struct Settings
bool display_show_inputs : 1 = false;
bool display_show_enhancements : 1 = false;
bool display_all_frames : 1 = false;
bool display_internal_resolution_screenshots : 1 = false;
bool display_stretch_vertically : 1 = false;
bool video_sync_enabled = DEFAULT_VSYNC_VALUE;
float display_osd_scale = 100.0f;
@ -374,6 +376,8 @@ struct Settings
static const char* GetRendererName(GPURenderer renderer);
static const char* GetRendererDisplayName(GPURenderer renderer);
static RenderAPI GetRenderAPIForRenderer(GPURenderer renderer);
static GPURenderer GetRendererForRenderAPI(RenderAPI api);
static GPURenderer GetAutomaticRenderer();
static std::optional<GPUTextureFilter> ParseTextureFilterName(const char* str);
static const char* GetTextureFilterName(GPUTextureFilter filter);
@ -411,6 +415,15 @@ struct Settings
static const char* GetDisplayExclusiveFullscreenControlName(DisplayExclusiveFullscreenControl mode);
static const char* GetDisplayExclusiveFullscreenControlDisplayName(DisplayExclusiveFullscreenControl mode);
static std::optional<DisplayScreenshotMode> ParseDisplayScreenshotMode(const char* str);
static const char* GetDisplayScreenshotModeName(DisplayScreenshotMode mode);
static const char* GetDisplayScreenshotModeDisplayName(DisplayScreenshotMode mode);
static std::optional<DisplayScreenshotFormat> ParseDisplayScreenshotFormat(const char* str);
static const char* GetDisplayScreenshotFormatName(DisplayScreenshotFormat mode);
static const char* GetDisplayScreenshotFormatDisplayName(DisplayScreenshotFormat mode);
static const char* GetDisplayScreenshotFormatExtension(DisplayScreenshotFormat mode);
static std::optional<AudioBackend> ParseAudioBackend(const char* str);
static const char* GetAudioBackendName(AudioBackend backend);
static const char* GetAudioBackendDisplayName(AudioBackend backend);
@ -473,6 +486,9 @@ struct Settings
static constexpr DisplayScalingMode DEFAULT_DISPLAY_SCALING = DisplayScalingMode::BilinearSmooth;
static constexpr DisplayExclusiveFullscreenControl DEFAULT_DISPLAY_EXCLUSIVE_FULLSCREEN_CONTROL =
DisplayExclusiveFullscreenControl::Automatic;
static constexpr DisplayScreenshotMode DEFAULT_DISPLAY_SCREENSHOT_MODE = DisplayScreenshotMode::ScreenResolution;
static constexpr DisplayScreenshotFormat DEFAULT_DISPLAY_SCREENSHOT_FORMAT = DisplayScreenshotFormat::PNG;
static constexpr u8 DEFAULT_DISPLAY_SCREENSHOT_QUALITY = 85;
static constexpr float DEFAULT_OSD_SCALE = 100.0f;
static constexpr u8 DEFAULT_CDROM_READAHEAD_SECTORS = 8;

View File

@ -4306,8 +4306,8 @@ void System::StopDumpingAudio()
Host::AddOSDMessage(TRANSLATE_STR("OSDMessage", "Stopped dumping audio."), 5.0f);
}
bool System::SaveScreenshot(const char* filename /* = nullptr */, bool full_resolution /* = true */,
bool apply_aspect_ratio /* = true */, bool compress_on_thread /* = true */)
bool System::SaveScreenshot(const char* filename, DisplayScreenshotMode mode, DisplayScreenshotFormat format,
u8 quality, bool compress_on_thread)
{
if (!System::IsValid())
return false;
@ -4316,7 +4316,7 @@ bool System::SaveScreenshot(const char* filename /* = nullptr */, bool full_reso
if (!filename)
{
const auto& code = System::GetGameSerial();
const char* extension = "png";
const char* extension = Settings::GetDisplayScreenshotFormatExtension(format);
if (code.empty())
{
auto_filename =
@ -4337,10 +4337,7 @@ bool System::SaveScreenshot(const char* filename /* = nullptr */, bool full_reso
return false;
}
const bool screenshot_saved =
g_gpu->RenderScreenshotToFile(filename, g_settings.display_internal_resolution_screenshots, compress_on_thread);
if (!screenshot_saved)
if (!g_gpu->RenderScreenshotToFile(filename, mode, quality, compress_on_thread))
{
Host::AddFormattedOSDMessage(10.0f, TRANSLATE("OSDMessage", "Failed to save screenshot to '%s'"), filename);
return false;

View File

@ -416,9 +416,10 @@ bool StartDumpingAudio(const char* filename = nullptr);
/// Stops dumping audio to file if it has been started.
void StopDumpingAudio();
/// Saves a screenshot to the specified file. IF no file name is provided, one will be generated automatically.
bool SaveScreenshot(const char* filename = nullptr, bool full_resolution = true, bool apply_aspect_ratio = true,
bool compress_on_thread = true);
/// Saves a screenshot to the specified file. If no file name is provided, one will be generated automatically.
bool SaveScreenshot(const char* filename = nullptr, DisplayScreenshotMode mode = g_settings.display_screenshot_mode,
DisplayScreenshotFormat format = g_settings.display_screenshot_format,
u8 quality = g_settings.display_screenshot_quality, bool compress_on_thread = true);
/// Loads the cheat list from the specified file.
bool LoadCheatList(const char* filename);

View File

@ -160,6 +160,23 @@ enum class DisplayExclusiveFullscreenControl : u8
Count
};
enum class DisplayScreenshotMode : u8
{
ScreenResolution,
InternalResolution,
UncorrectedInternalResolution,
Count
};
enum class DisplayScreenshotFormat : u8
{
PNG,
JPEG,
TGA,
BMP,
Count
};
enum class AudioBackend : u8
{
Null,