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:
gdkchan 2024-09-17 15:52:30 -03:00 committed by GitHub
parent ccf96bf5e6
commit eb8132b627
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
31 changed files with 294 additions and 279 deletions

View File

@ -4,7 +4,6 @@ namespace Ryujinx.Graphics.GAL
{ {
public interface IImageArray : IDisposable public interface IImageArray : IDisposable
{ {
void SetFormats(int index, Format[] imageFormats);
void SetImages(int index, ITexture[] images); void SetImages(int index, ITexture[] images);
} }
} }

View File

@ -58,7 +58,7 @@ namespace Ryujinx.Graphics.GAL
void SetIndexBuffer(BufferRange buffer, IndexType type); void SetIndexBuffer(BufferRange buffer, IndexType type);
void SetImage(ShaderStage stage, int binding, ITexture texture, Format imageFormat); void SetImage(ShaderStage stage, int binding, ITexture texture);
void SetImageArray(ShaderStage stage, int binding, IImageArray array); void SetImageArray(ShaderStage stage, int binding, IImageArray array);
void SetImageArraySeparate(ShaderStage stage, int setIndex, IImageArray array); void SetImageArraySeparate(ShaderStage stage, int setIndex, IImageArray array);

View File

@ -67,7 +67,6 @@ namespace Ryujinx.Graphics.GAL.Multithreading
Register<CounterEventFlushCommand>(CommandType.CounterEventFlush); Register<CounterEventFlushCommand>(CommandType.CounterEventFlush);
Register<ImageArrayDisposeCommand>(CommandType.ImageArrayDispose); Register<ImageArrayDisposeCommand>(CommandType.ImageArrayDispose);
Register<ImageArraySetFormatsCommand>(CommandType.ImageArraySetFormats);
Register<ImageArraySetImagesCommand>(CommandType.ImageArraySetImages); Register<ImageArraySetImagesCommand>(CommandType.ImageArraySetImages);
Register<ProgramDisposeCommand>(CommandType.ProgramDispose); Register<ProgramDisposeCommand>(CommandType.ProgramDispose);

View File

@ -27,7 +27,6 @@ namespace Ryujinx.Graphics.GAL.Multithreading
CounterEventFlush, CounterEventFlush,
ImageArrayDispose, ImageArrayDispose,
ImageArraySetFormats,
ImageArraySetImages, ImageArraySetImages,
ProgramDispose, ProgramDispose,

View File

@ -1,26 +0,0 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.ImageArray
{
struct ImageArraySetFormatsCommand : IGALCommand, IGALCommand<ImageArraySetFormatsCommand>
{
public readonly CommandType CommandType => CommandType.ImageArraySetFormats;
private TableRef<ThreadedImageArray> _imageArray;
private int _index;
private TableRef<Format[]> _imageFormats;
public void Set(TableRef<ThreadedImageArray> imageArray, int index, TableRef<Format[]> imageFormats)
{
_imageArray = imageArray;
_index = index;
_imageFormats = imageFormats;
}
public static void Run(ref ImageArraySetFormatsCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
ThreadedImageArray imageArray = command._imageArray.Get(threaded);
imageArray.Base.SetFormats(command._index, command._imageFormats.Get(threaded));
}
}
}

View File

@ -10,19 +10,17 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands
private ShaderStage _stage; private ShaderStage _stage;
private int _binding; private int _binding;
private TableRef<ITexture> _texture; private TableRef<ITexture> _texture;
private Format _imageFormat;
public void Set(ShaderStage stage, int binding, TableRef<ITexture> texture, Format imageFormat) public void Set(ShaderStage stage, int binding, TableRef<ITexture> texture)
{ {
_stage = stage; _stage = stage;
_binding = binding; _binding = binding;
_texture = texture; _texture = texture;
_imageFormat = imageFormat;
} }
public static void Run(ref SetImageCommand command, ThreadedRenderer threaded, IRenderer renderer) public static void Run(ref SetImageCommand command, ThreadedRenderer threaded, IRenderer renderer)
{ {
renderer.Pipeline.SetImage(command._stage, command._binding, command._texture.GetAs<ThreadedTexture>(threaded)?.Base, command._imageFormat); renderer.Pipeline.SetImage(command._stage, command._binding, command._texture.GetAs<ThreadedTexture>(threaded)?.Base);
} }
} }
} }

View File

@ -27,12 +27,6 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetFormats(int index, Format[] imageFormats)
{
_renderer.New<ImageArraySetFormatsCommand>().Set(Ref(this), index, Ref(imageFormats));
_renderer.QueueCommand();
}
public void SetImages(int index, ITexture[] images) public void SetImages(int index, ITexture[] images)
{ {
_renderer.New<ImageArraySetImagesCommand>().Set(Ref(this), index, Ref(images)); _renderer.New<ImageArraySetImagesCommand>().Set(Ref(this), index, Ref(images));

View File

@ -177,9 +177,9 @@ namespace Ryujinx.Graphics.GAL.Multithreading
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetImage(ShaderStage stage, int binding, ITexture texture, Format imageFormat) public void SetImage(ShaderStage stage, int binding, ITexture texture)
{ {
_renderer.New<SetImageCommand>().Set(stage, binding, Ref(texture), imageFormat); _renderer.New<SetImageCommand>().Set(stage, binding, Ref(texture));
_renderer.QueueCommand(); _renderer.QueueCommand();
} }

View File

@ -1,5 +1,6 @@
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu.Image;
using Ryujinx.Graphics.Shader; using Ryujinx.Graphics.Shader;
namespace Ryujinx.Graphics.Gpu.Engine namespace Ryujinx.Graphics.Gpu.Engine
@ -61,51 +62,51 @@ namespace Ryujinx.Graphics.Gpu.Engine
/// </summary> /// </summary>
/// <param name="format">Shader image format</param> /// <param name="format">Shader image format</param>
/// <returns>Texture format</returns> /// <returns>Texture format</returns>
public static Format GetFormat(TextureFormat format) public static FormatInfo GetFormatInfo(TextureFormat format)
{ {
return format switch return format switch
{ {
#pragma warning disable IDE0055 // Disable formatting #pragma warning disable IDE0055 // Disable formatting
TextureFormat.R8Unorm => Format.R8Unorm, TextureFormat.R8Unorm => new(Format.R8Unorm, 1, 1, 1, 1),
TextureFormat.R8Snorm => Format.R8Snorm, TextureFormat.R8Snorm => new(Format.R8Snorm, 1, 1, 1, 1),
TextureFormat.R8Uint => Format.R8Uint, TextureFormat.R8Uint => new(Format.R8Uint, 1, 1, 1, 1),
TextureFormat.R8Sint => Format.R8Sint, TextureFormat.R8Sint => new(Format.R8Sint, 1, 1, 1, 1),
TextureFormat.R16Float => Format.R16Float, TextureFormat.R16Float => new(Format.R16Float, 1, 1, 2, 1),
TextureFormat.R16Unorm => Format.R16Unorm, TextureFormat.R16Unorm => new(Format.R16Unorm, 1, 1, 2, 1),
TextureFormat.R16Snorm => Format.R16Snorm, TextureFormat.R16Snorm => new(Format.R16Snorm, 1, 1, 2, 1),
TextureFormat.R16Uint => Format.R16Uint, TextureFormat.R16Uint => new(Format.R16Uint, 1, 1, 2, 1),
TextureFormat.R16Sint => Format.R16Sint, TextureFormat.R16Sint => new(Format.R16Sint, 1, 1, 2, 1),
TextureFormat.R32Float => Format.R32Float, TextureFormat.R32Float => new(Format.R32Float, 1, 1, 4, 1),
TextureFormat.R32Uint => Format.R32Uint, TextureFormat.R32Uint => new(Format.R32Uint, 1, 1, 4, 1),
TextureFormat.R32Sint => Format.R32Sint, TextureFormat.R32Sint => new(Format.R32Sint, 1, 1, 4, 1),
TextureFormat.R8G8Unorm => Format.R8G8Unorm, TextureFormat.R8G8Unorm => new(Format.R8G8Unorm, 1, 1, 2, 2),
TextureFormat.R8G8Snorm => Format.R8G8Snorm, TextureFormat.R8G8Snorm => new(Format.R8G8Snorm, 1, 1, 2, 2),
TextureFormat.R8G8Uint => Format.R8G8Uint, TextureFormat.R8G8Uint => new(Format.R8G8Uint, 1, 1, 2, 2),
TextureFormat.R8G8Sint => Format.R8G8Sint, TextureFormat.R8G8Sint => new(Format.R8G8Sint, 1, 1, 2, 2),
TextureFormat.R16G16Float => Format.R16G16Float, TextureFormat.R16G16Float => new(Format.R16G16Float, 1, 1, 4, 2),
TextureFormat.R16G16Unorm => Format.R16G16Unorm, TextureFormat.R16G16Unorm => new(Format.R16G16Unorm, 1, 1, 4, 2),
TextureFormat.R16G16Snorm => Format.R16G16Snorm, TextureFormat.R16G16Snorm => new(Format.R16G16Snorm, 1, 1, 4, 2),
TextureFormat.R16G16Uint => Format.R16G16Uint, TextureFormat.R16G16Uint => new(Format.R16G16Uint, 1, 1, 4, 2),
TextureFormat.R16G16Sint => Format.R16G16Sint, TextureFormat.R16G16Sint => new(Format.R16G16Sint, 1, 1, 4, 2),
TextureFormat.R32G32Float => Format.R32G32Float, TextureFormat.R32G32Float => new(Format.R32G32Float, 1, 1, 8, 2),
TextureFormat.R32G32Uint => Format.R32G32Uint, TextureFormat.R32G32Uint => new(Format.R32G32Uint, 1, 1, 8, 2),
TextureFormat.R32G32Sint => Format.R32G32Sint, TextureFormat.R32G32Sint => new(Format.R32G32Sint, 1, 1, 8, 2),
TextureFormat.R8G8B8A8Unorm => Format.R8G8B8A8Unorm, TextureFormat.R8G8B8A8Unorm => new(Format.R8G8B8A8Unorm, 1, 1, 4, 4),
TextureFormat.R8G8B8A8Snorm => Format.R8G8B8A8Snorm, TextureFormat.R8G8B8A8Snorm => new(Format.R8G8B8A8Snorm, 1, 1, 4, 4),
TextureFormat.R8G8B8A8Uint => Format.R8G8B8A8Uint, TextureFormat.R8G8B8A8Uint => new(Format.R8G8B8A8Uint, 1, 1, 4, 4),
TextureFormat.R8G8B8A8Sint => Format.R8G8B8A8Sint, TextureFormat.R8G8B8A8Sint => new(Format.R8G8B8A8Sint, 1, 1, 4, 4),
TextureFormat.R16G16B16A16Float => Format.R16G16B16A16Float, TextureFormat.R16G16B16A16Float => new(Format.R16G16B16A16Float, 1, 1, 8, 4),
TextureFormat.R16G16B16A16Unorm => Format.R16G16B16A16Unorm, TextureFormat.R16G16B16A16Unorm => new(Format.R16G16B16A16Unorm, 1, 1, 8, 4),
TextureFormat.R16G16B16A16Snorm => Format.R16G16B16A16Snorm, TextureFormat.R16G16B16A16Snorm => new(Format.R16G16B16A16Snorm, 1, 1, 8, 4),
TextureFormat.R16G16B16A16Uint => Format.R16G16B16A16Uint, TextureFormat.R16G16B16A16Uint => new(Format.R16G16B16A16Uint, 1, 1, 8, 4),
TextureFormat.R16G16B16A16Sint => Format.R16G16B16A16Sint, TextureFormat.R16G16B16A16Sint => new(Format.R16G16B16A16Sint, 1, 1, 8, 4),
TextureFormat.R32G32B32A32Float => Format.R32G32B32A32Float, TextureFormat.R32G32B32A32Float => new(Format.R32G32B32A32Float, 1, 1, 16, 4),
TextureFormat.R32G32B32A32Uint => Format.R32G32B32A32Uint, TextureFormat.R32G32B32A32Uint => new(Format.R32G32B32A32Uint, 1, 1, 16, 4),
TextureFormat.R32G32B32A32Sint => Format.R32G32B32A32Sint, TextureFormat.R32G32B32A32Sint => new(Format.R32G32B32A32Sint, 1, 1, 16, 4),
TextureFormat.R10G10B10A2Unorm => Format.R10G10B10A2Unorm, TextureFormat.R10G10B10A2Unorm => new(Format.R10G10B10A2Unorm, 1, 1, 4, 4),
TextureFormat.R10G10B10A2Uint => Format.R10G10B10A2Uint, TextureFormat.R10G10B10A2Uint => new(Format.R10G10B10A2Uint, 1, 1, 4, 4),
TextureFormat.R11G11B10Float => Format.R11G11B10Float, TextureFormat.R11G11B10Float => new(Format.R11G11B10Float, 1, 1, 4, 3),
_ => 0, _ => FormatInfo.Invalid,
#pragma warning restore IDE0055 #pragma warning restore IDE0055
}; };
} }

View File

@ -7,6 +7,11 @@ namespace Ryujinx.Graphics.Gpu.Image
/// </summary> /// </summary>
readonly struct FormatInfo readonly struct FormatInfo
{ {
/// <summary>
/// An invalid texture format.
/// </summary>
public static FormatInfo Invalid { get; } = new(0, 0, 0, 0, 0);
/// <summary> /// <summary>
/// A default, generic RGBA8 texture format. /// A default, generic RGBA8 texture format.
/// </summary> /// </summary>
@ -23,7 +28,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <remarks> /// <remarks>
/// Must be 1 for non-compressed formats. /// Must be 1 for non-compressed formats.
/// </remarks> /// </remarks>
public int BlockWidth { get; } public byte BlockWidth { get; }
/// <summary> /// <summary>
/// The block height for compressed formats. /// The block height for compressed formats.
@ -31,17 +36,17 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <remarks> /// <remarks>
/// Must be 1 for non-compressed formats. /// Must be 1 for non-compressed formats.
/// </remarks> /// </remarks>
public int BlockHeight { get; } public byte BlockHeight { get; }
/// <summary> /// <summary>
/// The number of bytes occupied by a single pixel in memory of the texture data. /// The number of bytes occupied by a single pixel in memory of the texture data.
/// </summary> /// </summary>
public int BytesPerPixel { get; } public byte BytesPerPixel { get; }
/// <summary> /// <summary>
/// The maximum number of components this format has defined (in RGBA order). /// The maximum number of components this format has defined (in RGBA order).
/// </summary> /// </summary>
public int Components { get; } public byte Components { get; }
/// <summary> /// <summary>
/// Whenever or not the texture format is a compressed format. Determined from block size. /// 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> /// <param name="bytesPerPixel">The number of bytes occupied by a single pixel in memory of the texture data</param>
public FormatInfo( public FormatInfo(
Format format, Format format,
int blockWidth, byte blockWidth,
int blockHeight, byte blockHeight,
int bytesPerPixel, byte bytesPerPixel,
int components) byte components)
{ {
Format = format; Format = format;
BlockWidth = blockWidth; BlockWidth = blockWidth;

View File

@ -17,7 +17,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <summary> /// <summary>
/// For images, indicates the format specified on the shader. /// For images, indicates the format specified on the shader.
/// </summary> /// </summary>
public Format Format { get; } public FormatInfo FormatInfo { get; }
/// <summary> /// <summary>
/// Shader texture host set index. /// Shader texture host set index.
@ -58,17 +58,17 @@ namespace Ryujinx.Graphics.Gpu.Image
/// Constructs the texture binding information structure. /// Constructs the texture binding information structure.
/// </summary> /// </summary>
/// <param name="target">The shader sampler target type</param> /// <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="set">Shader texture host set index</param>
/// <param name="binding">The shader texture binding point</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="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="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="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> /// <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; Target = target;
Format = format; FormatInfo = formatInfo;
Set = set; Set = set;
Binding = binding; Binding = binding;
ArrayLength = arrayLength; ArrayLength = arrayLength;
@ -96,7 +96,7 @@ namespace Ryujinx.Graphics.Gpu.Image
int cbufSlot, int cbufSlot,
int handle, int handle,
TextureUsageFlags flags, 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; IsSamplerOnly = isSamplerOnly;
} }

View File

@ -659,7 +659,6 @@ namespace Ryujinx.Graphics.Gpu.Image
int length = (isSampler ? samplerPool.MaximumId : texturePool.MaximumId) + 1; int length = (isSampler ? samplerPool.MaximumId : texturePool.MaximumId) + 1;
length = Math.Min(length, bindingInfo.ArrayLength); length = Math.Min(length, bindingInfo.ArrayLength);
Format[] formats = isImage ? new Format[bindingInfo.ArrayLength] : null;
ISampler[] samplers = isImage ? null : new ISampler[bindingInfo.ArrayLength]; ISampler[] samplers = isImage ? null : new ISampler[bindingInfo.ArrayLength];
ITexture[] textures = new ITexture[bindingInfo.ArrayLength]; ITexture[] textures = new ITexture[bindingInfo.ArrayLength];
@ -674,7 +673,7 @@ namespace Ryujinx.Graphics.Gpu.Image
} }
else 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) if (texture != null)
{ {
@ -697,8 +696,6 @@ namespace Ryujinx.Graphics.Gpu.Image
ITexture hostTexture = texture?.GetTargetTexture(bindingInfo.Target); ITexture hostTexture = texture?.GetTargetTexture(bindingInfo.Target);
ISampler hostSampler = sampler?.GetHostSampler(texture); ISampler hostSampler = sampler?.GetHostSampler(texture);
Format format = bindingInfo.Format;
if (hostTexture != null && texture.Target == Target.TextureBuffer) if (hostTexture != null && texture.Target == Target.TextureBuffer)
{ {
// Ensure that the buffer texture is using the correct buffer as storage. // 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. // to ensure we're not using a old buffer that was already deleted.
if (isImage) if (isImage)
{ {
if (format == 0 && texture != null) _channel.BufferManager.SetBufferTextureStorage(stage, entry.ImageArray, hostTexture, texture.Range, bindingInfo, index);
{
format = texture.Format;
}
_channel.BufferManager.SetBufferTextureStorage(stage, entry.ImageArray, hostTexture, texture.Range, bindingInfo, index, format);
} }
else 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) else if (isImage)
{ {
if (format == 0 && texture != null)
{
format = texture.Format;
}
formats[index] = format;
textures[index] = hostTexture; textures[index] = hostTexture;
} }
else else
@ -737,7 +723,6 @@ namespace Ryujinx.Graphics.Gpu.Image
if (isImage) if (isImage)
{ {
entry.ImageArray.SetFormats(0, formats);
entry.ImageArray.SetImages(0, textures); entry.ImageArray.SetImages(0, textures);
SetImageArray(stage, bindingInfo, entry.ImageArray); SetImageArray(stage, bindingInfo, entry.ImageArray);
@ -863,7 +848,6 @@ namespace Ryujinx.Graphics.Gpu.Image
entry.UpdateData(cachedTextureBuffer, cachedSamplerBuffer, separateSamplerBuffer); entry.UpdateData(cachedTextureBuffer, cachedSamplerBuffer, separateSamplerBuffer);
Format[] formats = isImage ? new Format[bindingInfo.ArrayLength] : null;
ISampler[] samplers = isImage ? null : new ISampler[bindingInfo.ArrayLength]; ISampler[] samplers = isImage ? null : new ISampler[bindingInfo.ArrayLength];
ITexture[] textures = new ITexture[bindingInfo.ArrayLength]; ITexture[] textures = new ITexture[bindingInfo.ArrayLength];
@ -883,7 +867,7 @@ namespace Ryujinx.Graphics.Gpu.Image
samplerId = TextureHandle.UnpackSamplerId(packedId); 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) if (texture != null)
{ {
@ -916,8 +900,6 @@ namespace Ryujinx.Graphics.Gpu.Image
hostSampler = sampler?.GetHostSampler(texture); hostSampler = sampler?.GetHostSampler(texture);
} }
Format format = bindingInfo.Format;
if (hostTexture != null && texture.Target == Target.TextureBuffer) if (hostTexture != null && texture.Target == Target.TextureBuffer)
{ {
// Ensure that the buffer texture is using the correct buffer as storage. // 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. // to ensure we're not using a old buffer that was already deleted.
if (isImage) if (isImage)
{ {
if (format == 0 && texture != null) _channel.BufferManager.SetBufferTextureStorage(stage, entry.ImageArray, hostTexture, texture.Range, bindingInfo, index);
{
format = texture.Format;
}
_channel.BufferManager.SetBufferTextureStorage(stage, entry.ImageArray, hostTexture, texture.Range, bindingInfo, index, format);
} }
else 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) else if (isImage)
{ {
if (format == 0 && texture != null)
{
format = texture.Format;
}
formats[index] = format;
textures[index] = hostTexture; textures[index] = hostTexture;
} }
else else
@ -956,7 +927,6 @@ namespace Ryujinx.Graphics.Gpu.Image
if (isImage) if (isImage)
{ {
entry.ImageArray.SetFormats(0, formats);
entry.ImageArray.SetImages(0, textures); entry.ImageArray.SetImages(0, textures);
SetImageArray(stage, bindingInfo, entry.ImageArray); SetImageArray(stage, bindingInfo, entry.ImageArray);

View File

@ -522,7 +522,7 @@ namespace Ryujinx.Graphics.Gpu.Image
// Ensure that the buffer texture is using the correct buffer as storage. // 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 // 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. // 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. // Cache is not used for buffer texture, it must always rebind.
state.CachedTexture = null; state.CachedTexture = null;
@ -616,6 +616,7 @@ namespace Ryujinx.Graphics.Gpu.Image
if (!poolModified && if (!poolModified &&
state.TextureHandle == textureId && state.TextureHandle == textureId &&
state.ImageFormat == bindingInfo.FormatInfo.Format &&
state.CachedTexture != null && state.CachedTexture != null &&
state.CachedTexture.InvalidatedSequence == state.InvalidatedSequence) state.CachedTexture.InvalidatedSequence == state.InvalidatedSequence)
{ {
@ -629,26 +630,22 @@ namespace Ryujinx.Graphics.Gpu.Image
cachedTexture.SignalModified(); cachedTexture.SignalModified();
} }
Format format = bindingInfo.Format == 0 ? cachedTexture.Format : bindingInfo.Format; if ((usageFlags & TextureUsageFlags.NeedsScaleValue) != 0 && UpdateScale(state.CachedTexture, usageFlags, scaleIndex, stage))
if (state.ImageFormat != format ||
((usageFlags & TextureUsageFlags.NeedsScaleValue) != 0 &&
UpdateScale(state.CachedTexture, usageFlags, scaleIndex, stage)))
{ {
ITexture hostTextureRebind = state.CachedTexture.GetTargetTexture(bindingInfo.Target); ITexture hostTextureRebind = state.CachedTexture.GetTargetTexture(bindingInfo.Target);
state.Texture = hostTextureRebind; state.Texture = hostTextureRebind;
state.ImageFormat = format;
_context.Renderer.Pipeline.SetImage(stage, bindingInfo.Binding, hostTextureRebind, format); _context.Renderer.Pipeline.SetImage(stage, bindingInfo.Binding, hostTextureRebind);
} }
continue; continue;
} }
state.TextureHandle = textureId; 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); 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 // 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. // to ensure we're not using a old buffer that was already deleted.
Format format = bindingInfo.Format; _channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, texture.Range, bindingInfo, true);
if (format == 0 && texture != null)
{
format = texture.Format;
}
_channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, texture.Range, bindingInfo, format, true);
// Cache is not used for buffer texture, it must always rebind. // Cache is not used for buffer texture, it must always rebind.
state.CachedTexture = null; state.CachedTexture = null;
@ -689,16 +679,7 @@ namespace Ryujinx.Graphics.Gpu.Image
{ {
state.Texture = hostTexture; state.Texture = hostTexture;
Format format = bindingInfo.Format; _context.Renderer.Pipeline.SetImage(stage, bindingInfo.Binding, hostTexture);
if (format == 0 && texture != null)
{
format = texture.Format;
}
state.ImageFormat = format;
_context.Renderer.Pipeline.SetImage(stage, bindingInfo.Binding, hostTexture, format);
} }
state.CachedTexture = texture; state.CachedTexture = texture;

View File

@ -739,7 +739,8 @@ namespace Ryujinx.Graphics.Gpu.Image
} }
return (lhsFormat.Format == Format.R8G8B8A8Unorm && rhsFormat.Format == Format.R32G32B32A32Float) || 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> /// <summary>

View File

@ -75,6 +75,76 @@ namespace Ryujinx.Graphics.Gpu.Image
private readonly ConcurrentQueue<DereferenceRequest> _dereferenceQueue = new(); private readonly ConcurrentQueue<DereferenceRequest> _dereferenceQueue = new();
private TextureDescriptor _defaultDescriptor; 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> /// <summary>
/// Linked list node used on the texture pool cache. /// Linked list node used on the texture pool cache.
/// </summary> /// </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) public TexturePool(GpuContext context, GpuChannel channel, ulong address, int maximumId) : base(context, channel.MemoryManager.Physical, address, maximumId)
{ {
_channel = channel; _channel = channel;
_aliasLists = new Dictionary<Texture, TextureAliasList>();
} }
/// <summary> /// <summary>
@ -115,14 +186,13 @@ namespace Ryujinx.Graphics.Gpu.Image
if (texture == null) if (texture == null)
{ {
TextureInfo info = GetInfo(descriptor, out int layerSize);
// The dereference queue can put our texture back on the cache. // The dereference queue can put our texture back on the cache.
if ((texture = ProcessDereferenceQueue(id)) != null) if ((texture = ProcessDereferenceQueue(id)) != null)
{ {
return ref descriptor; return ref descriptor;
} }
TextureInfo info = GetInfo(descriptor, out int layerSize);
texture = PhysicalMemory.TextureCache.FindOrCreateTexture(_channel.MemoryManager, TextureSearchFlags.ForSampler, info, 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. // 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); 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> /// <summary>
/// Checks if the pool was modified, and returns the last sequence number where a modification was detected. /// Checks if the pool was modified, and returns the last sequence number where a modification was detected.
/// </summary> /// </summary>
@ -234,6 +349,7 @@ namespace Ryujinx.Graphics.Gpu.Image
else else
{ {
texture.DecrementReferenceCount(); texture.DecrementReferenceCount();
RemoveAliasList(texture);
} }
} }
@ -327,6 +443,8 @@ namespace Ryujinx.Graphics.Gpu.Image
{ {
texture.DecrementReferenceCount(); texture.DecrementReferenceCount();
} }
RemoveAliasList(texture);
} }
return null; return null;
@ -369,6 +487,7 @@ namespace Ryujinx.Graphics.Gpu.Image
if (Interlocked.Exchange(ref Items[id], null) != null) if (Interlocked.Exchange(ref Items[id], null) != null)
{ {
texture.DecrementReferenceCount(this, id); texture.DecrementReferenceCount(this, id);
RemoveAliasList(texture);
} }
} }
} }
@ -622,6 +741,57 @@ namespace Ryujinx.Graphics.Gpu.Image
component == SwizzleComponent.Green; 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> /// <summary>
/// Decrements the reference count of the texture. /// Decrements the reference count of the texture.
/// This indicates that the texture pool is not using it anymore. /// 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> /// <param name="item">The texture to be deleted</param>
protected override void Delete(Texture item) protected override void Delete(Texture item)
{ {
item?.DecrementReferenceCount(this); if (item != null)
{
item.DecrementReferenceCount(this);
RemoveAliasList(item);
}
} }
public override void Dispose() public override void Dispose()

View File

@ -509,7 +509,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
if (binding.IsImage) 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 else
{ {
@ -873,12 +873,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
ITexture texture, ITexture texture,
MultiRange range, MultiRange range,
TextureBindingInfo bindingInfo, TextureBindingInfo bindingInfo,
Format format,
bool isImage) bool isImage)
{ {
_channel.MemoryManager.Physical.BufferCache.CreateBuffer(range, BufferStageUtils.TextureBuffer(stage, bindingInfo.Flags)); _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> /// <summary>
@ -897,12 +896,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
ITexture texture, ITexture texture,
MultiRange range, MultiRange range,
TextureBindingInfo bindingInfo, TextureBindingInfo bindingInfo,
int index, int index)
Format format)
{ {
_channel.MemoryManager.Physical.BufferCache.CreateBuffer(range, BufferStageUtils.TextureBuffer(stage, bindingInfo.Flags)); _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> /// <summary>
@ -921,12 +919,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
ITexture texture, ITexture texture,
MultiRange range, MultiRange range,
TextureBindingInfo bindingInfo, TextureBindingInfo bindingInfo,
int index, int index)
Format format)
{ {
_channel.MemoryManager.Physical.BufferCache.CreateBuffer(range, BufferStageUtils.TextureBuffer(stage, bindingInfo.Flags)); _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> /// <summary>

View File

@ -34,33 +34,26 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// </summary> /// </summary>
public int Index { get; } public int Index { get; }
/// <summary>
/// The image format for the binding.
/// </summary>
public Format Format { get; }
/// <summary> /// <summary>
/// Create a new buffer texture binding. /// Create a new buffer texture binding.
/// </summary> /// </summary>
/// <param name="array">Array</param>
/// <param name="texture">Buffer texture</param> /// <param name="texture">Buffer texture</param>
/// <param name="range">Physical ranges of memory where the buffer texture data is located</param> /// <param name="range">Physical ranges of memory where the buffer texture data is located</param>
/// <param name="bindingInfo">Binding info</param> /// <param name="bindingInfo">Binding info</param>
/// <param name="index">Index of the binding on the array</param> /// <param name="index">Index of the binding on the array</param>
/// <param name="format">Binding format</param>
public BufferTextureArrayBinding( public BufferTextureArrayBinding(
T array, T array,
ITexture texture, ITexture texture,
MultiRange range, MultiRange range,
TextureBindingInfo bindingInfo, TextureBindingInfo bindingInfo,
int index, int index)
Format format)
{ {
Array = array; Array = array;
Texture = texture; Texture = texture;
Range = range; Range = range;
BindingInfo = bindingInfo; BindingInfo = bindingInfo;
Index = index; Index = index;
Format = format;
} }
} }
} }

View File

@ -30,11 +30,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// </summary> /// </summary>
public TextureBindingInfo BindingInfo { get; } public TextureBindingInfo BindingInfo { get; }
/// <summary>
/// The image format for the binding.
/// </summary>
public Format Format { get; }
/// <summary> /// <summary>
/// Whether the binding is for an image or a sampler. /// Whether the binding is for an image or a sampler.
/// </summary> /// </summary>
@ -47,21 +42,18 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// <param name="texture">Buffer texture</param> /// <param name="texture">Buffer texture</param>
/// <param name="range">Physical ranges of memory where the buffer texture data is located</param> /// <param name="range">Physical ranges of memory where the buffer texture data is located</param>
/// <param name="bindingInfo">Binding info</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> /// <param name="isImage">Whether the binding is for an image or a sampler</param>
public BufferTextureBinding( public BufferTextureBinding(
ShaderStage stage, ShaderStage stage,
ITexture texture, ITexture texture,
MultiRange range, MultiRange range,
TextureBindingInfo bindingInfo, TextureBindingInfo bindingInfo,
Format format,
bool isImage) bool isImage)
{ {
Stage = stage; Stage = stage;
Texture = texture; Texture = texture;
Range = range; Range = range;
BindingInfo = bindingInfo; BindingInfo = bindingInfo;
Format = format;
IsImage = isImage; IsImage = isImage;
} }
} }

View File

@ -86,11 +86,11 @@ namespace Ryujinx.Graphics.Gpu.Shader
ImageBindings[i] = stage.Info.Images.Select(descriptor => ImageBindings[i] = stage.Info.Images.Select(descriptor =>
{ {
Target target = ShaderTexture.GetTarget(descriptor.Type); Target target = ShaderTexture.GetTarget(descriptor.Type);
Format format = ShaderTexture.GetFormat(descriptor.Format); FormatInfo formatInfo = ShaderTexture.GetFormatInfo(descriptor.Format);
var result = new TextureBindingInfo( var result = new TextureBindingInfo(
target, target,
format, formatInfo,
descriptor.Set, descriptor.Set,
descriptor.Binding, descriptor.Binding,
descriptor.ArrayLength, descriptor.ArrayLength,

View File

@ -131,7 +131,7 @@ namespace Ryujinx.Graphics.Gpu
bool isLinear, bool isLinear,
int gobBlocksInY, int gobBlocksInY,
Format format, Format format,
int bytesPerPixel, byte bytesPerPixel,
ImageCrop crop, ImageCrop crop,
Action<GpuContext, object> acquireCallback, Action<GpuContext, object> acquireCallback,
Action<object> releaseCallback, Action<object> releaseCallback,

View File

@ -1,6 +1,5 @@
using OpenTK.Graphics.OpenGL; using OpenTK.Graphics.OpenGL;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using System;
namespace Ryujinx.Graphics.OpenGL.Image namespace Ryujinx.Graphics.OpenGL.Image
{ {
@ -19,14 +18,6 @@ namespace Ryujinx.Graphics.OpenGL.Image
_images = new TextureRef[size]; _images = new TextureRef[size];
} }
public void SetFormats(int index, GAL.Format[] imageFormats)
{
for (int i = 0; i < imageFormats.Length; i++)
{
_images[index + i].Format = imageFormats[i];
}
}
public void SetImages(int index, ITexture[] images) public void SetImages(int index, ITexture[] images)
{ {
for (int i = 0; i < images.Length; i++) for (int i = 0; i < images.Length; i++)
@ -36,6 +27,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
if (image is TextureBase imageBase) if (image is TextureBase imageBase)
{ {
_images[index + i].Handle = imageBase.Handle; _images[index + i].Handle = imageBase.Handle;
_images[index + i].Format = imageBase.Format;
} }
else else
{ {

View File

@ -45,7 +45,7 @@ namespace Ryujinx.Graphics.OpenGL
private readonly Vector4<int>[] _fpIsBgra = new Vector4<int>[SupportBuffer.FragmentIsBgraCount]; private readonly Vector4<int>[] _fpIsBgra = new Vector4<int>[SupportBuffer.FragmentIsBgraCount];
private readonly (TextureBase, Format)[] _images; private readonly TextureBase[] _images;
private TextureBase _unit0Texture; private TextureBase _unit0Texture;
private Sampler _unit0Sampler; private Sampler _unit0Sampler;
@ -78,7 +78,7 @@ namespace Ryujinx.Graphics.OpenGL
_fragmentOutputMap = uint.MaxValue; _fragmentOutputMap = uint.MaxValue;
_componentMasks = uint.MaxValue; _componentMasks = uint.MaxValue;
_images = new (TextureBase, Format)[SavedImages]; _images = new TextureBase[SavedImages];
_tfbs = new BufferHandle[Constants.MaxTransformFeedbackBuffers]; _tfbs = new BufferHandle[Constants.MaxTransformFeedbackBuffers];
_tfbTargets = new BufferRange[Constants.MaxTransformFeedbackBuffers]; _tfbTargets = new BufferRange[Constants.MaxTransformFeedbackBuffers];
@ -935,11 +935,11 @@ namespace Ryujinx.Graphics.OpenGL
SetFrontFace(_frontFace = frontFace.Convert()); SetFrontFace(_frontFace = frontFace.Convert());
} }
public void SetImage(ShaderStage stage, int binding, ITexture texture, Format imageFormat) public void SetImage(ShaderStage stage, int binding, ITexture texture)
{ {
if ((uint)binding < SavedImages) if ((uint)binding < SavedImages)
{ {
_images[binding] = (texture as TextureBase, imageFormat); _images[binding] = texture as TextureBase;
} }
if (texture == null) if (texture == null)
@ -950,7 +950,7 @@ namespace Ryujinx.Graphics.OpenGL
TextureBase texBase = (TextureBase)texture; TextureBase texBase = (TextureBase)texture;
SizedInternalFormat format = FormatTable.GetImageFormat(imageFormat); SizedInternalFormat format = FormatTable.GetImageFormat(texBase.Format);
if (format != 0) if (format != 0)
{ {
@ -1622,11 +1622,11 @@ namespace Ryujinx.Graphics.OpenGL
{ {
for (int i = 0; i < SavedImages; i++) for (int i = 0; i < SavedImages; i++)
{ {
(TextureBase texBase, Format imageFormat) = _images[i]; TextureBase texBase = _images[i];
if (texBase != null) if (texBase != null)
{ {
SizedInternalFormat format = FormatTable.GetImageFormat(imageFormat); SizedInternalFormat format = FormatTable.GetImageFormat(texBase.Format);
if (format != 0) if (format != 0)
{ {

View File

@ -82,7 +82,6 @@ namespace Ryujinx.Graphics.Vulkan
private readonly ImageRef[] _imageRefs; private readonly ImageRef[] _imageRefs;
private readonly TextureBuffer[] _bufferTextureRefs; private readonly TextureBuffer[] _bufferTextureRefs;
private readonly TextureBuffer[] _bufferImageRefs; private readonly TextureBuffer[] _bufferImageRefs;
private readonly Format[] _bufferImageFormats;
private ArrayRef<TextureArray>[] _textureArrayRefs; private ArrayRef<TextureArray>[] _textureArrayRefs;
private ArrayRef<ImageArray>[] _imageArrayRefs; private ArrayRef<ImageArray>[] _imageArrayRefs;
@ -141,7 +140,6 @@ namespace Ryujinx.Graphics.Vulkan
_imageRefs = new ImageRef[Constants.MaxImageBindings * 2]; _imageRefs = new ImageRef[Constants.MaxImageBindings * 2];
_bufferTextureRefs = new TextureBuffer[Constants.MaxTextureBindings * 2]; _bufferTextureRefs = new TextureBuffer[Constants.MaxTextureBindings * 2];
_bufferImageRefs = new TextureBuffer[Constants.MaxImageBindings * 2]; _bufferImageRefs = new TextureBuffer[Constants.MaxImageBindings * 2];
_bufferImageFormats = new Format[Constants.MaxImageBindings * 2];
_textureArrayRefs = Array.Empty<ArrayRef<TextureArray>>(); _textureArrayRefs = Array.Empty<ArrayRef<TextureArray>>();
_imageArrayRefs = Array.Empty<ArrayRef<ImageArray>>(); _imageArrayRefs = Array.Empty<ArrayRef<ImageArray>>();
@ -391,17 +389,11 @@ namespace Ryujinx.Graphics.Vulkan
_dirty = DirtyFlags.All; _dirty = DirtyFlags.All;
} }
public void SetImage( public void SetImage(CommandBufferScoped cbs, ShaderStage stage, int binding, ITexture image)
CommandBufferScoped cbs,
ShaderStage stage,
int binding,
ITexture image,
Format imageFormat)
{ {
if (image is TextureBuffer imageBuffer) if (image is TextureBuffer imageBuffer)
{ {
_bufferImageRefs[binding] = imageBuffer; _bufferImageRefs[binding] = imageBuffer;
_bufferImageFormats[binding] = imageFormat;
} }
else if (image is TextureView view) else if (image is TextureView view)
{ {
@ -410,13 +402,12 @@ namespace Ryujinx.Graphics.Vulkan
iRef.View?.ClearUsage(FeedbackLoopHazards); iRef.View?.ClearUsage(FeedbackLoopHazards);
view?.PrepareForUsage(cbs, stage.ConvertToPipelineStageFlags(), FeedbackLoopHazards); view?.PrepareForUsage(cbs, stage.ConvertToPipelineStageFlags(), FeedbackLoopHazards);
iRef = new(stage, view, view.GetView(imageFormat).GetIdentityImageView()); iRef = new(stage, view, view.GetIdentityImageView());
} }
else else
{ {
_imageRefs[binding] = default; _imageRefs[binding] = default;
_bufferImageRefs[binding] = null; _bufferImageRefs[binding] = null;
_bufferImageFormats[binding] = default;
} }
SignalDirty(DirtyFlags.Image); SignalDirty(DirtyFlags.Image);
@ -923,7 +914,7 @@ namespace Ryujinx.Graphics.Vulkan
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
bufferImages[i] = _bufferImageRefs[binding + i]?.GetBufferView(cbs, _bufferImageFormats[binding + i], true) ?? default; bufferImages[i] = _bufferImageRefs[binding + i]?.GetBufferView(cbs, true) ?? default;
} }
tu.Push<BufferView>(bufferImages[..count]); tu.Push<BufferView>(bufferImages[..count]);

View File

@ -154,7 +154,7 @@ namespace Ryujinx.Graphics.Vulkan.Effects
int dispatchY = (height + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim; int dispatchY = (height + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, buffer.Range) }); _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, buffer.Range) });
_pipeline.SetImage(ShaderStage.Compute, 0, _intermediaryTexture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)); _pipeline.SetImage(ShaderStage.Compute, 0, _intermediaryTexture.GetView(FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)));
_pipeline.DispatchCompute(dispatchX, dispatchY, 1); _pipeline.DispatchCompute(dispatchX, dispatchY, 1);
_pipeline.ComputeBarrier(); _pipeline.ComputeBarrier();

View File

@ -75,7 +75,7 @@ namespace Ryujinx.Graphics.Vulkan.Effects
var dispatchX = BitUtils.DivRoundUp(view.Width, IPostProcessingEffect.LocalGroupSize); var dispatchX = BitUtils.DivRoundUp(view.Width, IPostProcessingEffect.LocalGroupSize);
var dispatchY = BitUtils.DivRoundUp(view.Height, IPostProcessingEffect.LocalGroupSize); var dispatchY = BitUtils.DivRoundUp(view.Height, IPostProcessingEffect.LocalGroupSize);
_pipeline.SetImage(ShaderStage.Compute, 0, _texture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)); _pipeline.SetImage(ShaderStage.Compute, 0, _texture.GetView(FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)));
_pipeline.DispatchCompute(dispatchX, dispatchY, 1); _pipeline.DispatchCompute(dispatchX, dispatchY, 1);
_pipeline.ComputeBarrier(); _pipeline.ComputeBarrier();

View File

@ -219,7 +219,7 @@ namespace Ryujinx.Graphics.Vulkan.Effects
buffer.Holder.SetDataUnchecked(buffer.Offset, resolutionBuffer); buffer.Holder.SetDataUnchecked(buffer.Offset, resolutionBuffer);
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, buffer.Range) }); _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, buffer.Range) });
_pipeline.SetImage(ShaderStage.Compute, 0, _edgeOutputTexture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)); _pipeline.SetImage(ShaderStage.Compute, 0, _edgeOutputTexture.GetView(FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)));
_pipeline.DispatchCompute(dispatchX, dispatchY, 1); _pipeline.DispatchCompute(dispatchX, dispatchY, 1);
_pipeline.ComputeBarrier(); _pipeline.ComputeBarrier();
@ -229,7 +229,7 @@ namespace Ryujinx.Graphics.Vulkan.Effects
_pipeline.SetTextureAndSampler(ShaderStage.Compute, 1, _edgeOutputTexture, _samplerLinear); _pipeline.SetTextureAndSampler(ShaderStage.Compute, 1, _edgeOutputTexture, _samplerLinear);
_pipeline.SetTextureAndSampler(ShaderStage.Compute, 3, _areaTexture, _samplerLinear); _pipeline.SetTextureAndSampler(ShaderStage.Compute, 3, _areaTexture, _samplerLinear);
_pipeline.SetTextureAndSampler(ShaderStage.Compute, 4, _searchTexture, _samplerLinear); _pipeline.SetTextureAndSampler(ShaderStage.Compute, 4, _searchTexture, _samplerLinear);
_pipeline.SetImage(ShaderStage.Compute, 0, _blendOutputTexture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)); _pipeline.SetImage(ShaderStage.Compute, 0, _blendOutputTexture.GetView(FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)));
_pipeline.DispatchCompute(dispatchX, dispatchY, 1); _pipeline.DispatchCompute(dispatchX, dispatchY, 1);
_pipeline.ComputeBarrier(); _pipeline.ComputeBarrier();
@ -238,7 +238,7 @@ namespace Ryujinx.Graphics.Vulkan.Effects
_pipeline.Specialize(_specConstants); _pipeline.Specialize(_specConstants);
_pipeline.SetTextureAndSampler(ShaderStage.Compute, 3, _blendOutputTexture, _samplerLinear); _pipeline.SetTextureAndSampler(ShaderStage.Compute, 3, _blendOutputTexture, _samplerLinear);
_pipeline.SetTextureAndSampler(ShaderStage.Compute, 1, view, _samplerLinear); _pipeline.SetTextureAndSampler(ShaderStage.Compute, 1, view, _samplerLinear);
_pipeline.SetImage(ShaderStage.Compute, 0, _outputTexture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)); _pipeline.SetImage(ShaderStage.Compute, 0, _outputTexture.GetView(FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)));
_pipeline.DispatchCompute(dispatchX, dispatchY, 1); _pipeline.DispatchCompute(dispatchX, dispatchY, 1);
_pipeline.ComputeBarrier(); _pipeline.ComputeBarrier();

View File

@ -1039,7 +1039,7 @@ namespace Ryujinx.Graphics.Vulkan
var dstView = Create2DLayerView(dst, dstLayer + z, dstLevel + l); var dstView = Create2DLayerView(dst, dstLayer + z, dstLevel + l);
_pipeline.SetTextureAndSamplerIdentitySwizzle(ShaderStage.Compute, 0, srcView, null); _pipeline.SetTextureAndSamplerIdentitySwizzle(ShaderStage.Compute, 0, srcView, null);
_pipeline.SetImage(ShaderStage.Compute, 0, dstView, dstFormat); _pipeline.SetImage(ShaderStage.Compute, 0, dstView.GetView(dstFormat));
int dispatchX = (Math.Min(srcView.Info.Width, dstView.Info.Width) + 31) / 32; int dispatchX = (Math.Min(srcView.Info.Width, dstView.Info.Width) + 31) / 32;
int dispatchY = (Math.Min(srcView.Info.Height, dstView.Info.Height) + 31) / 32; int dispatchY = (Math.Min(srcView.Info.Height, dstView.Info.Height) + 31) / 32;
@ -1168,7 +1168,7 @@ namespace Ryujinx.Graphics.Vulkan
var dstView = Create2DLayerView(dst, dstLayer + z, 0); var dstView = Create2DLayerView(dst, dstLayer + z, 0);
_pipeline.SetTextureAndSamplerIdentitySwizzle(ShaderStage.Compute, 0, srcView, null); _pipeline.SetTextureAndSamplerIdentitySwizzle(ShaderStage.Compute, 0, srcView, null);
_pipeline.SetImage(ShaderStage.Compute, 0, dstView, format); _pipeline.SetImage(ShaderStage.Compute, 0, dstView.GetView(format));
_pipeline.DispatchCompute(dispatchX, dispatchY, 1); _pipeline.DispatchCompute(dispatchX, dispatchY, 1);

View File

@ -13,7 +13,6 @@ namespace Ryujinx.Graphics.Vulkan
{ {
public TextureStorage Storage; public TextureStorage Storage;
public TextureView View; public TextureView View;
public GAL.Format ImageFormat;
} }
private readonly TextureRef[] _textureRefs; private readonly TextureRef[] _textureRefs;
@ -52,16 +51,6 @@ namespace Ryujinx.Graphics.Vulkan
_isBuffer = isBuffer; _isBuffer = isBuffer;
} }
public void SetFormats(int index, GAL.Format[] imageFormats)
{
for (int i = 0; i < imageFormats.Length; i++)
{
_textureRefs[index + i].ImageFormat = imageFormats[i];
}
SetDirty();
}
public void SetImages(int index, ITexture[] images) public void SetImages(int index, ITexture[] images)
{ {
for (int i = 0; i < images.Length; i++) for (int i = 0; i < images.Length; i++)
@ -142,7 +131,7 @@ namespace Ryujinx.Graphics.Vulkan
ref var texture = ref textures[i]; ref var texture = ref textures[i];
ref var refs = ref _textureRefs[i]; ref var refs = ref _textureRefs[i];
if (i > 0 && _textureRefs[i - 1].View == refs.View && _textureRefs[i - 1].ImageFormat == refs.ImageFormat) if (i > 0 && _textureRefs[i - 1].View == refs.View)
{ {
texture = textures[i - 1]; texture = textures[i - 1];
@ -150,7 +139,7 @@ namespace Ryujinx.Graphics.Vulkan
} }
texture.ImageLayout = ImageLayout.General; texture.ImageLayout = ImageLayout.General;
texture.ImageView = refs.View?.GetView(refs.ImageFormat).GetIdentityImageView().Get(cbs).Value ?? default; texture.ImageView = refs.View?.GetIdentityImageView().Get(cbs).Value ?? default;
if (texture.ImageView.Handle == 0) if (texture.ImageView.Handle == 0)
{ {
@ -167,7 +156,7 @@ namespace Ryujinx.Graphics.Vulkan
for (int i = 0; i < bufferTextures.Length; i++) for (int i = 0; i < bufferTextures.Length; i++)
{ {
bufferTextures[i] = _bufferTextureRefs[i]?.GetBufferView(cbs, _textureRefs[i].ImageFormat, true) ?? default; bufferTextures[i] = _bufferTextureRefs[i]?.GetBufferView(cbs, true) ?? default;
} }
return bufferTextures; return bufferTextures;

View File

@ -836,9 +836,9 @@ namespace Ryujinx.Graphics.Vulkan
SignalStateChange(); SignalStateChange();
} }
public void SetImage(ShaderStage stage, int binding, ITexture image, Format imageFormat) public void SetImage(ShaderStage stage, int binding, ITexture image)
{ {
_descriptorSetUpdater.SetImage(Cbs, stage, binding, image, imageFormat); _descriptorSetUpdater.SetImage(Cbs, stage, binding, image);
} }
public void SetImage(int binding, Auto<DisposableImageView> image) public void SetImage(int binding, Auto<DisposableImageView> image)

View File

@ -16,7 +16,6 @@ namespace Ryujinx.Graphics.Vulkan
private int _offset; private int _offset;
private int _size; private int _size;
private Auto<DisposableBufferView> _bufferView; private Auto<DisposableBufferView> _bufferView;
private Dictionary<Format, Auto<DisposableBufferView>> _selfManagedViews;
private int _bufferCount; private int _bufferCount;
@ -80,16 +79,6 @@ namespace Ryujinx.Graphics.Vulkan
private void ReleaseImpl() private void ReleaseImpl()
{ {
if (_selfManagedViews != null)
{
foreach (var bufferView in _selfManagedViews.Values)
{
bufferView.Dispose();
}
_selfManagedViews = null;
}
_bufferView?.Dispose(); _bufferView?.Dispose();
_bufferView = null; _bufferView = null;
} }
@ -137,28 +126,5 @@ namespace Ryujinx.Graphics.Vulkan
return _bufferView?.Get(cbs, _offset, _size, write).Value ?? default; return _bufferView?.Get(cbs, _offset, _size, write).Value ?? default;
} }
public BufferView GetBufferView(CommandBufferScoped cbs, Format format, bool write)
{
var vkFormat = FormatTable.GetFormat(format);
if (vkFormat == VkFormat)
{
return GetBufferView(cbs, write);
}
if (_selfManagedViews != null && _selfManagedViews.TryGetValue(format, out var bufferView))
{
return bufferView.Get(cbs, _offset, _size, write).Value;
}
bufferView = _gd.BufferManager.CreateView(_bufferHandle, vkFormat, _offset, _size, ReleaseImpl);
if (bufferView != null)
{
(_selfManagedViews ??= new Dictionary<Format, Auto<DisposableBufferView>>()).Add(format, bufferView);
}
return bufferView?.Get(cbs, _offset, _size, write).Value ?? default;
}
} }
} }

View File

@ -412,9 +412,9 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
Format format = ConvertColorFormat(item.GraphicBuffer.Object.Buffer.Surfaces[0].ColorFormat); Format format = ConvertColorFormat(item.GraphicBuffer.Object.Buffer.Surfaces[0].ColorFormat);
int bytesPerPixel = byte bytesPerPixel =
format == Format.B5G6R5Unorm || format == Format.B5G6R5Unorm ||
format == Format.R4G4B4A4Unorm ? 2 : 4; format == Format.R4G4B4A4Unorm ? (byte)2 : (byte)4;
int gobBlocksInY = 1 << item.GraphicBuffer.Object.Buffer.Surfaces[0].BlockHeightLog2; int gobBlocksInY = 1 << item.GraphicBuffer.Object.Buffer.Surfaces[0].BlockHeightLog2;