From 09e7a5843f0c0efb8352af22297a6c1576d97c03 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Thu, 31 Aug 2023 23:37:17 +1000 Subject: [PATCH] GPU: Add scaling shader support Currently only Bilinear (Sharp). --- src/core/CMakeLists.txt | 2 + src/core/core.vcxproj | 4 +- src/core/core.vcxproj.filters | 4 +- src/core/fullscreen_ui.cpp | 18 +-- src/core/gpu.cpp | 146 +++++++++++++------ src/core/gpu.h | 7 +- src/core/gpu_hw.cpp | 7 +- src/core/gpu_hw.h | 2 +- src/core/gpu_shadergen.cpp | 79 ++++++++++ src/core/gpu_shadergen.h | 20 +++ src/core/gpu_sw.cpp | 4 +- src/core/gpu_sw.h | 2 +- src/core/hotkeys.cpp | 18 ++- src/core/settings.cpp | 123 ++++++++++------ src/core/settings.h | 9 +- src/core/system.cpp | 15 +- src/core/types.h | 11 +- src/duckstation-qt/displaysettingswidget.cpp | 35 ++--- src/duckstation-qt/displaysettingswidget.h | 1 - src/duckstation-qt/displaysettingswidget.ui | 37 ++--- src/util/gpu_device.cpp | 1 + src/util/shadergen.cpp | 42 +----- src/util/shadergen.h | 2 - 23 files changed, 370 insertions(+), 219 deletions(-) create mode 100644 src/core/gpu_shadergen.cpp create mode 100644 src/core/gpu_shadergen.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 63f1f9043..04279e7a5 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -46,6 +46,8 @@ add_library(core gpu_hw.h gpu_hw_shadergen.cpp gpu_hw_shadergen.h + gpu_shadergen.cpp + gpu_shadergen.h gpu_sw.cpp gpu_sw.h gpu_sw_backend.cpp diff --git a/src/core/core.vcxproj b/src/core/core.vcxproj index 47dfbbd09..de388dc99 100644 --- a/src/core/core.vcxproj +++ b/src/core/core.vcxproj @@ -39,6 +39,7 @@ + @@ -103,6 +104,7 @@ + @@ -190,4 +192,4 @@ - + \ No newline at end of file diff --git a/src/core/core.vcxproj.filters b/src/core/core.vcxproj.filters index 91b13258f..95ce97505 100644 --- a/src/core/core.vcxproj.filters +++ b/src/core/core.vcxproj.filters @@ -58,6 +58,7 @@ + @@ -120,5 +121,6 @@ + - + \ No newline at end of file diff --git a/src/core/fullscreen_ui.cpp b/src/core/fullscreen_ui.cpp index f4698a601..2ed6856eb 100644 --- a/src/core/fullscreen_ui.cpp +++ b/src/core/fullscreen_ui.cpp @@ -3883,7 +3883,7 @@ void FullscreenUI::DrawDisplaySettingsPage() DrawEnumSetting( bsi, FSUI_CSTR("Position"), FSUI_CSTR("Determines the position on the screen when black borders must be added."), "Display", "Alignment", Settings::DEFAULT_DISPLAY_ALIGNMENT, &Settings::ParseDisplayAlignment, - &Settings::GetDisplayAlignmentDisplayName, &Settings::GetDisplayAlignmentDisplayName, DisplayAlignment::Count); + &Settings::GetDisplayAlignmentName, &Settings::GetDisplayAlignmentDisplayName, DisplayAlignment::Count); DrawEnumSetting(bsi, FSUI_CSTR("Downsampling"), FSUI_CSTR("Downsamples the rendered image prior to displaying it. Can improve " @@ -3892,17 +3892,11 @@ void FullscreenUI::DrawDisplaySettingsPage() &Settings::GetDownsampleModeName, &Settings::GetDownsampleModeDisplayName, GPUDownsampleMode::Count, (renderer != GPURenderer::Software)); - DrawToggleSetting(bsi, FSUI_CSTR("Linear Upscaling"), - FSUI_CSTR("Uses a bilinear filter when upscaling to display, smoothing out the image."), "Display", - "LinearFiltering", true); - - DrawToggleSetting(bsi, FSUI_CSTR("Integer Upscaling"), - FSUI_CSTR("Adds padding to ensure pixels are a whole number in size."), "Display", "IntegerScaling", - false); - - DrawToggleSetting(bsi, FSUI_CSTR("Stretch To Fit"), - FSUI_CSTR("Fills the window with the active display area, regardless of the aspect ratio."), - "Display", "Stretch", false); + DrawEnumSetting( + bsi, FSUI_CSTR("Scaling"), + FSUI_CSTR("Determines how the emulated console's output is upscaled or downscaled to your monitor's resolution."), + "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", diff --git a/src/core/gpu.cpp b/src/core/gpu.cpp index 4de7048c6..8c538c4d6 100644 --- a/src/core/gpu.cpp +++ b/src/core/gpu.cpp @@ -1,8 +1,9 @@ -// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin +// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #include "gpu.h" #include "dma.h" +#include "gpu_shadergen.h" #include "host.h" #include "imgui.h" #include "interrupt_controller.h" @@ -59,7 +60,7 @@ bool GPU::Initialize() m_console_is_pal = System::IsPALRegion(); UpdateCRTCConfig(); - if (!CompilePipelines()) + if (!CompileDisplayPipeline()) { Host::ReportErrorAsync("Error", "Failed to compile base GPU pipelines."); return false; @@ -70,7 +71,7 @@ bool GPU::Initialize() return true; } -void GPU::UpdateSettings() +void GPU::UpdateSettings(const Settings& old_settings) { m_force_progressive_scan = g_settings.gpu_disable_interlacing; m_fifo_size = g_settings.gpu_fifo_size; @@ -86,6 +87,12 @@ void GPU::UpdateSettings() // Crop mode calls this, so recalculate the display area UpdateCRTCDisplayParameters(); + if (g_settings.display_scaling != old_settings.display_scaling) + { + if (!CompileDisplayPipeline()) + Panic("Failed to compile display pipeline on settings change."); + } + g_gpu_device->SetGPUTimingEnabled(g_settings.display_show_gpu); } @@ -1540,9 +1547,9 @@ void GPU::SetTextureWindow(u32 value) m_draw_mode.texture_window_changed = true; } -bool GPU::CompilePipelines() +bool GPU::CompileDisplayPipeline() { - ShaderGen shadergen(g_gpu_device->GetRenderAPI(), g_gpu_device->GetFeatures().dual_source_blend); + GPUShaderGen shadergen(g_gpu_device->GetRenderAPI(), g_gpu_device->GetFeatures().dual_source_blend); GPUPipeline::GraphicsConfig plconfig; plconfig.layout = GPUPipeline::Layout::SingleTextureAndPushConstants; @@ -1556,20 +1563,35 @@ bool GPU::CompilePipelines() plconfig.samples = 1; plconfig.per_sample_shading = false; - std::unique_ptr display_vs = - g_gpu_device->CreateShader(GPUShaderStage::Vertex, shadergen.GenerateDisplayVertexShader()); - std::unique_ptr display_fs = - g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GenerateDisplayFragmentShader(true)); - if (!display_vs || !display_fs) - return false; - GL_OBJECT_NAME(display_vs, "Display Vertex Shader"); - GL_OBJECT_NAME(display_fs, "Display Fragment Shader"); + std::string vs = shadergen.GenerateDisplayVertexShader(); + std::string fs; + switch (g_settings.display_scaling) + { + case DisplayScalingMode::BilinearSharp: + fs = shadergen.GenerateDisplaySharpBilinearFragmentShader(); + break; - plconfig.vertex_shader = display_vs.get(); - plconfig.fragment_shader = display_fs.get(); + case DisplayScalingMode::Nearest: + case DisplayScalingMode::BilinearSmooth: + case DisplayScalingMode::NearestInteger: + default: + fs = shadergen.GenerateDisplayFragmentShader(); + break; + } + + std::unique_ptr vso = g_gpu_device->CreateShader(GPUShaderStage::Vertex, vs); + std::unique_ptr fso = g_gpu_device->CreateShader(GPUShaderStage::Fragment, fs); + if (!vso || !fso) + return false; + GL_OBJECT_NAME(vso, "Display Vertex Shader"); + GL_OBJECT_NAME(fso, "Display Fragment Shader [%s]", Settings::GetDisplayScalingName(g_settings.display_scaling)); + + plconfig.vertex_shader = vso.get(); + plconfig.fragment_shader = fso.get(); if (!(m_display_pipeline = g_gpu_device->CreatePipeline(plconfig))) return false; - GL_OBJECT_NAME(m_display_pipeline, "Display Pipeline"); + GL_OBJECT_NAME(m_display_pipeline, "Display Pipeline [%s]", + Settings::GetDisplayScalingName(g_settings.display_scaling)); return true; } @@ -1620,17 +1642,56 @@ bool GPU::PresentDisplay() const Common::Rectangle draw_rect = CalculateDrawRect(g_gpu_device->GetWindowWidth(), g_gpu_device->GetWindowHeight()); - return RenderDisplay(nullptr, draw_rect, g_settings.display_linear_filtering, true); + return RenderDisplay(nullptr, draw_rect, true); } -bool GPU::RenderDisplay(GPUFramebuffer* target, const Common::Rectangle& draw_rect, bool linear_filter, - bool postfx) +bool GPU::RenderDisplay(GPUFramebuffer* target, const Common::Rectangle& draw_rect, bool postfx) { GL_SCOPE("RenderDisplay: %dx%d at %d,%d", draw_rect.left, draw_rect.top, draw_rect.GetWidth(), draw_rect.GetHeight()); if (m_display_texture) m_display_texture->MakeReadyForSampling(); + bool texture_filter_linear = false; + bool bilinear_adjust = false; + + struct Uniforms + { + float src_rect[4]; + float src_size[4]; + float params[4]; + } uniforms; + std::memset(uniforms.params, 0, sizeof(uniforms.params)); + + switch (g_settings.display_scaling) + { + case DisplayScalingMode::Nearest: + case DisplayScalingMode::NearestInteger: + break; + + case DisplayScalingMode::BilinearSmooth: + texture_filter_linear = true; + bilinear_adjust = true; + break; + + case DisplayScalingMode::BilinearSharp: + { + texture_filter_linear = true; + uniforms.params[0] = std::max( + std::floor(static_cast(draw_rect.GetWidth()) / static_cast(m_display_texture_view_width)), 1.0f); + uniforms.params[1] = std::max( + std::floor(static_cast(draw_rect.GetHeight()) / static_cast(m_display_texture_view_height)), + 1.0f); + uniforms.params[2] = 0.5f - 0.5f / uniforms.params[0]; + uniforms.params[3] = 0.5f - 0.5f / uniforms.params[1]; + } + break; + + default: + UnreachableCode(); + break; + } + const GPUTexture::Format hdformat = (target && target->GetRT()) ? target->GetRT()->GetFormat() : g_gpu_device->GetWindowFormat(); const u32 target_width = target ? target->GetWidth() : g_gpu_device->GetWindowWidth(); @@ -1654,29 +1715,30 @@ bool GPU::RenderDisplay(GPUFramebuffer* target, const Common::Rectangle& dr return true; g_gpu_device->SetPipeline(m_display_pipeline.get()); - g_gpu_device->SetTextureSampler(0, m_display_texture, - linear_filter ? g_gpu_device->GetLinearSampler() : g_gpu_device->GetNearestSampler()); + g_gpu_device->SetTextureSampler( + 0, m_display_texture, texture_filter_linear ? g_gpu_device->GetLinearSampler() : g_gpu_device->GetNearestSampler()); - const float position_adjust = linear_filter ? 0.5f : 0.0f; - const float size_adjust = linear_filter ? 1.0f : 0.0f; - const float uniforms[4] = {(static_cast(m_display_texture_view_x) + position_adjust) / - static_cast(m_display_texture->GetWidth()), - (static_cast(m_display_texture_view_y) + position_adjust) / - static_cast(m_display_texture->GetHeight()), - (static_cast(m_display_texture_view_width) - size_adjust) / - static_cast(m_display_texture->GetWidth()), - (static_cast(m_display_texture_view_height) - size_adjust) / - static_cast(m_display_texture->GetHeight())}; - g_gpu_device->PushUniformBuffer(uniforms, sizeof(uniforms)); + const float position_adjust = bilinear_adjust ? 0.5f : 0.0f; + const float size_adjust = bilinear_adjust ? 1.0f : 0.0f; + const float rcp_width = 1.0f / static_cast(m_display_texture->GetWidth()); + const float rcp_height = 1.0f / static_cast(m_display_texture->GetHeight()); + uniforms.src_rect[0] = (static_cast(m_display_texture_view_x) + position_adjust) * rcp_width; + uniforms.src_rect[1] = (static_cast(m_display_texture_view_y) + position_adjust) * rcp_height; + uniforms.src_rect[2] = (static_cast(m_display_texture_view_width) - size_adjust) * rcp_width; + uniforms.src_rect[3] = (static_cast(m_display_texture_view_height) - size_adjust) * rcp_height; + uniforms.src_size[0] = static_cast(m_display_texture->GetWidth()); + uniforms.src_size[1] = static_cast(m_display_texture->GetHeight()); + uniforms.src_size[2] = rcp_width; + uniforms.src_size[3] = rcp_height; + g_gpu_device->PushUniformBuffer(&uniforms, sizeof(uniforms)); g_gpu_device->SetViewportAndScissor(draw_rect.left, draw_rect.top, draw_rect.GetWidth(), draw_rect.GetHeight()); g_gpu_device->Draw(3, 0); if (really_postfx) { - return PostProcessing::Apply(target, draw_rect.left, draw_rect.top, draw_rect.GetWidth(), - draw_rect.GetHeight(), m_display_texture_view_width, - m_display_texture_view_height); + return PostProcessing::Apply(target, draw_rect.left, draw_rect.top, draw_rect.GetWidth(), draw_rect.GetHeight(), + m_display_texture_view_width, m_display_texture_view_height); } else { @@ -1689,10 +1751,9 @@ Common::Rectangle GPU::CalculateDrawRect(s32 window_width, s32 window_hei bool apply_aspect_ratio /* = true */) const { const float window_ratio = static_cast(window_width) / static_cast(window_height); - const float display_aspect_ratio = g_settings.display_stretch ? window_ratio : m_display_aspect_ratio; const float x_scale = apply_aspect_ratio ? - (display_aspect_ratio / (static_cast(m_display_width) / static_cast(m_display_height))) : + (m_display_aspect_ratio / (static_cast(m_display_width) / static_cast(m_display_height))) : 1.0f; const float display_width = g_settings.display_stretch_vertically ? static_cast(m_display_width) : static_cast(m_display_width) * x_scale; @@ -1717,12 +1778,12 @@ Common::Rectangle GPU::CalculateDrawRect(s32 window_width, s32 window_hei { // align in middle vertically scale = static_cast(window_width) / display_width; - if (g_settings.display_integer_scaling) + if (g_settings.display_scaling == DisplayScalingMode::NearestInteger) scale = std::max(std::floor(scale), 1.0f); if (out_left_padding) { - if (g_settings.display_integer_scaling) + if (g_settings.display_scaling == DisplayScalingMode::NearestInteger) *out_left_padding = std::max((static_cast(window_width) - display_width * scale) / 2.0f, 0.0f); else *out_left_padding = 0.0f; @@ -1751,7 +1812,7 @@ Common::Rectangle GPU::CalculateDrawRect(s32 window_width, s32 window_hei { // align in middle horizontally scale = static_cast(window_height) / display_height; - if (g_settings.display_integer_scaling) + if (g_settings.display_scaling == DisplayScalingMode::NearestInteger) scale = std::max(std::floor(scale), 1.0f); if (out_left_padding) @@ -1776,7 +1837,7 @@ Common::Rectangle GPU::CalculateDrawRect(s32 window_width, s32 window_hei if (out_top_padding) { - if (g_settings.display_integer_scaling) + if (g_settings.display_scaling == DisplayScalingMode::NearestInteger) *out_top_padding = std::max((static_cast(window_height) - (display_height * scale)) / 2.0f, 0.0f); else *out_top_padding = 0.0f; @@ -1974,7 +2035,8 @@ bool GPU::RenderScreenshotToBuffer(u32 width, u32 height, const Common::Rectangl g_gpu_device->ClearRenderTarget(render_texture.get(), 0); - RenderDisplay(render_fb.get(), draw_rect, g_settings.display_linear_filtering, postfx); + // TODO: this should use copy shader instead. + RenderDisplay(render_fb.get(), draw_rect, postfx); g_gpu_device->SetFramebuffer(nullptr); diff --git a/src/core/gpu.h b/src/core/gpu.h index 18c55b423..df9b42055 100644 --- a/src/core/gpu.h +++ b/src/core/gpu.h @@ -27,6 +27,7 @@ class GPUFramebuffer; class GPUTexture; class GPUPipeline; +struct Settings; class TimingEvent; namespace Threading { @@ -151,7 +152,7 @@ public: void SynchronizeCRTC(); /// Recompile shaders/recreate framebuffers when needed. - virtual void UpdateSettings(); + virtual void UpdateSettings(const Settings& old_settings); /// Updates the resolution scale when it's set to automatic. virtual void UpdateResolutionScale(); @@ -582,7 +583,7 @@ protected: float* out_top_padding, float* out_scale, float* out_x_scale, bool apply_aspect_ratio = true) const; - bool RenderDisplay(GPUFramebuffer* target, const Common::Rectangle& draw_rect, bool linear_filter, bool postfx); + bool RenderDisplay(GPUFramebuffer* target, const Common::Rectangle& draw_rect, bool postfx); s32 m_display_width = 0; s32 m_display_height = 0; @@ -612,7 +613,7 @@ protected: Stats m_last_stats = {}; private: - bool CompilePipelines(); + bool CompileDisplayPipeline(); using GP0CommandHandler = bool (GPU::*)(); using GP0CommandHandlerTable = std::array; diff --git a/src/core/gpu_hw.cpp b/src/core/gpu_hw.cpp index 72c76e657..09c006dc7 100644 --- a/src/core/gpu_hw.cpp +++ b/src/core/gpu_hw.cpp @@ -286,9 +286,9 @@ void GPU_HW::RestoreGraphicsAPIState() m_batch_ubo_dirty = true; } -void GPU_HW::UpdateSettings() +void GPU_HW::UpdateSettings(const Settings& old_settings) { - GPU::UpdateSettings(); + GPU::UpdateSettings(old_settings); const u32 resolution_scale = CalculateResolutionScale(); const u32 multisamples = std::min(g_settings.gpu_multisamples, g_gpu_device->GetMaxMultisamples()); @@ -297,6 +297,7 @@ void GPU_HW::UpdateSettings() const bool use_uv_limits = ShouldUseUVLimits(); const bool disable_color_perspective = m_supports_disable_color_perspective && ShouldDisableColorPerspective(); + // TODO: Use old_settings const bool framebuffer_changed = (m_resolution_scale != resolution_scale || m_multisamples != multisamples || m_downsample_mode != downsample_mode); const bool shaders_changed = @@ -429,7 +430,7 @@ void GPU_HW::UpdateResolutionScale() GPU::UpdateResolutionScale(); if (CalculateResolutionScale() != m_resolution_scale) - UpdateSettings(); + UpdateSettings(g_settings); } GPUDownsampleMode GPU_HW::GetDownsampleMode(u32 resolution_scale) const diff --git a/src/core/gpu_hw.h b/src/core/gpu_hw.h index e3f819e10..8dd320d83 100644 --- a/src/core/gpu_hw.h +++ b/src/core/gpu_hw.h @@ -51,7 +51,7 @@ public: void RestoreGraphicsAPIState() override; - void UpdateSettings() override; + void UpdateSettings(const Settings& old_settings) override; void UpdateResolutionScale() override final; std::tuple GetEffectiveDisplayResolution(bool scaled = true) override final; std::tuple GetFullDisplayResolution(bool scaled = true) override final; diff --git a/src/core/gpu_shadergen.cpp b/src/core/gpu_shadergen.cpp new file mode 100644 index 000000000..94d3d8269 --- /dev/null +++ b/src/core/gpu_shadergen.cpp @@ -0,0 +1,79 @@ +// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin +// SPDX-License-Identifier: GPL-3.0 + +#include "gpu_shadergen.h" + +GPUShaderGen::GPUShaderGen(RenderAPI render_api, bool supports_dual_source_blend) + : ShaderGen(render_api, supports_dual_source_blend) +{ +} + +GPUShaderGen::~GPUShaderGen() = default; + +void GPUShaderGen::WriteDisplayUniformBuffer(std::stringstream& ss) +{ + DeclareUniformBuffer(ss, {"float4 u_src_rect", "float4 u_src_size", "float4 u_params"}, true); +} + +std::string GPUShaderGen::GenerateDisplayVertexShader() +{ + std::stringstream ss; + WriteHeader(ss); + WriteDisplayUniformBuffer(ss); + DeclareVertexEntryPoint(ss, {}, 0, 1, {}, true); + ss << R"( +{ + float2 pos = float2(float((v_id << 1) & 2u), float(v_id & 2u)); + v_tex0 = u_src_rect.xy + pos * u_src_rect.zw; + v_pos = float4(pos * float2(2.0f, -2.0f) + float2(-1.0f, 1.0f), 0.0f, 1.0f); + #if API_VULKAN + v_pos.y = -v_pos.y; + #endif +} +)"; + + return ss.str(); +} + +std::string GPUShaderGen::GenerateDisplayFragmentShader() +{ + std::stringstream ss; + WriteHeader(ss); + WriteDisplayUniformBuffer(ss); + DeclareTexture(ss, "samp0", 0); + DeclareFragmentEntryPoint(ss, 0, 1, {}, false, 1); + ss << R"( +{ + o_col0 = float4(SAMPLE_TEXTURE(samp0, v_tex0).rgb, 1.0f); +})"; + + return ss.str(); +} + +std::string GPUShaderGen::GenerateDisplaySharpBilinearFragmentShader() +{ + std::stringstream ss; + WriteHeader(ss); + WriteDisplayUniformBuffer(ss); + DeclareTexture(ss, "samp0", 0, false); + + // Based on https://github.com/rsn8887/Sharp-Bilinear-Shaders/blob/master/Copy_To_RetroPie/shaders/sharp-bilinear-simple.glsl + DeclareFragmentEntryPoint(ss, 0, 1, {}, false, 1, false, false, false, false); + ss << R"( +{ + float2 scale = u_params.xy; + float2 region_range = u_params.zw; + + float2 texel = v_tex0 * u_src_size.xy; + float2 texel_floored = floor(texel); + float2 s = frac(texel); + + float2 center_dist = s - 0.5; + float2 f = (center_dist - clamp(center_dist, -region_range, region_range)) * scale + 0.5; + float2 mod_texel = texel_floored + f; + + o_col0 = float4(SAMPLE_TEXTURE(samp0, mod_texel * u_src_size.zw).rgb, 1.0f); +})"; + + return ss.str(); +} diff --git a/src/core/gpu_shadergen.h b/src/core/gpu_shadergen.h new file mode 100644 index 000000000..55b73231b --- /dev/null +++ b/src/core/gpu_shadergen.h @@ -0,0 +1,20 @@ +// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin +// SPDX-License-Identifier: GPL-3.0 + +#pragma once + +#include "util/shadergen.h" + +class GPUShaderGen : public ShaderGen +{ +public: + GPUShaderGen(RenderAPI render_api, bool supports_dual_source_blend); + ~GPUShaderGen(); + + std::string GenerateDisplayVertexShader(); + std::string GenerateDisplayFragmentShader(); + std::string GenerateDisplaySharpBilinearFragmentShader(); + +private: + void WriteDisplayUniformBuffer(std::stringstream& ss); +}; diff --git a/src/core/gpu_sw.cpp b/src/core/gpu_sw.cpp index 90e901784..b9ae0ca63 100644 --- a/src/core/gpu_sw.cpp +++ b/src/core/gpu_sw.cpp @@ -97,9 +97,9 @@ void GPU_SW::Reset(bool clear_vram) m_backend.Reset(clear_vram); } -void GPU_SW::UpdateSettings() +void GPU_SW::UpdateSettings(const Settings& old_settings) { - GPU::UpdateSettings(); + GPU::UpdateSettings(old_settings); m_backend.UpdateSettings(); } diff --git a/src/core/gpu_sw.h b/src/core/gpu_sw.h index 52b375fa5..70d13c0ec 100644 --- a/src/core/gpu_sw.h +++ b/src/core/gpu_sw.h @@ -33,7 +33,7 @@ public: bool Initialize() override; bool DoState(StateWrapper& sw, GPUTexture** host_texture, bool update_display) override; void Reset(bool clear_vram) override; - void UpdateSettings() override; + void UpdateSettings(const Settings& old_settings) override; protected: void ReadVRAM(u32 x, u32 y, u32 width, u32 height) override; diff --git a/src/core/hotkeys.cpp b/src/core/hotkeys.cpp index 0af471965..0cb8bf864 100644 --- a/src/core/hotkeys.cpp +++ b/src/core/hotkeys.cpp @@ -48,12 +48,13 @@ static void HotkeyModifyResolutionScale(s32 increment) if (new_resolution_scale == g_settings.gpu_resolution_scale) return; + const Settings old_settings = g_settings; g_settings.gpu_resolution_scale = new_resolution_scale; if (System::IsValid()) { g_gpu->RestoreGraphicsAPIState(); - g_gpu->UpdateSettings(); + g_gpu->UpdateSettings(old_settings); System::ClearMemorySaveStates(); } } @@ -309,9 +310,10 @@ DEFINE_HOTKEY("TogglePGXP", TRANSLATE_NOOP("Hotkeys", "Graphics"), TRANSLATE_NOO [](s32 pressed) { if (!pressed && System::IsValid()) { + Settings old_settings = g_settings; g_settings.gpu_pgxp_enable = !g_settings.gpu_pgxp_enable; g_gpu->RestoreGraphicsAPIState(); - g_gpu->UpdateSettings(); + g_gpu->UpdateSettings(old_settings); System::ClearMemorySaveStates(); Host::AddKeyedOSDMessage("TogglePGXP", g_settings.gpu_pgxp_enable ? @@ -374,12 +376,14 @@ DEFINE_HOTKEY("TogglePGXPDepth", TRANSLATE_NOOP("Hotkeys", "Graphics"), TRANSLATE_NOOP("Hotkeys", "Toggle PGXP Depth Buffer"), [](s32 pressed) { if (!pressed && System::IsValid()) { - g_settings.gpu_pgxp_depth_buffer = !g_settings.gpu_pgxp_depth_buffer; if (!g_settings.gpu_pgxp_enable) return; + const Settings old_settings = g_settings; + g_settings.gpu_pgxp_depth_buffer = !g_settings.gpu_pgxp_depth_buffer; + g_gpu->RestoreGraphicsAPIState(); - g_gpu->UpdateSettings(); + g_gpu->UpdateSettings(old_settings); System::ClearMemorySaveStates(); Host::AddKeyedOSDMessage("TogglePGXPDepth", g_settings.gpu_pgxp_depth_buffer ? @@ -393,12 +397,14 @@ DEFINE_HOTKEY("TogglePGXPCPU", TRANSLATE_NOOP("Hotkeys", "Graphics"), TRANSLATE_ [](s32 pressed) { if (pressed && System::IsValid()) { - g_settings.gpu_pgxp_cpu = !g_settings.gpu_pgxp_cpu; if (!g_settings.gpu_pgxp_enable) return; + const Settings old_settings = g_settings; + g_settings.gpu_pgxp_cpu = !g_settings.gpu_pgxp_cpu; + g_gpu->RestoreGraphicsAPIState(); - g_gpu->UpdateSettings(); + g_gpu->UpdateSettings(old_settings); System::ClearMemorySaveStates(); Host::AddKeyedOSDMessage("TogglePGXPCPU", g_settings.gpu_pgxp_cpu ? diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 10a548bdb..2cf782936 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -161,7 +161,7 @@ void Settings::Load(SettingsInterface& si) region = ParseConsoleRegionName( si.GetStringValue("Console", "Region", Settings::GetConsoleRegionName(Settings::DEFAULT_CONSOLE_REGION)).c_str()) - .value_or(DEFAULT_CONSOLE_REGION); + .value_or(DEFAULT_CONSOLE_REGION); enable_8mb_ram = si.GetBoolValue("Console", "Enable8MBRAM", false); emulation_speed = si.GetFloatValue("Main", "EmulationSpeed", 1.0f); @@ -192,7 +192,7 @@ void Settings::Load(SettingsInterface& si) cpu_execution_mode = ParseCPUExecutionMode( si.GetStringValue("CPU", "ExecutionMode", GetCPUExecutionModeName(DEFAULT_CPU_EXECUTION_MODE)).c_str()) - .value_or(DEFAULT_CPU_EXECUTION_MODE); + .value_or(DEFAULT_CPU_EXECUTION_MODE); cpu_overclock_numerator = std::max(si.GetIntValue("CPU", "OverclockNumerator", 1), 1); cpu_overclock_denominator = std::max(si.GetIntValue("CPU", "OverclockDenominator", 1), 1); cpu_overclock_enable = si.GetBoolValue("CPU", "OverclockEnable", false); @@ -201,11 +201,11 @@ void Settings::Load(SettingsInterface& si) cpu_recompiler_block_linking = si.GetBoolValue("CPU", "RecompilerBlockLinking", true); cpu_recompiler_icache = si.GetBoolValue("CPU", "RecompilerICache", false); cpu_fastmem_mode = ParseCPUFastmemMode( - si.GetStringValue("CPU", "FastmemMode", GetCPUFastmemModeName(DEFAULT_CPU_FASTMEM_MODE)).c_str()) - .value_or(DEFAULT_CPU_FASTMEM_MODE); + si.GetStringValue("CPU", "FastmemMode", GetCPUFastmemModeName(DEFAULT_CPU_FASTMEM_MODE)).c_str()) + .value_or(DEFAULT_CPU_FASTMEM_MODE); gpu_renderer = ParseRendererName(si.GetStringValue("GPU", "Renderer", GetRendererName(DEFAULT_GPU_RENDERER)).c_str()) - .value_or(DEFAULT_GPU_RENDERER); + .value_or(DEFAULT_GPU_RENDERER); gpu_adapter = si.GetStringValue("GPU", "Adapter", ""); gpu_resolution_scale = static_cast(si.GetIntValue("GPU", "ResolutionScale", 1)); gpu_multisamples = static_cast(si.GetIntValue("GPU", "Multisamples", 1)); @@ -220,11 +220,11 @@ void Settings::Load(SettingsInterface& si) gpu_texture_filter = ParseTextureFilterName( si.GetStringValue("GPU", "TextureFilter", GetTextureFilterName(DEFAULT_GPU_TEXTURE_FILTER)).c_str()) - .value_or(DEFAULT_GPU_TEXTURE_FILTER); + .value_or(DEFAULT_GPU_TEXTURE_FILTER); gpu_downsample_mode = ParseDownsampleModeName( si.GetStringValue("GPU", "DownsampleMode", GetDownsampleModeName(DEFAULT_GPU_DOWNSAMPLE_MODE)).c_str()) - .value_or(DEFAULT_GPU_DOWNSAMPLE_MODE); + .value_or(DEFAULT_GPU_DOWNSAMPLE_MODE); gpu_disable_interlacing = si.GetBoolValue("GPU", "DisableInterlacing", true); gpu_force_ntsc_timings = si.GetBoolValue("GPU", "ForceNTSCTimings", false); gpu_widescreen_hack = si.GetBoolValue("GPU", "WidescreenHack", false); @@ -243,11 +243,11 @@ void Settings::Load(SettingsInterface& si) display_crop_mode = ParseDisplayCropMode( si.GetStringValue("Display", "CropMode", GetDisplayCropModeName(DEFAULT_DISPLAY_CROP_MODE)).c_str()) - .value_or(DEFAULT_DISPLAY_CROP_MODE); + .value_or(DEFAULT_DISPLAY_CROP_MODE); display_aspect_ratio = ParseDisplayAspectRatio( si.GetStringValue("Display", "AspectRatio", GetDisplayAspectRatioName(DEFAULT_DISPLAY_ASPECT_RATIO)).c_str()) - .value_or(DEFAULT_DISPLAY_ASPECT_RATIO); + .value_or(DEFAULT_DISPLAY_ASPECT_RATIO); display_aspect_ratio_custom_numerator = static_cast( std::clamp(si.GetIntValue("Display", "CustomAspectRatioNumerator", 4), 1, std::numeric_limits::max())); display_aspect_ratio_custom_denominator = static_cast( @@ -255,15 +255,15 @@ void Settings::Load(SettingsInterface& si) display_alignment = ParseDisplayAlignment( si.GetStringValue("Display", "Alignment", GetDisplayAlignmentName(DEFAULT_DISPLAY_ALIGNMENT)).c_str()) - .value_or(DEFAULT_DISPLAY_ALIGNMENT); + .value_or(DEFAULT_DISPLAY_ALIGNMENT); + display_scaling = + ParseDisplayScaling(si.GetStringValue("Display", "Scaling", GetDisplayScalingName(DEFAULT_DISPLAY_SCALING)).c_str()) + .value_or(DEFAULT_DISPLAY_SCALING); display_force_4_3_for_24bit = si.GetBoolValue("Display", "Force4_3For24Bit", false); display_active_start_offset = static_cast(si.GetIntValue("Display", "ActiveStartOffset", 0)); display_active_end_offset = static_cast(si.GetIntValue("Display", "ActiveEndOffset", 0)); display_line_start_offset = static_cast(si.GetIntValue("Display", "LineStartOffset", 0)); display_line_end_offset = static_cast(si.GetIntValue("Display", "LineEndOffset", 0)); - display_linear_filtering = si.GetBoolValue("Display", "LinearFiltering", true); - display_integer_scaling = si.GetBoolValue("Display", "IntegerScaling", false); - display_stretch = si.GetBoolValue("Display", "Stretch", false); display_show_osd_messages = si.GetBoolValue("Display", "ShowOSDMessages", true); display_show_fps = si.GetBoolValue("Display", "ShowFPS", false); display_show_speed = si.GetBoolValue("Display", "ShowSpeed", false); @@ -292,13 +292,13 @@ void Settings::Load(SettingsInterface& si) audio_backend = ParseAudioBackend(si.GetStringValue("Audio", "Backend", GetAudioBackendName(DEFAULT_AUDIO_BACKEND)).c_str()) - .value_or(DEFAULT_AUDIO_BACKEND); + .value_or(DEFAULT_AUDIO_BACKEND); audio_driver = si.GetStringValue("Audio", "Driver"); audio_output_device = si.GetStringValue("Audio", "OutputDevice"); audio_stretch_mode = AudioStream::ParseStretchMode( si.GetStringValue("Audio", "StretchMode", AudioStream::GetStretchModeName(DEFAULT_AUDIO_STRETCH_MODE)).c_str()) - .value_or(DEFAULT_AUDIO_STRETCH_MODE); + .value_or(DEFAULT_AUDIO_STRETCH_MODE); audio_output_latency_ms = si.GetUIntValue("Audio", "OutputLatencyMS", DEFAULT_AUDIO_OUTPUT_LATENCY_MS); audio_buffer_ms = si.GetUIntValue("Audio", "BufferMS", DEFAULT_AUDIO_BUFFER_MS); audio_output_volume = si.GetUIntValue("Audio", "OutputVolume", 100); @@ -323,14 +323,14 @@ void Settings::Load(SettingsInterface& si) multitap_mode = ParseMultitapModeName( si.GetStringValue("ControllerPorts", "MultitapMode", GetMultitapModeName(DEFAULT_MULTITAP_MODE)).c_str()) - .value_or(DEFAULT_MULTITAP_MODE); + .value_or(DEFAULT_MULTITAP_MODE); controller_types[0] = ParseControllerTypeName(si.GetStringValue(Controller::GetSettingsSection(0).c_str(), "Type", - GetControllerTypeName(DEFAULT_CONTROLLER_1_TYPE)) - .c_str()) - .value_or(DEFAULT_CONTROLLER_1_TYPE); + GetControllerTypeName(DEFAULT_CONTROLLER_1_TYPE)) + .c_str()) + .value_or(DEFAULT_CONTROLLER_1_TYPE); - const std::array mtap_enabled = {{IsPort1MultitapEnabled(), IsPort2MultitapEnabled()}}; + const std::array mtap_enabled = { {IsPort1MultitapEnabled(), IsPort2MultitapEnabled()} }; for (u32 i = 1; i < NUM_CONTROLLER_AND_CARD_PORTS; i++) { // Ignore types when multitap not enabled @@ -342,19 +342,19 @@ void Settings::Load(SettingsInterface& si) } controller_types[i] = ParseControllerTypeName(si.GetStringValue(Controller::GetSettingsSection(i).c_str(), "Type", - GetControllerTypeName(DEFAULT_CONTROLLER_2_TYPE)) - .c_str()) - .value_or(DEFAULT_CONTROLLER_2_TYPE); + GetControllerTypeName(DEFAULT_CONTROLLER_2_TYPE)) + .c_str()) + .value_or(DEFAULT_CONTROLLER_2_TYPE); } memory_card_types[0] = ParseMemoryCardTypeName( si.GetStringValue("MemoryCards", "Card1Type", GetMemoryCardTypeName(DEFAULT_MEMORY_CARD_1_TYPE)).c_str()) - .value_or(DEFAULT_MEMORY_CARD_1_TYPE); + .value_or(DEFAULT_MEMORY_CARD_1_TYPE); memory_card_types[1] = ParseMemoryCardTypeName( si.GetStringValue("MemoryCards", "Card2Type", GetMemoryCardTypeName(DEFAULT_MEMORY_CARD_2_TYPE)).c_str()) - .value_or(DEFAULT_MEMORY_CARD_2_TYPE); + .value_or(DEFAULT_MEMORY_CARD_2_TYPE); memory_card_paths[0] = si.GetStringValue("MemoryCards", "Card1Path", ""); memory_card_paths[1] = si.GetStringValue("MemoryCards", "Card2Path", ""); memory_card_use_playlist_title = si.GetBoolValue("MemoryCards", "UsePlaylistTitle", true); @@ -372,7 +372,7 @@ void Settings::Load(SettingsInterface& si) achievements_use_raintegration = si.GetBoolValue("Cheevos", "UseRAIntegration", false); log_level = ParseLogLevelName(si.GetStringValue("Logging", "LogLevel", GetLogLevelName(DEFAULT_LOG_LEVEL)).c_str()) - .value_or(DEFAULT_LOG_LEVEL); + .value_or(DEFAULT_LOG_LEVEL); log_filter = si.GetStringValue("Logging", "LogFilter", ""); log_to_console = si.GetBoolValue("Logging", "LogToConsole", DEFAULT_LOG_TO_CONSOLE); log_to_debug = si.GetBoolValue("Logging", "LogToDebug", false); @@ -401,6 +401,12 @@ void Settings::Load(SettingsInterface& si) si.GetIntValue("TextureReplacements", "DumpVRAMWriteWidthThreshold", 128); texture_replacements.dump_vram_write_height_threshold = si.GetIntValue("TextureReplacements", "DumpVRAMWriteHeightThreshold", 128); + +#ifdef __ANDROID__ + // Android users are incredibly silly and don't understand that stretch is in the aspect ratio list... + if (si.GetBoolValue("Display", "Stretch", false)) + display_aspect_ratio = DisplayAspectRatio::MatchWindow; +#endif } void Settings::Save(SettingsInterface& si) const @@ -479,11 +485,9 @@ void Settings::Save(SettingsInterface& si) const si.SetBoolValue("Display", "Force4_3For24Bit", display_force_4_3_for_24bit); si.SetStringValue("Display", "AspectRatio", GetDisplayAspectRatioName(display_aspect_ratio)); si.SetStringValue("Display", "Alignment", GetDisplayAlignmentName(display_alignment)); + si.SetBoolValue("Display", "Scaling", GetDisplayScalingName(display_scaling)); si.SetIntValue("Display", "CustomAspectRatioNumerator", display_aspect_ratio_custom_numerator); si.GetIntValue("Display", "CustomAspectRatioDenominator", display_aspect_ratio_custom_denominator); - si.SetBoolValue("Display", "LinearFiltering", display_linear_filtering); - si.SetBoolValue("Display", "IntegerScaling", display_integer_scaling); - si.SetBoolValue("Display", "Stretch", display_stretch); si.SetBoolValue("Display", "ShowOSDMessages", display_show_osd_messages); si.SetBoolValue("Display", "ShowFPS", display_show_fps); si.SetBoolValue("Display", "ShowSpeed", display_show_speed); @@ -628,18 +632,6 @@ void Settings::FixIncompatibleSettings(bool display_osd_messages) g_settings.pcdrv_enable = false; } - if (g_settings.display_integer_scaling && g_settings.display_linear_filtering) - { - Log_WarningPrintf("Disabling linear filter due to integer upscaling."); - g_settings.display_linear_filtering = false; - } - - if (g_settings.display_integer_scaling && g_settings.display_stretch) - { - Log_WarningPrintf("Disabling stretch due to integer upscaling."); - g_settings.display_stretch = false; - } - if (g_settings.gpu_pgxp_enable) { if (g_settings.gpu_renderer == GPURenderer::Software) @@ -1091,7 +1083,7 @@ const char* Settings::GetDisplayCropModeDisplayName(DisplayCropMode crop_mode) static std::array(DisplayAspectRatio::Count)> s_display_aspect_ratio_names = { {TRANSLATE_NOOP("DisplayAspectRatio", "Auto (Game Native)"), - TRANSLATE_NOOP("DisplayAspectRatio", "Auto (Match Window)"), TRANSLATE_NOOP("DisplayAspectRatio", "Custom"), "4:3", + TRANSLATE_NOOP("DisplayAspectRatio", "Stretch To Fill"), TRANSLATE_NOOP("DisplayAspectRatio", "Custom"), "4:3", "16:9", "19:9", "20:9", "PAR 1:1"}}; static constexpr std::array(DisplayAspectRatio::Count)> s_display_aspect_ratio_values = { {-1.0f, -1.0f, -1.0f, 4.0f / 3.0f, 16.0f / 9.0f, 19.0f / 9.0f, 20.0f / 9.0f, -1.0f}}; @@ -1172,7 +1164,44 @@ const char* Settings::GetDisplayAlignmentName(DisplayAlignment alignment) const char* Settings::GetDisplayAlignmentDisplayName(DisplayAlignment alignment) { - return s_display_alignment_display_names[static_cast(alignment)]; + return Host::TranslateToCString("DisplayAlignment", s_display_alignment_display_names[static_cast(alignment)]); +} + +static std::array(DisplayScalingMode::Count)> s_display_scaling_names = {{ + "Nearest", + "BilinearSmooth", + "NearestInteger", + "BilinearSharp", +}}; +static std::array(DisplayScalingMode::Count)> s_display_scaling_display_names = {{ + TRANSLATE_NOOP("DisplayScalingMode", "Nearest-Neighbor"), + TRANSLATE_NOOP("DisplayScalingMode", "Bilinear (Smooth)"), + TRANSLATE_NOOP("DisplayScalingMode", "Nearest-Neighbor (Integer)"), + TRANSLATE_NOOP("DisplayScalingMode", "Bilinear (Sharp)"), +}}; + +std::optional Settings::ParseDisplayScaling(const char* str) +{ + int index = 0; + for (const char* name : s_display_scaling_names) + { + if (StringUtil::Strcasecmp(name, str) == 0) + return static_cast(index); + + index++; + } + + return std::nullopt; +} + +const char* Settings::GetDisplayScalingName(DisplayScalingMode mode) +{ + return s_display_scaling_names[static_cast(mode)]; +} + +const char* Settings::GetDisplayScalingDisplayName(DisplayScalingMode mode) +{ + return Host::TranslateToCString("DisplayScalingMode", s_display_scaling_display_names[static_cast(mode)]); } static constexpr const char* s_audio_backend_names[] = { @@ -1470,8 +1499,12 @@ bool EmuFolders::EnsureFoldersExist() result = FileSystem::EnsureDirectoryExists(Screenshots.c_str(), false) && result; result = FileSystem::EnsureDirectoryExists(Shaders.c_str(), false) && result; result = FileSystem::EnsureDirectoryExists(Path::Combine(Shaders, "reshade").c_str(), false) && result; - result = FileSystem::EnsureDirectoryExists(Path::Combine(Shaders, "reshade" FS_OSPATH_SEPARATOR_STR "Shaders").c_str(), false) && result; - result = FileSystem::EnsureDirectoryExists(Path::Combine(Shaders, "reshade" FS_OSPATH_SEPARATOR_STR "Textures").c_str(), false) && result; + result = FileSystem::EnsureDirectoryExists( + Path::Combine(Shaders, "reshade" FS_OSPATH_SEPARATOR_STR "Shaders").c_str(), false) && + result; + result = FileSystem::EnsureDirectoryExists( + Path::Combine(Shaders, "reshade" FS_OSPATH_SEPARATOR_STR "Textures").c_str(), false) && + result; result = FileSystem::EnsureDirectoryExists(Textures.c_str(), false) && result; return result; } diff --git a/src/core/settings.h b/src/core/settings.h index 9e39f75a9..bd0a4b596 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -120,6 +120,7 @@ struct Settings DisplayCropMode display_crop_mode = DEFAULT_DISPLAY_CROP_MODE; DisplayAspectRatio display_aspect_ratio = DEFAULT_DISPLAY_ASPECT_RATIO; DisplayAlignment display_alignment = DEFAULT_DISPLAY_ALIGNMENT; + DisplayScalingMode display_scaling = DEFAULT_DISPLAY_SCALING; u16 display_aspect_ratio_custom_numerator = 0; u16 display_aspect_ratio_custom_denominator = 0; s16 display_active_start_offset = 0; @@ -128,9 +129,6 @@ struct Settings s8 display_line_end_offset = 0; bool display_force_4_3_for_24bit = false; bool gpu_24bit_chroma_smoothing = false; - bool display_linear_filtering = true; - bool display_integer_scaling = false; - bool display_stretch = false; bool display_show_osd_messages = true; bool display_show_fps = false; bool display_show_speed = false; @@ -387,6 +385,10 @@ struct Settings static const char* GetDisplayAlignmentName(DisplayAlignment alignment); static const char* GetDisplayAlignmentDisplayName(DisplayAlignment alignment); + static std::optional ParseDisplayScaling(const char* str); + static const char* GetDisplayScalingName(DisplayScalingMode mode); + static const char* GetDisplayScalingDisplayName(DisplayScalingMode mode); + static std::optional ParseAudioBackend(const char* str); static const char* GetAudioBackendName(AudioBackend backend); static const char* GetAudioBackendDisplayName(AudioBackend backend); @@ -448,6 +450,7 @@ struct Settings static constexpr DisplayCropMode DEFAULT_DISPLAY_CROP_MODE = DisplayCropMode::Overscan; static constexpr DisplayAspectRatio DEFAULT_DISPLAY_ASPECT_RATIO = DisplayAspectRatio::Auto; static constexpr DisplayAlignment DEFAULT_DISPLAY_ALIGNMENT = DisplayAlignment::Center; + static constexpr DisplayScalingMode DEFAULT_DISPLAY_SCALING = DisplayScalingMode::BilinearSmooth; static constexpr float DEFAULT_OSD_SCALE = 100.0f; static constexpr u8 DEFAULT_CDROM_READAHEAD_SECTORS = 8; diff --git a/src/core/system.cpp b/src/core/system.cpp index 3ee1e266e..99ba47393 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -2267,7 +2267,7 @@ bool System::LoadStateFromStream(ByteStream* state, bool update_display, bool ig { media_filename.resize(header.media_filename_length); if (!state->SeekAbsolute(header.offset_to_media_filename) || - !state->Read2(media_filename.data(), header.media_filename_length)) + !state->Read2(media_filename.data(), header.media_filename_length)) { return false; } @@ -2288,7 +2288,7 @@ bool System::LoadStateFromStream(ByteStream* state, bool update_display, bool ig Host::AddFormattedOSDMessage( 30.0f, TRANSLATE("OSDMessage", "Failed to open CD image from save state '%s': %s. Using " - "existing image '%s', this may result in instability."), + "existing image '%s', this may result in instability."), media_filename.c_str(), error.GetDescription().c_str(), old_media->GetFileName().c_str()); media = std::move(old_media); header.media_subimage_index = media->GetCurrentSubImage(); @@ -2296,8 +2296,8 @@ bool System::LoadStateFromStream(ByteStream* state, bool update_display, bool ig else { Host::ReportFormattedErrorAsync("Error", - TRANSLATE("System", "Failed to open CD image '%s' used by save state: %s."), - media_filename.c_str(), error.GetDescription().c_str()); + TRANSLATE("System", "Failed to open CD image '%s' used by save state: %s."), + media_filename.c_str(), error.GetDescription().c_str()); return false; } } @@ -2310,8 +2310,8 @@ bool System::LoadStateFromStream(ByteStream* state, bool update_display, bool ig { const u32 num_subimages = media->HasSubImages() ? media->GetSubImageCount() : 1; if (header.media_subimage_index >= num_subimages || - (media->HasSubImages() && media->GetCurrentSubImage() != header.media_subimage_index && - !media->SwitchSubImage(header.media_subimage_index, &error))) + (media->HasSubImages() && media->GetCurrentSubImage() != header.media_subimage_index && + !media->SwitchSubImage(header.media_subimage_index, &error))) { Host::ReportFormattedErrorAsync( "Error", TRANSLATE("System", "Failed to switch to subimage %u in CD image '%s' used by save state: %s."), @@ -3592,6 +3592,7 @@ void System::CheckForSettingsChanges(const Settings& old_settings) g_settings.display_crop_mode != old_settings.display_crop_mode || g_settings.display_aspect_ratio != old_settings.display_aspect_ratio || g_settings.display_alignment != old_settings.display_alignment || + g_settings.display_scaling != old_settings.display_scaling || g_settings.display_show_gpu != old_settings.display_show_gpu || g_settings.gpu_pgxp_enable != old_settings.gpu_pgxp_enable || g_settings.gpu_pgxp_texture_correction != old_settings.gpu_pgxp_texture_correction || @@ -3604,7 +3605,7 @@ void System::CheckForSettingsChanges(const Settings& old_settings) g_settings.rewind_enable != old_settings.rewind_enable || g_settings.runahead_frames != old_settings.runahead_frames) { - g_gpu->UpdateSettings(); + g_gpu->UpdateSettings(old_settings); InvalidateDisplay(); } diff --git a/src/core/types.h b/src/core/types.h index 3092d25f4..91ac0c35d 100644 --- a/src/core/types.h +++ b/src/core/types.h @@ -116,7 +116,7 @@ enum class DisplayAspectRatio : u8 Count }; -enum class DisplayAlignment +enum class DisplayAlignment : u8 { LeftOrTop, Center, @@ -124,6 +124,15 @@ enum class DisplayAlignment Count }; +enum class DisplayScalingMode : u8 +{ + Nearest, + BilinearSmooth, + NearestInteger, + BilinearSharp, + Count +}; + enum class AudioBackend : u8 { Null, diff --git a/src/duckstation-qt/displaysettingswidget.cpp b/src/duckstation-qt/displaysettingswidget.cpp index e14c6a048..880a8afbd 100644 --- a/src/duckstation-qt/displaysettingswidget.cpp +++ b/src/duckstation-qt/displaysettingswidget.cpp @@ -41,9 +41,9 @@ DisplaySettingsWidget::DisplaySettingsWidget(SettingsDialog* dialog, QWidget* pa SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.displayAlignment, "Display", "Alignment", &Settings::ParseDisplayAlignment, &Settings::GetDisplayAlignmentName, Settings::DEFAULT_DISPLAY_ALIGNMENT); - SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.displayLinearFiltering, "Display", "LinearFiltering", true); - SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.displayIntegerScaling, "Display", "IntegerScaling", false); - SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.displayStretch, "Display", "Stretch", false); + SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.displayScaling, "Display", "Scaling", + &Settings::ParseDisplayScaling, &Settings::GetDisplayScalingName, + Settings::DEFAULT_DISPLAY_SCALING); SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.internalResolutionScreenshots, "Display", "InternalResolutionScreenshots", false); SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.vsync, "Display", "VSync", false); @@ -66,10 +66,7 @@ DisplaySettingsWidget::DisplaySettingsWidget(SettingsDialog* dialog, QWidget* pa &DisplaySettingsWidget::onGPUFullscreenModeIndexChanged); connect(m_ui.displayAspectRatio, QOverload::of(&QComboBox::currentIndexChanged), this, &DisplaySettingsWidget::onAspectRatioChanged); - connect(m_ui.displayIntegerScaling, &QCheckBox::stateChanged, this, - &DisplaySettingsWidget::onIntegerFilteringChanged); populateGPUAdaptersAndResolutions(); - onIntegerFilteringChanged(); onAspectRatioChanged(); dialog->registerWidgetHelp( @@ -100,18 +97,9 @@ DisplaySettingsWidget::DisplaySettingsWidget(SettingsDialog* dialog, QWidget* pa m_ui.displayAlignment, tr("Position"), QString::fromUtf8(Settings::GetDisplayAlignmentDisplayName(Settings::DEFAULT_DISPLAY_ALIGNMENT)), tr("Determines the position on the screen when black borders must be added.")); - dialog->registerWidgetHelp(m_ui.displayLinearFiltering, tr("Linear Upscaling"), tr("Checked"), - tr("Uses bilinear texture filtering when displaying the console's framebuffer to the " - "screen.
Disabling filtering " - "will producer a sharper, blockier/pixelated image. Enabling will smooth out the " - "image.
The option will be less " - "noticable the higher the resolution scale.")); dialog->registerWidgetHelp( - m_ui.displayIntegerScaling, tr("Integer Upscaling"), tr("Unchecked"), - tr("Adds padding to the display area to ensure that the ratio between pixels on the host to " - "pixels in the console is an integer number.
May result in a sharper image in some 2D games.")); - dialog->registerWidgetHelp(m_ui.displayStretch, tr("Stretch To Fill"), tr("Unchecked"), - tr("Fills the window with the active display area, regardless of the aspect ratio.")); + m_ui.displayScaling, tr("Scaling"), tr("Bilinear (Smooth)"), + tr("Determines how the emulated console's output is upscaled or downscaled to your monitor's resolution.")); dialog->registerWidgetHelp(m_ui.internalResolutionScreenshots, tr("Internal Resolution Screenshots"), tr("Unchecked"), tr("Saves screenshots at internal render resolution and without postprocessing. If this " "option is disabled, the screenshots will be taken at the window's resolution. " @@ -177,6 +165,12 @@ void DisplaySettingsWidget::setupAdditionalUi() QString::fromUtf8(Settings::GetDisplayCropModeDisplayName(static_cast(i)))); } + for (u32 i = 0; i < static_cast(DisplayScalingMode::Count); i++) + { + m_ui.displayScaling->addItem( + QString::fromUtf8(Settings::GetDisplayScalingDisplayName(static_cast(i)))); + } + for (u32 i = 0; i < static_cast(DisplayAlignment::Count); i++) { m_ui.displayAlignment->addItem( @@ -289,13 +283,6 @@ void DisplaySettingsWidget::onGPUFullscreenModeIndexChanged() m_dialog->setStringSettingValue("GPU", "FullscreenMode", m_ui.fullscreenMode->currentText().toUtf8().constData()); } -void DisplaySettingsWidget::onIntegerFilteringChanged() -{ - const bool integer_scaling = m_dialog->getEffectiveBoolValue("Display", "IntegerScaling", false); - m_ui.displayLinearFiltering->setEnabled(!integer_scaling); - m_ui.displayStretch->setEnabled(!integer_scaling); -} - void DisplaySettingsWidget::onAspectRatioChanged() { const DisplayAspectRatio ratio = diff --git a/src/duckstation-qt/displaysettingswidget.h b/src/duckstation-qt/displaysettingswidget.h index 7a124c767..320013837 100644 --- a/src/duckstation-qt/displaysettingswidget.h +++ b/src/duckstation-qt/displaysettingswidget.h @@ -22,7 +22,6 @@ private Q_SLOTS: void populateGPUAdaptersAndResolutions(); void onGPUAdapterIndexChanged(); void onGPUFullscreenModeIndexChanged(); - void onIntegerFilteringChanged(); void onAspectRatioChanged(); private: diff --git a/src/duckstation-qt/displaysettingswidget.ui b/src/duckstation-qt/displaysettingswidget.ui index 3c1198833..9d9770cc7 100644 --- a/src/duckstation-qt/displaysettingswidget.ui +++ b/src/duckstation-qt/displaysettingswidget.ui @@ -154,40 +154,19 @@ - + Position: - + - + - - - - Integer Upscaling - - - - - - - Stretch To Fill - - - - - - Linear Upscaling - - - - Internal Resolution Screenshots @@ -196,6 +175,16 @@ + + + + Scaling: + + + + + + diff --git a/src/util/gpu_device.cpp b/src/util/gpu_device.cpp index caaabdf13..6b9af1799 100644 --- a/src/util/gpu_device.cpp +++ b/src/util/gpu_device.cpp @@ -426,6 +426,7 @@ bool GPUDevice::CreateResources() plconfig.rasterization = GPUPipeline::RasterizationState::GetNoCullState(); plconfig.depth = GPUPipeline::DepthState::GetNoTestsState(); plconfig.blend = GPUPipeline::BlendState::GetAlphaBlendingState(); + plconfig.blend.write_mask = 0x7; plconfig.color_format = HasSurface() ? m_window_info.surface_format : GPUTexture::Format::RGBA8; plconfig.depth_format = GPUTexture::Format::Unknown; plconfig.samples = 1; diff --git a/src/util/shadergen.cpp b/src/util/shadergen.cpp index 2c5da67d4..a2de5908e 100644 --- a/src/util/shadergen.cpp +++ b/src/util/shadergen.cpp @@ -210,7 +210,8 @@ void ShaderGen::WriteHeader(std::stringstream& ss) ss << "#define SAMPLE_TEXTURE(name, coords) texture(name, coords)\n"; ss << "#define SAMPLE_TEXTURE_OFFSET(name, coords, offset) textureOffset(name, coords, offset)\n"; ss << "#define SAMPLE_TEXTURE_LEVEL(name, coords, level) textureLod(name, coords, level)\n"; - ss << "#define SAMPLE_TEXTURE_LEVEL_OFFSET(name, coords, level, offset) textureLodOffset(name, coords, level, offset)\n"; + ss << "#define SAMPLE_TEXTURE_LEVEL_OFFSET(name, coords, level, offset) textureLodOffset(name, coords, level, " + "offset)\n"; ss << "#define LOAD_TEXTURE(name, coords, mip) texelFetch(name, coords, mip)\n"; ss << "#define LOAD_TEXTURE_MS(name, coords, sample) texelFetch(name, coords, int(sample))\n"; ss << "#define LOAD_TEXTURE_OFFSET(name, coords, mip, offset) texelFetchOffset(name, coords, mip, offset)\n"; @@ -303,7 +304,6 @@ void ShaderGen::WriteUniformBufferDeclaration(std::stringstream& ss, bool push_c ss << "cbuffer UBOBlock : register(b0)\n"; m_has_uniform_buffer = true; } - } void ShaderGen::DeclareUniformBuffer(std::stringstream& ss, const std::initializer_list& members, @@ -680,44 +680,6 @@ std::string ShaderGen::GenerateCopyFragmentShader() return ss.str(); } -std::string ShaderGen::GenerateDisplayVertexShader() -{ - std::stringstream ss; - WriteHeader(ss); - DeclareUniformBuffer(ss, {"float4 u_src_rect"}, true); - DeclareVertexEntryPoint(ss, {}, 0, 1, {}, true); - ss << R"( -{ - float2 pos = float2(float((v_id << 1) & 2u), float(v_id & 2u)); - v_tex0 = u_src_rect.xy + pos * u_src_rect.zw; - v_pos = float4(pos * float2(2.0f, -2.0f) + float2(-1.0f, 1.0f), 0.0f, 1.0f); - #if API_VULKAN - v_pos.y = -v_pos.y; - #endif -} -)"; - - return ss.str(); -} - -std::string ShaderGen::GenerateDisplayFragmentShader(bool set_alpha_to_one /* = false */) -{ - std::stringstream ss; - WriteHeader(ss); - DeclareTexture(ss, "samp0", 0); - DeclareFragmentEntryPoint(ss, 0, 1, {}, false, 1); - ss << "{\n"; - - if (set_alpha_to_one) - ss << "o_col0 = float4(SAMPLE_TEXTURE(samp0, v_tex0).rgb, 1.0f);"; - else - ss << "o_col0 = SAMPLE_TEXTURE(samp0, v_tex0);"; - - ss << "\n}\n"; - - return ss.str(); -} - std::string ShaderGen::GenerateImGuiVertexShader() { std::stringstream ss; diff --git a/src/util/shadergen.h b/src/util/shadergen.h index b2d983404..2d48458b3 100644 --- a/src/util/shadergen.h +++ b/src/util/shadergen.h @@ -20,8 +20,6 @@ public: std::string GenerateUVQuadVertexShader(); std::string GenerateFillFragmentShader(); std::string GenerateCopyFragmentShader(); - std::string GenerateDisplayVertexShader(); - std::string GenerateDisplayFragmentShader(bool set_alpha_to_one = false); std::string GenerateImGuiVertexShader(); std::string GenerateImGuiFragmentShader();