Compare commits

...

5 Commits

Author SHA1 Message Date
Isaac Marovitz da0e22c2d0
Merge e994e7826b into 73f985d27c 2024-09-19 06:30:54 +03:00
jhorv 73f985d27c
Replace passing by IMemoryOwner<byte> with passing by concrete MemoryOwner<byte> (#7171)
* refactor(perf): pass MemoryOwner<byte> around as itself rather than IMemoryOwner<byte>

* fix(perf): get span via MemoryOwner<byte>.Span property instead of through Memory property

* fix: incorrect comment change
2024-09-18 23:00:54 -03:00
gdkchan ef81658fbd
Implement support for shader ATOM.EXCH instruction (#7320)
* Implement support for shader ATOM.EXCH instruction

* Shader cache version bump

* Check type
2024-09-18 15:48:55 -03:00
Isaac Marovitz e994e7826b
Fix >16 primitives 2024-09-02 10:23:27 +02:00
Isaac Marovitz 3005c38a63
Use compute shader for non indirect index buffer conversion 2024-09-01 23:25:38 +02:00
18 changed files with 146 additions and 168 deletions

View File

@ -1,4 +1,4 @@
using System.Buffers;
using Ryujinx.Common.Memory;
namespace Ryujinx.Graphics.GAL
{
@ -18,30 +18,30 @@ namespace Ryujinx.Graphics.GAL
PinnedSpan<byte> GetData(int layer, int level);
/// <summary>
/// Sets the texture data. The data passed as a <see cref="IMemoryOwner{Byte}" /> will be disposed when
/// Sets the texture data. The data passed as a <see cref="MemoryOwner{Byte}" /> will be disposed when
/// the operation completes.
/// </summary>
/// <param name="data">Texture data bytes</param>
void SetData(IMemoryOwner<byte> data);
void SetData(MemoryOwner<byte> data);
/// <summary>
/// Sets the texture data. The data passed as a <see cref="IMemoryOwner{Byte}" /> will be disposed when
/// Sets the texture data. The data passed as a <see cref="MemoryOwner{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);
void SetData(MemoryOwner<byte> data, int layer, int level);
/// <summary>
/// Sets the texture data. The data passed as a <see cref="IMemoryOwner{Byte}" /> will be disposed when
/// Sets the texture data. The data passed as a <see cref="MemoryOwner{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 SetData(MemoryOwner<byte> data, int layer, int level, Rectangle<int> region);
void SetStorage(BufferRange buffer);

View File

@ -1,6 +1,6 @@
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
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<ThreadedTexture> _texture;
private TableRef<IMemoryOwner<byte>> _data;
private TableRef<MemoryOwner<byte>> _data;
public void Set(TableRef<ThreadedTexture> texture, TableRef<IMemoryOwner<byte>> data)
public void Set(TableRef<ThreadedTexture> texture, TableRef<MemoryOwner<byte>> data)
{
_texture = texture;
_data = data;

View File

@ -1,6 +1,6 @@
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
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<ThreadedTexture> _texture;
private TableRef<IMemoryOwner<byte>> _data;
private TableRef<MemoryOwner<byte>> _data;
private int _layer;
private int _level;
public void Set(TableRef<ThreadedTexture> texture, TableRef<IMemoryOwner<byte>> data, int layer, int level)
public void Set(TableRef<ThreadedTexture> texture, TableRef<MemoryOwner<byte>> data, int layer, int level)
{
_texture = texture;
_data = data;

View File

@ -1,6 +1,6 @@
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
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<ThreadedTexture> _texture;
private TableRef<IMemoryOwner<byte>> _data;
private TableRef<MemoryOwner<byte>> _data;
private int _layer;
private int _level;
private Rectangle<int> _region;
public void Set(TableRef<ThreadedTexture> texture, TableRef<IMemoryOwner<byte>> data, int layer, int level, Rectangle<int> region)
public void Set(TableRef<ThreadedTexture> texture, TableRef<MemoryOwner<byte>> data, int layer, int level, Rectangle<int> region)
{
_texture = texture;
_data = data;

View File

@ -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
{
@ -111,21 +111,21 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources
}
/// <inheritdoc/>
public void SetData(IMemoryOwner<byte> data)
public void SetData(MemoryOwner<byte> data)
{
_renderer.New<TextureSetDataCommand>().Set(Ref(this), Ref(data));
_renderer.QueueCommand();
}
/// <inheritdoc/>
public void SetData(IMemoryOwner<byte> data, int layer, int level)
public void SetData(MemoryOwner<byte> data, int layer, int level)
{
_renderer.New<TextureSetDataSliceCommand>().Set(Ref(this), Ref(data), layer, level);
_renderer.QueueCommand();
}
/// <inheritdoc/>
public void SetData(IMemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
public void SetData(MemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
{
_renderer.New<TextureSetDataSliceRegionCommand>().Set(Ref(this), Ref(data), layer, level, region);
_renderer.QueueCommand();

View File

@ -1,10 +1,10 @@
using Ryujinx.Common;
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.Device;
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;
@ -353,7 +353,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
if (target != null)
{
IMemoryOwner<byte> data;
MemoryOwner<byte> data;
if (srcLinear)
{
data = LayoutConverter.ConvertLinearStridedToLinear(

View File

@ -7,7 +7,6 @@ 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;
@ -662,7 +661,7 @@ namespace Ryujinx.Graphics.Gpu.Image
}
}
IMemoryOwner<byte> result = ConvertToHostCompatibleFormat(data);
MemoryOwner<byte> result = ConvertToHostCompatibleFormat(data);
if (ScaleFactor != 1f && AllowScaledSetData())
{
@ -685,7 +684,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// Uploads new texture data to the host GPU.
/// </summary>
/// <param name="data">New data</param>
public void SetData(IMemoryOwner<byte> data)
public void SetData(MemoryOwner<byte> data)
{
BlacklistScale();
@ -704,7 +703,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <param name="data">New data</param>
/// <param name="layer">Target layer</param>
/// <param name="level">Target level</param>
public void SetData(IMemoryOwner<byte> data, int layer, int level)
public void SetData(MemoryOwner<byte> data, int layer, int level)
{
BlacklistScale();
@ -722,7 +721,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <param name="layer">Target layer</param>
/// <param name="level">Target level</param>
/// <param name="region">Target sub-region of the texture to update</param>
public void SetData(IMemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
public void SetData(MemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
{
BlacklistScale();
@ -740,7 +739,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <param name="level">Mip level to convert</param>
/// <param name="single">True to convert a single slice</param>
/// <returns>Converted data</returns>
public IMemoryOwner<byte> ConvertToHostCompatibleFormat(ReadOnlySpan<byte> data, int level = 0, bool single = false)
public MemoryOwner<byte> ConvertToHostCompatibleFormat(ReadOnlySpan<byte> data, int level = 0, bool single = false)
{
int width = Info.Width;
int height = Info.Height;
@ -755,7 +754,7 @@ namespace Ryujinx.Graphics.Gpu.Image
int sliceDepth = single ? 1 : depth;
IMemoryOwner<byte> linear;
MemoryOwner<byte> linear;
if (Info.IsLinear)
{
@ -788,7 +787,7 @@ namespace Ryujinx.Graphics.Gpu.Image
data);
}
IMemoryOwner<byte> result = linear;
MemoryOwner<byte> result = linear;
// Handle compressed cases not supported by the host:
// - ASTC is usually not supported on desktop cards.
@ -832,19 +831,19 @@ namespace Ryujinx.Graphics.Gpu.Image
case Format.Etc2RgbaUnorm:
using (result)
{
return ETC2Decoder.DecodeRgba(result.Memory.Span, width, height, sliceDepth, levels, layers);
return ETC2Decoder.DecodeRgba(result.Span, width, height, sliceDepth, levels, layers);
}
case Format.Etc2RgbPtaSrgb:
case Format.Etc2RgbPtaUnorm:
using (result)
{
return ETC2Decoder.DecodePta(result.Memory.Span, width, height, sliceDepth, levels, layers);
return ETC2Decoder.DecodePta(result.Span, width, height, sliceDepth, levels, layers);
}
case Format.Etc2RgbSrgb:
case Format.Etc2RgbUnorm:
using (result)
{
return ETC2Decoder.DecodeRgb(result.Memory.Span, width, height, sliceDepth, levels, layers);
return ETC2Decoder.DecodeRgb(result.Span, width, height, sliceDepth, levels, layers);
}
}
}
@ -856,43 +855,43 @@ namespace Ryujinx.Graphics.Gpu.Image
case Format.Bc1RgbaUnorm:
using (result)
{
return BCnDecoder.DecodeBC1(result.Memory.Span, width, height, sliceDepth, levels, layers);
return BCnDecoder.DecodeBC1(result.Span, width, height, sliceDepth, levels, layers);
}
case Format.Bc2Srgb:
case Format.Bc2Unorm:
using (result)
{
return BCnDecoder.DecodeBC2(result.Memory.Span, width, height, sliceDepth, levels, layers);
return BCnDecoder.DecodeBC2(result.Span, width, height, sliceDepth, levels, layers);
}
case Format.Bc3Srgb:
case Format.Bc3Unorm:
using (result)
{
return BCnDecoder.DecodeBC3(result.Memory.Span, width, height, sliceDepth, levels, layers);
return BCnDecoder.DecodeBC3(result.Span, width, height, sliceDepth, levels, layers);
}
case Format.Bc4Snorm:
case Format.Bc4Unorm:
using (result)
{
return BCnDecoder.DecodeBC4(result.Memory.Span, width, height, sliceDepth, levels, layers, Format == Format.Bc4Snorm);
return BCnDecoder.DecodeBC4(result.Span, width, height, sliceDepth, levels, layers, Format == Format.Bc4Snorm);
}
case Format.Bc5Snorm:
case Format.Bc5Unorm:
using (result)
{
return BCnDecoder.DecodeBC5(result.Memory.Span, width, height, sliceDepth, levels, layers, Format == Format.Bc5Snorm);
return BCnDecoder.DecodeBC5(result.Span, width, height, sliceDepth, levels, layers, Format == Format.Bc5Snorm);
}
case Format.Bc6HSfloat:
case Format.Bc6HUfloat:
using (result)
{
return BCnDecoder.DecodeBC6(result.Memory.Span, width, height, sliceDepth, levels, layers, Format == Format.Bc6HSfloat);
return BCnDecoder.DecodeBC6(result.Span, width, height, sliceDepth, levels, layers, Format == Format.Bc6HSfloat);
}
case Format.Bc7Srgb:
case Format.Bc7Unorm:
using (result)
{
return BCnDecoder.DecodeBC7(result.Memory.Span, width, height, sliceDepth, levels, layers);
return BCnDecoder.DecodeBC7(result.Span, width, height, sliceDepth, levels, layers);
}
}
}
@ -900,7 +899,7 @@ namespace Ryujinx.Graphics.Gpu.Image
{
using (result)
{
var converted = PixelConverter.ConvertR4G4ToR4G4B4A4(result.Memory.Span, width);
var converted = PixelConverter.ConvertR4G4ToR4G4B4A4(result.Span, width);
if (_context.Capabilities.SupportsR4G4B4A4Format)
{
@ -910,7 +909,7 @@ namespace Ryujinx.Graphics.Gpu.Image
{
using (converted)
{
return PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(converted.Memory.Span, width);
return PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(converted.Span, width);
}
}
}
@ -921,7 +920,7 @@ namespace Ryujinx.Graphics.Gpu.Image
{
using (result)
{
return PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(result.Memory.Span, width);
return PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(result.Span, width);
}
}
}
@ -933,24 +932,24 @@ namespace Ryujinx.Graphics.Gpu.Image
case Format.R5G6B5Unorm:
using (result)
{
return PixelConverter.ConvertR5G6B5ToR8G8B8A8(result.Memory.Span, width);
return PixelConverter.ConvertR5G6B5ToR8G8B8A8(result.Span, width);
}
case Format.B5G5R5A1Unorm:
case Format.R5G5B5X1Unorm:
case Format.R5G5B5A1Unorm:
using (result)
{
return PixelConverter.ConvertR5G5B5ToR8G8B8A8(result.Memory.Span, width, Format == Format.R5G5B5X1Unorm);
return PixelConverter.ConvertR5G5B5ToR8G8B8A8(result.Span, width, Format == Format.R5G5B5X1Unorm);
}
case Format.A1B5G5R5Unorm:
using (result)
{
return PixelConverter.ConvertA1B5G5R5ToR8G8B8A8(result.Memory.Span, width);
return PixelConverter.ConvertA1B5G5R5ToR8G8B8A8(result.Span, width);
}
case Format.R4G4B4A4Unorm:
using (result)
{
return PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(result.Memory.Span, width);
return PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(result.Span, width);
}
}
}

View File

@ -1,3 +1,4 @@
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu.Memory;
using Ryujinx.Graphics.Texture;
@ -5,7 +6,6 @@ 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<byte> data = dataSpan[(offset - spanBase)..];
IMemoryOwner<byte> result = Storage.ConvertToHostCompatibleFormat(data, info.BaseLevel + level, true);
MemoryOwner<byte> result = Storage.ConvertToHostCompatibleFormat(data, info.BaseLevel + level, true);
Storage.SetData(result, info.BaseLayer + layer, info.BaseLevel + level);
}

View File

@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
private const ushort FileFormatVersionMajor = 1;
private const ushort FileFormatVersionMinor = 2;
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
private const uint CodeGenVersion = 7131;
private const uint CodeGenVersion = 7320;
private const string SharedTocFileName = "shared.toc";
private const string SharedDataFileName = "shared.data";

View File

@ -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
{
@ -55,9 +55,9 @@ namespace Ryujinx.Graphics.OpenGL.Image
}
/// <inheritdoc/>
public void SetData(IMemoryOwner<byte> data)
public void SetData(MemoryOwner<byte> data)
{
var dataSpan = data.Memory.Span;
var dataSpan = data.Span;
Buffer.SetData(_buffer, _bufferOffset, dataSpan[..Math.Min(dataSpan.Length, _bufferSize)]);
@ -65,13 +65,13 @@ namespace Ryujinx.Graphics.OpenGL.Image
}
/// <inheritdoc/>
public void SetData(IMemoryOwner<byte> data, int layer, int level)
public void SetData(MemoryOwner<byte> data, int layer, int level)
{
throw new NotSupportedException();
}
/// <inheritdoc/>
public void SetData(IMemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
public void SetData(MemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
{
throw new NotSupportedException();
}

View File

@ -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,13 +448,13 @@ namespace Ryujinx.Graphics.OpenGL.Image
}
}
public void SetData(IMemoryOwner<byte> data)
public void SetData(MemoryOwner<byte> data)
{
using (data = EnsureDataFormat(data))
{
unsafe
{
var dataSpan = data.Memory.Span;
var dataSpan = data.Span;
fixed (byte* ptr = dataSpan)
{
ReadFrom((IntPtr)ptr, dataSpan.Length);
@ -463,13 +463,13 @@ namespace Ryujinx.Graphics.OpenGL.Image
}
}
public void SetData(IMemoryOwner<byte> data, int layer, int level)
public void SetData(MemoryOwner<byte> data, int layer, int level)
{
using (data = EnsureDataFormat(data))
{
unsafe
{
fixed (byte* ptr = data.Memory.Span)
fixed (byte* ptr = data.Span)
{
int width = Math.Max(Info.Width >> level, 1);
int height = Math.Max(Info.Height >> level, 1);
@ -480,7 +480,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
}
}
public void SetData(IMemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
public void SetData(MemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
{
using (data = EnsureDataFormat(data))
{
@ -489,7 +489,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
unsafe
{
fixed (byte* ptr = data.Memory.Span)
fixed (byte* ptr = data.Span)
{
ReadFrom2D(
(IntPtr)ptr,
@ -522,13 +522,13 @@ namespace Ryujinx.Graphics.OpenGL.Image
ReadFrom2D(data, layer, level, x, y, width, height, mipSize);
}
private IMemoryOwner<byte> EnsureDataFormat(IMemoryOwner<byte> data)
private MemoryOwner<byte> EnsureDataFormat(MemoryOwner<byte> data)
{
if (Format == Format.S8UintD24Unorm)
{
using (data)
{
return FormatConverter.ConvertS8D24ToD24S8(data.Memory.Span);
return FormatConverter.ConvertS8D24ToD24S8(data.Span);
}
}

View File

@ -222,30 +222,14 @@ namespace Ryujinx.Graphics.Shader.Instructions
context.TranslatorContext.GpuAccessor.Log($"Invalid reduction type: {type}.");
}
break;
case AtomOp.And:
if (type == AtomSize.S32 || type == AtomSize.U32)
case AtomOp.Min:
if (type == AtomSize.S32)
{
res = context.AtomicAnd(storageKind, e0, e1, value);
res = context.AtomicMinS32(storageKind, e0, e1, value);
}
else
else if (type == AtomSize.U32)
{
context.TranslatorContext.GpuAccessor.Log($"Invalid reduction type: {type}.");
}
break;
case AtomOp.Xor:
if (type == AtomSize.S32 || type == AtomSize.U32)
{
res = context.AtomicXor(storageKind, e0, e1, value);
}
else
{
context.TranslatorContext.GpuAccessor.Log($"Invalid reduction type: {type}.");
}
break;
case AtomOp.Or:
if (type == AtomSize.S32 || type == AtomSize.U32)
{
res = context.AtomicOr(storageKind, e0, e1, value);
res = context.AtomicMinU32(storageKind, e0, e1, value);
}
else
{
@ -266,20 +250,49 @@ namespace Ryujinx.Graphics.Shader.Instructions
context.TranslatorContext.GpuAccessor.Log($"Invalid reduction type: {type}.");
}
break;
case AtomOp.Min:
if (type == AtomSize.S32)
case AtomOp.And:
if (type == AtomSize.S32 || type == AtomSize.U32)
{
res = context.AtomicMinS32(storageKind, e0, e1, value);
}
else if (type == AtomSize.U32)
{
res = context.AtomicMinU32(storageKind, e0, e1, value);
res = context.AtomicAnd(storageKind, e0, e1, value);
}
else
{
context.TranslatorContext.GpuAccessor.Log($"Invalid reduction type: {type}.");
}
break;
case AtomOp.Or:
if (type == AtomSize.S32 || type == AtomSize.U32)
{
res = context.AtomicOr(storageKind, e0, e1, value);
}
else
{
context.TranslatorContext.GpuAccessor.Log($"Invalid reduction type: {type}.");
}
break;
case AtomOp.Xor:
if (type == AtomSize.S32 || type == AtomSize.U32)
{
res = context.AtomicXor(storageKind, e0, e1, value);
}
else
{
context.TranslatorContext.GpuAccessor.Log($"Invalid reduction type: {type}.");
}
break;
case AtomOp.Exch:
if (type == AtomSize.S32 || type == AtomSize.U32)
{
res = context.AtomicSwap(storageKind, e0, e1, value);
}
else
{
context.TranslatorContext.GpuAccessor.Log($"Invalid reduction type: {type}.");
}
break;
default:
context.TranslatorContext.GpuAccessor.Log($"Invalid atomic operation: {op}.");
break;
}
return res;

View File

@ -896,57 +896,42 @@ namespace Ryujinx.Graphics.Vulkan
public unsafe void ConvertIndexBuffer(VulkanRenderer gd,
CommandBufferScoped cbs,
BufferHolder src,
BufferHolder dst,
BufferHolder srcIndexBuffer,
BufferHolder dstIndexBuffer,
IndexBufferPattern pattern,
int indexSize,
int srcOffset,
int indexCount)
{
// TODO: Support conversion with primitive restart enabled.
// TODO: Convert with a compute shader?
int primitiveCount = pattern.GetPrimitiveCount(indexCount);
int convertedCount = pattern.GetConvertedCount(indexCount);
int outputIndexSize = 4;
var srcBuffer = src.GetBuffer().Get(cbs, srcOffset, indexCount * indexSize).Value;
var dstBuffer = dst.GetBuffer().Get(cbs, 0, convertedCount * outputIndexSize).Value;
var dstBuffer = dstIndexBuffer.GetBuffer().Get(cbs, 0, convertedCount * outputIndexSize).Value;
gd.Api.CmdFillBuffer(cbs.CommandBuffer, dstBuffer, 0, Vk.WholeSize, 0);
const int ParamsBufferSize = 16 * sizeof(int);
var bufferCopy = new List<BufferCopy>();
int outputOffset = 0;
Span<int> shaderParams = stackalloc int[ParamsBufferSize / sizeof(int)];
// Try to merge copies of adjacent indices to reduce copy count.
int sequenceStart = 0;
int sequenceLength = 0;
shaderParams[8] = pattern.PrimitiveVertices;
shaderParams[9] = pattern.PrimitiveVerticesOut;
shaderParams[10] = indexSize;
shaderParams[11] = outputIndexSize;
shaderParams[12] = pattern.BaseIndex;
shaderParams[13] = pattern.IndexStride;
shaderParams[14] = srcOffset;
shaderParams[15] = primitiveCount;
foreach (var index in pattern.GetIndexMapping(indexCount))
{
if (sequenceLength > 0)
{
if (index == sequenceStart + sequenceLength && indexSize == outputIndexSize)
{
sequenceLength++;
continue;
}
pattern.OffsetIndex.CopyTo(shaderParams[..pattern.OffsetIndex.Length]);
// Commit the copy so far.
bufferCopy.Add(new BufferCopy((ulong)(srcOffset + sequenceStart * indexSize), (ulong)outputOffset, (ulong)(indexSize * sequenceLength)));
outputOffset += outputIndexSize * sequenceLength;
}
using var patternScoped = gd.BufferManager.ReserveOrCreate(gd, cbs, ParamsBufferSize);
var patternBuffer = patternScoped.Holder;
sequenceStart = index;
sequenceLength = 1;
}
patternBuffer.SetDataUnchecked<int>(patternScoped.Offset, shaderParams);
if (sequenceLength > 0)
{
// Commit final pending copy.
bufferCopy.Add(new BufferCopy((ulong)(srcOffset + sequenceStart * indexSize), (ulong)outputOffset, (ulong)(indexSize * sequenceLength)));
}
var bufferCopyArray = bufferCopy.ToArray();
_pipeline.SetCommandBuffer(cbs);
BufferHolder.InsertBufferBarrier(
gd,
@ -959,10 +944,11 @@ namespace Ryujinx.Graphics.Vulkan
0,
convertedCount * outputIndexSize);
fixed (BufferCopy* pBufferCopy = bufferCopyArray)
{
gd.Api.CmdCopyBuffer(cbs.CommandBuffer, srcBuffer, dstBuffer, (uint)bufferCopyArray.Length, pBufferCopy);
}
_pipeline.SetUniformBuffers([new BufferAssignment(0, new BufferRange(patternScoped.Handle, patternScoped.Offset, ParamsBufferSize))]);
_pipeline.SetStorageBuffers(1, new[] { srcIndexBuffer.GetBuffer(), dstIndexBuffer.GetBuffer() });
_pipeline.SetProgram(_programConvertIndexBuffer);
_pipeline.DispatchCompute(BitUtils.DivRoundUp(primitiveCount, 16), 1, 1);
BufferHolder.InsertBufferBarrier(
gd,
@ -974,6 +960,8 @@ namespace Ryujinx.Graphics.Vulkan
PipelineStageFlags.AllCommandsBit,
0,
convertedCount * outputIndexSize);
_pipeline.Finish(gd, cbs);
}
public void CopyIncompatibleFormats(

View File

@ -47,28 +47,6 @@ namespace Ryujinx.Graphics.Vulkan
return primitiveCount * OffsetIndex.Length;
}
public IEnumerable<int> GetIndexMapping(int indexCount)
{
int primitiveCount = GetPrimitiveCount(indexCount);
int index = BaseIndex;
for (int i = 0; i < primitiveCount; i++)
{
if (RepeatStart)
{
// Used for triangle fan
yield return 0;
}
for (int j = RepeatStart ? 1 : 0; j < OffsetIndex.Length; j++)
{
yield return index + OffsetIndex[j];
}
index += IndexStride;
}
}
public BufferHandle GetRepeatingBuffer(int vertexCount, out int indexCount)
{
int primitiveCount = GetPrimitiveCount(vertexCount);

View File

@ -1,7 +1,7 @@
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL;
using Silk.NET.Vulkan;
using System;
using System.Buffers;
using System.Collections.Generic;
using Format = Ryujinx.Graphics.GAL.Format;
using VkFormat = Silk.NET.Vulkan.Format;
@ -84,20 +84,20 @@ namespace Ryujinx.Graphics.Vulkan
}
/// <inheritdoc/>
public void SetData(IMemoryOwner<byte> data)
public void SetData(MemoryOwner<byte> data)
{
_gd.SetBufferData(_bufferHandle, _offset, data.Memory.Span);
_gd.SetBufferData(_bufferHandle, _offset, data.Span);
data.Dispose();
}
/// <inheritdoc/>
public void SetData(IMemoryOwner<byte> data, int layer, int level)
public void SetData(MemoryOwner<byte> data, int layer, int level)
{
throw new NotSupportedException();
}
/// <inheritdoc/>
public void SetData(IMemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
public void SetData(MemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
{
throw new NotSupportedException();
}

View File

@ -1,7 +1,7 @@
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL;
using Silk.NET.Vulkan;
using System;
using System.Buffers;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
@ -746,23 +746,23 @@ namespace Ryujinx.Graphics.Vulkan
}
/// <inheritdoc/>
public void SetData(IMemoryOwner<byte> data)
public void SetData(MemoryOwner<byte> data)
{
SetData(data.Memory.Span, 0, 0, Info.GetLayers(), Info.Levels, singleSlice: false);
SetData(data.Span, 0, 0, Info.GetLayers(), Info.Levels, singleSlice: false);
data.Dispose();
}
/// <inheritdoc/>
public void SetData(IMemoryOwner<byte> data, int layer, int level)
public void SetData(MemoryOwner<byte> data, int layer, int level)
{
SetData(data.Memory.Span, layer, level, 1, 1, singleSlice: true);
SetData(data.Span, layer, level, 1, 1, singleSlice: true);
data.Dispose();
}
/// <inheritdoc/>
public void SetData(IMemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
public void SetData(MemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
{
SetData(data.Memory.Span, layer, level, 1, 1, singleSlice: true, region);
SetData(data.Span, layer, level, 1, 1, singleSlice: true, region);
data.Dispose();
}

View File

@ -14,7 +14,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
{
private readonly MemoryOwner<byte> _rawDataOwner;
private Span<byte> Raw => _rawDataOwner.Memory.Span;
private Span<byte> Raw => _rawDataOwner.Span;
private ref ParcelHeader Header => ref MemoryMarshal.Cast<byte, ParcelHeader>(Raw)[0];

View File

@ -1,5 +1,5 @@
using Ryujinx.Common.Memory;
using System;
using System.Buffers;
namespace Ryujinx.Memory
{
@ -7,7 +7,7 @@ namespace Ryujinx.Memory
{
private readonly IWritableBlock _block;
private readonly ulong _va;
private readonly IMemoryOwner<byte> _memoryOwner;
private readonly MemoryOwner<byte> _memoryOwner;
private readonly bool _tracked;
private bool NeedsWriteback => _block != null;
@ -22,7 +22,7 @@ namespace Ryujinx.Memory
Memory = memory;
}
public WritableRegion(IWritableBlock block, ulong va, IMemoryOwner<byte> memoryOwner, bool tracked = false)
public WritableRegion(IWritableBlock block, ulong va, MemoryOwner<byte> memoryOwner, bool tracked = false)
: this(block, va, memoryOwner.Memory, tracked)
{
_memoryOwner = memoryOwner;