From b6375638f511fd311efef5cf2e482af5d6c03f4c Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Wed, 31 May 2017 21:23:20 -0700 Subject: [PATCH] GPU: Block mipmap autogen for matching size. If the mips don't get smaller, we can't autogen - the bias in that case is used to select a different texture. Fixes #9731. This also may improve a minor performance issue on PowerVR in some games. --- GPU/Common/TextureCacheCommon.h | 2 ++ GPU/D3D11/TextureCacheD3D11.cpp | 10 +++++-- GPU/Directx9/TextureCacheDX9.cpp | 12 ++++++-- GPU/GLES/TextureCacheGLES.cpp | 46 ++++++++++++++++++++++--------- GPU/Vulkan/TextureCacheVulkan.cpp | 8 +++++- 5 files changed, 59 insertions(+), 19 deletions(-) diff --git a/GPU/Common/TextureCacheCommon.h b/GPU/Common/TextureCacheCommon.h index 7b3b1709eb..5dd4753970 100644 --- a/GPU/Common/TextureCacheCommon.h +++ b/GPU/Common/TextureCacheCommon.h @@ -111,6 +111,8 @@ struct TexCacheEntry { // is commonly the only part accessed. If access is made above 272, we hash the entire // texture, and set this flag to allow scaling the texture just once for the new hash. STATUS_FREE_CHANGE = 0x200, // Allow one change before marking "frequent". + + STATUS_BAD_MIPS = 0x400, // Has bad or unusable mipmap levels. }; // Status, but int so we can zero initialize. diff --git a/GPU/D3D11/TextureCacheD3D11.cpp b/GPU/D3D11/TextureCacheD3D11.cpp index 95d5cf401e..7250a34c14 100644 --- a/GPU/D3D11/TextureCacheD3D11.cpp +++ b/GPU/D3D11/TextureCacheD3D11.cpp @@ -177,7 +177,8 @@ void TextureCacheD3D11::UpdateSamplingParams(TexCacheEntry &entry, SamplerCacheK bool tClamp; float lodBias; bool autoMip; - GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, entry.maxLevel, entry.addr, autoMip); + u8 maxLevel = (entry.status & TexCacheEntry::STATUS_BAD_MIPS) ? 0 : entry.maxLevel; + GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, maxLevel, entry.addr, autoMip); key.minFilt = minFilt & 1; key.mipEnable = (minFilt >> 2) & 1; key.mipFilt = (minFilt >> 1) & 1; @@ -186,7 +187,7 @@ void TextureCacheD3D11::UpdateSamplingParams(TexCacheEntry &entry, SamplerCacheK key.tClamp = tClamp; // Don't clamp to maxLevel - this may bias magnify levels. key.lodBias = (int)(lodBias * 256.0f); - key.maxLevel = entry.maxLevel; + key.maxLevel = maxLevel; key.lodAuto = autoMip; if (entry.framebuffer) { @@ -587,6 +588,11 @@ void TextureCacheD3D11::BuildTexture(TexCacheEntry *const entry, bool replaceIma } } + if (maxLevel == 0) { + entry->status |= TexCacheEntry::STATUS_BAD_MIPS; + } else { + entry->status &= ~TexCacheEntry::STATUS_BAD_MIPS; + } if (replaced.Valid()) { entry->SetAlphaStatus(TexCacheEntry::Status(replaced.AlphaStatus())); } diff --git a/GPU/Directx9/TextureCacheDX9.cpp b/GPU/Directx9/TextureCacheDX9.cpp index 0fffa606ea..0a3e82ae3d 100644 --- a/GPU/Directx9/TextureCacheDX9.cpp +++ b/GPU/Directx9/TextureCacheDX9.cpp @@ -155,16 +155,17 @@ void TextureCacheDX9::UpdateSamplingParams(TexCacheEntry &entry, bool force) { bool tClamp; float lodBias; bool autoMip; - GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, entry.maxLevel, entry.addr, autoMip); + u8 maxLevel = (entry.status & TexCacheEntry::STATUS_BAD_MIPS) ? 0 : entry.maxLevel; + GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, maxLevel, entry.addr, autoMip); - if (entry.maxLevel != 0) { + if (maxLevel != 0) { if (autoMip) { dxstate.texMaxMipLevel.set(0); dxstate.texMipLodBias.set(lodBias); } else { // TODO: This is just an approximation - texMaxMipLevel sets the lowest numbered mip to use. // Unfortunately, this doesn't support a const 1.5 or etc. - dxstate.texMaxMipLevel.set(std::max(0, std::min((int)entry.maxLevel, (int)lodBias))); + dxstate.texMaxMipLevel.set(std::max(0, std::min((int)maxLevel, (int)lodBias))); dxstate.texMipLodBias.set(-1000.0f); } entry.lodBias = lodBias; @@ -590,6 +591,11 @@ void TextureCacheDX9::BuildTexture(TexCacheEntry *const entry, bool replaceImage } } + if (maxLevel == 0) { + entry->status |= TexCacheEntry::STATUS_BAD_MIPS; + } else { + entry->status &= ~TexCacheEntry::STATUS_BAD_MIPS; + } if (replaced.Valid()) { entry->SetAlphaStatus(TexCacheEntry::Status(replaced.AlphaStatus())); } diff --git a/GPU/GLES/TextureCacheGLES.cpp b/GPU/GLES/TextureCacheGLES.cpp index 2950324c88..fbbf489bc0 100644 --- a/GPU/GLES/TextureCacheGLES.cpp +++ b/GPU/GLES/TextureCacheGLES.cpp @@ -129,10 +129,11 @@ void TextureCacheGLES::UpdateSamplingParams(TexCacheEntry &entry, bool force) { bool tClamp; float lodBias; bool autoMip; - GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, entry.maxLevel, entry.addr, autoMip); + u8 maxLevel = (entry.status & TexCacheEntry::STATUS_BAD_MIPS) ? 0 : entry.maxLevel; + GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, maxLevel, entry.addr, autoMip); if (gstate_c.Supports(GPU_SUPPORTS_TEXTURE_LOD_CONTROL)) { - if (entry.maxLevel != 0) { + if (maxLevel != 0) { // TODO: What about a swap of autoMip mode? if (force || entry.lodBias != lodBias) { if (autoMip) { @@ -141,10 +142,10 @@ void TextureCacheGLES::UpdateSamplingParams(TexCacheEntry &entry, bool force) { glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, lodBias); #endif glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, (float)entry.maxLevel); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, (float)maxLevel); } else { - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, std::max(0.0f, std::min((float)entry.maxLevel, lodBias))); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, std::max(0.0f, std::min((float)entry.maxLevel, lodBias))); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, std::max(0.0f, std::min((float)maxLevel, lodBias))); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, std::max(0.0f, std::min((float)maxLevel, lodBias))); } entry.lodBias = lodBias; } @@ -570,6 +571,7 @@ void TextureCacheGLES::BuildTexture(TexCacheEntry *const entry, bool replaceImag // Adjust maxLevel to actually present levels.. bool badMipSizes = false; + bool canAutoGen = false; int maxLevel = entry->maxLevel; for (int i = 0; i <= maxLevel; i++) { // If encountering levels pointing to nothing, adjust max level. @@ -587,11 +589,19 @@ void TextureCacheGLES::BuildTexture(TexCacheEntry *const entry, bool replaceImag break; } - if (i > 0 && gstate_c.Supports(GPU_SUPPORTS_TEXTURE_LOD_CONTROL)) { - if (tw != 1 && tw != (gstate.getTextureWidth(i - 1) >> 1)) - badMipSizes = true; - else if (th != 1 && th != (gstate.getTextureHeight(i - 1) >> 1)) - badMipSizes = true; + if (i > 0) { + int lastW = gstate.getTextureWidth(i - 1); + int lastH = gstate.getTextureHeight(i - 1); + + if (gstate_c.Supports(GPU_SUPPORTS_TEXTURE_LOD_CONTROL)) { + if (tw != 1 && tw != (lastW >> 1)) + badMipSizes = true; + else if (th != 1 && th != (lastH >> 1)) + badMipSizes = true; + } + + if (lastW > tw || lastH > th) + canAutoGen = true; } } @@ -688,7 +698,12 @@ void TextureCacheGLES::BuildTexture(TexCacheEntry *const entry, bool replaceImag if (gstate_c.Supports(GPU_SUPPORTS_TEXTURE_LOD_CONTROL)) { if (badMipSizes) { // WARN_LOG(G3D, "Bad mipmap for texture sized %dx%dx%d - autogenerating", w, h, (int)format); - glGenerateMipmap(GL_TEXTURE_2D); + if (canAutoGen) { + glGenerateMipmap(GL_TEXTURE_2D); + } else { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); + maxLevel = 0; + } } else { for (int i = 1; i <= maxLevel; i++) { LoadTextureLevel(*entry, replaced, i, replaceImages, scaleFactor, dstFmt); @@ -697,17 +712,22 @@ void TextureCacheGLES::BuildTexture(TexCacheEntry *const entry, bool replaceImag } } else { // Avoid PowerVR driver bug - if (w > 1 && h > 1 && !(h > w && (gl_extensions.bugs & BUG_PVR_GENMIPMAP_HEIGHT_GREATER))) { // Really! only seems to fail if height > width + if (canAutoGen && w > 1 && h > 1 && !(h > w && (gl_extensions.bugs & BUG_PVR_GENMIPMAP_HEIGHT_GREATER))) { // Really! only seems to fail if height > width // NOTICE_LOG(G3D, "Generating mipmap for texture sized %dx%d%d", w, h, (int)format); glGenerateMipmap(GL_TEXTURE_2D); } else { - entry->maxLevel = 0; + maxLevel = 0; } } } else if (gstate_c.Supports(GPU_SUPPORTS_TEXTURE_LOD_CONTROL)) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); } + if (maxLevel == 0) { + entry->status |= TexCacheEntry::STATUS_BAD_MIPS; + } else { + entry->status &= ~TexCacheEntry::STATUS_BAD_MIPS; + } if (replaced.Valid()) { entry->SetAlphaStatus(TexCacheEntry::Status(replaced.AlphaStatus())); } diff --git a/GPU/Vulkan/TextureCacheVulkan.cpp b/GPU/Vulkan/TextureCacheVulkan.cpp index 1c79a9474d..b1fbad234f 100644 --- a/GPU/Vulkan/TextureCacheVulkan.cpp +++ b/GPU/Vulkan/TextureCacheVulkan.cpp @@ -212,7 +212,8 @@ void TextureCacheVulkan::UpdateSamplingParams(TexCacheEntry &entry, SamplerCache bool tClamp; float lodBias; bool autoMip; - GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, entry.maxLevel, entry.addr, autoMip); + u8 maxLevel = (entry.status & TexCacheEntry::STATUS_BAD_MIPS) ? 0 : entry.maxLevel; + GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, maxLevel, entry.addr, autoMip); key.minFilt = minFilt & 1; key.mipEnable = (minFilt >> 2) & 1; key.mipFilt = (minFilt >> 1) & 1; @@ -661,6 +662,11 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry, bool replaceIm entry->vkTex->texture_->UploadMip(i, mipWidth, mipHeight, texBuf, bufferOffset, stride / bpp); } + if (maxLevel == 0) { + entry->status |= TexCacheEntry::STATUS_BAD_MIPS; + } else { + entry->status &= ~TexCacheEntry::STATUS_BAD_MIPS; + } if (replaced.Valid()) { entry->SetAlphaStatus(TexCacheEntry::Status(replaced.AlphaStatus())); }