mirror of
https://github.com/libretro/ppsspp.git
synced 2024-11-27 18:30:56 +00:00
Fix fake mipmap issue related #5350
This commit is contained in:
parent
cbf24a9d78
commit
945e603072
@ -90,7 +90,7 @@ void TextureCacheCommon::GetSamplingParams(int &minFilt, int &magFilt, bool &sCl
|
||||
sClamp = gstate.isTexCoordClampedS();
|
||||
tClamp = gstate.isTexCoordClampedT();
|
||||
|
||||
bool noMip = (gstate.texlevel & 0xFFFFFF) == 0x000001 || (gstate.texlevel & 0xFFFFFF) == 0x100001 ; // Fix texlevel at 0
|
||||
bool noMip = gstate.getTexLevelMode() == GE_TEXLEVEL_MODE_CONST;
|
||||
|
||||
if (maxLevel == 0) {
|
||||
// Enforce no mip filtering, for safety.
|
||||
|
@ -100,7 +100,7 @@ static const CommandTableEntry commandTable[] = {
|
||||
{ GE_CMD_TEXSIZE6, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
|
||||
{ GE_CMD_TEXSIZE7, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
|
||||
{ GE_CMD_TEXFORMAT, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_IMAGE },
|
||||
{ GE_CMD_TEXLEVEL, 0, DIRTY_TEXTURE_PARAMS }, // Flushing on this is EXPENSIVE in Gran Turismo and of little use
|
||||
{ GE_CMD_TEXLEVEL, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS }, // Allow flushing only (Mode == 1 && Level > 0)
|
||||
{ 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 },
|
||||
@ -662,7 +662,8 @@ void GPU_DX9::FastRunLoop(DisplayList &list) {
|
||||
const u8 cmdFlags = info.flags; // If we stashed the cmdFlags in the top bits of the cmdmem, we could get away with one table lookup instead of two
|
||||
const u32 diff = op ^ gstate.cmdmem[cmd];
|
||||
// Inlined CheckFlushOp here to get rid of the dumpThisFrame_ check.
|
||||
if ((cmdFlags & FLAG_FLUSHBEFORE) || (diff && (cmdFlags & FLAG_FLUSHBEFOREONCHANGE))) {
|
||||
if ((cmdFlags & FLAG_FLUSHBEFORE) || (diff && (cmdFlags & FLAG_FLUSHBEFOREONCHANGE)
|
||||
&& (cmd != 0xc8 || (gstate.getTexLevelMode() == GE_TEXLEVEL_MODE_CONST && (0x00FF0000 & gstate.texlevel) != 0)))) { // Avoid always flushing when texlevel(0xc8).
|
||||
drawEngine_.Flush();
|
||||
}
|
||||
gstate.cmdmem[cmd] = op; // TODO: no need to write if diff==0...
|
||||
@ -684,7 +685,8 @@ void GPU_DX9::FinishDeferred() {
|
||||
|
||||
inline void GPU_DX9::CheckFlushOp(int cmd, u32 diff) {
|
||||
const u8 cmdFlags = cmdInfo_[cmd].flags;
|
||||
if ((cmdFlags & FLAG_FLUSHBEFORE) || (diff && (cmdFlags & FLAG_FLUSHBEFOREONCHANGE))) {
|
||||
if ((cmdFlags & FLAG_FLUSHBEFORE) || (diff && (cmdFlags & FLAG_FLUSHBEFOREONCHANGE)
|
||||
&& (cmd != 0xc8 || (gstate.getTexLevelMode() == GE_TEXLEVEL_MODE_CONST && (0x00FF0000 & gstate.texlevel) != 0)))) { // Avoid always flushing when texlevel(0xc8).
|
||||
if (dumpThisFrame_) {
|
||||
NOTICE_LOG(G3D, "================ FLUSH ================");
|
||||
}
|
||||
|
@ -604,7 +604,10 @@ void TextureCacheDX9::SetTexture(bool force) {
|
||||
lastBoundTexture = INVALID_TEX;
|
||||
}
|
||||
|
||||
u32 texaddr = gstate.getTextureAddress(0);
|
||||
u8 level = 0;
|
||||
if (gstate.getTexLevelMode() == GE_TEXLEVEL_MODE_CONST)
|
||||
level = (gstate.texlevel >> 20) & 0xF;
|
||||
u32 texaddr = gstate.getTextureAddress(level);
|
||||
if (!Memory::IsValidAddress(texaddr)) {
|
||||
// Bind a null texture and return.
|
||||
pD3Ddevice->SetTexture(0, NULL);
|
||||
@ -612,9 +615,9 @@ void TextureCacheDX9::SetTexture(bool force) {
|
||||
return;
|
||||
}
|
||||
|
||||
const u16 dim = gstate.getTextureDimension(0);
|
||||
int w = gstate.getTextureWidth(0);
|
||||
int h = gstate.getTextureHeight(0);
|
||||
const u16 dim = gstate.getTextureDimension(level);
|
||||
int w = gstate.getTextureWidth(level);
|
||||
int h = gstate.getTextureHeight(level);
|
||||
|
||||
GETextureFormat format = gstate.getTextureFormat();
|
||||
if (format >= 11) {
|
||||
@ -1011,7 +1014,11 @@ void TextureCacheDX9::BuildTexture(TexCacheEntry *const entry, bool replaceImage
|
||||
maxLevel = 0;
|
||||
}
|
||||
|
||||
LoadTextureLevel(*entry, replaced, 0, maxLevel, replaceImages, scaleFactor, dstFmt);
|
||||
if (gstate.getTexLevelMode() == GE_TEXLEVEL_MODE_CONST) {
|
||||
u8 level = (gstate.texlevel >> 20) & 0xF;
|
||||
LoadTextureLevel(*entry, replaced, level, maxLevel, replaceImages, scaleFactor, dstFmt);
|
||||
} else
|
||||
LoadTextureLevel(*entry, replaced, 0, maxLevel, replaceImages, scaleFactor, dstFmt);
|
||||
LPDIRECT3DTEXTURE9 &texture = DxTex(entry);
|
||||
if (!texture) {
|
||||
return;
|
||||
@ -1095,7 +1102,7 @@ void TextureCacheDX9::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &re
|
||||
int h = gstate.getTextureHeight(level);
|
||||
|
||||
LPDIRECT3DTEXTURE9 &texture = DxTex(&entry);
|
||||
if (level == 0 && (!replaceImages || texture == nullptr)) {
|
||||
if ((level == 0 || gstate.getTexLevelMode() == GE_TEXLEVEL_MODE_CONST) && (!replaceImages || texture == nullptr)) {
|
||||
// Create texture
|
||||
D3DPOOL pool = D3DPOOL_MANAGED;
|
||||
int usage = 0;
|
||||
@ -1115,7 +1122,11 @@ void TextureCacheDX9::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &re
|
||||
tfmt = D3DFMT_A8R8G8B8;
|
||||
}
|
||||
}
|
||||
HRESULT hr = pD3Ddevice->CreateTexture(tw, th, levels, usage, tfmt, pool, &texture, NULL);
|
||||
HRESULT hr;
|
||||
if (gstate.getTexLevelMode() == GE_TEXLEVEL_MODE_CONST)
|
||||
hr = pD3Ddevice->CreateTexture(tw, th, 1, usage, tfmt, pool, &texture, NULL);
|
||||
else
|
||||
hr = pD3Ddevice->CreateTexture(tw, th, levels, usage, tfmt, pool, &texture, NULL);
|
||||
if (FAILED(hr)) {
|
||||
INFO_LOG(G3D, "Failed to create D3D texture");
|
||||
ReleaseTexture(&entry);
|
||||
@ -1124,7 +1135,10 @@ void TextureCacheDX9::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &re
|
||||
}
|
||||
|
||||
D3DLOCKED_RECT rect;
|
||||
texture->LockRect(level, &rect, NULL, 0);
|
||||
if (gstate.getTexLevelMode() == GE_TEXLEVEL_MODE_CONST)
|
||||
texture->LockRect(0, &rect, NULL, 0);
|
||||
else
|
||||
texture->LockRect(level, &rect, NULL, 0);
|
||||
|
||||
gpuStats.numTexturesDecoded++;
|
||||
if (replaced.GetSize(level, w, h)) {
|
||||
@ -1191,7 +1205,10 @@ void TextureCacheDX9::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &re
|
||||
}
|
||||
}
|
||||
|
||||
texture->UnlockRect(level);
|
||||
if (gstate.getTexLevelMode() == GE_TEXLEVEL_MODE_CONST)
|
||||
texture->UnlockRect(0);
|
||||
else
|
||||
texture->UnlockRect(level);
|
||||
}
|
||||
|
||||
bool TextureCacheDX9::DecodeTexture(u8 *output, const GPUgstate &state)
|
||||
|
@ -104,7 +104,7 @@ static const CommandTableEntry commandTable[] = {
|
||||
{GE_CMD_TEXSIZE6, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS},
|
||||
{GE_CMD_TEXSIZE7, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS},
|
||||
{GE_CMD_TEXFORMAT, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_IMAGE},
|
||||
{GE_CMD_TEXLEVEL, 0, DIRTY_TEXTURE_PARAMS}, // Flushing on this is EXPENSIVE in Gran Turismo and of little use
|
||||
{GE_CMD_TEXLEVEL, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS}, // Allow flushing only (Mode == 1 && Level > 0)
|
||||
{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},
|
||||
@ -876,7 +876,8 @@ void GPU_GLES::FastRunLoop(DisplayList &list) {
|
||||
const u8 cmdFlags = info.flags; // If we stashed the cmdFlags in the top bits of the cmdmem, we could get away with one table lookup instead of two
|
||||
const u32 diff = op ^ gstate.cmdmem[cmd];
|
||||
// Inlined CheckFlushOp here to get rid of the dumpThisFrame_ check.
|
||||
if ((cmdFlags & FLAG_FLUSHBEFORE) || (diff && (cmdFlags & FLAG_FLUSHBEFOREONCHANGE))) {
|
||||
if ((cmdFlags & FLAG_FLUSHBEFORE) || (diff && (cmdFlags & FLAG_FLUSHBEFOREONCHANGE)
|
||||
&& (cmd != 0xc8 || (gstate.getTexLevelMode() == GE_TEXLEVEL_MODE_CONST && (0x00FF0000 & gstate.texlevel) != 0)))) { // Avoid always flushing when texlevel(0xc8).
|
||||
drawEngine_.Flush();
|
||||
}
|
||||
gstate.cmdmem[cmd] = op; // TODO: no need to write if diff==0...
|
||||
@ -901,7 +902,8 @@ void GPU_GLES::FinishDeferred() {
|
||||
|
||||
inline void GPU_GLES::CheckFlushOp(int cmd, u32 diff) {
|
||||
const u8 cmdFlags = cmdInfo_[cmd].flags;
|
||||
if ((cmdFlags & FLAG_FLUSHBEFORE) || (diff && (cmdFlags & FLAG_FLUSHBEFOREONCHANGE))) {
|
||||
if ((cmdFlags & FLAG_FLUSHBEFORE) || (diff && (cmdFlags & FLAG_FLUSHBEFOREONCHANGE)
|
||||
&& (cmd != 0xc8 || (gstate.getTexLevelMode() == GE_TEXLEVEL_MODE_CONST && (0x00FF0000 & gstate.texlevel) != 0)))) { // Avoid always flushing when texlevel(0xc8).
|
||||
if (dumpThisFrame_) {
|
||||
NOTICE_LOG(G3D, "================ FLUSH ================");
|
||||
}
|
||||
|
@ -686,7 +686,10 @@ void TextureCacheGLES::SetTexture(bool force) {
|
||||
lastBoundTexture = INVALID_TEX;
|
||||
}
|
||||
|
||||
u32 texaddr = gstate.getTextureAddress(0);
|
||||
u8 level = 0;
|
||||
if (gstate.getTexLevelMode() == GE_TEXLEVEL_MODE_CONST)
|
||||
level = (gstate.texlevel >> 20) & 0xF;
|
||||
u32 texaddr = gstate.getTextureAddress(level);
|
||||
if (!Memory::IsValidAddress(texaddr)) {
|
||||
// Bind a null texture and return.
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
@ -694,9 +697,9 @@ void TextureCacheGLES::SetTexture(bool force) {
|
||||
return;
|
||||
}
|
||||
|
||||
const u16 dim = gstate.getTextureDimension(0);
|
||||
int w = gstate.getTextureWidth(0);
|
||||
int h = gstate.getTextureHeight(0);
|
||||
const u16 dim = gstate.getTextureDimension(level);
|
||||
int w = gstate.getTextureWidth(level);
|
||||
int h = gstate.getTextureHeight(level);
|
||||
|
||||
GETextureFormat format = gstate.getTextureFormat();
|
||||
if (format >= 11) {
|
||||
@ -1055,7 +1058,11 @@ void TextureCacheGLES::BuildTexture(TexCacheEntry *const entry, bool replaceImag
|
||||
// be as good quality as the game's own (might even be better in some cases though).
|
||||
|
||||
// Always load base level texture here
|
||||
LoadTextureLevel(*entry, replaced, 0, replaceImages, scaleFactor, dstFmt);
|
||||
if (gstate.getTexLevelMode() == GE_TEXLEVEL_MODE_CONST) {
|
||||
u8 level = (gstate.texlevel >> 20) & 0xF;
|
||||
LoadTextureLevel(*entry, replaced, level, replaceImages, scaleFactor, dstFmt);
|
||||
} else
|
||||
LoadTextureLevel(*entry, replaced, 0, replaceImages, scaleFactor, dstFmt);
|
||||
|
||||
// Mipmapping only enable when texture scaling disable
|
||||
if (maxLevel > 0 && scaleFactor == 1) {
|
||||
@ -1271,7 +1278,10 @@ void TextureCacheGLES::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &r
|
||||
glTexSubImage2D(GL_TEXTURE_2D, level, 0, 0, w, h, components2, dstFmt, pixelData);
|
||||
} else {
|
||||
PROFILE_THIS_SCOPE("loadtex");
|
||||
glTexImage2D(GL_TEXTURE_2D, level, components, w, h, 0, components2, dstFmt, pixelData);
|
||||
if (gstate.getTexLevelMode() == GE_TEXLEVEL_MODE_CONST)
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, components, w, h, 0, components2, dstFmt, pixelData);
|
||||
else
|
||||
glTexImage2D(GL_TEXTURE_2D, level, components, w, h, 0, components2, dstFmt, pixelData);
|
||||
if (!lowMemoryMode_) {
|
||||
GLenum err = glGetError();
|
||||
if (err == GL_OUT_OF_MEMORY) {
|
||||
|
@ -100,7 +100,7 @@ static const CommandTableEntry commandTable[] = {
|
||||
{ GE_CMD_TEXSIZE6, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
|
||||
{ GE_CMD_TEXSIZE7, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
|
||||
{ GE_CMD_TEXFORMAT, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_IMAGE },
|
||||
{ GE_CMD_TEXLEVEL, 0, DIRTY_TEXTURE_PARAMS }, // Flushing on this is EXPENSIVE in Gran Turismo and of little use
|
||||
{ GE_CMD_TEXLEVEL, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS }, // Allow flushing only (Mode == 1 && Level > 0)
|
||||
{ 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 },
|
||||
@ -710,7 +710,8 @@ void GPU_Vulkan::FastRunLoop(DisplayList &list) {
|
||||
const u8 cmdFlags = info.flags; // If we stashed the cmdFlags in the top bits of the cmdmem, we could get away with one table lookup instead of two
|
||||
const u32 diff = op ^ gstate.cmdmem[cmd];
|
||||
// Inlined CheckFlushOp here to get rid of the dumpThisFrame_ check.
|
||||
if ((cmdFlags & FLAG_FLUSHBEFORE) || (diff && (cmdFlags & FLAG_FLUSHBEFOREONCHANGE))) {
|
||||
if ((cmdFlags & FLAG_FLUSHBEFORE) || (diff && (cmdFlags & FLAG_FLUSHBEFOREONCHANGE)
|
||||
&& (cmd != 0xc8 || (gstate.getTexLevelMode() == GE_TEXLEVEL_MODE_CONST && (0x00FF0000 & gstate.texlevel) != 0)))) { // Avoid always flushing when texlevel(0xc8).
|
||||
drawEngine_.Flush(curCmd_);
|
||||
}
|
||||
gstate.cmdmem[cmd] = op; // TODO: no need to write if diff==0...
|
||||
@ -733,7 +734,8 @@ void GPU_Vulkan::FinishDeferred() {
|
||||
|
||||
inline void GPU_Vulkan::CheckFlushOp(int cmd, u32 diff) {
|
||||
const u8 cmdFlags = cmdInfo_[cmd].flags;
|
||||
if ((cmdFlags & FLAG_FLUSHBEFORE) || (diff && (cmdFlags & FLAG_FLUSHBEFOREONCHANGE))) {
|
||||
if ((cmdFlags & FLAG_FLUSHBEFORE) || (diff && (cmdFlags & FLAG_FLUSHBEFOREONCHANGE)
|
||||
&& (cmd != 0xc8 || (gstate.getTexLevelMode() == GE_TEXLEVEL_MODE_CONST && (0x00FF0000 & gstate.texlevel) != 0)))) { // Avoid always flushing when texlevel(0xc8).
|
||||
if (dumpThisFrame_) {
|
||||
NOTICE_LOG(G3D, "================ FLUSH ================");
|
||||
}
|
||||
|
@ -623,16 +623,19 @@ void TextureCacheVulkan::SetTexture() {
|
||||
}
|
||||
#endif
|
||||
|
||||
u32 texaddr = gstate.getTextureAddress(0);
|
||||
u8 level = 0;
|
||||
if (gstate.getTexLevelMode() == GE_TEXLEVEL_MODE_CONST)
|
||||
level = (gstate.texlevel >> 20) & 0xF;
|
||||
u32 texaddr = gstate.getTextureAddress(level);
|
||||
if (!Memory::IsValidAddress(texaddr)) {
|
||||
// Bind a null texture and return.
|
||||
lastBoundTexture = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
const u16 dim = gstate.getTextureDimension(0);
|
||||
int w = gstate.getTextureWidth(0);
|
||||
int h = gstate.getTextureHeight(0);
|
||||
const u16 dim = gstate.getTextureDimension(level);
|
||||
int w = gstate.getTextureWidth(level);
|
||||
int h = gstate.getTextureHeight(level);
|
||||
if (texaddr == 0x04000000 && w == 2 && h == 2) {
|
||||
// Nonsense bootup texture. Discard.
|
||||
}
|
||||
@ -1082,6 +1085,8 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry, VulkanPushBuff
|
||||
}
|
||||
|
||||
if (entry->vkTex) {
|
||||
u8 level = (gstate.texlevel >> 20) & 0xF;
|
||||
bool fakeMipmap = gstate.getTexLevelMode() == GE_TEXLEVEL_MODE_CONST && level > 0;
|
||||
// Upload the texture data.
|
||||
for (int i = 0; i <= maxLevel; i++) {
|
||||
int mipWidth = gstate.getTextureWidth(i) * scaleFactor;
|
||||
@ -1098,7 +1103,12 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry, VulkanPushBuff
|
||||
if (replaced.Valid()) {
|
||||
replaced.Load(i, data, stride);
|
||||
} else {
|
||||
LoadTextureLevel(*entry, (uint8_t *)data, stride, i, scaleFactor, dstFmt);
|
||||
if (fakeMipmap) {
|
||||
LoadTextureLevel(*entry, (uint8_t *)data, stride, level, scaleFactor, dstFmt);
|
||||
entry->vkTex->texture_->UploadMip(0, mipWidth, mipHeight, texBuf, bufferOffset, stride / bpp);
|
||||
break;
|
||||
} else
|
||||
LoadTextureLevel(*entry, (uint8_t *)data, stride, i, scaleFactor, dstFmt);
|
||||
if (replacer.Enabled()) {
|
||||
replacer.NotifyTextureDecoded(replacedInfo, data, stride, i, mipWidth, mipHeight);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user