mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2025-07-29 09:10:01 -06:00
Change image format view handling to allow view incompatible formats (#7311)
* Allow creating texture aliases on texture pool * Delete old image format override code * New format incompatible alias * Missing bounds check * GetForBinding now takes FormatInfo * Make FormatInfo struct more compact
This commit is contained in:
@ -75,6 +75,76 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
private readonly ConcurrentQueue<DereferenceRequest> _dereferenceQueue = new();
|
||||
private TextureDescriptor _defaultDescriptor;
|
||||
|
||||
/// <summary>
|
||||
/// List of textures that shares the same memory region, but have different formats.
|
||||
/// </summary>
|
||||
private class TextureAliasList
|
||||
{
|
||||
/// <summary>
|
||||
/// Alias texture.
|
||||
/// </summary>
|
||||
/// <param name="Format">Texture format</param>
|
||||
/// <param name="Texture">Texture</param>
|
||||
private readonly record struct Alias(Format Format, Texture Texture);
|
||||
|
||||
/// <summary>
|
||||
/// List of texture aliases.
|
||||
/// </summary>
|
||||
private readonly List<Alias> _aliases;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the texture alias list.
|
||||
/// </summary>
|
||||
public TextureAliasList()
|
||||
{
|
||||
_aliases = new List<Alias>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new texture alias.
|
||||
/// </summary>
|
||||
/// <param name="format">Alias format</param>
|
||||
/// <param name="texture">Alias texture</param>
|
||||
public void Add(Format format, Texture texture)
|
||||
{
|
||||
_aliases.Add(new Alias(format, texture));
|
||||
texture.IncrementReferenceCount();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds a texture with the requested format, or returns null if not found.
|
||||
/// </summary>
|
||||
/// <param name="format">Format to find</param>
|
||||
/// <returns>Texture with the requested format, or null if not found</returns>
|
||||
public Texture Find(Format format)
|
||||
{
|
||||
foreach (var alias in _aliases)
|
||||
{
|
||||
if (alias.Format == format)
|
||||
{
|
||||
return alias.Texture;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all alias textures.
|
||||
/// </summary>
|
||||
public void Destroy()
|
||||
{
|
||||
foreach (var entry in _aliases)
|
||||
{
|
||||
entry.Texture.DecrementReferenceCount();
|
||||
}
|
||||
|
||||
_aliases.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
private readonly Dictionary<Texture, TextureAliasList> _aliasLists;
|
||||
|
||||
/// <summary>
|
||||
/// Linked list node used on the texture pool cache.
|
||||
/// </summary>
|
||||
@ -95,6 +165,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
public TexturePool(GpuContext context, GpuChannel channel, ulong address, int maximumId) : base(context, channel.MemoryManager.Physical, address, maximumId)
|
||||
{
|
||||
_channel = channel;
|
||||
_aliasLists = new Dictionary<Texture, TextureAliasList>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -115,14 +186,13 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
|
||||
if (texture == null)
|
||||
{
|
||||
TextureInfo info = GetInfo(descriptor, out int layerSize);
|
||||
|
||||
// The dereference queue can put our texture back on the cache.
|
||||
if ((texture = ProcessDereferenceQueue(id)) != null)
|
||||
{
|
||||
return ref descriptor;
|
||||
}
|
||||
|
||||
TextureInfo info = GetInfo(descriptor, out int layerSize);
|
||||
texture = PhysicalMemory.TextureCache.FindOrCreateTexture(_channel.MemoryManager, TextureSearchFlags.ForSampler, info, layerSize);
|
||||
|
||||
// If this happens, then the texture address is invalid, we can't add it to the cache.
|
||||
@ -197,6 +267,51 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
return ref GetInternal(id, out texture);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the texture descriptor and texture with the given ID.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method assumes that the pool has been manually synchronized before doing binding.
|
||||
/// </remarks>
|
||||
/// <param name="id">ID of the texture. This is effectively a zero-based index</param>
|
||||
/// <param name="formatInfo">Texture format information</param>
|
||||
/// <param name="texture">The texture with the given ID</param>
|
||||
/// <returns>The texture descriptor with the given ID</returns>
|
||||
public ref readonly TextureDescriptor GetForBinding(int id, FormatInfo formatInfo, out Texture texture)
|
||||
{
|
||||
if ((uint)id >= Items.Length)
|
||||
{
|
||||
texture = null;
|
||||
return ref _defaultDescriptor;
|
||||
}
|
||||
|
||||
ref readonly TextureDescriptor descriptor = ref GetInternal(id, out texture);
|
||||
|
||||
if (texture != null && formatInfo.Format != 0 && texture.Format != formatInfo.Format)
|
||||
{
|
||||
if (!_aliasLists.TryGetValue(texture, out TextureAliasList aliasList))
|
||||
{
|
||||
_aliasLists.Add(texture, aliasList = new TextureAliasList());
|
||||
}
|
||||
|
||||
texture = aliasList.Find(formatInfo.Format);
|
||||
|
||||
if (texture == null)
|
||||
{
|
||||
TextureInfo info = GetInfo(descriptor, out int layerSize);
|
||||
info = ChangeFormat(info, formatInfo);
|
||||
texture = PhysicalMemory.TextureCache.FindOrCreateTexture(_channel.MemoryManager, TextureSearchFlags.ForSampler, info, layerSize);
|
||||
|
||||
if (texture != null)
|
||||
{
|
||||
aliasList.Add(formatInfo.Format, texture);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ref descriptor;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the pool was modified, and returns the last sequence number where a modification was detected.
|
||||
/// </summary>
|
||||
@ -234,6 +349,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
else
|
||||
{
|
||||
texture.DecrementReferenceCount();
|
||||
RemoveAliasList(texture);
|
||||
}
|
||||
}
|
||||
|
||||
@ -327,6 +443,8 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
{
|
||||
texture.DecrementReferenceCount();
|
||||
}
|
||||
|
||||
RemoveAliasList(texture);
|
||||
}
|
||||
|
||||
return null;
|
||||
@ -369,6 +487,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
if (Interlocked.Exchange(ref Items[id], null) != null)
|
||||
{
|
||||
texture.DecrementReferenceCount(this, id);
|
||||
RemoveAliasList(texture);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -622,6 +741,57 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
component == SwizzleComponent.Green;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Changes the format on the texture information structure, and also adjusts the width for the new format if needed.
|
||||
/// </summary>
|
||||
/// <param name="info">Texture information</param>
|
||||
/// <param name="dstFormat">New format</param>
|
||||
/// <returns>Texture information with the new format</returns>
|
||||
private static TextureInfo ChangeFormat(in TextureInfo info, FormatInfo dstFormat)
|
||||
{
|
||||
int width = info.Width;
|
||||
|
||||
if (info.FormatInfo.BytesPerPixel != dstFormat.BytesPerPixel)
|
||||
{
|
||||
int stride = width * info.FormatInfo.BytesPerPixel;
|
||||
width = stride / dstFormat.BytesPerPixel;
|
||||
}
|
||||
|
||||
return new TextureInfo(
|
||||
info.GpuAddress,
|
||||
width,
|
||||
info.Height,
|
||||
info.DepthOrLayers,
|
||||
info.Levels,
|
||||
info.SamplesInX,
|
||||
info.SamplesInY,
|
||||
info.Stride,
|
||||
info.IsLinear,
|
||||
info.GobBlocksInY,
|
||||
info.GobBlocksInZ,
|
||||
info.GobBlocksInTileX,
|
||||
info.Target,
|
||||
dstFormat,
|
||||
info.DepthStencilMode,
|
||||
info.SwizzleR,
|
||||
info.SwizzleG,
|
||||
info.SwizzleB,
|
||||
info.SwizzleA);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all aliases for a texture.
|
||||
/// </summary>
|
||||
/// <param name="texture">Texture to have the aliases removed</param>
|
||||
private void RemoveAliasList(Texture texture)
|
||||
{
|
||||
if (_aliasLists.TryGetValue(texture, out TextureAliasList aliasList))
|
||||
{
|
||||
_aliasLists.Remove(texture);
|
||||
aliasList.Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decrements the reference count of the texture.
|
||||
/// This indicates that the texture pool is not using it anymore.
|
||||
@ -629,7 +799,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
/// <param name="item">The texture to be deleted</param>
|
||||
protected override void Delete(Texture item)
|
||||
{
|
||||
item?.DecrementReferenceCount(this);
|
||||
if (item != null)
|
||||
{
|
||||
item.DecrementReferenceCount(this);
|
||||
RemoveAliasList(item);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
|
Reference in New Issue
Block a user