From c4d1863ded0c941ed068bfdb2aa140b02c74db40 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 12 May 2017 20:01:08 -0700 Subject: [PATCH 1/2] GPU: Consistently bias const mip levels. Since SLOPE is just a more complicated CONST, we can treat them the same. --- GPU/Common/TextureCacheCommon.cpp | 40 ++++++++++++++++++++--------- GPU/Common/TextureCacheCommon.h | 5 ++-- GPU/D3D11/TextureCacheD3D11.cpp | 21 ++++++++-------- GPU/Directx9/TextureCacheDX9.cpp | 22 ++++++---------- GPU/GLES/TextureCacheGLES.cpp | 42 ++++++++++++------------------- GPU/Software/Rasterizer.cpp | 2 +- GPU/Vulkan/TextureCacheVulkan.cpp | 17 +++++-------- 7 files changed, 71 insertions(+), 78 deletions(-) diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index 5903674833..ca676290c7 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -124,23 +124,43 @@ int TextureCacheCommon::AttachedDrawingHeight() { return 0; } -void TextureCacheCommon::GetSamplingParams(int &minFilt, int &magFilt, bool &sClamp, bool &tClamp, float &lodBias, u8 maxLevel, u32 addr) { +// Produces a signed 1.23.8 value. +static int TexLog2(float delta) { + union FloatBits { + float f; + u32 u; + }; + FloatBits f; + f.f = delta; + // Use the exponent as the tex level, and the top mantissa bits for a frac. + // We can't support more than 8 bits of frac, so truncate. + int useful = (f.u >> 15) & 0xFFFF; + // Now offset so the exponent aligns with log2f (exp=127 is 0.) + return useful - 127 * 256; +} + +void TextureCacheCommon::GetSamplingParams(int &minFilt, int &magFilt, bool &sClamp, bool &tClamp, float &lodBias, u8 maxLevel, u32 addr, bool &autoMip) { minFilt = gstate.texfilter & 0x7; magFilt = (gstate.texfilter >> 8) & 1; sClamp = gstate.isTexCoordClampedS(); tClamp = gstate.isTexCoordClampedT(); - bool noMip = (gstate.texlevel & 0xFFFFFF) == 0x000001; // Fix texlevel at 0 - if (IsFakeMipmapChange()) - noMip = gstate.getTexLevelMode() == GE_TEXLEVEL_MODE_CONST; + GETexLevelMode mipMode = gstate.getTexLevelMode(); + autoMip = mipMode == GE_TEXLEVEL_MODE_AUTO; + lodBias = (float)(int)(s8)((gstate.texlevel >> 16) & 0xFF) * (1.0f / 16.0f); + if (mipMode == GE_TEXLEVEL_MODE_SLOPE) { + lodBias += 1.0f + TexLog2(gstate.getTextureLodSlope()) * (1.0f / 256.0f); + } - if (maxLevel == 0) { + // If mip level is forced to zero, disable mipmapping. + bool noMip = !g_Config.bMipMap || maxLevel == 0 || (!autoMip && lodBias <= 0.0f); + if (IsFakeMipmapChange()) + noMip = noMip || !autoMip; + + if (noMip) { // Enforce no mip filtering, for safety. minFilt &= 1; // no mipmaps yet lodBias = 0.0f; - } else { - // Texture lod bias should be signed. - lodBias = (float)(int)(s8)((gstate.texlevel >> 16) & 0xFF) / 16.0f; } if (g_Config.iTexFiltering == TEX_FILTER_LINEAR_VIDEO) { @@ -169,10 +189,6 @@ void TextureCacheCommon::GetSamplingParams(int &minFilt, int &magFilt, bool &sCl magFilt &= ~1; minFilt &= ~1; } - - if (!g_Config.bMipMap || noMip) { - minFilt &= 1; - } } void TextureCacheCommon::UpdateMaxSeenV(TexCacheEntry *entry, bool throughMode) { diff --git a/GPU/Common/TextureCacheCommon.h b/GPU/Common/TextureCacheCommon.h index 18ce41711d..7b3b1709eb 100644 --- a/GPU/Common/TextureCacheCommon.h +++ b/GPU/Common/TextureCacheCommon.h @@ -71,8 +71,9 @@ struct SamplerCacheKey { bool tClamp : 1; bool lodAuto : 1; bool : 1; - int8_t lodBias : 8; int8_t maxLevel : 4; + int8_t : 4; + int16_t lodBias : 16; }; }; @@ -242,7 +243,7 @@ protected: } u32 EstimateTexMemoryUsage(const TexCacheEntry *entry); - void GetSamplingParams(int &minFilt, int &magFilt, bool &sClamp, bool &tClamp, float &lodBias, u8 maxLevel, u32 addr); + void GetSamplingParams(int &minFilt, int &magFilt, bool &sClamp, bool &tClamp, float &lodBias, u8 maxLevel, u32 addr, bool &autoMip); void UpdateMaxSeenV(TexCacheEntry *entry, bool throughMode); bool AttachFramebuffer(TexCacheEntry *entry, u32 address, VirtualFramebuffer *framebuffer, u32 texaddrOffset = 0); diff --git a/GPU/D3D11/TextureCacheD3D11.cpp b/GPU/D3D11/TextureCacheD3D11.cpp index 2c112229ea..59b1775b18 100644 --- a/GPU/D3D11/TextureCacheD3D11.cpp +++ b/GPU/D3D11/TextureCacheD3D11.cpp @@ -99,11 +99,11 @@ ID3D11SamplerState *SamplerCacheD3D11::GetOrCreateSampler(ID3D11Device *device, // Auto selected mip + bias. samp.MaxLOD = key.maxLevel; samp.MinLOD = 0.0f; - samp.MipLODBias = (float)key.lodBias / 16.0f; + samp.MipLODBias = (float)key.lodBias / 256.0f; } else { // Constant mip at bias. - samp.MaxLOD = (float)key.lodBias / 16.0f; - samp.MinLOD = (float)key.lodBias / 16.0f; + samp.MaxLOD = std::max(0.0f, std::min((float)key.maxLevel, (float)key.lodBias / 256.0f)); + samp.MinLOD = std::max(0.0f, std::min((float)key.maxLevel, (float)key.lodBias / 256.0f)); samp.MipLODBias = 0.0f; } #endif @@ -176,20 +176,18 @@ void TextureCacheD3D11::UpdateSamplingParams(TexCacheEntry &entry, SamplerCacheK bool sClamp; bool tClamp; float lodBias; - GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, entry.maxLevel, entry.addr); + bool autoMip; + GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, entry.maxLevel, entry.addr, autoMip); key.minFilt = minFilt & 1; key.mipEnable = (minFilt >> 2) & 1; key.mipFilt = (minFilt >> 1) & 1; key.magFilt = magFilt & 1; key.sClamp = sClamp; key.tClamp = tClamp; - key.lodBias = (s8)((gstate.texlevel >> 16) & 0xFF); - if (key.lodBias > entry.maxLevel * 16) { - key.lodBias = entry.maxLevel * 16; - } + // Don't clamp to maxLevel - this may bias magnify levels. + key.lodBias = (int)(lodBias * 256.0f); key.maxLevel = entry.maxLevel; - key.lodAuto = gstate.getTexLevelMode() == GE_TEXLEVEL_MODE_AUTO; - // TODO: GE_TEXLEVEL_MODE_SLOPE + key.lodAuto = autoMip; if (entry.framebuffer) { WARN_LOG_REPORT_ONCE(wrongFramebufAttach, G3D, "Framebuffer still attached in UpdateSamplingParams()?"); @@ -202,7 +200,8 @@ void TextureCacheD3D11::SetFramebufferSamplingParams(u16 bufferWidth, u16 buffer bool sClamp; bool tClamp; float lodBias; - GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, 0, 0); + bool autoMip; + GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, 0, 0, autoMip); key.minFilt = minFilt & 1; key.mipFilt = 0; diff --git a/GPU/Directx9/TextureCacheDX9.cpp b/GPU/Directx9/TextureCacheDX9.cpp index 148bbff86c..688b01212f 100644 --- a/GPU/Directx9/TextureCacheDX9.cpp +++ b/GPU/Directx9/TextureCacheDX9.cpp @@ -154,27 +154,18 @@ void TextureCacheDX9::UpdateSamplingParams(TexCacheEntry &entry, bool force) { bool sClamp; bool tClamp; float lodBias; - GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, entry.maxLevel, entry.addr); + bool autoMip; + GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, entry.maxLevel, entry.addr, autoMip); if (entry.maxLevel != 0) { - GETexLevelMode mode = gstate.getTexLevelMode(); - switch (mode) { - case GE_TEXLEVEL_MODE_AUTO: + if (autoMip) { dxstate.texMaxMipLevel.set(0); dxstate.texMipLodBias.set(lodBias); - break; - case GE_TEXLEVEL_MODE_CONST: + } 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((int)lodBias); + dxstate.texMaxMipLevel.set(std::max(0, std::min((int)entry.maxLevel, (int)lodBias))); dxstate.texMipLodBias.set(-1000.0f); - break; - case GE_TEXLEVEL_MODE_SLOPE: - WARN_LOG_REPORT_ONCE(texSlope, G3D, "Unsupported texture lod slope: %f + %f", gstate.getTextureLodSlope(), lodBias); - // TODO: This behavior isn't correct. - dxstate.texMaxMipLevel.set(0); - dxstate.texMipLodBias.set(lodBias); - break; } entry.lodBias = lodBias; } else { @@ -203,7 +194,8 @@ void TextureCacheDX9::SetFramebufferSamplingParams(u16 bufferWidth, u16 bufferHe bool sClamp; bool tClamp; float lodBias; - GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, 0, 0); + bool autoMip; + GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, 0, 0, autoMip); dxstate.texMinFilter.set(MinFilt[minFilt]); dxstate.texMipFilter.set(MipFilt[minFilt]); diff --git a/GPU/GLES/TextureCacheGLES.cpp b/GPU/GLES/TextureCacheGLES.cpp index 0072a36b6e..c1d9eaf8bc 100644 --- a/GPU/GLES/TextureCacheGLES.cpp +++ b/GPU/GLES/TextureCacheGLES.cpp @@ -128,41 +128,30 @@ void TextureCacheGLES::UpdateSamplingParams(TexCacheEntry &entry, bool force) { bool sClamp; bool tClamp; float lodBias; - GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, entry.maxLevel, entry.addr); + bool autoMip; + GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, entry.maxLevel, entry.addr, autoMip); - if (entry.maxLevel != 0) { - if (force || entry.lodBias != lodBias) { - if (gstate_c.Supports(GPU_SUPPORTS_TEXTURE_LOD_CONTROL)) { - GETexLevelMode mode = gstate.getTexLevelMode(); - switch (mode) { - case GE_TEXLEVEL_MODE_AUTO: + if (gstate_c.Supports(GPU_SUPPORTS_TEXTURE_LOD_CONTROL)) { + if (entry.maxLevel != 0) { + // TODO: What about a swap of autoMip mode? + if (force || entry.lodBias != lodBias) { + if (autoMip) { #ifndef USING_GLES2 // Sigh, LOD_BIAS is not even in ES 3.0.. but we could do it in the shader via texture()... 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); - break; - case GE_TEXLEVEL_MODE_CONST: - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, lodBias); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, lodBias); - break; - case GE_TEXLEVEL_MODE_SLOPE: - WARN_LOG_REPORT_ONCE(texSlope, G3D, "Unsupported texture lod slope: %f + %f", gstate.getTextureLodSlope(), lodBias); - // TODO: This behavior isn't correct. -#ifndef USING_GLES2 - 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); - break; + } 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))); } + entry.lodBias = lodBias; } - entry.lodBias = lodBias; + } else { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0.0f); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 0.0f); } - } else if (gstate_c.Supports(GPU_SUPPORTS_TEXTURE_LOD_CONTROL)) { - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0.0f); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 0.0f); } if (force || entry.minFilt != minFilt) { @@ -195,7 +184,8 @@ void TextureCacheGLES::SetFramebufferSamplingParams(u16 bufferWidth, u16 bufferH bool sClamp; bool tClamp; float lodBias; - GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, 0, 0); + bool autoMip; + GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, 0, 0, autoMip); minFilt &= 1; // framebuffers can't mipmap. diff --git a/GPU/Software/Rasterizer.cpp b/GPU/Software/Rasterizer.cpp index 527f56dd2f..d1b1ee3b40 100644 --- a/GPU/Software/Rasterizer.cpp +++ b/GPU/Software/Rasterizer.cpp @@ -1226,7 +1226,7 @@ static inline void ApplyTexturing(Vec4 *prim_color, const Vec4 &s, c break; case GE_TEXLEVEL_MODE_CONST: default: - // TODO: Verify what 3 does. + // Unused value 3 operates the same as CONST. detail = 0; break; } diff --git a/GPU/Vulkan/TextureCacheVulkan.cpp b/GPU/Vulkan/TextureCacheVulkan.cpp index a48480e779..e3af9dd032 100644 --- a/GPU/Vulkan/TextureCacheVulkan.cpp +++ b/GPU/Vulkan/TextureCacheVulkan.cpp @@ -211,7 +211,8 @@ void TextureCacheVulkan::UpdateSamplingParams(TexCacheEntry &entry, SamplerCache bool sClamp; bool tClamp; float lodBias; - GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, entry.maxLevel, entry.addr); + bool autoMip; + GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, entry.maxLevel, entry.addr, autoMip); key.minFilt = minFilt & 1; key.mipEnable = (minFilt >> 2) & 1; key.mipFilt = (minFilt >> 1) & 1; @@ -223,17 +224,10 @@ void TextureCacheVulkan::UpdateSamplingParams(TexCacheEntry &entry, SamplerCache if (entry.maxLevel != 0) { if (force || entry.lodBias != lodBias) { if (gstate_c.Supports(GPU_SUPPORTS_TEXTURE_LOD_CONTROL)) { - GETexLevelMode mode = gstate.getTexLevelMode(); - switch (mode) { - case GE_TEXLEVEL_MODE_AUTO: + if (autoMip) { // TODO - break; - case GE_TEXLEVEL_MODE_CONST: - // Sigh, LOD_BIAS is not even in ES 3.0.. - break; - case GE_TEXLEVEL_MODE_SLOPE: + } else { // TODO - break; } } entry.lodBias = lodBias; @@ -252,7 +246,8 @@ void TextureCacheVulkan::SetFramebufferSamplingParams(u16 bufferWidth, u16 buffe bool sClamp; bool tClamp; float lodBias; - GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, 0, 0); + bool autoMip; + GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, 0, 0, autoMip); key.minFilt = minFilt & 1; key.mipFilt = 0; From 10e511273a4240553627acec69e96c812188ada4 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 12 May 2017 20:05:35 -0700 Subject: [PATCH 2/2] GPU: Flush on mipmap slope change. --- GPU/GPUCommon.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index c73404c800..1001821710 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -124,6 +124,7 @@ const CommonCommandTableEntry commonCommandTable[] = { { GE_CMD_TEXSIZE7, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS }, { GE_CMD_TEXFORMAT, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_IMAGE }, { GE_CMD_TEXLEVEL, FLAG_EXECUTEONCHANGE, DIRTY_TEXTURE_PARAMS, &GPUCommon::Execute_TexLevel }, + { GE_CMD_TEXLODSLOPE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS }, { GE_CMD_TEXADDR0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_IMAGE | DIRTY_UVSCALEOFFSET }, { GE_CMD_TEXADDR1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS }, { GE_CMD_TEXADDR2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS }, @@ -265,7 +266,6 @@ const CommonCommandTableEntry commonCommandTable[] = { // Ignored commands { GE_CMD_TEXFLUSH, 0 }, - { GE_CMD_TEXLODSLOPE, 0 }, { GE_CMD_TEXSYNC, 0 }, // These are just nop or part of other later commands. @@ -1416,7 +1416,7 @@ void GPUCommon::Execute_TexLevel(u32 op, u32 diff) { if (diff == 0xFFFFFFFF) return; gstate.texlevel ^= diff; - if (gstate.getTexLevelMode() == GE_TEXLEVEL_MODE_CONST && (0x00FF0000 & gstate.texlevel) != 0) { + if (gstate.getTexLevelMode() != GE_TEXLEVEL_MODE_AUTO && (0x00FF0000 & gstate.texlevel) != 0) { Flush(); } gstate.texlevel ^= diff;