Skip to content

Commit

Permalink
Merge pull request #10130 from hrydgard/lod-bias-fixes
Browse files Browse the repository at this point in the history
Mipmaps: Disable slope mode pending a better method. Implementing it entirely as a LOD bias is not the way it works.
  • Loading branch information
hrydgard authored Nov 20, 2017
2 parents a005bf7 + 7ab6956 commit 674d5c7
Show file tree
Hide file tree
Showing 11 changed files with 109 additions and 132 deletions.
59 changes: 57 additions & 2 deletions GPU/Common/TextureCacheCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,14 +142,15 @@ static int TexLog2(float delta) {
return useful - 127 * 256;
}

void TextureCacheCommon::GetSamplingParams(int &minFilt, int &magFilt, bool &sClamp, bool &tClamp, float &lodBias, u8 maxLevel, u32 addr, bool &autoMip) {
void TextureCacheCommon::GetSamplingParams(int &minFilt, int &magFilt, bool &sClamp, bool &tClamp, float &lodBias, int maxLevel, u32 addr, GETexLevelMode &mode) {
minFilt = gstate.texfilter & 0x7;
magFilt = gstate.isMagnifyFilteringEnabled();
sClamp = gstate.isTexCoordClampedS();
tClamp = gstate.isTexCoordClampedT();

GETexLevelMode mipMode = gstate.getTexLevelMode();
autoMip = mipMode == GE_TEXLEVEL_MODE_AUTO;
mode = mipMode;
bool autoMip = mipMode == GE_TEXLEVEL_MODE_AUTO;
lodBias = (float)gstate.getTexLevelOffset16() * (1.0f / 16.0f);
if (mipMode == GE_TEXLEVEL_MODE_SLOPE) {
lodBias += 1.0f + TexLog2(gstate.getTextureLodSlope()) * (1.0f / 256.0f);
Expand Down Expand Up @@ -194,6 +195,60 @@ void TextureCacheCommon::GetSamplingParams(int &minFilt, int &magFilt, bool &sCl
}
}

void TextureCacheCommon::UpdateSamplingParams(TexCacheEntry &entry, SamplerCacheKey &key) {
// TODO: Make GetSamplingParams write SamplerCacheKey directly
int minFilt;
int magFilt;
bool sClamp;
bool tClamp;
float lodBias;
int maxLevel = (entry.status & TexCacheEntry::STATUS_BAD_MIPS) ? 0 : entry.maxLevel;
GETexLevelMode mode;
GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, maxLevel, entry.addr, mode);
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.aniso = false;

if (!key.mipEnable) {
key.maxLevel = 0;
key.minLevel = 0;
key.lodBias = 0;
} else {
switch (mode) {
case GE_TEXLEVEL_MODE_AUTO:
key.maxLevel = entry.maxLevel * 256;
key.minLevel = 0;
key.lodBias = (int)(lodBias * 256.0f);
if (gstate_c.Supports(GPU_SUPPORTS_ANISOTROPY) && g_Config.iAnisotropyLevel > 0) {
key.aniso = true;
break;
}
case GE_TEXLEVEL_MODE_CONST:
case GE_TEXLEVEL_MODE_UNKNOWN:
key.maxLevel = (int)(lodBias * 256.0f);
key.minLevel = (int)(lodBias * 256.0f);
key.lodBias = 0;
break;
case GE_TEXLEVEL_MODE_SLOPE:
// It's incorrect to use the slope as a bias. Instead it should be passed
// into the shader directly as an explicit lod level, with the bias on top. For now, we just kill the
// lodBias in this mode, working around #9772.
key.maxLevel = entry.maxLevel * 256;
key.minLevel = 0;
key.lodBias = 0;
break;
}
}

if (entry.framebuffer) {
WARN_LOG_REPORT_ONCE(wrongFramebufAttach, G3D, "Framebuffer still attached in UpdateSamplingParams()?");
}
}

void TextureCacheCommon::UpdateMaxSeenV(TexCacheEntry *entry, bool throughMode) {
// If the texture is >= 512 pixels tall...
if (entry->dim >= 0x900) {
Expand Down
19 changes: 9 additions & 10 deletions GPU/Common/TextureCacheCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,25 +58,23 @@ class DrawContext;

// Used by D3D11 and Vulkan, could be used by modern GL
struct SamplerCacheKey {
SamplerCacheKey() : fullKey(0) {}

union {
u32 fullKey;
uint64_t fullKey;
struct {
// These are 8.8 fixed point.
int16_t maxLevel;
int16_t minLevel;
int16_t lodBias;

bool mipEnable : 1;
bool minFilt : 1;
bool mipFilt : 1;
bool magFilt : 1;
bool sClamp : 1;
bool tClamp : 1;
bool lodAuto : 1;
bool : 1;
int8_t maxLevel : 4;
int8_t : 4;
int16_t lodBias : 16;
bool aniso : 1;
};
};

bool operator < (const SamplerCacheKey &other) const {
return fullKey < other.fullKey;
}
Expand Down Expand Up @@ -247,7 +245,8 @@ class TextureCacheCommon {
}

u32 EstimateTexMemoryUsage(const TexCacheEntry *entry);
void GetSamplingParams(int &minFilt, int &magFilt, bool &sClamp, bool &tClamp, float &lodBias, u8 maxLevel, u32 addr, bool &autoMip);
void GetSamplingParams(int &minFilt, int &magFilt, bool &sClamp, bool &tClamp, float &lodBias, int maxLevel, u32 addr, GETexLevelMode &mode);
void UpdateSamplingParams(TexCacheEntry &entry, SamplerCacheKey &key); // Used by D3D11 and Vulkan.
void UpdateMaxSeenV(TexCacheEntry *entry, bool throughMode);

bool AttachFramebuffer(TexCacheEntry *entry, u32 address, VirtualFramebuffer *framebuffer, u32 texaddrOffset = 0);
Expand Down
10 changes: 0 additions & 10 deletions GPU/D3D11/GPU_D3D11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,16 +176,6 @@ GPU_D3D11::GPU_D3D11(GraphicsContext *gfxCtx, Draw::DrawContext *draw)
// Some of our defaults are different from hw defaults, let's assert them.
// We restore each frame anyway, but here is convenient for tests.
textureCache_->NotifyConfigChanged();

if (g_Config.bHardwareTessellation) {
if (false) { // TODO: Check GPU features
// Disable hardware tessellation.
g_Config.bHardwareTessellation = false;
ERROR_LOG(G3D, "Hardware Tessellation is unsupported, falling back to software tessellation");
I18NCategory *gr = GetI18NCategory("Graphics");
host->NotifyUserMessage(gr->T("Turn off Hardware Tessellation - unsupported"), 2.5f, 0xFF3030FF);
}
}
}

GPU_D3D11::~GPU_D3D11() {
Expand Down
56 changes: 9 additions & 47 deletions GPU/D3D11/TextureCacheD3D11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ ID3D11SamplerState *SamplerCacheD3D11::GetOrCreateSampler(ID3D11Device *device,
samp.AddressU = key.sClamp ? D3D11_TEXTURE_ADDRESS_CLAMP : D3D11_TEXTURE_ADDRESS_WRAP;
samp.AddressV = key.tClamp ? D3D11_TEXTURE_ADDRESS_CLAMP : D3D11_TEXTURE_ADDRESS_WRAP;
samp.AddressW = samp.AddressU; // Mali benefits from all clamps being the same, and this one is irrelevant.
if (gstate_c.Supports(GPU_SUPPORTS_ANISOTROPY) && g_Config.iAnisotropyLevel > 0) {
if (key.aniso) {
samp.MaxAnisotropy = (float)(1 << g_Config.iAnisotropyLevel);
} else {
samp.MaxAnisotropy = 1.0f;
Expand All @@ -81,7 +81,7 @@ ID3D11SamplerState *SamplerCacheD3D11::GetOrCreateSampler(ID3D11Device *device,
D3D11_FILTER_MIN_MAG_MIP_LINEAR,
};
// Only switch to aniso if linear min and mag are set.
if (samp.MaxAnisotropy > 1.0f && key.magFilt != 0 && key.minFilt != 0)
if (key.aniso && key.magFilt != 0 && key.minFilt != 0)
samp.Filter = D3D11_FILTER_ANISOTROPIC;
else
samp.Filter = filters[filterKey];
Expand All @@ -91,21 +91,9 @@ ID3D11SamplerState *SamplerCacheD3D11::GetOrCreateSampler(ID3D11Device *device,
samp.MinLOD = -FLT_MAX;
samp.MipLODBias = 0.0f;
#else
if (!key.mipEnable) {
samp.MaxLOD = 0.0f;
samp.MinLOD = 0.0f;
samp.MipLODBias = 0.0f;
} else if (key.lodAuto) {
// Auto selected mip + bias.
samp.MaxLOD = key.maxLevel;
samp.MinLOD = 0.0f;
samp.MipLODBias = (float)key.lodBias / 256.0f;
} else {
// Constant mip at bias.
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;
}
samp.MaxLOD = key.maxLevel / 256.0f;
samp.MinLOD = key.minLevel / 256.0f;
samp.MipLODBias = key.lodBias / 256.0f;
#endif
samp.ComparisonFunc = D3D11_COMPARISON_NEVER;
for (int i = 0; i < 4; i++) {
Expand Down Expand Up @@ -169,40 +157,14 @@ void TextureCacheD3D11::InvalidateLastTexture(TexCacheEntry *entry) {
}
}

void TextureCacheD3D11::UpdateSamplingParams(TexCacheEntry &entry, SamplerCacheKey &key) {
// TODO: Make GetSamplingParams write SamplerCacheKey directly
int minFilt;
int magFilt;
bool sClamp;
bool tClamp;
float lodBias;
bool 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;
key.magFilt = magFilt & 1;
key.sClamp = sClamp;
key.tClamp = tClamp;
// Don't clamp to maxLevel - this may bias magnify levels.
key.lodBias = (int)(lodBias * 256.0f);
key.maxLevel = maxLevel;
key.lodAuto = autoMip;

if (entry.framebuffer) {
WARN_LOG_REPORT_ONCE(wrongFramebufAttach, G3D, "Framebuffer still attached in UpdateSamplingParams()?");
}
}

void TextureCacheD3D11::SetFramebufferSamplingParams(u16 bufferWidth, u16 bufferHeight, SamplerCacheKey &key) {
int minFilt;
int magFilt;
bool sClamp;
bool tClamp;
float lodBias;
bool autoMip;
GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, 0, 0, autoMip);
GETexLevelMode mode;
GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, 0, 0, mode);

key.minFilt = minFilt & 1;
key.mipFilt = 0;
Expand Down Expand Up @@ -275,7 +237,7 @@ void TextureCacheD3D11::BindTexture(TexCacheEntry *entry) {
context_->PSSetShaderResources(0, 1, &textureView);
lastBoundTexture = textureView;
}
SamplerCacheKey key;
SamplerCacheKey key{};
UpdateSamplingParams(*entry, key);
ID3D11SamplerState *state = samplerCache_.GetOrCreateSampler(device_, key);
context_->PSSetSamplers(0, 1, &state);
Expand Down Expand Up @@ -455,7 +417,7 @@ void TextureCacheD3D11::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFra
gstate_c.SetTextureFullAlpha(gstate.getTextureFormat() == GE_TFMT_5650);
framebufferManagerD3D11_->RebindFramebuffer(); // Probably not necessary.
}
SamplerCacheKey samplerKey;
SamplerCacheKey samplerKey{};
SetFramebufferSamplingParams(framebuffer->bufferWidth, framebuffer->bufferHeight, samplerKey);
ID3D11SamplerState *state = samplerCache_.GetOrCreateSampler(device_, samplerKey);
context_->PSSetSamplers(0, 1, &state);
Expand Down
1 change: 0 additions & 1 deletion GPU/D3D11/TextureCacheD3D11.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ class TextureCacheD3D11 : public TextureCacheCommon {
void ReleaseTexture(TexCacheEntry *entry, bool delete_them) override;

private:
void UpdateSamplingParams(TexCacheEntry &entry, SamplerCacheKey &key);
void LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &replaced, int level, int maxLevel, bool replaceImages, int scaleFactor, DXGI_FORMAT dstFmt);
DXGI_FORMAT GetDestFormat(GETextureFormat format, GEPaletteFormat clutFormat) const;
TexCacheEntry::Status CheckAlpha(const u32 *pixelData, u32 dstFmt, int stride, int w, int h);
Expand Down
15 changes: 9 additions & 6 deletions GPU/Directx9/TextureCacheDX9.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -154,19 +154,22 @@ void TextureCacheDX9::UpdateSamplingParams(TexCacheEntry &entry, bool force) {
bool sClamp;
bool tClamp;
float lodBias;
bool autoMip;
GETexLevelMode mode;
u8 maxLevel = (entry.status & TexCacheEntry::STATUS_BAD_MIPS) ? 0 : entry.maxLevel;
GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, maxLevel, entry.addr, autoMip);
GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, maxLevel, entry.addr, mode);

if (maxLevel != 0) {
if (autoMip) {
if (mode == GE_TEXLEVEL_MODE_AUTO) {
dxstate.texMaxMipLevel.set(0);
dxstate.texMipLodBias.set(lodBias);
} else {
} else if (mode == GE_TEXLEVEL_MODE_CONST) {
// 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)maxLevel, (int)lodBias)));
dxstate.texMipLodBias.set(-1000.0f);
} else { // if (mode == GE_TEXLEVEL_MODE_SLOPE{
dxstate.texMaxMipLevel.set(0);
dxstate.texMipLodBias.set(0.0f);
}
entry.lodBias = lodBias;
} else {
Expand Down Expand Up @@ -195,8 +198,8 @@ void TextureCacheDX9::SetFramebufferSamplingParams(u16 bufferWidth, u16 bufferHe
bool sClamp;
bool tClamp;
float lodBias;
bool autoMip;
GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, 0, 0, autoMip);
GETexLevelMode mode;
GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, 0, 0, mode);

dxstate.texMinFilter.set(MinFilt[minFilt]);
dxstate.texMipFilter.set(MipFilt[minFilt]);
Expand Down
21 changes: 15 additions & 6 deletions GPU/GLES/TextureCacheGLES.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,24 +128,33 @@ void TextureCacheGLES::UpdateSamplingParams(TexCacheEntry &entry, bool force) {
bool sClamp;
bool tClamp;
float lodBias;
bool autoMip;
u8 maxLevel = (entry.status & TexCacheEntry::STATUS_BAD_MIPS) ? 0 : entry.maxLevel;
GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, maxLevel, entry.addr, autoMip);
GETexLevelMode mode;
GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, maxLevel, entry.addr, mode);

if (gstate_c.Supports(GPU_SUPPORTS_TEXTURE_LOD_CONTROL)) {
if (maxLevel != 0) {
// TODO: What about a swap of autoMip mode?
if (force || entry.lodBias != lodBias) {
if (autoMip) {
if (mode == GE_TEXLEVEL_MODE_AUTO) {
#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)maxLevel);
} else {
} else if (mode == GE_TEXLEVEL_MODE_CONST) {
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)));
} else { // mode == GE_TEXLEVEL_MODE_SLOPE) {
// It's incorrect to use the slope as a bias. Instead it should be passed
// into the shader directly as an explicit lod level, with the bias on top. For now, we just kill the
// lodBias in this mode, working around #9772.
#ifndef USING_GLES2
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, 0.0f);
#endif
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, (float)maxLevel);
}
entry.lodBias = lodBias;
}
Expand Down Expand Up @@ -185,8 +194,8 @@ void TextureCacheGLES::SetFramebufferSamplingParams(u16 bufferWidth, u16 bufferH
bool sClamp;
bool tClamp;
float lodBias;
bool autoMip;
GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, 0, 0, autoMip);
GETexLevelMode mode;
GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, 0, 0, mode);

minFilt &= 1; // framebuffers can't mipmap.

Expand Down
Loading

0 comments on commit 674d5c7

Please sign in to comment.