From 6bfe4c83a5e56b46202af390be08c61e9f7d0082 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sat, 19 Jan 2019 23:22:57 +1000 Subject: [PATCH 1/4] OGL: Fix broken stereoscopy geometry shader for EFB copies --- Source/Core/VideoBackends/OGL/TextureCache.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Core/VideoBackends/OGL/TextureCache.cpp b/Source/Core/VideoBackends/OGL/TextureCache.cpp index 4fbbb39935..9b0699587b 100644 --- a/Source/Core/VideoBackends/OGL/TextureCache.cpp +++ b/Source/Core/VideoBackends/OGL/TextureCache.cpp @@ -61,6 +61,7 @@ void main() gl_Position = gl_in[i].gl_Position; gl_Layer = layer; EmitVertex(); + } } EndPrimitive(); } From ade255a5ffafd69255f3387fe7e0a1a7b4bd6eec Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sat, 19 Jan 2019 23:23:18 +1000 Subject: [PATCH 2/4] TextureCache: Fix broken XFB stitching with stereoscopy is enabled --- Source/Core/VideoCommon/TextureCacheBase.cpp | 111 ++++++++++--------- Source/Core/VideoCommon/TextureCacheBase.h | 8 +- 2 files changed, 61 insertions(+), 58 deletions(-) diff --git a/Source/Core/VideoCommon/TextureCacheBase.cpp b/Source/Core/VideoCommon/TextureCacheBase.cpp index 89cde6542d..7dafc7bb4b 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/TextureCacheBase.cpp @@ -1140,37 +1140,25 @@ TextureCacheBase::GetXFBTexture(u32 address, u32 width, u32 height, TextureForma texture_cache_safety_color_sample_size, false, 0, 0, 0, TLUTFormat::IA8, 1); if (!tex_info) - { return nullptr; - } + // Try a direct lookup by address/hash. const TextureLookupInformation tex_info_value = tex_info.value(); - TCacheEntry* entry = GetXFBFromCache(tex_info_value); - if (entry != nullptr) - { + if (entry) return entry; - } - entry = CreateNormalTexture(tex_info.value()); - - // XFBs created for the purpose of being a container for textures from memory - // or as a container for overlapping textures, never need to be combined - // with other textures - entry->may_have_overlapping_textures = false; - - // At this point, the XFB wasn't found in cache - // this means the address is most likely not pointing at an xfb copy but instead - // an area of memory. Let's attempt to stitch all entries in this memory space - // together - bool loaded_from_overlapping = LoadTextureFromOverlappingTextures(entry, tex_info_value); - - if (!loaded_from_overlapping) + // At this point, the XFB wasn't found in cache. This means the address is most likely not + // pointing at an xfb copy but instead an area of memory. Let's attempt to stitch all entries in + // this memory space together + bool loaded_from_overlapping = true; + entry = GetTextureFromOverlappingTextures(tex_info_value); + if (!entry) { - // At this point, the xfb address is truly "bogus" - // it likely is an area of memory defined by the CPU - // so load it from memory - LoadTextureFromMemory(entry, tex_info_value); + // At this point, the xfb address is truly "bogus" it likely is an area of memory defined by the + // CPU, so load it from memory. + entry = GetTextureFromMemory(tex_info_value); + loaded_from_overlapping = false; } if (g_ActiveConfig.bDumpXFBTarget) @@ -1299,12 +1287,17 @@ TextureCacheBase::GetXFBFromCache(const TextureLookupInformation& tex_info) return nullptr; } -bool TextureCacheBase::LoadTextureFromOverlappingTextures(TCacheEntry* entry_to_update, - const TextureLookupInformation& tex_info) +TextureCacheBase::TCacheEntry* +TextureCacheBase::GetTextureFromOverlappingTextures(const TextureLookupInformation& tex_info) { - bool updated_entry = false; + u32 numBlocksX = tex_info.native_width / tex_info.block_width; - u32 numBlocksX = entry_to_update->native_width / tex_info.block_width; + // XFBs created for the purpose of being a container for textures from memory + // or as a container for overlapping textures, never need to be combined + // with other textures + TCacheEntry* stitched_entry = + CreateNormalTexture(tex_info, FramebufferManagerBase::GetEFBLayers()); + stitched_entry->may_have_overlapping_textures = false; // It is possible that some of the overlapping textures overlap each other. // This behavior has been seen with XFB copies in Rogue Leader. @@ -1315,14 +1308,13 @@ bool TextureCacheBase::LoadTextureFromOverlappingTextures(TCacheEntry* entry_to_ // instead, which would reduce the amount of copying work here. std::vector candidates; - auto iter = FindOverlappingTextures(entry_to_update->addr, entry_to_update->size_in_bytes); + auto iter = FindOverlappingTextures(tex_info.address, tex_info.total_bytes); while (iter.first != iter.second) { TCacheEntry* entry = iter.first->second; - if (entry != entry_to_update && entry->IsCopy() && !entry->tmem_only && - entry->references.count(entry_to_update) == 0 && - entry->OverlapsMemoryRange(entry_to_update->addr, entry_to_update->size_in_bytes) && - entry->memory_stride == entry_to_update->memory_stride) + if (entry->IsCopy() && !entry->tmem_only && + entry->OverlapsMemoryRange(tex_info.address, tex_info.total_bytes) && + entry->memory_stride == stitched_entry->memory_stride) { if (entry->hash == entry->CalculateHash()) { @@ -1341,6 +1333,7 @@ bool TextureCacheBase::LoadTextureFromOverlappingTextures(TCacheEntry* entry_to_ std::sort(candidates.begin(), candidates.end(), [](const TCacheEntry* a, const TCacheEntry* b) { return a->id < b->id; }); + bool updated_entry = false; for (TCacheEntry* entry : candidates) { if (tex_info.is_palette_texture) @@ -1351,7 +1344,7 @@ bool TextureCacheBase::LoadTextureFromOverlappingTextures(TCacheEntry* entry_to_ { // Link the efb copy with the partially updated texture, so we won't apply this partial // update again - entry->CreateReference(entry_to_update); + entry->CreateReference(stitched_entry); // Mark the texture update as used, as if it was loaded directly entry->frameCount = FRAMECOUNT_INVALID; entry = decoded_entry; @@ -1366,9 +1359,9 @@ bool TextureCacheBase::LoadTextureFromOverlappingTextures(TCacheEntry* entry_to_ // Note for understanding the math: // Normal textures can't be strided, so the 2 missing cases with src_x > 0 don't exist - if (entry->addr >= entry_to_update->addr) + if (entry->addr >= stitched_entry->addr) { - s32 block_offset = (entry->addr - entry_to_update->addr) / tex_info.bytes_per_block; + s32 block_offset = (entry->addr - stitched_entry->addr) / tex_info.bytes_per_block; s32 block_x = block_offset % numBlocksX; s32 block_y = block_offset / numBlocksX; src_x = 0; @@ -1379,7 +1372,7 @@ bool TextureCacheBase::LoadTextureFromOverlappingTextures(TCacheEntry* entry_to_ else { s32 srcNumBlocksX = entry->native_width / tex_info.block_width; - s32 block_offset = (entry_to_update->addr - entry->addr) / tex_info.bytes_per_block; + s32 block_offset = (stitched_entry->addr - entry->addr) / tex_info.bytes_per_block; s32 block_x = block_offset % srcNumBlocksX; s32 block_y = block_offset / srcNumBlocksX; src_x = block_x * tex_info.block_width; @@ -1388,18 +1381,17 @@ bool TextureCacheBase::LoadTextureFromOverlappingTextures(TCacheEntry* entry_to_ dst_y = 0; } - 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); + u32 copy_width = std::min(entry->native_width - src_x, stitched_entry->native_width - dst_x); + u32 copy_height = std::min(entry->native_height - src_y, stitched_entry->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->GetWidth() || - entry_to_update->native_height != entry_to_update->GetHeight() || + if (stitched_entry->native_width != stitched_entry->GetWidth() || + stitched_entry->native_height != stitched_entry->GetHeight() || entry->native_width != entry->GetWidth() || entry->native_height != entry->GetHeight()) { - ScaleTextureCacheEntryTo(entry_to_update, - g_renderer->EFBToScaledX(entry_to_update->native_width), - g_renderer->EFBToScaledY(entry_to_update->native_height)); + ScaleTextureCacheEntryTo(stitched_entry, + g_renderer->EFBToScaledX(stitched_entry->native_width), + g_renderer->EFBToScaledY(stitched_entry->native_height)); ScaleTextureCacheEntryTo(entry, g_renderer->EFBToScaledX(entry->native_width), g_renderer->EFBToScaledY(entry->native_height)); @@ -1424,8 +1416,8 @@ bool TextureCacheBase::LoadTextureFromOverlappingTextures(TCacheEntry* entry_to_ for (u32 layer = 0; layer < entry->texture->GetConfig().layers; layer++) { - entry_to_update->texture->CopyRectangleFromTexture(entry->texture.get(), srcrect, layer, 0, - dstrect, layer, 0); + stitched_entry->texture->CopyRectangleFromTexture(entry->texture.get(), srcrect, layer, 0, + dstrect, layer, 0); } updated_entry = true; @@ -1438,17 +1430,25 @@ bool TextureCacheBase::LoadTextureFromOverlappingTextures(TCacheEntry* entry_to_ else { // Link the two textures together, so we won't apply this partial update again - entry->CreateReference(entry_to_update); + entry->CreateReference(stitched_entry); // Mark the texture update as used, as if it was loaded directly entry->frameCount = FRAMECOUNT_INVALID; } } - return updated_entry; + if (!updated_entry) + { + // Kinda annoying that we have to throw away the texture we just created, but with the above + // code requiring the TCacheEntry object exists, can't do much at the moment. + InvalidateTexture(GetTexCacheIter(stitched_entry)); + return nullptr; + } + + return stitched_entry; } TextureCacheBase::TCacheEntry* -TextureCacheBase::CreateNormalTexture(const TextureLookupInformation& tex_info) +TextureCacheBase::CreateNormalTexture(const TextureLookupInformation& tex_info, u32 layers) { // create the entry/texture TextureConfig config; @@ -1457,6 +1457,7 @@ TextureCacheBase::CreateNormalTexture(const TextureLookupInformation& tex_info) config.levels = tex_info.computed_levels; config.format = AbstractTextureFormat::RGBA8; config.rendertarget = true; + config.layers = layers; TCacheEntry* entry = AllocateCacheEntry(config); GFX_DEBUGGER_PAUSE_AT(NEXT_NEW_TEXTURE, true); @@ -1485,8 +1486,8 @@ TextureCacheBase::CreateNormalTexture(const TextureLookupInformation& tex_info) return entry; } -void TextureCacheBase::LoadTextureFromMemory(TCacheEntry* entry_to_update, - const TextureLookupInformation& tex_info) +TextureCacheBase::TCacheEntry* +TextureCacheBase::GetTextureFromMemory(const TextureLookupInformation& tex_info) { // We can decode on the GPU if it is a supported format and the flag is enabled. // Currently we don't decode RGBA8 textures from Tmem, as that would require copying from both @@ -1498,7 +1499,11 @@ void TextureCacheBase::LoadTextureFromMemory(TCacheEntry* entry_to_update, tex_info.full_format.tlutfmt) && !(tex_info.from_tmem && tex_info.full_format.texfmt == TextureFormat::RGBA8); - LoadTextureLevelZeroFromMemory(entry_to_update, tex_info, decode_on_gpu); + // Since it's coming from RAM, it can only have one layer (no stereo). + TCacheEntry* entry = CreateNormalTexture(tex_info, 1); + entry->may_have_overlapping_textures = false; + LoadTextureLevelZeroFromMemory(entry, tex_info, decode_on_gpu); + return entry; } void TextureCacheBase::LoadTextureLevelZeroFromMemory(TCacheEntry* entry_to_update, diff --git a/Source/Core/VideoCommon/TextureCacheBase.h b/Source/Core/VideoCommon/TextureCacheBase.h index c797a9a4f0..fc9c49311b 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.h +++ b/Source/Core/VideoCommon/TextureCacheBase.h @@ -250,11 +250,9 @@ public: u32 tmem_address_even, u32 tmem_address_odd, u32 tlutaddr, TLUTFormat tlutfmt, u32 levels); TCacheEntry* GetXFBFromCache(const TextureLookupInformation& tex_info); - bool LoadTextureFromOverlappingTextures(TCacheEntry* entry_to_update, - const TextureLookupInformation& tex_info); - TCacheEntry* CreateNormalTexture(const TextureLookupInformation& tex_info); - void LoadTextureFromMemory(TCacheEntry* entry_to_update, - const TextureLookupInformation& tex_info); + TCacheEntry* GetTextureFromOverlappingTextures(const TextureLookupInformation& tex_info); + TCacheEntry* GetTextureFromMemory(const TextureLookupInformation& tex_info); + TCacheEntry* CreateNormalTexture(const TextureLookupInformation& tex_info, u32 layers); void LoadTextureLevelZeroFromMemory(TCacheEntry* entry_to_update, const TextureLookupInformation& tex_info, bool decode_on_gpu); virtual void BindTextures(); From 84bcbef944669a93bfe2905f1c7eb68bda7c9d4e Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sat, 19 Jan 2019 23:27:49 +1000 Subject: [PATCH 3/4] TextureCache: Don't partial copy to non-existant texture layers --- Source/Core/VideoCommon/TextureCacheBase.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Source/Core/VideoCommon/TextureCacheBase.cpp b/Source/Core/VideoCommon/TextureCacheBase.cpp index 7dafc7bb4b..f31cac5364 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/TextureCacheBase.cpp @@ -416,7 +416,10 @@ TextureCacheBase::DoPartialTextureUpdates(TCacheEntry* entry_to_update, u8* pale dstrect.top = dst_y; dstrect.right = (dst_x + copy_width); dstrect.bottom = (dst_y + copy_height); - for (u32 layer = 0; layer < entry->texture->GetConfig().layers; layer++) + + // If one copy is stereo, and the other isn't... not much we can do here :/ + const u32 layers_to_copy = std::min(entry->GetNumLayers(), entry_to_update->GetNumLayers()); + for (u32 layer = 0; layer < layers_to_copy; layer++) { entry_to_update->texture->CopyRectangleFromTexture(entry->texture.get(), srcrect, layer, 0, dstrect, layer, 0); @@ -1414,7 +1417,9 @@ TextureCacheBase::GetTextureFromOverlappingTextures(const TextureLookupInformati dstrect.right = (dst_x + copy_width); dstrect.bottom = (dst_y + copy_height); - for (u32 layer = 0; layer < entry->texture->GetConfig().layers; layer++) + // If one copy is stereo, and the other isn't... not much we can do here :/ + const u32 layers_to_copy = std::min(entry->GetNumLayers(), stitched_entry->GetNumLayers()); + for (u32 layer = 0; layer < layers_to_copy; layer++) { stitched_entry->texture->CopyRectangleFromTexture(entry->texture.get(), srcrect, layer, 0, dstrect, layer, 0); From 10701921654c8990e42e3e944c422d94c399099c Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sat, 19 Jan 2019 23:32:40 +1000 Subject: [PATCH 4/4] TextureCache: Fix a possible crash when partial updating palette textures --- Source/Core/VideoCommon/TextureCacheBase.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Source/Core/VideoCommon/TextureCacheBase.cpp b/Source/Core/VideoCommon/TextureCacheBase.cpp index f31cac5364..a42438e0b1 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/TextureCacheBase.cpp @@ -429,7 +429,8 @@ TextureCacheBase::DoPartialTextureUpdates(TCacheEntry* entry_to_update, u8* pale { // Remove the temporary converted texture, it won't be used anywhere else // TODO: It would be nice to convert and copy in one step, but this code path isn't common - InvalidateTexture(GetTexCacheIter(entry)); + iter.first = InvalidateTexture(iter.first); + continue; } else {