Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mipmaps: Disable slope mode pending a better method. Implementing it entirely as a LOD bias is not the way it works. #10130

Merged
merged 11 commits into from
Nov 20, 2017
Merged
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