diff --git a/src/core/gpu_hw.cpp b/src/core/gpu_hw.cpp index 217ac4615..1750e291f 100644 --- a/src/core/gpu_hw.cpp +++ b/src/core/gpu_hw.cpp @@ -26,9 +26,11 @@ bool GPU_HW::Initialize(HostDisplay* host_display, System* system, DMA* dma, Int if (!GPU::Initialize(host_display, system, dma, interrupt_controller, timers)) return false; - m_resolution_scale = m_system->GetSettings().gpu_resolution_scale; - m_true_color = m_system->GetSettings().gpu_true_color; - m_texture_filtering = m_system->GetSettings().gpu_texture_filtering; + const Settings& settings = m_system->GetSettings(); + m_resolution_scale = settings.gpu_resolution_scale; + m_true_color = settings.gpu_true_color; + m_scaled_dithering = settings.gpu_scaled_dithering; + m_texture_filtering = settings.gpu_texture_filtering; if (m_resolution_scale < 1 || m_resolution_scale > m_max_resolution_scale) { m_system->GetHostInterface()->AddFormattedOSDMessage(5.0f, "Invalid resolution scale %ux specified. Maximum is %u.", @@ -68,9 +70,11 @@ void GPU_HW::UpdateSettings() { GPU::UpdateSettings(); - m_resolution_scale = std::clamp(m_system->GetSettings().gpu_resolution_scale, 1, m_max_resolution_scale); - m_true_color = m_system->GetSettings().gpu_true_color; - m_texture_filtering = m_system->GetSettings().gpu_texture_filtering; + const Settings& settings = m_system->GetSettings(); + m_resolution_scale = std::clamp(settings.gpu_resolution_scale, 1, m_max_resolution_scale); + m_true_color = settings.gpu_true_color; + m_scaled_dithering = settings.gpu_scaled_dithering; + m_texture_filtering = settings.gpu_texture_filtering; } void GPU_HW::LoadVertices(RenderCommand rc, u32 num_vertices, const u32* command_ptr) diff --git a/src/core/gpu_hw.h b/src/core/gpu_hw.h index 1f3baebf5..48c857d65 100644 --- a/src/core/gpu_hw.h +++ b/src/core/gpu_hw.h @@ -161,7 +161,8 @@ protected: u32 m_resolution_scale = 1; u32 m_max_resolution_scale = 1; - bool m_true_color = false; + bool m_true_color = true; + bool m_scaled_dithering = false; bool m_texture_filtering = false; bool m_supports_dual_source_blend = false; diff --git a/src/core/gpu_hw_d3d11.cpp b/src/core/gpu_hw_d3d11.cpp index 80a7b8e36..fbea38a2f 100644 --- a/src/core/gpu_hw_d3d11.cpp +++ b/src/core/gpu_hw_d3d11.cpp @@ -242,8 +242,8 @@ bool GPU_HW_D3D11::CreateBatchInputLayout() {"ATTR", 3, DXGI_FORMAT_R32_SINT, 0, offsetof(BatchVertex, texpage), D3D11_INPUT_PER_VERTEX_DATA, 0}}}; // we need a vertex shader... - GPU_HW_ShaderGen shadergen(m_host_display->GetRenderAPI(), m_resolution_scale, m_true_color, m_texture_filtering, - m_supports_dual_source_blend); + GPU_HW_ShaderGen shadergen(m_host_display->GetRenderAPI(), m_resolution_scale, m_true_color, m_scaled_dithering, + m_texture_filtering, m_supports_dual_source_blend); ComPtr vs_bytecode = m_shader_cache.GetShaderBlob(D3D11::ShaderCompiler::Type::Vertex, shadergen.GenerateBatchVertexShader(true)); if (!vs_bytecode) @@ -325,8 +325,8 @@ bool GPU_HW_D3D11::CreateStateObjects() bool GPU_HW_D3D11::CompileShaders() { - GPU_HW_ShaderGen shadergen(m_host_display->GetRenderAPI(), m_resolution_scale, m_true_color, m_texture_filtering, - m_supports_dual_source_blend); + GPU_HW_ShaderGen shadergen(m_host_display->GetRenderAPI(), m_resolution_scale, m_true_color, m_scaled_dithering, + m_texture_filtering, m_supports_dual_source_blend); m_system->GetHostInterface()->DisplayLoadingScreen("Compiling shaders..."); diff --git a/src/core/gpu_hw_opengl.cpp b/src/core/gpu_hw_opengl.cpp index 4c4cc3d9c..f5d2ce6f9 100644 --- a/src/core/gpu_hw_opengl.cpp +++ b/src/core/gpu_hw_opengl.cpp @@ -290,8 +290,8 @@ bool GPU_HW_OpenGL::CreateTextureBuffer() bool GPU_HW_OpenGL::CompilePrograms() { - GPU_HW_ShaderGen shadergen(m_host_display->GetRenderAPI(), m_resolution_scale, m_true_color, m_texture_filtering, - m_supports_dual_source_blend); + GPU_HW_ShaderGen shadergen(m_host_display->GetRenderAPI(), m_resolution_scale, m_true_color, m_scaled_dithering, + m_texture_filtering, m_supports_dual_source_blend); m_system->GetHostInterface()->DisplayLoadingScreen("Compiling Shaders..."); diff --git a/src/core/gpu_hw_opengl_es.cpp b/src/core/gpu_hw_opengl_es.cpp index 2ae57b8fd..207cff22c 100644 --- a/src/core/gpu_hw_opengl_es.cpp +++ b/src/core/gpu_hw_opengl_es.cpp @@ -188,8 +188,8 @@ void GPU_HW_OpenGL_ES::ClearFramebuffer() bool GPU_HW_OpenGL_ES::CompilePrograms() { - GPU_HW_ShaderGen shadergen(m_host_display->GetRenderAPI(), m_resolution_scale, m_true_color, m_texture_filtering, - m_supports_dual_source_blend); + GPU_HW_ShaderGen shadergen(m_host_display->GetRenderAPI(), m_resolution_scale, m_true_color, m_scaled_dithering, + m_texture_filtering, m_supports_dual_source_blend); for (u32 render_mode = 0; render_mode < 4; render_mode++) { diff --git a/src/core/gpu_hw_shadergen.cpp b/src/core/gpu_hw_shadergen.cpp index b48868a38..1434772eb 100644 --- a/src/core/gpu_hw_shadergen.cpp +++ b/src/core/gpu_hw_shadergen.cpp @@ -6,10 +6,11 @@ Log_SetChannel(GPU_HW_ShaderGen); GPU_HW_ShaderGen::GPU_HW_ShaderGen(HostDisplay::RenderAPI render_api, u32 resolution_scale, bool true_color, - bool texture_filtering, bool supports_dual_source_blend) + bool scaled_dithering, bool texture_filtering, bool supports_dual_source_blend) : m_render_api(render_api), m_resolution_scale(resolution_scale), m_true_color(true_color), - m_texture_filering(texture_filtering), m_glsl(render_api != HostDisplay::RenderAPI::D3D11), - m_glsl_es(render_api == HostDisplay::RenderAPI::OpenGLES), m_supports_dual_source_blend(supports_dual_source_blend) + m_scaled_dithering(scaled_dithering), m_texture_filering(texture_filtering), + m_glsl(render_api != HostDisplay::RenderAPI::D3D11), m_glsl_es(render_api == HostDisplay::RenderAPI::OpenGLES), + m_supports_dual_source_blend(supports_dual_source_blend) { if (m_glsl) SetGLSLVersionString(); @@ -411,6 +412,7 @@ std::string GPU_HW_ShaderGen::GenerateBatchFragmentShader(GPU_HW::BatchRenderMod DefineMacro(ss, "PALETTE_8_BIT", actual_texture_mode == GPU::TextureMode::Palette8Bit); DefineMacro(ss, "RAW_TEXTURE", raw_texture); DefineMacro(ss, "DITHERING", dithering); + DefineMacro(ss, "DITHERING_SCALED", m_scaled_dithering); DefineMacro(ss, "TRUE_COLOR", m_true_color); DefineMacro(ss, "TEXTURE_FILTERING", m_texture_filering); DefineMacro(ss, "USE_DUAL_SOURCE", use_dual_source); @@ -570,7 +572,11 @@ float4 SampleFromVRAM(int4 texpage, int2 icoord) // Apply dithering #if DITHERING - icolor = ApplyDithering(int2(v_pos.xy) / int2(RESOLUTION_SCALE, RESOLUTION_SCALE), icolor); + #if DITHERING_SCALED + icolor = ApplyDithering(int2(v_pos.xy), icolor); + #else + icolor = ApplyDithering(int2(v_pos.xy) / int2(RESOLUTION_SCALE, RESOLUTION_SCALE), icolor); + #endif #endif // Clip to 15-bit range diff --git a/src/core/gpu_hw_shadergen.h b/src/core/gpu_hw_shadergen.h index b7c1a7cfa..a4d788e63 100644 --- a/src/core/gpu_hw_shadergen.h +++ b/src/core/gpu_hw_shadergen.h @@ -7,7 +7,7 @@ class GPU_HW_ShaderGen { public: - GPU_HW_ShaderGen(HostDisplay::RenderAPI render_api, u32 resolution_scale, bool true_color, + GPU_HW_ShaderGen(HostDisplay::RenderAPI render_api, u32 resolution_scale, bool true_color, bool scaled_dithering, bool texture_filtering, bool supports_dual_source_belnd); ~GPU_HW_ShaderGen(); @@ -25,6 +25,7 @@ public: HostDisplay::RenderAPI m_render_api; u32 m_resolution_scale; bool m_true_color; + bool m_scaled_dithering; bool m_texture_filering; bool m_glsl; bool m_glsl_es; diff --git a/src/core/host_interface.cpp b/src/core/host_interface.cpp index e2712ae22..b0f0aaa02 100644 --- a/src/core/host_interface.cpp +++ b/src/core/host_interface.cpp @@ -812,6 +812,7 @@ void HostInterface::SetDefaultSettings(SettingsInterface& si) si.SetStringValue("GPU", "Renderer", Settings::GetRendererName(Settings::DEFAULT_GPU_RENDERER)); si.SetIntValue("GPU", "ResolutionScale", 1); si.SetBoolValue("GPU", "TrueColor", true); + si.SetBoolValue("GPU", "ScaledDithering", false); si.SetBoolValue("GPU", "TextureFiltering", false); si.SetBoolValue("GPU", "UseDebugDevice", false); @@ -855,6 +856,7 @@ void HostInterface::UpdateSettings(const std::function& apply_callback) const GPURenderer old_gpu_renderer = m_settings.gpu_renderer; const u32 old_gpu_resolution_scale = m_settings.gpu_resolution_scale; const bool old_gpu_true_color = m_settings.gpu_true_color; + const bool old_gpu_scaled_dithering = m_settings.gpu_scaled_dithering; const bool old_gpu_texture_filtering = m_settings.gpu_texture_filtering; const bool old_display_force_progressive_scan = m_settings.display_force_progressive_scan; const bool old_gpu_debug_device = m_settings.gpu_use_debug_device; @@ -907,6 +909,7 @@ void HostInterface::UpdateSettings(const std::function& apply_callback) if (m_settings.gpu_resolution_scale != old_gpu_resolution_scale || m_settings.gpu_true_color != old_gpu_true_color || + m_settings.gpu_scaled_dithering != old_gpu_scaled_dithering || m_settings.gpu_texture_filtering != old_gpu_texture_filtering || m_settings.display_force_progressive_scan != old_display_force_progressive_scan || m_settings.display_crop_mode != old_display_crop_mode) diff --git a/src/core/settings.cpp b/src/core/settings.cpp index dcdb10d47..2c570c49f 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -22,7 +22,8 @@ void Settings::Load(SettingsInterface& si) gpu_renderer = ParseRendererName(si.GetStringValue("GPU", "Renderer", GetRendererName(DEFAULT_GPU_RENDERER)).c_str()) .value_or(DEFAULT_GPU_RENDERER); gpu_resolution_scale = static_cast(si.GetIntValue("GPU", "ResolutionScale", 1)); - gpu_true_color = si.GetBoolValue("GPU", "TrueColor", false); + gpu_true_color = si.GetBoolValue("GPU", "TrueColor", true); + gpu_scaled_dithering = si.GetBoolValue("GPU", "ScaledDithering", false); gpu_texture_filtering = si.GetBoolValue("GPU", "TextureFiltering", false); gpu_use_debug_device = si.GetBoolValue("GPU", "UseDebugDevice", false); @@ -78,6 +79,7 @@ void Settings::Save(SettingsInterface& si) const si.SetStringValue("GPU", "Renderer", GetRendererName(gpu_renderer)); si.SetIntValue("GPU", "ResolutionScale", static_cast(gpu_resolution_scale)); si.SetBoolValue("GPU", "TrueColor", gpu_true_color); + si.SetBoolValue("GPU", "ScaledDithering", gpu_scaled_dithering); si.SetBoolValue("GPU", "TextureFiltering", gpu_texture_filtering); si.SetBoolValue("GPU", "UseDebugDevice", gpu_use_debug_device); diff --git a/src/core/settings.h b/src/core/settings.h index 344817cca..62b7358e1 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -46,7 +46,8 @@ struct Settings GPURenderer gpu_renderer = GPURenderer::Software; u32 gpu_resolution_scale = 1; - bool gpu_true_color = false; + bool gpu_true_color = true; + bool gpu_scaled_dithering = false; bool gpu_texture_filtering = false; bool gpu_use_debug_device = false; DisplayCropMode display_crop_mode = DisplayCropMode::None; diff --git a/src/duckstation-qt/gpusettingswidget.cpp b/src/duckstation-qt/gpusettingswidget.cpp index f1c2d14c6..c97def9bc 100644 --- a/src/duckstation-qt/gpusettingswidget.cpp +++ b/src/duckstation-qt/gpusettingswidget.cpp @@ -22,11 +22,25 @@ GPUSettingsWidget::GPUSettingsWidget(QtHostInterface* host_interface, QWidget* p SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.vsync, "Display/VSync"); SettingWidgetBinder::BindWidgetToIntSetting(m_host_interface, m_ui.resolutionScale, "GPU/ResolutionScale"); SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.trueColor, "GPU/TrueColor"); + SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.scaledDithering, "GPU/ScaledDithering"); SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.linearTextureFiltering, "GPU/TextureFiltering"); + + connect(m_ui.resolutionScale, static_cast(&QComboBox::currentIndexChanged), this, + &GPUSettingsWidget::updateScaledDitheringEnabled); + connect(m_ui.trueColor, &QCheckBox::stateChanged, this, &GPUSettingsWidget::updateScaledDitheringEnabled); + updateScaledDitheringEnabled(); } GPUSettingsWidget::~GPUSettingsWidget() = default; +void GPUSettingsWidget::updateScaledDitheringEnabled() +{ + const int resolution_scale = m_ui.resolutionScale->currentIndex(); + const bool true_color = m_ui.trueColor->isChecked(); + const bool allow_scaled_dithering = (resolution_scale != 1 && !true_color); + m_ui.scaledDithering->setEnabled(allow_scaled_dithering); +} + void GPUSettingsWidget::setupAdditionalUi() { for (u32 i = 0; i < static_cast(GPURenderer::Count); i++) diff --git a/src/duckstation-qt/gpusettingswidget.h b/src/duckstation-qt/gpusettingswidget.h index 5847de7fc..89e8f1e30 100644 --- a/src/duckstation-qt/gpusettingswidget.h +++ b/src/duckstation-qt/gpusettingswidget.h @@ -14,6 +14,9 @@ public: GPUSettingsWidget(QtHostInterface* host_interface, QWidget* parent = nullptr); ~GPUSettingsWidget(); +private Q_SLOTS: + void updateScaledDitheringEnabled(); + private: void setupAdditionalUi(); diff --git a/src/duckstation-qt/gpusettingswidget.ui b/src/duckstation-qt/gpusettingswidget.ui index d60426e07..8273db9ab 100644 --- a/src/duckstation-qt/gpusettingswidget.ui +++ b/src/duckstation-qt/gpusettingswidget.ui @@ -123,6 +123,13 @@ + + + Scaled Dithering (scale dither pattern to resolution) + + + + Bilinear Texture Filtering diff --git a/src/duckstation-sdl/sdl_host_interface.cpp b/src/duckstation-sdl/sdl_host_interface.cpp index 3c09a423a..1fde71b3a 100644 --- a/src/duckstation-sdl/sdl_host_interface.cpp +++ b/src/duckstation-sdl/sdl_host_interface.cpp @@ -885,6 +885,7 @@ void SDLHostInterface::DrawQuickSettingsMenu() } settings_changed |= ImGui::MenuItem("True (24-Bit) Color", nullptr, &m_settings_copy.gpu_true_color); + settings_changed |= ImGui::MenuItem("Scaled Dithering", nullptr, &m_settings_copy.gpu_scaled_dithering); settings_changed |= ImGui::MenuItem("Texture Filtering", nullptr, &m_settings_copy.gpu_texture_filtering); settings_changed |= ImGui::MenuItem("Display Linear Filtering", nullptr, &m_settings_copy.display_linear_filtering);