Compare commits

...

3 Commits

Author SHA1 Message Date
Emmanuel Hansen
bc5bb4459e Fix deadlock in mouse input on Avalonia (#3444)
* fix deadlock in mouse input

* apply @AcK77 changes
2022-07-08 09:53:48 -03:00
gdkchan
55e97959b9 Fix Vi managed and stray layers open/close/destroy (#3438)
* Fix Vi managed and stray layers open/close/destroy

* OpenLayer should set the state to ManagedOpened
2022-07-06 13:37:36 -03:00
gdkchan
f7ef6364b7 Implement CPU FCVT Half <-> Double conversion variants (#3439)
* Half <-> Double conversion support

* Add tests, fast path and deduplicate SoftFloat code

* PPTC version
2022-07-06 13:40:31 +02:00
11 changed files with 877 additions and 466 deletions

View File

@@ -105,11 +105,48 @@ namespace ARMeilleure.Instructions
} }
else if (op.Size == 1 && op.Opc == 3) // Double -> Half. else if (op.Size == 1 && op.Opc == 3) // Double -> Half.
{ {
throw new NotImplementedException("Double-precision to half-precision."); if (Optimizations.UseF16c)
{
Debug.Assert(!Optimizations.ForceLegacySse);
Operand n = GetVec(op.Rn);
Operand res = context.AddIntrinsic(Intrinsic.X86Cvtsd2ss, context.VectorZero(), n);
res = context.AddIntrinsic(Intrinsic.X86Vcvtps2ph, res, Const(X86GetRoundControl(FPRoundingMode.ToNearest)));
context.Copy(GetVec(op.Rd), res);
}
else
{
Operand ne = context.VectorExtract(OperandType.FP64, GetVec(op.Rn), 0);
Operand res = context.Call(typeof(SoftFloat64_16).GetMethod(nameof(SoftFloat64_16.FPConvert)), ne);
res = context.ZeroExtend16(OperandType.I64, res);
context.Copy(GetVec(op.Rd), EmitVectorInsert(context, context.VectorZero(), res, 0, 1));
}
} }
else if (op.Size == 3 && op.Opc == 1) // Double -> Half. else if (op.Size == 3 && op.Opc == 1) // Half -> Double.
{ {
throw new NotImplementedException("Half-precision to double-precision."); if (Optimizations.UseF16c)
{
Operand n = GetVec(op.Rn);
Operand res = context.AddIntrinsic(Intrinsic.X86Vcvtph2ps, GetVec(op.Rn));
res = context.AddIntrinsic(Intrinsic.X86Cvtss2sd, context.VectorZero(), res);
res = context.VectorZeroUpper64(res);
context.Copy(GetVec(op.Rd), res);
}
else
{
Operand ne = EmitVectorExtractZx(context, op.Rn, 0, 1);
Operand res = context.Call(typeof(SoftFloat16_64).GetMethod(nameof(SoftFloat16_64.FPConvert)), ne);
context.Copy(GetVec(op.Rd), context.VectorInsert(context.VectorZero(), res, 0));
}
} }
else // Invalid encoding. else // Invalid encoding.
{ {

File diff suppressed because it is too large Load Diff

View File

@@ -206,6 +206,7 @@ namespace ARMeilleure.Translation
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedSrcUnsignedDstSatQ))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedSrcUnsignedDstSatQ)));
SetDelegateInfo(typeof(SoftFloat16_32).GetMethod(nameof(SoftFloat16_32.FPConvert))); SetDelegateInfo(typeof(SoftFloat16_32).GetMethod(nameof(SoftFloat16_32.FPConvert)));
SetDelegateInfo(typeof(SoftFloat16_64).GetMethod(nameof(SoftFloat16_64.FPConvert)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPAdd))); SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPAdd)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPAddFpscr))); // A32 only. SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPAddFpscr))); // A32 only.
@@ -294,6 +295,8 @@ namespace ARMeilleure.Translation
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtStepFused))); SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtStepFused)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPSqrt))); SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPSqrt)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPSub))); SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPSub)));
SetDelegateInfo(typeof(SoftFloat64_16).GetMethod(nameof(SoftFloat64_16.FPConvert)));
} }
} }
} }

View File

@@ -27,7 +27,7 @@ namespace ARMeilleure.Translation.PTC
private const string OuterHeaderMagicString = "PTCohd\0\0"; private const string OuterHeaderMagicString = "PTCohd\0\0";
private const string InnerHeaderMagicString = "PTCihd\0\0"; private const string InnerHeaderMagicString = "PTCihd\0\0";
private const uint InternalVersion = 3362; //! To be incremented manually for each change to the ARMeilleure project. private const uint InternalVersion = 3439; //! To be incremented manually for each change to the ARMeilleure project.
private const string ActualDir = "0"; private const string ActualDir = "0";
private const string BackupDir = "1"; private const string BackupDir = "1";

View File

@@ -1,3 +1,4 @@
using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Threading; using Avalonia.Threading;
@@ -13,6 +14,7 @@ namespace Ryujinx.Ava.Input
{ {
private Control _widget; private Control _widget;
private bool _isDisposed; private bool _isDisposed;
private Size _size;
public bool[] PressedButtons { get; } public bool[] PressedButtons { get; }
@@ -29,6 +31,14 @@ namespace Ryujinx.Ava.Input
_widget.PointerWheelChanged += Parent_ScrollEvent; _widget.PointerWheelChanged += Parent_ScrollEvent;
PressedButtons = new bool[(int)MouseButton.Count]; PressedButtons = new bool[(int)MouseButton.Count];
_size = new Size((int)parent.Bounds.Width, (int)parent.Bounds.Height);
parent.GetObservable(Control.BoundsProperty).Subscribe(Resized);
}
private void Resized(Rect rect)
{
_size = new Size((int)rect.Width, (int)rect.Height);
} }
private void Parent_ScrollEvent(object o, PointerWheelEventArgs args) private void Parent_ScrollEvent(object o, PointerWheelEventArgs args)
@@ -78,14 +88,7 @@ namespace Ryujinx.Ava.Input
public Size GetClientSize() public Size GetClientSize()
{ {
Size size = new(); return _size;
Dispatcher.UIThread.InvokeAsync(() =>
{
size = new Size((int)_widget.Bounds.Width, (int)_widget.Bounds.Height);
}).Wait();
return size;
} }
public string DriverName => "Avalonia"; public string DriverName => "Avalonia";

View File

@@ -217,7 +217,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
// CreateManagedDisplayLayer() -> u64 // CreateManagedDisplayLayer() -> u64
public ResultCode CreateManagedDisplayLayer(ServiceCtx context) public ResultCode CreateManagedDisplayLayer(ServiceCtx context)
{ {
context.Device.System.SurfaceFlinger.CreateLayer(_pid, out long layerId); context.Device.System.SurfaceFlinger.CreateLayer(out long layerId, _pid);
context.Device.System.SurfaceFlinger.SetRenderLayer(layerId); context.Device.System.SurfaceFlinger.SetRenderLayer(layerId);
context.ResponseData.Write(layerId); context.ResponseData.Write(layerId);
@@ -238,8 +238,8 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
// CreateManagedDisplaySeparableLayer() -> (u64, u64) // CreateManagedDisplaySeparableLayer() -> (u64, u64)
public ResultCode CreateManagedDisplaySeparableLayer(ServiceCtx context) public ResultCode CreateManagedDisplaySeparableLayer(ServiceCtx context)
{ {
context.Device.System.SurfaceFlinger.CreateLayer(_pid, out long displayLayerId); context.Device.System.SurfaceFlinger.CreateLayer(out long displayLayerId, _pid);
context.Device.System.SurfaceFlinger.CreateLayer(_pid, out long recordingLayerId); context.Device.System.SurfaceFlinger.CreateLayer(out long recordingLayerId, _pid);
context.Device.System.SurfaceFlinger.SetRenderLayer(displayLayerId); context.Device.System.SurfaceFlinger.SetRenderLayer(displayLayerId);
context.ResponseData.Write(displayLayerId); context.ResponseData.Write(displayLayerId);

View File

@@ -0,0 +1,10 @@
namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
{
enum LayerState
{
NotInitialized,
ManagedClosed,
ManagedOpened,
Stray
}
}

View File

@@ -11,6 +11,8 @@ using System.Threading;
namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
{ {
using ResultCode = Ryujinx.HLE.HOS.Services.Vi.ResultCode;
class SurfaceFlinger : IConsumerListener, IDisposable class SurfaceFlinger : IConsumerListener, IDisposable
{ {
private const int TargetFps = 60; private const int TargetFps = 60;
@@ -45,6 +47,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
public BufferItemConsumer Consumer; public BufferItemConsumer Consumer;
public BufferQueueCore Core; public BufferQueueCore Core;
public ulong Owner; public ulong Owner;
public LayerState State;
} }
private class TextureCallbackInformation private class TextureCallbackInformation
@@ -92,24 +95,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
} }
} }
public IGraphicBufferProducer OpenLayer(ulong pid, long layerId) public IGraphicBufferProducer CreateLayer(out long layerId, ulong pid, LayerState initialState = LayerState.ManagedClosed)
{
bool needCreate;
lock (Lock)
{
needCreate = GetLayerByIdLocked(layerId) == null;
}
if (needCreate)
{
CreateLayerFromId(pid, layerId);
}
return GetProducerByLayerId(layerId);
}
public IGraphicBufferProducer CreateLayer(ulong pid, out long layerId)
{ {
layerId = 1; layerId = 1;
@@ -124,12 +110,12 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
} }
} }
CreateLayerFromId(pid, layerId); CreateLayerFromId(pid, layerId, initialState);
return GetProducerByLayerId(layerId); return GetProducerByLayerId(layerId);
} }
private void CreateLayerFromId(ulong pid, long layerId) private void CreateLayerFromId(ulong pid, long layerId, LayerState initialState)
{ {
lock (Lock) lock (Lock)
{ {
@@ -148,39 +134,129 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
Producer = producer, Producer = producer,
Consumer = new BufferItemConsumer(_device, consumer, 0, -1, false, this), Consumer = new BufferItemConsumer(_device, consumer, 0, -1, false, this),
Core = core, Core = core,
Owner = pid Owner = pid,
State = initialState
}); });
} }
} }
public bool CloseLayer(long layerId) public ResultCode OpenLayer(ulong pid, long layerId, out IBinder producer)
{
Layer layer = GetLayerByIdLocked(layerId);
if (layer == null || layer.State != LayerState.ManagedClosed)
{
producer = null;
return ResultCode.InvalidArguments;
}
layer.State = LayerState.ManagedOpened;
producer = layer.Producer;
return ResultCode.Success;
}
public ResultCode CloseLayer(long layerId)
{ {
lock (Lock) lock (Lock)
{ {
Layer layer = GetLayerByIdLocked(layerId); Layer layer = GetLayerByIdLocked(layerId);
if (layer != null) if (layer == null)
{ {
HOSBinderDriverServer.UnregisterBinderObject(layer.ProducerBinderId); Logger.Error?.Print(LogClass.SurfaceFlinger, $"Failed to close layer {layerId}");
return ResultCode.InvalidValue;
} }
bool removed = _layers.Remove(layerId); CloseLayer(layerId, layer);
// If the layer was removed and the current in use, we need to change the current layer in use. return ResultCode.Success;
if (removed && RenderLayerId == layerId) }
}
public ResultCode DestroyManagedLayer(long layerId)
{
lock (Lock)
{
Layer layer = GetLayerByIdLocked(layerId);
if (layer == null)
{ {
// If no layer is availaible, reset to default value. Logger.Error?.Print(LogClass.SurfaceFlinger, $"Failed to destroy managed layer {layerId} (not found)");
if (_layers.Count == 0)
{ return ResultCode.InvalidValue;
SetRenderLayer(0);
}
else
{
SetRenderLayer(_layers.Last().Key);
}
} }
return removed; if (layer.State != LayerState.ManagedClosed && layer.State != LayerState.ManagedOpened)
{
Logger.Error?.Print(LogClass.SurfaceFlinger, $"Failed to destroy managed layer {layerId} (permission denied)");
return ResultCode.PermissionDenied;
}
HOSBinderDriverServer.UnregisterBinderObject(layer.ProducerBinderId);
if (_layers.Remove(layerId) && layer.State == LayerState.ManagedOpened)
{
CloseLayer(layerId, layer);
}
return ResultCode.Success;
}
}
public ResultCode DestroyStrayLayer(long layerId)
{
lock (Lock)
{
Layer layer = GetLayerByIdLocked(layerId);
if (layer == null)
{
Logger.Error?.Print(LogClass.SurfaceFlinger, $"Failed to destroy stray layer {layerId} (not found)");
return ResultCode.InvalidValue;
}
if (layer.State != LayerState.Stray)
{
Logger.Error?.Print(LogClass.SurfaceFlinger, $"Failed to destroy stray layer {layerId} (permission denied)");
return ResultCode.PermissionDenied;
}
HOSBinderDriverServer.UnregisterBinderObject(layer.ProducerBinderId);
if (_layers.Remove(layerId))
{
CloseLayer(layerId, layer);
}
return ResultCode.Success;
}
}
private void CloseLayer(long layerId, Layer layer)
{
// If the layer was removed and the current in use, we need to change the current layer in use.
if (RenderLayerId == layerId)
{
// If no layer is availaible, reset to default value.
if (_layers.Count == 0)
{
SetRenderLayer(0);
}
else
{
SetRenderLayer(_layers.Last().Key);
}
}
if (layer.State == LayerState.ManagedOpened)
{
layer.State = LayerState.ManagedClosed;
} }
} }

View File

@@ -35,7 +35,7 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService.ApplicationDisplayService
ulong pid = context.Device.System.AppletState.AppletResourceUserIds.GetData<ulong>((int)appletResourceUserId); ulong pid = context.Device.System.AppletState.AppletResourceUserIds.GetData<ulong>((int)appletResourceUserId);
context.Device.System.SurfaceFlinger.CreateLayer(pid, out long layerId); context.Device.System.SurfaceFlinger.CreateLayer(out long layerId, pid);
context.Device.System.SurfaceFlinger.SetRenderLayer(layerId); context.Device.System.SurfaceFlinger.SetRenderLayer(layerId);
context.ResponseData.Write(layerId); context.ResponseData.Write(layerId);
@@ -49,9 +49,7 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService.ApplicationDisplayService
{ {
long layerId = context.RequestData.ReadInt64(); long layerId = context.RequestData.ReadInt64();
context.Device.System.SurfaceFlinger.CloseLayer(layerId); return context.Device.System.SurfaceFlinger.DestroyManagedLayer(layerId);
return ResultCode.Success;
} }
[CommandHipc(2012)] // 7.0.0+ [CommandHipc(2012)] // 7.0.0+

View File

@@ -237,7 +237,12 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService
long userId = context.RequestData.ReadInt64(); long userId = context.RequestData.ReadInt64();
ulong parcelPtr = context.Request.ReceiveBuff[0].Position; ulong parcelPtr = context.Request.ReceiveBuff[0].Position;
IBinder producer = context.Device.System.SurfaceFlinger.OpenLayer(context.Request.HandleDesc.PId, layerId); ResultCode result = context.Device.System.SurfaceFlinger.OpenLayer(context.Request.HandleDesc.PId, layerId, out IBinder producer);
if (result != ResultCode.Success)
{
return result;
}
context.Device.System.SurfaceFlinger.SetRenderLayer(layerId); context.Device.System.SurfaceFlinger.SetRenderLayer(layerId);
@@ -260,9 +265,7 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService
{ {
long layerId = context.RequestData.ReadInt64(); long layerId = context.RequestData.ReadInt64();
context.Device.System.SurfaceFlinger.CloseLayer(layerId); return context.Device.System.SurfaceFlinger.CloseLayer(layerId);
return ResultCode.Success;
} }
[CommandHipc(2030)] [CommandHipc(2030)]
@@ -275,7 +278,7 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService
ulong parcelPtr = context.Request.ReceiveBuff[0].Position; ulong parcelPtr = context.Request.ReceiveBuff[0].Position;
// TODO: support multi display. // TODO: support multi display.
IBinder producer = context.Device.System.SurfaceFlinger.CreateLayer(0, out long layerId); IBinder producer = context.Device.System.SurfaceFlinger.CreateLayer(out long layerId, 0, LayerState.Stray);
context.Device.System.SurfaceFlinger.SetRenderLayer(layerId); context.Device.System.SurfaceFlinger.SetRenderLayer(layerId);
@@ -299,9 +302,7 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService
{ {
long layerId = context.RequestData.ReadInt64(); long layerId = context.RequestData.ReadInt64();
context.Device.System.SurfaceFlinger.CloseLayer(layerId); return context.Device.System.SurfaceFlinger.DestroyStrayLayer(layerId);
return ResultCode.Success;
} }
[CommandHipc(2101)] [CommandHipc(2101)]

View File

@@ -825,6 +825,14 @@ namespace Ryujinx.Tests.Cpu
}; };
} }
private static uint[] _F_Cvt_S_DH_()
{
return new uint[]
{
0x1E63C020u // FCVT H0, D1
};
}
private static uint[] _F_Cvt_S_HS_() private static uint[] _F_Cvt_S_HS_()
{ {
return new uint[] return new uint[]
@@ -833,6 +841,14 @@ namespace Ryujinx.Tests.Cpu
}; };
} }
private static uint[] _F_Cvt_S_HD_()
{
return new uint[]
{
0x1EE2C020u // FCVT D0, H1
};
}
private static uint[] _F_Cvt_ANZ_SU_S_S_() private static uint[] _F_Cvt_ANZ_SU_S_S_()
{ {
return new uint[] return new uint[]
@@ -1998,6 +2014,22 @@ namespace Ryujinx.Tests.Cpu
CompareAgainstUnicorn(); CompareAgainstUnicorn();
} }
[Test, Pairwise] [Explicit]
public void F_Cvt_S_DH([ValueSource("_F_Cvt_S_DH_")] uint opcodes,
[ValueSource("_1D_F_")] ulong a,
[Values(RMode.Rn)] RMode rMode)
{
ulong z = TestContext.CurrentContext.Random.NextULong();
V128 v0 = MakeVectorE0E1(z, z);
V128 v1 = MakeVectorE0(a);
int fpcr = (int)rMode << (int)Fpcr.RMode;
SingleOpcode(opcodes, v0: v0, v1: v1, fpcr: fpcr);
CompareAgainstUnicorn();
}
[Test, Pairwise] [Explicit] [Test, Pairwise] [Explicit]
public void F_Cvt_S_HS([ValueSource("_F_Cvt_S_HS_")] uint opcodes, public void F_Cvt_S_HS([ValueSource("_F_Cvt_S_HS_")] uint opcodes,
[ValueSource("_1H_F_")] ulong a) [ValueSource("_1H_F_")] ulong a)
@@ -2011,6 +2043,19 @@ namespace Ryujinx.Tests.Cpu
CompareAgainstUnicorn(); CompareAgainstUnicorn();
} }
[Test, Pairwise] [Explicit]
public void F_Cvt_S_HD([ValueSource("_F_Cvt_S_HD_")] uint opcodes,
[ValueSource("_1H_F_")] ulong a)
{
ulong z = TestContext.CurrentContext.Random.NextULong();
V128 v0 = MakeVectorE0E1(z, z);
V128 v1 = MakeVectorE0(a);
SingleOpcode(opcodes, v0: v0, v1: v1);
CompareAgainstUnicorn();
}
[Test, Pairwise] [Explicit] [Test, Pairwise] [Explicit]
public void F_Cvt_ANZ_SU_S_S([ValueSource("_F_Cvt_ANZ_SU_S_S_")] uint opcodes, public void F_Cvt_ANZ_SU_S_S([ValueSource("_F_Cvt_ANZ_SU_S_S_")] uint opcodes,
[ValueSource("_1S_F_W_")] ulong a) [ValueSource("_1S_F_W_")] ulong a)