diff --git a/Common/GPU/OpenGL/GLQueueRunner.cpp b/Common/GPU/OpenGL/GLQueueRunner.cpp index 5a622c881f..1c7043475d 100644 --- a/Common/GPU/OpenGL/GLQueueRunner.cpp +++ b/Common/GPU/OpenGL/GLQueueRunner.cpp @@ -1281,10 +1281,12 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step, bool first, bool last tex->minFilter = c.textureSampler.minFilter; } CHECK_GL_ERROR_IF_DEBUG(); - if (tex->anisotropy != c.textureSampler.anisotropy) { - if (c.textureSampler.anisotropy != 0.0f) { - glTexParameterf(tex->target, GL_TEXTURE_MAX_ANISOTROPY_EXT, c.textureSampler.anisotropy); - } + // 0.0f means "don't care", used by callers that never want anisotropy. Note that we must + // only record the value when we actually set it, or we'd think we had reset the texture + // to something we never applied. + if (tex->anisotropy != c.textureSampler.anisotropy && c.textureSampler.anisotropy != 0.0f && caps_.anisoSupported) { + // Values above the device maximum are not allowed, and the minimum is 1.0. + glTexParameterf(tex->target, GL_TEXTURE_MAX_ANISOTROPY_EXT, std::max(1.0f, std::min(c.textureSampler.anisotropy, maxAnisotropyLevel_))); tex->anisotropy = c.textureSampler.anisotropy; } CHECK_GL_ERROR_IF_DEBUG(); diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index 27919e9d5c..820c0244e0 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -195,6 +195,11 @@ SamplerCacheKey TextureCacheCommon::GetSamplingParams(int maxLevel, const TexCac key.aniso = false; key.texture3d = gstate_c.curTextureIs3D; + // Anisotropic filtering must stay off for CLUT8-indexed textures - what gets sampled there are + // palette indices that the shader depalettizes afterwards, and averaging indices gives garbage. + const bool canUseAniso = gstate_c.Use(GPU_USE_ANISOTROPY) && !flatZ && + !(entry && (entry->status & TexStatus::CLUT8_INDEXED)); + GETexLevelMode mipMode = gstate.getTexLevelMode(); bool autoMip = mipMode == GE_TEXLEVEL_MODE_AUTO; @@ -224,7 +229,7 @@ SamplerCacheKey TextureCacheCommon::GetSamplingParams(int maxLevel, const TexCac key.maxLevel = maxLevel * 256; key.minLevel = 0; key.lodBias = (int)(lodBias * 256.0f); - if (gstate_c.Use(GPU_USE_ANISOTROPY) && !flatZ) { + if (canUseAniso) { key.aniso = true; } break; @@ -260,7 +265,7 @@ SamplerCacheKey TextureCacheCommon::GetSamplingParams(int maxLevel, const TexCac key.mipEnable = true; key.mipFilt = 1; key.maxLevel = 9 * 256; - if (gstate_c.Use(GPU_USE_ANISOTROPY) && !flatZ) { + if (canUseAniso) { key.aniso = true; } } @@ -293,19 +298,17 @@ SamplerCacheKey TextureCacheCommon::GetSamplingParams(int maxLevel, const TexCac case TEX_FILTER_AUTO_MAX_QUALITY: default: forceFiltering = TEX_FILTER_AUTO_MAX_QUALITY; - if (gstate_c.Use(GPU_USE_ANISOTROPY) && !flatZ) { + if (canUseAniso) { key.aniso = true; } if (gstate.isModeThrough() && g_Config.iInternalResolution != 1) { bool uglyColorTest = gstate.isColorTestEnabled() && !IsColorTestTriviallyTrue() && gstate.getColorTestRef() != 0; if (uglyColorTest) { forceFiltering = TEX_FILTER_FORCE_NEAREST; - key.aniso = false; } } if (pixelMapped) { forceFiltering = TEX_FILTER_FORCE_NEAREST; - key.aniso = false; } break; } @@ -322,6 +325,10 @@ SamplerCacheKey TextureCacheCommon::GetSamplingParams(int maxLevel, const TexCac case TEX_FILTER_FORCE_NEAREST: key.magFilt = 0; key.minFilt = 0; + // Anisotropic filtering is meaningless without minification filtering, and every path that + // forces nearest does so to keep the texels exact - so clear it here rather than at each + // of the places that can set forceFiltering to nearest. + key.aniso = false; break; case TEX_FILTER_AUTO_MAX_QUALITY: // NOTE: We do not override magfilt here. If a game should have pixellated filtering, diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index c9b7e0c1a1..eb8220c2b0 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -266,7 +266,10 @@ void DrawEngineGLES::Flush() { Shader *vshader = shaderManager_->ApplyVertexShader(useHWTransform, dec_->VertexType(), clipInfoFlags_, &vsid); if (!vshader) { // Both the requested shader and the software transform fallback failed to compile. - // Not much we can do here, let's skip drawing. + // Not much we can do here, let's skip drawing. Note that the failure is cached, so this + // will keep happening for this shader ID - hence the log, or geometry would just silently + // disappear for the rest of the session. + WARN_LOG_N_TIMES(novshader, 5, Log::G3D, "Skipping draw, no vertex shader"); goto bail; } diff --git a/GPU/GLES/TextureCacheGLES.cpp b/GPU/GLES/TextureCacheGLES.cpp index b5d96717ae..9e137ac5d2 100644 --- a/GPU/GLES/TextureCacheGLES.cpp +++ b/GPU/GLES/TextureCacheGLES.cpp @@ -26,6 +26,8 @@ #include "Common/GPU/OpenGL/GLRenderManager.h" #include "Common/TimeUtil.h" +#include "Core/Config.h" + #include "GPU/ge_constants.h" #include "GPU/GPUState.h" #include "GPU/GPUDefinitions.h" @@ -99,7 +101,8 @@ void TextureCacheGLES::ApplySamplerByKey(const SamplerCacheKey &key) { render_->SetTextureLod(0, minLod, maxLod, lodBias); } - float aniso = 0.0f; + // 1.0 means no anisotropic filtering. The queue runner clamps to the device maximum. + float aniso = key.aniso ? (float)(1 << g_Config.iAnisotropyLevel) : 1.0f; int minKey = ((int)key.mipEnable << 2) | ((int)key.mipFilt << 1) | ((int)key.minFilt); render_->SetTextureSampler(0, key.sClamp ? GL_CLAMP_TO_EDGE : GL_REPEAT, key.tClamp ? GL_CLAMP_TO_EDGE : GL_REPEAT,