Merge pull request #9678 from unknownbrackets/mipmaps

Make const mipmaps more consistent
This commit is contained in:
Henrik Rydgård 2017-05-13 16:58:55 +02:00 committed by GitHub
commit 8cff9f8bc9
8 changed files with 73 additions and 80 deletions

View File

@ -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) {

View File

@ -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);

View File

@ -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;

View File

@ -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]);

View File

@ -128,42 +128,31 @@ 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 (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;
}
} else if (gstate_c.Supports(GPU_SUPPORTS_TEXTURE_LOD_CONTROL)) {
} else {
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) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, MinFiltGL[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.

View File

@ -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;

View File

@ -1226,7 +1226,7 @@ static inline void ApplyTexturing(Vec4<int> *prim_color, const Vec4<float> &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;
}

View File

@ -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;