From 99555a35cad56b53ead422f23eae49a2251e52d6 Mon Sep 17 00:00:00 2001 From: mimimi085181 Date: Fri, 18 Dec 2015 16:59:11 +0100 Subject: [PATCH 1/2] For partial texture updates check the dimensions of the efb copy and the target texture, not just the binary size. This should get Donkey Kong Country Returns characters to be as broken as they should be. They will be fixed in a later pr. Expected result is: efbtex: characters are always flickering or invisible, no matter what scaling or IR setting efb2ram: characters are always working properly at 1xIR, no matter what scaling or IR setting --- .../Core/VideoBackends/D3D/TextureCache.cpp | 18 +- Source/Core/VideoCommon/TextureCacheBase.cpp | 157 ++++++++++++------ Source/Core/VideoCommon/TextureCacheBase.h | 1 + 3 files changed, 117 insertions(+), 59 deletions(-) diff --git a/Source/Core/VideoBackends/D3D/TextureCache.cpp b/Source/Core/VideoBackends/D3D/TextureCache.cpp index ef0158653d..1403027dfc 100644 --- a/Source/Core/VideoBackends/D3D/TextureCache.cpp +++ b/Source/Core/VideoBackends/D3D/TextureCache.cpp @@ -87,16 +87,14 @@ void TextureCache::TCacheEntry::CopyRectangleFromTexture( if (srcrect.GetWidth() == dstrect.GetWidth() && srcrect.GetHeight() == dstrect.GetHeight()) { - const D3D11_BOX *psrcbox = nullptr; D3D11_BOX srcbox; - if (srcrect.left != 0 || srcrect.top != 0) - { - srcbox.left = srcrect.left; - srcbox.top = srcrect.top; - srcbox.right = srcrect.right; - srcbox.bottom = srcrect.bottom; - psrcbox = &srcbox; - } + srcbox.left = srcrect.left; + srcbox.top = srcrect.top; + srcbox.right = srcrect.right; + srcbox.bottom = srcrect.bottom; + srcbox.front = 0; + srcbox.back = 1; + D3D::context->CopySubresourceRegion( texture->GetTex(), 0, @@ -105,7 +103,7 @@ void TextureCache::TCacheEntry::CopyRectangleFromTexture( 0, srcentry->texture->GetTex(), 0, - psrcbox); + &srcbox); return; } else if (!config.rendertarget) diff --git a/Source/Core/VideoCommon/TextureCacheBase.cpp b/Source/Core/VideoCommon/TextureCacheBase.cpp index f3f05984e4..106e9fa588 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/TextureCacheBase.cpp @@ -209,6 +209,75 @@ bool TextureCacheBase::TCacheEntryBase::OverlapsMemoryRange(u32 range_address, u return true; } +void TextureCacheBase::ScaleTextureCacheEntryTo(TextureCacheBase::TCacheEntryBase** entry, u32 new_width, u32 new_height) +{ + if ((*entry)->config.width == new_width && (*entry)->config.height == new_height) + { + return; + } + + u32 max = g_renderer->GetMaxTextureSize(); + if (max < new_width || max < new_height) + { + ERROR_LOG(VIDEO, "Texture too big, width = %d, height = %d", new_width, new_height); + return; + } + + TextureCacheBase::TCacheEntryConfig newconfig; + newconfig.width = new_width; + newconfig.height = new_height; + newconfig.rendertarget = true; + + TCacheEntryBase* newentry = AllocateTexture(newconfig); + if (newentry) + { + newentry->SetGeneralParameters((*entry)->addr, (*entry)->size_in_bytes, (*entry)->format); + newentry->SetDimensions((*entry)->native_width, (*entry)->native_height, 1); + newentry->SetHashes((*entry)->base_hash, (*entry)->hash); + newentry->frameCount = frameCount; + newentry->is_efb_copy = false; + MathUtil::Rectangle srcrect, dstrect; + srcrect.left = 0; + srcrect.top = 0; + srcrect.right = (*entry)->config.width; + srcrect.bottom = (*entry)->config.height; + dstrect.left = 0; + dstrect.top = 0; + dstrect.right = new_width; + dstrect.bottom = new_height; + newentry->CopyRectangleFromTexture(*entry, srcrect, dstrect); + + // Keep track of the pointer for textures_by_hash + if ((*entry)->textures_by_hash_iter != textures_by_hash.end()) + { + newentry->textures_by_hash_iter = textures_by_hash.emplace((*entry)->hash, newentry); + } + + // Remove the old texture + std::pairiter_range = textures_by_address.equal_range((*entry)->addr); + TexCache::iterator iter = iter_range.first; + while (iter != iter_range.second) + { + if (iter->second == *entry) + { + FreeTexture(iter); + iter = iter_range.second; + } + else + { + iter++; + } + } + + *entry = newentry; + textures_by_address.emplace((*entry)->addr, *entry); + } + else + { + ERROR_LOG(VIDEO, "Scaling failed"); + } +} + TextureCacheBase::TCacheEntryBase* TextureCacheBase::DoPartialTextureUpdates(TexCache::iterator iter_t) { TCacheEntryBase* entry_to_update = iter_t->second; @@ -232,7 +301,6 @@ TextureCacheBase::TCacheEntryBase* TextureCacheBase::DoPartialTextureUpdates(Tex 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; @@ -249,56 +317,47 @@ TextureCacheBase::TCacheEntryBase* TextureCacheBase::DoPartialTextureUpdates(Tex u32 block_x = block_offset % numBlocksX; u32 block_y = block_offset / numBlocksX; - u32 x = block_x * block_width; - u32 y = block_y * block_height; - MathUtil::Rectangle srcrect, dstrect; - srcrect.left = 0; - srcrect.top = 0; - dstrect.left = 0; - dstrect.top = 0; - if (entry_need_scaling) + u32 dst_x = block_x * block_width; + u32 dst_y = block_y * block_height; + u32 src_x = 0; + u32 src_y = 0; + + // If the EFB copy doesn't fully fit, cancel the copy process + if (entry->native_width - src_x > entry_to_update->native_width - dst_x + || entry->native_height - src_y > entry_to_update->native_height - dst_y) { - 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) - { - TextureCacheBase::TCacheEntryConfig newconfig; - newconfig.width = w; - newconfig.height = h; - newconfig.rendertarget = true; - TCacheEntryBase* newentry = AllocateTexture(newconfig); - if (newentry) - { - 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->base_hash, 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); - } - } + iter++; + continue; } - 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; + + u32 copy_width = std::min(entry->native_width - src_x, entry_to_update->native_width - dst_x); + u32 copy_height = std::min(entry->native_height - src_y, entry_to_update->native_height - dst_y); + + // If one of the textures is scaled, scale both with the current efb scaling factor + if (entry_to_update->native_width != entry_to_update->config.width + || entry_to_update->native_height != entry_to_update->config.height + || entry->native_width != entry->config.width || entry->native_height != entry->config.height) + { + ScaleTextureCacheEntryTo(&entry_to_update, Renderer::EFBToScaledX(entry_to_update->native_width), Renderer::EFBToScaledY(entry_to_update->native_height)); + ScaleTextureCacheEntryTo(&entry, Renderer::EFBToScaledX(entry->native_width), Renderer::EFBToScaledY(entry->native_height)); + + src_x = Renderer::EFBToScaledX(src_x); + src_y = Renderer::EFBToScaledY(src_y); + dst_x = Renderer::EFBToScaledX(dst_x); + dst_y = Renderer::EFBToScaledY(dst_y); + copy_width = Renderer::EFBToScaledX(copy_width); + copy_height = Renderer::EFBToScaledY(copy_height); + } + + MathUtil::Rectangle srcrect, dstrect; + srcrect.left = src_x; + srcrect.top = src_y; + srcrect.right = (src_x + copy_width); + srcrect.bottom = (src_y + copy_height); + dstrect.left = dst_x; + dstrect.top = dst_y; + dstrect.right = (dst_x + copy_width); + dstrect.bottom = (dst_y + copy_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; diff --git a/Source/Core/VideoCommon/TextureCacheBase.h b/Source/Core/VideoCommon/TextureCacheBase.h index b753fab1f9..9b9eb6eed9 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.h +++ b/Source/Core/VideoCommon/TextureCacheBase.h @@ -153,6 +153,7 @@ protected: private: typedef std::multimap TexCache; typedef std::unordered_multimap TexPool; + static void ScaleTextureCacheEntryTo(TCacheEntryBase** entry, u32 new_width, u32 new_height); static TCacheEntryBase* DoPartialTextureUpdates(TexCache::iterator iter); static void DumpTexture(TCacheEntryBase* entry, std::string basename, unsigned int level); static void CheckTempSize(size_t required_size); From bb4d636f34ab26c4c964cf83383d0694be6beb8c Mon Sep 17 00:00:00 2001 From: mimimi085181 Date: Sun, 14 Feb 2016 17:13:07 +0100 Subject: [PATCH 2/2] Copy all layers of textures with CopyRectangleFromTexture --- Source/Core/VideoBackends/D3D/TextureCache.cpp | 4 ++-- Source/Core/VideoBackends/OGL/TextureCache.cpp | 2 +- Source/Core/VideoCommon/TextureCacheBase.cpp | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Source/Core/VideoBackends/D3D/TextureCache.cpp b/Source/Core/VideoBackends/D3D/TextureCache.cpp index 1403027dfc..ac8271fbb5 100644 --- a/Source/Core/VideoBackends/D3D/TextureCache.cpp +++ b/Source/Core/VideoBackends/D3D/TextureCache.cpp @@ -93,7 +93,7 @@ void TextureCache::TCacheEntry::CopyRectangleFromTexture( srcbox.right = srcrect.right; srcbox.bottom = srcrect.bottom; srcbox.front = 0; - srcbox.back = 1; + srcbox.back = srcentry->config.layers; D3D::context->CopySubresourceRegion( texture->GetTex(), @@ -130,7 +130,7 @@ void TextureCache::TCacheEntry::CopyRectangleFromTexture( srcentry->config.width, srcentry->config.height, PixelShaderCache::GetColorCopyProgram(false), VertexShaderCache::GetSimpleVertexShader(), - VertexShaderCache::GetSimpleInputLayout(), nullptr, 1.0, 0); + VertexShaderCache::GetSimpleInputLayout(), GeometryShaderCache::GetCopyGeometryShader(), 1.0, 0); D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), diff --git a/Source/Core/VideoBackends/OGL/TextureCache.cpp b/Source/Core/VideoBackends/OGL/TextureCache.cpp index 824d16b8c1..6cd9c50359 100644 --- a/Source/Core/VideoBackends/OGL/TextureCache.cpp +++ b/Source/Core/VideoBackends/OGL/TextureCache.cpp @@ -168,7 +168,7 @@ void TextureCache::TCacheEntry::CopyRectangleFromTexture( 0, dstrect.GetWidth(), dstrect.GetHeight(), - 1); + srcentry->config.layers); return; } else if (!framebuffer) diff --git a/Source/Core/VideoCommon/TextureCacheBase.cpp b/Source/Core/VideoCommon/TextureCacheBase.cpp index 106e9fa588..eb4b041c18 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/TextureCacheBase.cpp @@ -226,6 +226,7 @@ void TextureCacheBase::ScaleTextureCacheEntryTo(TextureCacheBase::TCacheEntryBas TextureCacheBase::TCacheEntryConfig newconfig; newconfig.width = new_width; newconfig.height = new_height; + newconfig.layers = (*entry)->config.layers; newconfig.rendertarget = true; TCacheEntryBase* newentry = AllocateTexture(newconfig);