From 902e5cddf76e941af8bd506cef34176d080184e6 Mon Sep 17 00:00:00 2001 From: EmptyChaos Date: Thu, 24 Mar 2016 02:23:56 +0000 Subject: [PATCH 1/2] VideoBackends: Do not use Anisotropy on Point filtered textures. The D3D backend was always forcing Anisotropic filtering when that is enabled regardless of how the game chose to configure the texture filtering registers; this causes the same issues as "Force Filtering" without Anisotropy, such as causing game UI elements to no longer line up adjacent correctly. Historically, OpenGL's Anisotropy support has always worked "better" than D3D's due to seeming to not have this problem; unfortunately, OpenGL's Anisotropy specification only gives GL_LINEAR based filtering modes defined behavior, with only the mipmap setting being required to be considered. Some OpenGL implementations were implicitly disabling Anisotropy when the min/mag filters were set to GL_NEAREST, but this behavior is not required by the spec so cannot be relied on. --- Source/Core/DolphinWX/VideoConfigDiag.cpp | 4 +-- Source/Core/VideoBackends/D3D/D3DState.cpp | 3 +- Source/Core/VideoBackends/D3D/Render.cpp | 3 +- Source/Core/VideoBackends/D3D12/D3DState.cpp | 3 +- Source/Core/VideoBackends/D3D12/Render.cpp | 3 +- .../Core/VideoBackends/OGL/SamplerCache.cpp | 28 +++++++++++++++---- Source/Core/VideoCommon/SamplerCommon.h | 18 ++++++++++++ Source/Core/VideoCommon/VideoCommon.vcxproj | 3 +- .../VideoCommon/VideoCommon.vcxproj.filters | 7 +++-- 9 files changed, 57 insertions(+), 15 deletions(-) create mode 100644 Source/Core/VideoCommon/SamplerCommon.h diff --git a/Source/Core/DolphinWX/VideoConfigDiag.cpp b/Source/Core/DolphinWX/VideoConfigDiag.cpp index b9869711ba..322b568171 100644 --- a/Source/Core/DolphinWX/VideoConfigDiag.cpp +++ b/Source/Core/DolphinWX/VideoConfigDiag.cpp @@ -104,13 +104,13 @@ static wxString prog_scan_desc = wxTRANSLATE("Enables progressive scan if suppor static wxString ar_desc = wxTRANSLATE("Select what aspect ratio to use when rendering:\nAuto: Use the native aspect ratio\nForce 16:9: Mimic an analog TV with a widescreen aspect ratio.\nForce 4:3: Mimic a standard 4:3 analog TV.\nStretch to Window: Stretch the picture to the window size.\n\nIf unsure, select Auto."); static wxString ws_hack_desc = wxTRANSLATE("Forces the game to output graphics for any aspect ratio.\nUse with \"Aspect Ratio\" set to \"Force 16:9\" to force 4:3-only games to run at 16:9.\nRarely produces good results and often partially breaks graphics and game UIs.\nUnnecessary (and detrimental) if using any AR/Gecko-code widescreen patches.\n\nIf unsure, leave this unchecked."); static wxString vsync_desc = wxTRANSLATE("Wait for vertical blanks in order to reduce tearing.\nDecreases performance if emulation speed is below 100%.\n\nIf unsure, leave this unchecked."); -static wxString af_desc = wxTRANSLATE("Enable anisotropic filtering.\nEnhances visual quality of textures that are at oblique viewing angles.\nMight cause issues in a small number of games.\nOn Direct3D, setting this above 1x will also have the same effect as enabling \"Force Texture Filtering\".\n\nIf unsure, select 1x."); +static wxString af_desc = wxTRANSLATE("Enable anisotropic filtering.\nEnhances visual quality of textures that are at oblique viewing angles.\nMight cause issues in a small number of games.\n\nIf unsure, select 1x."); static wxString aa_desc = wxTRANSLATE("Reduces the amount of aliasing caused by rasterizing 3D graphics. This smooths out jagged edges on objects.\nIncreases GPU load and sometimes causes graphical issues. SSAA is significantly more demanding than MSAA, but provides top quality geometry anti-aliasing and also applies anti-aliasing to lighting, shader effects, and textures.\n\nIf unsure, select None."); static wxString scaled_efb_copy_desc = wxTRANSLATE("Greatly increases quality of textures generated using render-to-texture effects.\nRaising the internal resolution will improve the effect of this setting.\nSlightly increases GPU load and causes relatively few graphical issues.\n\nIf unsure, leave this checked."); static wxString pixel_lighting_desc = wxTRANSLATE("Calculates lighting of 3D objects per-pixel rather than per-vertex, smoothing out the appearance of lit polygons and making individual triangles less noticeable.\nRarely causes slowdowns or graphical issues.\n\nIf unsure, leave this unchecked."); static wxString fast_depth_calc_desc = wxTRANSLATE("Use a less accurate algorithm to calculate depth values.\nCauses issues in a few games, but can give a decent speedup depending on the game and/or your GPU.\n\nIf unsure, leave this checked."); static wxString disable_bbox_desc = wxTRANSLATE("Disable the bounding box emulation.\nThis may improve the GPU performance a lot, but some games will break.\n\nIf unsure, leave this checked."); -static wxString force_filtering_desc = wxTRANSLATE("Filter all textures, including any that the game explicitly set as unfiltered.\nMay improve quality of certain textures in some games, but will cause issues in others.\nOn Direct3D, setting Anisotropic Filtering above 1x will also have the same effect as enabling this option.\n\nIf unsure, leave this unchecked."); +static wxString force_filtering_desc = wxTRANSLATE("Filter all textures, including any that the game explicitly set as unfiltered.\nMay improve quality of certain textures in some games, but will cause issues in others.\n\nIf unsure, leave this unchecked."); static wxString borderless_fullscreen_desc = wxTRANSLATE("Implement fullscreen mode with a borderless window spanning the whole screen instead of using exclusive mode.\nAllows for faster transitions between fullscreen and windowed mode, but slightly increases input latency, makes movement less smooth and slightly decreases performance.\nExclusive mode is required for Nvidia 3D Vision to work in the Direct3D backend.\n\nIf unsure, leave this unchecked."); static wxString internal_res_desc = wxTRANSLATE("Specifies the resolution used to render at. A high resolution greatly improves visual quality, but also greatly increases GPU load and can cause issues in certain games.\n\"Multiple of 640x528\" will result in a size slightly larger than \"Window Size\" but yield fewer issues. Generally speaking, the lower the internal resolution is, the better your performance will be. Auto (Window Size), 1.5x, and 2.5x may cause issues in some games.\n\nIf unsure, select Native."); static wxString efb_access_desc = wxTRANSLATE("Ignore any requests from the CPU to read from or write to the EFB.\nImproves performance in some games, but might disable some gameplay-related features or graphical effects.\n\nIf unsure, leave this unchecked."); diff --git a/Source/Core/VideoBackends/D3D/D3DState.cpp b/Source/Core/VideoBackends/D3D/D3DState.cpp index c5c70dd19a..ca8778b909 100644 --- a/Source/Core/VideoBackends/D3D/D3DState.cpp +++ b/Source/Core/VideoBackends/D3D/D3DState.cpp @@ -9,6 +9,7 @@ #include "VideoBackends/D3D/D3DBase.h" #include "VideoBackends/D3D/D3DState.h" +#include "VideoCommon/SamplerCommon.h" namespace DX11 { @@ -259,7 +260,7 @@ ID3D11SamplerState* StateCache::Get(SamplerState state) unsigned int mip = d3dMipFilters[state.min_filter & 3]; - if (state.max_anisotropy > 1) + if (state.max_anisotropy > 1 && !IsBpTexMode0PointFiltering(state)) { sampdc.Filter = D3D11_FILTER_ANISOTROPIC; sampdc.MaxAnisotropy = (u32)state.max_anisotropy; diff --git a/Source/Core/VideoBackends/D3D/Render.cpp b/Source/Core/VideoBackends/D3D/Render.cpp index dc54a527be..9b73300fb9 100644 --- a/Source/Core/VideoBackends/D3D/Render.cpp +++ b/Source/Core/VideoBackends/D3D/Render.cpp @@ -1200,7 +1200,8 @@ void Renderer::SetSamplerState(int stage, int texindex, bool custom_tex) if (g_ActiveConfig.bForceFiltering) { - gx_state.sampler[stage].min_filter = 6; // 4 (linear mip) | 2 (linear min) + // Only use mipmaps if the game says they are available. + gx_state.sampler[stage].min_filter = (tm0.min_filter & 3) == TexMode0::TEXF_NONE ? 4 : 6; gx_state.sampler[stage].mag_filter = 1; // linear mag } else diff --git a/Source/Core/VideoBackends/D3D12/D3DState.cpp b/Source/Core/VideoBackends/D3D12/D3DState.cpp index 4399641d7f..c752087c91 100644 --- a/Source/Core/VideoBackends/D3D12/D3DState.cpp +++ b/Source/Core/VideoBackends/D3D12/D3DState.cpp @@ -20,6 +20,7 @@ #include "VideoBackends/D3D12/ShaderCache.h" #include "VideoBackends/D3D12/StaticShaderCache.h" +#include "VideoCommon/SamplerCommon.h" #include "VideoCommon/VertexLoaderManager.h" #include "VideoCommon/VideoConfig.h" @@ -185,7 +186,7 @@ D3D12_SAMPLER_DESC StateCache::GetDesc12(SamplerState state) unsigned int mip = d3d_mip_filters[state.min_filter & 3]; sampdc.MaxAnisotropy = 1; - if (g_ActiveConfig.iMaxAnisotropy > 1) + if (g_ActiveConfig.iMaxAnisotropy > 0 && !IsBpTexMode0PointFiltering(state)) { sampdc.Filter = D3D12_FILTER_ANISOTROPIC; sampdc.MaxAnisotropy = 1 << g_ActiveConfig.iMaxAnisotropy; diff --git a/Source/Core/VideoBackends/D3D12/Render.cpp b/Source/Core/VideoBackends/D3D12/Render.cpp index cd4785569c..49f882f89c 100644 --- a/Source/Core/VideoBackends/D3D12/Render.cpp +++ b/Source/Core/VideoBackends/D3D12/Render.cpp @@ -1245,7 +1245,8 @@ void Renderer::SetSamplerState(int stage, int tex_index, bool custom_tex) if (g_ActiveConfig.bForceFiltering) { - new_state.min_filter = 6; // 4 (linear min) | 2 (linear mip) + // Only use mipmaps if the game says they are available. + new_state.min_filter = (tm0.min_filter & 3) == TexMode0::TEXF_NONE ? 4 : 6; new_state.mag_filter = 1; // linear mag } else diff --git a/Source/Core/VideoBackends/OGL/SamplerCache.cpp b/Source/Core/VideoBackends/OGL/SamplerCache.cpp index 0eeae5ee38..5f809825d5 100644 --- a/Source/Core/VideoBackends/OGL/SamplerCache.cpp +++ b/Source/Core/VideoBackends/OGL/SamplerCache.cpp @@ -8,6 +8,7 @@ #include "Common/CommonTypes.h" #include "Common/GL/GLInterfaceBase.h" #include "VideoBackends/OGL/SamplerCache.h" +#include "VideoCommon/SamplerCommon.h" #include "VideoCommon/VideoConfig.h" namespace OGL @@ -59,8 +60,8 @@ void SamplerCache::SetSamplerState(int stage, const TexMode0& tm0, const TexMode // take equivalent forced linear when bForceFiltering if (g_ActiveConfig.bForceFiltering) { - params.tm0.min_filter |= 0x4; - params.tm0.mag_filter |= 0x1; + params.tm0.min_filter = (tm0.min_filter & 3) == TexMode0::TEXF_NONE ? 4 : 6; + params.tm0.mag_filter = 1; } // custom textures may have higher resolution, so disable the max_lod @@ -122,9 +123,6 @@ void SamplerCache::SetParameters(GLuint sampler_id, const Params& params) auto& tm0 = params.tm0; auto& tm1 = params.tm1; - glSamplerParameteri(sampler_id, GL_TEXTURE_MIN_FILTER, min_filters[tm0.min_filter % ArraySize(min_filters)]); - glSamplerParameteri(sampler_id, GL_TEXTURE_MAG_FILTER, tm0.mag_filter ? GL_LINEAR : GL_NEAREST); - glSamplerParameteri(sampler_id, GL_TEXTURE_WRAP_S, wrap_settings[tm0.wrap_s]); glSamplerParameteri(sampler_id, GL_TEXTURE_WRAP_T, wrap_settings[tm0.wrap_t]); @@ -134,8 +132,26 @@ void SamplerCache::SetParameters(GLuint sampler_id, const Params& params) if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGL) glSamplerParameterf(sampler_id, GL_TEXTURE_LOD_BIAS, (s32)tm0.lod_bias / 32.f); - if (g_ActiveConfig.iMaxAnisotropy > 0 && g_ogl_config.bSupportsAniso) + GLint min_filter = min_filters[tm0.min_filter]; + GLint mag_filter = tm0.mag_filter ? GL_LINEAR : GL_NEAREST; + + if (g_ActiveConfig.iMaxAnisotropy > 0 && g_ogl_config.bSupportsAniso && + !IsBpTexMode0PointFiltering(tm0)) + { + // https://www.opengl.org/registry/specs/EXT/texture_filter_anisotropic.txt + // For predictable results on all hardware/drivers, only use one of: + // GL_LINEAR + GL_LINEAR (No Mipmaps [Bilinear]) + // GL_LINEAR + GL_LINEAR_MIPMAP_LINEAR (w/ Mipmaps [Trilinear]) + // Letting the game set other combinations will have varying arbitrary results; + // possibly being interpreted as equal to bilinear/trilinear, implicitly + // disabling anisotropy, or changing the anisotropic algorithm employed. + min_filter = (tm0.min_filter & 3) == TexMode0::TEXF_NONE ? GL_LINEAR : GL_LINEAR_MIPMAP_LINEAR; + mag_filter = GL_LINEAR; glSamplerParameterf(sampler_id, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)(1 << g_ActiveConfig.iMaxAnisotropy)); + } + + glSamplerParameteri(sampler_id, GL_TEXTURE_MIN_FILTER, min_filter); + glSamplerParameteri(sampler_id, GL_TEXTURE_MAG_FILTER, mag_filter); } void SamplerCache::Clear() diff --git a/Source/Core/VideoCommon/SamplerCommon.h b/Source/Core/VideoCommon/SamplerCommon.h new file mode 100644 index 0000000000..5e6dd565f1 --- /dev/null +++ b/Source/Core/VideoCommon/SamplerCommon.h @@ -0,0 +1,18 @@ +// Copyright 2016 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +// Helper for checking if a BPMemory TexMode0 register is set to Point +// Filtering modes. This is used to decide whether Anisotropic enhancements +// are (mostly) safe in the VideoBackends. +// If both the minification and magnification filters are set to POINT modes +// then applying anisotropic filtering is equivalent to forced filtering. Point +// mode textures are usually some sort of 2D UI billboard which will end up +// misaligned from the correct pixels when filtered anisotropically. +template +constexpr bool IsBpTexMode0PointFiltering(const T& tm0) +{ + return tm0.min_filter < 4 && !tm0.mag_filter; +} diff --git a/Source/Core/VideoCommon/VideoCommon.vcxproj b/Source/Core/VideoCommon/VideoCommon.vcxproj index 9e372e9da9..4bf4c4dde7 100644 --- a/Source/Core/VideoCommon/VideoCommon.vcxproj +++ b/Source/Core/VideoCommon/VideoCommon.vcxproj @@ -1,4 +1,4 @@ - + @@ -133,6 +133,7 @@ + diff --git a/Source/Core/VideoCommon/VideoCommon.vcxproj.filters b/Source/Core/VideoCommon/VideoCommon.vcxproj.filters index 4bb07cf53b..0926ec0dc0 100644 --- a/Source/Core/VideoCommon/VideoCommon.vcxproj.filters +++ b/Source/Core/VideoCommon/VideoCommon.vcxproj.filters @@ -1,4 +1,4 @@ - + @@ -302,8 +302,11 @@ Shader Managers + + Util + - + \ No newline at end of file From 0b9a72a62d38481ff08f742b2318d07f29ff5dff Mon Sep 17 00:00:00 2001 From: EmptyChaos Date: Thu, 24 Mar 2016 02:42:08 +0000 Subject: [PATCH 2/2] VideoCommon: Refactor TexMode0 mipmaps disabled test into a helper function --- Source/Core/VideoBackends/D3D/D3DState.cpp | 8 +++++--- Source/Core/VideoBackends/D3D/Render.cpp | 3 ++- Source/Core/VideoBackends/D3D12/D3DState.cpp | 8 +++++--- Source/Core/VideoBackends/D3D12/Render.cpp | 3 ++- Source/Core/VideoBackends/OGL/SamplerCache.cpp | 6 +++--- .../Core/VideoBackends/Software/TextureSampler.cpp | 7 ++++--- Source/Core/VideoCommon/SamplerCommon.h | 12 ++++++++++++ Source/Core/VideoCommon/TextureCacheBase.cpp | 3 ++- 8 files changed, 35 insertions(+), 15 deletions(-) diff --git a/Source/Core/VideoBackends/D3D/D3DState.cpp b/Source/Core/VideoBackends/D3D/D3DState.cpp index ca8778b909..64c6b48740 100644 --- a/Source/Core/VideoBackends/D3D/D3DState.cpp +++ b/Source/Core/VideoBackends/D3D/D3DState.cpp @@ -2,6 +2,8 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include + #include "Common/BitSet.h" #include "Common/CommonTypes.h" #include "Common/MsgHandler.h" @@ -260,7 +262,7 @@ ID3D11SamplerState* StateCache::Get(SamplerState state) unsigned int mip = d3dMipFilters[state.min_filter & 3]; - if (state.max_anisotropy > 1 && !IsBpTexMode0PointFiltering(state)) + if (state.max_anisotropy > 1 && !SamplerCommon::IsBpTexMode0PointFiltering(state)) { sampdc.Filter = D3D11_FILTER_ANISOTROPIC; sampdc.MaxAnisotropy = (u32)state.max_anisotropy; @@ -311,8 +313,8 @@ ID3D11SamplerState* StateCache::Get(SamplerState state) sampdc.AddressU = d3dClamps[state.wrap_s]; sampdc.AddressV = d3dClamps[state.wrap_t]; - sampdc.MaxLOD = (mip == TexMode0::TEXF_NONE) ? 0.0f : (float)state.max_lod / 16.f; - sampdc.MinLOD = (float)state.min_lod / 16.f; + sampdc.MaxLOD = SamplerCommon::AreBpTexMode0MipmapsEnabled(state) ? state.max_lod / 16.f : 0.f; + sampdc.MinLOD = std::min(state.min_lod / 16.f, sampdc.MaxLOD); sampdc.MipLODBias = (s32)state.lod_bias / 32.0f; ID3D11SamplerState* res = nullptr; diff --git a/Source/Core/VideoBackends/D3D/Render.cpp b/Source/Core/VideoBackends/D3D/Render.cpp index 9b73300fb9..dd6fafcdb9 100644 --- a/Source/Core/VideoBackends/D3D/Render.cpp +++ b/Source/Core/VideoBackends/D3D/Render.cpp @@ -36,6 +36,7 @@ #include "VideoCommon/OnScreenDisplay.h" #include "VideoCommon/PixelEngine.h" #include "VideoCommon/PixelShaderManager.h" +#include "VideoCommon/SamplerCommon.h" #include "VideoCommon/VideoConfig.h" namespace DX11 @@ -1201,7 +1202,7 @@ void Renderer::SetSamplerState(int stage, int texindex, bool custom_tex) if (g_ActiveConfig.bForceFiltering) { // Only use mipmaps if the game says they are available. - gx_state.sampler[stage].min_filter = (tm0.min_filter & 3) == TexMode0::TEXF_NONE ? 4 : 6; + gx_state.sampler[stage].min_filter = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? 6 : 4; gx_state.sampler[stage].mag_filter = 1; // linear mag } else diff --git a/Source/Core/VideoBackends/D3D12/D3DState.cpp b/Source/Core/VideoBackends/D3D12/D3DState.cpp index c752087c91..9da11541cc 100644 --- a/Source/Core/VideoBackends/D3D12/D3DState.cpp +++ b/Source/Core/VideoBackends/D3D12/D3DState.cpp @@ -2,6 +2,8 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include + #include "Common/BitSet.h" #include "Common/CommonTypes.h" #include "Common/FileUtil.h" @@ -186,7 +188,7 @@ D3D12_SAMPLER_DESC StateCache::GetDesc12(SamplerState state) unsigned int mip = d3d_mip_filters[state.min_filter & 3]; sampdc.MaxAnisotropy = 1; - if (g_ActiveConfig.iMaxAnisotropy > 0 && !IsBpTexMode0PointFiltering(state)) + if (g_ActiveConfig.iMaxAnisotropy > 0 && !SamplerCommon::IsBpTexMode0PointFiltering(state)) { sampdc.Filter = D3D12_FILTER_ANISOTROPIC; sampdc.MaxAnisotropy = 1 << g_ActiveConfig.iMaxAnisotropy; @@ -242,8 +244,8 @@ D3D12_SAMPLER_DESC StateCache::GetDesc12(SamplerState state) sampdc.BorderColor[0] = sampdc.BorderColor[1] = sampdc.BorderColor[2] = sampdc.BorderColor[3] = 1.0f; - sampdc.MaxLOD = (mip == TexMode0::TEXF_NONE) ? 0.0f : static_cast(state.max_lod) / 16.f; - sampdc.MinLOD = static_cast(state.min_lod) / 16.f; + sampdc.MaxLOD = SamplerCommon::AreBpTexMode0MipmapsEnabled(state) ? state.max_lod / 16.f : 0.f; + sampdc.MinLOD = std::min(state.min_lod / 16.f, sampdc.MaxLOD); sampdc.MipLODBias = static_cast(state.lod_bias) / 32.0f; return sampdc; diff --git a/Source/Core/VideoBackends/D3D12/Render.cpp b/Source/Core/VideoBackends/D3D12/Render.cpp index 49f882f89c..ac95d198b3 100644 --- a/Source/Core/VideoBackends/D3D12/Render.cpp +++ b/Source/Core/VideoBackends/D3D12/Render.cpp @@ -39,6 +39,7 @@ #include "VideoCommon/OnScreenDisplay.h" #include "VideoCommon/PixelEngine.h" #include "VideoCommon/PixelShaderManager.h" +#include "VideoCommon/SamplerCommon.h" #include "VideoCommon/VertexLoaderManager.h" #include "VideoCommon/VideoConfig.h" @@ -1246,7 +1247,7 @@ void Renderer::SetSamplerState(int stage, int tex_index, bool custom_tex) if (g_ActiveConfig.bForceFiltering) { // Only use mipmaps if the game says they are available. - new_state.min_filter = (tm0.min_filter & 3) == TexMode0::TEXF_NONE ? 4 : 6; + new_state.min_filter = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? 6 : 4; new_state.mag_filter = 1; // linear mag } else diff --git a/Source/Core/VideoBackends/OGL/SamplerCache.cpp b/Source/Core/VideoBackends/OGL/SamplerCache.cpp index 5f809825d5..d9a2008a50 100644 --- a/Source/Core/VideoBackends/OGL/SamplerCache.cpp +++ b/Source/Core/VideoBackends/OGL/SamplerCache.cpp @@ -60,7 +60,7 @@ void SamplerCache::SetSamplerState(int stage, const TexMode0& tm0, const TexMode // take equivalent forced linear when bForceFiltering if (g_ActiveConfig.bForceFiltering) { - params.tm0.min_filter = (tm0.min_filter & 3) == TexMode0::TEXF_NONE ? 4 : 6; + params.tm0.min_filter = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? 6 : 4; params.tm0.mag_filter = 1; } @@ -136,7 +136,7 @@ void SamplerCache::SetParameters(GLuint sampler_id, const Params& params) GLint mag_filter = tm0.mag_filter ? GL_LINEAR : GL_NEAREST; if (g_ActiveConfig.iMaxAnisotropy > 0 && g_ogl_config.bSupportsAniso && - !IsBpTexMode0PointFiltering(tm0)) + !SamplerCommon::IsBpTexMode0PointFiltering(tm0)) { // https://www.opengl.org/registry/specs/EXT/texture_filter_anisotropic.txt // For predictable results on all hardware/drivers, only use one of: @@ -145,7 +145,7 @@ void SamplerCache::SetParameters(GLuint sampler_id, const Params& params) // Letting the game set other combinations will have varying arbitrary results; // possibly being interpreted as equal to bilinear/trilinear, implicitly // disabling anisotropy, or changing the anisotropic algorithm employed. - min_filter = (tm0.min_filter & 3) == TexMode0::TEXF_NONE ? GL_LINEAR : GL_LINEAR_MIPMAP_LINEAR; + min_filter = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR; mag_filter = GL_LINEAR; glSamplerParameterf(sampler_id, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)(1 << g_ActiveConfig.iMaxAnisotropy)); } diff --git a/Source/Core/VideoBackends/Software/TextureSampler.cpp b/Source/Core/VideoBackends/Software/TextureSampler.cpp index 6c1001a6c8..b5049cb6a3 100644 --- a/Source/Core/VideoBackends/Software/TextureSampler.cpp +++ b/Source/Core/VideoBackends/Software/TextureSampler.cpp @@ -10,6 +10,7 @@ #include "VideoBackends/Software/TextureSampler.h" #include "VideoCommon/BPMemory.h" +#include "VideoCommon/SamplerCommon.h" #include "VideoCommon/TextureDecoder.h" #define ALLOW_MIPMAP 1 @@ -69,14 +70,14 @@ void Sample(s32 s, s32 t, s32 lod, bool linear, u8 texmap, u8 *sample) s32 lodFract = lod & 0xf; - if (lod > 0 && tm0.min_filter & 3) + if (lod > 0 && SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0)) { // use mipmap baseMip = lod >> 4; - mipLinear = (lodFract && tm0.min_filter & 2); + mipLinear = (lodFract && tm0.min_filter & TexMode0::TEXF_LINEAR); // if using nearest mip filter and lodFract >= 0.5 round up to next mip - baseMip += (lodFract >> 3) & (tm0.min_filter & 1); + baseMip += (lodFract >> 3) & (tm0.min_filter & TexMode0::TEXF_POINT); } if (mipLinear) diff --git a/Source/Core/VideoCommon/SamplerCommon.h b/Source/Core/VideoCommon/SamplerCommon.h index 5e6dd565f1..0605fddd03 100644 --- a/Source/Core/VideoCommon/SamplerCommon.h +++ b/Source/Core/VideoCommon/SamplerCommon.h @@ -4,6 +4,9 @@ #pragma once +namespace SamplerCommon +{ + // Helper for checking if a BPMemory TexMode0 register is set to Point // Filtering modes. This is used to decide whether Anisotropic enhancements // are (mostly) safe in the VideoBackends. @@ -16,3 +19,12 @@ constexpr bool IsBpTexMode0PointFiltering(const T& tm0) { return tm0.min_filter < 4 && !tm0.mag_filter; } + +// Check if the minification filter has mipmap based filtering modes enabled. +template +constexpr bool AreBpTexMode0MipmapsEnabled(const T& tm0) +{ + return (tm0.min_filter & 3) != 0; +} + +} diff --git a/Source/Core/VideoCommon/TextureCacheBase.cpp b/Source/Core/VideoCommon/TextureCacheBase.cpp index ffa2c68ad3..1707be49cb 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/TextureCacheBase.cpp @@ -26,6 +26,7 @@ #include "VideoCommon/FramebufferManagerBase.h" #include "VideoCommon/HiresTextures.h" #include "VideoCommon/RenderBase.h" +#include "VideoCommon/SamplerCommon.h" #include "VideoCommon/Statistics.h" #include "VideoCommon/TextureCacheBase.h" #include "VideoCommon/TextureDecoder.h" @@ -440,7 +441,7 @@ TextureCacheBase::TCacheEntryBase* TextureCacheBase::Load(const u32 stage) const int texformat = tex.texImage0[id].format; const u32 tlutaddr = tex.texTlut[id].tmem_offset << 9; const u32 tlutfmt = tex.texTlut[id].tlut_format; - const bool use_mipmaps = (tex.texMode0[id].min_filter & 3) != 0; + const bool use_mipmaps = SamplerCommon::AreBpTexMode0MipmapsEnabled(tex.texMode0[id]); u32 tex_levels = use_mipmaps ? ((tex.texMode1[id].max_lod + 0xf) / 0x10 + 1) : 1; const bool from_tmem = tex.texImage1[id].image_type != 0;