Compare commits

..

5 Commits

Author SHA1 Message Date
38275f9056 Change vsync signal to happen at 60hz, regardless of swap interval (#3642)
* Change vsync signal to happen at 60hz, regardless of swap interval

* Update Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs

Co-authored-by: gdkchan <gab.dark.100@gmail.com>

* Fix softlock when toggling vsync

Co-authored-by: gdkchan <gab.dark.100@gmail.com>
2022-09-01 17:57:50 -03:00
67cbdc3a6a bsd: Fix Poll(0) returning ETIMEDOUT instead of SUCCESS
This was an oversight of the implementation.
2022-09-01 21:46:11 +02:00
131b43170e sfdsnres: fix endianess issue for port serialisation 2022-09-01 21:31:20 +02:00
730d2f4b9b Address gdkchan's comment 2022-08-31 21:33:03 +02:00
f6a7309b14 account: Implement LoadNetworkServiceLicenseKindAsync
This is needed to run Pokemon Legends Arceus 1.1.1 with guest internet enabled.

The game still get stuck at loading screen.
2022-08-31 21:33:03 +02:00
9 changed files with 116 additions and 25 deletions

View File

@ -57,5 +57,19 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc.AccountService
{ {
return _managerServer.StoreOpenContext(context); return _managerServer.StoreOpenContext(context);
} }
[CommandHipc(170)] // 6.0.0+
// LoadNetworkServiceLicenseKindAsync() -> object<nn::account::detail::IAsyncNetworkServiceLicenseKindContext>
public ResultCode LoadNetworkServiceLicenseKindAsync(ServiceCtx context)
{
ResultCode resultCode = _managerServer.LoadNetworkServiceLicenseKindAsync(context, out IAsyncNetworkServiceLicenseKindContext asyncContext);
if (resultCode == ResultCode.Success)
{
MakeObject(context, asyncContext);
}
return resultCode;
}
} }
} }

View File

@ -166,5 +166,22 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc.AccountService
return ResultCode.Success; return ResultCode.Success;
} }
public ResultCode LoadNetworkServiceLicenseKindAsync(ServiceCtx context, out IAsyncNetworkServiceLicenseKindContext asyncContext)
{
KEvent asyncEvent = new KEvent(context.Device.System.KernelContext);
AsyncExecution asyncExecution = new AsyncExecution(asyncEvent);
Logger.Stub?.PrintStub(LogClass.ServiceAcc);
// NOTE: This is an extension of the data retrieved from the id token cache.
asyncExecution.Initialize(1000, EnsureIdTokenCacheAsyncImpl);
asyncContext = new IAsyncNetworkServiceLicenseKindContext(asyncExecution, NetworkServiceLicenseKind.Subscribed);
// return ResultCode.NullObject if the IAsyncNetworkServiceLicenseKindContext pointer is null. Doesn't occur in our case.
return ResultCode.Success;
}
} }
} }

View File

@ -7,18 +7,18 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
{ {
class IAsyncContext : IpcService class IAsyncContext : IpcService
{ {
AsyncExecution _asyncExecution; protected AsyncExecution AsyncExecution;
public IAsyncContext(AsyncExecution asyncExecution) public IAsyncContext(AsyncExecution asyncExecution)
{ {
_asyncExecution = asyncExecution; AsyncExecution = asyncExecution;
} }
[CommandHipc(0)] [CommandHipc(0)]
// GetSystemEvent() -> handle<copy> // GetSystemEvent() -> handle<copy>
public ResultCode GetSystemEvent(ServiceCtx context) public ResultCode GetSystemEvent(ServiceCtx context)
{ {
if (context.Process.HandleTable.GenerateHandle(_asyncExecution.SystemEvent.ReadableEvent, out int _systemEventHandle) != KernelResult.Success) if (context.Process.HandleTable.GenerateHandle(AsyncExecution.SystemEvent.ReadableEvent, out int _systemEventHandle) != KernelResult.Success)
{ {
throw new InvalidOperationException("Out of handles!"); throw new InvalidOperationException("Out of handles!");
} }
@ -32,14 +32,14 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
// Cancel() // Cancel()
public ResultCode Cancel(ServiceCtx context) public ResultCode Cancel(ServiceCtx context)
{ {
if (!_asyncExecution.IsInitialized) if (!AsyncExecution.IsInitialized)
{ {
return ResultCode.AsyncExecutionNotInitialized; return ResultCode.AsyncExecutionNotInitialized;
} }
if (_asyncExecution.IsRunning) if (AsyncExecution.IsRunning)
{ {
_asyncExecution.Cancel(); AsyncExecution.Cancel();
} }
return ResultCode.Success; return ResultCode.Success;
@ -49,12 +49,12 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
// HasDone() -> b8 // HasDone() -> b8
public ResultCode HasDone(ServiceCtx context) public ResultCode HasDone(ServiceCtx context)
{ {
if (!_asyncExecution.IsInitialized) if (!AsyncExecution.IsInitialized)
{ {
return ResultCode.AsyncExecutionNotInitialized; return ResultCode.AsyncExecutionNotInitialized;
} }
context.ResponseData.Write(_asyncExecution.SystemEvent.ReadableEvent.IsSignaled()); context.ResponseData.Write(AsyncExecution.SystemEvent.ReadableEvent.IsSignaled());
return ResultCode.Success; return ResultCode.Success;
} }
@ -63,12 +63,12 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
// GetResult() // GetResult()
public ResultCode GetResult(ServiceCtx context) public ResultCode GetResult(ServiceCtx context)
{ {
if (!_asyncExecution.IsInitialized) if (!AsyncExecution.IsInitialized)
{ {
return ResultCode.AsyncExecutionNotInitialized; return ResultCode.AsyncExecutionNotInitialized;
} }
if (!_asyncExecution.SystemEvent.ReadableEvent.IsSignaled()) if (!AsyncExecution.SystemEvent.ReadableEvent.IsSignaled())
{ {
return ResultCode.Unknown41; return ResultCode.Unknown41;
} }

View File

@ -0,0 +1,38 @@
using Ryujinx.HLE.HOS.Services.Account.Acc.AsyncContext;
namespace Ryujinx.HLE.HOS.Services.Account.Acc
{
class IAsyncNetworkServiceLicenseKindContext : IAsyncContext
{
private NetworkServiceLicenseKind? _serviceLicenseKind;
public IAsyncNetworkServiceLicenseKindContext(AsyncExecution asyncExecution, NetworkServiceLicenseKind? serviceLicenseKind) : base(asyncExecution)
{
_serviceLicenseKind = serviceLicenseKind;
}
[CommandHipc(100)]
// GetNetworkServiceLicenseKind() -> nn::account::NetworkServiceLicenseKind
public ResultCode GetNetworkServiceLicenseKind(ServiceCtx context)
{
if (!AsyncExecution.IsInitialized)
{
return ResultCode.AsyncExecutionNotInitialized;
}
if (!AsyncExecution.SystemEvent.ReadableEvent.IsSignaled())
{
return ResultCode.Unknown41;
}
if (!_serviceLicenseKind.HasValue)
{
return ResultCode.MissingNetworkServiceLicenseKind;
}
context.ResponseData.Write((uint)_serviceLicenseKind.Value);
return ResultCode.Success;
}
}
}

View File

@ -0,0 +1,8 @@
namespace Ryujinx.HLE.HOS.Services.Account.Acc
{
enum NetworkServiceLicenseKind : uint
{
NoSubscription,
Subscribed
}
}

View File

@ -18,6 +18,7 @@ namespace Ryujinx.HLE.HOS.Services.Account
UserNotFound = (100 << ErrorCodeShift) | ModuleId, UserNotFound = (100 << ErrorCodeShift) | ModuleId,
NullObject = (302 << ErrorCodeShift) | ModuleId, NullObject = (302 << ErrorCodeShift) | ModuleId,
Unknown341 = (341 << ErrorCodeShift) | ModuleId, Unknown341 = (341 << ErrorCodeShift) | ModuleId,
MissingNetworkServiceLicenseKind = (400 << ErrorCodeShift) | ModuleId,
InvalidIdTokenCacheBufferSize = (451 << ErrorCodeShift) | ModuleId InvalidIdTokenCacheBufferSize = (451 << ErrorCodeShift) | ModuleId
} }
} }

View File

@ -336,6 +336,12 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
context.Memory.Write(outputBufferPosition + (ulong)(i * Unsafe.SizeOf<PollEventData>()), events[i].Data); context.Memory.Write(outputBufferPosition + (ulong)(i * Unsafe.SizeOf<PollEventData>()), events[i].Data);
} }
// In case of non blocking call timeout should not be returned.
if (timeout == 0 && errno == LinuxError.ETIMEDOUT)
{
errno = LinuxError.SUCCESS;
}
return WriteBsdResult(context, updateCount, errno); return WriteBsdResult(context, updateCount, errno);
} }

View File

@ -19,7 +19,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Sfdnsres.Types
{ {
Length = (byte)Unsafe.SizeOf<Array4<byte>>(); Length = (byte)Unsafe.SizeOf<Array4<byte>>();
Family = (byte)AddressFamily.InterNetwork; Family = (byte)AddressFamily.InterNetwork;
Port = port; Port = IPAddress.HostToNetworkOrder(port);
Address = new Array4<byte>(); Address = new Array4<byte>();
address.TryWriteBytes(Address.AsSpan(), out _); address.TryWriteBytes(Address.AsSpan(), out _);

View File

@ -35,6 +35,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
private long _1msTicks; private long _1msTicks;
private int _swapInterval; private int _swapInterval;
private int _swapIntervalDelay;
private readonly object Lock = new object(); private readonly object Lock = new object();
@ -91,7 +92,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
} }
else else
{ {
_ticksPerFrame = Stopwatch.Frequency / (TargetFps / _swapInterval); _ticksPerFrame = Stopwatch.Frequency / TargetFps;
} }
} }
@ -321,9 +322,15 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
lastTicks = ticks; lastTicks = ticks;
if (_ticks >= _ticksPerFrame) if (_ticks >= _ticksPerFrame)
{
if (_swapIntervalDelay-- == 0)
{ {
Compose(); Compose();
// When a frame is presented, delay the next one by its swap interval value.
_swapIntervalDelay = Math.Max(0, _swapInterval - 1);
}
_device.System?.SignalVsync(); _device.System?.SignalVsync();
// Apply a maximum bound of 3 frames to the tick remainder, in case some event causes Ryujinx to pause for a long time or messes with the timer. // Apply a maximum bound of 3 frames to the tick remainder, in case some event causes Ryujinx to pause for a long time or messes with the timer.