diff options
| author | degasus <wickmarkus@web.de> | 2015-10-29 18:08:04 +0100 |
|---|---|---|
| committer | degasus <wickmarkus@web.de> | 2015-11-15 12:02:41 +0100 |
| commit | 087ba5268a5512e95783ad69bc743a5aeb0bb0b9 (patch) | |
| tree | ba5beb146187c96b8030bdfb0a3292dcbe0a0276 /Source/Core/VideoCommon/TextureCacheBase.cpp | |
| parent | dcdf8fd3ced5e5d2b94299bc710a69ee06bab0d6 (diff) | |
TextureCache: Rewrite EFB Copy control flow
Diffstat (limited to 'Source/Core/VideoCommon/TextureCacheBase.cpp')
| -rw-r--r-- | Source/Core/VideoCommon/TextureCacheBase.cpp | 125 |
1 files changed, 72 insertions, 53 deletions
diff --git a/Source/Core/VideoCommon/TextureCacheBase.cpp b/Source/Core/VideoCommon/TextureCacheBase.cpp index 44fdf9fe48..693b4b5ba1 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/TextureCacheBase.cpp @@ -1032,80 +1032,109 @@ void TextureCacheBase::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFo } } - // create the texture - TCacheEntryConfig config; - config.rendertarget = true; - config.width = scaled_tex_w; - config.height = scaled_tex_h; - config.layers = FramebufferManagerBase::GetEFBLayers(); + u32 blockH = TexDecoder_GetBlockHeightInTexels(dstFormat); + const u32 blockW = TexDecoder_GetBlockWidthInTexels(dstFormat); - TCacheEntryBase* entry = AllocateTexture(config); + // Round up source height to multiple of block size + u32 actualHeight = ROUND_UP(tex_h, blockH); + const u32 actualWidth = ROUND_UP(tex_w, blockW); - entry->SetGeneralParameters(dstAddr, 0, dstFormat); - entry->SetDimensions(tex_w, tex_h, 1); + u32 num_blocks_y = actualHeight / blockH; + const u32 num_blocks_x = actualWidth / blockW; - entry->frameCount = FRAMECOUNT_INVALID; - entry->SetEfbCopy(dstStride); - entry->is_custom_tex = false; + // RGBA takes two cache lines per block; all others take one + const u32 bytes_per_block = dstFormat == GX_TF_RGBA8 ? 64 : 32; - entry->FromRenderTarget(dst, dstFormat, dstStride, srcFormat, srcRect, isIntensity, scaleByHalf, cbufid, colmat); + u32 bytes_per_row = num_blocks_x * bytes_per_block; - if (g_ActiveConfig.bSkipEFBCopyToRam) - { - entry->Zero(dst); - } - else + bool copy_to_ram = !g_ActiveConfig.bSkipEFBCopyToRam; + bool copy_to_vram = true; + + if (copy_to_ram) { g_texture_cache->CopyEFB( dst, - entry->format, - entry->native_width, - entry->BytesPerRow(), - entry->NumBlocksY(), - entry->memory_stride, + dstFormat, + tex_w, + bytes_per_row, + num_blocks_y, + dstStride, srcFormat, srcRect, isIntensity, scaleByHalf); } + else + { + // Hack: Most games don't actually need the correct texture data in RAM + // and we can just keep a copy in VRAM. We zero the memory so we + // can check it hasn't changed before using our copy in VRAM. + u8* ptr = dst; + for (u32 i = 0; i < num_blocks_y; i++) + { + memset(ptr, 0, bytes_per_row); + ptr += dstStride; + } + } - u64 hash = entry->CalculateHash(); - entry->SetHashes(hash, hash); + 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 < num_blocks_y; i++) + { + FifoRecorder::GetInstance().UseMemory(address, bytes_per_row, MemoryUpdate::TEXTURE_MAP, true); + address += dstStride; + } + } // 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->BytesPerRow()) + if (dstStride == bytes_per_row || !copy_to_vram) { 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 + if (iter->second->addr + iter->second->size_in_bytes <= dstAddr || iter->second->addr >= dstAddr + num_blocks_y * dstStride) ++iter; + else + iter = FreeTexture(iter); } } - if (g_ActiveConfig.bDumpEFBTarget) + if (copy_to_vram) { - static int count = 0; - entry->Save(StringFromFormat("%sefb_frame_%i.png", File::GetUserPath(D_DUMPTEXTURES_IDX).c_str(), - count++), 0); - } + // create the texture + TCacheEntryConfig config; + config.rendertarget = true; + config.width = scaled_tex_w; + config.height = scaled_tex_h; + config.layers = FramebufferManagerBase::GetEFBLayers(); - 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++) + TCacheEntryBase* entry = AllocateTexture(config); + + entry->SetGeneralParameters(dstAddr, 0, dstFormat); + entry->SetDimensions(tex_w, tex_h, 1); + + entry->frameCount = FRAMECOUNT_INVALID; + entry->SetEfbCopy(dstStride); + entry->is_custom_tex = false; + + entry->FromRenderTarget(dst, srcFormat, srcRect, scaleByHalf, cbufid, colmat); + + u64 hash = entry->CalculateHash(); + entry->SetHashes(hash, hash); + + if (g_ActiveConfig.bDumpEFBTarget) { - FifoRecorder::GetInstance().UseMemory(address, entry->BytesPerRow(), MemoryUpdate::TEXTURE_MAP, true); - address += entry->memory_stride; + static int count = 0; + entry->Save(StringFromFormat("%sefb_frame_%i.png", File::GetUserPath(D_DUMPTEXTURES_IDX).c_str(), + count++), 0); } - } - textures_by_address.emplace((u64)dstAddr, entry); + textures_by_address.emplace((u64)dstAddr, entry); + } } TextureCacheBase::TCacheEntryBase* TextureCacheBase::AllocateTexture(const TCacheEntryConfig& config) @@ -1177,16 +1206,6 @@ void TextureCacheBase::TCacheEntryBase::SetEfbCopy(u32 stride) size_in_bytes = memory_stride * NumBlocksY(); } -// Fill gamecube memory backing this texture with zeros. -void TextureCacheBase::TCacheEntryBase::Zero(u8* ptr) -{ - for (u32 i = 0; i < NumBlocksY(); i++) - { - memset(ptr, 0, BytesPerRow()); - ptr += memory_stride; - } -} - u64 TextureCacheBase::TCacheEntryBase::CalculateHash() const { u8* ptr = Memory::GetPointer(addr); |
