mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2025-07-25 06:17:10 +02: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:
parent
ccf96bf5e6
commit
eb8132b627
31 changed files with 294 additions and 279 deletions
|
@ -1,5 +1,6 @@
|
|||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Gpu.Image;
|
||||
using Ryujinx.Graphics.Shader;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Engine
|
||||
|
@ -61,51 +62,51 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
|||
/// </summary>
|
||||
/// <param name="format">Shader image format</param>
|
||||
/// <returns>Texture format</returns>
|
||||
public static Format GetFormat(TextureFormat format)
|
||||
public static FormatInfo GetFormatInfo(TextureFormat format)
|
||||
{
|
||||
return format switch
|
||||
{
|
||||
#pragma warning disable IDE0055 // Disable formatting
|
||||
TextureFormat.R8Unorm => Format.R8Unorm,
|
||||
TextureFormat.R8Snorm => Format.R8Snorm,
|
||||
TextureFormat.R8Uint => Format.R8Uint,
|
||||
TextureFormat.R8Sint => Format.R8Sint,
|
||||
TextureFormat.R16Float => Format.R16Float,
|
||||
TextureFormat.R16Unorm => Format.R16Unorm,
|
||||
TextureFormat.R16Snorm => Format.R16Snorm,
|
||||
TextureFormat.R16Uint => Format.R16Uint,
|
||||
TextureFormat.R16Sint => Format.R16Sint,
|
||||
TextureFormat.R32Float => Format.R32Float,
|
||||
TextureFormat.R32Uint => Format.R32Uint,
|
||||
TextureFormat.R32Sint => Format.R32Sint,
|
||||
TextureFormat.R8G8Unorm => Format.R8G8Unorm,
|
||||
TextureFormat.R8G8Snorm => Format.R8G8Snorm,
|
||||
TextureFormat.R8G8Uint => Format.R8G8Uint,
|
||||
TextureFormat.R8G8Sint => Format.R8G8Sint,
|
||||
TextureFormat.R16G16Float => Format.R16G16Float,
|
||||
TextureFormat.R16G16Unorm => Format.R16G16Unorm,
|
||||
TextureFormat.R16G16Snorm => Format.R16G16Snorm,
|
||||
TextureFormat.R16G16Uint => Format.R16G16Uint,
|
||||
TextureFormat.R16G16Sint => Format.R16G16Sint,
|
||||
TextureFormat.R32G32Float => Format.R32G32Float,
|
||||
TextureFormat.R32G32Uint => Format.R32G32Uint,
|
||||
TextureFormat.R32G32Sint => Format.R32G32Sint,
|
||||
TextureFormat.R8G8B8A8Unorm => Format.R8G8B8A8Unorm,
|
||||
TextureFormat.R8G8B8A8Snorm => Format.R8G8B8A8Snorm,
|
||||
TextureFormat.R8G8B8A8Uint => Format.R8G8B8A8Uint,
|
||||
TextureFormat.R8G8B8A8Sint => Format.R8G8B8A8Sint,
|
||||
TextureFormat.R16G16B16A16Float => Format.R16G16B16A16Float,
|
||||
TextureFormat.R16G16B16A16Unorm => Format.R16G16B16A16Unorm,
|
||||
TextureFormat.R16G16B16A16Snorm => Format.R16G16B16A16Snorm,
|
||||
TextureFormat.R16G16B16A16Uint => Format.R16G16B16A16Uint,
|
||||
TextureFormat.R16G16B16A16Sint => Format.R16G16B16A16Sint,
|
||||
TextureFormat.R32G32B32A32Float => Format.R32G32B32A32Float,
|
||||
TextureFormat.R32G32B32A32Uint => Format.R32G32B32A32Uint,
|
||||
TextureFormat.R32G32B32A32Sint => Format.R32G32B32A32Sint,
|
||||
TextureFormat.R10G10B10A2Unorm => Format.R10G10B10A2Unorm,
|
||||
TextureFormat.R10G10B10A2Uint => Format.R10G10B10A2Uint,
|
||||
TextureFormat.R11G11B10Float => Format.R11G11B10Float,
|
||||
_ => 0,
|
||||
TextureFormat.R8Unorm => new(Format.R8Unorm, 1, 1, 1, 1),
|
||||
TextureFormat.R8Snorm => new(Format.R8Snorm, 1, 1, 1, 1),
|
||||
TextureFormat.R8Uint => new(Format.R8Uint, 1, 1, 1, 1),
|
||||
TextureFormat.R8Sint => new(Format.R8Sint, 1, 1, 1, 1),
|
||||
TextureFormat.R16Float => new(Format.R16Float, 1, 1, 2, 1),
|
||||
TextureFormat.R16Unorm => new(Format.R16Unorm, 1, 1, 2, 1),
|
||||
TextureFormat.R16Snorm => new(Format.R16Snorm, 1, 1, 2, 1),
|
||||
TextureFormat.R16Uint => new(Format.R16Uint, 1, 1, 2, 1),
|
||||
TextureFormat.R16Sint => new(Format.R16Sint, 1, 1, 2, 1),
|
||||
TextureFormat.R32Float => new(Format.R32Float, 1, 1, 4, 1),
|
||||
TextureFormat.R32Uint => new(Format.R32Uint, 1, 1, 4, 1),
|
||||
TextureFormat.R32Sint => new(Format.R32Sint, 1, 1, 4, 1),
|
||||
TextureFormat.R8G8Unorm => new(Format.R8G8Unorm, 1, 1, 2, 2),
|
||||
TextureFormat.R8G8Snorm => new(Format.R8G8Snorm, 1, 1, 2, 2),
|
||||
TextureFormat.R8G8Uint => new(Format.R8G8Uint, 1, 1, 2, 2),
|
||||
TextureFormat.R8G8Sint => new(Format.R8G8Sint, 1, 1, 2, 2),
|
||||
TextureFormat.R16G16Float => new(Format.R16G16Float, 1, 1, 4, 2),
|
||||
TextureFormat.R16G16Unorm => new(Format.R16G16Unorm, 1, 1, 4, 2),
|
||||
TextureFormat.R16G16Snorm => new(Format.R16G16Snorm, 1, 1, 4, 2),
|
||||
TextureFormat.R16G16Uint => new(Format.R16G16Uint, 1, 1, 4, 2),
|
||||
TextureFormat.R16G16Sint => new(Format.R16G16Sint, 1, 1, 4, 2),
|
||||
TextureFormat.R32G32Float => new(Format.R32G32Float, 1, 1, 8, 2),
|
||||
TextureFormat.R32G32Uint => new(Format.R32G32Uint, 1, 1, 8, 2),
|
||||
TextureFormat.R32G32Sint => new(Format.R32G32Sint, 1, 1, 8, 2),
|
||||
TextureFormat.R8G8B8A8Unorm => new(Format.R8G8B8A8Unorm, 1, 1, 4, 4),
|
||||
TextureFormat.R8G8B8A8Snorm => new(Format.R8G8B8A8Snorm, 1, 1, 4, 4),
|
||||
TextureFormat.R8G8B8A8Uint => new(Format.R8G8B8A8Uint, 1, 1, 4, 4),
|
||||
TextureFormat.R8G8B8A8Sint => new(Format.R8G8B8A8Sint, 1, 1, 4, 4),
|
||||
TextureFormat.R16G16B16A16Float => new(Format.R16G16B16A16Float, 1, 1, 8, 4),
|
||||
TextureFormat.R16G16B16A16Unorm => new(Format.R16G16B16A16Unorm, 1, 1, 8, 4),
|
||||
TextureFormat.R16G16B16A16Snorm => new(Format.R16G16B16A16Snorm, 1, 1, 8, 4),
|
||||
TextureFormat.R16G16B16A16Uint => new(Format.R16G16B16A16Uint, 1, 1, 8, 4),
|
||||
TextureFormat.R16G16B16A16Sint => new(Format.R16G16B16A16Sint, 1, 1, 8, 4),
|
||||
TextureFormat.R32G32B32A32Float => new(Format.R32G32B32A32Float, 1, 1, 16, 4),
|
||||
TextureFormat.R32G32B32A32Uint => new(Format.R32G32B32A32Uint, 1, 1, 16, 4),
|
||||
TextureFormat.R32G32B32A32Sint => new(Format.R32G32B32A32Sint, 1, 1, 16, 4),
|
||||
TextureFormat.R10G10B10A2Unorm => new(Format.R10G10B10A2Unorm, 1, 1, 4, 4),
|
||||
TextureFormat.R10G10B10A2Uint => new(Format.R10G10B10A2Uint, 1, 1, 4, 4),
|
||||
TextureFormat.R11G11B10Float => new(Format.R11G11B10Float, 1, 1, 4, 3),
|
||||
_ => FormatInfo.Invalid,
|
||||
#pragma warning restore IDE0055
|
||||
};
|
||||
}
|
||||
|
|
|
@ -7,6 +7,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
/// </summary>
|
||||
readonly struct FormatInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// An invalid texture format.
|
||||
/// </summary>
|
||||
public static FormatInfo Invalid { get; } = new(0, 0, 0, 0, 0);
|
||||
|
||||
/// <summary>
|
||||
/// A default, generic RGBA8 texture format.
|
||||
/// </summary>
|
||||
|
@ -23,7 +28,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
/// <remarks>
|
||||
/// Must be 1 for non-compressed formats.
|
||||
/// </remarks>
|
||||
public int BlockWidth { get; }
|
||||
public byte BlockWidth { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The block height for compressed formats.
|
||||
|
@ -31,17 +36,17 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
/// <remarks>
|
||||
/// Must be 1 for non-compressed formats.
|
||||
/// </remarks>
|
||||
public int BlockHeight { get; }
|
||||
public byte BlockHeight { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of bytes occupied by a single pixel in memory of the texture data.
|
||||
/// </summary>
|
||||
public int BytesPerPixel { get; }
|
||||
public byte BytesPerPixel { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The maximum number of components this format has defined (in RGBA order).
|
||||
/// </summary>
|
||||
public int Components { get; }
|
||||
public byte Components { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Whenever or not the texture format is a compressed format. Determined from block size.
|
||||
|
@ -57,10 +62,10 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
/// <param name="bytesPerPixel">The number of bytes occupied by a single pixel in memory of the texture data</param>
|
||||
public FormatInfo(
|
||||
Format format,
|
||||
int blockWidth,
|
||||
int blockHeight,
|
||||
int bytesPerPixel,
|
||||
int components)
|
||||
byte blockWidth,
|
||||
byte blockHeight,
|
||||
byte bytesPerPixel,
|
||||
byte components)
|
||||
{
|
||||
Format = format;
|
||||
BlockWidth = blockWidth;
|
||||
|
|
|
@ -17,7 +17,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
/// <summary>
|
||||
/// For images, indicates the format specified on the shader.
|
||||
/// </summary>
|
||||
public Format Format { get; }
|
||||
public FormatInfo FormatInfo { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Shader texture host set index.
|
||||
|
@ -58,17 +58,17 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
/// Constructs the texture binding information structure.
|
||||
/// </summary>
|
||||
/// <param name="target">The shader sampler target type</param>
|
||||
/// <param name="format">Format of the image as declared on the shader</param>
|
||||
/// <param name="formatInfo">Format of the image as declared on the shader</param>
|
||||
/// <param name="set">Shader texture host set index</param>
|
||||
/// <param name="binding">The shader texture binding point</param>
|
||||
/// <param name="arrayLength">For array of textures, this indicates the length of the array. A value of one indicates it is not an array</param>
|
||||
/// <param name="cbufSlot">Constant buffer slot where the texture handle is located</param>
|
||||
/// <param name="handle">The shader texture handle (read index into the texture constant buffer)</param>
|
||||
/// <param name="flags">The texture's usage flags, indicating how it is used in the shader</param>
|
||||
public TextureBindingInfo(Target target, Format format, int set, int binding, int arrayLength, int cbufSlot, int handle, TextureUsageFlags flags)
|
||||
public TextureBindingInfo(Target target, FormatInfo formatInfo, int set, int binding, int arrayLength, int cbufSlot, int handle, TextureUsageFlags flags)
|
||||
{
|
||||
Target = target;
|
||||
Format = format;
|
||||
FormatInfo = formatInfo;
|
||||
Set = set;
|
||||
Binding = binding;
|
||||
ArrayLength = arrayLength;
|
||||
|
@ -96,7 +96,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
int cbufSlot,
|
||||
int handle,
|
||||
TextureUsageFlags flags,
|
||||
bool isSamplerOnly) : this(target, 0, set, binding, arrayLength, cbufSlot, handle, flags)
|
||||
bool isSamplerOnly) : this(target, FormatInfo.Invalid, set, binding, arrayLength, cbufSlot, handle, flags)
|
||||
{
|
||||
IsSamplerOnly = isSamplerOnly;
|
||||
}
|
||||
|
|
|
@ -659,7 +659,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
int length = (isSampler ? samplerPool.MaximumId : texturePool.MaximumId) + 1;
|
||||
length = Math.Min(length, bindingInfo.ArrayLength);
|
||||
|
||||
Format[] formats = isImage ? new Format[bindingInfo.ArrayLength] : null;
|
||||
ISampler[] samplers = isImage ? null : new ISampler[bindingInfo.ArrayLength];
|
||||
ITexture[] textures = new ITexture[bindingInfo.ArrayLength];
|
||||
|
||||
|
@ -674,7 +673,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
}
|
||||
else
|
||||
{
|
||||
ref readonly TextureDescriptor descriptor = ref texturePool.GetForBinding(index, out texture);
|
||||
ref readonly TextureDescriptor descriptor = ref texturePool.GetForBinding(index, bindingInfo.FormatInfo, out texture);
|
||||
|
||||
if (texture != null)
|
||||
{
|
||||
|
@ -697,8 +696,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
ITexture hostTexture = texture?.GetTargetTexture(bindingInfo.Target);
|
||||
ISampler hostSampler = sampler?.GetHostSampler(texture);
|
||||
|
||||
Format format = bindingInfo.Format;
|
||||
|
||||
if (hostTexture != null && texture.Target == Target.TextureBuffer)
|
||||
{
|
||||
// Ensure that the buffer texture is using the correct buffer as storage.
|
||||
|
@ -706,26 +703,15 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
// to ensure we're not using a old buffer that was already deleted.
|
||||
if (isImage)
|
||||
{
|
||||
if (format == 0 && texture != null)
|
||||
{
|
||||
format = texture.Format;
|
||||
}
|
||||
|
||||
_channel.BufferManager.SetBufferTextureStorage(stage, entry.ImageArray, hostTexture, texture.Range, bindingInfo, index, format);
|
||||
_channel.BufferManager.SetBufferTextureStorage(stage, entry.ImageArray, hostTexture, texture.Range, bindingInfo, index);
|
||||
}
|
||||
else
|
||||
{
|
||||
_channel.BufferManager.SetBufferTextureStorage(stage, entry.TextureArray, hostTexture, texture.Range, bindingInfo, index, format);
|
||||
_channel.BufferManager.SetBufferTextureStorage(stage, entry.TextureArray, hostTexture, texture.Range, bindingInfo, index);
|
||||
}
|
||||
}
|
||||
else if (isImage)
|
||||
{
|
||||
if (format == 0 && texture != null)
|
||||
{
|
||||
format = texture.Format;
|
||||
}
|
||||
|
||||
formats[index] = format;
|
||||
textures[index] = hostTexture;
|
||||
}
|
||||
else
|
||||
|
@ -737,7 +723,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
|
||||
if (isImage)
|
||||
{
|
||||
entry.ImageArray.SetFormats(0, formats);
|
||||
entry.ImageArray.SetImages(0, textures);
|
||||
|
||||
SetImageArray(stage, bindingInfo, entry.ImageArray);
|
||||
|
@ -863,7 +848,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
|
||||
entry.UpdateData(cachedTextureBuffer, cachedSamplerBuffer, separateSamplerBuffer);
|
||||
|
||||
Format[] formats = isImage ? new Format[bindingInfo.ArrayLength] : null;
|
||||
ISampler[] samplers = isImage ? null : new ISampler[bindingInfo.ArrayLength];
|
||||
ITexture[] textures = new ITexture[bindingInfo.ArrayLength];
|
||||
|
||||
|
@ -883,7 +867,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
samplerId = TextureHandle.UnpackSamplerId(packedId);
|
||||
}
|
||||
|
||||
ref readonly TextureDescriptor descriptor = ref texturePool.GetForBinding(textureId, out Texture texture);
|
||||
ref readonly TextureDescriptor descriptor = ref texturePool.GetForBinding(textureId, bindingInfo.FormatInfo, out Texture texture);
|
||||
|
||||
if (texture != null)
|
||||
{
|
||||
|
@ -916,8 +900,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
hostSampler = sampler?.GetHostSampler(texture);
|
||||
}
|
||||
|
||||
Format format = bindingInfo.Format;
|
||||
|
||||
if (hostTexture != null && texture.Target == Target.TextureBuffer)
|
||||
{
|
||||
// Ensure that the buffer texture is using the correct buffer as storage.
|
||||
|
@ -925,26 +907,15 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
// to ensure we're not using a old buffer that was already deleted.
|
||||
if (isImage)
|
||||
{
|
||||
if (format == 0 && texture != null)
|
||||
{
|
||||
format = texture.Format;
|
||||
}
|
||||
|
||||
_channel.BufferManager.SetBufferTextureStorage(stage, entry.ImageArray, hostTexture, texture.Range, bindingInfo, index, format);
|
||||
_channel.BufferManager.SetBufferTextureStorage(stage, entry.ImageArray, hostTexture, texture.Range, bindingInfo, index);
|
||||
}
|
||||
else
|
||||
{
|
||||
_channel.BufferManager.SetBufferTextureStorage(stage, entry.TextureArray, hostTexture, texture.Range, bindingInfo, index, format);
|
||||
_channel.BufferManager.SetBufferTextureStorage(stage, entry.TextureArray, hostTexture, texture.Range, bindingInfo, index);
|
||||
}
|
||||
}
|
||||
else if (isImage)
|
||||
{
|
||||
if (format == 0 && texture != null)
|
||||
{
|
||||
format = texture.Format;
|
||||
}
|
||||
|
||||
formats[index] = format;
|
||||
textures[index] = hostTexture;
|
||||
}
|
||||
else
|
||||
|
@ -956,7 +927,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
|
||||
if (isImage)
|
||||
{
|
||||
entry.ImageArray.SetFormats(0, formats);
|
||||
entry.ImageArray.SetImages(0, textures);
|
||||
|
||||
SetImageArray(stage, bindingInfo, entry.ImageArray);
|
||||
|
|
|
@ -522,7 +522,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
// Ensure that the buffer texture is using the correct buffer as storage.
|
||||
// Buffers are frequently re-created to accommodate larger data, so we need to re-bind
|
||||
// to ensure we're not using a old buffer that was already deleted.
|
||||
_channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, texture.Range, bindingInfo, bindingInfo.Format, false);
|
||||
_channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, texture.Range, bindingInfo, false);
|
||||
|
||||
// Cache is not used for buffer texture, it must always rebind.
|
||||
state.CachedTexture = null;
|
||||
|
@ -616,6 +616,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
|
||||
if (!poolModified &&
|
||||
state.TextureHandle == textureId &&
|
||||
state.ImageFormat == bindingInfo.FormatInfo.Format &&
|
||||
state.CachedTexture != null &&
|
||||
state.CachedTexture.InvalidatedSequence == state.InvalidatedSequence)
|
||||
{
|
||||
|
@ -629,26 +630,22 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
cachedTexture.SignalModified();
|
||||
}
|
||||
|
||||
Format format = bindingInfo.Format == 0 ? cachedTexture.Format : bindingInfo.Format;
|
||||
|
||||
if (state.ImageFormat != format ||
|
||||
((usageFlags & TextureUsageFlags.NeedsScaleValue) != 0 &&
|
||||
UpdateScale(state.CachedTexture, usageFlags, scaleIndex, stage)))
|
||||
if ((usageFlags & TextureUsageFlags.NeedsScaleValue) != 0 && UpdateScale(state.CachedTexture, usageFlags, scaleIndex, stage))
|
||||
{
|
||||
ITexture hostTextureRebind = state.CachedTexture.GetTargetTexture(bindingInfo.Target);
|
||||
|
||||
state.Texture = hostTextureRebind;
|
||||
state.ImageFormat = format;
|
||||
|
||||
_context.Renderer.Pipeline.SetImage(stage, bindingInfo.Binding, hostTextureRebind, format);
|
||||
_context.Renderer.Pipeline.SetImage(stage, bindingInfo.Binding, hostTextureRebind);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
state.TextureHandle = textureId;
|
||||
state.ImageFormat = bindingInfo.FormatInfo.Format;
|
||||
|
||||
ref readonly TextureDescriptor descriptor = ref pool.GetForBinding(textureId, out Texture texture);
|
||||
ref readonly TextureDescriptor descriptor = ref pool.GetForBinding(textureId, bindingInfo.FormatInfo, out Texture texture);
|
||||
|
||||
specStateMatches &= specState.MatchesImage(stage, index, descriptor);
|
||||
|
||||
|
@ -660,14 +657,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
// Buffers are frequently re-created to accommodate larger data, so we need to re-bind
|
||||
// to ensure we're not using a old buffer that was already deleted.
|
||||
|
||||
Format format = bindingInfo.Format;
|
||||
|
||||
if (format == 0 && texture != null)
|
||||
{
|
||||
format = texture.Format;
|
||||
}
|
||||
|
||||
_channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, texture.Range, bindingInfo, format, true);
|
||||
_channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, texture.Range, bindingInfo, true);
|
||||
|
||||
// Cache is not used for buffer texture, it must always rebind.
|
||||
state.CachedTexture = null;
|
||||
|
@ -689,16 +679,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
{
|
||||
state.Texture = hostTexture;
|
||||
|
||||
Format format = bindingInfo.Format;
|
||||
|
||||
if (format == 0 && texture != null)
|
||||
{
|
||||
format = texture.Format;
|
||||
}
|
||||
|
||||
state.ImageFormat = format;
|
||||
|
||||
_context.Renderer.Pipeline.SetImage(stage, bindingInfo.Binding, hostTexture, format);
|
||||
_context.Renderer.Pipeline.SetImage(stage, bindingInfo.Binding, hostTexture);
|
||||
}
|
||||
|
||||
state.CachedTexture = texture;
|
||||
|
|
|
@ -739,7 +739,8 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
}
|
||||
|
||||
return (lhsFormat.Format == Format.R8G8B8A8Unorm && rhsFormat.Format == Format.R32G32B32A32Float) ||
|
||||
(lhsFormat.Format == Format.R8Unorm && rhsFormat.Format == Format.R8G8B8A8Unorm);
|
||||
(lhsFormat.Format == Format.R8Unorm && rhsFormat.Format == Format.R8G8B8A8Unorm) ||
|
||||
(lhsFormat.Format == Format.R8Unorm && rhsFormat.Format == Format.R32Uint);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -509,7 +509,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
|
||||
if (binding.IsImage)
|
||||
{
|
||||
_context.Renderer.Pipeline.SetImage(binding.Stage, binding.BindingInfo.Binding, binding.Texture, binding.Format);
|
||||
_context.Renderer.Pipeline.SetImage(binding.Stage, binding.BindingInfo.Binding, binding.Texture);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -873,12 +873,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
ITexture texture,
|
||||
MultiRange range,
|
||||
TextureBindingInfo bindingInfo,
|
||||
Format format,
|
||||
bool isImage)
|
||||
{
|
||||
_channel.MemoryManager.Physical.BufferCache.CreateBuffer(range, BufferStageUtils.TextureBuffer(stage, bindingInfo.Flags));
|
||||
|
||||
_bufferTextures.Add(new BufferTextureBinding(stage, texture, range, bindingInfo, format, isImage));
|
||||
_bufferTextures.Add(new BufferTextureBinding(stage, texture, range, bindingInfo, isImage));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -897,12 +896,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
ITexture texture,
|
||||
MultiRange range,
|
||||
TextureBindingInfo bindingInfo,
|
||||
int index,
|
||||
Format format)
|
||||
int index)
|
||||
{
|
||||
_channel.MemoryManager.Physical.BufferCache.CreateBuffer(range, BufferStageUtils.TextureBuffer(stage, bindingInfo.Flags));
|
||||
|
||||
_bufferTextureArrays.Add(new BufferTextureArrayBinding<ITextureArray>(array, texture, range, bindingInfo, index, format));
|
||||
_bufferTextureArrays.Add(new BufferTextureArrayBinding<ITextureArray>(array, texture, range, bindingInfo, index));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -921,12 +919,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
ITexture texture,
|
||||
MultiRange range,
|
||||
TextureBindingInfo bindingInfo,
|
||||
int index,
|
||||
Format format)
|
||||
int index)
|
||||
{
|
||||
_channel.MemoryManager.Physical.BufferCache.CreateBuffer(range, BufferStageUtils.TextureBuffer(stage, bindingInfo.Flags));
|
||||
|
||||
_bufferImageArrays.Add(new BufferTextureArrayBinding<IImageArray>(array, texture, range, bindingInfo, index, format));
|
||||
_bufferImageArrays.Add(new BufferTextureArrayBinding<IImageArray>(array, texture, range, bindingInfo, index));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -34,33 +34,26 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
/// </summary>
|
||||
public int Index { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The image format for the binding.
|
||||
/// </summary>
|
||||
public Format Format { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new buffer texture binding.
|
||||
/// </summary>
|
||||
/// <param name="array">Array</param>
|
||||
/// <param name="texture">Buffer texture</param>
|
||||
/// <param name="range">Physical ranges of memory where the buffer texture data is located</param>
|
||||
/// <param name="bindingInfo">Binding info</param>
|
||||
/// <param name="index">Index of the binding on the array</param>
|
||||
/// <param name="format">Binding format</param>
|
||||
public BufferTextureArrayBinding(
|
||||
T array,
|
||||
ITexture texture,
|
||||
MultiRange range,
|
||||
TextureBindingInfo bindingInfo,
|
||||
int index,
|
||||
Format format)
|
||||
int index)
|
||||
{
|
||||
Array = array;
|
||||
Texture = texture;
|
||||
Range = range;
|
||||
BindingInfo = bindingInfo;
|
||||
Index = index;
|
||||
Format = format;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,11 +30,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
/// </summary>
|
||||
public TextureBindingInfo BindingInfo { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The image format for the binding.
|
||||
/// </summary>
|
||||
public Format Format { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether the binding is for an image or a sampler.
|
||||
/// </summary>
|
||||
|
@ -47,21 +42,18 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
/// <param name="texture">Buffer texture</param>
|
||||
/// <param name="range">Physical ranges of memory where the buffer texture data is located</param>
|
||||
/// <param name="bindingInfo">Binding info</param>
|
||||
/// <param name="format">Binding format</param>
|
||||
/// <param name="isImage">Whether the binding is for an image or a sampler</param>
|
||||
public BufferTextureBinding(
|
||||
ShaderStage stage,
|
||||
ITexture texture,
|
||||
MultiRange range,
|
||||
TextureBindingInfo bindingInfo,
|
||||
Format format,
|
||||
bool isImage)
|
||||
{
|
||||
Stage = stage;
|
||||
Texture = texture;
|
||||
Range = range;
|
||||
BindingInfo = bindingInfo;
|
||||
Format = format;
|
||||
IsImage = isImage;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -86,11 +86,11 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||
ImageBindings[i] = stage.Info.Images.Select(descriptor =>
|
||||
{
|
||||
Target target = ShaderTexture.GetTarget(descriptor.Type);
|
||||
Format format = ShaderTexture.GetFormat(descriptor.Format);
|
||||
FormatInfo formatInfo = ShaderTexture.GetFormatInfo(descriptor.Format);
|
||||
|
||||
var result = new TextureBindingInfo(
|
||||
target,
|
||||
format,
|
||||
formatInfo,
|
||||
descriptor.Set,
|
||||
descriptor.Binding,
|
||||
descriptor.ArrayLength,
|
||||
|
|
|
@ -131,7 +131,7 @@ namespace Ryujinx.Graphics.Gpu
|
|||
bool isLinear,
|
||||
int gobBlocksInY,
|
||||
Format format,
|
||||
int bytesPerPixel,
|
||||
byte bytesPerPixel,
|
||||
ImageCrop crop,
|
||||
Action<GpuContext, object> acquireCallback,
|
||||
Action<object> releaseCallback,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue