Compare commits
6 Commits
Author | SHA1 | Date | |
---|---|---|---|
4dd77316f7 | |||
3f98369a17 | |||
c26aeefe03 | |||
666e05f5cb | |||
8d9d508dc7 | |||
e27f5522e2 |
@ -11,6 +11,7 @@ using Ryujinx.Audio.Renderer.Server.Voice;
|
|||||||
using Ryujinx.Audio.Renderer.Utils;
|
using Ryujinx.Audio.Renderer.Utils;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Buffers;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
@ -149,12 +150,16 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
state.InUse = false;
|
state.InUse = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Memory<VoiceUpdateState>[] voiceUpdateStatesArray = ArrayPool<Memory<VoiceUpdateState>>.Shared.Rent(Constants.VoiceChannelCountMax);
|
||||||
|
|
||||||
|
Span<Memory<VoiceUpdateState>> voiceUpdateStates = voiceUpdateStatesArray.AsSpan(0, Constants.VoiceChannelCountMax);
|
||||||
|
|
||||||
// Start processing
|
// Start processing
|
||||||
for (int i = 0; i < context.GetCount(); i++)
|
for (int i = 0; i < context.GetCount(); i++)
|
||||||
{
|
{
|
||||||
VoiceInParameter parameter = parameters[i];
|
VoiceInParameter parameter = parameters[i];
|
||||||
|
|
||||||
Memory<VoiceUpdateState>[] voiceUpdateStates = new Memory<VoiceUpdateState>[Constants.VoiceChannelCountMax];
|
voiceUpdateStates.Fill(Memory<VoiceUpdateState>.Empty);
|
||||||
|
|
||||||
ref VoiceOutStatus outStatus = ref SpanIOHelper.GetWriteRef<VoiceOutStatus>(ref _output)[0];
|
ref VoiceOutStatus outStatus = ref SpanIOHelper.GetWriteRef<VoiceOutStatus>(ref _output)[0];
|
||||||
|
|
||||||
@ -197,6 +202,8 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ArrayPool<Memory<VoiceUpdateState>>.Shared.Return(voiceUpdateStatesArray);
|
||||||
|
|
||||||
int currentOutputSize = _output.Length;
|
int currentOutputSize = _output.Length;
|
||||||
|
|
||||||
OutputHeader.VoicesSize = (uint)(Unsafe.SizeOf<VoiceOutStatus>() * context.GetCount());
|
OutputHeader.VoicesSize = (uint)(Unsafe.SizeOf<VoiceOutStatus>() * context.GetCount());
|
||||||
|
@ -378,7 +378,7 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
|
|||||||
/// <param name="outStatus">The given user output.</param>
|
/// <param name="outStatus">The given user output.</param>
|
||||||
/// <param name="parameter">The user parameter.</param>
|
/// <param name="parameter">The user parameter.</param>
|
||||||
/// <param name="voiceUpdateStates">The voice states associated to the <see cref="VoiceState"/>.</param>
|
/// <param name="voiceUpdateStates">The voice states associated to the <see cref="VoiceState"/>.</param>
|
||||||
public void WriteOutStatus(ref VoiceOutStatus outStatus, ref VoiceInParameter parameter, Memory<VoiceUpdateState>[] voiceUpdateStates)
|
public void WriteOutStatus(ref VoiceOutStatus outStatus, ref VoiceInParameter parameter, ReadOnlySpan<Memory<VoiceUpdateState>> voiceUpdateStates)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
// Sanity check in debug mode of the internal state
|
// Sanity check in debug mode of the internal state
|
||||||
@ -424,7 +424,7 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
|
|||||||
/// <param name="voiceUpdateStates">The voice states associated to the <see cref="VoiceState"/>.</param>
|
/// <param name="voiceUpdateStates">The voice states associated to the <see cref="VoiceState"/>.</param>
|
||||||
/// <param name="mapper">The mapper to use.</param>
|
/// <param name="mapper">The mapper to use.</param>
|
||||||
/// <param name="behaviourContext">The behaviour context.</param>
|
/// <param name="behaviourContext">The behaviour context.</param>
|
||||||
public void UpdateWaveBuffers(out ErrorInfo[] errorInfos, ref VoiceInParameter parameter, Memory<VoiceUpdateState>[] voiceUpdateStates, ref PoolMapper mapper, ref BehaviourContext behaviourContext)
|
public void UpdateWaveBuffers(out ErrorInfo[] errorInfos, ref VoiceInParameter parameter, ReadOnlySpan<Memory<VoiceUpdateState>> voiceUpdateStates, ref PoolMapper mapper, ref BehaviourContext behaviourContext)
|
||||||
{
|
{
|
||||||
errorInfos = new ErrorInfo[Constants.VoiceWaveBufferCount * 2];
|
errorInfos = new ErrorInfo[Constants.VoiceWaveBufferCount * 2];
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ using Ryujinx.Ava.UI.Helpers;
|
|||||||
using Ryujinx.Ava.UI.Windows;
|
using Ryujinx.Ava.UI.Windows;
|
||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Common.Utilities;
|
using Ryujinx.Common.Utilities;
|
||||||
using Ryujinx.Ui.Common.Models.Amiibo;
|
using Ryujinx.Ui.Common.Models.Amiibo;
|
||||||
using System;
|
using System;
|
||||||
@ -42,13 +43,18 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
private bool _showAllAmiibo;
|
private bool _showAllAmiibo;
|
||||||
private bool _useRandomUuid;
|
private bool _useRandomUuid;
|
||||||
private string _usage;
|
private string _usage;
|
||||||
|
|
||||||
private static readonly AmiiboJsonSerializerContext SerializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
private static readonly AmiiboJsonSerializerContext SerializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
||||||
|
|
||||||
public AmiiboWindowViewModel(StyleableWindow owner, string lastScannedAmiiboId, string titleId)
|
public AmiiboWindowViewModel(StyleableWindow owner, string lastScannedAmiiboId, string titleId)
|
||||||
{
|
{
|
||||||
_owner = owner;
|
_owner = owner;
|
||||||
_httpClient = new HttpClient { Timeout = TimeSpan.FromMilliseconds(5000) };
|
|
||||||
|
_httpClient = new HttpClient
|
||||||
|
{
|
||||||
|
Timeout = TimeSpan.FromSeconds(30)
|
||||||
|
};
|
||||||
|
|
||||||
LastScannedAmiiboId = lastScannedAmiiboId;
|
LastScannedAmiiboId = lastScannedAmiiboId;
|
||||||
TitleId = titleId;
|
TitleId = titleId;
|
||||||
|
|
||||||
@ -89,9 +95,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
{
|
{
|
||||||
_showAllAmiibo = value;
|
_showAllAmiibo = value;
|
||||||
|
|
||||||
#pragma warning disable 4014
|
|
||||||
ParseAmiiboData();
|
ParseAmiiboData();
|
||||||
#pragma warning restore 4014
|
|
||||||
|
|
||||||
OnPropertyChanged();
|
OnPropertyChanged();
|
||||||
}
|
}
|
||||||
@ -203,8 +207,10 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
{
|
{
|
||||||
amiiboJsonString = await DownloadAmiiboJson();
|
amiiboJsonString = await DownloadAmiiboJson();
|
||||||
}
|
}
|
||||||
catch
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
Logger.Error?.Print(LogClass.Application, $"Failed to download amiibo data: {ex}");
|
||||||
|
|
||||||
ShowInfoDialog();
|
ShowInfoDialog();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -369,8 +375,10 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
catch
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
Logger.Error?.Print(LogClass.Application, $"Failed to check for amiibo updates: {ex}");
|
||||||
|
|
||||||
ShowInfoDialog();
|
ShowInfoDialog();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -393,6 +401,8 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
return amiiboJsonString;
|
return amiiboJsonString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Logger.Error?.Print(LogClass.Application, $"Failed to download amiibo data. Response status code: {response.StatusCode}");
|
||||||
|
|
||||||
await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance[LocaleKeys.DialogAmiiboApiTitle],
|
await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance[LocaleKeys.DialogAmiiboApiTitle],
|
||||||
LocaleManager.Instance[LocaleKeys.DialogAmiiboApiFailFetchMessage],
|
LocaleManager.Instance[LocaleKeys.DialogAmiiboApiFailFetchMessage],
|
||||||
LocaleManager.Instance[LocaleKeys.InputDialogOk],
|
LocaleManager.Instance[LocaleKeys.InputDialogOk],
|
||||||
@ -429,6 +439,10 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
AmiiboImage = bitmap.CreateScaledBitmap(new PixelSize(resizeWidth, resizeHeight));
|
AmiiboImage = bitmap.CreateScaledBitmap(new PixelSize(resizeWidth, resizeHeight));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logger.Error?.Print(LogClass.Application, $"Failed to get amiibo preview. Response status code: {response.StatusCode}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ResetAmiiboPreview()
|
private void ResetAmiiboPreview()
|
||||||
|
51
Ryujinx.Common/Memory/ByteMemoryPool.ByteMemoryPoolBuffer.cs
Normal file
51
Ryujinx.Common/Memory/ByteMemoryPool.ByteMemoryPoolBuffer.cs
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
using System;
|
||||||
|
using System.Buffers;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace Ryujinx.Common.Memory
|
||||||
|
{
|
||||||
|
public sealed partial class ByteMemoryPool
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a <see cref="IMemoryOwner{Byte}"/> that wraps an array rented from
|
||||||
|
/// <see cref="ArrayPool{Byte}.Shared"/> and exposes it as <see cref="Memory{Byte}"/>
|
||||||
|
/// with a length of the requested size.
|
||||||
|
/// </summary>
|
||||||
|
private sealed class ByteMemoryPoolBuffer : IMemoryOwner<byte>
|
||||||
|
{
|
||||||
|
private byte[] _array;
|
||||||
|
private readonly int _length;
|
||||||
|
|
||||||
|
public ByteMemoryPoolBuffer(int length)
|
||||||
|
{
|
||||||
|
_array = ArrayPool<byte>.Shared.Rent(length);
|
||||||
|
_length = length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a <see cref="Memory{Byte}"/> belonging to this owner.
|
||||||
|
/// </summary>
|
||||||
|
public Memory<byte> Memory
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
byte[] array = _array;
|
||||||
|
|
||||||
|
ObjectDisposedException.ThrowIf(array is null, this);
|
||||||
|
|
||||||
|
return new Memory<byte>(array, 0, _length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
var array = Interlocked.Exchange(ref _array, null);
|
||||||
|
|
||||||
|
if (array != null)
|
||||||
|
{
|
||||||
|
ArrayPool<byte>.Shared.Return(array);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
108
Ryujinx.Common/Memory/ByteMemoryPool.cs
Normal file
108
Ryujinx.Common/Memory/ByteMemoryPool.cs
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
using System;
|
||||||
|
using System.Buffers;
|
||||||
|
|
||||||
|
namespace Ryujinx.Common.Memory
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides a pool of re-usable byte array instances.
|
||||||
|
/// </summary>
|
||||||
|
public sealed partial class ByteMemoryPool
|
||||||
|
{
|
||||||
|
private static readonly ByteMemoryPool _shared = new ByteMemoryPool();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructs a <see cref="ByteMemoryPool"/> instance. Private to force access through
|
||||||
|
/// the <see cref="ByteMemoryPool.Shared"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
private ByteMemoryPool()
|
||||||
|
{
|
||||||
|
// No implementation
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves a shared <see cref="ByteMemoryPool"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
public static ByteMemoryPool Shared => _shared;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the maximum buffer size supported by this pool.
|
||||||
|
/// </summary>
|
||||||
|
public int MaxBufferSize => Array.MaxLength;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rents a byte memory buffer from <see cref="ArrayPool{Byte}.Shared"/>.
|
||||||
|
/// The buffer may contain data from a prior use.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="length">The buffer's required length in bytes</param>
|
||||||
|
/// <returns>A <see cref="IMemoryOwner{Byte}"/> wrapping the rented memory</returns>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||||
|
public IMemoryOwner<byte> Rent(long length)
|
||||||
|
=> RentImpl(checked((int)length));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rents a byte memory buffer from <see cref="ArrayPool{Byte}.Shared"/>.
|
||||||
|
/// The buffer may contain data from a prior use.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="length">The buffer's required length in bytes</param>
|
||||||
|
/// <returns>A <see cref="IMemoryOwner{Byte}"/> wrapping the rented memory</returns>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||||
|
public IMemoryOwner<byte> Rent(ulong length)
|
||||||
|
=> RentImpl(checked((int)length));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rents a byte memory buffer from <see cref="ArrayPool{Byte}.Shared"/>.
|
||||||
|
/// The buffer may contain data from a prior use.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="length">The buffer's required length in bytes</param>
|
||||||
|
/// <returns>A <see cref="IMemoryOwner{Byte}"/> wrapping the rented memory</returns>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||||
|
public IMemoryOwner<byte> Rent(int length)
|
||||||
|
=> RentImpl(length);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rents a byte memory buffer from <see cref="ArrayPool{Byte}.Shared"/>.
|
||||||
|
/// The buffer's contents are cleared (set to all 0s) before returning.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="length">The buffer's required length in bytes</param>
|
||||||
|
/// <returns>A <see cref="IMemoryOwner{Byte}"/> wrapping the rented memory</returns>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||||
|
public IMemoryOwner<byte> RentCleared(long length)
|
||||||
|
=> RentCleared(checked((int)length));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rents a byte memory buffer from <see cref="ArrayPool{Byte}.Shared"/>.
|
||||||
|
/// The buffer's contents are cleared (set to all 0s) before returning.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="length">The buffer's required length in bytes</param>
|
||||||
|
/// <returns>A <see cref="IMemoryOwner{Byte}"/> wrapping the rented memory</returns>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||||
|
public IMemoryOwner<byte> RentCleared(ulong length)
|
||||||
|
=> RentCleared(checked((int)length));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rents a byte memory buffer from <see cref="ArrayPool{Byte}.Shared"/>.
|
||||||
|
/// The buffer's contents are cleared (set to all 0s) before returning.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="length">The buffer's required length in bytes</param>
|
||||||
|
/// <returns>A <see cref="IMemoryOwner{Byte}"/> wrapping the rented memory</returns>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||||
|
public IMemoryOwner<byte> RentCleared(int length)
|
||||||
|
{
|
||||||
|
var buffer = RentImpl(length);
|
||||||
|
|
||||||
|
buffer.Memory.Span.Clear();
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ByteMemoryPoolBuffer RentImpl(int length)
|
||||||
|
{
|
||||||
|
if ((uint)length > Array.MaxLength)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(length), length, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ByteMemoryPoolBuffer(length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -48,6 +48,8 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
public readonly float MaximumSupportedAnisotropy;
|
public readonly float MaximumSupportedAnisotropy;
|
||||||
public readonly int StorageBufferOffsetAlignment;
|
public readonly int StorageBufferOffsetAlignment;
|
||||||
|
|
||||||
|
public readonly int GatherBiasPrecision;
|
||||||
|
|
||||||
public Capabilities(
|
public Capabilities(
|
||||||
TargetApi api,
|
TargetApi api,
|
||||||
string vendorName,
|
string vendorName,
|
||||||
@ -87,7 +89,8 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
uint maximumImagesPerStage,
|
uint maximumImagesPerStage,
|
||||||
int maximumComputeSharedMemorySize,
|
int maximumComputeSharedMemorySize,
|
||||||
float maximumSupportedAnisotropy,
|
float maximumSupportedAnisotropy,
|
||||||
int storageBufferOffsetAlignment)
|
int storageBufferOffsetAlignment,
|
||||||
|
int gatherBiasPrecision)
|
||||||
{
|
{
|
||||||
Api = api;
|
Api = api;
|
||||||
VendorName = vendorName;
|
VendorName = vendorName;
|
||||||
@ -128,6 +131,7 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
MaximumComputeSharedMemorySize = maximumComputeSharedMemorySize;
|
MaximumComputeSharedMemorySize = maximumComputeSharedMemorySize;
|
||||||
MaximumSupportedAnisotropy = maximumSupportedAnisotropy;
|
MaximumSupportedAnisotropy = maximumSupportedAnisotropy;
|
||||||
StorageBufferOffsetAlignment = storageBufferOffsetAlignment;
|
StorageBufferOffsetAlignment = storageBufferOffsetAlignment;
|
||||||
|
GatherBiasPrecision = gatherBiasPrecision;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
|||||||
private const ushort FileFormatVersionMajor = 1;
|
private const ushort FileFormatVersionMajor = 1;
|
||||||
private const ushort FileFormatVersionMinor = 2;
|
private const ushort FileFormatVersionMinor = 2;
|
||||||
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
|
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
|
||||||
private const uint CodeGenVersion = 4404;
|
private const uint CodeGenVersion = 4707;
|
||||||
|
|
||||||
private const string SharedTocFileName = "shared.toc";
|
private const string SharedTocFileName = "shared.toc";
|
||||||
private const string SharedDataFileName = "shared.data";
|
private const string SharedDataFileName = "shared.data";
|
||||||
|
@ -112,6 +112,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int QueryHostGatherBiasPrecision() => _context.Capabilities.GatherBiasPrecision;
|
||||||
|
|
||||||
public bool QueryHostReducedPrecision() => _context.Capabilities.ReduceShaderPrecision;
|
public bool QueryHostReducedPrecision() => _context.Capabilities.ReduceShaderPrecision;
|
||||||
|
|
||||||
public bool QueryHostHasFrontFacingBug() => _context.Capabilities.HasFrontFacingBug;
|
public bool QueryHostHasFrontFacingBug() => _context.Capabilities.HasFrontFacingBug;
|
||||||
|
@ -449,7 +449,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
if (translatorContexts[i] != null)
|
if (translatorContexts[i] != null)
|
||||||
{
|
{
|
||||||
translatorContexts[i].SetGeometryShaderLayerInputAttribute(info.GpLayerInputAttribute);
|
translatorContexts[i].SetGeometryShaderLayerInputAttribute(info.GpLayerInputAttribute);
|
||||||
translatorContexts[i].SetLastInVertexPipeline(translatorContexts[5] != null);
|
translatorContexts[i].SetLastInVertexPipeline();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -103,11 +103,14 @@ namespace Ryujinx.Graphics.OpenGL
|
|||||||
|
|
||||||
public Capabilities GetCapabilities()
|
public Capabilities GetCapabilities()
|
||||||
{
|
{
|
||||||
|
bool intelWindows = HwCapabilities.Vendor == HwCapabilities.GpuVendor.IntelWindows;
|
||||||
|
bool amdWindows = HwCapabilities.Vendor == HwCapabilities.GpuVendor.AmdWindows;
|
||||||
|
|
||||||
return new Capabilities(
|
return new Capabilities(
|
||||||
api: TargetApi.OpenGL,
|
api: TargetApi.OpenGL,
|
||||||
vendorName: GpuVendor,
|
vendorName: GpuVendor,
|
||||||
hasFrontFacingBug: HwCapabilities.Vendor == HwCapabilities.GpuVendor.IntelWindows,
|
hasFrontFacingBug: intelWindows,
|
||||||
hasVectorIndexingBug: HwCapabilities.Vendor == HwCapabilities.GpuVendor.AmdWindows,
|
hasVectorIndexingBug: amdWindows,
|
||||||
needsFragmentOutputSpecialization: false,
|
needsFragmentOutputSpecialization: false,
|
||||||
reduceShaderPrecision: false,
|
reduceShaderPrecision: false,
|
||||||
supportsAstcCompression: HwCapabilities.SupportsAstcCompression,
|
supportsAstcCompression: HwCapabilities.SupportsAstcCompression,
|
||||||
@ -142,7 +145,8 @@ namespace Ryujinx.Graphics.OpenGL
|
|||||||
maximumImagesPerStage: 8,
|
maximumImagesPerStage: 8,
|
||||||
maximumComputeSharedMemorySize: HwCapabilities.MaximumComputeSharedMemorySize,
|
maximumComputeSharedMemorySize: HwCapabilities.MaximumComputeSharedMemorySize,
|
||||||
maximumSupportedAnisotropy: HwCapabilities.MaximumSupportedAnisotropy,
|
maximumSupportedAnisotropy: HwCapabilities.MaximumSupportedAnisotropy,
|
||||||
storageBufferOffsetAlignment: HwCapabilities.StorageBufferOffsetAlignment);
|
storageBufferOffsetAlignment: HwCapabilities.StorageBufferOffsetAlignment,
|
||||||
|
gatherBiasPrecision: intelWindows || amdWindows ? 8 : 0); // Precision is 8 for these vendors on Vulkan.
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetBufferData(BufferHandle buffer, int offset, ReadOnlySpan<byte> data)
|
public void SetBufferData(BufferHandle buffer, int offset, ReadOnlySpan<byte> data)
|
||||||
|
@ -569,7 +569,23 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||||||
|
|
||||||
if (context.Config.TransformFeedbackEnabled && context.Config.Stage == ShaderStage.Fragment)
|
if (context.Config.TransformFeedbackEnabled && context.Config.Stage == ShaderStage.Fragment)
|
||||||
{
|
{
|
||||||
for (int c = 0; c < 4; c++)
|
int attrOffset = AttributeConsts.UserAttributeBase + attr * 16;
|
||||||
|
int components = context.Info.GetTransformFeedbackOutputComponents(attrOffset);
|
||||||
|
|
||||||
|
if (components > 1)
|
||||||
|
{
|
||||||
|
string type = components switch
|
||||||
|
{
|
||||||
|
2 => "vec2",
|
||||||
|
3 => "vec3",
|
||||||
|
4 => "vec4",
|
||||||
|
_ => "float"
|
||||||
|
};
|
||||||
|
|
||||||
|
context.AppendLine($"layout (location = {attr}) in {type} {name};");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int c = components > 1 ? components : 0; c < 4; c++)
|
||||||
{
|
{
|
||||||
char swzMask = "xyzw"[c];
|
char swzMask = "xyzw"[c];
|
||||||
|
|
||||||
@ -642,7 +658,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||||||
if (context.Config.TransformFeedbackEnabled && context.Config.LastInVertexPipeline)
|
if (context.Config.TransformFeedbackEnabled && context.Config.LastInVertexPipeline)
|
||||||
{
|
{
|
||||||
int attrOffset = AttributeConsts.UserAttributeBase + attr * 16;
|
int attrOffset = AttributeConsts.UserAttributeBase + attr * 16;
|
||||||
int components = context.Config.LastInPipeline ? context.Info.GetTransformFeedbackOutputComponents(attrOffset) : 1;
|
int components = context.Info.GetTransformFeedbackOutputComponents(attrOffset);
|
||||||
|
|
||||||
if (components > 1)
|
if (components > 1)
|
||||||
{
|
{
|
||||||
@ -664,22 +680,20 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||||||
|
|
||||||
context.AppendLine($"layout (location = {attr}{xfb}) out {type} {name};");
|
context.AppendLine($"layout (location = {attr}{xfb}) out {type} {name};");
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
for (int c = components > 1 ? components : 0; c < 4; c++)
|
||||||
{
|
{
|
||||||
for (int c = 0; c < 4; c++)
|
char swzMask = "xyzw"[c];
|
||||||
|
|
||||||
|
string xfb = string.Empty;
|
||||||
|
|
||||||
|
var tfOutput = context.Info.GetTransformFeedbackOutput(attrOffset + c * 4);
|
||||||
|
if (tfOutput.Valid)
|
||||||
{
|
{
|
||||||
char swzMask = "xyzw"[c];
|
xfb = $", xfb_buffer = {tfOutput.Buffer}, xfb_offset = {tfOutput.Offset}, xfb_stride = {tfOutput.Stride}";
|
||||||
|
|
||||||
string xfb = string.Empty;
|
|
||||||
|
|
||||||
var tfOutput = context.Info.GetTransformFeedbackOutput(attrOffset + c * 4);
|
|
||||||
if (tfOutput.Valid)
|
|
||||||
{
|
|
||||||
xfb = $", xfb_buffer = {tfOutput.Buffer}, xfb_offset = {tfOutput.Offset}, xfb_stride = {tfOutput.Stride}";
|
|
||||||
}
|
|
||||||
|
|
||||||
context.AppendLine($"layout (location = {attr}, component = {c}{xfb}) out float {name}_{swzMask};");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
context.AppendLine($"layout (location = {attr}, component = {c}{xfb}) out float {name}_{swzMask};");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -677,7 +677,28 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
|||||||
return vector;
|
return vector;
|
||||||
}
|
}
|
||||||
|
|
||||||
Append(ApplyScaling(AssemblePVector(pCount)));
|
string ApplyBias(string vector)
|
||||||
|
{
|
||||||
|
int gatherBiasPrecision = context.Config.GpuAccessor.QueryHostGatherBiasPrecision();
|
||||||
|
if (isGather && gatherBiasPrecision != 0)
|
||||||
|
{
|
||||||
|
// GPU requires texture gather to be slightly offset to match NVIDIA behaviour when point is exactly between two texels.
|
||||||
|
// Offset by the gather precision divided by 2 to correct for rounding.
|
||||||
|
|
||||||
|
if (pCount == 1)
|
||||||
|
{
|
||||||
|
vector = $"{vector} + (1.0 / (float(textureSize({samplerName}, 0)) * float({1 << (gatherBiasPrecision + 1)})))";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vector = $"{vector} + (1.0 / (vec{pCount}(textureSize({samplerName}, 0).{"xyz".Substring(0, pCount)}) * float({1 << (gatherBiasPrecision + 1)})))";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return vector;
|
||||||
|
}
|
||||||
|
|
||||||
|
Append(ApplyBias(ApplyScaling(AssemblePVector(pCount))));
|
||||||
|
|
||||||
string AssembleDerivativesVector(int count)
|
string AssembleDerivativesVector(int count)
|
||||||
{
|
{
|
||||||
|
@ -220,7 +220,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||||||
((config.LastInVertexPipeline && isOutAttr) ||
|
((config.LastInVertexPipeline && isOutAttr) ||
|
||||||
(config.Stage == ShaderStage.Fragment && !isOutAttr)))
|
(config.Stage == ShaderStage.Fragment && !isOutAttr)))
|
||||||
{
|
{
|
||||||
int components = config.LastInPipeline ? context.Info.GetTransformFeedbackOutputComponents(attrOffset) : 1;
|
int components = context.Info.GetTransformFeedbackOutputComponents(attrOffset);
|
||||||
string name = components > 1 ? $"{prefix}{(value >> 4)}" : $"{prefix}{(value >> 4)}_{swzMask}";
|
string name = components > 1 ? $"{prefix}{(value >> 4)}" : $"{prefix}{(value >> 4)}_{swzMask}";
|
||||||
|
|
||||||
if (AttributeInfo.IsArrayAttributeGlsl(config.Stage, isOutAttr))
|
if (AttributeInfo.IsArrayAttributeGlsl(config.Stage, isOutAttr))
|
||||||
|
@ -341,7 +341,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
attrOffset = attr;
|
attrOffset = attr;
|
||||||
type = elemType;
|
type = elemType;
|
||||||
|
|
||||||
if (Config.LastInPipeline && isOutAttr)
|
if (isOutAttr)
|
||||||
{
|
{
|
||||||
int components = Info.GetTransformFeedbackOutputComponents(attr);
|
int components = Info.GetTransformFeedbackOutputComponents(attr);
|
||||||
|
|
||||||
|
@ -673,7 +673,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
int components = 1;
|
int components = 1;
|
||||||
var type = attrInfo.Type & AggregateType.ElementTypeMask;
|
var type = attrInfo.Type & AggregateType.ElementTypeMask;
|
||||||
|
|
||||||
if (context.Config.LastInPipeline && isOutAttr)
|
if (isOutAttr)
|
||||||
{
|
{
|
||||||
components = context.Info.GetTransformFeedbackOutputComponents(attr);
|
components = context.Info.GetTransformFeedbackOutputComponents(attr);
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ using Ryujinx.Graphics.Shader.Translation;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using static Spv.Specification;
|
using static Spv.Specification;
|
||||||
|
|
||||||
@ -1556,6 +1557,33 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SpvInstruction ApplyBias(SpvInstruction vector, SpvInstruction image)
|
||||||
|
{
|
||||||
|
int gatherBiasPrecision = context.Config.GpuAccessor.QueryHostGatherBiasPrecision();
|
||||||
|
if (isGather && gatherBiasPrecision != 0)
|
||||||
|
{
|
||||||
|
// GPU requires texture gather to be slightly offset to match NVIDIA behaviour when point is exactly between two texels.
|
||||||
|
// Offset by the gather precision divided by 2 to correct for rounding.
|
||||||
|
var sizeType = pCount == 1 ? context.TypeS32() : context.TypeVector(context.TypeS32(), pCount);
|
||||||
|
var pVectorType = pCount == 1 ? context.TypeFP32() : context.TypeVector(context.TypeFP32(), pCount);
|
||||||
|
|
||||||
|
var bias = context.Constant(context.TypeFP32(), (float)(1 << (gatherBiasPrecision + 1)));
|
||||||
|
var biasVector = context.CompositeConstruct(pVectorType, Enumerable.Repeat(bias, pCount).ToArray());
|
||||||
|
|
||||||
|
var one = context.Constant(context.TypeFP32(), 1f);
|
||||||
|
var oneVector = context.CompositeConstruct(pVectorType, Enumerable.Repeat(one, pCount).ToArray());
|
||||||
|
|
||||||
|
var divisor = context.FMul(
|
||||||
|
pVectorType,
|
||||||
|
context.ConvertSToF(pVectorType, context.ImageQuerySize(sizeType, image)),
|
||||||
|
biasVector);
|
||||||
|
|
||||||
|
vector = context.FAdd(pVectorType, vector, context.FDiv(pVectorType, oneVector, divisor));
|
||||||
|
}
|
||||||
|
|
||||||
|
return vector;
|
||||||
|
}
|
||||||
|
|
||||||
SpvInstruction pCoords = AssemblePVector(pCount);
|
SpvInstruction pCoords = AssemblePVector(pCount);
|
||||||
pCoords = ScalingHelpers.ApplyScaling(context, texOp, pCoords, intCoords, isBindless, isIndexed, isArray, pCount);
|
pCoords = ScalingHelpers.ApplyScaling(context, texOp, pCoords, intCoords, isBindless, isIndexed, isArray, pCount);
|
||||||
|
|
||||||
@ -1716,6 +1744,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
image = context.Image(imageType, image);
|
image = context.Image(imageType, image);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pCoords = ApplyBias(pCoords, image);
|
||||||
|
|
||||||
var operands = operandsList.ToArray();
|
var operands = operandsList.ToArray();
|
||||||
|
|
||||||
SpvInstruction result;
|
SpvInstruction result;
|
||||||
|
@ -196,6 +196,15 @@ namespace Ryujinx.Graphics.Shader
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queries host's gather operation precision bits for biasing their coordinates. Zero means no bias.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Bits of gather operation precision to use for coordinate bias</returns>
|
||||||
|
int QueryHostGatherBiasPrecision()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Queries host about whether to reduce precision to improve performance.
|
/// Queries host about whether to reduce precision to improve performance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -65,7 +65,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
|||||||
context.LeaveFunction();
|
context.LeaveFunction();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.TransformFeedbackEnabled && config.LastInVertexPipeline)
|
if (config.TransformFeedbackEnabled && (config.LastInVertexPipeline || config.Stage == ShaderStage.Fragment))
|
||||||
{
|
{
|
||||||
for (int tfbIndex = 0; tfbIndex < 4; tfbIndex++)
|
for (int tfbIndex = 0; tfbIndex < 4; tfbIndex++)
|
||||||
{
|
{
|
||||||
|
@ -17,7 +17,6 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
public ShaderStage Stage { get; }
|
public ShaderStage Stage { get; }
|
||||||
|
|
||||||
public bool GpPassthrough { get; }
|
public bool GpPassthrough { get; }
|
||||||
public bool LastInPipeline { get; private set; }
|
|
||||||
public bool LastInVertexPipeline { get; private set; }
|
public bool LastInVertexPipeline { get; private set; }
|
||||||
|
|
||||||
public bool HasLayerInputAttribute { get; private set; }
|
public bool HasLayerInputAttribute { get; private set; }
|
||||||
@ -145,7 +144,6 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
OmapSampleMask = header.OmapSampleMask;
|
OmapSampleMask = header.OmapSampleMask;
|
||||||
OmapDepth = header.OmapDepth;
|
OmapDepth = header.OmapDepth;
|
||||||
TransformFeedbackEnabled = gpuAccessor.QueryTransformFeedbackEnabled();
|
TransformFeedbackEnabled = gpuAccessor.QueryTransformFeedbackEnabled();
|
||||||
LastInPipeline = true;
|
|
||||||
LastInVertexPipeline = header.Stage < ShaderStage.Fragment;
|
LastInVertexPipeline = header.Stage < ShaderStage.Fragment;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,13 +251,8 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
GpLayerInputAttribute = attr;
|
GpLayerInputAttribute = attr;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetLastInVertexPipeline(bool hasFragment)
|
public void SetLastInVertexPipeline()
|
||||||
{
|
{
|
||||||
if (!hasFragment)
|
|
||||||
{
|
|
||||||
LastInPipeline = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
LastInVertexPipeline = true;
|
LastInVertexPipeline = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -331,8 +324,6 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
config._perPatchAttributeLocations = locationsMap;
|
config._perPatchAttributeLocations = locationsMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
LastInPipeline = false;
|
|
||||||
|
|
||||||
// We don't consider geometry shaders using the geometry shader passthrough feature
|
// We don't consider geometry shaders using the geometry shader passthrough feature
|
||||||
// as being the last because when this feature is used, it can't actually modify any of the outputs,
|
// as being the last because when this feature is used, it can't actually modify any of the outputs,
|
||||||
// so the stage that comes before it is the last one that can do modifications.
|
// so the stage that comes before it is the last one that can do modifications.
|
||||||
|
@ -143,9 +143,9 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
_config.SetGeometryShaderLayerInputAttribute(attr);
|
_config.SetGeometryShaderLayerInputAttribute(attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetLastInVertexPipeline(bool hasFragment)
|
public void SetLastInVertexPipeline()
|
||||||
{
|
{
|
||||||
_config.SetLastInVertexPipeline(hasFragment);
|
_config.SetLastInVertexPipeline();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ShaderProgram Translate(TranslatorContext other = null)
|
public ShaderProgram Translate(TranslatorContext other = null)
|
||||||
|
@ -46,6 +46,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
public readonly SampleCountFlags SupportedSampleCounts;
|
public readonly SampleCountFlags SupportedSampleCounts;
|
||||||
public readonly PortabilitySubsetFlags PortabilitySubset;
|
public readonly PortabilitySubsetFlags PortabilitySubset;
|
||||||
public readonly uint VertexBufferAlignment;
|
public readonly uint VertexBufferAlignment;
|
||||||
|
public readonly uint SubTexelPrecisionBits;
|
||||||
|
|
||||||
public HardwareCapabilities(
|
public HardwareCapabilities(
|
||||||
bool supportsIndexTypeUint8,
|
bool supportsIndexTypeUint8,
|
||||||
@ -77,7 +78,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
ShaderStageFlags requiredSubgroupSizeStages,
|
ShaderStageFlags requiredSubgroupSizeStages,
|
||||||
SampleCountFlags supportedSampleCounts,
|
SampleCountFlags supportedSampleCounts,
|
||||||
PortabilitySubsetFlags portabilitySubset,
|
PortabilitySubsetFlags portabilitySubset,
|
||||||
uint vertexBufferAlignment)
|
uint vertexBufferAlignment,
|
||||||
|
uint subTexelPrecisionBits)
|
||||||
{
|
{
|
||||||
SupportsIndexTypeUint8 = supportsIndexTypeUint8;
|
SupportsIndexTypeUint8 = supportsIndexTypeUint8;
|
||||||
SupportsCustomBorderColor = supportsCustomBorderColor;
|
SupportsCustomBorderColor = supportsCustomBorderColor;
|
||||||
@ -109,6 +111,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
SupportedSampleCounts = supportedSampleCounts;
|
SupportedSampleCounts = supportedSampleCounts;
|
||||||
PortabilitySubset = portabilitySubset;
|
PortabilitySubset = portabilitySubset;
|
||||||
VertexBufferAlignment = vertexBufferAlignment;
|
VertexBufferAlignment = vertexBufferAlignment;
|
||||||
|
SubTexelPrecisionBits = subTexelPrecisionBits;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -311,7 +311,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
propertiesSubgroupSizeControl.RequiredSubgroupSizeStages,
|
propertiesSubgroupSizeControl.RequiredSubgroupSizeStages,
|
||||||
supportedSampleCounts,
|
supportedSampleCounts,
|
||||||
portabilityFlags,
|
portabilityFlags,
|
||||||
vertexBufferAlignment);
|
vertexBufferAlignment,
|
||||||
|
properties.Limits.SubTexelPrecisionBits);
|
||||||
|
|
||||||
IsSharedMemory = MemoryAllocator.IsDeviceMemoryShared(_physicalDevice);
|
IsSharedMemory = MemoryAllocator.IsDeviceMemoryShared(_physicalDevice);
|
||||||
|
|
||||||
@ -576,7 +577,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
maximumImagesPerStage: Constants.MaxImagesPerStage,
|
maximumImagesPerStage: Constants.MaxImagesPerStage,
|
||||||
maximumComputeSharedMemorySize: (int)limits.MaxComputeSharedMemorySize,
|
maximumComputeSharedMemorySize: (int)limits.MaxComputeSharedMemorySize,
|
||||||
maximumSupportedAnisotropy: (int)limits.MaxSamplerAnisotropy,
|
maximumSupportedAnisotropy: (int)limits.MaxSamplerAnisotropy,
|
||||||
storageBufferOffsetAlignment: (int)limits.MinStorageBufferOffsetAlignment);
|
storageBufferOffsetAlignment: (int)limits.MinStorageBufferOffsetAlignment,
|
||||||
|
gatherBiasPrecision: IsIntelWindows || IsAmdWindows ? (int)Capabilities.SubTexelPrecisionBits : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public HardwareInfo GetHardwareInfo()
|
public HardwareInfo GetHardwareInfo()
|
||||||
|
@ -27,98 +27,103 @@ namespace Ryujinx.HLE.HOS.Ipc
|
|||||||
|
|
||||||
public IpcMessage()
|
public IpcMessage()
|
||||||
{
|
{
|
||||||
PtrBuff = new List<IpcPtrBuffDesc>();
|
PtrBuff = new List<IpcPtrBuffDesc>(0);
|
||||||
SendBuff = new List<IpcBuffDesc>();
|
SendBuff = new List<IpcBuffDesc>(0);
|
||||||
ReceiveBuff = new List<IpcBuffDesc>();
|
ReceiveBuff = new List<IpcBuffDesc>(0);
|
||||||
ExchangeBuff = new List<IpcBuffDesc>();
|
ExchangeBuff = new List<IpcBuffDesc>(0);
|
||||||
RecvListBuff = new List<IpcRecvListBuffDesc>();
|
RecvListBuff = new List<IpcRecvListBuffDesc>(0);
|
||||||
|
|
||||||
ObjectIds = new List<int>();
|
ObjectIds = new List<int>(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IpcMessage(ReadOnlySpan<byte> data, long cmdPtr) : this()
|
public IpcMessage(ReadOnlySpan<byte> data, long cmdPtr)
|
||||||
{
|
{
|
||||||
using (RecyclableMemoryStream ms = MemoryStreamManager.Shared.GetStream(data))
|
using (RecyclableMemoryStream ms = MemoryStreamManager.Shared.GetStream(data))
|
||||||
{
|
{
|
||||||
BinaryReader reader = new BinaryReader(ms);
|
BinaryReader reader = new BinaryReader(ms);
|
||||||
|
|
||||||
Initialize(reader, cmdPtr);
|
int word0 = reader.ReadInt32();
|
||||||
}
|
int word1 = reader.ReadInt32();
|
||||||
}
|
|
||||||
|
|
||||||
private void Initialize(BinaryReader reader, long cmdPtr)
|
Type = (IpcMessageType)(word0 & 0xffff);
|
||||||
{
|
|
||||||
int word0 = reader.ReadInt32();
|
|
||||||
int word1 = reader.ReadInt32();
|
|
||||||
|
|
||||||
Type = (IpcMessageType)(word0 & 0xffff);
|
int ptrBuffCount = (word0 >> 16) & 0xf;
|
||||||
|
int sendBuffCount = (word0 >> 20) & 0xf;
|
||||||
|
int recvBuffCount = (word0 >> 24) & 0xf;
|
||||||
|
int xchgBuffCount = (word0 >> 28) & 0xf;
|
||||||
|
|
||||||
int ptrBuffCount = (word0 >> 16) & 0xf;
|
int rawDataSize = (word1 >> 0) & 0x3ff;
|
||||||
int sendBuffCount = (word0 >> 20) & 0xf;
|
int recvListFlags = (word1 >> 10) & 0xf;
|
||||||
int recvBuffCount = (word0 >> 24) & 0xf;
|
bool hndDescEnable = ((word1 >> 31) & 0x1) != 0;
|
||||||
int xchgBuffCount = (word0 >> 28) & 0xf;
|
|
||||||
|
|
||||||
int rawDataSize = (word1 >> 0) & 0x3ff;
|
if (hndDescEnable)
|
||||||
int recvListFlags = (word1 >> 10) & 0xf;
|
|
||||||
bool hndDescEnable = ((word1 >> 31) & 0x1) != 0;
|
|
||||||
|
|
||||||
if (hndDescEnable)
|
|
||||||
{
|
|
||||||
HandleDesc = new IpcHandleDesc(reader);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int index = 0; index < ptrBuffCount; index++)
|
|
||||||
{
|
|
||||||
PtrBuff.Add(new IpcPtrBuffDesc(reader));
|
|
||||||
}
|
|
||||||
|
|
||||||
void ReadBuff(List<IpcBuffDesc> buff, int count)
|
|
||||||
{
|
|
||||||
for (int index = 0; index < count; index++)
|
|
||||||
{
|
{
|
||||||
buff.Add(new IpcBuffDesc(reader));
|
HandleDesc = new IpcHandleDesc(reader);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
ReadBuff(SendBuff, sendBuffCount);
|
PtrBuff = new List<IpcPtrBuffDesc>(ptrBuffCount);
|
||||||
ReadBuff(ReceiveBuff, recvBuffCount);
|
|
||||||
ReadBuff(ExchangeBuff, xchgBuffCount);
|
|
||||||
|
|
||||||
rawDataSize *= 4;
|
for (int index = 0; index < ptrBuffCount; index++)
|
||||||
|
{
|
||||||
|
PtrBuff.Add(new IpcPtrBuffDesc(reader));
|
||||||
|
}
|
||||||
|
|
||||||
long recvListPos = reader.BaseStream.Position + rawDataSize;
|
static List<IpcBuffDesc> ReadBuff(BinaryReader reader, int count)
|
||||||
|
{
|
||||||
|
List<IpcBuffDesc> buff = new List<IpcBuffDesc>(count);
|
||||||
|
|
||||||
|
for (int index = 0; index < count; index++)
|
||||||
|
{
|
||||||
|
buff.Add(new IpcBuffDesc(reader));
|
||||||
|
}
|
||||||
|
|
||||||
|
return buff;
|
||||||
|
}
|
||||||
|
|
||||||
|
SendBuff = ReadBuff(reader, sendBuffCount);
|
||||||
|
ReceiveBuff = ReadBuff(reader, recvBuffCount);
|
||||||
|
ExchangeBuff = ReadBuff(reader, xchgBuffCount);
|
||||||
|
|
||||||
|
rawDataSize *= 4;
|
||||||
|
|
||||||
|
long recvListPos = reader.BaseStream.Position + rawDataSize;
|
||||||
|
|
||||||
// Only CMIF has the padding requirements.
|
// Only CMIF has the padding requirements.
|
||||||
if (Type < IpcMessageType.TipcCloseSession)
|
if (Type < IpcMessageType.TipcCloseSession)
|
||||||
{
|
{
|
||||||
long pad0 = GetPadSize16(reader.BaseStream.Position + cmdPtr);
|
long pad0 = GetPadSize16(reader.BaseStream.Position + cmdPtr);
|
||||||
|
|
||||||
if (rawDataSize != 0)
|
if (rawDataSize != 0)
|
||||||
{
|
{
|
||||||
rawDataSize -= (int)pad0;
|
rawDataSize -= (int)pad0;
|
||||||
|
}
|
||||||
|
|
||||||
|
reader.BaseStream.Seek(pad0, SeekOrigin.Current);
|
||||||
}
|
}
|
||||||
|
|
||||||
reader.BaseStream.Seek(pad0, SeekOrigin.Current);
|
int recvListCount = recvListFlags - 2;
|
||||||
}
|
|
||||||
|
|
||||||
int recvListCount = recvListFlags - 2;
|
if (recvListCount == 0)
|
||||||
|
{
|
||||||
|
recvListCount = 1;
|
||||||
|
}
|
||||||
|
else if (recvListCount < 0)
|
||||||
|
{
|
||||||
|
recvListCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (recvListCount == 0)
|
RawData = reader.ReadBytes(rawDataSize);
|
||||||
{
|
|
||||||
recvListCount = 1;
|
|
||||||
}
|
|
||||||
else if (recvListCount < 0)
|
|
||||||
{
|
|
||||||
recvListCount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
RawData = reader.ReadBytes(rawDataSize);
|
reader.BaseStream.Seek(recvListPos, SeekOrigin.Begin);
|
||||||
|
|
||||||
reader.BaseStream.Seek(recvListPos, SeekOrigin.Begin);
|
RecvListBuff = new List<IpcRecvListBuffDesc>(recvListCount);
|
||||||
|
|
||||||
for (int index = 0; index < recvListCount; index++)
|
for (int index = 0; index < recvListCount; index++)
|
||||||
{
|
{
|
||||||
RecvListBuff.Add(new IpcRecvListBuffDesc(reader.ReadUInt64()));
|
RecvListBuff.Add(new IpcRecvListBuffDesc(reader.ReadUInt64()));
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectIds = new List<int>(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,7 +71,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Common
|
|||||||
{
|
{
|
||||||
lock (_context.CriticalSection.Lock)
|
lock (_context.CriticalSection.Lock)
|
||||||
{
|
{
|
||||||
_waitingObjects.RemoveAll(x => x.Object == schedulerObj);
|
for (int index = _waitingObjects.Count - 1; index >= 0; index--)
|
||||||
|
{
|
||||||
|
if (_waitingObjects[index].Object == schedulerObj)
|
||||||
|
{
|
||||||
|
_waitingObjects.RemoveAt(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,16 +111,19 @@ namespace Ryujinx.HLE.HOS.Kernel.Common
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
while (Interlocked.Read(ref _enforceWakeupFromSpinWait) != 1 && PerformanceCounter.ElapsedTicks <= next.TimePoint)
|
while (Interlocked.Read(ref _enforceWakeupFromSpinWait) != 1 && PerformanceCounter.ElapsedTicks < next.TimePoint)
|
||||||
{
|
{
|
||||||
|
// Our time is close - don't let SpinWait go off and potentially Thread.Sleep().
|
||||||
if (spinWait.NextSpinWillYield)
|
if (spinWait.NextSpinWillYield)
|
||||||
{
|
{
|
||||||
Thread.Yield();
|
Thread.Yield();
|
||||||
|
|
||||||
spinWait.Reset();
|
spinWait.Reset();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
spinWait.SpinOnce();
|
{
|
||||||
|
spinWait.SpinOnce();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
spinWait.Reset();
|
spinWait.Reset();
|
||||||
|
@ -9,6 +9,7 @@ using Ryujinx.HLE.HOS.Kernel.Process;
|
|||||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||||
using Ryujinx.Horizon.Common;
|
using Ryujinx.Horizon.Common;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Buffers;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
@ -553,7 +554,9 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||||||
|
|
||||||
KProcess currentProcess = KernelStatic.GetCurrentProcess();
|
KProcess currentProcess = KernelStatic.GetCurrentProcess();
|
||||||
|
|
||||||
KSynchronizationObject[] syncObjs = handles.Length == 0 ? Array.Empty<KSynchronizationObject>() : new KSynchronizationObject[handles.Length];
|
KSynchronizationObject[] syncObjsArray = ArrayPool<KSynchronizationObject>.Shared.Rent(handles.Length);
|
||||||
|
|
||||||
|
Span<KSynchronizationObject> syncObjs = syncObjsArray.AsSpan(0, handles.Length);
|
||||||
|
|
||||||
for (int index = 0; index < handles.Length; index++)
|
for (int index = 0; index < handles.Length; index++)
|
||||||
{
|
{
|
||||||
@ -606,6 +609,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ArrayPool<KSynchronizationObject>.Shared.Return(syncObjsArray);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using Ryujinx.HLE.HOS.Kernel.Common;
|
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||||
using Ryujinx.Horizon.Common;
|
using Ryujinx.Horizon.Common;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Buffers;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Kernel.Threading
|
namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||||
@ -59,7 +60,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LinkedListNode<KThread>[] syncNodes = syncObjs.Length == 0 ? Array.Empty<LinkedListNode<KThread>>() : new LinkedListNode<KThread>[syncObjs.Length];
|
LinkedListNode<KThread>[] syncNodesArray = ArrayPool<LinkedListNode<KThread>>.Shared.Rent(syncObjs.Length);
|
||||||
|
|
||||||
|
Span<LinkedListNode<KThread>> syncNodes = syncNodesArray.AsSpan(0, syncObjs.Length);
|
||||||
|
|
||||||
for (int index = 0; index < syncObjs.Length; index++)
|
for (int index = 0; index < syncObjs.Length; index++)
|
||||||
{
|
{
|
||||||
@ -101,6 +104,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||||||
handleIndex = index;
|
handleIndex = index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ArrayPool<LinkedListNode<KThread>>.Shared.Return(syncNodesArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
_context.CriticalSection.Leave();
|
_context.CriticalSection.Leave();
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
|
using Ryujinx.Common.Memory;
|
||||||
using Ryujinx.HLE.HOS.Ipc;
|
using Ryujinx.HLE.HOS.Ipc;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||||
using Ryujinx.Horizon.Common;
|
using Ryujinx.Horizon.Common;
|
||||||
@ -68,25 +69,29 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer
|
|||||||
|
|
||||||
ReadOnlyMemory<byte> input = context.Memory.GetSpan(inputPosition, (int)inputSize).ToArray();
|
ReadOnlyMemory<byte> input = context.Memory.GetSpan(inputPosition, (int)inputSize).ToArray();
|
||||||
|
|
||||||
Memory<byte> output = new byte[outputSize];
|
using (IMemoryOwner<byte> outputOwner = ByteMemoryPool.Shared.RentCleared(outputSize))
|
||||||
Memory<byte> performanceOutput = new byte[performanceOutputSize];
|
using (IMemoryOwner<byte> performanceOutputOwner = ByteMemoryPool.Shared.RentCleared(performanceOutputSize))
|
||||||
|
|
||||||
using MemoryHandle outputHandle = output.Pin();
|
|
||||||
using MemoryHandle performanceOutputHandle = performanceOutput.Pin();
|
|
||||||
|
|
||||||
ResultCode result = _impl.RequestUpdate(output, performanceOutput, input);
|
|
||||||
|
|
||||||
if (result == ResultCode.Success)
|
|
||||||
{
|
{
|
||||||
context.Memory.Write(outputPosition, output.Span);
|
Memory<byte> output = outputOwner.Memory;
|
||||||
context.Memory.Write(performanceOutputPosition, performanceOutput.Span);
|
Memory<byte> performanceOutput = performanceOutputOwner.Memory;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Logger.Error?.Print(LogClass.ServiceAudio, $"Error while processing renderer update: 0x{(int)result:X}");
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
using MemoryHandle outputHandle = output.Pin();
|
||||||
|
using MemoryHandle performanceOutputHandle = performanceOutput.Pin();
|
||||||
|
|
||||||
|
ResultCode result = _impl.RequestUpdate(output, performanceOutput, input);
|
||||||
|
|
||||||
|
if (result == ResultCode.Success)
|
||||||
|
{
|
||||||
|
context.Memory.Write(outputPosition, output.Span);
|
||||||
|
context.Memory.Write(performanceOutputPosition, performanceOutput.Span);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logger.Error?.Print(LogClass.ServiceAudio, $"Error while processing renderer update: 0x{(int)result:X}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[CommandCmif(5)]
|
[CommandCmif(5)]
|
||||||
|
@ -76,6 +76,8 @@ namespace Ryujinx.HLE.HOS.Services
|
|||||||
|
|
||||||
context.RequestData.BaseStream.Seek(0x10 + dataPayloadSize, SeekOrigin.Begin);
|
context.RequestData.BaseStream.Seek(0x10 + dataPayloadSize, SeekOrigin.Begin);
|
||||||
|
|
||||||
|
context.Request.ObjectIds.EnsureCapacity(inputObjCount);
|
||||||
|
|
||||||
for (int index = 0; index < inputObjCount; index++)
|
for (int index = 0; index < inputObjCount; index++)
|
||||||
{
|
{
|
||||||
context.Request.ObjectIds.Add(context.RequestData.ReadInt32());
|
context.Request.ObjectIds.Add(context.RequestData.ReadInt32());
|
||||||
|
@ -217,6 +217,8 @@ namespace Ryujinx.HLE.HOS.Services
|
|||||||
|
|
||||||
if (noReceive)
|
if (noReceive)
|
||||||
{
|
{
|
||||||
|
response.PtrBuff.EnsureCapacity(request.RecvListBuff.Count);
|
||||||
|
|
||||||
for (int i = 0; i < request.RecvListBuff.Count; i++)
|
for (int i = 0; i < request.RecvListBuff.Count; i++)
|
||||||
{
|
{
|
||||||
ulong size = (ulong)BinaryPrimitives.ReadInt16LittleEndian(request.RawData.AsSpan(sizesOffset + i * 2, 2));
|
ulong size = (ulong)BinaryPrimitives.ReadInt16LittleEndian(request.RawData.AsSpan(sizesOffset + i * 2, 2));
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
using Ryujinx.HLE.HOS.Ipc;
|
using Ryujinx.Common.Memory;
|
||||||
|
using Ryujinx.HLE.HOS.Ipc;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||||
using Ryujinx.Horizon.Common;
|
using Ryujinx.Horizon.Common;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Buffers;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||||
{
|
{
|
||||||
@ -83,16 +85,19 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
|||||||
|
|
||||||
ReadOnlySpan<byte> inputParcel = context.Memory.GetSpan(dataPos, (int)dataSize);
|
ReadOnlySpan<byte> inputParcel = context.Memory.GetSpan(dataPos, (int)dataSize);
|
||||||
|
|
||||||
Span<byte> outputParcel = new Span<byte>(new byte[replySize]);
|
using (IMemoryOwner<byte> outputParcelOwner = ByteMemoryPool.Shared.RentCleared(replySize))
|
||||||
|
|
||||||
ResultCode result = OnTransact(binderId, code, flags, inputParcel, outputParcel);
|
|
||||||
|
|
||||||
if (result == ResultCode.Success)
|
|
||||||
{
|
{
|
||||||
context.Memory.Write(replyPos, outputParcel);
|
Span<byte> outputParcel = outputParcelOwner.Memory.Span;
|
||||||
}
|
|
||||||
|
ResultCode result = OnTransact(binderId, code, flags, inputParcel, outputParcel);
|
||||||
|
|
||||||
return result;
|
if (result == ResultCode.Success)
|
||||||
|
{
|
||||||
|
context.Memory.Write(replyPos, outputParcel);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract ResultCode AdjustRefcount(int binderId, int addVal, int type);
|
protected abstract ResultCode AdjustRefcount(int binderId, int addVal, int type);
|
||||||
|
@ -12,17 +12,7 @@ namespace Ryujinx.Input.SDL2
|
|||||||
{
|
{
|
||||||
private bool HasConfiguration => _configuration != null;
|
private bool HasConfiguration => _configuration != null;
|
||||||
|
|
||||||
private class ButtonMappingEntry
|
private record struct ButtonMappingEntry(GamepadButtonInputId To, GamepadButtonInputId From);
|
||||||
{
|
|
||||||
public readonly GamepadButtonInputId To;
|
|
||||||
public readonly GamepadButtonInputId From;
|
|
||||||
|
|
||||||
public ButtonMappingEntry(GamepadButtonInputId to, GamepadButtonInputId from)
|
|
||||||
{
|
|
||||||
To = to;
|
|
||||||
From = from;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private StandardControllerInputConfig _configuration;
|
private StandardControllerInputConfig _configuration;
|
||||||
|
|
||||||
@ -85,7 +75,7 @@ namespace Ryujinx.Input.SDL2
|
|||||||
public SDL2Gamepad(IntPtr gamepadHandle, string driverId)
|
public SDL2Gamepad(IntPtr gamepadHandle, string driverId)
|
||||||
{
|
{
|
||||||
_gamepadHandle = gamepadHandle;
|
_gamepadHandle = gamepadHandle;
|
||||||
_buttonsUserMapping = new List<ButtonMappingEntry>();
|
_buttonsUserMapping = new List<ButtonMappingEntry>(20);
|
||||||
|
|
||||||
Name = SDL_GameControllerName(_gamepadHandle);
|
Name = SDL_GameControllerName(_gamepadHandle);
|
||||||
Id = driverId;
|
Id = driverId;
|
||||||
|
@ -12,7 +12,6 @@ namespace Ryujinx.Input
|
|||||||
public Vector3 Rotation { get; set; }
|
public Vector3 Rotation { get; set; }
|
||||||
|
|
||||||
private readonly MotionSensorFilter _filter;
|
private readonly MotionSensorFilter _filter;
|
||||||
private int _calibrationFrame = 0;
|
|
||||||
|
|
||||||
public MotionInput()
|
public MotionInput()
|
||||||
{
|
{
|
||||||
@ -29,26 +28,6 @@ namespace Ryujinx.Input
|
|||||||
{
|
{
|
||||||
if (TimeStamp != 0)
|
if (TimeStamp != 0)
|
||||||
{
|
{
|
||||||
if (gyro.Length() <= 1f && accel.Length() >= 0.8f && accel.Z >= 0.8f)
|
|
||||||
{
|
|
||||||
_calibrationFrame++;
|
|
||||||
|
|
||||||
if (_calibrationFrame >= 90)
|
|
||||||
{
|
|
||||||
gyro = Vector3.Zero;
|
|
||||||
|
|
||||||
Rotation = Vector3.Zero;
|
|
||||||
|
|
||||||
_filter.Reset();
|
|
||||||
|
|
||||||
_calibrationFrame = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_calibrationFrame = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Accelerometer = -accel;
|
Accelerometer = -accel;
|
||||||
|
|
||||||
if (gyro.Length() < deadzone)
|
if (gyro.Length() < deadzone)
|
||||||
|
@ -96,6 +96,8 @@ namespace Ryujinx
|
|||||||
// Delete backup files after updating.
|
// Delete backup files after updating.
|
||||||
Task.Run(Updater.CleanupUpdate);
|
Task.Run(Updater.CleanupUpdate);
|
||||||
|
|
||||||
|
Console.Title = $"Ryujinx Console {Version}";
|
||||||
|
|
||||||
// NOTE: GTK3 doesn't init X11 in a multi threaded way.
|
// NOTE: GTK3 doesn't init X11 in a multi threaded way.
|
||||||
// This ends up causing race condition and abort of XCB when a context is created by SPB (even if SPB do call XInitThreads).
|
// This ends up causing race condition and abort of XCB when a context is created by SPB (even if SPB do call XInitThreads).
|
||||||
if (OperatingSystem.IsLinux())
|
if (OperatingSystem.IsLinux())
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using Gtk;
|
using Gtk;
|
||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Common.Utilities;
|
using Ryujinx.Common.Utilities;
|
||||||
using Ryujinx.Ui.Common.Configuration;
|
using Ryujinx.Ui.Common.Configuration;
|
||||||
using Ryujinx.Ui.Common.Models.Amiibo;
|
using Ryujinx.Ui.Common.Models.Amiibo;
|
||||||
@ -12,7 +13,6 @@ using System.Linq;
|
|||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Json;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using AmiiboApi = Ryujinx.Ui.Common.Models.Amiibo.AmiiboApi;
|
using AmiiboApi = Ryujinx.Ui.Common.Models.Amiibo.AmiiboApi;
|
||||||
using AmiiboJsonSerializerContext = Ryujinx.Ui.Common.Models.Amiibo.AmiiboJsonSerializerContext;
|
using AmiiboJsonSerializerContext = Ryujinx.Ui.Common.Models.Amiibo.AmiiboJsonSerializerContext;
|
||||||
@ -57,7 +57,7 @@ namespace Ryujinx.Ui.Windows
|
|||||||
|
|
||||||
_httpClient = new HttpClient()
|
_httpClient = new HttpClient()
|
||||||
{
|
{
|
||||||
Timeout = TimeSpan.FromMilliseconds(5000)
|
Timeout = TimeSpan.FromSeconds(30)
|
||||||
};
|
};
|
||||||
|
|
||||||
Directory.CreateDirectory(System.IO.Path.Join(AppDataManager.BaseDirPath, "system", "amiibo"));
|
Directory.CreateDirectory(System.IO.Path.Join(AppDataManager.BaseDirPath, "system", "amiibo"));
|
||||||
@ -93,8 +93,10 @@ namespace Ryujinx.Ui.Windows
|
|||||||
{
|
{
|
||||||
amiiboJsonString = await DownloadAmiiboJson();
|
amiiboJsonString = await DownloadAmiiboJson();
|
||||||
}
|
}
|
||||||
catch
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
Logger.Error?.Print(LogClass.Application, $"Failed to download amiibo data: {ex}");
|
||||||
|
|
||||||
ShowInfoDialog();
|
ShowInfoDialog();
|
||||||
|
|
||||||
Close();
|
Close();
|
||||||
@ -183,8 +185,10 @@ namespace Ryujinx.Ui.Windows
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
catch
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
Logger.Error?.Print(LogClass.Application, $"Failed to check for amiibo updates: {ex}");
|
||||||
|
|
||||||
ShowInfoDialog();
|
ShowInfoDialog();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -208,6 +212,8 @@ namespace Ryujinx.Ui.Windows
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
Logger.Error?.Print(LogClass.Application, $"Failed to download amiibo data. Response status code: {response.StatusCode}");
|
||||||
|
|
||||||
GtkDialog.CreateInfoDialog($"Amiibo API", "An error occured while fetching information from the API.");
|
GtkDialog.CreateInfoDialog($"Amiibo API", "An error occured while fetching information from the API.");
|
||||||
|
|
||||||
Close();
|
Close();
|
||||||
@ -233,6 +239,10 @@ namespace Ryujinx.Ui.Windows
|
|||||||
|
|
||||||
_amiiboImage.Pixbuf = amiiboPreview.ScaleSimple(resizeWidth, resizeHeight, Gdk.InterpType.Bilinear);
|
_amiiboImage.Pixbuf = amiiboPreview.ScaleSimple(resizeWidth, resizeHeight, Gdk.InterpType.Bilinear);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logger.Error?.Print(LogClass.Application, $"Failed to get amiibo preview. Response status code: {response.StatusCode}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ShowInfoDialog()
|
private void ShowInfoDialog()
|
||||||
@ -374,4 +384,4 @@ namespace Ryujinx.Ui.Windows
|
|||||||
base.Dispose(disposing);
|
base.Dispose(disposing);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Reference in New Issue
Block a user