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.Common.Logging;
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
@ -149,12 +150,16 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
state.InUse = false;
|
||||
}
|
||||
|
||||
Memory<VoiceUpdateState>[] voiceUpdateStatesArray = ArrayPool<Memory<VoiceUpdateState>>.Shared.Rent(Constants.VoiceChannelCountMax);
|
||||
|
||||
Span<Memory<VoiceUpdateState>> voiceUpdateStates = voiceUpdateStatesArray.AsSpan(0, Constants.VoiceChannelCountMax);
|
||||
|
||||
// Start processing
|
||||
for (int i = 0; i < context.GetCount(); 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];
|
||||
|
||||
@ -197,6 +202,8 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
}
|
||||
}
|
||||
|
||||
ArrayPool<Memory<VoiceUpdateState>>.Shared.Return(voiceUpdateStatesArray);
|
||||
|
||||
int currentOutputSize = _output.Length;
|
||||
|
||||
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="parameter">The user parameter.</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
|
||||
// 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="mapper">The mapper to use.</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];
|
||||
|
||||
|
@ -7,6 +7,7 @@ using Ryujinx.Ava.UI.Helpers;
|
||||
using Ryujinx.Ava.UI.Windows;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Common.Utilities;
|
||||
using Ryujinx.Ui.Common.Models.Amiibo;
|
||||
using System;
|
||||
@ -42,13 +43,18 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
private bool _showAllAmiibo;
|
||||
private bool _useRandomUuid;
|
||||
private string _usage;
|
||||
|
||||
|
||||
private static readonly AmiiboJsonSerializerContext SerializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
||||
|
||||
public AmiiboWindowViewModel(StyleableWindow owner, string lastScannedAmiiboId, string titleId)
|
||||
{
|
||||
_owner = owner;
|
||||
_httpClient = new HttpClient { Timeout = TimeSpan.FromMilliseconds(5000) };
|
||||
|
||||
_httpClient = new HttpClient
|
||||
{
|
||||
Timeout = TimeSpan.FromSeconds(30)
|
||||
};
|
||||
|
||||
LastScannedAmiiboId = lastScannedAmiiboId;
|
||||
TitleId = titleId;
|
||||
|
||||
@ -89,9 +95,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
{
|
||||
_showAllAmiibo = value;
|
||||
|
||||
#pragma warning disable 4014
|
||||
ParseAmiiboData();
|
||||
#pragma warning restore 4014
|
||||
|
||||
OnPropertyChanged();
|
||||
}
|
||||
@ -203,8 +207,10 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
{
|
||||
amiiboJsonString = await DownloadAmiiboJson();
|
||||
}
|
||||
catch
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application, $"Failed to download amiibo data: {ex}");
|
||||
|
||||
ShowInfoDialog();
|
||||
}
|
||||
}
|
||||
@ -369,8 +375,10 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
|
||||
return false;
|
||||
}
|
||||
catch
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application, $"Failed to check for amiibo updates: {ex}");
|
||||
|
||||
ShowInfoDialog();
|
||||
|
||||
return false;
|
||||
@ -393,6 +401,8 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
return amiiboJsonString;
|
||||
}
|
||||
|
||||
Logger.Error?.Print(LogClass.Application, $"Failed to download amiibo data. Response status code: {response.StatusCode}");
|
||||
|
||||
await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance[LocaleKeys.DialogAmiiboApiTitle],
|
||||
LocaleManager.Instance[LocaleKeys.DialogAmiiboApiFailFetchMessage],
|
||||
LocaleManager.Instance[LocaleKeys.InputDialogOk],
|
||||
@ -429,6 +439,10 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
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()
|
||||
|
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 int StorageBufferOffsetAlignment;
|
||||
|
||||
public readonly int GatherBiasPrecision;
|
||||
|
||||
public Capabilities(
|
||||
TargetApi api,
|
||||
string vendorName,
|
||||
@ -87,7 +89,8 @@ namespace Ryujinx.Graphics.GAL
|
||||
uint maximumImagesPerStage,
|
||||
int maximumComputeSharedMemorySize,
|
||||
float maximumSupportedAnisotropy,
|
||||
int storageBufferOffsetAlignment)
|
||||
int storageBufferOffsetAlignment,
|
||||
int gatherBiasPrecision)
|
||||
{
|
||||
Api = api;
|
||||
VendorName = vendorName;
|
||||
@ -128,6 +131,7 @@ namespace Ryujinx.Graphics.GAL
|
||||
MaximumComputeSharedMemorySize = maximumComputeSharedMemorySize;
|
||||
MaximumSupportedAnisotropy = maximumSupportedAnisotropy;
|
||||
StorageBufferOffsetAlignment = storageBufferOffsetAlignment;
|
||||
GatherBiasPrecision = gatherBiasPrecision;
|
||||
}
|
||||
}
|
||||
}
|
@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||
private const ushort FileFormatVersionMajor = 1;
|
||||
private const ushort FileFormatVersionMinor = 2;
|
||||
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
|
||||
private const uint CodeGenVersion = 4404;
|
||||
private const uint CodeGenVersion = 4707;
|
||||
|
||||
private const string SharedTocFileName = "shared.toc";
|
||||
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 QueryHostHasFrontFacingBug() => _context.Capabilities.HasFrontFacingBug;
|
||||
|
@ -449,7 +449,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
if (translatorContexts[i] != null)
|
||||
{
|
||||
translatorContexts[i].SetGeometryShaderLayerInputAttribute(info.GpLayerInputAttribute);
|
||||
translatorContexts[i].SetLastInVertexPipeline(translatorContexts[5] != null);
|
||||
translatorContexts[i].SetLastInVertexPipeline();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -103,11 +103,14 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
|
||||
public Capabilities GetCapabilities()
|
||||
{
|
||||
bool intelWindows = HwCapabilities.Vendor == HwCapabilities.GpuVendor.IntelWindows;
|
||||
bool amdWindows = HwCapabilities.Vendor == HwCapabilities.GpuVendor.AmdWindows;
|
||||
|
||||
return new Capabilities(
|
||||
api: TargetApi.OpenGL,
|
||||
vendorName: GpuVendor,
|
||||
hasFrontFacingBug: HwCapabilities.Vendor == HwCapabilities.GpuVendor.IntelWindows,
|
||||
hasVectorIndexingBug: HwCapabilities.Vendor == HwCapabilities.GpuVendor.AmdWindows,
|
||||
hasFrontFacingBug: intelWindows,
|
||||
hasVectorIndexingBug: amdWindows,
|
||||
needsFragmentOutputSpecialization: false,
|
||||
reduceShaderPrecision: false,
|
||||
supportsAstcCompression: HwCapabilities.SupportsAstcCompression,
|
||||
@ -142,7 +145,8 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
maximumImagesPerStage: 8,
|
||||
maximumComputeSharedMemorySize: HwCapabilities.MaximumComputeSharedMemorySize,
|
||||
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)
|
||||
|
@ -569,7 +569,23 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
|
||||
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];
|
||||
|
||||
@ -642,7 +658,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
if (context.Config.TransformFeedbackEnabled && context.Config.LastInVertexPipeline)
|
||||
{
|
||||
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)
|
||||
{
|
||||
@ -664,22 +680,20 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
|
||||
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];
|
||||
|
||||
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};");
|
||||
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};");
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -677,7 +677,28 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
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)
|
||||
{
|
||||
|
@ -220,7 +220,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
((config.LastInVertexPipeline && 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}";
|
||||
|
||||
if (AttributeInfo.IsArrayAttributeGlsl(config.Stage, isOutAttr))
|
||||
|
@ -341,7 +341,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
attrOffset = attr;
|
||||
type = elemType;
|
||||
|
||||
if (Config.LastInPipeline && isOutAttr)
|
||||
if (isOutAttr)
|
||||
{
|
||||
int components = Info.GetTransformFeedbackOutputComponents(attr);
|
||||
|
||||
|
@ -673,7 +673,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
int components = 1;
|
||||
var type = attrInfo.Type & AggregateType.ElementTypeMask;
|
||||
|
||||
if (context.Config.LastInPipeline && isOutAttr)
|
||||
if (isOutAttr)
|
||||
{
|
||||
components = context.Info.GetTransformFeedbackOutputComponents(attr);
|
||||
|
||||
|
@ -4,6 +4,7 @@ using Ryujinx.Graphics.Shader.Translation;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
pCoords = ApplyBias(pCoords, image);
|
||||
|
||||
var operands = operandsList.ToArray();
|
||||
|
||||
SpvInstruction result;
|
||||
|
@ -196,6 +196,15 @@ namespace Ryujinx.Graphics.Shader
|
||||
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>
|
||||
/// Queries host about whether to reduce precision to improve performance.
|
||||
/// </summary>
|
||||
|
@ -65,7 +65,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
context.LeaveFunction();
|
||||
}
|
||||
|
||||
if (config.TransformFeedbackEnabled && config.LastInVertexPipeline)
|
||||
if (config.TransformFeedbackEnabled && (config.LastInVertexPipeline || config.Stage == ShaderStage.Fragment))
|
||||
{
|
||||
for (int tfbIndex = 0; tfbIndex < 4; tfbIndex++)
|
||||
{
|
||||
|
@ -17,7 +17,6 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
public ShaderStage Stage { get; }
|
||||
|
||||
public bool GpPassthrough { get; }
|
||||
public bool LastInPipeline { get; private set; }
|
||||
public bool LastInVertexPipeline { get; private set; }
|
||||
|
||||
public bool HasLayerInputAttribute { get; private set; }
|
||||
@ -145,7 +144,6 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
OmapSampleMask = header.OmapSampleMask;
|
||||
OmapDepth = header.OmapDepth;
|
||||
TransformFeedbackEnabled = gpuAccessor.QueryTransformFeedbackEnabled();
|
||||
LastInPipeline = true;
|
||||
LastInVertexPipeline = header.Stage < ShaderStage.Fragment;
|
||||
}
|
||||
|
||||
@ -253,13 +251,8 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
GpLayerInputAttribute = attr;
|
||||
}
|
||||
|
||||
public void SetLastInVertexPipeline(bool hasFragment)
|
||||
public void SetLastInVertexPipeline()
|
||||
{
|
||||
if (!hasFragment)
|
||||
{
|
||||
LastInPipeline = true;
|
||||
}
|
||||
|
||||
LastInVertexPipeline = true;
|
||||
}
|
||||
|
||||
@ -331,8 +324,6 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
config._perPatchAttributeLocations = locationsMap;
|
||||
}
|
||||
|
||||
LastInPipeline = false;
|
||||
|
||||
// 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,
|
||||
// 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);
|
||||
}
|
||||
|
||||
public void SetLastInVertexPipeline(bool hasFragment)
|
||||
public void SetLastInVertexPipeline()
|
||||
{
|
||||
_config.SetLastInVertexPipeline(hasFragment);
|
||||
_config.SetLastInVertexPipeline();
|
||||
}
|
||||
|
||||
public ShaderProgram Translate(TranslatorContext other = null)
|
||||
|
@ -46,6 +46,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
public readonly SampleCountFlags SupportedSampleCounts;
|
||||
public readonly PortabilitySubsetFlags PortabilitySubset;
|
||||
public readonly uint VertexBufferAlignment;
|
||||
public readonly uint SubTexelPrecisionBits;
|
||||
|
||||
public HardwareCapabilities(
|
||||
bool supportsIndexTypeUint8,
|
||||
@ -77,7 +78,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
ShaderStageFlags requiredSubgroupSizeStages,
|
||||
SampleCountFlags supportedSampleCounts,
|
||||
PortabilitySubsetFlags portabilitySubset,
|
||||
uint vertexBufferAlignment)
|
||||
uint vertexBufferAlignment,
|
||||
uint subTexelPrecisionBits)
|
||||
{
|
||||
SupportsIndexTypeUint8 = supportsIndexTypeUint8;
|
||||
SupportsCustomBorderColor = supportsCustomBorderColor;
|
||||
@ -109,6 +111,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
SupportedSampleCounts = supportedSampleCounts;
|
||||
PortabilitySubset = portabilitySubset;
|
||||
VertexBufferAlignment = vertexBufferAlignment;
|
||||
SubTexelPrecisionBits = subTexelPrecisionBits;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -311,7 +311,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
propertiesSubgroupSizeControl.RequiredSubgroupSizeStages,
|
||||
supportedSampleCounts,
|
||||
portabilityFlags,
|
||||
vertexBufferAlignment);
|
||||
vertexBufferAlignment,
|
||||
properties.Limits.SubTexelPrecisionBits);
|
||||
|
||||
IsSharedMemory = MemoryAllocator.IsDeviceMemoryShared(_physicalDevice);
|
||||
|
||||
@ -576,7 +577,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
maximumImagesPerStage: Constants.MaxImagesPerStage,
|
||||
maximumComputeSharedMemorySize: (int)limits.MaxComputeSharedMemorySize,
|
||||
maximumSupportedAnisotropy: (int)limits.MaxSamplerAnisotropy,
|
||||
storageBufferOffsetAlignment: (int)limits.MinStorageBufferOffsetAlignment);
|
||||
storageBufferOffsetAlignment: (int)limits.MinStorageBufferOffsetAlignment,
|
||||
gatherBiasPrecision: IsIntelWindows || IsAmdWindows ? (int)Capabilities.SubTexelPrecisionBits : 0);
|
||||
}
|
||||
|
||||
public HardwareInfo GetHardwareInfo()
|
||||
|
@ -27,98 +27,103 @@ namespace Ryujinx.HLE.HOS.Ipc
|
||||
|
||||
public IpcMessage()
|
||||
{
|
||||
PtrBuff = new List<IpcPtrBuffDesc>();
|
||||
SendBuff = new List<IpcBuffDesc>();
|
||||
ReceiveBuff = new List<IpcBuffDesc>();
|
||||
ExchangeBuff = new List<IpcBuffDesc>();
|
||||
RecvListBuff = new List<IpcRecvListBuffDesc>();
|
||||
PtrBuff = new List<IpcPtrBuffDesc>(0);
|
||||
SendBuff = new List<IpcBuffDesc>(0);
|
||||
ReceiveBuff = new List<IpcBuffDesc>(0);
|
||||
ExchangeBuff = new List<IpcBuffDesc>(0);
|
||||
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))
|
||||
{
|
||||
BinaryReader reader = new BinaryReader(ms);
|
||||
|
||||
Initialize(reader, cmdPtr);
|
||||
}
|
||||
}
|
||||
int word0 = reader.ReadInt32();
|
||||
int word1 = reader.ReadInt32();
|
||||
|
||||
private void Initialize(BinaryReader reader, long cmdPtr)
|
||||
{
|
||||
int word0 = reader.ReadInt32();
|
||||
int word1 = reader.ReadInt32();
|
||||
Type = (IpcMessageType)(word0 & 0xffff);
|
||||
|
||||
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 sendBuffCount = (word0 >> 20) & 0xf;
|
||||
int recvBuffCount = (word0 >> 24) & 0xf;
|
||||
int xchgBuffCount = (word0 >> 28) & 0xf;
|
||||
int rawDataSize = (word1 >> 0) & 0x3ff;
|
||||
int recvListFlags = (word1 >> 10) & 0xf;
|
||||
bool hndDescEnable = ((word1 >> 31) & 0x1) != 0;
|
||||
|
||||
int rawDataSize = (word1 >> 0) & 0x3ff;
|
||||
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++)
|
||||
if (hndDescEnable)
|
||||
{
|
||||
buff.Add(new IpcBuffDesc(reader));
|
||||
HandleDesc = new IpcHandleDesc(reader);
|
||||
}
|
||||
}
|
||||
|
||||
ReadBuff(SendBuff, sendBuffCount);
|
||||
ReadBuff(ReceiveBuff, recvBuffCount);
|
||||
ReadBuff(ExchangeBuff, xchgBuffCount);
|
||||
PtrBuff = new List<IpcPtrBuffDesc>(ptrBuffCount);
|
||||
|
||||
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.
|
||||
if (Type < IpcMessageType.TipcCloseSession)
|
||||
{
|
||||
long pad0 = GetPadSize16(reader.BaseStream.Position + cmdPtr);
|
||||
|
||||
if (rawDataSize != 0)
|
||||
{
|
||||
rawDataSize -= (int)pad0;
|
||||
if (rawDataSize != 0)
|
||||
{
|
||||
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)
|
||||
{
|
||||
recvListCount = 1;
|
||||
}
|
||||
else if (recvListCount < 0)
|
||||
{
|
||||
recvListCount = 0;
|
||||
}
|
||||
RawData = reader.ReadBytes(rawDataSize);
|
||||
|
||||
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++)
|
||||
{
|
||||
RecvListBuff.Add(new IpcRecvListBuffDesc(reader.ReadUInt64()));
|
||||
for (int index = 0; index < recvListCount; index++)
|
||||
{
|
||||
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)
|
||||
{
|
||||
_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
|
||||
{
|
||||
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)
|
||||
{
|
||||
Thread.Yield();
|
||||
|
||||
spinWait.Reset();
|
||||
}
|
||||
|
||||
spinWait.SpinOnce();
|
||||
else
|
||||
{
|
||||
spinWait.SpinOnce();
|
||||
}
|
||||
}
|
||||
|
||||
spinWait.Reset();
|
||||
|
@ -9,6 +9,7 @@ using Ryujinx.HLE.HOS.Kernel.Process;
|
||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
using Ryujinx.Horizon.Common;
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Threading;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||
@ -553,7 +554,9 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||
|
||||
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++)
|
||||
{
|
||||
@ -606,6 +609,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||
}
|
||||
}
|
||||
|
||||
ArrayPool<KSynchronizationObject>.Shared.Return(syncObjsArray);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||
using Ryujinx.Horizon.Common;
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||
@ -59,7 +60,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||
}
|
||||
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++)
|
||||
{
|
||||
@ -101,6 +104,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||
handleIndex = index;
|
||||
}
|
||||
}
|
||||
|
||||
ArrayPool<LinkedListNode<KThread>>.Shared.Return(syncNodesArray);
|
||||
}
|
||||
|
||||
_context.CriticalSection.Leave();
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
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();
|
||||
|
||||
Memory<byte> output = new byte[outputSize];
|
||||
Memory<byte> performanceOutput = new byte[performanceOutputSize];
|
||||
|
||||
using MemoryHandle outputHandle = output.Pin();
|
||||
using MemoryHandle performanceOutputHandle = performanceOutput.Pin();
|
||||
|
||||
ResultCode result = _impl.RequestUpdate(output, performanceOutput, input);
|
||||
|
||||
if (result == ResultCode.Success)
|
||||
using (IMemoryOwner<byte> outputOwner = ByteMemoryPool.Shared.RentCleared(outputSize))
|
||||
using (IMemoryOwner<byte> performanceOutputOwner = ByteMemoryPool.Shared.RentCleared(performanceOutputSize))
|
||||
{
|
||||
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}");
|
||||
}
|
||||
Memory<byte> output = outputOwner.Memory;
|
||||
Memory<byte> performanceOutput = performanceOutputOwner.Memory;
|
||||
|
||||
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)]
|
||||
|
@ -76,6 +76,8 @@ namespace Ryujinx.HLE.HOS.Services
|
||||
|
||||
context.RequestData.BaseStream.Seek(0x10 + dataPayloadSize, SeekOrigin.Begin);
|
||||
|
||||
context.Request.ObjectIds.EnsureCapacity(inputObjCount);
|
||||
|
||||
for (int index = 0; index < inputObjCount; index++)
|
||||
{
|
||||
context.Request.ObjectIds.Add(context.RequestData.ReadInt32());
|
||||
|
@ -217,6 +217,8 @@ namespace Ryujinx.HLE.HOS.Services
|
||||
|
||||
if (noReceive)
|
||||
{
|
||||
response.PtrBuff.EnsureCapacity(request.RecvListBuff.Count);
|
||||
|
||||
for (int i = 0; i < request.RecvListBuff.Count; i++)
|
||||
{
|
||||
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.Horizon.Common;
|
||||
using System;
|
||||
using System.Buffers;
|
||||
|
||||
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);
|
||||
|
||||
Span<byte> outputParcel = new Span<byte>(new byte[replySize]);
|
||||
|
||||
ResultCode result = OnTransact(binderId, code, flags, inputParcel, outputParcel);
|
||||
|
||||
if (result == ResultCode.Success)
|
||||
using (IMemoryOwner<byte> outputParcelOwner = ByteMemoryPool.Shared.RentCleared(replySize))
|
||||
{
|
||||
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);
|
||||
|
@ -12,17 +12,7 @@ namespace Ryujinx.Input.SDL2
|
||||
{
|
||||
private bool HasConfiguration => _configuration != null;
|
||||
|
||||
private class ButtonMappingEntry
|
||||
{
|
||||
public readonly GamepadButtonInputId To;
|
||||
public readonly GamepadButtonInputId From;
|
||||
|
||||
public ButtonMappingEntry(GamepadButtonInputId to, GamepadButtonInputId from)
|
||||
{
|
||||
To = to;
|
||||
From = from;
|
||||
}
|
||||
}
|
||||
private record struct ButtonMappingEntry(GamepadButtonInputId To, GamepadButtonInputId From);
|
||||
|
||||
private StandardControllerInputConfig _configuration;
|
||||
|
||||
@ -85,7 +75,7 @@ namespace Ryujinx.Input.SDL2
|
||||
public SDL2Gamepad(IntPtr gamepadHandle, string driverId)
|
||||
{
|
||||
_gamepadHandle = gamepadHandle;
|
||||
_buttonsUserMapping = new List<ButtonMappingEntry>();
|
||||
_buttonsUserMapping = new List<ButtonMappingEntry>(20);
|
||||
|
||||
Name = SDL_GameControllerName(_gamepadHandle);
|
||||
Id = driverId;
|
||||
|
@ -12,7 +12,6 @@ namespace Ryujinx.Input
|
||||
public Vector3 Rotation { get; set; }
|
||||
|
||||
private readonly MotionSensorFilter _filter;
|
||||
private int _calibrationFrame = 0;
|
||||
|
||||
public MotionInput()
|
||||
{
|
||||
@ -29,26 +28,6 @@ namespace Ryujinx.Input
|
||||
{
|
||||
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;
|
||||
|
||||
if (gyro.Length() < deadzone)
|
||||
|
@ -96,6 +96,8 @@ namespace Ryujinx
|
||||
// Delete backup files after updating.
|
||||
Task.Run(Updater.CleanupUpdate);
|
||||
|
||||
Console.Title = $"Ryujinx Console {Version}";
|
||||
|
||||
// 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).
|
||||
if (OperatingSystem.IsLinux())
|
||||
|
@ -1,6 +1,7 @@
|
||||
using Gtk;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Common.Utilities;
|
||||
using Ryujinx.Ui.Common.Configuration;
|
||||
using Ryujinx.Ui.Common.Models.Amiibo;
|
||||
@ -12,7 +13,6 @@ using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using AmiiboApi = Ryujinx.Ui.Common.Models.Amiibo.AmiiboApi;
|
||||
using AmiiboJsonSerializerContext = Ryujinx.Ui.Common.Models.Amiibo.AmiiboJsonSerializerContext;
|
||||
@ -57,7 +57,7 @@ namespace Ryujinx.Ui.Windows
|
||||
|
||||
_httpClient = new HttpClient()
|
||||
{
|
||||
Timeout = TimeSpan.FromMilliseconds(5000)
|
||||
Timeout = TimeSpan.FromSeconds(30)
|
||||
};
|
||||
|
||||
Directory.CreateDirectory(System.IO.Path.Join(AppDataManager.BaseDirPath, "system", "amiibo"));
|
||||
@ -93,8 +93,10 @@ namespace Ryujinx.Ui.Windows
|
||||
{
|
||||
amiiboJsonString = await DownloadAmiiboJson();
|
||||
}
|
||||
catch
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application, $"Failed to download amiibo data: {ex}");
|
||||
|
||||
ShowInfoDialog();
|
||||
|
||||
Close();
|
||||
@ -183,8 +185,10 @@ namespace Ryujinx.Ui.Windows
|
||||
|
||||
return false;
|
||||
}
|
||||
catch
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application, $"Failed to check for amiibo updates: {ex}");
|
||||
|
||||
ShowInfoDialog();
|
||||
|
||||
return false;
|
||||
@ -208,6 +212,8 @@ namespace Ryujinx.Ui.Windows
|
||||
}
|
||||
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.");
|
||||
|
||||
Close();
|
||||
@ -233,6 +239,10 @@ namespace Ryujinx.Ui.Windows
|
||||
|
||||
_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()
|
||||
@ -374,4 +384,4 @@ namespace Ryujinx.Ui.Windows
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user