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
This commit is contained in:
mimimi085181 2015-12-18 16:59:11 +01:00
parent cafc879b7c
commit 99555a35ca
3 changed files with 117 additions and 59 deletions

View File

@ -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)

View File

@ -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<int> 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::pair<TexCache::iterator, TexCache::iterator>iter_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<int> 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<int> 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;

View File

@ -153,6 +153,7 @@ protected:
private:
typedef std::multimap<u64, TCacheEntryBase*> TexCache;
typedef std::unordered_multimap<TCacheEntryConfig, TCacheEntryBase*, TCacheEntryConfig::Hasher> 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);