Compare commits
6 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
097562bc6c | ||
|
db4242c5dc | ||
|
4dd77316f7 | ||
|
3f98369a17 | ||
|
c26aeefe03 | ||
|
666e05f5cb |
@@ -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;
|
||||||
@@ -48,7 +49,12 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -6,6 +6,7 @@ using Ryujinx.Graphics.Texture;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Runtime.Intrinsics;
|
using System.Runtime.Intrinsics;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gpu.Engine.Dma
|
namespace Ryujinx.Graphics.Gpu.Engine.Dma
|
||||||
@@ -32,6 +33,69 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
|
|||||||
RemapEnable = 1 << 10
|
RemapEnable = 1 << 10
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Texture parameters for copy.
|
||||||
|
/// </summary>
|
||||||
|
private struct TextureParams
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Copy region X coordinate.
|
||||||
|
/// </summary>
|
||||||
|
public readonly int RegionX;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Copy region Y coordinate.
|
||||||
|
/// </summary>
|
||||||
|
public readonly int RegionY;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Offset from the base pointer of the data in memory.
|
||||||
|
/// </summary>
|
||||||
|
public readonly int BaseOffset;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Bytes per pixel.
|
||||||
|
/// </summary>
|
||||||
|
public readonly int Bpp;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the texture is linear. If false, the texture is block linear.
|
||||||
|
/// </summary>
|
||||||
|
public readonly bool Linear;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Pixel offset from XYZ coordinates calculator.
|
||||||
|
/// </summary>
|
||||||
|
public readonly OffsetCalculator Calculator;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates texture parameters.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="regionX">Copy region X coordinate</param>
|
||||||
|
/// <param name="regionY">Copy region Y coordinate</param>
|
||||||
|
/// <param name="baseOffset">Offset from the base pointer of the data in memory</param>
|
||||||
|
/// <param name="bpp">Bytes per pixel</param>
|
||||||
|
/// <param name="linear">Whether the texture is linear. If false, the texture is block linear</param>
|
||||||
|
/// <param name="calculator">Pixel offset from XYZ coordinates calculator</param>
|
||||||
|
public TextureParams(int regionX, int regionY, int baseOffset, int bpp, bool linear, OffsetCalculator calculator)
|
||||||
|
{
|
||||||
|
RegionX = regionX;
|
||||||
|
RegionY = regionY;
|
||||||
|
BaseOffset = baseOffset;
|
||||||
|
Bpp = bpp;
|
||||||
|
Linear = linear;
|
||||||
|
Calculator = calculator;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential, Size = 3, Pack = 1)]
|
||||||
|
private struct UInt24
|
||||||
|
{
|
||||||
|
public byte Byte0;
|
||||||
|
public byte Byte1;
|
||||||
|
public byte Byte2;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new instance of the DMA copy engine class.
|
/// Creates a new instance of the DMA copy engine class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -154,8 +218,10 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
|
|||||||
{
|
{
|
||||||
// Buffer to texture copy.
|
// Buffer to texture copy.
|
||||||
int componentSize = (int)_state.State.SetRemapComponentsComponentSize + 1;
|
int componentSize = (int)_state.State.SetRemapComponentsComponentSize + 1;
|
||||||
int srcBpp = remap ? ((int)_state.State.SetRemapComponentsNumSrcComponents + 1) * componentSize : 1;
|
int srcComponents = (int)_state.State.SetRemapComponentsNumSrcComponents + 1;
|
||||||
int dstBpp = remap ? ((int)_state.State.SetRemapComponentsNumDstComponents + 1) * componentSize : 1;
|
int dstComponents = (int)_state.State.SetRemapComponentsNumDstComponents + 1;
|
||||||
|
int srcBpp = remap ? srcComponents * componentSize : 1;
|
||||||
|
int dstBpp = remap ? dstComponents * componentSize : 1;
|
||||||
|
|
||||||
var dst = Unsafe.As<uint, DmaTexture>(ref _state.State.SetDstBlockSize);
|
var dst = Unsafe.As<uint, DmaTexture>(ref _state.State.SetDstBlockSize);
|
||||||
var src = Unsafe.As<uint, DmaTexture>(ref _state.State.SetSrcBlockSize);
|
var src = Unsafe.As<uint, DmaTexture>(ref _state.State.SetSrcBlockSize);
|
||||||
@@ -274,63 +340,51 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe bool Convert<T>(Span<byte> dstSpan, ReadOnlySpan<byte> srcSpan) where T : unmanaged
|
|
||||||
{
|
|
||||||
if (srcLinear && dstLinear && srcBpp == dstBpp)
|
|
||||||
{
|
|
||||||
// Optimized path for purely linear copies - we don't need to calculate every single byte offset,
|
|
||||||
// and we can make use of Span.CopyTo which is very very fast (even compared to pointers)
|
|
||||||
for (int y = 0; y < yCount; y++)
|
|
||||||
{
|
|
||||||
srcCalculator.SetY(srcRegionY + y);
|
|
||||||
dstCalculator.SetY(dstRegionY + y);
|
|
||||||
int srcOffset = srcCalculator.GetOffset(srcRegionX);
|
|
||||||
int dstOffset = dstCalculator.GetOffset(dstRegionX);
|
|
||||||
srcSpan.Slice(srcOffset - srcBaseOffset, xCount * srcBpp)
|
|
||||||
.CopyTo(dstSpan.Slice(dstOffset - dstBaseOffset, xCount * dstBpp));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fixed (byte* dstPtr = dstSpan, srcPtr = srcSpan)
|
|
||||||
{
|
|
||||||
byte* dstBase = dstPtr - dstBaseOffset; // Layout offset is relative to the base, so we need to subtract the span's offset.
|
|
||||||
byte* srcBase = srcPtr - srcBaseOffset;
|
|
||||||
|
|
||||||
for (int y = 0; y < yCount; y++)
|
|
||||||
{
|
|
||||||
srcCalculator.SetY(srcRegionY + y);
|
|
||||||
dstCalculator.SetY(dstRegionY + y);
|
|
||||||
|
|
||||||
for (int x = 0; x < xCount; x++)
|
|
||||||
{
|
|
||||||
int srcOffset = srcCalculator.GetOffset(srcRegionX + x);
|
|
||||||
int dstOffset = dstCalculator.GetOffset(dstRegionX + x);
|
|
||||||
|
|
||||||
*(T*)(dstBase + dstOffset) = *(T*)(srcBase + srcOffset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// OPT: This allocates a (potentially) huge temporary array and then copies an existing
|
// OPT: This allocates a (potentially) huge temporary array and then copies an existing
|
||||||
// region of memory into it, data that might get overwritten entirely anyways. Ideally this should
|
// region of memory into it, data that might get overwritten entirely anyways. Ideally this should
|
||||||
// all be rewritten to use pooled arrays, but that gets complicated with packed data and strides
|
// all be rewritten to use pooled arrays, but that gets complicated with packed data and strides
|
||||||
Span<byte> dstSpan = memoryManager.GetSpan(dstGpuVa + (ulong)dstBaseOffset, dstSize).ToArray();
|
Span<byte> dstSpan = memoryManager.GetSpan(dstGpuVa + (ulong)dstBaseOffset, dstSize).ToArray();
|
||||||
|
|
||||||
bool _ = srcBpp switch
|
TextureParams srcParams = new TextureParams(srcRegionX, srcRegionY, srcBaseOffset, srcBpp, srcLinear, srcCalculator);
|
||||||
|
TextureParams dstParams = new TextureParams(dstRegionX, dstRegionY, dstBaseOffset, dstBpp, dstLinear, dstCalculator);
|
||||||
|
|
||||||
|
// If remapping is enabled, we always copy the components directly, in order.
|
||||||
|
// If it's enabled, but the mapping is just XYZW, we also copy them in order.
|
||||||
|
bool isIdentityRemap = !remap ||
|
||||||
|
(_state.State.SetRemapComponentsDstX == SetRemapComponentsDst.SrcX &&
|
||||||
|
(dstComponents < 2 || _state.State.SetRemapComponentsDstY == SetRemapComponentsDst.SrcY) &&
|
||||||
|
(dstComponents < 3 || _state.State.SetRemapComponentsDstZ == SetRemapComponentsDst.SrcZ) &&
|
||||||
|
(dstComponents < 4 || _state.State.SetRemapComponentsDstW == SetRemapComponentsDst.SrcW));
|
||||||
|
|
||||||
|
if (isIdentityRemap)
|
||||||
{
|
{
|
||||||
1 => Convert<byte>(dstSpan, srcSpan),
|
// The order of the components doesn't change, so we can just copy directly
|
||||||
2 => Convert<ushort>(dstSpan, srcSpan),
|
// (with layout conversion if necessary).
|
||||||
4 => Convert<uint>(dstSpan, srcSpan),
|
|
||||||
8 => Convert<ulong>(dstSpan, srcSpan),
|
switch (srcBpp)
|
||||||
12 => Convert<Bpp12Pixel>(dstSpan, srcSpan),
|
{
|
||||||
16 => Convert<Vector128<byte>>(dstSpan, srcSpan),
|
case 1: Copy<byte>(dstSpan, srcSpan, dstParams, srcParams); break;
|
||||||
_ => throw new NotSupportedException($"Unable to copy ${srcBpp} bpp pixel format.")
|
case 2: Copy<ushort>(dstSpan, srcSpan, dstParams, srcParams); break;
|
||||||
};
|
case 4: Copy<uint>(dstSpan, srcSpan, dstParams, srcParams); break;
|
||||||
|
case 8: Copy<ulong>(dstSpan, srcSpan, dstParams, srcParams); break;
|
||||||
|
case 12: Copy<Bpp12Pixel>(dstSpan, srcSpan, dstParams, srcParams); break;
|
||||||
|
case 16: Copy<Vector128<byte>>(dstSpan, srcSpan, dstParams, srcParams); break;
|
||||||
|
default: throw new NotSupportedException($"Unable to copy ${srcBpp} bpp pixel format.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// The order or value of the components might change.
|
||||||
|
|
||||||
|
switch (componentSize)
|
||||||
|
{
|
||||||
|
case 1: CopyShuffle<byte>(dstSpan, srcSpan, dstParams, srcParams); break;
|
||||||
|
case 2: CopyShuffle<ushort>(dstSpan, srcSpan, dstParams, srcParams); break;
|
||||||
|
case 3: CopyShuffle<UInt24>(dstSpan, srcSpan, dstParams, srcParams); break;
|
||||||
|
case 4: CopyShuffle<uint>(dstSpan, srcSpan, dstParams, srcParams); break;
|
||||||
|
default: throw new NotSupportedException($"Unable to copy ${componentSize} component size.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
memoryManager.Write(dstGpuVa + (ulong)dstBaseOffset, dstSpan);
|
memoryManager.Write(dstGpuVa + (ulong)dstBaseOffset, dstSpan);
|
||||||
}
|
}
|
||||||
@@ -372,6 +426,133 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Copies data from one texture to another, while performing layout conversion if necessary.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">Pixel type</typeparam>
|
||||||
|
/// <param name="dstSpan">Destination texture memory region</param>
|
||||||
|
/// <param name="srcSpan">Source texture memory region</param>
|
||||||
|
/// <param name="dst">Destination texture parameters</param>
|
||||||
|
/// <param name="src">Source texture parameters</param>
|
||||||
|
private unsafe void Copy<T>(Span<byte> dstSpan, ReadOnlySpan<byte> srcSpan, TextureParams dst, TextureParams src) where T : unmanaged
|
||||||
|
{
|
||||||
|
int xCount = (int)_state.State.LineLengthIn;
|
||||||
|
int yCount = (int)_state.State.LineCount;
|
||||||
|
|
||||||
|
if (src.Linear && dst.Linear && src.Bpp == dst.Bpp)
|
||||||
|
{
|
||||||
|
// Optimized path for purely linear copies - we don't need to calculate every single byte offset,
|
||||||
|
// and we can make use of Span.CopyTo which is very very fast (even compared to pointers)
|
||||||
|
for (int y = 0; y < yCount; y++)
|
||||||
|
{
|
||||||
|
src.Calculator.SetY(src.RegionY + y);
|
||||||
|
dst.Calculator.SetY(dst.RegionY + y);
|
||||||
|
int srcOffset = src.Calculator.GetOffset(src.RegionX);
|
||||||
|
int dstOffset = dst.Calculator.GetOffset(dst.RegionX);
|
||||||
|
srcSpan.Slice(srcOffset - src.BaseOffset, xCount * src.Bpp)
|
||||||
|
.CopyTo(dstSpan.Slice(dstOffset - dst.BaseOffset, xCount * dst.Bpp));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fixed (byte* dstPtr = dstSpan, srcPtr = srcSpan)
|
||||||
|
{
|
||||||
|
byte* dstBase = dstPtr - dst.BaseOffset; // Layout offset is relative to the base, so we need to subtract the span's offset.
|
||||||
|
byte* srcBase = srcPtr - src.BaseOffset;
|
||||||
|
|
||||||
|
for (int y = 0; y < yCount; y++)
|
||||||
|
{
|
||||||
|
src.Calculator.SetY(src.RegionY + y);
|
||||||
|
dst.Calculator.SetY(dst.RegionY + y);
|
||||||
|
|
||||||
|
for (int x = 0; x < xCount; x++)
|
||||||
|
{
|
||||||
|
int srcOffset = src.Calculator.GetOffset(src.RegionX + x);
|
||||||
|
int dstOffset = dst.Calculator.GetOffset(dst.RegionX + x);
|
||||||
|
|
||||||
|
*(T*)(dstBase + dstOffset) = *(T*)(srcBase + srcOffset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets texture pixel data to a constant value, while performing layout conversion if necessary.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">Pixel type</typeparam>
|
||||||
|
/// <param name="dstSpan">Destination texture memory region</param>
|
||||||
|
/// <param name="dst">Destination texture parameters</param>
|
||||||
|
/// <param name="fillValue">Constant pixel value to be set</param>
|
||||||
|
private unsafe void Fill<T>(Span<byte> dstSpan, TextureParams dst, T fillValue) where T : unmanaged
|
||||||
|
{
|
||||||
|
int xCount = (int)_state.State.LineLengthIn;
|
||||||
|
int yCount = (int)_state.State.LineCount;
|
||||||
|
|
||||||
|
fixed (byte* dstPtr = dstSpan)
|
||||||
|
{
|
||||||
|
byte* dstBase = dstPtr - dst.BaseOffset; // Layout offset is relative to the base, so we need to subtract the span's offset.
|
||||||
|
|
||||||
|
for (int y = 0; y < yCount; y++)
|
||||||
|
{
|
||||||
|
dst.Calculator.SetY(dst.RegionY + y);
|
||||||
|
|
||||||
|
for (int x = 0; x < xCount; x++)
|
||||||
|
{
|
||||||
|
int dstOffset = dst.Calculator.GetOffset(dst.RegionX + x);
|
||||||
|
|
||||||
|
*(T*)(dstBase + dstOffset) = fillValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Copies data from one texture to another, while performing layout conversion and component shuffling if necessary.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">Pixel type</typeparam>
|
||||||
|
/// <param name="dstSpan">Destination texture memory region</param>
|
||||||
|
/// <param name="srcSpan">Source texture memory region</param>
|
||||||
|
/// <param name="dst">Destination texture parameters</param>
|
||||||
|
/// <param name="src">Source texture parameters</param>
|
||||||
|
private void CopyShuffle<T>(Span<byte> dstSpan, ReadOnlySpan<byte> srcSpan, TextureParams dst, TextureParams src) where T : unmanaged
|
||||||
|
{
|
||||||
|
int dstComponents = (int)_state.State.SetRemapComponentsNumDstComponents + 1;
|
||||||
|
|
||||||
|
for (int i = 0; i < dstComponents; i++)
|
||||||
|
{
|
||||||
|
SetRemapComponentsDst componentsDst = i switch
|
||||||
|
{
|
||||||
|
0 => _state.State.SetRemapComponentsDstX,
|
||||||
|
1 => _state.State.SetRemapComponentsDstY,
|
||||||
|
2 => _state.State.SetRemapComponentsDstZ,
|
||||||
|
_ => _state.State.SetRemapComponentsDstW
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (componentsDst)
|
||||||
|
{
|
||||||
|
case SetRemapComponentsDst.SrcX:
|
||||||
|
Copy<T>(dstSpan.Slice(Unsafe.SizeOf<T>() * i), srcSpan, dst, src);
|
||||||
|
break;
|
||||||
|
case SetRemapComponentsDst.SrcY:
|
||||||
|
Copy<T>(dstSpan.Slice(Unsafe.SizeOf<T>() * i), srcSpan.Slice(Unsafe.SizeOf<T>()), dst, src);
|
||||||
|
break;
|
||||||
|
case SetRemapComponentsDst.SrcZ:
|
||||||
|
Copy<T>(dstSpan.Slice(Unsafe.SizeOf<T>() * i), srcSpan.Slice(Unsafe.SizeOf<T>() * 2), dst, src);
|
||||||
|
break;
|
||||||
|
case SetRemapComponentsDst.SrcW:
|
||||||
|
Copy<T>(dstSpan.Slice(Unsafe.SizeOf<T>() * i), srcSpan.Slice(Unsafe.SizeOf<T>() * 3), dst, src);
|
||||||
|
break;
|
||||||
|
case SetRemapComponentsDst.ConstA:
|
||||||
|
Fill<T>(dstSpan.Slice(Unsafe.SizeOf<T>() * i), dst, Unsafe.As<uint, T>(ref _state.State.SetRemapConstA));
|
||||||
|
break;
|
||||||
|
case SetRemapComponentsDst.ConstB:
|
||||||
|
Fill<T>(dstSpan.Slice(Unsafe.SizeOf<T>() * i), dst, Unsafe.As<uint, T>(ref _state.State.SetRemapConstB));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Copies block linear data with block linear GOBs to a block linear destination with linear GOBs.
|
/// Copies block linear data with block linear GOBs to a block linear destination with linear GOBs.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@@ -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 = 4703;
|
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";
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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,9 +680,8 @@ 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];
|
char swzMask = "xyzw"[c];
|
||||||
|
|
||||||
@@ -681,7 +696,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||||||
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
|
||||||
{
|
{
|
||||||
string type = context.Config.Stage != ShaderStage.Fragment ? "vec4" :
|
string type = context.Config.Stage != ShaderStage.Fragment ? "vec4" :
|
||||||
|
@@ -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);
|
||||||
|
|
||||||
|
@@ -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)
|
||||||
|
@@ -27,27 +27,21 @@ 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Initialize(BinaryReader reader, long cmdPtr)
|
|
||||||
{
|
|
||||||
int word0 = reader.ReadInt32();
|
int word0 = reader.ReadInt32();
|
||||||
int word1 = reader.ReadInt32();
|
int word1 = reader.ReadInt32();
|
||||||
|
|
||||||
@@ -67,22 +61,28 @@ namespace Ryujinx.HLE.HOS.Ipc
|
|||||||
HandleDesc = new IpcHandleDesc(reader);
|
HandleDesc = new IpcHandleDesc(reader);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PtrBuff = new List<IpcPtrBuffDesc>(ptrBuffCount);
|
||||||
|
|
||||||
for (int index = 0; index < ptrBuffCount; index++)
|
for (int index = 0; index < ptrBuffCount; index++)
|
||||||
{
|
{
|
||||||
PtrBuff.Add(new IpcPtrBuffDesc(reader));
|
PtrBuff.Add(new IpcPtrBuffDesc(reader));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReadBuff(List<IpcBuffDesc> buff, int count)
|
static List<IpcBuffDesc> ReadBuff(BinaryReader reader, int count)
|
||||||
{
|
{
|
||||||
|
List<IpcBuffDesc> buff = new List<IpcBuffDesc>(count);
|
||||||
|
|
||||||
for (int index = 0; index < count; index++)
|
for (int index = 0; index < count; index++)
|
||||||
{
|
{
|
||||||
buff.Add(new IpcBuffDesc(reader));
|
buff.Add(new IpcBuffDesc(reader));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return buff;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReadBuff(SendBuff, sendBuffCount);
|
SendBuff = ReadBuff(reader, sendBuffCount);
|
||||||
ReadBuff(ReceiveBuff, recvBuffCount);
|
ReceiveBuff = ReadBuff(reader, recvBuffCount);
|
||||||
ReadBuff(ExchangeBuff, xchgBuffCount);
|
ExchangeBuff = ReadBuff(reader, xchgBuffCount);
|
||||||
|
|
||||||
rawDataSize *= 4;
|
rawDataSize *= 4;
|
||||||
|
|
||||||
@@ -116,10 +116,15 @@ namespace Ryujinx.HLE.HOS.Ipc
|
|||||||
|
|
||||||
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public RecyclableMemoryStream GetStream(long cmdPtr, ulong recvListAddr)
|
public RecyclableMemoryStream GetStream(long cmdPtr, ulong recvListAddr)
|
||||||
|
@@ -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,17 +111,20 @@ 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();
|
||||||
}
|
}
|
||||||
|
@@ -188,8 +188,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
|||||||
|
|
||||||
if (request.AsyncEvent == null)
|
if (request.AsyncEvent == null)
|
||||||
{
|
{
|
||||||
if (request.ClientThread.ShallBeTerminated ||
|
if (request.ClientThread.TerminationRequested)
|
||||||
request.ClientThread.SchedFlags == ThreadSchedState.TerminationPending)
|
|
||||||
{
|
{
|
||||||
return KernelResult.ThreadTerminating;
|
return KernelResult.ThreadTerminating;
|
||||||
}
|
}
|
||||||
@@ -1104,8 +1103,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
|||||||
{
|
{
|
||||||
foreach (KSessionRequest request in IterateWithRemovalOfAllRequests())
|
foreach (KSessionRequest request in IterateWithRemovalOfAllRequests())
|
||||||
{
|
{
|
||||||
if (request.ClientThread.ShallBeTerminated ||
|
if (request.ClientThread.TerminationRequested)
|
||||||
request.ClientThread.SchedFlags == ThreadSchedState.TerminationPending)
|
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -31,6 +31,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||||||
|
|
||||||
_context.CriticalSection.Enter();
|
_context.CriticalSection.Enter();
|
||||||
|
|
||||||
|
if (currentThread.TerminationRequested)
|
||||||
|
{
|
||||||
|
_context.CriticalSection.Leave();
|
||||||
|
|
||||||
|
return KernelResult.ThreadTerminating;
|
||||||
|
}
|
||||||
|
|
||||||
currentThread.SignaledObj = null;
|
currentThread.SignaledObj = null;
|
||||||
currentThread.ObjSyncResult = Result.Success;
|
currentThread.ObjSyncResult = Result.Success;
|
||||||
|
|
||||||
@@ -114,8 +121,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||||||
currentThread.SignaledObj = null;
|
currentThread.SignaledObj = null;
|
||||||
currentThread.ObjSyncResult = KernelResult.TimedOut;
|
currentThread.ObjSyncResult = KernelResult.TimedOut;
|
||||||
|
|
||||||
if (currentThread.ShallBeTerminated ||
|
if (currentThread.TerminationRequested)
|
||||||
currentThread.SchedFlags == ThreadSchedState.TerminationPending)
|
|
||||||
{
|
{
|
||||||
_context.CriticalSection.Leave();
|
_context.CriticalSection.Leave();
|
||||||
|
|
||||||
@@ -280,8 +286,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||||||
|
|
||||||
_context.CriticalSection.Enter();
|
_context.CriticalSection.Enter();
|
||||||
|
|
||||||
if (currentThread.ShallBeTerminated ||
|
if (currentThread.TerminationRequested)
|
||||||
currentThread.SchedFlags == ThreadSchedState.TerminationPending)
|
|
||||||
{
|
{
|
||||||
_context.CriticalSection.Leave();
|
_context.CriticalSection.Leave();
|
||||||
|
|
||||||
@@ -351,8 +356,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||||||
|
|
||||||
_context.CriticalSection.Enter();
|
_context.CriticalSection.Enter();
|
||||||
|
|
||||||
if (currentThread.ShallBeTerminated ||
|
if (currentThread.TerminationRequested)
|
||||||
currentThread.SchedFlags == ThreadSchedState.TerminationPending)
|
|
||||||
{
|
{
|
||||||
_context.CriticalSection.Leave();
|
_context.CriticalSection.Leave();
|
||||||
|
|
||||||
|
@@ -19,8 +19,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||||||
|
|
||||||
currentThread.WithholderNode = threadList.AddLast(currentThread);
|
currentThread.WithholderNode = threadList.AddLast(currentThread);
|
||||||
|
|
||||||
if (currentThread.ShallBeTerminated ||
|
if (currentThread.TerminationRequested)
|
||||||
currentThread.SchedFlags == ThreadSchedState.TerminationPending)
|
|
||||||
{
|
{
|
||||||
threadList.Remove(currentThread.WithholderNode);
|
threadList.Remove(currentThread.WithholderNode);
|
||||||
|
|
||||||
|
@@ -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
|
||||||
@@ -46,8 +47,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||||||
|
|
||||||
KThread currentThread = KernelStatic.GetCurrentThread();
|
KThread currentThread = KernelStatic.GetCurrentThread();
|
||||||
|
|
||||||
if (currentThread.ShallBeTerminated ||
|
if (currentThread.TerminationRequested)
|
||||||
currentThread.SchedFlags == ThreadSchedState.TerminationPending)
|
|
||||||
{
|
{
|
||||||
result = KernelResult.ThreadTerminating;
|
result = KernelResult.ThreadTerminating;
|
||||||
}
|
}
|
||||||
@@ -59,7 +59,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 +103,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||||||
handleIndex = index;
|
handleIndex = index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ArrayPool<LinkedListNode<KThread>>.Shared.Return(syncNodesArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
_context.CriticalSection.Leave();
|
_context.CriticalSection.Leave();
|
||||||
|
@@ -99,11 +99,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||||||
|
|
||||||
private int _shallBeTerminated;
|
private int _shallBeTerminated;
|
||||||
|
|
||||||
public bool ShallBeTerminated
|
private bool ShallBeTerminated => _shallBeTerminated != 0;
|
||||||
{
|
|
||||||
get => _shallBeTerminated != 0;
|
|
||||||
set => _shallBeTerminated = value ? 1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TerminationRequested => ShallBeTerminated || SchedFlags == ThreadSchedState.TerminationPending;
|
public bool TerminationRequested => ShallBeTerminated || SchedFlags == ThreadSchedState.TerminationPending;
|
||||||
|
|
||||||
@@ -322,7 +318,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||||||
|
|
||||||
ThreadSchedState result;
|
ThreadSchedState result;
|
||||||
|
|
||||||
if (Interlocked.CompareExchange(ref _shallBeTerminated, 1, 0) == 0)
|
if (Interlocked.Exchange(ref _shallBeTerminated, 1) == 0)
|
||||||
{
|
{
|
||||||
if ((SchedFlags & ThreadSchedState.LowMask) == ThreadSchedState.None)
|
if ((SchedFlags & ThreadSchedState.LowMask) == ThreadSchedState.None)
|
||||||
{
|
{
|
||||||
@@ -470,7 +466,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||||||
{
|
{
|
||||||
KernelContext.CriticalSection.Enter();
|
KernelContext.CriticalSection.Enter();
|
||||||
|
|
||||||
if (ShallBeTerminated || SchedFlags == ThreadSchedState.TerminationPending)
|
if (TerminationRequested)
|
||||||
{
|
{
|
||||||
KernelContext.CriticalSection.Leave();
|
KernelContext.CriticalSection.Leave();
|
||||||
|
|
||||||
@@ -552,7 +548,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||||||
return KernelResult.InvalidState;
|
return KernelResult.InvalidState;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ShallBeTerminated && SchedFlags != ThreadSchedState.TerminationPending)
|
if (!TerminationRequested)
|
||||||
{
|
{
|
||||||
if (pause)
|
if (pause)
|
||||||
{
|
{
|
||||||
|
@@ -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,8 +69,11 @@ 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))
|
||||||
|
{
|
||||||
|
Memory<byte> output = outputOwner.Memory;
|
||||||
|
Memory<byte> performanceOutput = performanceOutputOwner.Memory;
|
||||||
|
|
||||||
using MemoryHandle outputHandle = output.Pin();
|
using MemoryHandle outputHandle = output.Pin();
|
||||||
using MemoryHandle performanceOutputHandle = performanceOutput.Pin();
|
using MemoryHandle performanceOutputHandle = performanceOutput.Pin();
|
||||||
@@ -88,6 +92,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[CommandCmif(5)]
|
[CommandCmif(5)]
|
||||||
// Start()
|
// Start()
|
||||||
|
@@ -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,7 +85,9 @@ 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))
|
||||||
|
{
|
||||||
|
Span<byte> outputParcel = outputParcelOwner.Memory.Span;
|
||||||
|
|
||||||
ResultCode result = OnTransact(binderId, code, flags, inputParcel, outputParcel);
|
ResultCode result = OnTransact(binderId, code, flags, inputParcel, outputParcel);
|
||||||
|
|
||||||
@@ -94,6 +98,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
|||||||
|
|
||||||
return result;
|
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;
|
||||||
|
@@ -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()
|
||||||
|
Reference in New Issue
Block a user