code: Add texture sampling option (#7118)

* This replaces the nearest neighbour filter that shouldn't have existed in the first place
This commit is contained in:
GPUCode 2023-11-23 02:04:47 +02:00 committed by GitHub
parent c17ec1d1aa
commit 85bd1be852
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 110 additions and 59 deletions

View file

@ -184,11 +184,6 @@
<string>Bicubic</string> <string>Bicubic</string>
</property> </property>
</item> </item>
<item>
<property name="text">
<string>Nearest Neighbor</string>
</property>
</item>
<item> <item>
<property name="text"> <property name="text">
<string>ScaleForce</string> <string>ScaleForce</string>

View file

@ -71,11 +71,17 @@ void ConfigureGraphics::SetConfiguration() {
!Settings::values.physical_device.UsingGlobal()); !Settings::values.physical_device.UsingGlobal());
ConfigurationShared::SetPerGameSetting(ui->physical_device_combo, ConfigurationShared::SetPerGameSetting(ui->physical_device_combo,
&Settings::values.physical_device); &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 { } else {
ui->graphics_api_combo->setCurrentIndex( ui->graphics_api_combo->setCurrentIndex(
static_cast<int>(Settings::values.graphics_api.GetValue())); static_cast<int>(Settings::values.graphics_api.GetValue()));
ui->physical_device_combo->setCurrentIndex( ui->physical_device_combo->setCurrentIndex(
static_cast<int>(Settings::values.physical_device.GetValue())); static_cast<int>(Settings::values.physical_device.GetValue()));
ui->texture_sampling_combobox->setCurrentIndex(
static_cast<int>(Settings::values.texture_sampling.GetValue()));
} }
ui->toggle_hw_shader->setChecked(Settings::values.use_hw_shader.GetValue()); ui->toggle_hw_shader->setChecked(Settings::values.use_hw_shader.GetValue());
@ -106,6 +112,8 @@ void ConfigureGraphics::ApplyConfiguration() {
use_hw_shader); use_hw_shader);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.shaders_accurate_mul, ConfigurationShared::ApplyPerGameSetting(&Settings::values.shaders_accurate_mul,
ui->toggle_accurate_mul, 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, ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_disk_shader_cache,
ui->toggle_disk_shader_cache, use_disk_shader_cache); ui->toggle_disk_shader_cache, use_disk_shader_cache);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vsync_new, ui->toggle_vsync_new, ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vsync_new, ui->toggle_vsync_new,
@ -132,6 +140,7 @@ void ConfigureGraphics::SetupPerGameUI() {
Settings::values.use_vsync_new.UsingGlobal()); Settings::values.use_vsync_new.UsingGlobal());
ui->toggle_async_shaders->setEnabled( ui->toggle_async_shaders->setEnabled(
Settings::values.async_shader_compilation.UsingGlobal()); 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->toggle_async_present->setEnabled(Settings::values.async_presentation.UsingGlobal());
ui->graphics_api_combo->setEnabled(Settings::values.graphics_api.UsingGlobal()); ui->graphics_api_combo->setEnabled(Settings::values.graphics_api.UsingGlobal());
ui->physical_device_combo->setEnabled(Settings::values.physical_device.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, ui->physical_device_combo, ui->physical_device_group,
static_cast<u32>(Settings::values.physical_device.GetValue(true))); static_cast<u32>(Settings::values.physical_device.GetValue(true)));
ConfigurationShared::SetColoredComboBox(
ui->texture_sampling_combobox, ui->widget_texture_sampling,
static_cast<int>(Settings::values.texture_sampling.GetValue(true)));
ConfigurationShared::SetColoredTristate(ui->toggle_hw_shader, Settings::values.use_hw_shader, ConfigurationShared::SetColoredTristate(ui->toggle_hw_shader, Settings::values.use_hw_shader,
use_hw_shader); use_hw_shader);
ConfigurationShared::SetColoredTristate( ConfigurationShared::SetColoredTristate(

View file

@ -212,6 +212,53 @@
<string>Advanced</string> <string>Advanced</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_2"> <layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QWidget" name="widget_texture_sampling" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="texture_sampling_label">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;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&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Texture Sampling</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="texture_sampling_combobox">
<item>
<property name="text">
<string>Game Controlled</string>
</property>
</item>
<item>
<property name="text">
<string>Nearest Neighbor</string>
</property>
</item>
<item>
<property name="text">
<string>Linear</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
<item> <item>
<widget class="QCheckBox" name="toggle_disk_shader_cache"> <widget class="QCheckBox" name="toggle_disk_shader_cache">
<property name="toolTip"> <property name="toolTip">

View file

@ -46,8 +46,6 @@ std::string_view GetTextureFilterName(TextureFilter filter) {
return "Anime4K"; return "Anime4K";
case TextureFilter::Bicubic: case TextureFilter::Bicubic:
return "Bicubic"; return "Bicubic";
case TextureFilter::NearestNeighbor:
return "NearestNeighbor";
case TextureFilter::ScaleForce: case TextureFilter::ScaleForce:
return "ScaleForce"; return "ScaleForce";
case TextureFilter::xBRZ: 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 } // Anonymous namespace
Values values = {}; Values values = {};
@ -87,6 +98,8 @@ void LogSettings() {
log_setting("Renderer_PostProcessingShader", values.pp_shader_name.GetValue()); log_setting("Renderer_PostProcessingShader", values.pp_shader_name.GetValue());
log_setting("Renderer_FilterMode", values.filter_mode.GetValue()); log_setting("Renderer_FilterMode", values.filter_mode.GetValue());
log_setting("Renderer_TextureFilter", GetTextureFilterName(values.texture_filter.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_Render3d", values.render_3d.GetValue());
log_setting("Stereoscopy_Factor3d", values.factor_3d.GetValue()); log_setting("Stereoscopy_Factor3d", values.factor_3d.GetValue());
log_setting("Stereoscopy_MonoRenderOption", values.mono_render_option.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.resolution_factor.SetGlobal(true);
values.frame_limit.SetGlobal(true); values.frame_limit.SetGlobal(true);
values.texture_filter.SetGlobal(true); values.texture_filter.SetGlobal(true);
values.texture_sampling.SetGlobal(true);
values.layout_option.SetGlobal(true); values.layout_option.SetGlobal(true);
values.swap_screen.SetGlobal(true); values.swap_screen.SetGlobal(true);
values.upright_screen.SetGlobal(true); values.upright_screen.SetGlobal(true);

View file

@ -72,10 +72,15 @@ enum class TextureFilter : u32 {
None = 0, None = 0,
Anime4K = 1, Anime4K = 1,
Bicubic = 2, Bicubic = 2,
NearestNeighbor = 3, ScaleForce = 3,
ScaleForce = 4, xBRZ = 4,
xBRZ = 5, MMPX = 5,
MMPX = 6 };
enum class TextureSampling : u32 {
GameControlled = 0,
NearestNeighbor = 1,
Linear = 2,
}; };
namespace NativeButton { namespace NativeButton {
@ -451,6 +456,8 @@ struct Values {
SwitchableSetting<u32, true> resolution_factor{1, 0, 10, "resolution_factor"}; SwitchableSetting<u32, true> resolution_factor{1, 0, 10, "resolution_factor"};
SwitchableSetting<u16, true> frame_limit{100, 0, 1000, "frame_limit"}; SwitchableSetting<u16, true> frame_limit{100, 0, 1000, "frame_limit"};
SwitchableSetting<TextureFilter> texture_filter{TextureFilter::None, "texture_filter"}; SwitchableSetting<TextureFilter> texture_filter{TextureFilter::None, "texture_filter"};
SwitchableSetting<TextureSampling> texture_sampling{TextureSampling::GameControlled,
"texture_sampling"};
SwitchableSetting<LayoutOption> layout_option{LayoutOption::Default, "layout_option"}; SwitchableSetting<LayoutOption> layout_option{LayoutOption::Default, "layout_option"};
SwitchableSetting<bool> swap_screen{false, "swap_screen"}; SwitchableSetting<bool> swap_screen{false, "swap_screen"};

View file

@ -7,7 +7,6 @@ set(SHADER_FILES
format_reinterpreter/rgba4_to_rgb5a1.frag format_reinterpreter/rgba4_to_rgb5a1.frag
format_reinterpreter/vulkan_d24s8_to_rgba8.comp format_reinterpreter/vulkan_d24s8_to_rgba8.comp
texture_filtering/bicubic.frag texture_filtering/bicubic.frag
texture_filtering/nearest_neighbor.frag
texture_filtering/refine.frag texture_filtering/refine.frag
texture_filtering/scale_force.frag texture_filtering/scale_force.frag
texture_filtering/xbrz_freescale.frag texture_filtering/xbrz_freescale.frag

View file

@ -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);
}

View file

@ -361,10 +361,25 @@ typename T::Sampler& RasterizerCache<T>::GetSampler(SamplerId sampler_id) {
template <class T> template <class T>
typename T::Sampler& RasterizerCache<T>::GetSampler( typename T::Sampler& RasterizerCache<T>::GetSampler(
const Pica::TexturingRegs::TextureConfig& config) { 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 = { const SamplerParams params = {
.mag_filter = config.mag_filter, .mag_filter = get_filter(config.mag_filter),
.min_filter = config.min_filter, .min_filter = get_filter(config.min_filter),
.mip_filter = config.mip_filter, .mip_filter = get_filter(config.mip_filter),
.wrap_s = config.wrap_s, .wrap_s = config.wrap_s,
.wrap_t = config.wrap_t, .wrap_t = config.wrap_t,
.border_color = config.border_color.raw, .border_color = config.border_color.raw,

View file

@ -15,7 +15,6 @@
#include "video_core/host_shaders/full_screen_triangle_vert.h" #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/bicubic_frag.h"
#include "video_core/host_shaders/texture_filtering/mmpx_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/refine_frag.h"
#include "video_core/host_shaders/texture_filtering/scale_force_frag.h" #include "video_core/host_shaders/texture_filtering/scale_force_frag.h"
#include "video_core/host_shaders/texture_filtering/x_gradient_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)}, : driver{driver_}, linear_sampler{CreateSampler(GL_LINEAR)},
nearest_sampler{CreateSampler(GL_NEAREST)}, bicubic_program{CreateProgram( nearest_sampler{CreateSampler(GL_NEAREST)}, bicubic_program{CreateProgram(
HostShaders::BICUBIC_FRAG)}, HostShaders::BICUBIC_FRAG)},
nearest_program{CreateProgram(HostShaders::NEAREST_NEIGHBOR_FRAG)},
scale_force_program{CreateProgram(HostShaders::SCALE_FORCE_FRAG)}, scale_force_program{CreateProgram(HostShaders::SCALE_FORCE_FRAG)},
xbrz_program{CreateProgram(HostShaders::XBRZ_FREESCALE_FRAG)}, xbrz_program{CreateProgram(HostShaders::XBRZ_FREESCALE_FRAG)},
mmpx_program{CreateProgram(HostShaders::MMPX_FRAG)}, gradient_x_program{CreateProgram( 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: case TextureFilter::Bicubic:
FilterBicubic(surface, blit); FilterBicubic(surface, blit);
break; break;
case TextureFilter::NearestNeighbor:
FilterNearest(surface, blit);
break;
case TextureFilter::ScaleForce: case TextureFilter::ScaleForce:
FilterScaleForce(surface, blit); FilterScaleForce(surface, blit);
break; 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); 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) { void BlitHelper::FilterScaleForce(Surface& surface, const VideoCore::TextureBlit& blit) {
const OpenGLState prev_state = OpenGLState::GetCurState(); const OpenGLState prev_state = OpenGLState::GetCurState();
SCOPE_EXIT({ prev_state.Apply(); }); SCOPE_EXIT({ prev_state.Apply(); });

View file

@ -33,20 +33,13 @@ public:
private: private:
void FilterAnime4K(Surface& surface, const VideoCore::TextureBlit& blit); void FilterAnime4K(Surface& surface, const VideoCore::TextureBlit& blit);
void FilterBicubic(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 FilterScaleForce(Surface& surface, const VideoCore::TextureBlit& blit);
void FilterXbrz(Surface& surface, const VideoCore::TextureBlit& blit); void FilterXbrz(Surface& surface, const VideoCore::TextureBlit& blit);
void FilterMMPX(Surface& surface, const VideoCore::TextureBlit& blit); void FilterMMPX(Surface& surface, const VideoCore::TextureBlit& blit);
void SetParams(OGLProgram& program, const VideoCore::Extent& src_extent, void SetParams(OGLProgram& program, const VideoCore::Extent& src_extent,
Common::Rectangle<u32> src_rect); Common::Rectangle<u32> src_rect);
void Draw(OGLProgram& program, GLuint dst_tex, GLuint dst_fbo, u32 dst_level, void Draw(OGLProgram& program, GLuint dst_tex, GLuint dst_fbo, u32 dst_level,
Common::Rectangle<u32> dst_rect); Common::Rectangle<u32> dst_rect);
@ -59,7 +52,6 @@ private:
OGLSampler nearest_sampler; OGLSampler nearest_sampler;
OGLProgram bicubic_program; OGLProgram bicubic_program;
OGLProgram nearest_program;
OGLProgram scale_force_program; OGLProgram scale_force_program;
OGLProgram xbrz_program; OGLProgram xbrz_program;
OGLProgram mmpx_program; OGLProgram mmpx_program;

View file

@ -35,10 +35,7 @@ public:
const VideoCore::BufferTextureCopy& copy); const VideoCore::BufferTextureCopy& copy);
private: private:
/// Creates compute pipelines used for blit
vk::Pipeline MakeComputePipeline(vk::ShaderModule shader, vk::PipelineLayout layout); vk::Pipeline MakeComputePipeline(vk::ShaderModule shader, vk::PipelineLayout layout);
/// Creates graphics pipelines used for blit
vk::Pipeline MakeDepthStencilBlitPipeline(); vk::Pipeline MakeDepthStencilBlitPipeline();
private: private: