Merge pull request #7716 from stenzek/stereo
Stereoscopy regression fixes
This commit is contained in:
commit
8aaebfa2b3
|
@ -61,6 +61,7 @@ void main()
|
||||||
gl_Position = gl_in[i].gl_Position;
|
gl_Position = gl_in[i].gl_Position;
|
||||||
gl_Layer = layer;
|
gl_Layer = layer;
|
||||||
EmitVertex();
|
EmitVertex();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
EndPrimitive();
|
EndPrimitive();
|
||||||
}
|
}
|
||||||
|
|
|
@ -416,7 +416,10 @@ TextureCacheBase::DoPartialTextureUpdates(TCacheEntry* entry_to_update, u8* pale
|
||||||
dstrect.top = dst_y;
|
dstrect.top = dst_y;
|
||||||
dstrect.right = (dst_x + copy_width);
|
dstrect.right = (dst_x + copy_width);
|
||||||
dstrect.bottom = (dst_y + copy_height);
|
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,
|
entry_to_update->texture->CopyRectangleFromTexture(entry->texture.get(), srcrect, layer,
|
||||||
0, dstrect, layer, 0);
|
0, dstrect, layer, 0);
|
||||||
|
@ -426,7 +429,8 @@ TextureCacheBase::DoPartialTextureUpdates(TCacheEntry* entry_to_update, u8* pale
|
||||||
{
|
{
|
||||||
// Remove the temporary converted texture, it won't be used anywhere else
|
// 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
|
// 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
|
else
|
||||||
{
|
{
|
||||||
|
@ -1140,37 +1144,25 @@ TextureCacheBase::GetXFBTexture(u32 address, u32 width, u32 height, TextureForma
|
||||||
texture_cache_safety_color_sample_size, false, 0, 0, 0,
|
texture_cache_safety_color_sample_size, false, 0, 0, 0,
|
||||||
TLUTFormat::IA8, 1);
|
TLUTFormat::IA8, 1);
|
||||||
if (!tex_info)
|
if (!tex_info)
|
||||||
{
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
|
||||||
|
|
||||||
|
// Try a direct lookup by address/hash.
|
||||||
const TextureLookupInformation tex_info_value = tex_info.value();
|
const TextureLookupInformation tex_info_value = tex_info.value();
|
||||||
|
|
||||||
TCacheEntry* entry = GetXFBFromCache(tex_info_value);
|
TCacheEntry* entry = GetXFBFromCache(tex_info_value);
|
||||||
if (entry != nullptr)
|
if (entry)
|
||||||
{
|
|
||||||
return entry;
|
return entry;
|
||||||
}
|
|
||||||
|
|
||||||
entry = CreateNormalTexture(tex_info.value());
|
// 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
|
||||||
// XFBs created for the purpose of being a container for textures from memory
|
// this memory space together
|
||||||
// or as a container for overlapping textures, never need to be combined
|
bool loaded_from_overlapping = true;
|
||||||
// with other textures
|
entry = GetTextureFromOverlappingTextures(tex_info_value);
|
||||||
entry->may_have_overlapping_textures = false;
|
if (!entry)
|
||||||
|
|
||||||
// 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 address is truly "bogus"
|
// At this point, the xfb address is truly "bogus" it likely is an area of memory defined by the
|
||||||
// it likely is an area of memory defined by the CPU
|
// CPU, so load it from memory.
|
||||||
// so load it from memory
|
entry = GetTextureFromMemory(tex_info_value);
|
||||||
LoadTextureFromMemory(entry, tex_info_value);
|
loaded_from_overlapping = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_ActiveConfig.bDumpXFBTarget)
|
if (g_ActiveConfig.bDumpXFBTarget)
|
||||||
|
@ -1299,12 +1291,17 @@ TextureCacheBase::GetXFBFromCache(const TextureLookupInformation& tex_info)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TextureCacheBase::LoadTextureFromOverlappingTextures(TCacheEntry* entry_to_update,
|
TextureCacheBase::TCacheEntry*
|
||||||
const TextureLookupInformation& tex_info)
|
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.
|
// It is possible that some of the overlapping textures overlap each other.
|
||||||
// This behavior has been seen with XFB copies in Rogue Leader.
|
// This behavior has been seen with XFB copies in Rogue Leader.
|
||||||
|
@ -1315,14 +1312,13 @@ bool TextureCacheBase::LoadTextureFromOverlappingTextures(TCacheEntry* entry_to_
|
||||||
// instead, which would reduce the amount of copying work here.
|
// instead, which would reduce the amount of copying work here.
|
||||||
std::vector<TCacheEntry*> candidates;
|
std::vector<TCacheEntry*> 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)
|
while (iter.first != iter.second)
|
||||||
{
|
{
|
||||||
TCacheEntry* entry = iter.first->second;
|
TCacheEntry* entry = iter.first->second;
|
||||||
if (entry != entry_to_update && entry->IsCopy() && !entry->tmem_only &&
|
if (entry->IsCopy() && !entry->tmem_only &&
|
||||||
entry->references.count(entry_to_update) == 0 &&
|
entry->OverlapsMemoryRange(tex_info.address, tex_info.total_bytes) &&
|
||||||
entry->OverlapsMemoryRange(entry_to_update->addr, entry_to_update->size_in_bytes) &&
|
entry->memory_stride == stitched_entry->memory_stride)
|
||||||
entry->memory_stride == entry_to_update->memory_stride)
|
|
||||||
{
|
{
|
||||||
if (entry->hash == entry->CalculateHash())
|
if (entry->hash == entry->CalculateHash())
|
||||||
{
|
{
|
||||||
|
@ -1341,6 +1337,7 @@ bool TextureCacheBase::LoadTextureFromOverlappingTextures(TCacheEntry* entry_to_
|
||||||
std::sort(candidates.begin(), candidates.end(),
|
std::sort(candidates.begin(), candidates.end(),
|
||||||
[](const TCacheEntry* a, const TCacheEntry* b) { return a->id < b->id; });
|
[](const TCacheEntry* a, const TCacheEntry* b) { return a->id < b->id; });
|
||||||
|
|
||||||
|
bool updated_entry = false;
|
||||||
for (TCacheEntry* entry : candidates)
|
for (TCacheEntry* entry : candidates)
|
||||||
{
|
{
|
||||||
if (tex_info.is_palette_texture)
|
if (tex_info.is_palette_texture)
|
||||||
|
@ -1351,7 +1348,7 @@ bool TextureCacheBase::LoadTextureFromOverlappingTextures(TCacheEntry* entry_to_
|
||||||
{
|
{
|
||||||
// Link the efb copy with the partially updated texture, so we won't apply this partial
|
// Link the efb copy with the partially updated texture, so we won't apply this partial
|
||||||
// update again
|
// update again
|
||||||
entry->CreateReference(entry_to_update);
|
entry->CreateReference(stitched_entry);
|
||||||
// Mark the texture update as used, as if it was loaded directly
|
// Mark the texture update as used, as if it was loaded directly
|
||||||
entry->frameCount = FRAMECOUNT_INVALID;
|
entry->frameCount = FRAMECOUNT_INVALID;
|
||||||
entry = decoded_entry;
|
entry = decoded_entry;
|
||||||
|
@ -1366,9 +1363,9 @@ bool TextureCacheBase::LoadTextureFromOverlappingTextures(TCacheEntry* entry_to_
|
||||||
|
|
||||||
// Note for understanding the math:
|
// Note for understanding the math:
|
||||||
// Normal textures can't be strided, so the 2 missing cases with src_x > 0 don't exist
|
// 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_x = block_offset % numBlocksX;
|
||||||
s32 block_y = block_offset / numBlocksX;
|
s32 block_y = block_offset / numBlocksX;
|
||||||
src_x = 0;
|
src_x = 0;
|
||||||
|
@ -1379,7 +1376,7 @@ bool TextureCacheBase::LoadTextureFromOverlappingTextures(TCacheEntry* entry_to_
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
s32 srcNumBlocksX = entry->native_width / tex_info.block_width;
|
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_x = block_offset % srcNumBlocksX;
|
||||||
s32 block_y = block_offset / srcNumBlocksX;
|
s32 block_y = block_offset / srcNumBlocksX;
|
||||||
src_x = block_x * tex_info.block_width;
|
src_x = block_x * tex_info.block_width;
|
||||||
|
@ -1388,18 +1385,17 @@ bool TextureCacheBase::LoadTextureFromOverlappingTextures(TCacheEntry* entry_to_
|
||||||
dst_y = 0;
|
dst_y = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 copy_width = std::min(entry->native_width - src_x, entry_to_update->native_width - dst_x);
|
u32 copy_width = std::min(entry->native_width - src_x, stitched_entry->native_width - dst_x);
|
||||||
u32 copy_height =
|
u32 copy_height = std::min(entry->native_height - src_y, stitched_entry->native_height - dst_y);
|
||||||
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 one of the textures is scaled, scale both with the current efb scaling factor
|
||||||
if (entry_to_update->native_width != entry_to_update->GetWidth() ||
|
if (stitched_entry->native_width != stitched_entry->GetWidth() ||
|
||||||
entry_to_update->native_height != entry_to_update->GetHeight() ||
|
stitched_entry->native_height != stitched_entry->GetHeight() ||
|
||||||
entry->native_width != entry->GetWidth() || entry->native_height != entry->GetHeight())
|
entry->native_width != entry->GetWidth() || entry->native_height != entry->GetHeight())
|
||||||
{
|
{
|
||||||
ScaleTextureCacheEntryTo(entry_to_update,
|
ScaleTextureCacheEntryTo(stitched_entry,
|
||||||
g_renderer->EFBToScaledX(entry_to_update->native_width),
|
g_renderer->EFBToScaledX(stitched_entry->native_width),
|
||||||
g_renderer->EFBToScaledY(entry_to_update->native_height));
|
g_renderer->EFBToScaledY(stitched_entry->native_height));
|
||||||
ScaleTextureCacheEntryTo(entry, g_renderer->EFBToScaledX(entry->native_width),
|
ScaleTextureCacheEntryTo(entry, g_renderer->EFBToScaledX(entry->native_width),
|
||||||
g_renderer->EFBToScaledY(entry->native_height));
|
g_renderer->EFBToScaledY(entry->native_height));
|
||||||
|
|
||||||
|
@ -1422,10 +1418,12 @@ bool TextureCacheBase::LoadTextureFromOverlappingTextures(TCacheEntry* entry_to_
|
||||||
dstrect.right = (dst_x + copy_width);
|
dstrect.right = (dst_x + copy_width);
|
||||||
dstrect.bottom = (dst_y + copy_height);
|
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++)
|
||||||
{
|
{
|
||||||
entry_to_update->texture->CopyRectangleFromTexture(entry->texture.get(), srcrect, layer, 0,
|
stitched_entry->texture->CopyRectangleFromTexture(entry->texture.get(), srcrect, layer, 0,
|
||||||
dstrect, layer, 0);
|
dstrect, layer, 0);
|
||||||
}
|
}
|
||||||
updated_entry = true;
|
updated_entry = true;
|
||||||
|
|
||||||
|
@ -1438,17 +1436,25 @@ bool TextureCacheBase::LoadTextureFromOverlappingTextures(TCacheEntry* entry_to_
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Link the two textures together, so we won't apply this partial update again
|
// 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
|
// Mark the texture update as used, as if it was loaded directly
|
||||||
entry->frameCount = FRAMECOUNT_INVALID;
|
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::TCacheEntry*
|
||||||
TextureCacheBase::CreateNormalTexture(const TextureLookupInformation& tex_info)
|
TextureCacheBase::CreateNormalTexture(const TextureLookupInformation& tex_info, u32 layers)
|
||||||
{
|
{
|
||||||
// create the entry/texture
|
// create the entry/texture
|
||||||
TextureConfig config;
|
TextureConfig config;
|
||||||
|
@ -1457,6 +1463,7 @@ TextureCacheBase::CreateNormalTexture(const TextureLookupInformation& tex_info)
|
||||||
config.levels = tex_info.computed_levels;
|
config.levels = tex_info.computed_levels;
|
||||||
config.format = AbstractTextureFormat::RGBA8;
|
config.format = AbstractTextureFormat::RGBA8;
|
||||||
config.rendertarget = true;
|
config.rendertarget = true;
|
||||||
|
config.layers = layers;
|
||||||
|
|
||||||
TCacheEntry* entry = AllocateCacheEntry(config);
|
TCacheEntry* entry = AllocateCacheEntry(config);
|
||||||
GFX_DEBUGGER_PAUSE_AT(NEXT_NEW_TEXTURE, true);
|
GFX_DEBUGGER_PAUSE_AT(NEXT_NEW_TEXTURE, true);
|
||||||
|
@ -1485,8 +1492,8 @@ TextureCacheBase::CreateNormalTexture(const TextureLookupInformation& tex_info)
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextureCacheBase::LoadTextureFromMemory(TCacheEntry* entry_to_update,
|
TextureCacheBase::TCacheEntry*
|
||||||
const TextureLookupInformation& tex_info)
|
TextureCacheBase::GetTextureFromMemory(const TextureLookupInformation& tex_info)
|
||||||
{
|
{
|
||||||
// We can decode on the GPU if it is a supported format and the flag is enabled.
|
// 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
|
// Currently we don't decode RGBA8 textures from Tmem, as that would require copying from both
|
||||||
|
@ -1498,7 +1505,11 @@ void TextureCacheBase::LoadTextureFromMemory(TCacheEntry* entry_to_update,
|
||||||
tex_info.full_format.tlutfmt) &&
|
tex_info.full_format.tlutfmt) &&
|
||||||
!(tex_info.from_tmem && tex_info.full_format.texfmt == TextureFormat::RGBA8);
|
!(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,
|
void TextureCacheBase::LoadTextureLevelZeroFromMemory(TCacheEntry* entry_to_update,
|
||||||
|
|
|
@ -250,11 +250,9 @@ public:
|
||||||
u32 tmem_address_even, u32 tmem_address_odd, u32 tlutaddr,
|
u32 tmem_address_even, u32 tmem_address_odd, u32 tlutaddr,
|
||||||
TLUTFormat tlutfmt, u32 levels);
|
TLUTFormat tlutfmt, u32 levels);
|
||||||
TCacheEntry* GetXFBFromCache(const TextureLookupInformation& tex_info);
|
TCacheEntry* GetXFBFromCache(const TextureLookupInformation& tex_info);
|
||||||
bool LoadTextureFromOverlappingTextures(TCacheEntry* entry_to_update,
|
TCacheEntry* GetTextureFromOverlappingTextures(const TextureLookupInformation& tex_info);
|
||||||
const TextureLookupInformation& tex_info);
|
TCacheEntry* GetTextureFromMemory(const TextureLookupInformation& tex_info);
|
||||||
TCacheEntry* CreateNormalTexture(const TextureLookupInformation& tex_info);
|
TCacheEntry* CreateNormalTexture(const TextureLookupInformation& tex_info, u32 layers);
|
||||||
void LoadTextureFromMemory(TCacheEntry* entry_to_update,
|
|
||||||
const TextureLookupInformation& tex_info);
|
|
||||||
void LoadTextureLevelZeroFromMemory(TCacheEntry* entry_to_update,
|
void LoadTextureLevelZeroFromMemory(TCacheEntry* entry_to_update,
|
||||||
const TextureLookupInformation& tex_info, bool decode_on_gpu);
|
const TextureLookupInformation& tex_info, bool decode_on_gpu);
|
||||||
virtual void BindTextures();
|
virtual void BindTextures();
|
||||||
|
|
Loading…
Reference in New Issue