Merge pull request #13368 from jordan-woyak/anisotropic-filtering

Use Game Requested Anisotropic Filtering
This commit is contained in:
JMC47 2025-03-23 15:17:24 -04:00 committed by GitHub
commit 9b0471532c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 98 additions and 56 deletions

View File

@ -100,32 +100,32 @@ LayerType GetActiveLayerForConfig(const Info<T>& info)
return GetActiveLayerForConfig(info.GetLocation());
}
template <typename T>
void Set(LayerType layer, const Info<T>& info, const std::common_type_t<T>& value)
template <typename InfoT, typename ValueT>
void Set(LayerType layer, const InfoT& info, const ValueT& value)
{
if (GetLayer(layer)->Set(info, value))
OnConfigChanged();
}
template <typename T>
void SetBase(const Info<T>& info, const std::common_type_t<T>& value)
template <typename InfoT, typename ValueT>
void SetBase(const Info<InfoT>& info, const ValueT& value)
{
Set<T>(LayerType::Base, info, value);
Set(LayerType::Base, info, value);
}
template <typename T>
void SetCurrent(const Info<T>& info, const std::common_type_t<T>& value)
template <typename InfoT, typename ValueT>
void SetCurrent(const Info<InfoT>& info, const ValueT& value)
{
Set<T>(LayerType::CurrentRun, info, value);
Set(LayerType::CurrentRun, info, value);
}
template <typename T>
void SetBaseOrCurrent(const Info<T>& info, const std::common_type_t<T>& value)
template <typename InfoT, typename ValueT>
void SetBaseOrCurrent(const Info<InfoT>& info, const ValueT& value)
{
if (GetActiveLayerForConfig(info) == LayerType::Base)
Set<T>(LayerType::Base, info, value);
Set(LayerType::Base, info, value);
else
Set<T>(LayerType::CurrentRun, info, value);
Set(LayerType::CurrentRun, info, value);
}
template <typename T>

View File

@ -8,7 +8,6 @@
#include <optional>
#include <string>
#include <type_traits>
#include <vector>
#include "Common/Config/ConfigInfo.h"
#include "Common/Config/Enums.h"
@ -16,6 +15,12 @@
namespace Config
{
// Setting a key to an object of this type will delete the key.
struct DefaultState
{
friend constexpr bool operator==(DefaultState, DefaultState) { return true; };
};
namespace detail
{
template <typename T, std::enable_if_t<!std::is_enum<T>::value>* = nullptr>
@ -116,12 +121,20 @@ public:
return detail::TryParse<T>(*iter->second);
}
template <typename T>
bool Set(const Info<T>& config_info, DefaultState)
{
return DeleteKey(config_info.GetLocation());
}
template <typename T>
bool Set(const Info<T>& config_info, const std::common_type_t<T>& value)
{
return Set(config_info.GetLocation(), value);
}
bool Set(const Location& location, DefaultState) { return DeleteKey(location); }
template <typename T>
bool Set(const Location& location, const T& value)
{

View File

@ -135,7 +135,8 @@ const Info<VertexLoaderType> GFX_VERTEX_LOADER_TYPE{{System::GFX, "Settings", "V
const Info<TextureFilteringMode> GFX_ENHANCE_FORCE_TEXTURE_FILTERING{
{System::GFX, "Enhancements", "ForceTextureFiltering"}, TextureFilteringMode::Default};
const Info<int> GFX_ENHANCE_MAX_ANISOTROPY{{System::GFX, "Enhancements", "MaxAnisotropy"}, 0};
const Info<AnisotropicFilteringMode> GFX_ENHANCE_MAX_ANISOTROPY{
{System::GFX, "Enhancements", "MaxAnisotropy"}, AnisotropicFilteringMode::Default};
const Info<OutputResamplingMode> GFX_ENHANCE_OUTPUT_RESAMPLING{
{System::GFX, "Enhancements", "OutputResampling"}, OutputResamplingMode::Default};
const Info<std::string> GFX_ENHANCE_POST_SHADER{

View File

@ -12,6 +12,7 @@ enum class ShaderCompilationMode : int;
enum class StereoMode : int;
enum class StereoPerEyeResolution : int;
enum class TextureFilteringMode : int;
enum class AnisotropicFilteringMode : int;
enum class OutputResamplingMode : int;
enum class ColorCorrectionRegion : int;
enum class TriState : int;
@ -111,7 +112,8 @@ extern const Info<bool> GFX_MODS_ENABLE;
// Graphics.Enhancements
extern const Info<TextureFilteringMode> GFX_ENHANCE_FORCE_TEXTURE_FILTERING;
extern const Info<int> GFX_ENHANCE_MAX_ANISOTROPY; // NOTE - this is x in (1 << x)
// NOTE - this is x in (1 << x)
extern const Info<AnisotropicFilteringMode> GFX_ENHANCE_MAX_ANISOTROPY;
extern const Info<OutputResamplingMode> GFX_ENHANCE_OUTPUT_RESAMPLING;
extern const Info<std::string> GFX_ENHANCE_POST_SHADER;
extern const Info<bool> GFX_ENHANCE_FORCE_TRUE_COLOR;

View File

@ -26,6 +26,7 @@
#include "Common/CommonTypes.h"
#include "Common/Config/Config.h"
#include "Common/Crypto/SHA1.h"
#include "Common/EnumUtils.h"
#include "Common/Random.h"
#include "Common/Timer.h"
#include "Common/Version.h"
@ -373,7 +374,7 @@ void DolphinAnalytics::MakePerGameBuilder()
// Video configuration.
builder.AddData("cfg-gfx-multisamples", g_Config.iMultisamples);
builder.AddData("cfg-gfx-ssaa", g_Config.bSSAA);
builder.AddData("cfg-gfx-anisotropy", g_Config.iMaxAnisotropy);
builder.AddData("cfg-gfx-anisotropy", Common::ToUnderlying(g_Config.iMaxAnisotropy));
builder.AddData("cfg-gfx-vsync", g_Config.bVSync);
builder.AddData("cfg-gfx-aspect-ratio", static_cast<int>(g_Config.aspect_mode));
builder.AddData("cfg-gfx-efb-access", g_Config.bEFBAccessEnable);

View File

@ -85,7 +85,7 @@ struct NetSettings
bool enable_pixel_lighting = false;
bool widescreen_hack = false;
TextureFilteringMode force_texture_filtering = TextureFilteringMode::Default;
int max_anisotropy = 0;
AnisotropicFilteringMode max_anisotropy = AnisotropicFilteringMode::Default;
bool force_true_color = false;
bool disable_copy_filter = false;
bool disable_fog = false;

View File

@ -131,17 +131,28 @@ void ConfigComplexChoice::SaveValue(int choice)
void ConfigComplexChoice::UpdateComboIndex()
{
auto Get = [this](auto& setting) {
auto get_layer_value = [this](auto& setting) {
if (m_layer != nullptr)
return static_cast<OptionVariant>(m_layer->Get(setting));
return static_cast<OptionVariant>(Config::Get(setting));
};
std::pair<OptionVariant, OptionVariant> values =
std::make_pair(std::visit(Get, m_setting1), std::visit(Get, m_setting2));
auto get_default_value = [](auto& setting) { return OptionVariant(setting.GetDefaultValue()); };
auto it = std::find(m_options.begin(), m_options.end(), values);
auto is_current_value = [&](const InfoVariant& info, const OptionVariant& option) {
return std::visit(get_layer_value, info) ==
(std::holds_alternative<Config::DefaultState>(option) ?
std::visit(get_default_value, info) :
option);
};
auto is_correct_option = [&](const std::pair<OptionVariant, OptionVariant>& option) {
return is_current_value(m_setting1, option.first) &&
is_current_value(m_setting2, option.second);
};
auto it = std::find_if(m_options.begin(), m_options.end(), is_correct_option);
int index = static_cast<int>(std::distance(m_options.begin(), it));
// Will crash if not blocked

View File

@ -53,7 +53,7 @@ class ConfigComplexChoice final : public ToolTipComboBox
Q_OBJECT
using InfoVariant = std::variant<Config::Info<u32>, Config::Info<int>, Config::Info<bool>>;
using OptionVariant = std::variant<u32, int, bool>;
using OptionVariant = std::variant<Config::DefaultState, u32, int, bool>;
public:
ConfigComplexChoice(const InfoVariant setting1, const InfoVariant setting2,

View File

@ -12,13 +12,12 @@
#include <QVBoxLayout>
#include "Common/CommonTypes.h"
#include "Common/EnumUtils.h"
#include "Core/Config/GraphicsSettings.h"
#include "Core/ConfigManager.h"
#include "DolphinQt/Config/ConfigControls/ConfigBool.h"
#include "DolphinQt/Config/ConfigControls/ConfigChoice.h"
#include "DolphinQt/Config/ConfigControls/ConfigRadio.h"
#include "DolphinQt/Config/ConfigControls/ConfigSlider.h"
#include "DolphinQt/Config/GameConfigWidget.h"
#include "DolphinQt/Config/Graphics/ColorCorrectionConfigWindow.h"
@ -63,14 +62,14 @@ EnhancementsWidget::EnhancementsWidget(GameConfigWidget* parent, Config::Layer*
&EnhancementsWidget::OnConfigChanged);
}
constexpr int ANISO_DEFAULT = 0;
constexpr int ANISO_2X = 1;
constexpr int ANISO_4X = 2;
constexpr int ANISO_8X = 3;
constexpr int ANISO_16X = 4;
constexpr int FILTERING_DEFAULT = 0;
constexpr int FILTERING_NEAREST = 1;
constexpr int FILTERING_LINEAR = 2;
constexpr int ANISO_1x = Common::ToUnderlying(AnisotropicFilteringMode::Force1x);
constexpr int ANISO_2X = Common::ToUnderlying(AnisotropicFilteringMode::Force2x);
constexpr int ANISO_4X = Common::ToUnderlying(AnisotropicFilteringMode::Force4x);
constexpr int ANISO_8X = Common::ToUnderlying(AnisotropicFilteringMode::Force8x);
constexpr int ANISO_16X = Common::ToUnderlying(AnisotropicFilteringMode::Force16x);
constexpr int FILTERING_DEFAULT = Common::ToUnderlying(TextureFilteringMode::Default);
constexpr int FILTERING_NEAREST = Common::ToUnderlying(TextureFilteringMode::Nearest);
constexpr int FILTERING_LINEAR = Common::ToUnderlying(TextureFilteringMode::Linear);
void EnhancementsWidget::CreateWidgets()
{
@ -129,13 +128,15 @@ void EnhancementsWidget::CreateWidgets()
new ConfigComplexChoice(Config::GFX_ENHANCE_MAX_ANISOTROPY,
Config::GFX_ENHANCE_FORCE_TEXTURE_FILTERING, m_game_layer);
m_texture_filtering_combo->Add(tr("Default"), ANISO_DEFAULT, FILTERING_DEFAULT);
m_texture_filtering_combo->Add(tr("Default"), Config::DefaultState{}, FILTERING_DEFAULT);
m_texture_filtering_combo->Add(tr("1x Anisotropic"), ANISO_1x, FILTERING_DEFAULT);
m_texture_filtering_combo->Add(tr("2x Anisotropic"), ANISO_2X, FILTERING_DEFAULT);
m_texture_filtering_combo->Add(tr("4x Anisotropic"), ANISO_4X, FILTERING_DEFAULT);
m_texture_filtering_combo->Add(tr("8x Anisotropic"), ANISO_8X, FILTERING_DEFAULT);
m_texture_filtering_combo->Add(tr("16x Anisotropic"), ANISO_16X, FILTERING_DEFAULT);
m_texture_filtering_combo->Add(tr("Force Nearest"), ANISO_DEFAULT, FILTERING_NEAREST);
m_texture_filtering_combo->Add(tr("Force Linear"), ANISO_DEFAULT, FILTERING_LINEAR);
m_texture_filtering_combo->Add(tr("Force Nearest and 1x Anisotropic "), ANISO_1x,
FILTERING_NEAREST);
m_texture_filtering_combo->Add(tr("Force Linear and 1x Anisotropic"), ANISO_1x, FILTERING_LINEAR);
m_texture_filtering_combo->Add(tr("Force Linear and 2x Anisotropic"), ANISO_2X, FILTERING_LINEAR);
m_texture_filtering_combo->Add(tr("Force Linear and 4x Anisotropic"), ANISO_4X, FILTERING_LINEAR);
m_texture_filtering_combo->Add(tr("Force Linear and 8x Anisotropic"), ANISO_8X, FILTERING_LINEAR);

View File

@ -344,10 +344,10 @@ ID3D11SamplerState* StateCache::Get(SamplerState state)
sampdc.MinLOD = state.tm1.min_lod / 16.f;
sampdc.MipLODBias = state.tm0.lod_bias / 256.f;
if (state.tm0.anisotropic_filtering)
if (state.tm0.anisotropic_filtering != 0)
{
sampdc.Filter = D3D11_FILTER_ANISOTROPIC;
sampdc.MaxAnisotropy = 1u << g_ActiveConfig.iMaxAnisotropy;
sampdc.MaxAnisotropy = 1u << state.tm0.anisotropic_filtering;
}
ComPtr<ID3D11SamplerState> res;

View File

@ -128,10 +128,10 @@ static void GetD3DSamplerDesc(D3D12_SAMPLER_DESC* desc, const SamplerState& stat
desc->MipLODBias = static_cast<s32>(state.tm0.lod_bias) / 256.f;
desc->ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER;
if (state.tm0.anisotropic_filtering)
if (state.tm0.anisotropic_filtering != 0)
{
desc->Filter = D3D12_FILTER_ANISOTROPIC;
desc->MaxAnisotropy = 1u << g_ActiveConfig.iMaxAnisotropy;
desc->MaxAnisotropy = 1u << state.tm0.anisotropic_filtering;
}
}

View File

@ -171,7 +171,7 @@ MRCOwned<id<MTLSamplerState>> Metal::ObjectCache::CreateSampler(SamplerSelector
[desc setMipFilter:ConvertMip(sel.MipFilter())];
[desc setSAddressMode:Convert(sel.WrapU())];
[desc setTAddressMode:Convert(sel.WrapV())];
[desc setMaxAnisotropy:1 << (sel.AnisotropicFiltering() ? g_ActiveConfig.iMaxAnisotropy : 0)];
[desc setMaxAnisotropy:1 << sel.AnisotropicFiltering()];
[desc setLabel:MRCTransfer([[NSString alloc]
initWithFormat:@"%s%s%s %s%s%s", to_string(sel.MinFilter()),
to_string(sel.MagFilter()), to_string(sel.MipFilter()),

View File

@ -102,10 +102,10 @@ void SamplerCache::SetParameters(GLuint sampler_id, const SamplerState& params)
glSamplerParameterf(sampler_id, GL_TEXTURE_LOD_BIAS, params.tm0.lod_bias / 256.f);
}
if (params.tm0.anisotropic_filtering && g_ogl_config.bSupportsAniso)
if (params.tm0.anisotropic_filtering != 0 && g_ogl_config.bSupportsAniso)
{
glSamplerParameterf(sampler_id, GL_TEXTURE_MAX_ANISOTROPY_EXT,
static_cast<float>(1 << g_ActiveConfig.iMaxAnisotropy));
static_cast<float>(1 << params.tm0.anisotropic_filtering));
}
}

View File

@ -398,11 +398,11 @@ VkSampler ObjectCache::GetSampler(const SamplerState& info)
};
// Can we use anisotropic filtering with this sampler?
if (info.tm0.anisotropic_filtering && g_vulkan_context->SupportsAnisotropicFiltering())
if (info.tm0.anisotropic_filtering != 0 && g_vulkan_context->SupportsAnisotropicFiltering())
{
// Cap anisotropy to device limits.
create_info.anisotropyEnable = VK_TRUE;
create_info.maxAnisotropy = std::min(static_cast<float>(1 << g_ActiveConfig.iMaxAnisotropy),
create_info.maxAnisotropy = std::min(static_cast<float>(1 << info.tm0.anisotropic_filtering),
g_vulkan_context->GetMaxSamplerAnisotropy());
}

View File

@ -309,10 +309,15 @@ void SamplerState::Generate(const BPMemory& bp, u32 index)
};
tm0.wrap_u = filter_invalid_wrap(bp_tm0.wrap_s);
tm0.wrap_v = filter_invalid_wrap(bp_tm0.wrap_t);
if (bp_tm0.max_aniso == MaxAniso::Two)
tm0.anisotropic_filtering = 1;
else if (bp_tm0.max_aniso == MaxAniso::Four)
tm0.anisotropic_filtering = 2;
else
tm0.anisotropic_filtering = 0;
tm0.diag_lod = bp_tm0.diag_lod;
tm0.anisotropic_filtering = false; // TODO: Respect BP anisotropic filtering mode
tm0.lod_clamp = bp_tm0.lod_clamp; // TODO: What does this do?
tm0.lod_clamp = bp_tm0.lod_clamp; // TODO: What does this do?
}
namespace RenderState

View File

@ -200,7 +200,7 @@ struct SamplerState
BitField<7, 1, LODType> diag_lod;
BitField<8, 16, s32> lod_bias; // multiplied by 256, higher precision than normal
BitField<24, 1, bool, u32> lod_clamp; // TODO: This isn't currently implemented
BitField<25, 1, bool, u32> anisotropic_filtering; // TODO: This doesn't use the BP one yet
BitField<25, 4, u32> anisotropic_filtering;
u32 hex = 0;
};
union TM1

View File

@ -20,6 +20,7 @@
#include "Common/Assert.h"
#include "Common/ChunkFile.h"
#include "Common/CommonTypes.h"
#include "Common/EnumUtils.h"
#include "Common/FileUtil.h"
#include "Common/Hash.h"
#include "Common/Logging/Log.h"
@ -1038,7 +1039,8 @@ SamplerState TextureCacheBase::GetSamplerState(u32 index, float custom_tex_scale
state.tm1.max_lod = 255;
// Anisotropic filtering option.
if (g_ActiveConfig.iMaxAnisotropy != 0 && IsAnisostropicEnhancementSafe(tm0))
if (g_ActiveConfig.iMaxAnisotropy != AnisotropicFilteringMode::Default &&
IsAnisostropicEnhancementSafe(tm0))
{
// https://www.opengl.org/registry/specs/EXT/texture_filter_anisotropic.txt
// For predictable results on all hardware/drivers, only use one of:
@ -1051,11 +1053,7 @@ SamplerState TextureCacheBase::GetSamplerState(u32 index, float custom_tex_scale
state.tm0.mag_filter = FilterMode::Linear;
if (tm0.mipmap_filter != MipMode::None)
state.tm0.mipmap_filter = FilterMode::Linear;
state.tm0.anisotropic_filtering = true;
}
else
{
state.tm0.anisotropic_filtering = false;
state.tm0.anisotropic_filtering = Common::ToUnderlying(g_ActiveConfig.iMaxAnisotropy);
}
if (has_arbitrary_mips && tm0.mipmap_filter != MipMode::None)
@ -1068,7 +1066,7 @@ SamplerState TextureCacheBase::GetSamplerState(u32 index, float custom_tex_scale
state.tm0.lod_bias = std::clamp<s32>(state.tm0.lod_bias + lod_offset, -32768, 32767);
// Anisotropic also pushes mips farther away so it cannot be used either
state.tm0.anisotropic_filtering = false;
state.tm0.anisotropic_filtering = 0;
}
return state;

View File

@ -265,7 +265,7 @@ void CheckForConfigChanges()
const ShaderHostConfig old_shader_host_config = ShaderHostConfig::GetCurrent();
const StereoMode old_stereo = g_ActiveConfig.stereo_mode;
const u32 old_multisamples = g_ActiveConfig.iMultisamples;
const int old_anisotropy = g_ActiveConfig.iMaxAnisotropy;
const auto old_anisotropy = g_ActiveConfig.iMaxAnisotropy;
const int old_efb_access_tile_size = g_ActiveConfig.iEFBAccessTileSize;
const auto old_texture_filtering_mode = g_ActiveConfig.texture_filtering_mode;
const bool old_vsync = g_ActiveConfig.bVSyncActive;

View File

@ -55,6 +55,16 @@ enum class TextureFilteringMode : int
Linear,
};
enum class AnisotropicFilteringMode : int
{
Default = -1,
Force1x = 0,
Force2x = 1,
Force4x = 2,
Force8x = 3,
Force16x = 4,
};
enum class OutputResamplingMode : int
{
Default,
@ -202,7 +212,7 @@ struct VideoConfig final
int iEFBScale = 0;
TextureFilteringMode texture_filtering_mode = TextureFilteringMode::Default;
OutputResamplingMode output_resampling_mode = OutputResamplingMode::Default;
int iMaxAnisotropy = 0;
AnisotropicFilteringMode iMaxAnisotropy = AnisotropicFilteringMode::Default;
std::string sPostProcessingShader;
bool bForceTrueColor = false;
bool bDisableCopyFilter = false;