diff --git a/src/Ryujinx.Graphics.Texture/Astc/AstcDecoder.cs b/src/Ryujinx.Graphics.Texture/Astc/AstcDecoder.cs index edf699dc32..3f65e1225b 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 2d68ca3468..eb85334a21 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 8103990ff3..253ba305cd 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 57f2e98d08..52801ff47d 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 d9a666c3f0..d6732674b5 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 7955aed3f1..27d1340741 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(output); + Span outputSpan = MemoryMarshal.Cast(output.Memory.Span); if (remainder == 0) { @@ -36,7 +38,7 @@ namespace Ryujinx.Graphics.Texture int sizeTrunc = data.Length & ~7; start = sizeTrunc; - fixed (byte* inputPtr = data, outputPtr = output) + fixed (byte* inputPtr = data, outputPtr = output.Memory.Span) { for (ulong offset = 0; offset < (ulong)sizeTrunc; offset += 8) { @@ -70,16 +72,16 @@ namespace Ryujinx.Graphics.Texture return output; } - public unsafe static byte[] ConvertR5G6B5ToR8G8B8A8(ReadOnlySpan data, int width) + public unsafe static IMemoryOwner ConvertR5G6B5ToR8G8B8A8(ReadOnlySpan data, int width) { - byte[] output = new byte[data.Length * 2]; + IMemoryOwner output = ByteMemoryPool.Rent(data.Length * 2); int offset = 0; int outOffset = 0; (int remainder, int outRemainder, int height) = GetLineRemainders(data.Length, width, 2, 4); ReadOnlySpan inputSpan = MemoryMarshal.Cast(data); - Span outputSpan = MemoryMarshal.Cast(output); + Span outputSpan = MemoryMarshal.Cast(output.Memory.Span); for (int y = 0; y < height; y++) { @@ -107,16 +109,16 @@ namespace Ryujinx.Graphics.Texture return output; } - public unsafe static byte[] ConvertR5G5B5ToR8G8B8A8(ReadOnlySpan data, int width, bool forceAlpha) + public unsafe static IMemoryOwner ConvertR5G5B5ToR8G8B8A8(ReadOnlySpan data, int width, bool forceAlpha) { - byte[] output = new byte[data.Length * 2]; + IMemoryOwner output = ByteMemoryPool.Rent(data.Length * 2); int offset = 0; int outOffset = 0; (int remainder, int outRemainder, int height) = GetLineRemainders(data.Length, width, 2, 4); ReadOnlySpan inputSpan = MemoryMarshal.Cast(data); - Span outputSpan = MemoryMarshal.Cast(output); + Span outputSpan = MemoryMarshal.Cast(output.Memory.Span); for (int y = 0; y < height; y++) { @@ -144,16 +146,16 @@ namespace Ryujinx.Graphics.Texture return output; } - public unsafe static byte[] ConvertA1B5G5R5ToR8G8B8A8(ReadOnlySpan data, int width) + public unsafe static IMemoryOwner ConvertA1B5G5R5ToR8G8B8A8(ReadOnlySpan data, int width) { - byte[] output = new byte[data.Length * 2]; + IMemoryOwner output = ByteMemoryPool.Rent(data.Length * 2); int offset = 0; int outOffset = 0; (int remainder, int outRemainder, int height) = GetLineRemainders(data.Length, width, 2, 4); ReadOnlySpan inputSpan = MemoryMarshal.Cast(data); - Span outputSpan = MemoryMarshal.Cast(output); + Span outputSpan = MemoryMarshal.Cast(output.Memory.Span); for (int y = 0; y < height; y++) { @@ -181,16 +183,16 @@ namespace Ryujinx.Graphics.Texture return output; } - public unsafe static byte[] ConvertR4G4B4A4ToR8G8B8A8(ReadOnlySpan data, int width) + public unsafe static IMemoryOwner ConvertR4G4B4A4ToR8G8B8A8(ReadOnlySpan data, int width) { - byte[] output = new byte[data.Length * 2]; + IMemoryOwner output = ByteMemoryPool.Rent(data.Length * 2); int offset = 0; int outOffset = 0; (int remainder, int outRemainder, int height) = GetLineRemainders(data.Length, width, 2, 4); ReadOnlySpan inputSpan = MemoryMarshal.Cast(data); - Span outputSpan = MemoryMarshal.Cast(output); + Span outputSpan = MemoryMarshal.Cast(output.Memory.Span); for (int y = 0; y < height; y++) {