Disable anisotropic filtering for all flat draws.

May improve performance slightly, and should fix the last instances of #19555
This commit is contained in:
Henrik Rydgård
2026-06-08 15:28:58 +02:00
parent 644f1b6caf
commit 2534eb4480
17 changed files with 51 additions and 43 deletions
+8 -8
View File
@@ -182,7 +182,7 @@ static int TexLog2(float delta) {
return useful - 127 * 256;
}
SamplerCacheKey TextureCacheCommon::GetSamplingParams(int maxLevel, const TexCacheEntry *entry) {
SamplerCacheKey TextureCacheCommon::GetSamplingParams(int maxLevel, const TexCacheEntry *entry, bool flatZ) {
SamplerCacheKey key{};
int minFilt = gstate.texfilter & 0x7;
@@ -224,7 +224,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) && g_Config.iAnisotropyLevel > 0) {
if (gstate_c.Use(GPU_USE_ANISOTROPY) && !flatZ) {
key.aniso = true;
}
break;
@@ -260,7 +260,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) && g_Config.iAnisotropyLevel > 0) {
if (gstate_c.Use(GPU_USE_ANISOTROPY) && !flatZ) {
key.aniso = true;
}
}
@@ -294,7 +294,7 @@ 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) && g_Config.iAnisotropyLevel > 0) {
if (gstate_c.Use(GPU_USE_ANISOTROPY) && !flatZ) {
key.aniso = true;
}
if (gstate.isModeThrough() && g_Config.iInternalResolution != 1) {
@@ -339,7 +339,7 @@ SamplerCacheKey TextureCacheCommon::GetSamplingParams(int maxLevel, const TexCac
}
SamplerCacheKey TextureCacheCommon::GetFramebufferSamplingParams(u16 bufferWidth, u16 bufferHeight) {
SamplerCacheKey key = GetSamplingParams(0, nullptr);
SamplerCacheKey key = GetSamplingParams(0, nullptr, true);
// In case auto max quality was on, restore min filt. Another fix for water in Outrun.
if (g_Config.iTexFiltering == TEX_FILTER_AUTO_MAX_QUALITY) {
@@ -2129,14 +2129,14 @@ CheckAlphaResult TextureCacheCommon::ReadIndexedTex(u8 *out, int outPitch, int l
}
}
void TextureCacheCommon::ApplyTexture(bool doBind) {
void TextureCacheCommon::ApplyTexture(bool doBind, bool flatZ) {
TexCacheEntry *entry = nextTexture_;
if (!entry) {
// Maybe we bound a framebuffer?
ForgetLastTexture();
if (failedTexture_) {
// Backends should handle this by binding a black texture with 0 alpha.
BindTexture(nullptr);
BindTexture(nullptr, flatZ);
} else if (nextFramebufferTexture_) {
// ApplyTextureFrameBuffer is responsible for setting SetTextureFullAlpha.
ApplyTextureFramebuffer(nextFramebufferTexture_, gstate.getTextureFormat(), nextFramebufferTextureChannel_);
@@ -2211,7 +2211,7 @@ void TextureCacheCommon::ApplyTexture(bool doBind) {
} else {
entry->lastFrame = gpuStats.totals.numFlips;
if (doBind) {
BindTexture(entry);
BindTexture(entry, flatZ);
}
gstate_c.SetTextureFullAlpha(entry->GetAlphaStatus() == TexCacheEntry::STATUS_ALPHA_FULL);
gstate_c.SetTextureIs3D((entry->status & TexCacheEntry::STATUS_3D) != 0);
+3 -3
View File
@@ -351,7 +351,7 @@ public:
shaderManager_ = sm;
}
void ApplyTexture(bool doBind = true);
void ApplyTexture(bool doBind, bool flatZ);
bool SetOffsetTexture(u32 yOffset);
void Invalidate(u32 addr, int size, GPUInvalidationType type);
void InvalidateAll(GPUInvalidationType type);
@@ -408,7 +408,7 @@ public:
protected:
bool PrepareBuildTexture(BuildTexturePlan &plan, TexCacheEntry *entry);
virtual void BindTexture(TexCacheEntry *entry) = 0;
virtual void BindTexture(TexCacheEntry *entry, bool flatZ) = 0;
virtual void Unbind() = 0;
virtual void ReleaseTexture(TexCacheEntry *entry, bool delete_them) = 0;
void DeleteTexture(TexCache::iterator it);
@@ -445,7 +445,7 @@ protected:
static u32 EstimateTexMemoryUsage(const TexCacheEntry *entry);
SamplerCacheKey GetSamplingParams(int maxLevel, const TexCacheEntry *entry);
SamplerCacheKey GetSamplingParams(int maxLevel, const TexCacheEntry *entry, bool flatZ);
SamplerCacheKey GetFramebufferSamplingParams(u16 bufferWidth, u16 bufferHeight);
void UpdateMaxSeenV(TexCacheEntry *entry, bool throughMode);
+2 -2
View File
@@ -105,7 +105,7 @@ public:
void ReadColor0(float color[4]) const {
switch (decFmt_.c0fmt) {
case DEC_U8_4:
Uint8x4ToFloat4(color, *(const u32 *)(data_ + decFmt_.c0off));
Vec4F32::LoadU8Norm(data_ + decFmt_.c0off).Store(color);
break;
case DEC_FLOAT_4:
memcpy(color, data_ + decFmt_.c0off, 16);
@@ -119,7 +119,7 @@ public:
Vec4F32 ReadColorF32() const {
switch (decFmt_.c0fmt) {
case DEC_U8_4:
return Vec4F32::LoadU8Norm((const u8 *)(data_ + decFmt_.c0off));
return Vec4F32::LoadU8Norm(data_ + decFmt_.c0off);
case DEC_FLOAT_4:
return Vec4F32::Load((const float *)(data_ + decFmt_.c0off));
default:
+5 -2
View File
@@ -304,6 +304,9 @@ void DrawEngineD3D11::Flush() {
if (changed & (ClipInfoFlags::DepthClampFragment | ClipInfoFlags::MinMaxZDiscard)) {
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_RASTER_STATE);
}
if (changed & ClipInfoFlags::FlatZ) {
gstate_c.Dirty(DIRTY_TEXTURE_PARAMS);
}
lastClipInfoFlags_ = clipInfoFlags_;
}
@@ -332,7 +335,7 @@ void DrawEngineD3D11::Flush() {
if (textureNeedsApply) {
gstate_c.dstSquared = false;
textureCache_->ApplyTexture();
textureCache_->ApplyTexture(true, clipInfoFlags_ & ClipInfoFlags::FlatZ);
if (gstate_c.dstSquared) {
gstate_c.Dirty(DIRTY_BLEND_STATE);
}
@@ -446,7 +449,7 @@ void DrawEngineD3D11::Flush() {
// TODO: This should be after BuildDrawingParams!
if (textureNeedsApply) {
gstate_c.pixelMapped = result.pixelMapped;
textureCache_->ApplyTexture();
textureCache_->ApplyTexture(true, clipInfoFlags_ & ClipInfoFlags::FlatZ);
gstate_c.pixelMapped = false;
}
+3 -3
View File
@@ -245,7 +245,7 @@ void TextureCacheD3D11::UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutBa
clutLastFormat_ = gstate.clutformat;
}
void TextureCacheD3D11::BindTexture(TexCacheEntry *entry) {
void TextureCacheD3D11::BindTexture(TexCacheEntry *entry, bool flatZ) {
if (!entry) {
ID3D11ShaderResourceView *textureView = nullptr;
context_->PSSetShaderResources(0, 1, &textureView);
@@ -257,7 +257,7 @@ void TextureCacheD3D11::BindTexture(TexCacheEntry *entry) {
lastBoundTexture_ = textureView;
}
int maxLevel = (entry->status & TexCacheEntry::STATUS_NO_MIPS) ? 0 : entry->maxLevel;
SamplerCacheKey samplerKey = GetSamplingParams(maxLevel, entry);
SamplerCacheKey samplerKey = GetSamplingParams(maxLevel, entry, flatZ);
ComPtr<ID3D11SamplerState> state;
samplerCache_.GetOrCreateSampler(device_, samplerKey, &state);
context_->PSSetSamplers(0, 1, state.GetAddressOf());
@@ -499,7 +499,7 @@ bool TextureCacheD3D11::GetCurrentTextureDebug(GPUDebugBuffer &buffer, int level
// Apply texture may need to rebuild the texture if we're about to render, or bind a framebuffer.
TexCacheEntry *entry = nextTexture_;
ApplyTexture();
ApplyTexture(true, false);
ID3D11Texture2D *texture = (ID3D11Texture2D *)entry->texturePtr;
if (!texture)
+1 -1
View File
@@ -64,7 +64,7 @@ public:
void DestroyDeviceObjects();
protected:
void BindTexture(TexCacheEntry *entry) override;
void BindTexture(TexCacheEntry *entry, bool flatZ) override;
void Unbind() override;
void ReleaseTexture(TexCacheEntry *entry, bool delete_them) override;
void BindAsClutTexture(Draw::Texture *tex, bool smooth) override;
+5 -2
View File
@@ -264,6 +264,9 @@ void DrawEngineGLES::Flush() {
if (changed & (ClipInfoFlags::DepthClampFragment | ClipInfoFlags::MinMaxZDiscard)) {
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_RASTER_STATE);
}
if (changed & ClipInfoFlags::FlatZ) {
gstate_c.Dirty(DIRTY_TEXTURE_PARAMS);
}
lastClipInfoFlags_ = clipInfoFlags_;
}
@@ -317,7 +320,7 @@ void DrawEngineGLES::Flush() {
}
if (textureNeedsApply) {
textureCache_->ApplyTexture();
textureCache_->ApplyTexture(true, clipInfoFlags_ & ClipInfoFlags::FlatZ);
}
// Need to ApplyDrawState after ApplyTexture because depal can launch a render pass and that wrecks the state.
@@ -398,7 +401,7 @@ void DrawEngineGLES::Flush() {
if (textureNeedsApply) {
gstate_c.pixelMapped = result.pixelMapped;
gstate_c.dstSquared = false;
textureCache_->ApplyTexture();
textureCache_->ApplyTexture(true, clipInfoFlags_ & ClipInfoFlags::FlatZ);
if (gstate_c.dstSquared) {
gstate_c.Dirty(DIRTY_BLEND_STATE);
}
+3 -3
View File
@@ -191,7 +191,7 @@ void TextureCacheGLES::UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutBas
clutLastFormat_ = gstate.clutformat;
}
void TextureCacheGLES::BindTexture(TexCacheEntry *entry) {
void TextureCacheGLES::BindTexture(TexCacheEntry *entry, bool flatZ) {
if (!entry) {
render_->BindTexture(0, nullptr);
lastBoundTexture = nullptr;
@@ -202,7 +202,7 @@ void TextureCacheGLES::BindTexture(TexCacheEntry *entry) {
lastBoundTexture = entry->textureName;
}
int maxLevel = (entry->status & TexCacheEntry::STATUS_NO_MIPS) ? 0 : entry->maxLevel;
SamplerCacheKey samplerKey = GetSamplingParams(maxLevel, entry);
SamplerCacheKey samplerKey = GetSamplingParams(maxLevel, entry, flatZ);
ApplySamplingParams(samplerKey);
gstate_c.SetUseShaderDepal(ShaderDepalMode::OFF);
}
@@ -388,7 +388,7 @@ bool TextureCacheGLES::GetCurrentTextureDebug(GPUDebugBuffer &buffer, int level,
TexCacheEntry *entry = nextTexture_;
// We might need a render pass to set the sampling params, unfortunately. Otherwise BuildTexture may crash.
framebufferManagerGL_->RebindFramebuffer("RebindFramebuffer - GetCurrentTextureDebug");
ApplyTexture(false);
ApplyTexture(false, false);
GLRenderManager *renderManager = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
+1 -1
View File
@@ -57,7 +57,7 @@ public:
void DeviceRestore(Draw::DrawContext *draw) override;
protected:
void BindTexture(TexCacheEntry *entry) override;
void BindTexture(TexCacheEntry *entry, bool flatZ) override;
void Unbind() override;
void ReleaseTexture(TexCacheEntry *entry, bool delete_them) override;
+1 -1
View File
@@ -573,7 +573,7 @@ u32 GPUCommonHW::CheckGPUFeatures() const {
if (draw_->GetDeviceCaps().logicOpSupported) {
features |= GPU_USE_LOGIC_OP;
}
if (draw_->GetDeviceCaps().anisoSupported) {
if (draw_->GetDeviceCaps().anisoSupported && g_Config.iAnisotropyLevel > 0) {
features |= GPU_USE_ANISOTROPY;
}
if (draw_->GetDeviceCaps().dualSourceBlend) {
+1
View File
@@ -196,6 +196,7 @@ enum {
};
enum class ClipInfoFlags {
Empty = 0,
Valid = 1,
SoftClipCull = 2,
FlatZ = 4,
+3 -9
View File
@@ -176,15 +176,9 @@ void GPUgstate::FastLoadBoneMatrix(u32 addr) {
__m128i row1 = _mm_slli_epi32(_mm_loadu_si128((const __m128i *)src), 8);
__m128i row2 = _mm_slli_epi32(_mm_loadu_si128((const __m128i *)(src + 4)), 8);
__m128i row3 = _mm_slli_epi32(_mm_loadu_si128((const __m128i *)(src + 8)), 8);
if ((num & 0x3) == 0) {
_mm_store_si128((__m128i *)dst, row1);
_mm_store_si128((__m128i *)(dst + 4), row2);
_mm_store_si128((__m128i *)(dst + 8), row3);
} else {
_mm_storeu_si128((__m128i *)dst, row1);
_mm_storeu_si128((__m128i *)(dst + 4), row2);
_mm_storeu_si128((__m128i *)(dst + 8), row3);
}
_mm_storeu_si128((__m128i *)dst, row1);
_mm_storeu_si128((__m128i *)(dst + 4), row2);
_mm_storeu_si128((__m128i *)(dst + 8), row3);
#elif PPSSPP_ARCH(ARM_NEON)
const uint32x4_t row1 = vshlq_n_u32(vld1q_u32(src), 8);
const uint32x4_t row2 = vshlq_n_u32(vld1q_u32(src + 4), 8);
+6 -3
View File
@@ -251,6 +251,9 @@ void DrawEngineVulkan::Flush() {
if (changed & (ClipInfoFlags::DepthClampFragment | ClipInfoFlags::MinMaxZDiscard)) {
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_RASTER_STATE);
}
if (changed & ClipInfoFlags::FlatZ) {
gstate_c.Dirty(DIRTY_TEXTURE_PARAMS);
}
lastClipInfoFlags_ = clipInfoFlags_;
}
@@ -297,8 +300,8 @@ void DrawEngineVulkan::Flush() {
gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && ((hasColor && (gstate.materialupdate & 1)) || gstate.getMaterialAmbientA() == 255) && (!gstate.isLightingEnabled() || gstate.getAmbientA() == 255);
}
if (textureNeedsApply || true) {
textureCache_->ApplyTexture();
if (textureNeedsApply) {
textureCache_->ApplyTexture(true, clipInfoFlags_ & ClipInfoFlags::FlatZ);
textureCache_->GetVulkanHandles(imageView, sampler);
if (imageView == VK_NULL_HANDLE)
imageView = (VkImageView)draw_->GetNativeObject(gstate_c.textureIsArray ? Draw::NativeObject::NULL_IMAGEVIEW_ARRAY : Draw::NativeObject::NULL_IMAGEVIEW);
@@ -462,7 +465,7 @@ void DrawEngineVulkan::Flush() {
if (textureNeedsApply) {
gstate_c.pixelMapped = result.pixelMapped;
gstate_c.dstSquared = false;
textureCache_->ApplyTexture();
textureCache_->ApplyTexture(true, clipInfoFlags_ & ClipInfoFlags::FlatZ);
gstate_c.pixelMapped = false;
textureCache_->GetVulkanHandles(imageView, sampler);
if (imageView == VK_NULL_HANDLE)
+3 -3
View File
@@ -632,14 +632,14 @@ void TextureCacheVulkan::UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutB
clutLastFormat_ = gstate.clutformat;
}
void TextureCacheVulkan::BindTexture(TexCacheEntry *entry) {
void TextureCacheVulkan::BindTexture(TexCacheEntry *entry, bool flatZ) {
if (!entry || !entry->vkTex) {
Unbind();
return;
}
int maxLevel = (entry->status & TexCacheEntry::STATUS_NO_MIPS) ? 0 : entry->maxLevel;
SamplerCacheKey samplerKey = GetSamplingParams(maxLevel, entry);
SamplerCacheKey samplerKey = GetSamplingParams(maxLevel, entry, flatZ);
curSampler_ = samplerCache_.GetOrCreateSampler(samplerKey);
imageView_ = entry->vkTex->GetImageView();
drawEngine_->SetDepalTexture(VK_NULL_HANDLE, false);
@@ -1060,7 +1060,7 @@ bool TextureCacheVulkan::GetCurrentTextureDebug(GPUDebugBuffer &buffer, int leve
// Apply texture may need to rebuild the texture if we're about to render, or bind a framebuffer.
TexCacheEntry *entry = nextTexture_;
ApplyTexture();
ApplyTexture(true, false);
if (!entry->vkTex)
return false;
+1 -1
View File
@@ -85,7 +85,7 @@ public:
void *GetNativeTextureView(const TexCacheEntry *entry, bool flat) const override;
protected:
void BindTexture(TexCacheEntry *entry) override;
void BindTexture(TexCacheEntry *entry, bool flatZ) override;
void Unbind() override;
void ReleaseTexture(TexCacheEntry *entry, bool delete_them) override;
void BindAsClutTexture(Draw::Texture *tex, bool smooth) override;
+4
View File
@@ -619,9 +619,13 @@ void GameSettingsScreen::CreateGraphicsSettings(UI::ViewGroup *graphicsSettings)
graphicsSettings->Add(new SettingHint(gr->T("Deposterize Tip", "Fixes visual banding glitches in upscaled textures"), deposterize));
graphicsSettings->Add(new ItemHeader(gr->T("Texture Filtering")));
static const char *anisoLevels[] = { "Off", "2x", "4x", "8x", "16x" };
PopupMultiChoice *anisoFiltering = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iAnisotropyLevel, gr->T("Anisotropic Filtering"), anisoLevels, 0, ARRAY_SIZE(anisoLevels), I18NCat::GRAPHICS, screenManager()));
anisoFiltering->SetDisabledPtr(&g_Config.bSoftwareRendering);
anisoFiltering->OnChoice.Add([](UI::EventParams &e) {
System_PostUIMessage(UIMessage::GPU_CONFIG_CHANGED);
});
static const char *texFilters[] = { "Auto", "Nearest", "Linear", "Auto Max Quality"};
PopupMultiChoice *filters = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iTexFiltering, gr->T("Texture Filter"), texFilters, 1, ARRAY_SIZE(texFilters), I18NCat::GRAPHICS, screenManager()));
+1 -1
View File
@@ -1344,7 +1344,7 @@ void ImGeDebuggerWindow::Draw(ImConfig &cfg, ImControl &control, GPUCommon *gpuD
TexCacheEntry *tex = texcache ? texcache->SetTexture() : nullptr;
if (tex) {
ImGui::Text("Texture: %08x", tex->addr);
texcache->ApplyTexture(false);
texcache->ApplyTexture(false, false);
void *nativeView = texcache->GetNativeTextureView(tex, true);
ImTextureID texId = ImGui_ImplThin3d_AddNativeTextureTemp(nativeView);