diff --git a/src/Ryujinx.Common/Memory/SpanOrArray.cs b/src/Ryujinx.Common/Memory/SpanOrArray.cs
deleted file mode 100644
index 269ac02f..00000000
--- a/src/Ryujinx.Common/Memory/SpanOrArray.cs
+++ /dev/null
@@ -1,89 +0,0 @@
-using System;
-
-namespace Ryujinx.Common.Memory
-{
- ///
- /// A struct that can represent both a Span and Array.
- /// This is useful to keep the Array representation when possible to avoid copies.
- ///
- /// Element Type
- public readonly ref struct SpanOrArray where T : unmanaged
- {
- public readonly T[] Array;
- public readonly ReadOnlySpan Span;
-
- ///
- /// Create a new SpanOrArray from an array.
- ///
- /// Array to store
- public SpanOrArray(T[] array)
- {
- Array = array;
- Span = ReadOnlySpan.Empty;
- }
-
- ///
- /// Create a new SpanOrArray from a readonly span.
- ///
- /// Span to store
- public SpanOrArray(ReadOnlySpan span)
- {
- Array = null;
- Span = span;
- }
-
- ///
- /// Return the contained array, or convert the span if necessary.
- ///
- /// An array containing the data
- public T[] ToArray()
- {
- return Array ?? Span.ToArray();
- }
-
- ///
- /// Return a ReadOnlySpan from either the array or ReadOnlySpan.
- ///
- /// A ReadOnlySpan containing the data
- public ReadOnlySpan AsSpan()
- {
- return Array ?? Span;
- }
-
- ///
- /// Cast an array to a SpanOrArray.
- ///
- /// Source array
- public static implicit operator SpanOrArray(T[] array)
- {
- return new SpanOrArray(array);
- }
-
- ///
- /// Cast a ReadOnlySpan to a SpanOrArray.
- ///
- /// Source ReadOnlySpan
- public static implicit operator SpanOrArray(ReadOnlySpan span)
- {
- return new SpanOrArray(span);
- }
-
- ///
- /// Cast a Span to a SpanOrArray.
- ///
- /// Source Span
- public static implicit operator SpanOrArray(Span span)
- {
- return new SpanOrArray(span);
- }
-
- ///
- /// Cast a SpanOrArray to a ReadOnlySpan
- ///
- /// Source SpanOrArray
- public static implicit operator ReadOnlySpan(SpanOrArray spanOrArray)
- {
- return spanOrArray.AsSpan();
- }
- }
-}
diff --git a/src/Ryujinx.Common/Utilities/EmbeddedResources.cs b/src/Ryujinx.Common/Utilities/EmbeddedResources.cs
index a4facc2e..e22571c9 100644
--- a/src/Ryujinx.Common/Utilities/EmbeddedResources.cs
+++ b/src/Ryujinx.Common/Utilities/EmbeddedResources.cs
@@ -1,5 +1,6 @@
using Ryujinx.Common.Utilities;
using System;
+using System.Buffers;
using System.IO;
using System.Linq;
using System.Reflection;
@@ -41,6 +42,22 @@ namespace Ryujinx.Common
return StreamUtils.StreamToBytes(stream);
}
+ public static IMemoryOwner ReadFileToRentedMemory(string filename)
+ {
+ var (assembly, path) = ResolveManifestPath(filename);
+
+ return ReadFileToRentedMemory(assembly, path);
+ }
+
+ public static IMemoryOwner ReadFileToRentedMemory(Assembly assembly, string filename)
+ {
+ using var stream = GetStream(assembly, filename);
+
+ return stream is null
+ ? null
+ : StreamUtils.StreamToRentedMemory(stream);
+ }
+
public async static Task ReadAsync(Assembly assembly, string filename)
{
using var stream = GetStream(assembly, filename);
diff --git a/src/Ryujinx.Common/Utilities/StreamUtils.cs b/src/Ryujinx.Common/Utilities/StreamUtils.cs
index 7a20c98e..74b6af5e 100644
--- a/src/Ryujinx.Common/Utilities/StreamUtils.cs
+++ b/src/Ryujinx.Common/Utilities/StreamUtils.cs
@@ -1,4 +1,6 @@
+using Microsoft.IO;
using Ryujinx.Common.Memory;
+using System.Buffers;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
@@ -9,12 +11,50 @@ namespace Ryujinx.Common.Utilities
{
public static byte[] StreamToBytes(Stream input)
{
- using MemoryStream stream = MemoryStreamManager.Shared.GetStream();
+ using RecyclableMemoryStream output = StreamToRecyclableMemoryStream(input);
+ return output.ToArray();
+ }
- input.CopyTo(stream);
+ public static IMemoryOwner StreamToRentedMemory(Stream input)
+ {
+ if (input is MemoryStream inputMemoryStream)
+ {
+ return MemoryStreamToRentedMemory(inputMemoryStream);
+ }
+ else if (input.CanSeek)
+ {
+ long bytesExpected = input.Length;
- return stream.ToArray();
+ IMemoryOwner ownedMemory = ByteMemoryPool.Rent(bytesExpected);
+
+ var destSpan = ownedMemory.Memory.Span;
+
+ int totalBytesRead = 0;
+
+ while (totalBytesRead < bytesExpected)
+ {
+ int bytesRead = input.Read(destSpan[totalBytesRead..]);
+
+ if (bytesRead == 0)
+ {
+ ownedMemory.Dispose();
+
+ throw new IOException($"Tried reading {bytesExpected} but the stream closed after reading {totalBytesRead}.");
+ }
+
+ totalBytesRead += bytesRead;
+ }
+
+ return ownedMemory;
+ }
+ else
+ {
+ // If input is (non-seekable) then copy twice: first into a RecyclableMemoryStream, then to a rented IMemoryOwner.
+ using RecyclableMemoryStream output = StreamToRecyclableMemoryStream(input);
+
+ return MemoryStreamToRentedMemory(output);
+ }
}
public static async Task StreamToBytesAsync(Stream input, CancellationToken cancellationToken = default)
@@ -25,5 +65,26 @@ namespace Ryujinx.Common.Utilities
return stream.ToArray();
}
+
+ private static IMemoryOwner MemoryStreamToRentedMemory(MemoryStream input)
+ {
+ input.Position = 0;
+
+ IMemoryOwner ownedMemory = ByteMemoryPool.Rent(input.Length);
+
+ // Discard the return value because we assume reading a MemoryStream always succeeds completely.
+ _ = input.Read(ownedMemory.Memory.Span);
+
+ return ownedMemory;
+ }
+
+ private static RecyclableMemoryStream StreamToRecyclableMemoryStream(Stream input)
+ {
+ RecyclableMemoryStream stream = MemoryStreamManager.Shared.GetStream();
+
+ input.CopyTo(stream);
+
+ return stream;
+ }
}
}
diff --git a/src/Ryujinx.Graphics.Device/DeviceMemoryManager.cs b/src/Ryujinx.Graphics.Device/DeviceMemoryManager.cs
index d64ed309..fc075a26 100644
--- a/src/Ryujinx.Graphics.Device/DeviceMemoryManager.cs
+++ b/src/Ryujinx.Graphics.Device/DeviceMemoryManager.cs
@@ -1,5 +1,7 @@
+using Ryujinx.Common.Memory;
using Ryujinx.Memory;
using System;
+using System.Buffers;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@@ -143,11 +145,11 @@ namespace Ryujinx.Graphics.Device
}
else
{
- Memory memory = new byte[size];
+ IMemoryOwner memoryOwner = ByteMemoryPool.Rent(size);
- GetSpan(va, size).CopyTo(memory.Span);
+ GetSpan(va, size).CopyTo(memoryOwner.Memory.Span);
- return new WritableRegion(this, va, memory, tracked: true);
+ return new WritableRegion(this, va, memoryOwner, tracked: true);
}
}
diff --git a/src/Ryujinx.Graphics.GAL/ITexture.cs b/src/Ryujinx.Graphics.GAL/ITexture.cs
index 5a4623a6..2d9c6b79 100644
--- a/src/Ryujinx.Graphics.GAL/ITexture.cs
+++ b/src/Ryujinx.Graphics.GAL/ITexture.cs
@@ -1,4 +1,4 @@
-using Ryujinx.Common.Memory;
+using System.Buffers;
namespace Ryujinx.Graphics.GAL
{
@@ -17,10 +17,34 @@ namespace Ryujinx.Graphics.GAL
PinnedSpan GetData();
PinnedSpan GetData(int layer, int level);
- void SetData(SpanOrArray data);
- void SetData(SpanOrArray data, int layer, int level);
- void SetData(SpanOrArray data, int layer, int level, Rectangle region);
+ ///
+ /// Sets the texture data. The data passed as a will be disposed when
+ /// the operation completes.
+ ///
+ /// Texture data bytes
+ void SetData(IMemoryOwner data);
+
+ ///
+ /// Sets the texture data. The data passed as a will be disposed when
+ /// the operation completes.
+ ///
+ /// Texture data bytes
+ /// Target layer
+ /// Target level
+ void SetData(IMemoryOwner data, int layer, int level);
+
+ ///
+ /// Sets the texture data. The data passed as a will be disposed when
+ /// the operation completes.
+ ///
+ /// Texture data bytes
+ /// Target layer
+ /// Target level
+ /// Target sub-region of the texture to update
+ void SetData(IMemoryOwner data, int layer, int level, Rectangle region);
+
void SetStorage(BufferRange buffer);
+
void Release();
}
}
diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureSetDataCommand.cs b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureSetDataCommand.cs
index 36feeeba..3aba004d 100644
--- a/src/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureSetDataCommand.cs
+++ b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureSetDataCommand.cs
@@ -1,6 +1,6 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
-using System;
+using System.Buffers;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
{
@@ -8,9 +8,9 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
{
public readonly CommandType CommandType => CommandType.TextureSetData;
private TableRef _texture;
- private TableRef _data;
+ private TableRef> _data;
- public void Set(TableRef texture, TableRef data)
+ public void Set(TableRef texture, TableRef> data)
{
_texture = texture;
_data = data;
@@ -19,7 +19,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
public static void Run(ref TextureSetDataCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
ThreadedTexture texture = command._texture.Get(threaded);
- texture.Base.SetData(new ReadOnlySpan(command._data.Get(threaded)));
+ texture.Base.SetData(command._data.Get(threaded));
}
}
}
diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureSetDataSliceCommand.cs b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureSetDataSliceCommand.cs
index c50bfe08..7ad709a7 100644
--- a/src/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureSetDataSliceCommand.cs
+++ b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureSetDataSliceCommand.cs
@@ -1,6 +1,6 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
-using System;
+using System.Buffers;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
{
@@ -8,11 +8,11 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
{
public readonly CommandType CommandType => CommandType.TextureSetDataSlice;
private TableRef _texture;
- private TableRef _data;
+ private TableRef> _data;
private int _layer;
private int _level;
- public void Set(TableRef texture, TableRef data, int layer, int level)
+ public void Set(TableRef texture, TableRef> data, int layer, int level)
{
_texture = texture;
_data = data;
@@ -23,7 +23,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
public static void Run(ref TextureSetDataSliceCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
ThreadedTexture texture = command._texture.Get(threaded);
- texture.Base.SetData(new ReadOnlySpan(command._data.Get(threaded)), command._layer, command._level);
+ texture.Base.SetData(command._data.Get(threaded), command._layer, command._level);
}
}
}
diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureSetDataSliceRegionCommand.cs b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureSetDataSliceRegionCommand.cs
index 4c80d9bc..c211931b 100644
--- a/src/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureSetDataSliceRegionCommand.cs
+++ b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureSetDataSliceRegionCommand.cs
@@ -1,6 +1,6 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
-using System;
+using System.Buffers;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
{
@@ -8,12 +8,12 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
{
public readonly CommandType CommandType => CommandType.TextureSetDataSliceRegion;
private TableRef _texture;
- private TableRef _data;
+ private TableRef> _data;
private int _layer;
private int _level;
private Rectangle _region;
- public void Set(TableRef texture, TableRef data, int layer, int level, Rectangle region)
+ public void Set(TableRef texture, TableRef> data, int layer, int level, Rectangle region)
{
_texture = texture;
_data = data;
@@ -25,7 +25,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
public static void Run(ref TextureSetDataSliceRegionCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
ThreadedTexture texture = command._texture.Get(threaded);
- texture.Base.SetData(new ReadOnlySpan(command._data.Get(threaded)), command._layer, command._level, command._region);
+ texture.Base.SetData(command._data.Get(threaded), command._layer, command._level, command._region);
}
}
}
diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedTexture.cs b/src/Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedTexture.cs
index 9ad9e645..80003b84 100644
--- a/src/Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedTexture.cs
+++ b/src/Ryujinx.Graphics.GAL/Multithreading/Resources/ThreadedTexture.cs
@@ -1,6 +1,6 @@
-using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL.Multithreading.Commands.Texture;
using Ryujinx.Graphics.GAL.Multithreading.Model;
+using System.Buffers;
namespace Ryujinx.Graphics.GAL.Multithreading.Resources
{
@@ -110,21 +110,24 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources
_renderer.QueueCommand();
}
- public void SetData(SpanOrArray data)
+ ///
+ public void SetData(IMemoryOwner data)
{
- _renderer.New().Set(Ref(this), Ref(data.ToArray()));
+ _renderer.New().Set(Ref(this), Ref(data));
_renderer.QueueCommand();
}
- public void SetData(SpanOrArray data, int layer, int level)
+ ///
+ public void SetData(IMemoryOwner data, int layer, int level)
{
- _renderer.New().Set(Ref(this), Ref(data.ToArray()), layer, level);
+ _renderer.New().Set(Ref(this), Ref(data), layer, level);
_renderer.QueueCommand();
}
- public void SetData(SpanOrArray data, int layer, int level, Rectangle region)
+ ///
+ public void SetData(IMemoryOwner data, int layer, int level, Rectangle region)
{
- _renderer.New().Set(Ref(this), Ref(data.ToArray()), layer, level, region);
+ _renderer.New().Set(Ref(this), Ref(data), layer, level, region);
_renderer.QueueCommand();
}
diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Dma/DmaClass.cs b/src/Ryujinx.Graphics.Gpu/Engine/Dma/DmaClass.cs
index de395d57..218db15c 100644
--- a/src/Ryujinx.Graphics.Gpu/Engine/Dma/DmaClass.cs
+++ b/src/Ryujinx.Graphics.Gpu/Engine/Dma/DmaClass.cs
@@ -4,6 +4,7 @@ using Ryujinx.Graphics.Gpu.Engine.Threed;
using Ryujinx.Graphics.Gpu.Memory;
using Ryujinx.Graphics.Texture;
using System;
+using System.Buffers;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@@ -308,7 +309,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
if (target != null)
{
- byte[] data;
+ IMemoryOwner data;
if (srcLinear)
{
data = LayoutConverter.ConvertLinearStridedToLinear(
diff --git a/src/Ryujinx.Graphics.Gpu/Engine/InlineToMemory/InlineToMemoryClass.cs b/src/Ryujinx.Graphics.Gpu/Engine/InlineToMemory/InlineToMemoryClass.cs
index 37d74fdd..93e43ce3 100644
--- a/src/Ryujinx.Graphics.Gpu/Engine/InlineToMemory/InlineToMemoryClass.cs
+++ b/src/Ryujinx.Graphics.Gpu/Engine/InlineToMemory/InlineToMemoryClass.cs
@@ -1,4 +1,5 @@
using Ryujinx.Common;
+using Ryujinx.Common.Memory;
using Ryujinx.Graphics.Device;
using Ryujinx.Graphics.Texture;
using System;
@@ -198,7 +199,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.InlineToMemory
if (target != null)
{
target.SynchronizeMemory();
- target.SetData(data, 0, 0, new GAL.Rectangle(_dstX, _dstY, _lineLengthIn / target.Info.FormatInfo.BytesPerPixel, _lineCount));
+ var dataCopy = ByteMemoryPool.RentCopy(data);
+ target.SetData(dataCopy, 0, 0, new GAL.Rectangle(_dstX, _dstY, _lineLengthIn / target.Info.FormatInfo.BytesPerPixel, _lineCount));
target.SignalModified();
return;
diff --git a/src/Ryujinx.Graphics.Gpu/Image/Texture.cs b/src/Ryujinx.Graphics.Gpu/Image/Texture.cs
index 7a043b2b..e67caea8 100644
--- a/src/Ryujinx.Graphics.Gpu/Image/Texture.cs
+++ b/src/Ryujinx.Graphics.Gpu/Image/Texture.cs
@@ -1,5 +1,4 @@
using Ryujinx.Common.Logging;
-using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu.Memory;
using Ryujinx.Graphics.Texture;
@@ -7,6 +6,7 @@ using Ryujinx.Graphics.Texture.Astc;
using Ryujinx.Memory;
using Ryujinx.Memory.Range;
using System;
+using System.Buffers;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
@@ -661,7 +661,7 @@ namespace Ryujinx.Graphics.Gpu.Image
}
}
- SpanOrArray result = ConvertToHostCompatibleFormat(data);
+ IMemoryOwner result = ConvertToHostCompatibleFormat(data);
if (ScaleFactor != 1f && AllowScaledSetData())
{
@@ -684,7 +684,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// Uploads new texture data to the host GPU.
///
/// New data
- public void SetData(SpanOrArray data)
+ public void SetData(IMemoryOwner data)
{
BlacklistScale();
@@ -703,7 +703,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// New data
/// Target layer
/// Target level
- public void SetData(SpanOrArray data, int layer, int level)
+ public void SetData(IMemoryOwner data, int layer, int level)
{
BlacklistScale();
@@ -721,7 +721,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// Target layer
/// Target level
/// Target sub-region of the texture to update
- public void SetData(ReadOnlySpan data, int layer, int level, Rectangle region)
+ public void SetData(IMemoryOwner data, int layer, int level, Rectangle region)
{
BlacklistScale();
@@ -739,7 +739,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// Mip level to convert
/// True to convert a single slice
/// Converted data
- public SpanOrArray ConvertToHostCompatibleFormat(ReadOnlySpan data, int level = 0, bool single = false)
+ public IMemoryOwner ConvertToHostCompatibleFormat(ReadOnlySpan data, int level = 0, bool single = false)
{
int width = Info.Width;
int height = Info.Height;
@@ -754,11 +754,11 @@ namespace Ryujinx.Graphics.Gpu.Image
int sliceDepth = single ? 1 : depth;
- SpanOrArray result;
+ IMemoryOwner linear;
if (Info.IsLinear)
{
- result = LayoutConverter.ConvertLinearStridedToLinear(
+ linear = LayoutConverter.ConvertLinearStridedToLinear(
width,
height,
Info.FormatInfo.BlockWidth,
@@ -770,7 +770,7 @@ namespace Ryujinx.Graphics.Gpu.Image
}
else
{
- result = LayoutConverter.ConvertBlockLinearToLinear(
+ linear = LayoutConverter.ConvertBlockLinearToLinear(
width,
height,
depth,
@@ -787,33 +787,41 @@ namespace Ryujinx.Graphics.Gpu.Image
data);
}
+ IMemoryOwner result = linear;
+
// Handle compressed cases not supported by the host:
// - ASTC is usually not supported on desktop cards.
// - BC4/BC5 is not supported on 3D textures.
if (!_context.Capabilities.SupportsAstcCompression && Format.IsAstc())
{
- if (!AstcDecoder.TryDecodeToRgba8P(
- result.ToArray(),
- Info.FormatInfo.BlockWidth,
- Info.FormatInfo.BlockHeight,
- width,
- height,
- sliceDepth,
- levels,
- layers,
- out byte[] decoded))
+ using (result)
{
- string texInfo = $"{Info.Target} {Info.FormatInfo.Format} {Info.Width}x{Info.Height}x{Info.DepthOrLayers} levels {Info.Levels}";
+ if (!AstcDecoder.TryDecodeToRgba8P(
+ result.Memory,
+ Info.FormatInfo.BlockWidth,
+ Info.FormatInfo.BlockHeight,
+ width,
+ height,
+ sliceDepth,
+ levels,
+ layers,
+ out IMemoryOwner decoded))
+ {
+ string texInfo = $"{Info.Target} {Info.FormatInfo.Format} {Info.Width}x{Info.Height}x{Info.DepthOrLayers} levels {Info.Levels}";
- Logger.Debug?.Print(LogClass.Gpu, $"Invalid ASTC texture at 0x{Info.GpuAddress:X} ({texInfo}).");
+ Logger.Debug?.Print(LogClass.Gpu, $"Invalid ASTC texture at 0x{Info.GpuAddress:X} ({texInfo}).");
+ }
+
+ if (GraphicsConfig.EnableTextureRecompression)
+ {
+ using (decoded)
+ {
+ return BCnEncoder.EncodeBC7(decoded.Memory, width, height, sliceDepth, levels, layers);
+ }
+ }
+
+ return decoded;
}
-
- if (GraphicsConfig.EnableTextureRecompression)
- {
- decoded = BCnEncoder.EncodeBC7(decoded, width, height, sliceDepth, levels, layers);
- }
-
- result = decoded;
}
else if (!_context.Capabilities.SupportsEtc2Compression && Format.IsEtc2())
{
@@ -821,16 +829,22 @@ namespace Ryujinx.Graphics.Gpu.Image
{
case Format.Etc2RgbaSrgb:
case Format.Etc2RgbaUnorm:
- result = ETC2Decoder.DecodeRgba(result, width, height, sliceDepth, levels, layers);
- break;
+ using (result)
+ {
+ return ETC2Decoder.DecodeRgba(result.Memory.Span, width, height, sliceDepth, levels, layers);
+ }
case Format.Etc2RgbPtaSrgb:
case Format.Etc2RgbPtaUnorm:
- result = ETC2Decoder.DecodePta(result, width, height, sliceDepth, levels, layers);
- break;
+ using (result)
+ {
+ return ETC2Decoder.DecodePta(result.Memory.Span, width, height, sliceDepth, levels, layers);
+ }
case Format.Etc2RgbSrgb:
case Format.Etc2RgbUnorm:
- result = ETC2Decoder.DecodeRgb(result, width, height, sliceDepth, levels, layers);
- break;
+ using (result)
+ {
+ return ETC2Decoder.DecodeRgb(result.Memory.Span, width, height, sliceDepth, levels, layers);
+ }
}
}
else if (!TextureCompatibility.HostSupportsBcFormat(Format, Target, _context.Capabilities))
@@ -839,48 +853,75 @@ namespace Ryujinx.Graphics.Gpu.Image
{
case Format.Bc1RgbaSrgb:
case Format.Bc1RgbaUnorm:
- result = BCnDecoder.DecodeBC1(result, width, height, sliceDepth, levels, layers);
- break;
+ using (result)
+ {
+ return BCnDecoder.DecodeBC1(result.Memory.Span, width, height, sliceDepth, levels, layers);
+ }
case Format.Bc2Srgb:
case Format.Bc2Unorm:
- result = BCnDecoder.DecodeBC2(result, width, height, sliceDepth, levels, layers);
- break;
+ using (result)
+ {
+ return BCnDecoder.DecodeBC2(result.Memory.Span, width, height, sliceDepth, levels, layers);
+ }
case Format.Bc3Srgb:
case Format.Bc3Unorm:
- result = BCnDecoder.DecodeBC3(result, width, height, sliceDepth, levels, layers);
- break;
+ using (result)
+ {
+ return BCnDecoder.DecodeBC3(result.Memory.Span, width, height, sliceDepth, levels, layers);
+ }
case Format.Bc4Snorm:
case Format.Bc4Unorm:
- result = BCnDecoder.DecodeBC4(result, width, height, sliceDepth, levels, layers, Format == Format.Bc4Snorm);
- break;
+ using (result)
+ {
+ return BCnDecoder.DecodeBC4(result.Memory.Span, width, height, sliceDepth, levels, layers, Format == Format.Bc4Snorm);
+ }
case Format.Bc5Snorm:
case Format.Bc5Unorm:
- result = BCnDecoder.DecodeBC5(result, width, height, sliceDepth, levels, layers, Format == Format.Bc5Snorm);
- break;
+ using (result)
+ {
+ return BCnDecoder.DecodeBC5(result.Memory.Span, width, height, sliceDepth, levels, layers, Format == Format.Bc5Snorm);
+ }
case Format.Bc6HSfloat:
case Format.Bc6HUfloat:
- result = BCnDecoder.DecodeBC6(result, width, height, sliceDepth, levels, layers, Format == Format.Bc6HSfloat);
- break;
+ using (result)
+ {
+ return BCnDecoder.DecodeBC6(result.Memory.Span, width, height, sliceDepth, levels, layers, Format == Format.Bc6HSfloat);
+ }
case Format.Bc7Srgb:
case Format.Bc7Unorm:
- result = BCnDecoder.DecodeBC7(result, width, height, sliceDepth, levels, layers);
- break;
+ using (result)
+ {
+ return BCnDecoder.DecodeBC7(result.Memory.Span, width, height, sliceDepth, levels, layers);
+ }
}
}
else if (!_context.Capabilities.SupportsR4G4Format && Format == Format.R4G4Unorm)
{
- result = PixelConverter.ConvertR4G4ToR4G4B4A4(result, width);
-
- if (!_context.Capabilities.SupportsR4G4B4A4Format)
+ using (result)
{
- result = PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(result, width);
+ var converted = PixelConverter.ConvertR4G4ToR4G4B4A4(result.Memory.Span, width);
+
+ if (_context.Capabilities.SupportsR4G4B4A4Format)
+ {
+ return converted;
+ }
+ else
+ {
+ using (converted)
+ {
+ return PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(converted.Memory.Span, width);
+ }
+ }
}
}
else if (Format == Format.R4G4B4A4Unorm)
{
if (!_context.Capabilities.SupportsR4G4B4A4Format)
{
- result = PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(result, width);
+ using (result)
+ {
+ return PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(result.Memory.Span, width);
+ }
}
}
else if (!_context.Capabilities.Supports5BitComponentFormat && Format.Is16BitPacked())
@@ -889,19 +930,27 @@ namespace Ryujinx.Graphics.Gpu.Image
{
case Format.B5G6R5Unorm:
case Format.R5G6B5Unorm:
- result = PixelConverter.ConvertR5G6B5ToR8G8B8A8(result, width);
- break;
+ using (result)
+ {
+ return PixelConverter.ConvertR5G6B5ToR8G8B8A8(result.Memory.Span, width);
+ }
case Format.B5G5R5A1Unorm:
case Format.R5G5B5X1Unorm:
case Format.R5G5B5A1Unorm:
- result = PixelConverter.ConvertR5G5B5ToR8G8B8A8(result, width, Format == Format.R5G5B5X1Unorm);
- break;
+ using (result)
+ {
+ return PixelConverter.ConvertR5G5B5ToR8G8B8A8(result.Memory.Span, width, Format == Format.R5G5B5X1Unorm);
+ }
case Format.A1B5G5R5Unorm:
- result = PixelConverter.ConvertA1B5G5R5ToR8G8B8A8(result, width);
- break;
+ using (result)
+ {
+ return PixelConverter.ConvertA1B5G5R5ToR8G8B8A8(result.Memory.Span, width);
+ }
case Format.R4G4B4A4Unorm:
- result = PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(result, width);
- break;
+ using (result)
+ {
+ return PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(result.Memory.Span, width);
+ }
}
}
diff --git a/src/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs b/src/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs
index 97858394..de9c47c9 100644
--- a/src/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs
+++ b/src/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs
@@ -1,4 +1,3 @@
-using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu.Memory;
using Ryujinx.Graphics.Texture;
@@ -6,6 +5,7 @@ using Ryujinx.Memory;
using Ryujinx.Memory.Range;
using Ryujinx.Memory.Tracking;
using System;
+using System.Buffers;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
@@ -445,7 +445,7 @@ namespace Ryujinx.Graphics.Gpu.Image
ReadOnlySpan data = dataSpan[(offset - spanBase)..];
- SpanOrArray result = Storage.ConvertToHostCompatibleFormat(data, info.BaseLevel + level, true);
+ IMemoryOwner result = Storage.ConvertToHostCompatibleFormat(data, info.BaseLevel + level, true);
Storage.SetData(result, info.BaseLayer + layer, info.BaseLevel + level);
}
diff --git a/src/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs b/src/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs
index 30f87813..0b6c78fa 100644
--- a/src/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs
+++ b/src/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs
@@ -1,6 +1,8 @@
+using Ryujinx.Common.Memory;
using Ryujinx.Memory;
using Ryujinx.Memory.Range;
using System;
+using System.Buffers;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@@ -240,11 +242,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
}
else
{
- Memory memory = new byte[size];
+ IMemoryOwner memoryOwner = ByteMemoryPool.Rent(size);
- GetSpan(va, size).CopyTo(memory.Span);
+ GetSpan(va, size).CopyTo(memoryOwner.Memory.Span);
- return new WritableRegion(this, va, memory, tracked);
+ return new WritableRegion(this, va, memoryOwner, tracked);
}
}
diff --git a/src/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs b/src/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs
index ce970fab..4d09c3aa 100644
--- a/src/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs
+++ b/src/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs
@@ -1,3 +1,4 @@
+using Ryujinx.Common.Memory;
using Ryujinx.Cpu;
using Ryujinx.Graphics.Device;
using Ryujinx.Graphics.Gpu.Image;
@@ -6,6 +7,7 @@ using Ryujinx.Memory;
using Ryujinx.Memory.Range;
using Ryujinx.Memory.Tracking;
using System;
+using System.Buffers;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
@@ -190,7 +192,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
}
else
{
- Memory memory = new byte[range.GetSize()];
+ IMemoryOwner memoryOwner = ByteMemoryPool.Rent(range.GetSize());
+
+ Memory memory = memoryOwner.Memory;
int offset = 0;
for (int i = 0; i < range.Count; i++)
@@ -204,7 +208,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
offset += size;
}
- return new WritableRegion(new MultiRangeWritableBlock(range, this), 0, memory, tracked);
+ return new WritableRegion(new MultiRangeWritableBlock(range, this), 0, memoryOwner, tracked);
}
}
diff --git a/src/Ryujinx.Graphics.OpenGL/Effects/SmaaPostProcessingEffect.cs b/src/Ryujinx.Graphics.OpenGL/Effects/SmaaPostProcessingEffect.cs
index 46dda13f..a6c5e4ac 100644
--- a/src/Ryujinx.Graphics.OpenGL/Effects/SmaaPostProcessingEffect.cs
+++ b/src/Ryujinx.Graphics.OpenGL/Effects/SmaaPostProcessingEffect.cs
@@ -33,7 +33,8 @@ namespace Ryujinx.Graphics.OpenGL.Effects.Smaa
public int Quality
{
- get => _quality; set
+ get => _quality;
+ set
{
_quality = Math.Clamp(value, 0, _qualities.Length - 1);
}
@@ -150,8 +151,8 @@ namespace Ryujinx.Graphics.OpenGL.Effects.Smaa
_areaTexture = new TextureStorage(_renderer, areaInfo);
_searchTexture = new TextureStorage(_renderer, searchInfo);
- var areaTexture = EmbeddedResources.Read("Ryujinx.Graphics.OpenGL/Effects/Textures/SmaaAreaTexture.bin");
- var searchTexture = EmbeddedResources.Read("Ryujinx.Graphics.OpenGL/Effects/Textures/SmaaSearchTexture.bin");
+ var areaTexture = EmbeddedResources.ReadFileToRentedMemory("Ryujinx.Graphics.OpenGL/Effects/Textures/SmaaAreaTexture.bin");
+ var searchTexture = EmbeddedResources.ReadFileToRentedMemory("Ryujinx.Graphics.OpenGL/Effects/Textures/SmaaSearchTexture.bin");
var areaView = _areaTexture.CreateDefaultView();
var searchView = _searchTexture.CreateDefaultView();
diff --git a/src/Ryujinx.Graphics.OpenGL/Image/FormatConverter.cs b/src/Ryujinx.Graphics.OpenGL/Image/FormatConverter.cs
index c4bbf745..434f2590 100644
--- a/src/Ryujinx.Graphics.OpenGL/Image/FormatConverter.cs
+++ b/src/Ryujinx.Graphics.OpenGL/Image/FormatConverter.cs
@@ -1,4 +1,6 @@
+using Ryujinx.Common.Memory;
using System;
+using System.Buffers;
using System.Numerics;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
@@ -8,9 +10,11 @@ namespace Ryujinx.Graphics.OpenGL.Image
{
static class FormatConverter
{
- public unsafe static byte[] ConvertS8D24ToD24S8(ReadOnlySpan data)
+ public unsafe static IMemoryOwner ConvertS8D24ToD24S8(ReadOnlySpan data)
{
- byte[] output = new byte[data.Length];
+ IMemoryOwner outputMemory = ByteMemoryPool.Rent(data.Length);
+
+ Span output = outputMemory.Memory.Span;
int start = 0;
@@ -74,7 +78,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
outSpan[i] = BitOperations.RotateLeft(dataSpan[i], 8);
}
- return output;
+ return outputMemory;
}
public unsafe static byte[] ConvertD24S8ToS8D24(ReadOnlySpan data)
diff --git a/src/Ryujinx.Graphics.OpenGL/Image/TextureBuffer.cs b/src/Ryujinx.Graphics.OpenGL/Image/TextureBuffer.cs
index f140b276..a8196541 100644
--- a/src/Ryujinx.Graphics.OpenGL/Image/TextureBuffer.cs
+++ b/src/Ryujinx.Graphics.OpenGL/Image/TextureBuffer.cs
@@ -1,7 +1,7 @@
using OpenTK.Graphics.OpenGL;
-using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL;
using System;
+using System.Buffers;
namespace Ryujinx.Graphics.OpenGL.Image
{
@@ -54,19 +54,24 @@ namespace Ryujinx.Graphics.OpenGL.Image
throw new NotImplementedException();
}
- public void SetData(SpanOrArray data)
+ ///
+ public void SetData(IMemoryOwner data)
{
- var dataSpan = data.AsSpan();
+ var dataSpan = data.Memory.Span;
Buffer.SetData(_buffer, _bufferOffset, dataSpan[..Math.Min(dataSpan.Length, _bufferSize)]);
+
+ data.Dispose();
}
- public void SetData(SpanOrArray data, int layer, int level)
+ ///
+ public void SetData(IMemoryOwner data, int layer, int level)
{
throw new NotSupportedException();
}
- public void SetData(SpanOrArray data, int layer, int level, Rectangle region)
+ ///
+ public void SetData(IMemoryOwner data, int layer, int level, Rectangle region)
{
throw new NotSupportedException();
}
diff --git a/src/Ryujinx.Graphics.OpenGL/Image/TextureView.cs b/src/Ryujinx.Graphics.OpenGL/Image/TextureView.cs
index 7f1b1c38..8a18e613 100644
--- a/src/Ryujinx.Graphics.OpenGL/Image/TextureView.cs
+++ b/src/Ryujinx.Graphics.OpenGL/Image/TextureView.cs
@@ -1,8 +1,8 @@
using OpenTK.Graphics.OpenGL;
using Ryujinx.Common;
-using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL;
using System;
+using System.Buffers;
using System.Diagnostics;
namespace Ryujinx.Graphics.OpenGL.Image
@@ -448,70 +448,59 @@ namespace Ryujinx.Graphics.OpenGL.Image
}
}
- public void SetData(SpanOrArray data)
+ public void SetData(IMemoryOwner data)
{
- var dataSpan = data.AsSpan();
-
- if (Format == Format.S8UintD24Unorm)
+ using (data = EnsureDataFormat(data))
{
- dataSpan = FormatConverter.ConvertS8D24ToD24S8(dataSpan);
- }
-
- unsafe
- {
- fixed (byte* ptr = dataSpan)
+ unsafe
{
- ReadFrom((IntPtr)ptr, dataSpan.Length);
+ var dataSpan = data.Memory.Span;
+ fixed (byte* ptr = dataSpan)
+ {
+ ReadFrom((IntPtr)ptr, dataSpan.Length);
+ }
}
}
}
- public void SetData(SpanOrArray data, int layer, int level)
+ public void SetData(IMemoryOwner data, int layer, int level)
{
- var dataSpan = data.AsSpan();
-
- if (Format == Format.S8UintD24Unorm)
+ using (data = EnsureDataFormat(data))
{
- dataSpan = FormatConverter.ConvertS8D24ToD24S8(dataSpan);
- }
-
- unsafe
- {
- fixed (byte* ptr = dataSpan)
+ unsafe
{
- int width = Math.Max(Info.Width >> level, 1);
- int height = Math.Max(Info.Height >> level, 1);
+ fixed (byte* ptr = data.Memory.Span)
+ {
+ int width = Math.Max(Info.Width >> level, 1);
+ int height = Math.Max(Info.Height >> level, 1);
- ReadFrom2D((IntPtr)ptr, layer, level, 0, 0, width, height);
+ ReadFrom2D((IntPtr)ptr, layer, level, 0, 0, width, height);
+ }
}
}
}
- public void SetData(SpanOrArray data, int layer, int level, Rectangle region)
+ public void SetData(IMemoryOwner data, int layer, int level, Rectangle region)
{
- var dataSpan = data.AsSpan();
-
- if (Format == Format.S8UintD24Unorm)
+ using (data = EnsureDataFormat(data))
{
- dataSpan = FormatConverter.ConvertS8D24ToD24S8(dataSpan);
- }
+ int wInBlocks = BitUtils.DivRoundUp(region.Width, Info.BlockWidth);
+ int hInBlocks = BitUtils.DivRoundUp(region.Height, Info.BlockHeight);
- int wInBlocks = BitUtils.DivRoundUp(region.Width, Info.BlockWidth);
- int hInBlocks = BitUtils.DivRoundUp(region.Height, Info.BlockHeight);
-
- unsafe
- {
- fixed (byte* ptr = dataSpan)
+ unsafe
{
- ReadFrom2D(
- (IntPtr)ptr,
- layer,
- level,
- region.X,
- region.Y,
- region.Width,
- region.Height,
- BitUtils.AlignUp(wInBlocks * Info.BytesPerPixel, 4) * hInBlocks);
+ fixed (byte* ptr = data.Memory.Span)
+ {
+ ReadFrom2D(
+ (IntPtr)ptr,
+ layer,
+ level,
+ region.X,
+ region.Y,
+ region.Width,
+ region.Height,
+ BitUtils.AlignUp(wInBlocks * Info.BytesPerPixel, 4) * hInBlocks);
+ }
}
}
}
@@ -533,6 +522,19 @@ namespace Ryujinx.Graphics.OpenGL.Image
ReadFrom2D(data, layer, level, x, y, width, height, mipSize);
}
+ private IMemoryOwner EnsureDataFormat(IMemoryOwner data)
+ {
+ if (Format == Format.S8UintD24Unorm)
+ {
+ using (data)
+ {
+ return FormatConverter.ConvertS8D24ToD24S8(data.Memory.Span);
+ }
+ }
+
+ return data;
+ }
+
private void ReadFrom2D(IntPtr data, int layer, int level, int x, int y, int width, int height, int mipSize)
{
TextureTarget target = Target.Convert();
diff --git a/src/Ryujinx.Graphics.Texture/Astc/AstcDecoder.cs b/src/Ryujinx.Graphics.Texture/Astc/AstcDecoder.cs
index edf699dc..3f65e122 100644
--- a/src/Ryujinx.Graphics.Texture/Astc/AstcDecoder.cs
+++ b/src/Ryujinx.Graphics.Texture/Astc/AstcDecoder.cs
@@ -1,5 +1,7 @@
+using Ryujinx.Common.Memory;
using Ryujinx.Common.Utilities;
using System;
+using System.Buffers;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
@@ -291,16 +293,14 @@ namespace Ryujinx.Graphics.Texture.Astc
int depth,
int levels,
int layers,
- out byte[] decoded)
+ out IMemoryOwner decoded)
{
- byte[] output = new byte[QueryDecompressedSize(width, height, depth, levels, layers)];
+ decoded = ByteMemoryPool.Rent(QueryDecompressedSize(width, height, depth, levels, layers));
- AstcDecoder decoder = new(data, output, blockWidth, blockHeight, width, height, depth, levels, layers);
+ AstcDecoder decoder = new(data, decoded.Memory, blockWidth, blockHeight, width, height, depth, levels, layers);
Enumerable.Range(0, decoder.TotalBlockCount).AsParallel().ForAll(x => decoder.ProcessBlock(x));
- decoded = output;
-
return decoder.Success;
}
diff --git a/src/Ryujinx.Graphics.Texture/BCnDecoder.cs b/src/Ryujinx.Graphics.Texture/BCnDecoder.cs
index 2d68ca34..eb85334a 100644
--- a/src/Ryujinx.Graphics.Texture/BCnDecoder.cs
+++ b/src/Ryujinx.Graphics.Texture/BCnDecoder.cs
@@ -1,5 +1,7 @@
using Ryujinx.Common;
+using Ryujinx.Common.Memory;
using System;
+using System.Buffers;
using System.Buffers.Binary;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
@@ -12,7 +14,7 @@ namespace Ryujinx.Graphics.Texture
private const int BlockWidth = 4;
private const int BlockHeight = 4;
- public static byte[] DecodeBC1(ReadOnlySpan data, int width, int height, int depth, int levels, int layers)
+ public static IMemoryOwner DecodeBC1(ReadOnlySpan data, int width, int height, int depth, int levels, int layers)
{
int size = 0;
@@ -21,12 +23,12 @@ namespace Ryujinx.Graphics.Texture
size += Math.Max(1, width >> l) * Math.Max(1, height >> l) * Math.Max(1, depth >> l) * layers * 4;
}
- byte[] output = new byte[size];
+ IMemoryOwner output = ByteMemoryPool.Rent(size);
Span tile = stackalloc byte[BlockWidth * BlockHeight * 4];
Span tileAsUint = MemoryMarshal.Cast(tile);
- Span outputAsUint = MemoryMarshal.Cast(output);
+ Span outputAsUint = MemoryMarshal.Cast(output.Memory.Span);
Span> tileAsVector128 = MemoryMarshal.Cast>(tile);
@@ -100,7 +102,7 @@ namespace Ryujinx.Graphics.Texture
return output;
}
- public static byte[] DecodeBC2(ReadOnlySpan data, int width, int height, int depth, int levels, int layers)
+ public static IMemoryOwner DecodeBC2(ReadOnlySpan data, int width, int height, int depth, int levels, int layers)
{
int size = 0;
@@ -109,12 +111,12 @@ namespace Ryujinx.Graphics.Texture
size += Math.Max(1, width >> l) * Math.Max(1, height >> l) * Math.Max(1, depth >> l) * layers * 4;
}
- byte[] output = new byte[size];
+ IMemoryOwner output = ByteMemoryPool.Rent(size);
Span tile = stackalloc byte[BlockWidth * BlockHeight * 4];
Span tileAsUint = MemoryMarshal.Cast(tile);
- Span outputAsUint = MemoryMarshal.Cast(output);
+ Span outputAsUint = MemoryMarshal.Cast(output.Memory.Span);
Span> tileAsVector128 = MemoryMarshal.Cast>(tile);
@@ -195,7 +197,7 @@ namespace Ryujinx.Graphics.Texture
return output;
}
- public static byte[] DecodeBC3(ReadOnlySpan data, int width, int height, int depth, int levels, int layers)
+ public static IMemoryOwner DecodeBC3(ReadOnlySpan data, int width, int height, int depth, int levels, int layers)
{
int size = 0;
@@ -204,13 +206,13 @@ namespace Ryujinx.Graphics.Texture
size += Math.Max(1, width >> l) * Math.Max(1, height >> l) * Math.Max(1, depth >> l) * layers * 4;
}
- byte[] output = new byte[size];
+ IMemoryOwner output = ByteMemoryPool.Rent(size);
Span tile = stackalloc byte[BlockWidth * BlockHeight * 4];
Span rPal = stackalloc byte[8];
Span tileAsUint = MemoryMarshal.Cast(tile);
- Span outputAsUint = MemoryMarshal.Cast(output);
+ Span outputAsUint = MemoryMarshal.Cast(output.Memory.Span);
Span> tileAsVector128 = MemoryMarshal.Cast>(tile);
@@ -292,7 +294,7 @@ namespace Ryujinx.Graphics.Texture
return output;
}
- public static byte[] DecodeBC4(ReadOnlySpan data, int width, int height, int depth, int levels, int layers, bool signed)
+ public static IMemoryOwner DecodeBC4(ReadOnlySpan data, int width, int height, int depth, int levels, int layers, bool signed)
{
int size = 0;
@@ -304,8 +306,8 @@ namespace Ryujinx.Graphics.Texture
// Backends currently expect a stride alignment of 4 bytes, so output width must be aligned.
int alignedWidth = BitUtils.AlignUp(width, 4);
- byte[] output = new byte[size];
- Span outputSpan = new(output);
+ IMemoryOwner output = ByteMemoryPool.Rent(size);
+ Span outputSpan = output.Memory.Span;
ReadOnlySpan data64 = MemoryMarshal.Cast(data);
@@ -400,7 +402,7 @@ namespace Ryujinx.Graphics.Texture
return output;
}
- public static byte[] DecodeBC5(ReadOnlySpan data, int width, int height, int depth, int levels, int layers, bool signed)
+ public static IMemoryOwner DecodeBC5(ReadOnlySpan data, int width, int height, int depth, int levels, int layers, bool signed)
{
int size = 0;
@@ -412,7 +414,7 @@ namespace Ryujinx.Graphics.Texture
// Backends currently expect a stride alignment of 4 bytes, so output width must be aligned.
int alignedWidth = BitUtils.AlignUp(width, 2);
- byte[] output = new byte[size];
+ IMemoryOwner output = ByteMemoryPool.Rent(size);
ReadOnlySpan data64 = MemoryMarshal.Cast(data);
@@ -421,7 +423,7 @@ namespace Ryujinx.Graphics.Texture
Span rPal = stackalloc byte[8];
Span gPal = stackalloc byte[8];
- Span outputAsUshort = MemoryMarshal.Cast(output);
+ Span outputAsUshort = MemoryMarshal.Cast(output.Memory.Span);
Span rTileAsUint = MemoryMarshal.Cast(rTile);
Span gTileAsUint = MemoryMarshal.Cast(gTile);
@@ -525,7 +527,7 @@ namespace Ryujinx.Graphics.Texture
return output;
}
- public static byte[] DecodeBC6(ReadOnlySpan data, int width, int height, int depth, int levels, int layers, bool signed)
+ public static IMemoryOwner DecodeBC6(ReadOnlySpan data, int width, int height, int depth, int levels, int layers, bool signed)
{
int size = 0;
@@ -534,7 +536,8 @@ namespace Ryujinx.Graphics.Texture
size += Math.Max(1, width >> l) * Math.Max(1, height >> l) * Math.Max(1, depth >> l) * layers * 8;
}
- byte[] output = new byte[size];
+ IMemoryOwner output = ByteMemoryPool.Rent(size);
+ Span outputSpan = output.Memory.Span;
int inputOffset = 0;
int outputOffset = 0;
@@ -548,7 +551,7 @@ namespace Ryujinx.Graphics.Texture
{
for (int z = 0; z < depth; z++)
{
- BC6Decoder.Decode(output.AsSpan()[outputOffset..], data[inputOffset..], width, height, signed);
+ BC6Decoder.Decode(outputSpan[outputOffset..], data[inputOffset..], width, height, signed);
inputOffset += w * h * 16;
outputOffset += width * height * 8;
@@ -563,7 +566,7 @@ namespace Ryujinx.Graphics.Texture
return output;
}
- public static byte[] DecodeBC7(ReadOnlySpan data, int width, int height, int depth, int levels, int layers)
+ public static IMemoryOwner DecodeBC7(ReadOnlySpan data, int width, int height, int depth, int levels, int layers)
{
int size = 0;
@@ -572,7 +575,8 @@ namespace Ryujinx.Graphics.Texture
size += Math.Max(1, width >> l) * Math.Max(1, height >> l) * Math.Max(1, depth >> l) * layers * 4;
}
- byte[] output = new byte[size];
+ IMemoryOwner output = ByteMemoryPool.Rent(size);
+ Span outputSpan = output.Memory.Span;
int inputOffset = 0;
int outputOffset = 0;
@@ -586,7 +590,7 @@ namespace Ryujinx.Graphics.Texture
{
for (int z = 0; z < depth; z++)
{
- BC7Decoder.Decode(output.AsSpan()[outputOffset..], data[inputOffset..], width, height);
+ BC7Decoder.Decode(outputSpan[outputOffset..], data[inputOffset..], width, height);
inputOffset += w * h * 16;
outputOffset += width * height * 4;
diff --git a/src/Ryujinx.Graphics.Texture/BCnEncoder.cs b/src/Ryujinx.Graphics.Texture/BCnEncoder.cs
index 8103990f..253ba305 100644
--- a/src/Ryujinx.Graphics.Texture/BCnEncoder.cs
+++ b/src/Ryujinx.Graphics.Texture/BCnEncoder.cs
@@ -1,6 +1,8 @@
using Ryujinx.Common;
+using Ryujinx.Common.Memory;
using Ryujinx.Graphics.Texture.Encoders;
using System;
+using System.Buffers;
namespace Ryujinx.Graphics.Texture
{
@@ -9,7 +11,7 @@ namespace Ryujinx.Graphics.Texture
private const int BlockWidth = 4;
private const int BlockHeight = 4;
- public static byte[] EncodeBC7(byte[] data, int width, int height, int depth, int levels, int layers)
+ public static IMemoryOwner EncodeBC7(Memory data, int width, int height, int depth, int levels, int layers)
{
int size = 0;
@@ -21,7 +23,8 @@ namespace Ryujinx.Graphics.Texture
size += w * h * 16 * Math.Max(1, depth >> l) * layers;
}
- byte[] output = new byte[size];
+ IMemoryOwner output = ByteMemoryPool.Rent(size);
+ Memory outputMemory = output.Memory;
int imageBaseIOffs = 0;
int imageBaseOOffs = 0;
@@ -36,8 +39,8 @@ namespace Ryujinx.Graphics.Texture
for (int z = 0; z < depth; z++)
{
BC7Encoder.Encode(
- output.AsMemory()[imageBaseOOffs..],
- data.AsMemory()[imageBaseIOffs..],
+ outputMemory[imageBaseOOffs..],
+ data[imageBaseIOffs..],
width,
height,
EncodeMode.Fast | EncodeMode.Multithreaded);
diff --git a/src/Ryujinx.Graphics.Texture/ETC2Decoder.cs b/src/Ryujinx.Graphics.Texture/ETC2Decoder.cs
index 57f2e98d..52801ff4 100644
--- a/src/Ryujinx.Graphics.Texture/ETC2Decoder.cs
+++ b/src/Ryujinx.Graphics.Texture/ETC2Decoder.cs
@@ -1,5 +1,7 @@
using Ryujinx.Common;
+using Ryujinx.Common.Memory;
using System;
+using System.Buffers;
using System.Buffers.Binary;
using System.Runtime.InteropServices;
@@ -49,15 +51,15 @@ namespace Ryujinx.Graphics.Texture
new int[] { -3, -5, -7, -9, 2, 4, 6, 8 },
};
- public static byte[] DecodeRgb(ReadOnlySpan data, int width, int height, int depth, int levels, int layers)
+ public static IMemoryOwner DecodeRgb(ReadOnlySpan data, int width, int height, int depth, int levels, int layers)
{
ReadOnlySpan dataUlong = MemoryMarshal.Cast(data);
int inputOffset = 0;
- byte[] output = new byte[CalculateOutputSize(width, height, depth, levels, layers)];
+ IMemoryOwner output = ByteMemoryPool.Rent(CalculateOutputSize(width, height, depth, levels, layers));
- Span outputUint = MemoryMarshal.Cast(output);
+ Span outputUint = MemoryMarshal.Cast(output.Memory.Span);
Span tile = stackalloc uint[BlockWidth * BlockHeight];
int imageBaseOOffs = 0;
@@ -111,15 +113,15 @@ namespace Ryujinx.Graphics.Texture
return output;
}
- public static byte[] DecodePta(ReadOnlySpan data, int width, int height, int depth, int levels, int layers)
+ public static IMemoryOwner DecodePta(ReadOnlySpan data, int width, int height, int depth, int levels, int layers)
{
ReadOnlySpan dataUlong = MemoryMarshal.Cast(data);
int inputOffset = 0;
- byte[] output = new byte[CalculateOutputSize(width, height, depth, levels, layers)];
+ IMemoryOwner output = ByteMemoryPool.Rent(CalculateOutputSize(width, height, depth, levels, layers));
- Span outputUint = MemoryMarshal.Cast(output);
+ Span outputUint = MemoryMarshal.Cast(output.Memory.Span);
Span tile = stackalloc uint[BlockWidth * BlockHeight];
int imageBaseOOffs = 0;
@@ -168,15 +170,15 @@ namespace Ryujinx.Graphics.Texture
return output;
}
- public static byte[] DecodeRgba(ReadOnlySpan data, int width, int height, int depth, int levels, int layers)
+ public static IMemoryOwner DecodeRgba(ReadOnlySpan data, int width, int height, int depth, int levels, int layers)
{
ReadOnlySpan dataUlong = MemoryMarshal.Cast(data);
int inputOffset = 0;
- byte[] output = new byte[CalculateOutputSize(width, height, depth, levels, layers)];
+ IMemoryOwner output = ByteMemoryPool.Rent(CalculateOutputSize(width, height, depth, levels, layers));
- Span outputUint = MemoryMarshal.Cast(output);
+ Span outputUint = MemoryMarshal.Cast(output.Memory.Span);
Span tile = stackalloc uint[BlockWidth * BlockHeight];
int imageBaseOOffs = 0;
diff --git a/src/Ryujinx.Graphics.Texture/LayoutConverter.cs b/src/Ryujinx.Graphics.Texture/LayoutConverter.cs
index d9a666c3..d6732674 100644
--- a/src/Ryujinx.Graphics.Texture/LayoutConverter.cs
+++ b/src/Ryujinx.Graphics.Texture/LayoutConverter.cs
@@ -1,5 +1,7 @@
using Ryujinx.Common;
+using Ryujinx.Common.Memory;
using System;
+using System.Buffers;
using System.Runtime.Intrinsics;
using static Ryujinx.Graphics.Texture.BlockLinearConstants;
@@ -93,7 +95,7 @@ namespace Ryujinx.Graphics.Texture
};
}
- public static byte[] ConvertBlockLinearToLinear(
+ public static IMemoryOwner ConvertBlockLinearToLinear(
int width,
int height,
int depth,
@@ -119,7 +121,8 @@ namespace Ryujinx.Graphics.Texture
blockHeight,
bytesPerPixel);
- byte[] output = new byte[outSize];
+ IMemoryOwner outputOwner = ByteMemoryPool.Rent(outSize);
+ Span output = outputOwner.Memory.Span;
int outOffs = 0;
@@ -243,10 +246,10 @@ namespace Ryujinx.Graphics.Texture
_ => throw new NotSupportedException($"Unable to convert ${bytesPerPixel} bpp pixel format."),
};
}
- return output;
+ return outputOwner;
}
- public static byte[] ConvertLinearStridedToLinear(
+ public static IMemoryOwner ConvertLinearStridedToLinear(
int width,
int height,
int blockWidth,
@@ -262,8 +265,8 @@ namespace Ryujinx.Graphics.Texture
int outStride = BitUtils.AlignUp(w * bytesPerPixel, HostStrideAlignment);
lineSize = Math.Min(lineSize, outStride);
- byte[] output = new byte[h * outStride];
- Span outSpan = output;
+ IMemoryOwner output = ByteMemoryPool.Rent(h * outStride);
+ Span outSpan = output.Memory.Span;
int outOffs = 0;
int inOffs = 0;
diff --git a/src/Ryujinx.Graphics.Texture/PixelConverter.cs b/src/Ryujinx.Graphics.Texture/PixelConverter.cs
index 7955aed3..4475cc98 100644
--- a/src/Ryujinx.Graphics.Texture/PixelConverter.cs
+++ b/src/Ryujinx.Graphics.Texture/PixelConverter.cs
@@ -1,5 +1,7 @@
using Ryujinx.Common;
+using Ryujinx.Common.Memory;
using System;
+using System.Buffers;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
@@ -19,13 +21,13 @@ namespace Ryujinx.Graphics.Texture
return (remainder, outRemainder, length / stride);
}
- public unsafe static byte[] ConvertR4G4ToR4G4B4A4(ReadOnlySpan data, int width)
+ public unsafe static IMemoryOwner ConvertR4G4ToR4G4B4A4(ReadOnlySpan data, int width)
{
- byte[] output = new byte[data.Length * 2];
+ IMemoryOwner output = ByteMemoryPool.Rent(data.Length * 2);
(int remainder, int outRemainder, int height) = GetLineRemainders(data.Length, width, 1, 2);
- Span outputSpan = MemoryMarshal.Cast