Merge branch 'master' into master
This commit is contained in:
commit
bf016d99eb
42 changed files with 526 additions and 343 deletions
|
@ -20,7 +20,7 @@
|
|||
<PackageVersion Include="LibHac" Version="0.19.0" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.9.2" />
|
||||
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="7.4.0" />
|
||||
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="7.5.1" />
|
||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
||||
<PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.0" />
|
||||
<PackageVersion Include="MsgPack.Cli" Version="1.0.1" />
|
||||
|
|
|
@ -2426,7 +2426,11 @@ namespace ARMeilleure.Instructions
|
|||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseSse41 && sizeF == 0)
|
||||
{
|
||||
Operand res = EmitSse41Round32Exp8OpF(context, context.AddIntrinsic(Intrinsic.X86Rsqrtss, GetVec(op.Rn)), scalar: true);
|
||||
// RSQRTSS handles subnormals as zero, which differs from Arm, so we can't use it here.
|
||||
|
||||
Operand res = context.AddIntrinsic(Intrinsic.X86Sqrtss, GetVec(op.Rn));
|
||||
res = context.AddIntrinsic(Intrinsic.X86Rcpss, res);
|
||||
res = EmitSse41Round32Exp8OpF(context, res, scalar: true);
|
||||
|
||||
context.Copy(GetVec(op.Rd), context.VectorZeroUpper96(res));
|
||||
}
|
||||
|
@ -2451,7 +2455,11 @@ namespace ARMeilleure.Instructions
|
|||
}
|
||||
else if (Optimizations.FastFP && Optimizations.UseSse41 && sizeF == 0)
|
||||
{
|
||||
Operand res = EmitSse41Round32Exp8OpF(context, context.AddIntrinsic(Intrinsic.X86Rsqrtps, GetVec(op.Rn)), scalar: false);
|
||||
// RSQRTPS handles subnormals as zero, which differs from Arm, so we can't use it here.
|
||||
|
||||
Operand res = context.AddIntrinsic(Intrinsic.X86Sqrtps, GetVec(op.Rn));
|
||||
res = context.AddIntrinsic(Intrinsic.X86Rcpps, res);
|
||||
res = EmitSse41Round32Exp8OpF(context, res, scalar: false);
|
||||
|
||||
if (op.RegisterSize == RegisterSize.Simd64)
|
||||
{
|
||||
|
|
|
@ -29,7 +29,7 @@ namespace ARMeilleure.Translation.PTC
|
|||
private const string OuterHeaderMagicString = "PTCohd\0\0";
|
||||
private const string InnerHeaderMagicString = "PTCihd\0\0";
|
||||
|
||||
private const uint InternalVersion = 6613; //! To be incremented manually for each change to the ARMeilleure project.
|
||||
private const uint InternalVersion = 6634; //! To be incremented manually for each change to the ARMeilleure project.
|
||||
|
||||
private const string ActualDir = "0";
|
||||
private const string BackupDir = "1";
|
||||
|
|
|
@ -159,6 +159,11 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter
|
|||
}
|
||||
}
|
||||
|
||||
if (destinationCount < parameter.DestinationCount)
|
||||
{
|
||||
input.Advance((parameter.DestinationCount - destinationCount) * sizeof(int));
|
||||
}
|
||||
|
||||
Debug.Assert(parameter.Id == Id);
|
||||
|
||||
if (parameter.Id == Id)
|
||||
|
|
|
@ -1,89 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace Ryujinx.Common.Memory
|
||||
{
|
||||
/// <summary>
|
||||
/// A struct that can represent both a Span and Array.
|
||||
/// This is useful to keep the Array representation when possible to avoid copies.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Element Type</typeparam>
|
||||
public readonly ref struct SpanOrArray<T> where T : unmanaged
|
||||
{
|
||||
public readonly T[] Array;
|
||||
public readonly ReadOnlySpan<T> Span;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new SpanOrArray from an array.
|
||||
/// </summary>
|
||||
/// <param name="array">Array to store</param>
|
||||
public SpanOrArray(T[] array)
|
||||
{
|
||||
Array = array;
|
||||
Span = ReadOnlySpan<T>.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new SpanOrArray from a readonly span.
|
||||
/// </summary>
|
||||
/// <param name="array">Span to store</param>
|
||||
public SpanOrArray(ReadOnlySpan<T> span)
|
||||
{
|
||||
Array = null;
|
||||
Span = span;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the contained array, or convert the span if necessary.
|
||||
/// </summary>
|
||||
/// <returns>An array containing the data</returns>
|
||||
public T[] ToArray()
|
||||
{
|
||||
return Array ?? Span.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a ReadOnlySpan from either the array or ReadOnlySpan.
|
||||
/// </summary>
|
||||
/// <returns>A ReadOnlySpan containing the data</returns>
|
||||
public ReadOnlySpan<T> AsSpan()
|
||||
{
|
||||
return Array ?? Span;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cast an array to a SpanOrArray.
|
||||
/// </summary>
|
||||
/// <param name="array">Source array</param>
|
||||
public static implicit operator SpanOrArray<T>(T[] array)
|
||||
{
|
||||
return new SpanOrArray<T>(array);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cast a ReadOnlySpan to a SpanOrArray.
|
||||
/// </summary>
|
||||
/// <param name="span">Source ReadOnlySpan</param>
|
||||
public static implicit operator SpanOrArray<T>(ReadOnlySpan<T> span)
|
||||
{
|
||||
return new SpanOrArray<T>(span);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cast a Span to a SpanOrArray.
|
||||
/// </summary>
|
||||
/// <param name="span">Source Span</param>
|
||||
public static implicit operator SpanOrArray<T>(Span<T> span)
|
||||
{
|
||||
return new SpanOrArray<T>(span);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cast a SpanOrArray to a ReadOnlySpan
|
||||
/// </summary>
|
||||
/// <param name="spanOrArray">Source SpanOrArray</param>
|
||||
public static implicit operator ReadOnlySpan<T>(SpanOrArray<T> spanOrArray)
|
||||
{
|
||||
return spanOrArray.AsSpan();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
using Ryujinx.Common.Utilities;
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
@ -41,6 +42,22 @@ namespace Ryujinx.Common
|
|||
return StreamUtils.StreamToBytes(stream);
|
||||
}
|
||||
|
||||
public static IMemoryOwner<byte> ReadFileToRentedMemory(string filename)
|
||||
{
|
||||
var (assembly, path) = ResolveManifestPath(filename);
|
||||
|
||||
return ReadFileToRentedMemory(assembly, path);
|
||||
}
|
||||
|
||||
public static IMemoryOwner<byte> ReadFileToRentedMemory(Assembly assembly, string filename)
|
||||
{
|
||||
using var stream = GetStream(assembly, filename);
|
||||
|
||||
return stream is null
|
||||
? null
|
||||
: StreamUtils.StreamToRentedMemory(stream);
|
||||
}
|
||||
|
||||
public async static Task<byte[]> ReadAsync(Assembly assembly, string filename)
|
||||
{
|
||||
using var stream = GetStream(assembly, filename);
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
using Microsoft.IO;
|
||||
using Ryujinx.Common.Memory;
|
||||
using System.Buffers;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -9,12 +11,50 @@ namespace Ryujinx.Common.Utilities
|
|||
{
|
||||
public static byte[] StreamToBytes(Stream input)
|
||||
{
|
||||
using MemoryStream stream = MemoryStreamManager.Shared.GetStream();
|
||||
using RecyclableMemoryStream output = StreamToRecyclableMemoryStream(input);
|
||||
|
||||
return output.ToArray();
|
||||
}
|
||||
|
||||
input.CopyTo(stream);
|
||||
public static IMemoryOwner<byte> StreamToRentedMemory(Stream input)
|
||||
{
|
||||
if (input is MemoryStream inputMemoryStream)
|
||||
{
|
||||
return MemoryStreamToRentedMemory(inputMemoryStream);
|
||||
}
|
||||
else if (input.CanSeek)
|
||||
{
|
||||
long bytesExpected = input.Length;
|
||||
|
||||
return stream.ToArray();
|
||||
IMemoryOwner<byte> ownedMemory = ByteMemoryPool.Rent(bytesExpected);
|
||||
|
||||
var destSpan = ownedMemory.Memory.Span;
|
||||
|
||||
int totalBytesRead = 0;
|
||||
|
||||
while (totalBytesRead < bytesExpected)
|
||||
{
|
||||
int bytesRead = input.Read(destSpan[totalBytesRead..]);
|
||||
|
||||
if (bytesRead == 0)
|
||||
{
|
||||
ownedMemory.Dispose();
|
||||
|
||||
throw new IOException($"Tried reading {bytesExpected} but the stream closed after reading {totalBytesRead}.");
|
||||
}
|
||||
|
||||
totalBytesRead += bytesRead;
|
||||
}
|
||||
|
||||
return ownedMemory;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If input is (non-seekable) then copy twice: first into a RecyclableMemoryStream, then to a rented IMemoryOwner<byte>.
|
||||
using RecyclableMemoryStream output = StreamToRecyclableMemoryStream(input);
|
||||
|
||||
return MemoryStreamToRentedMemory(output);
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<byte[]> StreamToBytesAsync(Stream input, CancellationToken cancellationToken = default)
|
||||
|
@ -25,5 +65,26 @@ namespace Ryujinx.Common.Utilities
|
|||
|
||||
return stream.ToArray();
|
||||
}
|
||||
|
||||
private static IMemoryOwner<byte> MemoryStreamToRentedMemory(MemoryStream input)
|
||||
{
|
||||
input.Position = 0;
|
||||
|
||||
IMemoryOwner<byte> ownedMemory = ByteMemoryPool.Rent(input.Length);
|
||||
|
||||
// Discard the return value because we assume reading a MemoryStream always succeeds completely.
|
||||
_ = input.Read(ownedMemory.Memory.Span);
|
||||
|
||||
return ownedMemory;
|
||||
}
|
||||
|
||||
private static RecyclableMemoryStream StreamToRecyclableMemoryStream(Stream input)
|
||||
{
|
||||
RecyclableMemoryStream stream = MemoryStreamManager.Shared.GetStream();
|
||||
|
||||
input.CopyTo(stream);
|
||||
|
||||
return stream;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
|
@ -143,11 +145,11 @@ namespace Ryujinx.Graphics.Device
|
|||
}
|
||||
else
|
||||
{
|
||||
Memory<byte> memory = new byte[size];
|
||||
IMemoryOwner<byte> memoryOwner = ByteMemoryPool.Rent(size);
|
||||
|
||||
GetSpan(va, size).CopyTo(memory.Span);
|
||||
GetSpan(va, size).CopyTo(memoryOwner.Memory.Span);
|
||||
|
||||
return new WritableRegion(this, va, memory, tracked: true);
|
||||
return new WritableRegion(this, va, memoryOwner, tracked: true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using Ryujinx.Common.Memory;
|
||||
using System.Buffers;
|
||||
|
||||
namespace Ryujinx.Graphics.GAL
|
||||
{
|
||||
|
@ -17,10 +17,34 @@ namespace Ryujinx.Graphics.GAL
|
|||
PinnedSpan<byte> GetData();
|
||||
PinnedSpan<byte> GetData(int layer, int level);
|
||||
|
||||
void SetData(SpanOrArray<byte> data);
|
||||
void SetData(SpanOrArray<byte> data, int layer, int level);
|
||||
void SetData(SpanOrArray<byte> data, int layer, int level, Rectangle<int> region);
|
||||
/// <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>
|
||||
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 Release();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
using Ryujinx.Graphics.GAL.Multithreading.Model;
|
||||
using Ryujinx.Graphics.GAL.Multithreading.Resources;
|
||||
using System;
|
||||
using System.Buffers;
|
||||
|
||||
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
|
||||
{
|
||||
|
@ -8,9 +8,9 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
|
|||
{
|
||||
public readonly CommandType CommandType => CommandType.TextureSetData;
|
||||
private TableRef<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;
|
||||
_data = data;
|
||||
|
@ -19,7 +19,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
|
|||
public static void Run(ref TextureSetDataCommand command, ThreadedRenderer threaded, IRenderer renderer)
|
||||
{
|
||||
ThreadedTexture texture = command._texture.Get(threaded);
|
||||
texture.Base.SetData(new ReadOnlySpan<byte>(command._data.Get(threaded)));
|
||||
texture.Base.SetData(command._data.Get(threaded));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
using Ryujinx.Graphics.GAL.Multithreading.Model;
|
||||
using Ryujinx.Graphics.GAL.Multithreading.Resources;
|
||||
using System;
|
||||
using System.Buffers;
|
||||
|
||||
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
|
||||
{
|
||||
|
@ -8,11 +8,11 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
|
|||
{
|
||||
public readonly CommandType CommandType => CommandType.TextureSetDataSlice;
|
||||
private TableRef<ThreadedTexture> _texture;
|
||||
private TableRef<byte[]> _data;
|
||||
private TableRef<IMemoryOwner<byte>> _data;
|
||||
private int _layer;
|
||||
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;
|
||||
_data = data;
|
||||
|
@ -23,7 +23,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
|
|||
public static void Run(ref TextureSetDataSliceCommand command, ThreadedRenderer threaded, IRenderer renderer)
|
||||
{
|
||||
ThreadedTexture texture = command._texture.Get(threaded);
|
||||
texture.Base.SetData(new ReadOnlySpan<byte>(command._data.Get(threaded)), command._layer, command._level);
|
||||
texture.Base.SetData(command._data.Get(threaded), command._layer, command._level);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
using Ryujinx.Graphics.GAL.Multithreading.Model;
|
||||
using Ryujinx.Graphics.GAL.Multithreading.Resources;
|
||||
using System;
|
||||
using System.Buffers;
|
||||
|
||||
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
|
||||
{
|
||||
|
@ -8,12 +8,12 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
|
|||
{
|
||||
public readonly CommandType CommandType => CommandType.TextureSetDataSliceRegion;
|
||||
private TableRef<ThreadedTexture> _texture;
|
||||
private TableRef<byte[]> _data;
|
||||
private TableRef<IMemoryOwner<byte>> _data;
|
||||
private int _layer;
|
||||
private int _level;
|
||||
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;
|
||||
_data = data;
|
||||
|
@ -25,7 +25,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
|
|||
public static void Run(ref TextureSetDataSliceRegionCommand command, ThreadedRenderer threaded, IRenderer renderer)
|
||||
{
|
||||
ThreadedTexture texture = command._texture.Get(threaded);
|
||||
texture.Base.SetData(new ReadOnlySpan<byte>(command._data.Get(threaded)), command._layer, command._level, command._region);
|
||||
texture.Base.SetData(command._data.Get(threaded), command._layer, command._level, command._region);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Graphics.GAL.Multithreading.Commands.Texture;
|
||||
using Ryujinx.Graphics.GAL.Multithreading.Model;
|
||||
using System.Buffers;
|
||||
|
||||
namespace Ryujinx.Graphics.GAL.Multithreading.Resources
|
||||
{
|
||||
|
@ -110,21 +110,24 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources
|
|||
_renderer.QueueCommand();
|
||||
}
|
||||
|
||||
public void SetData(SpanOrArray<byte> data)
|
||||
/// <inheritdoc/>
|
||||
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();
|
||||
}
|
||||
|
||||
public void SetData(SpanOrArray<byte> data, int layer, int level)
|
||||
/// <inheritdoc/>
|
||||
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();
|
||||
}
|
||||
|
||||
public void SetData(SpanOrArray<byte> data, int layer, int level, Rectangle<int> region)
|
||||
/// <inheritdoc/>
|
||||
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();
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ using Ryujinx.Graphics.Gpu.Engine.Threed;
|
|||
using Ryujinx.Graphics.Gpu.Memory;
|
||||
using Ryujinx.Graphics.Texture;
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
@ -308,7 +309,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
|
|||
|
||||
if (target != null)
|
||||
{
|
||||
byte[] data;
|
||||
IMemoryOwner<byte> data;
|
||||
if (srcLinear)
|
||||
{
|
||||
data = LayoutConverter.ConvertLinearStridedToLinear(
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Graphics.Device;
|
||||
using Ryujinx.Graphics.Texture;
|
||||
using System;
|
||||
|
@ -198,7 +199,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.InlineToMemory
|
|||
if (target != null)
|
||||
{
|
||||
target.SynchronizeMemory();
|
||||
target.SetData(data, 0, 0, new GAL.Rectangle<int>(_dstX, _dstY, _lineLengthIn / target.Info.FormatInfo.BytesPerPixel, _lineCount));
|
||||
var dataCopy = ByteMemoryPool.RentCopy(data);
|
||||
target.SetData(dataCopy, 0, 0, new GAL.Rectangle<int>(_dstX, _dstY, _lineLengthIn / target.Info.FormatInfo.BytesPerPixel, _lineCount));
|
||||
target.SignalModified();
|
||||
|
||||
return;
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Gpu.Memory;
|
||||
using Ryujinx.Graphics.Texture;
|
||||
|
@ -7,6 +6,7 @@ using Ryujinx.Graphics.Texture.Astc;
|
|||
using Ryujinx.Memory;
|
||||
using Ryujinx.Memory.Range;
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
|
@ -661,7 +661,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
}
|
||||
}
|
||||
|
||||
SpanOrArray<byte> result = ConvertToHostCompatibleFormat(data);
|
||||
IMemoryOwner<byte> result = ConvertToHostCompatibleFormat(data);
|
||||
|
||||
if (ScaleFactor != 1f && AllowScaledSetData())
|
||||
{
|
||||
|
@ -684,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(SpanOrArray<byte> data)
|
||||
public void SetData(IMemoryOwner<byte> data)
|
||||
{
|
||||
BlacklistScale();
|
||||
|
||||
|
@ -703,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(SpanOrArray<byte> data, int layer, int level)
|
||||
public void SetData(IMemoryOwner<byte> data, int layer, int level)
|
||||
{
|
||||
BlacklistScale();
|
||||
|
||||
|
@ -721,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(ReadOnlySpan<byte> data, int layer, int level, Rectangle<int> region)
|
||||
public void SetData(IMemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
|
||||
{
|
||||
BlacklistScale();
|
||||
|
||||
|
@ -739,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 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 height = Info.Height;
|
||||
|
@ -754,11 +754,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
|
||||
int sliceDepth = single ? 1 : depth;
|
||||
|
||||
SpanOrArray<byte> result;
|
||||
IMemoryOwner<byte> linear;
|
||||
|
||||
if (Info.IsLinear)
|
||||
{
|
||||
result = LayoutConverter.ConvertLinearStridedToLinear(
|
||||
linear = LayoutConverter.ConvertLinearStridedToLinear(
|
||||
width,
|
||||
height,
|
||||
Info.FormatInfo.BlockWidth,
|
||||
|
@ -770,7 +770,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
}
|
||||
else
|
||||
{
|
||||
result = LayoutConverter.ConvertBlockLinearToLinear(
|
||||
linear = LayoutConverter.ConvertBlockLinearToLinear(
|
||||
width,
|
||||
height,
|
||||
depth,
|
||||
|
@ -787,33 +787,41 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
data);
|
||||
}
|
||||
|
||||
IMemoryOwner<byte> result = linear;
|
||||
|
||||
// Handle compressed cases not supported by the host:
|
||||
// - ASTC is usually not supported on desktop cards.
|
||||
// - BC4/BC5 is not supported on 3D textures.
|
||||
if (!_context.Capabilities.SupportsAstcCompression && Format.IsAstc())
|
||||
{
|
||||
if (!AstcDecoder.TryDecodeToRgba8P(
|
||||
result.ToArray(),
|
||||
Info.FormatInfo.BlockWidth,
|
||||
Info.FormatInfo.BlockHeight,
|
||||
width,
|
||||
height,
|
||||
sliceDepth,
|
||||
levels,
|
||||
layers,
|
||||
out byte[] decoded))
|
||||
using (result)
|
||||
{
|
||||
string texInfo = $"{Info.Target} {Info.FormatInfo.Format} {Info.Width}x{Info.Height}x{Info.DepthOrLayers} levels {Info.Levels}";
|
||||
if (!AstcDecoder.TryDecodeToRgba8P(
|
||||
result.Memory,
|
||||
Info.FormatInfo.BlockWidth,
|
||||
Info.FormatInfo.BlockHeight,
|
||||
width,
|
||||
height,
|
||||
sliceDepth,
|
||||
levels,
|
||||
layers,
|
||||
out IMemoryOwner<byte> decoded))
|
||||
{
|
||||
string texInfo = $"{Info.Target} {Info.FormatInfo.Format} {Info.Width}x{Info.Height}x{Info.DepthOrLayers} levels {Info.Levels}";
|
||||
|
||||
Logger.Debug?.Print(LogClass.Gpu, $"Invalid ASTC texture at 0x{Info.GpuAddress:X} ({texInfo}).");
|
||||
Logger.Debug?.Print(LogClass.Gpu, $"Invalid ASTC texture at 0x{Info.GpuAddress:X} ({texInfo}).");
|
||||
}
|
||||
|
||||
if (GraphicsConfig.EnableTextureRecompression)
|
||||
{
|
||||
using (decoded)
|
||||
{
|
||||
return BCnEncoder.EncodeBC7(decoded.Memory, width, height, sliceDepth, levels, layers);
|
||||
}
|
||||
}
|
||||
|
||||
return decoded;
|
||||
}
|
||||
|
||||
if (GraphicsConfig.EnableTextureRecompression)
|
||||
{
|
||||
decoded = BCnEncoder.EncodeBC7(decoded, width, height, sliceDepth, levels, layers);
|
||||
}
|
||||
|
||||
result = decoded;
|
||||
}
|
||||
else if (!_context.Capabilities.SupportsEtc2Compression && Format.IsEtc2())
|
||||
{
|
||||
|
@ -821,16 +829,22 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
{
|
||||
case Format.Etc2RgbaSrgb:
|
||||
case Format.Etc2RgbaUnorm:
|
||||
result = ETC2Decoder.DecodeRgba(result, width, height, sliceDepth, levels, layers);
|
||||
break;
|
||||
using (result)
|
||||
{
|
||||
return ETC2Decoder.DecodeRgba(result.Memory.Span, width, height, sliceDepth, levels, layers);
|
||||
}
|
||||
case Format.Etc2RgbPtaSrgb:
|
||||
case Format.Etc2RgbPtaUnorm:
|
||||
result = ETC2Decoder.DecodePta(result, width, height, sliceDepth, levels, layers);
|
||||
break;
|
||||
using (result)
|
||||
{
|
||||
return ETC2Decoder.DecodePta(result.Memory.Span, width, height, sliceDepth, levels, layers);
|
||||
}
|
||||
case Format.Etc2RgbSrgb:
|
||||
case Format.Etc2RgbUnorm:
|
||||
result = ETC2Decoder.DecodeRgb(result, width, height, sliceDepth, levels, layers);
|
||||
break;
|
||||
using (result)
|
||||
{
|
||||
return ETC2Decoder.DecodeRgb(result.Memory.Span, width, height, sliceDepth, levels, layers);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!TextureCompatibility.HostSupportsBcFormat(Format, Target, _context.Capabilities))
|
||||
|
@ -839,48 +853,75 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
{
|
||||
case Format.Bc1RgbaSrgb:
|
||||
case Format.Bc1RgbaUnorm:
|
||||
result = BCnDecoder.DecodeBC1(result, width, height, sliceDepth, levels, layers);
|
||||
break;
|
||||
using (result)
|
||||
{
|
||||
return BCnDecoder.DecodeBC1(result.Memory.Span, width, height, sliceDepth, levels, layers);
|
||||
}
|
||||
case Format.Bc2Srgb:
|
||||
case Format.Bc2Unorm:
|
||||
result = BCnDecoder.DecodeBC2(result, width, height, sliceDepth, levels, layers);
|
||||
break;
|
||||
using (result)
|
||||
{
|
||||
return BCnDecoder.DecodeBC2(result.Memory.Span, width, height, sliceDepth, levels, layers);
|
||||
}
|
||||
case Format.Bc3Srgb:
|
||||
case Format.Bc3Unorm:
|
||||
result = BCnDecoder.DecodeBC3(result, width, height, sliceDepth, levels, layers);
|
||||
break;
|
||||
using (result)
|
||||
{
|
||||
return BCnDecoder.DecodeBC3(result.Memory.Span, width, height, sliceDepth, levels, layers);
|
||||
}
|
||||
case Format.Bc4Snorm:
|
||||
case Format.Bc4Unorm:
|
||||
result = BCnDecoder.DecodeBC4(result, width, height, sliceDepth, levels, layers, Format == Format.Bc4Snorm);
|
||||
break;
|
||||
using (result)
|
||||
{
|
||||
return BCnDecoder.DecodeBC4(result.Memory.Span, width, height, sliceDepth, levels, layers, Format == Format.Bc4Snorm);
|
||||
}
|
||||
case Format.Bc5Snorm:
|
||||
case Format.Bc5Unorm:
|
||||
result = BCnDecoder.DecodeBC5(result, width, height, sliceDepth, levels, layers, Format == Format.Bc5Snorm);
|
||||
break;
|
||||
using (result)
|
||||
{
|
||||
return BCnDecoder.DecodeBC5(result.Memory.Span, width, height, sliceDepth, levels, layers, Format == Format.Bc5Snorm);
|
||||
}
|
||||
case Format.Bc6HSfloat:
|
||||
case Format.Bc6HUfloat:
|
||||
result = BCnDecoder.DecodeBC6(result, width, height, sliceDepth, levels, layers, Format == Format.Bc6HSfloat);
|
||||
break;
|
||||
using (result)
|
||||
{
|
||||
return BCnDecoder.DecodeBC6(result.Memory.Span, width, height, sliceDepth, levels, layers, Format == Format.Bc6HSfloat);
|
||||
}
|
||||
case Format.Bc7Srgb:
|
||||
case Format.Bc7Unorm:
|
||||
result = BCnDecoder.DecodeBC7(result, width, height, sliceDepth, levels, layers);
|
||||
break;
|
||||
using (result)
|
||||
{
|
||||
return BCnDecoder.DecodeBC7(result.Memory.Span, width, height, sliceDepth, levels, layers);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!_context.Capabilities.SupportsR4G4Format && Format == Format.R4G4Unorm)
|
||||
{
|
||||
result = PixelConverter.ConvertR4G4ToR4G4B4A4(result, width);
|
||||
|
||||
if (!_context.Capabilities.SupportsR4G4B4A4Format)
|
||||
using (result)
|
||||
{
|
||||
result = PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(result, width);
|
||||
var converted = PixelConverter.ConvertR4G4ToR4G4B4A4(result.Memory.Span, width);
|
||||
|
||||
if (_context.Capabilities.SupportsR4G4B4A4Format)
|
||||
{
|
||||
return converted;
|
||||
}
|
||||
else
|
||||
{
|
||||
using (converted)
|
||||
{
|
||||
return PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(converted.Memory.Span, width);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (Format == Format.R4G4B4A4Unorm)
|
||||
{
|
||||
if (!_context.Capabilities.SupportsR4G4B4A4Format)
|
||||
{
|
||||
result = PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(result, width);
|
||||
using (result)
|
||||
{
|
||||
return PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(result.Memory.Span, width);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!_context.Capabilities.Supports5BitComponentFormat && Format.Is16BitPacked())
|
||||
|
@ -889,19 +930,27 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
{
|
||||
case Format.B5G6R5Unorm:
|
||||
case Format.R5G6B5Unorm:
|
||||
result = PixelConverter.ConvertR5G6B5ToR8G8B8A8(result, width);
|
||||
break;
|
||||
using (result)
|
||||
{
|
||||
return PixelConverter.ConvertR5G6B5ToR8G8B8A8(result.Memory.Span, width);
|
||||
}
|
||||
case Format.B5G5R5A1Unorm:
|
||||
case Format.R5G5B5X1Unorm:
|
||||
case Format.R5G5B5A1Unorm:
|
||||
result = PixelConverter.ConvertR5G5B5ToR8G8B8A8(result, width, Format == Format.R5G5B5X1Unorm);
|
||||
break;
|
||||
using (result)
|
||||
{
|
||||
return PixelConverter.ConvertR5G5B5ToR8G8B8A8(result.Memory.Span, width, Format == Format.R5G5B5X1Unorm);
|
||||
}
|
||||
case Format.A1B5G5R5Unorm:
|
||||
result = PixelConverter.ConvertA1B5G5R5ToR8G8B8A8(result, width);
|
||||
break;
|
||||
using (result)
|
||||
{
|
||||
return PixelConverter.ConvertA1B5G5R5ToR8G8B8A8(result.Memory.Span, width);
|
||||
}
|
||||
case Format.R4G4B4A4Unorm:
|
||||
result = PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(result, width);
|
||||
break;
|
||||
using (result)
|
||||
{
|
||||
return PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(result.Memory.Span, width);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -224,7 +224,8 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
/// Synchronizes memory for all textures in the array.
|
||||
/// </summary>
|
||||
/// <param name="isStore">Indicates if the texture may be modified by the access</param>
|
||||
public void SynchronizeMemory(bool isStore)
|
||||
/// <param name="blacklistScale">Indicates if the texture should be blacklisted for scaling</param>
|
||||
public void SynchronizeMemory(bool isStore, bool blacklistScale)
|
||||
{
|
||||
foreach (Texture texture in Textures.Keys)
|
||||
{
|
||||
|
@ -234,6 +235,13 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
{
|
||||
texture.SignalModified();
|
||||
}
|
||||
|
||||
if (blacklistScale && texture.ScaleMode != TextureScaleMode.Blacklisted)
|
||||
{
|
||||
// Scaling textures used on arrays is currently not supported.
|
||||
|
||||
texture.BlacklistScale();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -467,6 +475,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
|
||||
bool poolsModified = entry.PoolsModified();
|
||||
bool isStore = bindingInfo.Flags.HasFlag(TextureUsageFlags.ImageStore);
|
||||
bool resScaleUnsupported = bindingInfo.Flags.HasFlag(TextureUsageFlags.ResScaleUnsupported);
|
||||
|
||||
ReadOnlySpan<int> cachedTextureBuffer;
|
||||
ReadOnlySpan<int> cachedSamplerBuffer;
|
||||
|
@ -475,7 +484,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
{
|
||||
if (entry.MatchesSequenceNumber(_context.SequenceNumber))
|
||||
{
|
||||
entry.SynchronizeMemory(isStore);
|
||||
entry.SynchronizeMemory(isStore, resScaleUnsupported);
|
||||
|
||||
if (isImage)
|
||||
{
|
||||
|
@ -504,7 +513,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
|
||||
if (entry.MatchesBufferData(cachedTextureBuffer, cachedSamplerBuffer, separateSamplerBuffer, samplerWordOffset))
|
||||
{
|
||||
entry.SynchronizeMemory(isStore);
|
||||
entry.SynchronizeMemory(isStore, resScaleUnsupported);
|
||||
|
||||
if (isImage)
|
||||
{
|
||||
|
@ -569,6 +578,13 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
{
|
||||
texture.SignalModified();
|
||||
}
|
||||
|
||||
if (resScaleUnsupported && texture.ScaleMode != TextureScaleMode.Blacklisted)
|
||||
{
|
||||
// Scaling textures used on arrays is currently not supported.
|
||||
|
||||
texture.BlacklistScale();
|
||||
}
|
||||
}
|
||||
|
||||
Sampler sampler = samplerPool?.Get(samplerId);
|
||||
|
|
|
@ -247,6 +247,10 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
{
|
||||
return TextureMatchQuality.FormatAlias;
|
||||
}
|
||||
else if (lhs.FormatInfo.Format == Format.D32FloatS8Uint && rhs.FormatInfo.Format == Format.R32G32Float)
|
||||
{
|
||||
return TextureMatchQuality.FormatAlias;
|
||||
}
|
||||
}
|
||||
|
||||
return lhs.FormatInfo.Format == rhs.FormatInfo.Format ? TextureMatchQuality.Perfect : TextureMatchQuality.NoMatch;
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Gpu.Memory;
|
||||
using Ryujinx.Graphics.Texture;
|
||||
|
@ -6,6 +5,7 @@ using Ryujinx.Memory;
|
|||
using Ryujinx.Memory.Range;
|
||||
using Ryujinx.Memory.Tracking;
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
|
@ -445,7 +445,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
|
||||
ReadOnlySpan<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);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Memory;
|
||||
using Ryujinx.Memory.Range;
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
@ -240,11 +242,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
}
|
||||
else
|
||||
{
|
||||
Memory<byte> memory = new byte[size];
|
||||
IMemoryOwner<byte> memoryOwner = ByteMemoryPool.Rent(size);
|
||||
|
||||
GetSpan(va, size).CopyTo(memory.Span);
|
||||
GetSpan(va, size).CopyTo(memoryOwner.Memory.Span);
|
||||
|
||||
return new WritableRegion(this, va, memory, tracked);
|
||||
return new WritableRegion(this, va, memoryOwner, tracked);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Cpu;
|
||||
using Ryujinx.Graphics.Device;
|
||||
using Ryujinx.Graphics.Gpu.Image;
|
||||
|
@ -6,6 +7,7 @@ using Ryujinx.Memory;
|
|||
using Ryujinx.Memory.Range;
|
||||
using Ryujinx.Memory.Tracking;
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
|
@ -190,7 +192,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
}
|
||||
else
|
||||
{
|
||||
Memory<byte> memory = new byte[range.GetSize()];
|
||||
IMemoryOwner<byte> memoryOwner = ByteMemoryPool.Rent(range.GetSize());
|
||||
|
||||
Memory<byte> memory = memoryOwner.Memory;
|
||||
|
||||
int offset = 0;
|
||||
for (int i = 0; i < range.Count; i++)
|
||||
|
@ -204,7 +208,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
offset += size;
|
||||
}
|
||||
|
||||
return new WritableRegion(new MultiRangeWritableBlock(range, this), 0, memory, tracked);
|
||||
return new WritableRegion(new MultiRangeWritableBlock(range, this), 0, memoryOwner, tracked);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,8 @@ namespace Ryujinx.Graphics.OpenGL.Effects.Smaa
|
|||
|
||||
public int Quality
|
||||
{
|
||||
get => _quality; set
|
||||
get => _quality;
|
||||
set
|
||||
{
|
||||
_quality = Math.Clamp(value, 0, _qualities.Length - 1);
|
||||
}
|
||||
|
@ -150,8 +151,8 @@ namespace Ryujinx.Graphics.OpenGL.Effects.Smaa
|
|||
_areaTexture = new TextureStorage(_renderer, areaInfo);
|
||||
_searchTexture = new TextureStorage(_renderer, searchInfo);
|
||||
|
||||
var areaTexture = EmbeddedResources.Read("Ryujinx.Graphics.OpenGL/Effects/Textures/SmaaAreaTexture.bin");
|
||||
var searchTexture = EmbeddedResources.Read("Ryujinx.Graphics.OpenGL/Effects/Textures/SmaaSearchTexture.bin");
|
||||
var areaTexture = EmbeddedResources.ReadFileToRentedMemory("Ryujinx.Graphics.OpenGL/Effects/Textures/SmaaAreaTexture.bin");
|
||||
var searchTexture = EmbeddedResources.ReadFileToRentedMemory("Ryujinx.Graphics.OpenGL/Effects/Textures/SmaaSearchTexture.bin");
|
||||
|
||||
var areaView = _areaTexture.CreateDefaultView();
|
||||
var searchView = _searchTexture.CreateDefaultView();
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
using Ryujinx.Common.Memory;
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Numerics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Intrinsics;
|
||||
|
@ -8,9 +10,11 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
|||
{
|
||||
static class FormatConverter
|
||||
{
|
||||
public unsafe static byte[] ConvertS8D24ToD24S8(ReadOnlySpan<byte> data)
|
||||
public unsafe static IMemoryOwner<byte> ConvertS8D24ToD24S8(ReadOnlySpan<byte> data)
|
||||
{
|
||||
byte[] output = new byte[data.Length];
|
||||
IMemoryOwner<byte> outputMemory = ByteMemoryPool.Rent(data.Length);
|
||||
|
||||
Span<byte> output = outputMemory.Memory.Span;
|
||||
|
||||
int start = 0;
|
||||
|
||||
|
@ -74,7 +78,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
|||
outSpan[i] = BitOperations.RotateLeft(dataSpan[i], 8);
|
||||
}
|
||||
|
||||
return output;
|
||||
return outputMemory;
|
||||
}
|
||||
|
||||
public unsafe static byte[] ConvertD24S8ToS8D24(ReadOnlySpan<byte> data)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
using OpenTK.Graphics.OpenGL;
|
||||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using System;
|
||||
using System.Buffers;
|
||||
|
||||
namespace Ryujinx.Graphics.OpenGL.Image
|
||||
{
|
||||
|
@ -54,19 +54,24 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
|||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void SetData(SpanOrArray<byte> data)
|
||||
/// <inheritdoc/>
|
||||
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)]);
|
||||
|
||||
data.Dispose();
|
||||
}
|
||||
|
||||
public void SetData(SpanOrArray<byte> data, int layer, int level)
|
||||
/// <inheritdoc/>
|
||||
public void SetData(IMemoryOwner<byte> data, int layer, int level)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public void SetData(SpanOrArray<byte> data, int layer, int level, Rectangle<int> region)
|
||||
/// <inheritdoc/>
|
||||
public void SetData(IMemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
using OpenTK.Graphics.OpenGL;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Ryujinx.Graphics.OpenGL.Image
|
||||
|
@ -448,70 +448,59 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
|||
}
|
||||
}
|
||||
|
||||
public void SetData(SpanOrArray<byte> data)
|
||||
public void SetData(IMemoryOwner<byte> data)
|
||||
{
|
||||
var dataSpan = data.AsSpan();
|
||||
|
||||
if (Format == Format.S8UintD24Unorm)
|
||||
using (data = EnsureDataFormat(data))
|
||||
{
|
||||
dataSpan = FormatConverter.ConvertS8D24ToD24S8(dataSpan);
|
||||
}
|
||||
|
||||
unsafe
|
||||
{
|
||||
fixed (byte* ptr = dataSpan)
|
||||
unsafe
|
||||
{
|
||||
ReadFrom((IntPtr)ptr, dataSpan.Length);
|
||||
var dataSpan = data.Memory.Span;
|
||||
fixed (byte* ptr = dataSpan)
|
||||
{
|
||||
ReadFrom((IntPtr)ptr, dataSpan.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SetData(SpanOrArray<byte> data, int layer, int level)
|
||||
public void SetData(IMemoryOwner<byte> data, int layer, int level)
|
||||
{
|
||||
var dataSpan = data.AsSpan();
|
||||
|
||||
if (Format == Format.S8UintD24Unorm)
|
||||
using (data = EnsureDataFormat(data))
|
||||
{
|
||||
dataSpan = FormatConverter.ConvertS8D24ToD24S8(dataSpan);
|
||||
}
|
||||
|
||||
unsafe
|
||||
{
|
||||
fixed (byte* ptr = dataSpan)
|
||||
unsafe
|
||||
{
|
||||
int width = Math.Max(Info.Width >> level, 1);
|
||||
int height = Math.Max(Info.Height >> level, 1);
|
||||
fixed (byte* ptr = data.Memory.Span)
|
||||
{
|
||||
int width = Math.Max(Info.Width >> level, 1);
|
||||
int height = Math.Max(Info.Height >> level, 1);
|
||||
|
||||
ReadFrom2D((IntPtr)ptr, layer, level, 0, 0, width, height);
|
||||
ReadFrom2D((IntPtr)ptr, layer, level, 0, 0, width, height);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SetData(SpanOrArray<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();
|
||||
|
||||
if (Format == Format.S8UintD24Unorm)
|
||||
using (data = EnsureDataFormat(data))
|
||||
{
|
||||
dataSpan = FormatConverter.ConvertS8D24ToD24S8(dataSpan);
|
||||
}
|
||||
int wInBlocks = BitUtils.DivRoundUp(region.Width, Info.BlockWidth);
|
||||
int hInBlocks = BitUtils.DivRoundUp(region.Height, Info.BlockHeight);
|
||||
|
||||
int wInBlocks = BitUtils.DivRoundUp(region.Width, Info.BlockWidth);
|
||||
int hInBlocks = BitUtils.DivRoundUp(region.Height, Info.BlockHeight);
|
||||
|
||||
unsafe
|
||||
{
|
||||
fixed (byte* ptr = dataSpan)
|
||||
unsafe
|
||||
{
|
||||
ReadFrom2D(
|
||||
(IntPtr)ptr,
|
||||
layer,
|
||||
level,
|
||||
region.X,
|
||||
region.Y,
|
||||
region.Width,
|
||||
region.Height,
|
||||
BitUtils.AlignUp(wInBlocks * Info.BytesPerPixel, 4) * hInBlocks);
|
||||
fixed (byte* ptr = data.Memory.Span)
|
||||
{
|
||||
ReadFrom2D(
|
||||
(IntPtr)ptr,
|
||||
layer,
|
||||
level,
|
||||
region.X,
|
||||
region.Y,
|
||||
region.Width,
|
||||
region.Height,
|
||||
BitUtils.AlignUp(wInBlocks * Info.BytesPerPixel, 4) * hInBlocks);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -533,6 +522,19 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
|||
ReadFrom2D(data, layer, level, x, y, width, height, mipSize);
|
||||
}
|
||||
|
||||
private IMemoryOwner<byte> EnsureDataFormat(IMemoryOwner<byte> data)
|
||||
{
|
||||
if (Format == Format.S8UintD24Unorm)
|
||||
{
|
||||
using (data)
|
||||
{
|
||||
return FormatConverter.ConvertS8D24ToD24S8(data.Memory.Span);
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
private void ReadFrom2D(IntPtr data, int layer, int level, int x, int y, int width, int height, int mipSize)
|
||||
{
|
||||
TextureTarget target = Target.Convert();
|
||||
|
|
|
@ -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<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));
|
||||
|
||||
decoded = output;
|
||||
|
||||
return decoder.Success;
|
||||
}
|
||||
|
||||
|
|
|
@ -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<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;
|
||||
|
||||
|
@ -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<byte> output = ByteMemoryPool.Rent(size);
|
||||
|
||||
Span<byte> tile = stackalloc byte[BlockWidth * BlockHeight * 4];
|
||||
|
||||
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);
|
||||
|
||||
|
@ -100,7 +102,7 @@ namespace Ryujinx.Graphics.Texture
|
|||
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;
|
||||
|
||||
|
@ -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<byte> output = ByteMemoryPool.Rent(size);
|
||||
|
||||
Span<byte> tile = stackalloc byte[BlockWidth * BlockHeight * 4];
|
||||
|
||||
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);
|
||||
|
||||
|
@ -195,7 +197,7 @@ namespace Ryujinx.Graphics.Texture
|
|||
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;
|
||||
|
||||
|
@ -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<byte> output = ByteMemoryPool.Rent(size);
|
||||
|
||||
Span<byte> tile = stackalloc byte[BlockWidth * BlockHeight * 4];
|
||||
Span<byte> rPal = stackalloc byte[8];
|
||||
|
||||
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);
|
||||
|
||||
|
@ -292,7 +294,7 @@ namespace Ryujinx.Graphics.Texture
|
|||
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;
|
||||
|
||||
|
@ -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<byte> outputSpan = new(output);
|
||||
IMemoryOwner<byte> output = ByteMemoryPool.Rent(size);
|
||||
Span<byte> outputSpan = output.Memory.Span;
|
||||
|
||||
ReadOnlySpan<ulong> data64 = MemoryMarshal.Cast<byte, ulong>(data);
|
||||
|
||||
|
@ -400,7 +402,7 @@ namespace Ryujinx.Graphics.Texture
|
|||
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;
|
||||
|
||||
|
@ -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<byte> output = ByteMemoryPool.Rent(size);
|
||||
|
||||
ReadOnlySpan<ulong> data64 = MemoryMarshal.Cast<byte, ulong>(data);
|
||||
|
||||
|
@ -421,7 +423,7 @@ namespace Ryujinx.Graphics.Texture
|
|||
Span<byte> rPal = 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> gTileAsUint = MemoryMarshal.Cast<byte, uint>(gTile);
|
||||
|
@ -525,7 +527,7 @@ namespace Ryujinx.Graphics.Texture
|
|||
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;
|
||||
|
||||
|
@ -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<byte> output = ByteMemoryPool.Rent(size);
|
||||
Span<byte> 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<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;
|
||||
|
||||
|
@ -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<byte> output = ByteMemoryPool.Rent(size);
|
||||
Span<byte> 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;
|
||||
|
|
|
@ -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<byte> EncodeBC7(Memory<byte> 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<byte> output = ByteMemoryPool.Rent(size);
|
||||
Memory<byte> 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);
|
||||
|
|
|
@ -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<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);
|
||||
|
||||
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];
|
||||
|
||||
int imageBaseOOffs = 0;
|
||||
|
@ -111,15 +113,15 @@ namespace Ryujinx.Graphics.Texture
|
|||
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);
|
||||
|
||||
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];
|
||||
|
||||
int imageBaseOOffs = 0;
|
||||
|
@ -168,15 +170,15 @@ namespace Ryujinx.Graphics.Texture
|
|||
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);
|
||||
|
||||
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];
|
||||
|
||||
int imageBaseOOffs = 0;
|
||||
|
|
|
@ -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<byte> ConvertBlockLinearToLinear(
|
||||
int width,
|
||||
int height,
|
||||
int depth,
|
||||
|
@ -119,7 +121,8 @@ namespace Ryujinx.Graphics.Texture
|
|||
blockHeight,
|
||||
bytesPerPixel);
|
||||
|
||||
byte[] output = new byte[outSize];
|
||||
IMemoryOwner<byte> outputOwner = ByteMemoryPool.Rent(outSize);
|
||||
Span<byte> 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<byte> 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<byte> outSpan = output;
|
||||
IMemoryOwner<byte> output = ByteMemoryPool.Rent(h * outStride);
|
||||
Span<byte> outSpan = output.Memory.Span;
|
||||
|
||||
int outOffs = 0;
|
||||
int inOffs = 0;
|
||||
|
|
|
@ -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<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);
|
||||
|
||||
Span<ushort> outputSpan = MemoryMarshal.Cast<byte, ushort>(output);
|
||||
Span<ushort> outputSpan = MemoryMarshal.Cast<byte, ushort>(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)
|
||||
{
|
||||
|
@ -47,7 +49,7 @@ namespace Ryujinx.Graphics.Texture
|
|||
|
||||
for (int i = start; i < data.Length; i++)
|
||||
{
|
||||
outputSpan[i] = (ushort)data[i];
|
||||
outputSpan[i] = data[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -70,16 +72,16 @@ namespace Ryujinx.Graphics.Texture
|
|||
return output;
|
||||
}
|
||||
|
||||
public unsafe static byte[] ConvertR5G6B5ToR8G8B8A8(ReadOnlySpan<byte> data, int width)
|
||||
public 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 outOffset = 0;
|
||||
|
||||
(int remainder, int outRemainder, int height) = GetLineRemainders(data.Length, width, 2, 4);
|
||||
|
||||
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++)
|
||||
{
|
||||
|
@ -107,16 +109,16 @@ namespace Ryujinx.Graphics.Texture
|
|||
return output;
|
||||
}
|
||||
|
||||
public unsafe static byte[] ConvertR5G5B5ToR8G8B8A8(ReadOnlySpan<byte> data, int width, bool forceAlpha)
|
||||
public 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 outOffset = 0;
|
||||
|
||||
(int remainder, int outRemainder, int height) = GetLineRemainders(data.Length, width, 2, 4);
|
||||
|
||||
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++)
|
||||
{
|
||||
|
@ -144,16 +146,16 @@ namespace Ryujinx.Graphics.Texture
|
|||
return output;
|
||||
}
|
||||
|
||||
public unsafe static byte[] ConvertA1B5G5R5ToR8G8B8A8(ReadOnlySpan<byte> data, int width)
|
||||
public 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 outOffset = 0;
|
||||
|
||||
(int remainder, int outRemainder, int height) = GetLineRemainders(data.Length, width, 2, 4);
|
||||
|
||||
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++)
|
||||
{
|
||||
|
@ -181,16 +183,16 @@ namespace Ryujinx.Graphics.Texture
|
|||
return output;
|
||||
}
|
||||
|
||||
public unsafe static byte[] ConvertR4G4B4A4ToR8G8B8A8(ReadOnlySpan<byte> data, int width)
|
||||
public 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 outOffset = 0;
|
||||
|
||||
(int remainder, int outRemainder, int height) = GetLineRemainders(data.Length, width, 2, 4);
|
||||
|
||||
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++)
|
||||
{
|
||||
|
|
|
@ -3,6 +3,7 @@ using Ryujinx.Graphics.GAL;
|
|||
using Ryujinx.Graphics.Shader;
|
||||
using Silk.NET.Vulkan;
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using CompareOp = Ryujinx.Graphics.GAL.CompareOp;
|
||||
|
@ -216,7 +217,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
|
||||
public void Initialize()
|
||||
{
|
||||
Span<byte> dummyTextureData = stackalloc byte[4];
|
||||
IMemoryOwner<byte> dummyTextureData = ByteMemoryPool.RentCleared(4);
|
||||
_dummyTexture.SetData(dummyTextureData);
|
||||
}
|
||||
|
||||
|
|
|
@ -174,8 +174,8 @@ namespace Ryujinx.Graphics.Vulkan.Effects
|
|||
SwizzleComponent.Blue,
|
||||
SwizzleComponent.Alpha);
|
||||
|
||||
var areaTexture = EmbeddedResources.Read("Ryujinx.Graphics.Vulkan/Effects/Textures/SmaaAreaTexture.bin");
|
||||
var searchTexture = EmbeddedResources.Read("Ryujinx.Graphics.Vulkan/Effects/Textures/SmaaSearchTexture.bin");
|
||||
var areaTexture = EmbeddedResources.ReadFileToRentedMemory("Ryujinx.Graphics.Vulkan/Effects/Textures/SmaaAreaTexture.bin");
|
||||
var searchTexture = EmbeddedResources.ReadFileToRentedMemory("Ryujinx.Graphics.Vulkan/Effects/Textures/SmaaSearchTexture.bin");
|
||||
|
||||
_areaTexture = _renderer.CreateTexture(areaInfo) as TextureView;
|
||||
_searchTexture = _renderer.CreateTexture(searchInfo) as TextureView;
|
||||
|
|
|
@ -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;
|
||||
|
@ -94,17 +94,21 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
_bufferView = null;
|
||||
}
|
||||
|
||||
public void SetData(SpanOrArray<byte> data)
|
||||
/// <inheritdoc/>
|
||||
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)
|
||||
/// <inheritdoc/>
|
||||
public void SetData(IMemoryOwner<byte> data, int layer, int level)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public void SetData(SpanOrArray<byte> data, int layer, int level, Rectangle<int> region)
|
||||
/// <inheritdoc/>
|
||||
public void SetData(IMemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
@ -702,19 +702,25 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
return GetDataFromBuffer(result, size, result);
|
||||
}
|
||||
|
||||
public void SetData(SpanOrArray<byte> data)
|
||||
/// <inheritdoc/>
|
||||
public void SetData(IMemoryOwner<byte> data)
|
||||
{
|
||||
SetData(data, 0, 0, Info.GetLayers(), Info.Levels, singleSlice: false);
|
||||
SetData(data.Memory.Span, 0, 0, Info.GetLayers(), Info.Levels, singleSlice: false);
|
||||
data.Dispose();
|
||||
}
|
||||
|
||||
public void SetData(SpanOrArray<byte> data, int layer, int level)
|
||||
/// <inheritdoc/>
|
||||
public void SetData(IMemoryOwner<byte> data, int layer, int level)
|
||||
{
|
||||
SetData(data, layer, level, 1, 1, singleSlice: true);
|
||||
SetData(data.Memory.Span, layer, level, 1, 1, singleSlice: true);
|
||||
data.Dispose();
|
||||
}
|
||||
|
||||
public void SetData(SpanOrArray<byte> data, int layer, int level, Rectangle<int> region)
|
||||
/// <inheritdoc/>
|
||||
public void SetData(IMemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
|
||||
{
|
||||
SetData(data, layer, level, 1, 1, singleSlice: true, 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)
|
||||
|
|
|
@ -330,6 +330,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
_swapchainIsDirty)
|
||||
{
|
||||
RecreateSwapchain();
|
||||
semaphoreIndex = (_frameIndex - 1) % _imageAvailableSemaphores.Length;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -440,8 +440,9 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
|||
|
||||
// If we are here, that mean nothing was available, sleep for 50ms
|
||||
context.Device.System.KernelContext.Syscall.SleepThread(50 * 1000000);
|
||||
context.Thread.HandlePostSyscall();
|
||||
}
|
||||
while (PerformanceCounter.ElapsedMilliseconds < budgetLeftMilliseconds);
|
||||
while (context.Thread.Context.Running && PerformanceCounter.ElapsedMilliseconds < budgetLeftMilliseconds);
|
||||
}
|
||||
else if (timeout == -1)
|
||||
{
|
||||
|
|
|
@ -245,9 +245,9 @@ namespace Ryujinx.Input.HLE
|
|||
{
|
||||
if (config is StandardControllerInputConfig controllerConfig)
|
||||
{
|
||||
bool needsMotionInputUpdate = _config == null || (_config is StandardControllerInputConfig oldControllerConfig &&
|
||||
(oldControllerConfig.Motion.EnableMotion != controllerConfig.Motion.EnableMotion) &&
|
||||
(oldControllerConfig.Motion.MotionBackend != controllerConfig.Motion.MotionBackend));
|
||||
bool needsMotionInputUpdate = _config is not StandardControllerInputConfig oldControllerConfig ||
|
||||
((oldControllerConfig.Motion.EnableMotion != controllerConfig.Motion.EnableMotion) &&
|
||||
(oldControllerConfig.Motion.MotionBackend != controllerConfig.Motion.MotionBackend));
|
||||
|
||||
if (needsMotionInputUpdate)
|
||||
{
|
||||
|
|
|
@ -112,6 +112,7 @@ namespace Ryujinx.Ava
|
|||
private readonly object _lockObject = new();
|
||||
|
||||
public event EventHandler AppExit;
|
||||
public event EventHandler<StatusInitEventArgs> StatusInitEvent;
|
||||
public event EventHandler<StatusUpdatedEventArgs> StatusUpdatedEvent;
|
||||
|
||||
public VirtualFileSystem VirtualFileSystem { get; }
|
||||
|
@ -947,6 +948,7 @@ namespace Ryujinx.Ava
|
|||
{
|
||||
_renderingStarted = true;
|
||||
_viewModel.SwitchToRenderer(false);
|
||||
InitStatus();
|
||||
}
|
||||
|
||||
Device.PresentFrame(() => (RendererHost.EmbeddedWindow as EmbeddedWindowOpenGL)?.SwapBuffers());
|
||||
|
@ -970,6 +972,18 @@ namespace Ryujinx.Ava
|
|||
(RendererHost.EmbeddedWindow as EmbeddedWindowOpenGL)?.MakeCurrent(true);
|
||||
}
|
||||
|
||||
public void InitStatus()
|
||||
{
|
||||
StatusInitEvent?.Invoke(this, new StatusInitEventArgs(
|
||||
ConfigurationState.Instance.Graphics.GraphicsBackend.Value switch
|
||||
{
|
||||
GraphicsBackend.Vulkan => "Vulkan",
|
||||
GraphicsBackend.OpenGl => "OpenGL",
|
||||
_ => throw new NotImplementedException()
|
||||
},
|
||||
$"GPU: {_renderer.GetHardwareInfo().GpuDriver}"));
|
||||
}
|
||||
|
||||
public void UpdateStatus()
|
||||
{
|
||||
// Run a status update only when a frame is to be drawn. This prevents from updating the ui and wasting a render when no frame is queued.
|
||||
|
@ -983,12 +997,10 @@ namespace Ryujinx.Ava
|
|||
StatusUpdatedEvent?.Invoke(this, new StatusUpdatedEventArgs(
|
||||
Device.EnableDeviceVsync,
|
||||
LocaleManager.Instance[LocaleKeys.VolumeShort] + $": {(int)(Device.GetVolume() * 100)}%",
|
||||
ConfigurationState.Instance.Graphics.GraphicsBackend.Value == GraphicsBackend.Vulkan ? "Vulkan" : "OpenGL",
|
||||
dockedMode,
|
||||
ConfigurationState.Instance.Graphics.AspectRatio.Value.ToText(),
|
||||
LocaleManager.Instance[LocaleKeys.Game] + $": {Device.Statistics.GetGameFrameRate():00.00} FPS ({Device.Statistics.GetGameFrameTime():00.00} ms)",
|
||||
$"FIFO: {Device.Statistics.GetFifoPercent():00.00} %",
|
||||
$"GPU: {_renderer.GetHardwareInfo().GpuDriver}"));
|
||||
$"FIFO: {Device.Statistics.GetFifoPercent():00.00} %"));
|
||||
}
|
||||
|
||||
public async Task ShowExitPrompt()
|
||||
|
|
16
src/Ryujinx/UI/Models/StatusInitEventArgs.cs
Normal file
16
src/Ryujinx/UI/Models/StatusInitEventArgs.cs
Normal file
|
@ -0,0 +1,16 @@
|
|||
using System;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Models
|
||||
{
|
||||
internal class StatusInitEventArgs : EventArgs
|
||||
{
|
||||
public string GpuBackend { get; }
|
||||
public string GpuName { get; }
|
||||
|
||||
public StatusInitEventArgs(string gpuBackend, string gpuName)
|
||||
{
|
||||
GpuBackend = gpuBackend;
|
||||
GpuName = gpuName;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,23 +6,19 @@ namespace Ryujinx.Ava.UI.Models
|
|||
{
|
||||
public bool VSyncEnabled { get; }
|
||||
public string VolumeStatus { get; }
|
||||
public string GpuBackend { get; }
|
||||
public string AspectRatio { get; }
|
||||
public string DockedMode { get; }
|
||||
public string FifoStatus { get; }
|
||||
public string GameStatus { get; }
|
||||
public string GpuName { get; }
|
||||
|
||||
public StatusUpdatedEventArgs(bool vSyncEnabled, string volumeStatus, string gpuBackend, string dockedMode, string aspectRatio, string gameStatus, string fifoStatus, string gpuName)
|
||||
public StatusUpdatedEventArgs(bool vSyncEnabled, string volumeStatus, string dockedMode, string aspectRatio, string gameStatus, string fifoStatus)
|
||||
{
|
||||
VSyncEnabled = vSyncEnabled;
|
||||
VolumeStatus = volumeStatus;
|
||||
GpuBackend = gpuBackend;
|
||||
DockedMode = dockedMode;
|
||||
AspectRatio = aspectRatio;
|
||||
GameStatus = gameStatus;
|
||||
FifoStatus = fifoStatus;
|
||||
GpuName = gpuName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1172,6 +1172,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||
{
|
||||
RendererHostControl.WindowCreated += RendererHost_Created;
|
||||
|
||||
AppHost.StatusInitEvent += Init_StatusBar;
|
||||
AppHost.StatusUpdatedEvent += Update_StatusBar;
|
||||
AppHost.AppExit += AppHost_AppExit;
|
||||
|
||||
|
@ -1198,6 +1199,18 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||
}
|
||||
}
|
||||
|
||||
private void Init_StatusBar(object sender, StatusInitEventArgs args)
|
||||
{
|
||||
if (ShowMenuAndStatusBar && !ShowLoadProgress)
|
||||
{
|
||||
Dispatcher.UIThread.InvokeAsync(() =>
|
||||
{
|
||||
GpuNameText = args.GpuName;
|
||||
BackendText = args.GpuBackend;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void Update_StatusBar(object sender, StatusUpdatedEventArgs args)
|
||||
{
|
||||
if (ShowMenuAndStatusBar && !ShowLoadProgress)
|
||||
|
@ -1220,8 +1233,6 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||
GameStatusText = args.GameStatus;
|
||||
VolumeStatusText = args.VolumeStatus;
|
||||
FifoStatusText = args.FifoStatus;
|
||||
GpuNameText = args.GpuName;
|
||||
BackendText = args.GpuBackend;
|
||||
|
||||
ShowStatusSeparator = true;
|
||||
});
|
||||
|
|
Loading…
Add table
Reference in a new issue