From daa205990fa043092394931b85be6efdc37408df Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sun, 28 Jun 2015 19:08:28 -0400 Subject: Use emplace() instead of insert() where applicable for maps. --- Source/Core/VideoCommon/TextureCacheBase.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'Source/Core/VideoCommon/TextureCacheBase.cpp') diff --git a/Source/Core/VideoCommon/TextureCacheBase.cpp b/Source/Core/VideoCommon/TextureCacheBase.cpp index 0b0588cf6e..6baca12326 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/TextureCacheBase.cpp @@ -474,7 +474,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage) decoded_entry->is_efb_copy = false; g_texture_cache->ConvertTexture(decoded_entry, entry, &texMem[tlutaddr], (TlutFormat)tlutfmt); - textures_by_address.insert(TexCache::value_type((u64)address, decoded_entry)); + textures_by_address.emplace((u64)address, decoded_entry); return ReturnEntry(stage, decoded_entry); } @@ -560,11 +560,11 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage) TCacheEntryBase* entry = AllocateTexture(config); GFX_DEBUGGER_PAUSE_AT(NEXT_NEW_TEXTURE, true); - textures_by_address.insert(TexCache::value_type((u64)address, entry)); + textures_by_address.emplace((u64)address, entry); if (g_ActiveConfig.iSafeTextureCache_ColorSamples == 0 || std::max(texture_size, palette_size) <= (u32)g_ActiveConfig.iSafeTextureCache_ColorSamples * 8) { - entry->textures_by_hash_iter = textures_by_hash.insert(TexCache::value_type(full_hash, entry)); + entry->textures_by_hash_iter = textures_by_hash.emplace(full_hash, entry); } entry->SetGeneralParameters(address, texture_size, full_format); @@ -963,7 +963,7 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat count++), 0); } - textures_by_address.insert(TexCache::value_type((u64)dstAddr, entry)); + textures_by_address.emplace((u64)dstAddr, entry); } TextureCache::TCacheEntryBase* TextureCache::AllocateTexture(const TCacheEntryConfig& config) @@ -996,7 +996,7 @@ TextureCache::TexCache::iterator TextureCache::FreeTexture(TexCache::iterator it } entry->frameCount = FRAMECOUNT_INVALID; - texture_pool.insert(TexPool::value_type(entry->config, entry)); + texture_pool.emplace(entry->config, entry); return textures_by_address.erase(iter); } -- cgit v1.2.3 From d8cd2c3252ab6f2ce6c1656b5eb194863e834f52 Mon Sep 17 00:00:00 2001 From: Rodolfo Bogado Date: Mon, 29 Jun 2015 22:19:19 -0300 Subject: Implement scaled partial texture updates --- Source/Core/VideoCommon/TextureCacheBase.cpp | 100 ++++++++++++++++++++------- 1 file changed, 76 insertions(+), 24 deletions(-) (limited to 'Source/Core/VideoCommon/TextureCacheBase.cpp') diff --git a/Source/Core/VideoCommon/TextureCacheBase.cpp b/Source/Core/VideoCommon/TextureCacheBase.cpp index 6baca12326..7d49e698da 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/TextureCacheBase.cpp @@ -211,46 +211,98 @@ bool TextureCache::TCacheEntryBase::OverlapsMemoryRange(u32 range_address, u32 r return true; } -void TextureCache::TCacheEntryBase::DoPartialTextureUpdates() +TextureCache::TCacheEntryBase* TextureCache::DoPartialTextureUpdates(TexCache::iterator iter_t) { - const bool isPaletteTexture = (format== GX_TF_C4 || format == GX_TF_C8 || format == GX_TF_C14X2 || format >= 0x10000); + TCacheEntryBase* entry_to_update = iter_t->second; + const bool isPaletteTexture = (entry_to_update->format == GX_TF_C4 + || entry_to_update->format == GX_TF_C8 + || entry_to_update->format == GX_TF_C14X2 + || entry_to_update->format >= 0x10000); // Efb copies and paletted textures are excluded from these updates, until there's an example where a game would // benefit from this. Both would require more work to be done. // TODO: Implement upscaling support for normal textures, and then remove the efb to ram and the scaled efb restrictions - if (!g_ActiveConfig.backend_info.bSupportsCopySubImage || !g_ActiveConfig.bSkipEFBCopyToRam || IsEfbCopy() - || isPaletteTexture || (g_ActiveConfig.bCopyEFBScaled && g_ActiveConfig.iEFBScale != SCALE_1X)) - return; - - u32 block_width = TexDecoder_GetBlockWidthInTexels(format); - u32 block_height = TexDecoder_GetBlockHeightInTexels(format); - u32 block_size = block_width * block_height * TexDecoder_GetTexelSizeInNibbles(format) / 2; + if (entry_to_update->IsEfbCopy() + || isPaletteTexture) + return entry_to_update; - u32 numBlocksX = (native_width + block_width - 1) / block_width; + u32 block_width = TexDecoder_GetBlockWidthInTexels(entry_to_update->format); + u32 block_height = TexDecoder_GetBlockHeightInTexels(entry_to_update->format); + u32 block_size = block_width * block_height * TexDecoder_GetTexelSizeInNibbles(entry_to_update->format) / 2; - TexCache::iterator iter = textures_by_address.lower_bound(addr); - TexCache::iterator iterend = textures_by_address.upper_bound(addr + size_in_bytes); + u32 numBlocksX = (entry_to_update->native_width + block_width - 1) / block_width; + TexCache::iterator iter = textures_by_address.lower_bound(entry_to_update->addr); + TexCache::iterator iterend = textures_by_address.upper_bound(entry_to_update->addr + entry_to_update->size_in_bytes); + bool entry_need_scaling = true; while (iter != iterend) { TCacheEntryBase* entry = iter->second; - if (entry->IsEfbCopy() && addr <= entry->addr && entry->addr + entry->size_in_bytes <= addr + size_in_bytes - && entry->frameCount == FRAMECOUNT_INVALID && entry->copyMipMapStrideChannels * 32 == numBlocksX * block_size) + if (entry != entry_to_update + && entry->IsEfbCopy() + && entry_to_update->addr <= entry->addr + && entry->addr + entry->size_in_bytes <= entry_to_update->addr + entry_to_update->size_in_bytes + && entry->frameCount == FRAMECOUNT_INVALID + && entry->copyMipMapStrideChannels * 32 == numBlocksX * block_size) { - u32 block_offset = (entry->addr - addr) / block_size; + u32 block_offset = (entry->addr - entry_to_update->addr) / block_size; u32 block_x = block_offset % numBlocksX; u32 block_y = block_offset / numBlocksX; u32 x = block_x * block_width; u32 y = block_y * block_height; - - DoPartialTextureUpdate(entry, x, y); - + MathUtil::Rectangle srcrect, dstrect; + srcrect.left = 0; + srcrect.top = 0; + dstrect.left = 0; + dstrect.top = 0; + if (entry_need_scaling) + { + entry_need_scaling = false; + u32 w = entry_to_update->native_width * entry->config.width / entry->native_width; + u32 h = entry_to_update->native_height * entry->config.height / entry->native_height; + u32 max = g_renderer->GetMaxTextureSize(); + if (max < w || max < h) + { + iter++; + continue; + } + if (entry_to_update->config.width != w || entry_to_update->config.height != h) + { + TextureCache::TCacheEntryConfig newconfig; + newconfig.width = w; + newconfig.height = h; + newconfig.rendertarget = true; + TCacheEntryBase* newentry = AllocateTexture(newconfig); + newentry->SetGeneralParameters(entry_to_update->addr, entry_to_update->size_in_bytes, entry_to_update->format); + newentry->SetDimensions(entry_to_update->native_width, entry_to_update->native_height, 1); + newentry->SetHashes(entry_to_update->hash); + newentry->frameCount = frameCount; + newentry->is_efb_copy = false; + srcrect.right = entry_to_update->config.width; + srcrect.bottom = entry_to_update->config.height; + dstrect.right = w; + dstrect.bottom = h; + newentry->CopyRectangleFromTexture(entry_to_update, srcrect, dstrect); + entry_to_update = newentry; + u64 key = iter_t->first; + iter_t = FreeTexture(iter_t); + textures_by_address.emplace(key, entry_to_update); + } + } + srcrect.right = entry->config.width; + srcrect.bottom = entry->config.height; + dstrect.left = x * entry_to_update->config.width / entry_to_update->native_width; + dstrect.top = y * entry_to_update->config.height / entry_to_update->native_height; + dstrect.right = (x + entry->native_width) * entry_to_update->config.width / entry_to_update->native_width; + dstrect.bottom = (y + entry->native_height) * entry_to_update->config.height / entry_to_update->native_height; + entry_to_update->CopyRectangleFromTexture(entry, srcrect, dstrect); // Mark the texture update as used, so it isn't applied more than once entry->frameCount = frameCount; } ++iter; } + return entry_to_update; } void TextureCache::DumpTexture(TCacheEntryBase* entry, std::string basename, unsigned int level) @@ -323,7 +375,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage) const unsigned int bsw = TexDecoder_GetBlockWidthInTexels(texformat) - 1; const unsigned int bsh = TexDecoder_GetBlockHeightInTexels(texformat) - 1; - unsigned int expandedWidth = (width + bsw) & (~bsw); + unsigned int expandedWidth = (width + bsw) & (~bsw); unsigned int expandedHeight = (height + bsh) & (~bsh); const unsigned int nativeW = width; const unsigned int nativeH = height; @@ -440,7 +492,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage) if (entry->hash == full_hash && entry->format == full_format && entry->native_levels >= tex_levels && entry->native_width == nativeW && entry->native_height == nativeH) { - entry->DoPartialTextureUpdates(); + entry = DoPartialTextureUpdates(iter); return ReturnEntry(stage, entry); } @@ -494,7 +546,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage) if (entry->format == full_format && entry->native_levels >= tex_levels && entry->native_width == nativeW && entry->native_height == nativeH) { - entry->DoPartialTextureUpdates(); + entry = DoPartialTextureUpdates(iter); return ReturnEntry(stage, entry); } @@ -539,7 +591,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage) if (!(texformat == GX_TF_RGBA8 && from_tmem)) { const u8* tlut = &texMem[tlutaddr]; - TexDecoder_Decode(temp, src_data, expandedWidth, expandedHeight, texformat, tlut, (TlutFormat) tlutfmt); + TexDecoder_Decode(temp, src_data, expandedWidth, expandedHeight, texformat, tlut, (TlutFormat)tlutfmt); } else { @@ -560,7 +612,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage) TCacheEntryBase* entry = AllocateTexture(config); GFX_DEBUGGER_PAUSE_AT(NEXT_NEW_TEXTURE, true); - textures_by_address.emplace((u64)address, entry); + iter = textures_by_address.emplace((u64)address, entry); if (g_ActiveConfig.iSafeTextureCache_ColorSamples == 0 || std::max(texture_size, palette_size) <= (u32)g_ActiveConfig.iSafeTextureCache_ColorSamples * 8) { @@ -636,7 +688,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage) INCSTAT(stats.numTexturesUploaded); SETSTAT(stats.numTexturesAlive, textures_by_address.size()); - entry->DoPartialTextureUpdates(); + entry = DoPartialTextureUpdates(iter); return ReturnEntry(stage, entry); } -- cgit v1.2.3 From 52948bb3ef016abd7e35e775b17b7cf3f487d49c Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Tue, 1 Sep 2015 02:41:16 +1200 Subject: Cleanup and unify handling of efb copy stride. --- Source/Core/VideoCommon/TextureCacheBase.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'Source/Core/VideoCommon/TextureCacheBase.cpp') diff --git a/Source/Core/VideoCommon/TextureCacheBase.cpp b/Source/Core/VideoCommon/TextureCacheBase.cpp index 7d49e698da..5ab1b47bc4 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/TextureCacheBase.cpp @@ -243,7 +243,7 @@ TextureCache::TCacheEntryBase* TextureCache::DoPartialTextureUpdates(TexCache::i && entry_to_update->addr <= entry->addr && entry->addr + entry->size_in_bytes <= entry_to_update->addr + entry_to_update->size_in_bytes && entry->frameCount == FRAMECOUNT_INVALID - && entry->copyMipMapStrideChannels * 32 == numBlocksX * block_size) + && entry->copyStride == numBlocksX * block_size) { u32 block_offset = (entry->addr - entry_to_update->addr) / block_size; u32 block_x = block_offset % numBlocksX; @@ -693,7 +693,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage) return ReturnEntry(stage, entry); } -void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat, PEControl::PixelFormat srcFormat, +void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat, u32 dstStride, PEControl::PixelFormat srcFormat, const EFBRectangle& srcRect, bool isIntensity, bool scaleByHalf) { // Emulation methods: @@ -1004,9 +1004,9 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat entry->frameCount = FRAMECOUNT_INVALID; entry->is_efb_copy = true; entry->is_custom_tex = false; - entry->copyMipMapStrideChannels = bpmem.copyMipMapStrideChannels; + entry->copyStride = dstStride; - entry->FromRenderTarget(dstAddr, dstFormat, srcFormat, srcRect, isIntensity, scaleByHalf, cbufid, colmat); + entry->FromRenderTarget(dstAddr, dstFormat, dstStride, srcFormat, srcRect, isIntensity, scaleByHalf, cbufid, colmat); if (g_ActiveConfig.bDumpEFBTarget) { -- cgit v1.2.3 From b9be3245e1bcd3929baf4d1c66fe5a14b336cdbc Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Sat, 5 Sep 2015 02:45:29 +1200 Subject: Move common EFB copy code into VideoCommon Addded a few duplicated depth copy texture formats to the enum in TextureDecoder.h. These texture formats were already implemented in TextureCacheBase and the ogl/dx11 texture cache implementations. --- Source/Core/VideoCommon/TextureCacheBase.cpp | 106 +++++++++++++++++++++------ 1 file changed, 82 insertions(+), 24 deletions(-) (limited to 'Source/Core/VideoCommon/TextureCacheBase.cpp') diff --git a/Source/Core/VideoCommon/TextureCacheBase.cpp b/Source/Core/VideoCommon/TextureCacheBase.cpp index 5ab1b47bc4..62bf511863 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/TextureCacheBase.cpp @@ -182,24 +182,6 @@ void TextureCache::Cleanup(int _frameCount) } } -void TextureCache::MakeRangeDynamic(u32 start_address, u32 size) -{ - TexCache::iterator - iter = textures_by_address.begin(); - - while (iter != textures_by_address.end()) - { - if (iter->second->OverlapsMemoryRange(start_address, size)) - { - iter = FreeTexture(iter); - } - else - { - ++iter; - } - } -} - bool TextureCache::TCacheEntryBase::OverlapsMemoryRange(u32 range_address, u32 range_size) const { if (addr + size_in_bytes <= range_address) @@ -243,7 +225,7 @@ TextureCache::TCacheEntryBase* TextureCache::DoPartialTextureUpdates(TexCache::i && entry_to_update->addr <= entry->addr && entry->addr + entry->size_in_bytes <= entry_to_update->addr + entry_to_update->size_in_bytes && entry->frameCount == FRAMECOUNT_INVALID - && entry->copyStride == numBlocksX * block_size) + && entry->memory_stride == numBlocksX * block_size) { u32 block_offset = (entry->addr - entry_to_update->addr) / block_size; u32 block_x = block_offset % numBlocksX; @@ -753,9 +735,11 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat case 0: // Z4 colmat[3] = colmat[7] = colmat[11] = colmat[15] = 1.0f; cbufid = 0; + dstFormat |= _GX_TF_CTF; break; + case 8: // Z8H + dstFormat |= _GX_TF_CTF; case 1: // Z8 - case 8: // Z8 colmat[0] = colmat[4] = colmat[8] = colmat[12] = 1.0f; cbufid = 1; break; @@ -768,6 +752,7 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat case 11: // Z16 (reverse order) colmat[0] = colmat[4] = colmat[8] = colmat[13] = 1.0f; cbufid = 3; + dstFormat |= _GX_TF_CTF; break; case 6: // Z24X8 @@ -778,11 +763,13 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat case 9: // Z8M colmat[1] = colmat[5] = colmat[9] = colmat[13] = 1.0f; cbufid = 5; + dstFormat |= _GX_TF_CTF; break; case 10: // Z8L colmat[2] = colmat[6] = colmat[10] = colmat[14] = 1.0f; cbufid = 6; + dstFormat |= _GX_TF_CTF; break; case 12: // Z16L - copy lower 16 depth bits @@ -790,6 +777,7 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat // Used e.g. in Zelda: Skyward Sword colmat[1] = colmat[5] = colmat[9] = colmat[14] = 1.0f; cbufid = 7; + dstFormat |= _GX_TF_CTF; break; default: @@ -798,6 +786,8 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat cbufid = 8; break; } + + dstFormat |= _GX_TF_ZTF; } else if (isIntensity) { @@ -862,11 +852,13 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat ColorMask[0] = 15.0f; ColorMask[4] = 1.0f / 15.0f; cbufid = 14; + dstFormat |= _GX_TF_CTF; break; case 1: // R8 case 8: // R8 colmat[0] = colmat[4] = colmat[8] = colmat[12] = 1; cbufid = 15; + dstFormat |= _GX_TF_CTF; break; case 2: // RA4 @@ -881,6 +873,7 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat fConstAdd[3] = 1.0f; cbufid = 17; } + dstFormat |= _GX_TF_CTF; break; case 3: // RA8 colmat[0] = colmat[4] = colmat[8] = colmat[15] = 1.0f; @@ -892,6 +885,7 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat fConstAdd[3] = 1.0f; cbufid = 19; } + dstFormat |= _GX_TF_CTF; break; case 7: // A8 @@ -907,25 +901,30 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat fConstAdd[3] = 1.0f; cbufid = 21; } + dstFormat |= _GX_TF_CTF; break; case 9: // G8 colmat[1] = colmat[5] = colmat[9] = colmat[13] = 1.0f; cbufid = 22; + dstFormat |= _GX_TF_CTF; break; case 10: // B8 colmat[2] = colmat[6] = colmat[10] = colmat[14] = 1.0f; cbufid = 23; + dstFormat |= _GX_TF_CTF; break; case 11: // RG8 colmat[0] = colmat[4] = colmat[8] = colmat[13] = 1.0f; cbufid = 24; + dstFormat |= _GX_TF_CTF; break; case 12: // GB8 colmat[1] = colmat[5] = colmat[9] = colmat[14] = 1.0f; cbufid = 25; + dstFormat |= _GX_TF_CTF; break; case 4: // RGB565 @@ -973,6 +972,13 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat } } + u8* dst = Memory::GetPointer(dstAddr); + if (dst == nullptr) + { + ERROR_LOG(VIDEO, "Trying to copy from EFB to invalid address 0x%8x", dstAddr); + return; + } + const unsigned int tex_w = scaleByHalf ? srcRect.GetWidth() / 2 : srcRect.GetWidth(); const unsigned int tex_h = scaleByHalf ? srcRect.GetHeight() / 2 : srcRect.GetHeight(); @@ -996,17 +1002,36 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat TCacheEntryBase* entry = AllocateTexture(config); - // TODO: Using the wrong dstFormat, dumb... entry->SetGeneralParameters(dstAddr, 0, dstFormat); entry->SetDimensions(tex_w, tex_h, 1); entry->SetHashes(TEXHASH_INVALID); entry->frameCount = FRAMECOUNT_INVALID; - entry->is_efb_copy = true; + entry->SetEfbCopy(dstStride); entry->is_custom_tex = false; - entry->copyStride = dstStride; - entry->FromRenderTarget(dstAddr, dstFormat, dstStride, srcFormat, srcRect, isIntensity, scaleByHalf, cbufid, colmat); + entry->FromRenderTarget(dst, dstFormat, dstStride, srcFormat, srcRect, isIntensity, scaleByHalf, cbufid, colmat); + + if (!g_ActiveConfig.bSkipEFBCopyToRam) + { + entry->hash = GetHash64(dst, (int)entry->size_in_bytes, g_ActiveConfig.iSafeTextureCache_ColorSamples); + + // Invalidate all textures that overlap the range of our texture + TexCache::iterator + iter = textures_by_address.begin(); + + while (iter != textures_by_address.end()) + { + if (iter->second->OverlapsMemoryRange(dstAddr, entry->size_in_bytes)) + { + iter = FreeTexture(iter); + } + else + { + ++iter; + } + } + } if (g_ActiveConfig.bDumpEFBTarget) { @@ -1052,3 +1077,36 @@ TextureCache::TexCache::iterator TextureCache::FreeTexture(TexCache::iterator it return textures_by_address.erase(iter); } + +u32 TextureCache::TCacheEntryBase::CacheLinesPerRow() const +{ + u32 blockW = TexDecoder_GetBlockWidthInTexels(format) - 1; + // Round up source height to multiple of block size + u32 actualWidth = (native_width + blockW) & ~(blockW); + + u32 numBlocksX = actualWidth / TexDecoder_GetBlockWidthInTexels(format); + + // RGBA takes two cache lines per block; all others take one + if (format == GX_TF_RGBA8) + numBlocksX = numBlocksX * 2; + return numBlocksX; +} + +u32 TextureCache::TCacheEntryBase::NumBlocksY() const +{ + u32 blockH = TexDecoder_GetBlockHeightInTexels(format) - 1; + // Round up source height to multiple of block size + u32 actualHeight = (native_height + blockH) & ~(blockH); + + return actualHeight / TexDecoder_GetBlockHeightInTexels(format); +} + +void TextureCache::TCacheEntryBase::SetEfbCopy(u32 stride) +{ + is_efb_copy = true; + memory_stride = stride; + + _assert_msg_(VIDEO, memory_stride >= CacheLinesPerRow(), "Memory stride is too small"); + + size_in_bytes = memory_stride * NumBlocksY(); +} -- cgit v1.2.3 From d797b5d0b55e6354af6ba66942b9a6766087e5f9 Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Sun, 6 Sep 2015 22:07:32 +1200 Subject: Use ROUND_UP instead of custom bittwiddling. --- Source/Core/VideoCommon/TextureCacheBase.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'Source/Core/VideoCommon/TextureCacheBase.cpp') diff --git a/Source/Core/VideoCommon/TextureCacheBase.cpp b/Source/Core/VideoCommon/TextureCacheBase.cpp index 62bf511863..9dcd960037 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/TextureCacheBase.cpp @@ -354,11 +354,11 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage) return nullptr; // TexelSizeInNibbles(format) * width * height / 16; - const unsigned int bsw = TexDecoder_GetBlockWidthInTexels(texformat) - 1; - const unsigned int bsh = TexDecoder_GetBlockHeightInTexels(texformat) - 1; + const unsigned int bsw = TexDecoder_GetBlockWidthInTexels(texformat); + const unsigned int bsh = TexDecoder_GetBlockHeightInTexels(texformat); - unsigned int expandedWidth = (width + bsw) & (~bsw); - unsigned int expandedHeight = (height + bsh) & (~bsh); + unsigned int expandedWidth = ROUND_UP(width, bsw); + unsigned int expandedHeight = ROUND_UP(height, bsh); const unsigned int nativeW = width; const unsigned int nativeH = height; @@ -650,8 +650,8 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage) { const u32 mip_width = CalculateLevelSize(width, level); const u32 mip_height = CalculateLevelSize(height, level); - const u32 expanded_mip_width = (mip_width + bsw) & (~bsw); - const u32 expanded_mip_height = (mip_height + bsh) & (~bsh); + const u32 expanded_mip_width = ROUND_UP(mip_width, bsw); + const u32 expanded_mip_height = ROUND_UP(mip_height, bsh); const u8*& mip_src_data = from_tmem ? ((level % 2) ? ptr_odd : ptr_even) @@ -1080,11 +1080,11 @@ TextureCache::TexCache::iterator TextureCache::FreeTexture(TexCache::iterator it u32 TextureCache::TCacheEntryBase::CacheLinesPerRow() const { - u32 blockW = TexDecoder_GetBlockWidthInTexels(format) - 1; + u32 blockW = TexDecoder_GetBlockWidthInTexels(format); // Round up source height to multiple of block size - u32 actualWidth = (native_width + blockW) & ~(blockW); + u32 actualWidth = ROUND_UP(native_width, blockW); - u32 numBlocksX = actualWidth / TexDecoder_GetBlockWidthInTexels(format); + u32 numBlocksX = actualWidth / blockW; // RGBA takes two cache lines per block; all others take one if (format == GX_TF_RGBA8) @@ -1094,11 +1094,11 @@ u32 TextureCache::TCacheEntryBase::CacheLinesPerRow() const u32 TextureCache::TCacheEntryBase::NumBlocksY() const { - u32 blockH = TexDecoder_GetBlockHeightInTexels(format) - 1; + u32 blockH = TexDecoder_GetBlockHeightInTexels(format); // Round up source height to multiple of block size - u32 actualHeight = (native_height + blockH) & ~(blockH); + u32 actualHeight = ROUND_UP(native_height, blockH); - return actualHeight / TexDecoder_GetBlockHeightInTexels(format); + return actualHeight / blockH; } void TextureCache::TCacheEntryBase::SetEfbCopy(u32 stride) -- cgit v1.2.3 From ee649c6d9f38510b2acad42dcce894400a8b4d4b Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Sun, 6 Sep 2015 02:03:49 +1200 Subject: Make efb2tex behave more like efb2ram. Instead of having special case code for efb2tex that ignores hashes, the only diffence between efb2tex and efb2ram now is that efb2tex writes zeros to the memory instead of actual texture data. Though keep in mind, all efb2tex copies will have hashes of zero as their hash. --- Source/Core/VideoCommon/TextureCacheBase.cpp | 43 +++++++++++++++------------- 1 file changed, 23 insertions(+), 20 deletions(-) (limited to 'Source/Core/VideoCommon/TextureCacheBase.cpp') diff --git a/Source/Core/VideoCommon/TextureCacheBase.cpp b/Source/Core/VideoCommon/TextureCacheBase.cpp index 9dcd960037..21b2e792bd 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/TextureCacheBase.cpp @@ -439,11 +439,9 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage) TCacheEntryBase* entry = iter->second; if (entry->IsEfbCopy()) { - // EFB copies have slightly different rules: the hash doesn't need to match - // in EFB2Tex mode, and EFB copy formats have different meanings from texture - // formats. - if (g_ActiveConfig.bSkipEFBCopyToRam || - (tex_hash == entry->hash && (!isPaletteTexture || g_Config.backend_info.bSupportsPaletteConversion))) + // EFB copies have slightly different rules as EFB copy formats have different + // meanings from texture formats. + if (tex_hash == entry->hash && (!isPaletteTexture || g_Config.backend_info.bSupportsPaletteConversion)) { // TODO: We should check format/width/height/levels for EFB copies. Checking // format is complicated because EFB copy formats don't exactly match @@ -986,11 +984,13 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat unsigned int scaled_tex_h = g_ActiveConfig.bCopyEFBScaled ? Renderer::EFBToScaledY(tex_h) : tex_h; // remove all texture cache entries at dstAddr - std::pair iter_range = textures_by_address.equal_range((u64)dstAddr); - TexCache::iterator iter = iter_range.first; - while (iter != iter_range.second) { - iter = FreeTexture(iter); + std::pair iter_range = textures_by_address.equal_range((u64)dstAddr); + TexCache::iterator iter = iter_range.first; + while (iter != iter_range.second) + { + iter = FreeTexture(iter); + } } // create the texture @@ -1012,24 +1012,17 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat entry->FromRenderTarget(dst, dstFormat, dstStride, srcFormat, srcRect, isIntensity, scaleByHalf, cbufid, colmat); - if (!g_ActiveConfig.bSkipEFBCopyToRam) - { - entry->hash = GetHash64(dst, (int)entry->size_in_bytes, g_ActiveConfig.iSafeTextureCache_ColorSamples); - - // Invalidate all textures that overlap the range of our texture - TexCache::iterator - iter = textures_by_address.begin(); + entry->hash = GetHash64(dst, (int)entry->size_in_bytes, g_ActiveConfig.iSafeTextureCache_ColorSamples); + // Invalidate all textures that overlap the range of our texture + { + TexCache::iterator iter = textures_by_address.begin(); while (iter != textures_by_address.end()) { if (iter->second->OverlapsMemoryRange(dstAddr, entry->size_in_bytes)) - { iter = FreeTexture(iter); - } else - { ++iter; - } } } @@ -1110,3 +1103,13 @@ void TextureCache::TCacheEntryBase::SetEfbCopy(u32 stride) size_in_bytes = memory_stride * NumBlocksY(); } + +// Fill gamecube memory backing this texture with zeros. +void TextureCache::TCacheEntryBase::Zero(u8* ptr) +{ + for (u32 i = 0; i < NumBlocksY(); i++) + { + memset(ptr, 0, CacheLinesPerRow() * 32); + ptr += memory_stride; + } +} -- cgit v1.2.3 From bda964e0b97deef869260a0f12681c38f9528a68 Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Sun, 6 Sep 2015 03:13:44 +1200 Subject: Workaround to allow partial texture updates to keep working in NSMBWii --- Source/Core/VideoCommon/TextureCacheBase.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'Source/Core/VideoCommon/TextureCacheBase.cpp') diff --git a/Source/Core/VideoCommon/TextureCacheBase.cpp b/Source/Core/VideoCommon/TextureCacheBase.cpp index 21b2e792bd..8626749283 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/TextureCacheBase.cpp @@ -1014,7 +1014,10 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat entry->hash = GetHash64(dst, (int)entry->size_in_bytes, g_ActiveConfig.iSafeTextureCache_ColorSamples); - // Invalidate all textures that overlap the range of our texture + // Invalidate all textures that overlap the range of our efb copy. + // Unless our efb copy has a weird stride, then we want avoid invalidating textures which + // we might be able to do a partial texture update on. + if (entry->memory_stride == entry->CacheLinesPerRow() * 32) { TexCache::iterator iter = textures_by_address.begin(); while (iter != textures_by_address.end()) -- cgit v1.2.3 From 8ce04f9a65612b7553015428e617ba7c53913175 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sat, 5 Sep 2015 11:44:21 -0400 Subject: General: Replace GC_ALIGN macros with alignas Standard supported alignment -> out with compiler-specific. --- Source/Core/VideoCommon/TextureCacheBase.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Source/Core/VideoCommon/TextureCacheBase.cpp') diff --git a/Source/Core/VideoCommon/TextureCacheBase.cpp b/Source/Core/VideoCommon/TextureCacheBase.cpp index 9dcd960037..430004b640 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/TextureCacheBase.cpp @@ -25,9 +25,9 @@ static const int TEXTURE_KILL_THRESHOLD = 60; static const int TEXTURE_POOL_KILL_THRESHOLD = 3; static const int FRAMECOUNT_INVALID = 0; -TextureCache *g_texture_cache; +TextureCache* g_texture_cache; -GC_ALIGNED16(u8 *TextureCache::temp) = nullptr; +alignas(16) u8* TextureCache::temp = nullptr; size_t TextureCache::temp_size; TextureCache::TexCache TextureCache::textures_by_address; -- cgit v1.2.3 From ac467d9fb9fba8580246394ddf289c1ccb2312d6 Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Mon, 7 Sep 2015 02:31:32 +1200 Subject: FifoPlayer: Don't check efb copy hashes when plaing back a broken dff --- Source/Core/VideoCommon/TextureCacheBase.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'Source/Core/VideoCommon/TextureCacheBase.cpp') diff --git a/Source/Core/VideoCommon/TextureCacheBase.cpp b/Source/Core/VideoCommon/TextureCacheBase.cpp index 8626749283..0107b3e57d 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/TextureCacheBase.cpp @@ -10,6 +10,7 @@ #include "Common/StringUtil.h" #include "Core/ConfigManager.h" +#include "Core/FifoPlayer/FifoPlayer.h" #include "Core/HW/Memmap.h" #include "VideoCommon/Debugger.h" @@ -441,7 +442,8 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage) { // EFB copies have slightly different rules as EFB copy formats have different // meanings from texture formats. - if (tex_hash == entry->hash && (!isPaletteTexture || g_Config.backend_info.bSupportsPaletteConversion)) + if ((tex_hash == entry->hash && (!isPaletteTexture || g_Config.backend_info.bSupportsPaletteConversion)) || + IsPlayingBackFifologWithBrokenEFBCopies) { // TODO: We should check format/width/height/levels for EFB copies. Checking // format is complicated because EFB copy formats don't exactly match -- cgit v1.2.3 From 38f6cf208934c7415c16f69a26bf85b201c447ba Mon Sep 17 00:00:00 2001 From: mimimi085181 Date: Mon, 7 Sep 2015 20:53:38 +0200 Subject: Perform garbage collection for efb copies This checks every TEXTURE_KILL_THRESHOLD frames, to see if the hash for the memory area of the efb copy has hanged. If it has changed, the efb copy can be removed, it wouldn't be used anymore. Before this pr, some efb copies would never be deleted. Fixes issue https://bugs.dolphin-emu.org/issues/6101 and possibly some other VRAM leaks. --- Source/Core/VideoCommon/TextureCacheBase.cpp | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) (limited to 'Source/Core/VideoCommon/TextureCacheBase.cpp') diff --git a/Source/Core/VideoCommon/TextureCacheBase.cpp b/Source/Core/VideoCommon/TextureCacheBase.cpp index 0107b3e57d..85a1726817 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/TextureCacheBase.cpp @@ -150,12 +150,28 @@ void TextureCache::Cleanup(int _frameCount) if (iter->second->frameCount == FRAMECOUNT_INVALID) { iter->second->frameCount = _frameCount; + ++iter; } - if (_frameCount > TEXTURE_KILL_THRESHOLD + iter->second->frameCount && - // EFB copies living on the host GPU are unrecoverable and thus shouldn't be deleted - !iter->second->IsEfbCopy()) + else if (_frameCount > TEXTURE_KILL_THRESHOLD + iter->second->frameCount) { - iter = FreeTexture(iter); + if (iter->second->IsEfbCopy()) + { + // Only remove EFB copies when they wouldn't be used anymore(changed hash), because EFB copies living on the + // host GPU are unrecoverable. Perform this check only every TEXTURE_KILL_THRESHOLD for performance reasons + if ((_frameCount - iter->second->frameCount) % TEXTURE_KILL_THRESHOLD == 1 && + iter->second->hash != GetHash64(Memory::GetPointer(iter->second->addr), iter->second->size_in_bytes, g_ActiveConfig.iSafeTextureCache_ColorSamples)) + { + iter = FreeTexture(iter); + } + else + { + ++iter; + } + } + else + { + iter = FreeTexture(iter); + } } else { -- cgit v1.2.3 From e408e0ab171ad5f55b9daa86f4701f29d1c54b2b Mon Sep 17 00:00:00 2001 From: mimimi085181 Date: Thu, 10 Sep 2015 22:28:59 +0200 Subject: Store the base hash for paletted textures in the texture cache entries --- Source/Core/VideoCommon/TextureCacheBase.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'Source/Core/VideoCommon/TextureCacheBase.cpp') diff --git a/Source/Core/VideoCommon/TextureCacheBase.cpp b/Source/Core/VideoCommon/TextureCacheBase.cpp index 85a1726817..45976dfaca 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/TextureCacheBase.cpp @@ -275,7 +275,7 @@ TextureCache::TCacheEntryBase* TextureCache::DoPartialTextureUpdates(TexCache::i TCacheEntryBase* newentry = AllocateTexture(newconfig); newentry->SetGeneralParameters(entry_to_update->addr, entry_to_update->size_in_bytes, entry_to_update->format); newentry->SetDimensions(entry_to_update->native_width, entry_to_update->native_height, 1); - newentry->SetHashes(entry_to_update->hash); + newentry->SetHashes(entry_to_update->base_hash, entry_to_update->hash); newentry->frameCount = frameCount; newentry->is_efb_copy = false; srcrect.right = entry_to_update->config.width; @@ -380,7 +380,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage) const unsigned int nativeH = height; // Hash assigned to texcache entry (also used to generate filenames used for texture dumping and custom texture lookup) - u64 tex_hash = TEXHASH_INVALID; + u64 base_hash = TEXHASH_INVALID; u64 full_hash = TEXHASH_INVALID; u32 full_format = texformat; @@ -403,16 +403,16 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage) src_data = Memory::GetPointer(address); // TODO: This doesn't hash GB tiles for preloaded RGBA8 textures (instead, it's hashing more data from the low tmem bank than it should) - tex_hash = GetHash64(src_data, texture_size, g_ActiveConfig.iSafeTextureCache_ColorSamples); + base_hash = GetHash64(src_data, texture_size, g_ActiveConfig.iSafeTextureCache_ColorSamples); u32 palette_size = 0; if (isPaletteTexture) { palette_size = TexDecoder_GetPaletteSize(texformat); - full_hash = tex_hash ^ GetHash64(&texMem[tlutaddr], palette_size, g_ActiveConfig.iSafeTextureCache_ColorSamples); + full_hash = base_hash ^ GetHash64(&texMem[tlutaddr], palette_size, g_ActiveConfig.iSafeTextureCache_ColorSamples); } else { - full_hash = tex_hash; + full_hash = base_hash; } // GPUs don't like when the specified mipmap count would require more than one 1x1-sized LOD in the mipmap chain @@ -458,7 +458,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage) { // EFB copies have slightly different rules as EFB copy formats have different // meanings from texture formats. - if ((tex_hash == entry->hash && (!isPaletteTexture || g_Config.backend_info.bSupportsPaletteConversion)) || + if ((base_hash == entry->hash && (!isPaletteTexture || g_Config.backend_info.bSupportsPaletteConversion)) || IsPlayingBackFifologWithBrokenEFBCopies) { // TODO: We should check format/width/height/levels for EFB copies. Checking @@ -519,7 +519,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage) decoded_entry->SetGeneralParameters(address, texture_size, full_format); decoded_entry->SetDimensions(entry->native_width, entry->native_height, 1); - decoded_entry->SetHashes(full_hash); + decoded_entry->SetHashes(base_hash, full_hash); decoded_entry->frameCount = FRAMECOUNT_INVALID; decoded_entry->is_efb_copy = false; @@ -619,7 +619,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage) entry->SetGeneralParameters(address, texture_size, full_format); entry->SetDimensions(nativeW, nativeH, tex_levels); - entry->hash = full_hash; + entry->SetHashes(base_hash, full_hash); entry->is_efb_copy = false; entry->is_custom_tex = hires_tex != nullptr; @@ -1022,7 +1022,6 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat entry->SetGeneralParameters(dstAddr, 0, dstFormat); entry->SetDimensions(tex_w, tex_h, 1); - entry->SetHashes(TEXHASH_INVALID); entry->frameCount = FRAMECOUNT_INVALID; entry->SetEfbCopy(dstStride); @@ -1030,7 +1029,8 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat entry->FromRenderTarget(dst, dstFormat, dstStride, srcFormat, srcRect, isIntensity, scaleByHalf, cbufid, colmat); - entry->hash = GetHash64(dst, (int)entry->size_in_bytes, g_ActiveConfig.iSafeTextureCache_ColorSamples); + u64 hash = GetHash64(dst, (int)entry->size_in_bytes, g_ActiveConfig.iSafeTextureCache_ColorSamples); + entry->SetHashes(hash, hash); // Invalidate all textures that overlap the range of our efb copy. // Unless our efb copy has a weird stride, then we want avoid invalidating textures which -- cgit v1.2.3 From dd458b554d3987d625cd4d17cbb5cdcd0b980f93 Mon Sep 17 00:00:00 2001 From: mimimi085181 Date: Sat, 12 Sep 2015 08:59:14 +0200 Subject: Fix performance regression in Sonic the Fighters, introduced by PR#2001 --- Source/Core/VideoCommon/TextureCacheBase.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'Source/Core/VideoCommon/TextureCacheBase.cpp') diff --git a/Source/Core/VideoCommon/TextureCacheBase.cpp b/Source/Core/VideoCommon/TextureCacheBase.cpp index 8b7b7190aa..694aa80c0a 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/TextureCacheBase.cpp @@ -22,7 +22,7 @@ #include "VideoCommon/VideoConfig.h" static const u64 TEXHASH_INVALID = 0; -static const int TEXTURE_KILL_THRESHOLD = 60; +static const int TEXTURE_KILL_THRESHOLD = 64; // Sonic the Fighters (inside Sonic Gems Collection) loops a 64 frames animation static const int TEXTURE_POOL_KILL_THRESHOLD = 3; static const int FRAMECOUNT_INVALID = 0; @@ -496,8 +496,12 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage) } } - // Find the entry which hasn't been used for the longest time - if (entry->frameCount != FRAMECOUNT_INVALID && entry->frameCount < temp_frameCount) + // Find the texture which hasn't been used for the longest time. Count paletted + // textures as the same texture here, when the texture itself is the same. This + // improves the performance a lot in some games that use paletted textures. + // Example: Sonic the Fighters (inside Sonic Gems Collection) + if (entry->frameCount != FRAMECOUNT_INVALID && entry->frameCount < temp_frameCount && + !(isPaletteTexture && entry->base_hash == base_hash)) { temp_frameCount = entry->frameCount; oldest_entry = iter; -- cgit v1.2.3 From a355d9868e855e0bbba766d6a5550bf88f1defe7 Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Tue, 8 Sep 2015 03:05:47 +1200 Subject: FifoRecorder: Use Video Common to record efb2ram correctly. Texture updates have been moved into TextureCache, while TMEM updates where moved into bpmem. Code for handling efb2ram updates was added to TextureCache. There was a bug for preloaded RGBA8 textures, it only copied half the texture. The TODO was wrong too. --- Source/Core/VideoCommon/TextureCacheBase.cpp | 38 ++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 5 deletions(-) (limited to 'Source/Core/VideoCommon/TextureCacheBase.cpp') diff --git a/Source/Core/VideoCommon/TextureCacheBase.cpp b/Source/Core/VideoCommon/TextureCacheBase.cpp index 694aa80c0a..e93e6955f4 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/TextureCacheBase.cpp @@ -11,6 +11,7 @@ #include "Core/ConfigManager.h" #include "Core/FifoPlayer/FifoPlayer.h" +#include "Core/FifoPlayer/FifoRecorder.h" #include "Core/HW/Memmap.h" #include "VideoCommon/Debugger.h" @@ -19,6 +20,7 @@ #include "VideoCommon/RenderBase.h" #include "VideoCommon/Statistics.h" #include "VideoCommon/TextureCacheBase.h" +#include "VideoCommon/VideoCommon.h" #include "VideoCommon/VideoConfig.h" static const u64 TEXHASH_INVALID = 0; @@ -395,6 +397,25 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage) full_format = texformat | (tlutfmt << 16); const u32 texture_size = TexDecoder_GetTextureSizeInBytes(expandedWidth, expandedHeight, texformat); + u32 additional_mips_size = 0; // not including level 0, which is texture_size + + // GPUs don't like when the specified mipmap count would require more than one 1x1-sized LOD in the mipmap chain + // e.g. 64x64 with 7 LODs would have the mipmap chain 64x64,32x32,16x16,8x8,4x4,2x2,1x1,0x0, so we limit the mipmap count to 6 there + tex_levels = std::min(IntLog2(std::max(width, height)) + 1, tex_levels); + + for (u32 level = 1; level != tex_levels; ++level) + { + // We still need to calculate the original size of the mips + const u32 expanded_mip_width = ROUND_UP(CalculateLevelSize(width, level), bsw); + const u32 expanded_mip_height = ROUND_UP(CalculateLevelSize(height, level), bsh); + + additional_mips_size += TexDecoder_GetTextureSizeInBytes(expanded_mip_width, expanded_mip_height, texformat); + } + + // If we are recording a FifoLog, keep track of what memory we read. + // FifiRecorder does it's own memory modification tracking independant of the texture hashing below. + if (g_bRecordFifoData && !from_tmem) + FifoRecorder::GetInstance().UseMemory(address, texture_size + additional_mips_size, MemoryUpdate::TEXTURE_MAP); const u8* src_data; if (from_tmem) @@ -415,10 +436,6 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage) full_hash = base_hash; } - // GPUs don't like when the specified mipmap count would require more than one 1x1-sized LOD in the mipmap chain - // e.g. 64x64 with 7 LODs would have the mipmap chain 64x64,32x32,16x16,8x8,4x4,2x2,1x1,0x0, so we limit the mipmap count to 6 there - tex_levels = std::min(IntLog2(std::max(width, height)) + 1, tex_levels); - // Search the texture cache for textures by address // // Find all texture cache entries for the current texture address, and decide whether to use one of @@ -740,7 +757,7 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat // // For historical reasons, Dolphin doesn't actually implement "pure" EFB to RAM emulation, but only EFB to texture and hybrid EFB copies. - float colmat[28] = {0}; + float colmat[28] = { 0 }; float *const fConstAdd = colmat + 16; float *const ColorMask = colmat + 20; ColorMask[0] = ColorMask[1] = ColorMask[2] = ColorMask[3] = 255.0f; @@ -1058,6 +1075,17 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat count++), 0); } + if (g_bRecordFifoData) + { + // Mark the memory behind this efb copy as dynamicly generated for the Fifo log + u32 address = dstAddr; + for (u32 i = 0; i < entry->NumBlocksY(); i++) + { + FifoRecorder::GetInstance().UseMemory(address, entry->CacheLinesPerRow() * 32, MemoryUpdate::TEXTURE_MAP, true); + address += entry->memory_stride; + } + } + textures_by_address.emplace((u64)dstAddr, entry); } -- cgit v1.2.3 From e24b8c4ab728c50b3c6a1d8b0066bdbf2f9292d7 Mon Sep 17 00:00:00 2001 From: mimimi085181 Date: Sun, 13 Sep 2015 13:30:56 +0200 Subject: Respect the stride for efb copies when hashing them --- Source/Core/VideoCommon/TextureCacheBase.cpp | 33 ++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) (limited to 'Source/Core/VideoCommon/TextureCacheBase.cpp') diff --git a/Source/Core/VideoCommon/TextureCacheBase.cpp b/Source/Core/VideoCommon/TextureCacheBase.cpp index e93e6955f4..1d9b564a8f 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/TextureCacheBase.cpp @@ -161,7 +161,7 @@ void TextureCache::Cleanup(int _frameCount) // Only remove EFB copies when they wouldn't be used anymore(changed hash), because EFB copies living on the // host GPU are unrecoverable. Perform this check only every TEXTURE_KILL_THRESHOLD for performance reasons if ((_frameCount - iter->second->frameCount) % TEXTURE_KILL_THRESHOLD == 1 && - iter->second->hash != GetHash64(Memory::GetPointer(iter->second->addr), iter->second->size_in_bytes, g_ActiveConfig.iSafeTextureCache_ColorSamples)) + iter->second->hash != iter->second->CalculateHash()) { iter = FreeTexture(iter); } @@ -1050,7 +1050,7 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat entry->FromRenderTarget(dst, dstFormat, dstStride, srcFormat, srcRect, isIntensity, scaleByHalf, cbufid, colmat); - u64 hash = GetHash64(dst, (int)entry->size_in_bytes, g_ActiveConfig.iSafeTextureCache_ColorSamples); + u64 hash = entry->CalculateHash(); entry->SetHashes(hash, hash); // Invalidate all textures that overlap the range of our efb copy. @@ -1166,3 +1166,32 @@ void TextureCache::TCacheEntryBase::Zero(u8* ptr) ptr += memory_stride; } } + +u64 TextureCache::TCacheEntryBase::CalculateHash() const +{ + u8* ptr = Memory::GetPointer(addr); + if (memory_stride == CacheLinesPerRow() * 32) + { + return GetHash64(ptr, size_in_bytes, g_ActiveConfig.iSafeTextureCache_ColorSamples); + } + else + { + u32 blocks = NumBlocksY(); + u64 temp_hash = size_in_bytes; + + u32 samples_per_row = 0; + if (g_ActiveConfig.iSafeTextureCache_ColorSamples != 0) + { + // Hash at least 4 samples per row to avoid hashing in a bad pattern, like just on the left side of the efb copy + samples_per_row = std::max(g_ActiveConfig.iSafeTextureCache_ColorSamples / blocks, 4u); + } + + for (u32 i = 0; i < blocks; i++) + { + // Multiply by a prime number to mix the hash up a bit. This prevents identical blocks from canceling each other out + temp_hash = (temp_hash * 397) ^ GetHash64(ptr, CacheLinesPerRow() * 32, samples_per_row); + ptr += memory_stride; + } + return temp_hash; + } +} -- cgit v1.2.3