Port of texture memory pool PR

This commit is contained in:
riperiperi 2024-01-12 17:56:48 +00:00
parent e9abc7e59e
commit 092af4585c
20 changed files with 228 additions and 138 deletions

View File

@ -1,4 +1,5 @@
using Ryujinx.Common.Memory; using Ryujinx.Common.Memory;
using System.Buffers;
namespace Ryujinx.Graphics.GAL namespace Ryujinx.Graphics.GAL
{ {
@ -17,9 +18,29 @@ namespace Ryujinx.Graphics.GAL
PinnedSpan<byte> GetData(); PinnedSpan<byte> GetData();
PinnedSpan<byte> GetData(int layer, int level); PinnedSpan<byte> GetData(int layer, int level);
void SetData(SpanOrArray<byte> data); /// <summary>
void SetData(SpanOrArray<byte> data, int layer, int level); /// Sets the texture data. The data passed as a <see cref="IMemoryOwner{Byte}" /> will be disposed when the operation completes.
void SetData(SpanOrArray<byte> data, int layer, int level, Rectangle<int> region); /// </summary>
/// <param name="data">Texture data bytes</param>
void SetData(IMemoryOwner<byte> data);
/// <summary>
/// Sets the texture data. The data passed as a <see cref="IMemoryOwner{Byte}" /> will be disposed when the operation completes.
/// </summary>
/// <param name="data">Texture data bytes</param>
/// <param name="layer">Target layer</param>
/// <param name="level">Target level</param>
void SetData(IMemoryOwner<byte> data, int layer, int level);
/// <summary>
/// Sets the texture data. The data passed as a <see cref="IMemoryOwner{Byte}" /> will be disposed when the operation completes.
/// </summary>
/// <param name="data">Texture data bytes</param>
/// <param name="layer">Target layer</param>
/// <param name="level">Target level</param>
/// <param name="region">Target sub-region of the texture to update</param>
void SetData(IMemoryOwner<byte> data, int layer, int level, Rectangle<int> region);
void SetStorage(BufferRange buffer); void SetStorage(BufferRange buffer);
void Release(); void Release();
} }

View File

@ -1,6 +1,7 @@
using Ryujinx.Graphics.GAL.Multithreading.Model; using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources; using Ryujinx.Graphics.GAL.Multithreading.Resources;
using System; using System;
using System.Buffers;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
{ {
@ -8,9 +9,9 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
{ {
public readonly CommandType CommandType => CommandType.TextureSetData; public readonly CommandType CommandType => CommandType.TextureSetData;
private TableRef<ThreadedTexture> _texture; private TableRef<ThreadedTexture> _texture;
private TableRef<byte[]> _data; private TableRef<IMemoryOwner<byte>> _data;
public void Set(TableRef<ThreadedTexture> texture, TableRef<byte[]> data) public void Set(TableRef<ThreadedTexture> texture, TableRef<IMemoryOwner<byte>> data)
{ {
_texture = texture; _texture = texture;
_data = data; _data = data;
@ -19,7 +20,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
public static void Run(ref TextureSetDataCommand command, ThreadedRenderer threaded, IRenderer renderer) public static void Run(ref TextureSetDataCommand command, ThreadedRenderer threaded, IRenderer renderer)
{ {
ThreadedTexture texture = command._texture.Get(threaded); ThreadedTexture texture = command._texture.Get(threaded);
texture.Base.SetData(new ReadOnlySpan<byte>(command._data.Get(threaded))); texture.Base.SetData(command._data.Get(threaded));
} }
} }
} }

View File

@ -1,6 +1,7 @@
using Ryujinx.Graphics.GAL.Multithreading.Model; using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources; using Ryujinx.Graphics.GAL.Multithreading.Resources;
using System; using System;
using System.Buffers;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
{ {
@ -8,11 +9,11 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
{ {
public readonly CommandType CommandType => CommandType.TextureSetDataSlice; public readonly CommandType CommandType => CommandType.TextureSetDataSlice;
private TableRef<ThreadedTexture> _texture; private TableRef<ThreadedTexture> _texture;
private TableRef<byte[]> _data; private TableRef<IMemoryOwner<byte>> _data;
private int _layer; private int _layer;
private int _level; private int _level;
public void Set(TableRef<ThreadedTexture> texture, TableRef<byte[]> data, int layer, int level) public void Set(TableRef<ThreadedTexture> texture, TableRef<IMemoryOwner<byte>> data, int layer, int level)
{ {
_texture = texture; _texture = texture;
_data = data; _data = data;
@ -23,7 +24,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
public static void Run(ref TextureSetDataSliceCommand command, ThreadedRenderer threaded, IRenderer renderer) public static void Run(ref TextureSetDataSliceCommand command, ThreadedRenderer threaded, IRenderer renderer)
{ {
ThreadedTexture texture = command._texture.Get(threaded); ThreadedTexture texture = command._texture.Get(threaded);
texture.Base.SetData(new ReadOnlySpan<byte>(command._data.Get(threaded)), command._layer, command._level); texture.Base.SetData(command._data.Get(threaded), command._layer, command._level);
} }
} }
} }

View File

@ -1,6 +1,7 @@
using Ryujinx.Graphics.GAL.Multithreading.Model; using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources; using Ryujinx.Graphics.GAL.Multithreading.Resources;
using System; using System;
using System.Buffers;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
{ {
@ -8,12 +9,12 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
{ {
public readonly CommandType CommandType => CommandType.TextureSetDataSliceRegion; public readonly CommandType CommandType => CommandType.TextureSetDataSliceRegion;
private TableRef<ThreadedTexture> _texture; private TableRef<ThreadedTexture> _texture;
private TableRef<byte[]> _data; private TableRef<IMemoryOwner<byte>> _data;
private int _layer; private int _layer;
private int _level; private int _level;
private Rectangle<int> _region; private Rectangle<int> _region;
public void Set(TableRef<ThreadedTexture> texture, TableRef<byte[]> data, int layer, int level, Rectangle<int> region) public void Set(TableRef<ThreadedTexture> texture, TableRef<IMemoryOwner<byte>> data, int layer, int level, Rectangle<int> region)
{ {
_texture = texture; _texture = texture;
_data = data; _data = data;
@ -25,7 +26,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
public static void Run(ref TextureSetDataSliceRegionCommand command, ThreadedRenderer threaded, IRenderer renderer) public static void Run(ref TextureSetDataSliceRegionCommand command, ThreadedRenderer threaded, IRenderer renderer)
{ {
ThreadedTexture texture = command._texture.Get(threaded); ThreadedTexture texture = command._texture.Get(threaded);
texture.Base.SetData(new ReadOnlySpan<byte>(command._data.Get(threaded)), command._layer, command._level, command._region); texture.Base.SetData(command._data.Get(threaded), command._layer, command._level, command._region);
} }
} }
} }

View File

@ -1,6 +1,7 @@
using Ryujinx.Common.Memory; using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL.Multithreading.Commands.Texture; using Ryujinx.Graphics.GAL.Multithreading.Commands.Texture;
using Ryujinx.Graphics.GAL.Multithreading.Model; using Ryujinx.Graphics.GAL.Multithreading.Model;
using System.Buffers;
namespace Ryujinx.Graphics.GAL.Multithreading.Resources namespace Ryujinx.Graphics.GAL.Multithreading.Resources
{ {
@ -110,21 +111,21 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetData(SpanOrArray<byte> data) public void SetData(IMemoryOwner<byte> data)
{ {
_renderer.New<TextureSetDataCommand>().Set(Ref(this), Ref(data.ToArray())); _renderer.New<TextureSetDataCommand>().Set(Ref(this), Ref(data));
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetData(SpanOrArray<byte> data, int layer, int level) public void SetData(IMemoryOwner<byte> data, int layer, int level)
{ {
_renderer.New<TextureSetDataSliceCommand>().Set(Ref(this), Ref(data.ToArray()), layer, level); _renderer.New<TextureSetDataSliceCommand>().Set(Ref(this), Ref(data), layer, level);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetData(SpanOrArray<byte> data, int layer, int level, Rectangle<int> region) public void SetData(IMemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
{ {
_renderer.New<TextureSetDataSliceRegionCommand>().Set(Ref(this), Ref(data.ToArray()), layer, level, region); _renderer.New<TextureSetDataSliceRegionCommand>().Set(Ref(this), Ref(data), layer, level, region);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }

View File

@ -4,6 +4,7 @@ using Ryujinx.Graphics.Gpu.Engine.Threed;
using Ryujinx.Graphics.Gpu.Memory; using Ryujinx.Graphics.Gpu.Memory;
using Ryujinx.Graphics.Texture; using Ryujinx.Graphics.Texture;
using System; using System;
using System.Buffers;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@ -300,7 +301,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
if (target != null) if (target != null)
{ {
byte[] data; IMemoryOwner<byte> data;
if (srcLinear) if (srcLinear)
{ {
data = LayoutConverter.ConvertLinearStridedToLinear( data = LayoutConverter.ConvertLinearStridedToLinear(

View File

@ -1,4 +1,5 @@
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.Device; using Ryujinx.Graphics.Device;
using Ryujinx.Graphics.Texture; using Ryujinx.Graphics.Texture;
using System; using System;
@ -197,8 +198,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.InlineToMemory
if (target != null) if (target != null)
{ {
var memory = ByteMemoryPool.Rent(data.Length);
data.CopyTo(memory.Memory.Span);
target.SynchronizeMemory(); target.SynchronizeMemory();
target.SetData(data, 0, 0, new GAL.Rectangle<int>(_dstX, _dstY, _lineLengthIn / target.Info.FormatInfo.BytesPerPixel, _lineCount)); target.SetData(memory, 0, 0, new GAL.Rectangle<int>(_dstX, _dstY, _lineLengthIn / target.Info.FormatInfo.BytesPerPixel, _lineCount));
target.SignalModified(); target.SignalModified();
return; return;

View File

@ -7,6 +7,7 @@ using Ryujinx.Graphics.Texture.Astc;
using Ryujinx.Memory; using Ryujinx.Memory;
using Ryujinx.Memory.Range; using Ryujinx.Memory.Range;
using System; using System;
using System.Buffers;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
@ -661,7 +662,7 @@ namespace Ryujinx.Graphics.Gpu.Image
} }
} }
SpanOrArray<byte> result = ConvertToHostCompatibleFormat(data); IMemoryOwner<byte> result = ConvertToHostCompatibleFormat(data);
if (ScaleFactor != 1f && AllowScaledSetData()) if (ScaleFactor != 1f && AllowScaledSetData())
{ {
@ -681,10 +682,10 @@ namespace Ryujinx.Graphics.Gpu.Image
} }
/// <summary> /// <summary>
/// Uploads new texture data to the host GPU. /// Uploads new texture data to the host GPU. The data passed as a <see cref="IMemoryOwner{Byte}" /> will be disposed when the operation completes.
/// </summary> /// </summary>
/// <param name="data">New data</param> /// <param name="data">New data</param>
public void SetData(SpanOrArray<byte> data) public void SetData(IMemoryOwner<byte> data)
{ {
BlacklistScale(); BlacklistScale();
@ -698,12 +699,12 @@ namespace Ryujinx.Graphics.Gpu.Image
} }
/// <summary> /// <summary>
/// Uploads new texture data to the host GPU for a specific layer/level. /// Uploads new texture data to the host GPU for a specific layer/level. The data passed as a <see cref="IMemoryOwner{Byte}" /> will be disposed when the operation completes.
/// </summary> /// </summary>
/// <param name="data">New data</param> /// <param name="data">New data</param>
/// <param name="layer">Target layer</param> /// <param name="layer">Target layer</param>
/// <param name="level">Target level</param> /// <param name="level">Target level</param>
public void SetData(SpanOrArray<byte> data, int layer, int level) public void SetData(IMemoryOwner<byte> data, int layer, int level)
{ {
BlacklistScale(); BlacklistScale();
@ -715,13 +716,13 @@ namespace Ryujinx.Graphics.Gpu.Image
} }
/// <summary> /// <summary>
/// Uploads new texture data to the host GPU for a specific layer/level and 2D sub-region. /// Uploads new texture data to the host GPU for a specific layer/level and 2D sub-region. The data passed as a <see cref="IMemoryOwner{Byte}" /> will be disposed when the operation completes.
/// </summary> /// </summary>
/// <param name="data">New data</param> /// <param name="data">New data</param>
/// <param name="layer">Target layer</param> /// <param name="layer">Target layer</param>
/// <param name="level">Target level</param> /// <param name="level">Target level</param>
/// <param name="region">Target sub-region of the texture to update</param> /// <param name="region">Target sub-region of the texture to update</param>
public void SetData(ReadOnlySpan<byte> data, int layer, int level, Rectangle<int> region) public void SetData(IMemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
{ {
BlacklistScale(); BlacklistScale();
@ -739,7 +740,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <param name="level">Mip level to convert</param> /// <param name="level">Mip level to convert</param>
/// <param name="single">True to convert a single slice</param> /// <param name="single">True to convert a single slice</param>
/// <returns>Converted data</returns> /// <returns>Converted data</returns>
public SpanOrArray<byte> ConvertToHostCompatibleFormat(ReadOnlySpan<byte> data, int level = 0, bool single = false) public IMemoryOwner<byte> ConvertToHostCompatibleFormat(ReadOnlySpan<byte> data, int level = 0, bool single = false)
{ {
int width = Info.Width; int width = Info.Width;
int height = Info.Height; int height = Info.Height;
@ -754,11 +755,11 @@ namespace Ryujinx.Graphics.Gpu.Image
int sliceDepth = single ? 1 : depth; int sliceDepth = single ? 1 : depth;
SpanOrArray<byte> result; IMemoryOwner<byte> linear;
if (Info.IsLinear) if (Info.IsLinear)
{ {
result = LayoutConverter.ConvertLinearStridedToLinear( linear = LayoutConverter.ConvertLinearStridedToLinear(
width, width,
height, height,
Info.FormatInfo.BlockWidth, Info.FormatInfo.BlockWidth,
@ -770,7 +771,7 @@ namespace Ryujinx.Graphics.Gpu.Image
} }
else else
{ {
result = LayoutConverter.ConvertBlockLinearToLinear( linear = LayoutConverter.ConvertBlockLinearToLinear(
width, width,
height, height,
depth, depth,
@ -787,13 +788,15 @@ namespace Ryujinx.Graphics.Gpu.Image
data); data);
} }
IMemoryOwner<byte> result = linear;
// Handle compressed cases not supported by the host: // Handle compressed cases not supported by the host:
// - ASTC is usually not supported on desktop cards. // - ASTC is usually not supported on desktop cards.
// - BC4/BC5 is not supported on 3D textures. // - BC4/BC5 is not supported on 3D textures.
if (!_context.Capabilities.SupportsAstcCompression && Format.IsAstc()) if (!_context.Capabilities.SupportsAstcCompression && Format.IsAstc())
{ {
if (!AstcDecoder.TryDecodeToRgba8P( if (!AstcDecoder.TryDecodeToRgba8P(
result.ToArray(), result.Memory,
Info.FormatInfo.BlockWidth, Info.FormatInfo.BlockWidth,
Info.FormatInfo.BlockHeight, Info.FormatInfo.BlockHeight,
width, width,
@ -801,7 +804,7 @@ namespace Ryujinx.Graphics.Gpu.Image
sliceDepth, sliceDepth,
levels, levels,
layers, layers,
out byte[] decoded)) out IMemoryOwner<byte> decoded))
{ {
string texInfo = $"{Info.Target} {Info.FormatInfo.Format} {Info.Width}x{Info.Height}x{Info.DepthOrLayers} levels {Info.Levels}"; string texInfo = $"{Info.Target} {Info.FormatInfo.Format} {Info.Width}x{Info.Height}x{Info.DepthOrLayers} levels {Info.Levels}";
@ -810,26 +813,31 @@ namespace Ryujinx.Graphics.Gpu.Image
if (GraphicsConfig.EnableTextureRecompression) if (GraphicsConfig.EnableTextureRecompression)
{ {
decoded = BCnEncoder.EncodeBC7(decoded, width, height, sliceDepth, levels, layers); using (decoded)
{
result = BCnEncoder.EncodeBC7(decoded.Memory, width, height, sliceDepth, levels, layers);
} }
}
else
{
result = decoded; result = decoded;
} }
}
else if (!_context.Capabilities.SupportsEtc2Compression && Format.IsEtc2()) else if (!_context.Capabilities.SupportsEtc2Compression && Format.IsEtc2())
{ {
switch (Format) switch (Format)
{ {
case Format.Etc2RgbaSrgb: case Format.Etc2RgbaSrgb:
case Format.Etc2RgbaUnorm: case Format.Etc2RgbaUnorm:
result = ETC2Decoder.DecodeRgba(result, width, height, sliceDepth, levels, layers); result = ETC2Decoder.DecodeRgba(result.Memory.Span, width, height, sliceDepth, levels, layers);
break; break;
case Format.Etc2RgbPtaSrgb: case Format.Etc2RgbPtaSrgb:
case Format.Etc2RgbPtaUnorm: case Format.Etc2RgbPtaUnorm:
result = ETC2Decoder.DecodePta(result, width, height, sliceDepth, levels, layers); result = ETC2Decoder.DecodePta(result.Memory.Span, width, height, sliceDepth, levels, layers);
break; break;
case Format.Etc2RgbSrgb: case Format.Etc2RgbSrgb:
case Format.Etc2RgbUnorm: case Format.Etc2RgbUnorm:
result = ETC2Decoder.DecodeRgb(result, width, height, sliceDepth, levels, layers); result = ETC2Decoder.DecodeRgb(result.Memory.Span, width, height, sliceDepth, levels, layers);
break; break;
} }
} }
@ -839,48 +847,55 @@ namespace Ryujinx.Graphics.Gpu.Image
{ {
case Format.Bc1RgbaSrgb: case Format.Bc1RgbaSrgb:
case Format.Bc1RgbaUnorm: case Format.Bc1RgbaUnorm:
result = BCnDecoder.DecodeBC1(result, width, height, sliceDepth, levels, layers); result = BCnDecoder.DecodeBC1(result.Memory.Span, width, height, sliceDepth, levels, layers);
break; break;
case Format.Bc2Srgb: case Format.Bc2Srgb:
case Format.Bc2Unorm: case Format.Bc2Unorm:
result = BCnDecoder.DecodeBC2(result, width, height, sliceDepth, levels, layers); result = BCnDecoder.DecodeBC2(result.Memory.Span, width, height, sliceDepth, levels, layers);
break; break;
case Format.Bc3Srgb: case Format.Bc3Srgb:
case Format.Bc3Unorm: case Format.Bc3Unorm:
result = BCnDecoder.DecodeBC3(result, width, height, sliceDepth, levels, layers); result = BCnDecoder.DecodeBC3(result.Memory.Span, width, height, sliceDepth, levels, layers);
break; break;
case Format.Bc4Snorm: case Format.Bc4Snorm:
case Format.Bc4Unorm: case Format.Bc4Unorm:
result = BCnDecoder.DecodeBC4(result, width, height, sliceDepth, levels, layers, Format == Format.Bc4Snorm); result = BCnDecoder.DecodeBC4(result.Memory.Span, width, height, sliceDepth, levels, layers, Format == Format.Bc4Snorm);
break; break;
case Format.Bc5Snorm: case Format.Bc5Snorm:
case Format.Bc5Unorm: case Format.Bc5Unorm:
result = BCnDecoder.DecodeBC5(result, width, height, sliceDepth, levels, layers, Format == Format.Bc5Snorm); result = BCnDecoder.DecodeBC5(result.Memory.Span, width, height, sliceDepth, levels, layers, Format == Format.Bc5Snorm);
break; break;
case Format.Bc6HSfloat: case Format.Bc6HSfloat:
case Format.Bc6HUfloat: case Format.Bc6HUfloat:
result = BCnDecoder.DecodeBC6(result, width, height, sliceDepth, levels, layers, Format == Format.Bc6HSfloat); result = BCnDecoder.DecodeBC6(result.Memory.Span, width, height, sliceDepth, levels, layers, Format == Format.Bc6HSfloat);
break; break;
case Format.Bc7Srgb: case Format.Bc7Srgb:
case Format.Bc7Unorm: case Format.Bc7Unorm:
result = BCnDecoder.DecodeBC7(result, width, height, sliceDepth, levels, layers); result = BCnDecoder.DecodeBC7(result.Memory.Span, width, height, sliceDepth, levels, layers);
break; break;
} }
} }
else if (!_context.Capabilities.SupportsR4G4Format && Format == Format.R4G4Unorm) else if (!_context.Capabilities.SupportsR4G4Format && Format == Format.R4G4Unorm)
{ {
result = PixelConverter.ConvertR4G4ToR4G4B4A4(result, width); var converted = PixelConverter.ConvertR4G4ToR4G4B4A4(result.Memory.Span, width);
if (!_context.Capabilities.SupportsR4G4B4A4Format) if (!_context.Capabilities.SupportsR4G4B4A4Format)
{ {
result = PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(result, width); using (converted)
{
result = PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(converted.Memory.Span, width);
}
}
else
{
result = converted;
} }
} }
else if (Format == Format.R4G4B4A4Unorm) else if (Format == Format.R4G4B4A4Unorm)
{ {
if (!_context.Capabilities.SupportsR4G4B4A4Format) if (!_context.Capabilities.SupportsR4G4B4A4Format)
{ {
result = PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(result, width); result = PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(result.Memory.Span, width);
} }
} }
else if (!_context.Capabilities.Supports5BitComponentFormat && Format.Is16BitPacked()) else if (!_context.Capabilities.Supports5BitComponentFormat && Format.Is16BitPacked())
@ -889,22 +904,27 @@ namespace Ryujinx.Graphics.Gpu.Image
{ {
case Format.B5G6R5Unorm: case Format.B5G6R5Unorm:
case Format.R5G6B5Unorm: case Format.R5G6B5Unorm:
result = PixelConverter.ConvertR5G6B5ToR8G8B8A8(result, width); result = PixelConverter.ConvertR5G6B5ToR8G8B8A8(result.Memory.Span, width);
break; break;
case Format.B5G5R5A1Unorm: case Format.B5G5R5A1Unorm:
case Format.R5G5B5X1Unorm: case Format.R5G5B5X1Unorm:
case Format.R5G5B5A1Unorm: case Format.R5G5B5A1Unorm:
result = PixelConverter.ConvertR5G5B5ToR8G8B8A8(result, width, Format == Format.R5G5B5X1Unorm); result = PixelConverter.ConvertR5G5B5ToR8G8B8A8(result.Memory.Span, width, Format == Format.R5G5B5X1Unorm);
break; break;
case Format.A1B5G5R5Unorm: case Format.A1B5G5R5Unorm:
result = PixelConverter.ConvertA1B5G5R5ToR8G8B8A8(result, width); result = PixelConverter.ConvertA1B5G5R5ToR8G8B8A8(result.Memory.Span, width);
break; break;
case Format.R4G4B4A4Unorm: case Format.R4G4B4A4Unorm:
result = PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(result, width); result = PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(result.Memory.Span, width);
break; break;
} }
} }
if (!ReferenceEquals(linear, result))
{
linear.Dispose();
}
return result; return result;
} }

View File

@ -6,6 +6,7 @@ using Ryujinx.Memory;
using Ryujinx.Memory.Range; using Ryujinx.Memory.Range;
using Ryujinx.Memory.Tracking; using Ryujinx.Memory.Tracking;
using System; using System;
using System.Buffers;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
@ -445,7 +446,7 @@ namespace Ryujinx.Graphics.Gpu.Image
ReadOnlySpan<byte> data = dataSpan[(offset - spanBase)..]; ReadOnlySpan<byte> data = dataSpan[(offset - spanBase)..];
SpanOrArray<byte> result = Storage.ConvertToHostCompatibleFormat(data, info.BaseLevel + level, true); IMemoryOwner<byte> result = Storage.ConvertToHostCompatibleFormat(data, info.BaseLevel + level, true);
Storage.SetData(result, info.BaseLayer + layer, info.BaseLevel + level); Storage.SetData(result, info.BaseLayer + layer, info.BaseLevel + level);
} }

View File

@ -2,6 +2,7 @@ using OpenTK.Graphics.OpenGL;
using Ryujinx.Common.Memory; using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using System; using System;
using System.Buffers;
namespace Ryujinx.Graphics.OpenGL.Image namespace Ryujinx.Graphics.OpenGL.Image
{ {
@ -54,20 +55,24 @@ namespace Ryujinx.Graphics.OpenGL.Image
throw new NotImplementedException(); throw new NotImplementedException();
} }
public void SetData(SpanOrArray<byte> data) public void SetData(IMemoryOwner<byte> data)
{ {
var dataSpan = data.AsSpan(); var dataSpan = data.Memory.Span;
Buffer.SetData(_buffer, _bufferOffset, dataSpan[..Math.Min(dataSpan.Length, _bufferSize)]); Buffer.SetData(_buffer, _bufferOffset, dataSpan[..Math.Min(dataSpan.Length, _bufferSize)]);
data.Dispose();
} }
public void SetData(SpanOrArray<byte> data, int layer, int level) public void SetData(IMemoryOwner<byte> data, int layer, int level)
{ {
data.Dispose();
throw new NotSupportedException(); throw new NotSupportedException();
} }
public void SetData(SpanOrArray<byte> data, int layer, int level, Rectangle<int> region) public void SetData(IMemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
{ {
data.Dispose();
throw new NotSupportedException(); throw new NotSupportedException();
} }

View File

@ -15,7 +15,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
private int _viewsCount; private int _viewsCount;
internal ITexture DefaultView { get; private set; } internal TextureView DefaultView { get; private set; }
public TextureStorage(OpenGLRenderer renderer, TextureCreateInfo info) public TextureStorage(OpenGLRenderer renderer, TextureCreateInfo info)
{ {
@ -144,14 +144,14 @@ namespace Ryujinx.Graphics.OpenGL.Image
} }
} }
public ITexture CreateDefaultView() public TextureView CreateDefaultView()
{ {
DefaultView = CreateView(Info, 0, 0); DefaultView = CreateView(Info, 0, 0);
return DefaultView; return DefaultView;
} }
public ITexture CreateView(TextureCreateInfo info, int firstLayer, int firstLevel) public TextureView CreateView(TextureCreateInfo info, int firstLayer, int firstLevel)
{ {
IncrementViewsCount(); IncrementViewsCount();

View File

@ -3,6 +3,7 @@ using Ryujinx.Common;
using Ryujinx.Common.Memory; using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using System; using System;
using System.Buffers;
using System.Diagnostics; using System.Diagnostics;
namespace Ryujinx.Graphics.OpenGL.Image namespace Ryujinx.Graphics.OpenGL.Image
@ -448,10 +449,8 @@ namespace Ryujinx.Graphics.OpenGL.Image
} }
} }
public void SetData(SpanOrArray<byte> data) public void SetData(ReadOnlySpan<byte> dataSpan)
{ {
var dataSpan = data.AsSpan();
if (Format == Format.S8UintD24Unorm) if (Format == Format.S8UintD24Unorm)
{ {
dataSpan = FormatConverter.ConvertS8D24ToD24S8(dataSpan); dataSpan = FormatConverter.ConvertS8D24ToD24S8(dataSpan);
@ -466,9 +465,16 @@ namespace Ryujinx.Graphics.OpenGL.Image
} }
} }
public void SetData(SpanOrArray<byte> data, int layer, int level) public void SetData(IMemoryOwner<byte> data)
{ {
var dataSpan = data.AsSpan(); SetData(data.Memory.Span);
data.Dispose();
}
public void SetData(IMemoryOwner<byte> data, int layer, int level)
{
var dataSpan = data.Memory.Span;
if (Format == Format.S8UintD24Unorm) if (Format == Format.S8UintD24Unorm)
{ {
@ -485,11 +491,13 @@ namespace Ryujinx.Graphics.OpenGL.Image
ReadFrom2D((IntPtr)ptr, layer, level, 0, 0, width, height); ReadFrom2D((IntPtr)ptr, layer, level, 0, 0, width, height);
} }
} }
data.Dispose();
} }
public void SetData(SpanOrArray<byte> data, int layer, int level, Rectangle<int> region) public void SetData(IMemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
{ {
var dataSpan = data.AsSpan(); var dataSpan = data.Memory.Span;
if (Format == Format.S8UintD24Unorm) if (Format == Format.S8UintD24Unorm)
{ {
@ -514,6 +522,8 @@ namespace Ryujinx.Graphics.OpenGL.Image
BitUtils.AlignUp(wInBlocks * Info.BytesPerPixel, 4) * hInBlocks); BitUtils.AlignUp(wInBlocks * Info.BytesPerPixel, 4) * hInBlocks);
} }
} }
data.Dispose();
} }
public void ReadFromPbo(int offset, int size) public void ReadFromPbo(int offset, int size)

View File

@ -1,5 +1,7 @@
using Ryujinx.Common.Memory;
using Ryujinx.Common.Utilities; using Ryujinx.Common.Utilities;
using System; using System;
using System.Buffers;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
@ -291,16 +293,14 @@ namespace Ryujinx.Graphics.Texture.Astc
int depth, int depth,
int levels, int levels,
int layers, int layers,
out byte[] decoded) out IMemoryOwner<byte> 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)); Enumerable.Range(0, decoder.TotalBlockCount).AsParallel().ForAll(x => decoder.ProcessBlock(x));
decoded = output;
return decoder.Success; return decoder.Success;
} }

View File

@ -1,5 +1,7 @@
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Memory;
using System; using System;
using System.Buffers;
using System.Buffers.Binary; using System.Buffers.Binary;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Runtime.Intrinsics; using System.Runtime.Intrinsics;
@ -12,7 +14,7 @@ namespace Ryujinx.Graphics.Texture
private const int BlockWidth = 4; private const int BlockWidth = 4;
private const int BlockHeight = 4; private const int BlockHeight = 4;
public static byte[] DecodeBC1(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers) public static IMemoryOwner<byte> DecodeBC1(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers)
{ {
int size = 0; 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; size += Math.Max(1, width >> l) * Math.Max(1, height >> l) * Math.Max(1, depth >> l) * layers * 4;
} }
byte[] output = new byte[size]; IMemoryOwner<byte> output = ByteMemoryPool.Rent(size);
Span<byte> tile = stackalloc byte[BlockWidth * BlockHeight * 4]; Span<byte> tile = stackalloc byte[BlockWidth * BlockHeight * 4];
Span<uint> tileAsUint = MemoryMarshal.Cast<byte, uint>(tile); Span<uint> tileAsUint = MemoryMarshal.Cast<byte, uint>(tile);
Span<uint> outputAsUint = MemoryMarshal.Cast<byte, uint>(output); Span<uint> outputAsUint = MemoryMarshal.Cast<byte, uint>(output.Memory.Span);
Span<Vector128<byte>> tileAsVector128 = MemoryMarshal.Cast<byte, Vector128<byte>>(tile); Span<Vector128<byte>> tileAsVector128 = MemoryMarshal.Cast<byte, Vector128<byte>>(tile);
@ -100,7 +102,7 @@ namespace Ryujinx.Graphics.Texture
return output; return output;
} }
public static byte[] DecodeBC2(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers) public static IMemoryOwner<byte> DecodeBC2(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers)
{ {
int size = 0; 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; size += Math.Max(1, width >> l) * Math.Max(1, height >> l) * Math.Max(1, depth >> l) * layers * 4;
} }
byte[] output = new byte[size]; IMemoryOwner<byte> output = ByteMemoryPool.Rent(size);
Span<byte> tile = stackalloc byte[BlockWidth * BlockHeight * 4]; Span<byte> tile = stackalloc byte[BlockWidth * BlockHeight * 4];
Span<uint> tileAsUint = MemoryMarshal.Cast<byte, uint>(tile); Span<uint> tileAsUint = MemoryMarshal.Cast<byte, uint>(tile);
Span<uint> outputAsUint = MemoryMarshal.Cast<byte, uint>(output); Span<uint> outputAsUint = MemoryMarshal.Cast<byte, uint>(output.Memory.Span);
Span<Vector128<byte>> tileAsVector128 = MemoryMarshal.Cast<byte, Vector128<byte>>(tile); Span<Vector128<byte>> tileAsVector128 = MemoryMarshal.Cast<byte, Vector128<byte>>(tile);
@ -195,7 +197,7 @@ namespace Ryujinx.Graphics.Texture
return output; return output;
} }
public static byte[] DecodeBC3(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers) public static IMemoryOwner<byte> DecodeBC3(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers)
{ {
int size = 0; 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; size += Math.Max(1, width >> l) * Math.Max(1, height >> l) * Math.Max(1, depth >> l) * layers * 4;
} }
byte[] output = new byte[size]; IMemoryOwner<byte> output = ByteMemoryPool.Rent(size);
Span<byte> tile = stackalloc byte[BlockWidth * BlockHeight * 4]; Span<byte> tile = stackalloc byte[BlockWidth * BlockHeight * 4];
Span<byte> rPal = stackalloc byte[8]; Span<byte> rPal = stackalloc byte[8];
Span<uint> tileAsUint = MemoryMarshal.Cast<byte, uint>(tile); Span<uint> tileAsUint = MemoryMarshal.Cast<byte, uint>(tile);
Span<uint> outputAsUint = MemoryMarshal.Cast<byte, uint>(output); Span<uint> outputAsUint = MemoryMarshal.Cast<byte, uint>(output.Memory.Span);
Span<Vector128<byte>> tileAsVector128 = MemoryMarshal.Cast<byte, Vector128<byte>>(tile); Span<Vector128<byte>> tileAsVector128 = MemoryMarshal.Cast<byte, Vector128<byte>>(tile);
@ -292,7 +294,7 @@ namespace Ryujinx.Graphics.Texture
return output; return output;
} }
public static byte[] DecodeBC4(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers, bool signed) public static IMemoryOwner<byte> DecodeBC4(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers, bool signed)
{ {
int size = 0; 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. // Backends currently expect a stride alignment of 4 bytes, so output width must be aligned.
int alignedWidth = BitUtils.AlignUp(width, 4); int alignedWidth = BitUtils.AlignUp(width, 4);
byte[] output = new byte[size]; IMemoryOwner<byte> output = ByteMemoryPool.Rent(size);
Span<byte> outputSpan = new(output); Span<byte> outputSpan = output.Memory.Span;
ReadOnlySpan<ulong> data64 = MemoryMarshal.Cast<byte, ulong>(data); ReadOnlySpan<ulong> data64 = MemoryMarshal.Cast<byte, ulong>(data);
@ -400,7 +402,7 @@ namespace Ryujinx.Graphics.Texture
return output; return output;
} }
public static byte[] DecodeBC5(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers, bool signed) public static IMemoryOwner<byte> DecodeBC5(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers, bool signed)
{ {
int size = 0; 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. // Backends currently expect a stride alignment of 4 bytes, so output width must be aligned.
int alignedWidth = BitUtils.AlignUp(width, 2); int alignedWidth = BitUtils.AlignUp(width, 2);
byte[] output = new byte[size]; IMemoryOwner<byte> output = ByteMemoryPool.Rent(size);
ReadOnlySpan<ulong> data64 = MemoryMarshal.Cast<byte, ulong>(data); ReadOnlySpan<ulong> data64 = MemoryMarshal.Cast<byte, ulong>(data);
@ -421,7 +423,7 @@ namespace Ryujinx.Graphics.Texture
Span<byte> rPal = stackalloc byte[8]; Span<byte> rPal = stackalloc byte[8];
Span<byte> gPal = stackalloc byte[8]; Span<byte> gPal = stackalloc byte[8];
Span<ushort> outputAsUshort = MemoryMarshal.Cast<byte, ushort>(output); Span<ushort> outputAsUshort = MemoryMarshal.Cast<byte, ushort>(output.Memory.Span);
Span<uint> rTileAsUint = MemoryMarshal.Cast<byte, uint>(rTile); Span<uint> rTileAsUint = MemoryMarshal.Cast<byte, uint>(rTile);
Span<uint> gTileAsUint = MemoryMarshal.Cast<byte, uint>(gTile); Span<uint> gTileAsUint = MemoryMarshal.Cast<byte, uint>(gTile);
@ -525,7 +527,7 @@ namespace Ryujinx.Graphics.Texture
return output; return output;
} }
public static byte[] DecodeBC6(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers, bool signed) public static IMemoryOwner<byte> DecodeBC6(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers, bool signed)
{ {
int size = 0; int size = 0;
@ -534,7 +536,7 @@ namespace Ryujinx.Graphics.Texture
size += Math.Max(1, width >> l) * Math.Max(1, height >> l) * Math.Max(1, depth >> l) * layers * 8; size += Math.Max(1, width >> l) * Math.Max(1, height >> l) * Math.Max(1, depth >> l) * layers * 8;
} }
byte[] output = new byte[size]; IMemoryOwner<byte> output = ByteMemoryPool.Rent(size);
int inputOffset = 0; int inputOffset = 0;
int outputOffset = 0; int outputOffset = 0;
@ -548,7 +550,7 @@ namespace Ryujinx.Graphics.Texture
{ {
for (int z = 0; z < depth; z++) for (int z = 0; z < depth; z++)
{ {
BC6Decoder.Decode(output.AsSpan()[outputOffset..], data[inputOffset..], width, height, signed); BC6Decoder.Decode(output.Memory.Span[outputOffset..], data[inputOffset..], width, height, signed);
inputOffset += w * h * 16; inputOffset += w * h * 16;
outputOffset += width * height * 8; outputOffset += width * height * 8;
@ -563,7 +565,7 @@ namespace Ryujinx.Graphics.Texture
return output; return output;
} }
public static byte[] DecodeBC7(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers) public static IMemoryOwner<byte> DecodeBC7(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers)
{ {
int size = 0; int size = 0;
@ -572,7 +574,7 @@ namespace Ryujinx.Graphics.Texture
size += Math.Max(1, width >> l) * Math.Max(1, height >> l) * Math.Max(1, depth >> l) * layers * 4; size += Math.Max(1, width >> l) * Math.Max(1, height >> l) * Math.Max(1, depth >> l) * layers * 4;
} }
byte[] output = new byte[size]; IMemoryOwner<byte> output = ByteMemoryPool.Rent(size);
int inputOffset = 0; int inputOffset = 0;
int outputOffset = 0; int outputOffset = 0;
@ -586,7 +588,7 @@ namespace Ryujinx.Graphics.Texture
{ {
for (int z = 0; z < depth; z++) for (int z = 0; z < depth; z++)
{ {
BC7Decoder.Decode(output.AsSpan()[outputOffset..], data[inputOffset..], width, height); BC7Decoder.Decode(output.Memory.Span[outputOffset..], data[inputOffset..], width, height);
inputOffset += w * h * 16; inputOffset += w * h * 16;
outputOffset += width * height * 4; outputOffset += width * height * 4;

View File

@ -1,6 +1,8 @@
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.Texture.Encoders; using Ryujinx.Graphics.Texture.Encoders;
using System; using System;
using System.Buffers;
namespace Ryujinx.Graphics.Texture namespace Ryujinx.Graphics.Texture
{ {
@ -9,7 +11,7 @@ namespace Ryujinx.Graphics.Texture
private const int BlockWidth = 4; private const int BlockWidth = 4;
private const int BlockHeight = 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<byte> EncodeBC7(Memory<byte> data, int width, int height, int depth, int levels, int layers)
{ {
int size = 0; int size = 0;
@ -21,7 +23,7 @@ namespace Ryujinx.Graphics.Texture
size += w * h * 16 * Math.Max(1, depth >> l) * layers; size += w * h * 16 * Math.Max(1, depth >> l) * layers;
} }
byte[] output = new byte[size]; IMemoryOwner<byte> output = ByteMemoryPool.Rent(size);
int imageBaseIOffs = 0; int imageBaseIOffs = 0;
int imageBaseOOffs = 0; int imageBaseOOffs = 0;
@ -36,8 +38,8 @@ namespace Ryujinx.Graphics.Texture
for (int z = 0; z < depth; z++) for (int z = 0; z < depth; z++)
{ {
BC7Encoder.Encode( BC7Encoder.Encode(
output.AsMemory()[imageBaseOOffs..], output.Memory[imageBaseOOffs..],
data.AsMemory()[imageBaseIOffs..], data[imageBaseIOffs..],
width, width,
height, height,
EncodeMode.Fast | EncodeMode.Multithreaded); EncodeMode.Fast | EncodeMode.Multithreaded);

View File

@ -1,5 +1,7 @@
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Memory;
using System; using System;
using System.Buffers;
using System.Buffers.Binary; using System.Buffers.Binary;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@ -49,15 +51,15 @@ namespace Ryujinx.Graphics.Texture
new int[] { -3, -5, -7, -9, 2, 4, 6, 8 }, new int[] { -3, -5, -7, -9, 2, 4, 6, 8 },
}; };
public static byte[] DecodeRgb(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers) public static IMemoryOwner<byte> DecodeRgb(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers)
{ {
ReadOnlySpan<ulong> dataUlong = MemoryMarshal.Cast<byte, ulong>(data); ReadOnlySpan<ulong> dataUlong = MemoryMarshal.Cast<byte, ulong>(data);
int inputOffset = 0; int inputOffset = 0;
byte[] output = new byte[CalculateOutputSize(width, height, depth, levels, layers)]; IMemoryOwner<byte> output = ByteMemoryPool.Rent(CalculateOutputSize(width, height, depth, levels, layers));
Span<uint> outputUint = MemoryMarshal.Cast<byte, uint>(output); Span<uint> outputUint = MemoryMarshal.Cast<byte, uint>(output.Memory.Span);
Span<uint> tile = stackalloc uint[BlockWidth * BlockHeight]; Span<uint> tile = stackalloc uint[BlockWidth * BlockHeight];
int imageBaseOOffs = 0; int imageBaseOOffs = 0;
@ -111,15 +113,15 @@ namespace Ryujinx.Graphics.Texture
return output; return output;
} }
public static byte[] DecodePta(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers) public static IMemoryOwner<byte> DecodePta(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers)
{ {
ReadOnlySpan<ulong> dataUlong = MemoryMarshal.Cast<byte, ulong>(data); ReadOnlySpan<ulong> dataUlong = MemoryMarshal.Cast<byte, ulong>(data);
int inputOffset = 0; int inputOffset = 0;
byte[] output = new byte[CalculateOutputSize(width, height, depth, levels, layers)]; IMemoryOwner<byte> output = ByteMemoryPool.Rent(CalculateOutputSize(width, height, depth, levels, layers));
Span<uint> outputUint = MemoryMarshal.Cast<byte, uint>(output); Span<uint> outputUint = MemoryMarshal.Cast<byte, uint>(output.Memory.Span);
Span<uint> tile = stackalloc uint[BlockWidth * BlockHeight]; Span<uint> tile = stackalloc uint[BlockWidth * BlockHeight];
int imageBaseOOffs = 0; int imageBaseOOffs = 0;
@ -168,15 +170,15 @@ namespace Ryujinx.Graphics.Texture
return output; return output;
} }
public static byte[] DecodeRgba(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers) public static IMemoryOwner<byte> DecodeRgba(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers)
{ {
ReadOnlySpan<ulong> dataUlong = MemoryMarshal.Cast<byte, ulong>(data); ReadOnlySpan<ulong> dataUlong = MemoryMarshal.Cast<byte, ulong>(data);
int inputOffset = 0; int inputOffset = 0;
byte[] output = new byte[CalculateOutputSize(width, height, depth, levels, layers)]; IMemoryOwner<byte> output = ByteMemoryPool.Rent(CalculateOutputSize(width, height, depth, levels, layers));
Span<uint> outputUint = MemoryMarshal.Cast<byte, uint>(output); Span<uint> outputUint = MemoryMarshal.Cast<byte, uint>(output.Memory.Span);
Span<uint> tile = stackalloc uint[BlockWidth * BlockHeight]; Span<uint> tile = stackalloc uint[BlockWidth * BlockHeight];
int imageBaseOOffs = 0; int imageBaseOOffs = 0;

View File

@ -1,5 +1,7 @@
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Memory;
using System; using System;
using System.Buffers;
using System.Runtime.Intrinsics; using System.Runtime.Intrinsics;
using static Ryujinx.Graphics.Texture.BlockLinearConstants; using static Ryujinx.Graphics.Texture.BlockLinearConstants;
@ -93,7 +95,7 @@ namespace Ryujinx.Graphics.Texture
}; };
} }
public static byte[] ConvertBlockLinearToLinear( public static IMemoryOwner<byte> ConvertBlockLinearToLinear(
int width, int width,
int height, int height,
int depth, int depth,
@ -119,7 +121,8 @@ namespace Ryujinx.Graphics.Texture
blockHeight, blockHeight,
bytesPerPixel); bytesPerPixel);
byte[] output = new byte[outSize]; IMemoryOwner<byte> outputOwner = ByteMemoryPool.Rent(outSize);
Span<byte> output = outputOwner.Memory.Span;
int outOffs = 0; int outOffs = 0;
@ -243,10 +246,10 @@ namespace Ryujinx.Graphics.Texture
_ => throw new NotSupportedException($"Unable to convert ${bytesPerPixel} bpp pixel format."), _ => throw new NotSupportedException($"Unable to convert ${bytesPerPixel} bpp pixel format."),
}; };
} }
return output; return outputOwner;
} }
public static byte[] ConvertLinearStridedToLinear( public static IMemoryOwner<byte> ConvertLinearStridedToLinear(
int width, int width,
int height, int height,
int blockWidth, int blockWidth,
@ -262,8 +265,8 @@ namespace Ryujinx.Graphics.Texture
int outStride = BitUtils.AlignUp(w * bytesPerPixel, HostStrideAlignment); int outStride = BitUtils.AlignUp(w * bytesPerPixel, HostStrideAlignment);
lineSize = Math.Min(lineSize, outStride); lineSize = Math.Min(lineSize, outStride);
byte[] output = new byte[h * outStride]; IMemoryOwner<byte> output = ByteMemoryPool.Rent(h * outStride);
Span<byte> outSpan = output; Span<byte> outSpan = output.Memory.Span;
int outOffs = 0; int outOffs = 0;
int inOffs = 0; int inOffs = 0;

View File

@ -1,5 +1,7 @@
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Memory;
using System; using System;
using System.Buffers;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Runtime.Intrinsics; using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86; using System.Runtime.Intrinsics.X86;
@ -19,13 +21,13 @@ namespace Ryujinx.Graphics.Texture
return (remainder, outRemainder, length / stride); return (remainder, outRemainder, length / stride);
} }
public unsafe static byte[] ConvertR4G4ToR4G4B4A4(ReadOnlySpan<byte> data, int width) public unsafe static IMemoryOwner<byte> ConvertR4G4ToR4G4B4A4(ReadOnlySpan<byte> data, int width)
{ {
byte[] output = new byte[data.Length * 2]; IMemoryOwner<byte> output = ByteMemoryPool.Rent(data.Length * 2);
(int remainder, int outRemainder, int height) = GetLineRemainders(data.Length, width, 1, 2); (int remainder, int outRemainder, int height) = GetLineRemainders(data.Length, width, 1, 2);
Span<ushort> outputSpan = MemoryMarshal.Cast<byte, ushort>(output); Span<ushort> outputSpan = MemoryMarshal.Cast<byte, ushort>(output.Memory.Span);
if (remainder == 0) if (remainder == 0)
{ {
@ -36,7 +38,7 @@ namespace Ryujinx.Graphics.Texture
int sizeTrunc = data.Length & ~7; int sizeTrunc = data.Length & ~7;
start = sizeTrunc; 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) for (ulong offset = 0; offset < (ulong)sizeTrunc; offset += 8)
{ {
@ -70,16 +72,16 @@ namespace Ryujinx.Graphics.Texture
return output; return output;
} }
public unsafe static byte[] ConvertR5G6B5ToR8G8B8A8(ReadOnlySpan<byte> data, int width) public unsafe static IMemoryOwner<byte> ConvertR5G6B5ToR8G8B8A8(ReadOnlySpan<byte> data, int width)
{ {
byte[] output = new byte[data.Length * 2]; IMemoryOwner<byte> output = ByteMemoryPool.Rent(data.Length * 2);
int offset = 0; int offset = 0;
int outOffset = 0; int outOffset = 0;
(int remainder, int outRemainder, int height) = GetLineRemainders(data.Length, width, 2, 4); (int remainder, int outRemainder, int height) = GetLineRemainders(data.Length, width, 2, 4);
ReadOnlySpan<ushort> inputSpan = MemoryMarshal.Cast<byte, ushort>(data); ReadOnlySpan<ushort> inputSpan = MemoryMarshal.Cast<byte, ushort>(data);
Span<uint> outputSpan = MemoryMarshal.Cast<byte, uint>(output); Span<uint> outputSpan = MemoryMarshal.Cast<byte, uint>(output.Memory.Span);
for (int y = 0; y < height; y++) for (int y = 0; y < height; y++)
{ {
@ -107,16 +109,16 @@ namespace Ryujinx.Graphics.Texture
return output; return output;
} }
public unsafe static byte[] ConvertR5G5B5ToR8G8B8A8(ReadOnlySpan<byte> data, int width, bool forceAlpha) public unsafe static IMemoryOwner<byte> ConvertR5G5B5ToR8G8B8A8(ReadOnlySpan<byte> data, int width, bool forceAlpha)
{ {
byte[] output = new byte[data.Length * 2]; IMemoryOwner<byte> output = ByteMemoryPool.Rent(data.Length * 2);
int offset = 0; int offset = 0;
int outOffset = 0; int outOffset = 0;
(int remainder, int outRemainder, int height) = GetLineRemainders(data.Length, width, 2, 4); (int remainder, int outRemainder, int height) = GetLineRemainders(data.Length, width, 2, 4);
ReadOnlySpan<ushort> inputSpan = MemoryMarshal.Cast<byte, ushort>(data); ReadOnlySpan<ushort> inputSpan = MemoryMarshal.Cast<byte, ushort>(data);
Span<uint> outputSpan = MemoryMarshal.Cast<byte, uint>(output); Span<uint> outputSpan = MemoryMarshal.Cast<byte, uint>(output.Memory.Span);
for (int y = 0; y < height; y++) for (int y = 0; y < height; y++)
{ {
@ -144,16 +146,16 @@ namespace Ryujinx.Graphics.Texture
return output; return output;
} }
public unsafe static byte[] ConvertA1B5G5R5ToR8G8B8A8(ReadOnlySpan<byte> data, int width) public unsafe static IMemoryOwner<byte> ConvertA1B5G5R5ToR8G8B8A8(ReadOnlySpan<byte> data, int width)
{ {
byte[] output = new byte[data.Length * 2]; IMemoryOwner<byte> output = ByteMemoryPool.Rent(data.Length * 2);
int offset = 0; int offset = 0;
int outOffset = 0; int outOffset = 0;
(int remainder, int outRemainder, int height) = GetLineRemainders(data.Length, width, 2, 4); (int remainder, int outRemainder, int height) = GetLineRemainders(data.Length, width, 2, 4);
ReadOnlySpan<ushort> inputSpan = MemoryMarshal.Cast<byte, ushort>(data); ReadOnlySpan<ushort> inputSpan = MemoryMarshal.Cast<byte, ushort>(data);
Span<uint> outputSpan = MemoryMarshal.Cast<byte, uint>(output); Span<uint> outputSpan = MemoryMarshal.Cast<byte, uint>(output.Memory.Span);
for (int y = 0; y < height; y++) for (int y = 0; y < height; y++)
{ {
@ -181,16 +183,16 @@ namespace Ryujinx.Graphics.Texture
return output; return output;
} }
public unsafe static byte[] ConvertR4G4B4A4ToR8G8B8A8(ReadOnlySpan<byte> data, int width) public unsafe static IMemoryOwner<byte> ConvertR4G4B4A4ToR8G8B8A8(ReadOnlySpan<byte> data, int width)
{ {
byte[] output = new byte[data.Length * 2]; IMemoryOwner<byte> output = ByteMemoryPool.Rent(data.Length * 2);
int offset = 0; int offset = 0;
int outOffset = 0; int outOffset = 0;
(int remainder, int outRemainder, int height) = GetLineRemainders(data.Length, width, 2, 4); (int remainder, int outRemainder, int height) = GetLineRemainders(data.Length, width, 2, 4);
ReadOnlySpan<ushort> inputSpan = MemoryMarshal.Cast<byte, ushort>(data); ReadOnlySpan<ushort> inputSpan = MemoryMarshal.Cast<byte, ushort>(data);
Span<uint> outputSpan = MemoryMarshal.Cast<byte, uint>(output); Span<uint> outputSpan = MemoryMarshal.Cast<byte, uint>(output.Memory.Span);
for (int y = 0; y < height; y++) for (int y = 0; y < height; y++)
{ {

View File

@ -2,6 +2,7 @@ using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using Silk.NET.Vulkan; using Silk.NET.Vulkan;
using System; using System;
using System.Buffers;
using System.Collections.Generic; using System.Collections.Generic;
using Format = Ryujinx.Graphics.GAL.Format; using Format = Ryujinx.Graphics.GAL.Format;
using VkFormat = Silk.NET.Vulkan.Format; using VkFormat = Silk.NET.Vulkan.Format;
@ -94,18 +95,21 @@ namespace Ryujinx.Graphics.Vulkan
_bufferView = null; _bufferView = null;
} }
public void SetData(SpanOrArray<byte> data) public void SetData(IMemoryOwner<byte> data)
{ {
_gd.SetBufferData(_bufferHandle, _offset, data); _gd.SetBufferData(_bufferHandle, _offset, data.Memory.Span);
data.Dispose();
} }
public void SetData(SpanOrArray<byte> data, int layer, int level) public void SetData(IMemoryOwner<byte> data, int layer, int level)
{ {
data.Dispose();
throw new NotSupportedException(); throw new NotSupportedException();
} }
public void SetData(SpanOrArray<byte> data, int layer, int level, Rectangle<int> region) public void SetData(IMemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
{ {
data.Dispose();
throw new NotSupportedException(); throw new NotSupportedException();
} }

View File

@ -2,6 +2,7 @@ using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using Silk.NET.Vulkan; using Silk.NET.Vulkan;
using System; using System;
using System.Buffers;
using System.Collections.Generic; using System.Collections.Generic;
using Format = Ryujinx.Graphics.GAL.Format; using Format = Ryujinx.Graphics.GAL.Format;
using VkBuffer = Silk.NET.Vulkan.Buffer; using VkBuffer = Silk.NET.Vulkan.Buffer;
@ -656,19 +657,27 @@ namespace Ryujinx.Graphics.Vulkan
return GetDataFromBuffer(result, size, result); return GetDataFromBuffer(result, size, result);
} }
public void SetData(SpanOrArray<byte> data) public void SetData(ReadOnlySpan<byte> data)
{ {
SetData(data, 0, 0, Info.GetLayers(), Info.Levels, singleSlice: false); SetData(data, 0, 0, Info.GetLayers(), Info.Levels, singleSlice: false);
} }
public void SetData(SpanOrArray<byte> data, int layer, int level) public void SetData(IMemoryOwner<byte> data)
{ {
SetData(data, layer, level, 1, 1, singleSlice: true); SetData(data.Memory.Span);
data.Dispose();
} }
public void SetData(SpanOrArray<byte> data, int layer, int level, Rectangle<int> region) public void SetData(IMemoryOwner<byte> data, int layer, int level)
{ {
SetData(data, layer, level, 1, 1, singleSlice: true, region); SetData(data.Memory.Span, layer, level, 1, 1, singleSlice: true);
data.Dispose();
}
public void SetData(IMemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
{
SetData(data.Memory.Span, layer, level, 1, 1, singleSlice: true, region);
data.Dispose();
} }
private void SetData(ReadOnlySpan<byte> data, int layer, int level, int layers, int levels, bool singleSlice, Rectangle<int>? region = null) private void SetData(ReadOnlySpan<byte> data, int layer, int level, int layers, int levels, bool singleSlice, Rectangle<int>? region = null)