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:
parent
c17ec1d1aa
commit
85bd1be852
@ -184,11 +184,6 @@
|
||||
<string>Bicubic</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Nearest Neighbor</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>ScaleForce</string>
|
||||
|
@ -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<int>(Settings::values.graphics_api.GetValue()));
|
||||
ui->physical_device_combo->setCurrentIndex(
|
||||
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());
|
||||
@ -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<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,
|
||||
use_hw_shader);
|
||||
ConfigurationShared::SetColoredTristate(
|
||||
|
@ -212,6 +212,53 @@
|
||||
<string>Advanced</string>
|
||||
</property>
|
||||
<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><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></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>
|
||||
<widget class="QCheckBox" name="toggle_disk_shader_cache">
|
||||
<property name="toolTip">
|
||||
|
@ -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);
|
||||
|
@ -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<u32, true> resolution_factor{1, 0, 10, "resolution_factor"};
|
||||
SwitchableSetting<u16, true> frame_limit{100, 0, 1000, "frame_limit"};
|
||||
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<bool> swap_screen{false, "swap_screen"};
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
@ -361,10 +361,25 @@ typename T::Sampler& RasterizerCache<T>::GetSampler(SamplerId sampler_id) {
|
||||
template <class T>
|
||||
typename T::Sampler& RasterizerCache<T>::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,
|
||||
|
@ -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(); });
|
||||
|
@ -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<u32> src_rect);
|
||||
|
||||
void Draw(OGLProgram& program, GLuint dst_tex, GLuint dst_fbo, u32 dst_level,
|
||||
Common::Rectangle<u32> 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;
|
||||
|
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user