From 85bd1be852ab2ed12cbe47bf0e2d5259aeceed76 Mon Sep 17 00:00:00 2001 From: GPUCode <47210458+GPUCode@users.noreply.github.com> Date: Thu, 23 Nov 2023 02:04:47 +0200 Subject: [PATCH] code: Add texture sampling option (#7118) * This replaces the nearest neighbour filter that shouldn't have existed in the first place --- .../configuration/configure_enhancements.ui | 15 ++---- .../configuration/configure_graphics.cpp | 13 +++++ .../configuration/configure_graphics.ui | 47 +++++++++++++++++++ src/common/settings.cpp | 18 ++++++- src/common/settings.h | 15 ++++-- src/video_core/host_shaders/CMakeLists.txt | 1 - .../texture_filtering/nearest_neighbor.frag | 15 ------ .../rasterizer_cache/rasterizer_cache.h | 21 +++++++-- .../renderer_opengl/gl_blit_helper.cpp | 13 ----- .../renderer_opengl/gl_blit_helper.h | 8 ---- .../renderer_vulkan/vk_blit_helper.h | 3 -- 11 files changed, 110 insertions(+), 59 deletions(-) delete mode 100644 src/video_core/host_shaders/texture_filtering/nearest_neighbor.frag diff --git a/src/citra_qt/configuration/configure_enhancements.ui b/src/citra_qt/configuration/configure_enhancements.ui index 83b85ba9a..ef77b2bc6 100644 --- a/src/citra_qt/configuration/configure_enhancements.ui +++ b/src/citra_qt/configuration/configure_enhancements.ui @@ -184,11 +184,6 @@ Bicubic - - - Nearest Neighbor - - ScaleForce @@ -199,11 +194,11 @@ xBRZ - - - MMPX - - + + + MMPX + + diff --git a/src/citra_qt/configuration/configure_graphics.cpp b/src/citra_qt/configuration/configure_graphics.cpp index 6424e3af1..463b9c848 100644 --- a/src/citra_qt/configuration/configure_graphics.cpp +++ b/src/citra_qt/configuration/configure_graphics.cpp @@ -71,11 +71,17 @@ void ConfigureGraphics::SetConfiguration() { !Settings::values.physical_device.UsingGlobal()); ConfigurationShared::SetPerGameSetting(ui->physical_device_combo, &Settings::values.physical_device); + ConfigurationShared::SetPerGameSetting(ui->texture_sampling_combobox, + &Settings::values.texture_sampling); + ConfigurationShared::SetHighlight(ui->widget_texture_sampling, + !Settings::values.texture_sampling.UsingGlobal()); } else { ui->graphics_api_combo->setCurrentIndex( static_cast(Settings::values.graphics_api.GetValue())); ui->physical_device_combo->setCurrentIndex( static_cast(Settings::values.physical_device.GetValue())); + ui->texture_sampling_combobox->setCurrentIndex( + static_cast(Settings::values.texture_sampling.GetValue())); } ui->toggle_hw_shader->setChecked(Settings::values.use_hw_shader.GetValue()); @@ -106,6 +112,8 @@ void ConfigureGraphics::ApplyConfiguration() { use_hw_shader); ConfigurationShared::ApplyPerGameSetting(&Settings::values.shaders_accurate_mul, ui->toggle_accurate_mul, shaders_accurate_mul); + ConfigurationShared::ApplyPerGameSetting(&Settings::values.texture_sampling, + ui->texture_sampling_combobox); ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_disk_shader_cache, ui->toggle_disk_shader_cache, use_disk_shader_cache); ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vsync_new, ui->toggle_vsync_new, @@ -132,6 +140,7 @@ void ConfigureGraphics::SetupPerGameUI() { Settings::values.use_vsync_new.UsingGlobal()); ui->toggle_async_shaders->setEnabled( Settings::values.async_shader_compilation.UsingGlobal()); + ui->widget_texture_sampling->setEnabled(Settings::values.texture_sampling.UsingGlobal()); ui->toggle_async_present->setEnabled(Settings::values.async_presentation.UsingGlobal()); ui->graphics_api_combo->setEnabled(Settings::values.graphics_api.UsingGlobal()); ui->physical_device_combo->setEnabled(Settings::values.physical_device.UsingGlobal()); @@ -148,6 +157,10 @@ void ConfigureGraphics::SetupPerGameUI() { ui->physical_device_combo, ui->physical_device_group, static_cast(Settings::values.physical_device.GetValue(true))); + ConfigurationShared::SetColoredComboBox( + ui->texture_sampling_combobox, ui->widget_texture_sampling, + static_cast(Settings::values.texture_sampling.GetValue(true))); + ConfigurationShared::SetColoredTristate(ui->toggle_hw_shader, Settings::values.use_hw_shader, use_hw_shader); ConfigurationShared::SetColoredTristate( diff --git a/src/citra_qt/configuration/configure_graphics.ui b/src/citra_qt/configuration/configure_graphics.ui index bd77e6d6b..be0764f4a 100644 --- a/src/citra_qt/configuration/configure_graphics.ui +++ b/src/citra_qt/configuration/configure_graphics.ui @@ -212,6 +212,53 @@ Advanced + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + <html><head/><body><p>Overrides the sampling filter used by games. This can be useful in certain cases with poorly behaved games when upscaling. If unsure set this to Game Controlled</p></body></html> + + + Texture Sampling + + + + + + + + Game Controlled + + + + + Nearest Neighbor + + + + + Linear + + + + + + + diff --git a/src/common/settings.cpp b/src/common/settings.cpp index d0b9af658..486340a3f 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp @@ -46,8 +46,6 @@ std::string_view GetTextureFilterName(TextureFilter filter) { return "Anime4K"; case TextureFilter::Bicubic: return "Bicubic"; - case TextureFilter::NearestNeighbor: - return "NearestNeighbor"; case TextureFilter::ScaleForce: return "ScaleForce"; case TextureFilter::xBRZ: @@ -59,6 +57,19 @@ std::string_view GetTextureFilterName(TextureFilter filter) { } } +std::string_view GetTextureSamplingName(TextureSampling sampling) { + switch (sampling) { + case TextureSampling::GameControlled: + return "GameControlled"; + case TextureSampling::NearestNeighbor: + return "NearestNeighbor"; + case TextureSampling::Linear: + return "Linear"; + default: + return "Invalid"; + } +} + } // Anonymous namespace Values values = {}; @@ -87,6 +98,8 @@ void LogSettings() { log_setting("Renderer_PostProcessingShader", values.pp_shader_name.GetValue()); log_setting("Renderer_FilterMode", values.filter_mode.GetValue()); log_setting("Renderer_TextureFilter", GetTextureFilterName(values.texture_filter.GetValue())); + log_setting("Renderer_TextureSampling", + GetTextureSamplingName(values.texture_sampling.GetValue())); log_setting("Stereoscopy_Render3d", values.render_3d.GetValue()); log_setting("Stereoscopy_Factor3d", values.factor_3d.GetValue()); log_setting("Stereoscopy_MonoRenderOption", values.mono_render_option.GetValue()); @@ -175,6 +188,7 @@ void RestoreGlobalState(bool is_powered_on) { values.resolution_factor.SetGlobal(true); values.frame_limit.SetGlobal(true); values.texture_filter.SetGlobal(true); + values.texture_sampling.SetGlobal(true); values.layout_option.SetGlobal(true); values.swap_screen.SetGlobal(true); values.upright_screen.SetGlobal(true); diff --git a/src/common/settings.h b/src/common/settings.h index aa4b4908e..e37e4eef3 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -72,10 +72,15 @@ enum class TextureFilter : u32 { None = 0, Anime4K = 1, Bicubic = 2, - NearestNeighbor = 3, - ScaleForce = 4, - xBRZ = 5, - MMPX = 6 + ScaleForce = 3, + xBRZ = 4, + MMPX = 5, +}; + +enum class TextureSampling : u32 { + GameControlled = 0, + NearestNeighbor = 1, + Linear = 2, }; namespace NativeButton { @@ -451,6 +456,8 @@ struct Values { SwitchableSetting resolution_factor{1, 0, 10, "resolution_factor"}; SwitchableSetting frame_limit{100, 0, 1000, "frame_limit"}; SwitchableSetting texture_filter{TextureFilter::None, "texture_filter"}; + SwitchableSetting texture_sampling{TextureSampling::GameControlled, + "texture_sampling"}; SwitchableSetting layout_option{LayoutOption::Default, "layout_option"}; SwitchableSetting swap_screen{false, "swap_screen"}; diff --git a/src/video_core/host_shaders/CMakeLists.txt b/src/video_core/host_shaders/CMakeLists.txt index 8acc71c03..27b466876 100644 --- a/src/video_core/host_shaders/CMakeLists.txt +++ b/src/video_core/host_shaders/CMakeLists.txt @@ -7,7 +7,6 @@ set(SHADER_FILES format_reinterpreter/rgba4_to_rgb5a1.frag format_reinterpreter/vulkan_d24s8_to_rgba8.comp texture_filtering/bicubic.frag - texture_filtering/nearest_neighbor.frag texture_filtering/refine.frag texture_filtering/scale_force.frag texture_filtering/xbrz_freescale.frag diff --git a/src/video_core/host_shaders/texture_filtering/nearest_neighbor.frag b/src/video_core/host_shaders/texture_filtering/nearest_neighbor.frag deleted file mode 100644 index e2db96f91..000000000 --- a/src/video_core/host_shaders/texture_filtering/nearest_neighbor.frag +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2023 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -//? #version 430 core -precision mediump float; - -layout(location = 0) in vec2 tex_coord; -layout(location = 0) out vec4 frag_color; - -layout(binding = 2) uniform sampler2D input_texture; - -void main() { - frag_color = texture(input_texture, tex_coord); -} diff --git a/src/video_core/rasterizer_cache/rasterizer_cache.h b/src/video_core/rasterizer_cache/rasterizer_cache.h index efb3eeb58..92f1613a1 100644 --- a/src/video_core/rasterizer_cache/rasterizer_cache.h +++ b/src/video_core/rasterizer_cache/rasterizer_cache.h @@ -361,10 +361,25 @@ typename T::Sampler& RasterizerCache::GetSampler(SamplerId sampler_id) { template typename T::Sampler& RasterizerCache::GetSampler( const Pica::TexturingRegs::TextureConfig& config) { + using TextureFilter = Pica::TexturingRegs::TextureConfig::TextureFilter; + + const auto get_filter = [](TextureFilter filter) { + switch (Settings::values.texture_sampling.GetValue()) { + case Settings::TextureSampling::GameControlled: + return filter; + case Settings::TextureSampling::NearestNeighbor: + return TextureFilter::Nearest; + case Settings::TextureSampling::Linear: + return TextureFilter::Linear; + default: + return filter; + } + }; + const SamplerParams params = { - .mag_filter = config.mag_filter, - .min_filter = config.min_filter, - .mip_filter = config.mip_filter, + .mag_filter = get_filter(config.mag_filter), + .min_filter = get_filter(config.min_filter), + .mip_filter = get_filter(config.mip_filter), .wrap_s = config.wrap_s, .wrap_t = config.wrap_t, .border_color = config.border_color.raw, diff --git a/src/video_core/renderer_opengl/gl_blit_helper.cpp b/src/video_core/renderer_opengl/gl_blit_helper.cpp index 830d28e32..73484894b 100644 --- a/src/video_core/renderer_opengl/gl_blit_helper.cpp +++ b/src/video_core/renderer_opengl/gl_blit_helper.cpp @@ -15,7 +15,6 @@ #include "video_core/host_shaders/full_screen_triangle_vert.h" #include "video_core/host_shaders/texture_filtering/bicubic_frag.h" #include "video_core/host_shaders/texture_filtering/mmpx_frag.h" -#include "video_core/host_shaders/texture_filtering/nearest_neighbor_frag.h" #include "video_core/host_shaders/texture_filtering/refine_frag.h" #include "video_core/host_shaders/texture_filtering/scale_force_frag.h" #include "video_core/host_shaders/texture_filtering/x_gradient_frag.h" @@ -58,7 +57,6 @@ BlitHelper::BlitHelper(const Driver& driver_) : driver{driver_}, linear_sampler{CreateSampler(GL_LINEAR)}, nearest_sampler{CreateSampler(GL_NEAREST)}, bicubic_program{CreateProgram( HostShaders::BICUBIC_FRAG)}, - nearest_program{CreateProgram(HostShaders::NEAREST_NEIGHBOR_FRAG)}, scale_force_program{CreateProgram(HostShaders::SCALE_FORCE_FRAG)}, xbrz_program{CreateProgram(HostShaders::XBRZ_FREESCALE_FRAG)}, mmpx_program{CreateProgram(HostShaders::MMPX_FRAG)}, gradient_x_program{CreateProgram( @@ -175,9 +173,6 @@ bool BlitHelper::Filter(Surface& surface, const VideoCore::TextureBlit& blit) { case TextureFilter::Bicubic: FilterBicubic(surface, blit); break; - case TextureFilter::NearestNeighbor: - FilterNearest(surface, blit); - break; case TextureFilter::ScaleForce: FilterScaleForce(surface, blit); break; @@ -257,14 +252,6 @@ void BlitHelper::FilterBicubic(Surface& surface, const VideoCore::TextureBlit& b Draw(bicubic_program, surface.Handle(), draw_fbo.handle, blit.dst_level, blit.dst_rect); } -void BlitHelper::FilterNearest(Surface& surface, const VideoCore::TextureBlit& blit) { - const OpenGLState prev_state = OpenGLState::GetCurState(); - SCOPE_EXIT({ prev_state.Apply(); }); - state.texture_units[2].texture_2d = surface.Handle(0); - SetParams(nearest_program, surface.RealExtent(false), blit.src_rect); - Draw(nearest_program, surface.Handle(), draw_fbo.handle, blit.dst_level, blit.dst_rect); -} - void BlitHelper::FilterScaleForce(Surface& surface, const VideoCore::TextureBlit& blit) { const OpenGLState prev_state = OpenGLState::GetCurState(); SCOPE_EXIT({ prev_state.Apply(); }); diff --git a/src/video_core/renderer_opengl/gl_blit_helper.h b/src/video_core/renderer_opengl/gl_blit_helper.h index e6ba9cce5..054fdef84 100644 --- a/src/video_core/renderer_opengl/gl_blit_helper.h +++ b/src/video_core/renderer_opengl/gl_blit_helper.h @@ -33,20 +33,13 @@ public: private: void FilterAnime4K(Surface& surface, const VideoCore::TextureBlit& blit); - void FilterBicubic(Surface& surface, const VideoCore::TextureBlit& blit); - - void FilterNearest(Surface& surface, const VideoCore::TextureBlit& blit); - void FilterScaleForce(Surface& surface, const VideoCore::TextureBlit& blit); - void FilterXbrz(Surface& surface, const VideoCore::TextureBlit& blit); - void FilterMMPX(Surface& surface, const VideoCore::TextureBlit& blit); void SetParams(OGLProgram& program, const VideoCore::Extent& src_extent, Common::Rectangle src_rect); - void Draw(OGLProgram& program, GLuint dst_tex, GLuint dst_fbo, u32 dst_level, Common::Rectangle dst_rect); @@ -59,7 +52,6 @@ private: OGLSampler nearest_sampler; OGLProgram bicubic_program; - OGLProgram nearest_program; OGLProgram scale_force_program; OGLProgram xbrz_program; OGLProgram mmpx_program; diff --git a/src/video_core/renderer_vulkan/vk_blit_helper.h b/src/video_core/renderer_vulkan/vk_blit_helper.h index b7735fcc9..8060a225b 100644 --- a/src/video_core/renderer_vulkan/vk_blit_helper.h +++ b/src/video_core/renderer_vulkan/vk_blit_helper.h @@ -35,10 +35,7 @@ public: const VideoCore::BufferTextureCopy& copy); private: - /// Creates compute pipelines used for blit vk::Pipeline MakeComputePipeline(vk::ShaderModule shader, vk::PipelineLayout layout); - - /// Creates graphics pipelines used for blit vk::Pipeline MakeDepthStencilBlitPipeline(); private: