Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
408bd63b08 | |||
df99257d7f | |||
f3835dc78b | |||
51bb8707ef | |||
5ff5fe47ba | |||
38275f9056 | |||
67cbdc3a6a | |||
131b43170e |
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: Bug Report
|
name: Bug Report
|
||||||
about: Something doesn't work correctly in Ryujinx.
|
about: Something doesn't work correctly in Ryujinx. Note that game-specific issues should be instead posted on the Game Compatibility List at https://github.com/Ryujinx/Ryujinx-Games-List, unless it is a provable regression.
|
||||||
#assignees:
|
#assignees:
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -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 = 3525;
|
private const uint CodeGenVersion = 3672;
|
||||||
|
|
||||||
private const string SharedTocFileName = "shared.toc";
|
private const string SharedTocFileName = "shared.toc";
|
||||||
private const string SharedDataFileName = "shared.data";
|
private const string SharedDataFileName = "shared.data";
|
||||||
|
@ -153,6 +153,10 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
|||||||
EvaluateFPUnary(operation, (x) => float.IsNaN(x));
|
EvaluateFPUnary(operation, (x) => float.IsNaN(x));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Instruction.LoadConstant:
|
||||||
|
operation.TurnIntoCopy(Cbuf(operation.GetSource(0).Value, operation.GetSource(1).Value));
|
||||||
|
break;
|
||||||
|
|
||||||
case Instruction.Maximum:
|
case Instruction.Maximum:
|
||||||
EvaluateBinary(operation, (x, y) => Math.Max(x, y));
|
EvaluateBinary(operation, (x, y) => Math.Max(x, y));
|
||||||
break;
|
break;
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -567,8 +573,11 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
|||||||
|
|
||||||
LinuxError errno = LinuxError.EBADF;
|
LinuxError errno = LinuxError.EBADF;
|
||||||
ISocket socket = _context.RetrieveSocket(socketFd);
|
ISocket socket = _context.RetrieveSocket(socketFd);
|
||||||
|
|
||||||
if (socket != null)
|
if (socket != null)
|
||||||
|
{
|
||||||
|
errno = LinuxError.ENOTCONN;
|
||||||
|
|
||||||
|
if (socket.RemoteEndPoint != null)
|
||||||
{
|
{
|
||||||
errno = LinuxError.SUCCESS;
|
errno = LinuxError.SUCCESS;
|
||||||
|
|
||||||
@ -576,6 +585,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
|||||||
WriteBsdResult(context, 0, errno);
|
WriteBsdResult(context, 0, errno);
|
||||||
context.ResponseData.Write(Unsafe.SizeOf<BsdSockAddr>());
|
context.ResponseData.Write(Unsafe.SizeOf<BsdSockAddr>());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return WriteBsdResult(context, 0, errno);
|
return WriteBsdResult(context, 0, errno);
|
||||||
}
|
}
|
||||||
@ -876,6 +886,91 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
|||||||
return WriteBsdResult(context, newSockFd, errno);
|
return WriteBsdResult(context, newSockFd, errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[CommandHipc(29)] // 7.0.0+
|
||||||
|
// RecvMMsg(u32 fd, u32 vlen, u32 flags, u32 reserved, nn::socket::TimeVal timeout) -> (i32 ret, u32 bsd_errno, buffer<bytes, 6> message);
|
||||||
|
public ResultCode RecvMMsg(ServiceCtx context)
|
||||||
|
{
|
||||||
|
int socketFd = context.RequestData.ReadInt32();
|
||||||
|
int vlen = context.RequestData.ReadInt32();
|
||||||
|
BsdSocketFlags socketFlags = (BsdSocketFlags)context.RequestData.ReadInt32();
|
||||||
|
uint reserved = context.RequestData.ReadUInt32();
|
||||||
|
TimeVal timeout = context.RequestData.ReadStruct<TimeVal>();
|
||||||
|
|
||||||
|
ulong receivePosition = context.Request.ReceiveBuff[0].Position;
|
||||||
|
ulong receiveLength = context.Request.ReceiveBuff[0].Size;
|
||||||
|
|
||||||
|
WritableRegion receiveRegion = context.Memory.GetWritableRegion(receivePosition, (int)receiveLength);
|
||||||
|
|
||||||
|
LinuxError errno = LinuxError.EBADF;
|
||||||
|
ISocket socket = _context.RetrieveSocket(socketFd);
|
||||||
|
int result = -1;
|
||||||
|
|
||||||
|
if (socket != null)
|
||||||
|
{
|
||||||
|
errno = BsdMMsgHdr.Deserialize(out BsdMMsgHdr message, receiveRegion.Memory.Span, vlen);
|
||||||
|
|
||||||
|
if (errno == LinuxError.SUCCESS)
|
||||||
|
{
|
||||||
|
errno = socket.RecvMMsg(out result, message, socketFlags, timeout);
|
||||||
|
|
||||||
|
if (errno == LinuxError.SUCCESS)
|
||||||
|
{
|
||||||
|
errno = BsdMMsgHdr.Serialize(receiveRegion.Memory.Span, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errno == LinuxError.SUCCESS)
|
||||||
|
{
|
||||||
|
SetResultErrno(socket, result);
|
||||||
|
receiveRegion.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
return WriteBsdResult(context, result, errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
[CommandHipc(30)] // 7.0.0+
|
||||||
|
// SendMMsg(u32 fd, u32 vlen, u32 flags) -> (i32 ret, u32 bsd_errno, buffer<bytes, 6> message);
|
||||||
|
public ResultCode SendMMsg(ServiceCtx context)
|
||||||
|
{
|
||||||
|
int socketFd = context.RequestData.ReadInt32();
|
||||||
|
int vlen = context.RequestData.ReadInt32();
|
||||||
|
BsdSocketFlags socketFlags = (BsdSocketFlags)context.RequestData.ReadInt32();
|
||||||
|
|
||||||
|
ulong receivePosition = context.Request.ReceiveBuff[0].Position;
|
||||||
|
ulong receiveLength = context.Request.ReceiveBuff[0].Size;
|
||||||
|
|
||||||
|
WritableRegion receiveRegion = context.Memory.GetWritableRegion(receivePosition, (int)receiveLength);
|
||||||
|
|
||||||
|
LinuxError errno = LinuxError.EBADF;
|
||||||
|
ISocket socket = _context.RetrieveSocket(socketFd);
|
||||||
|
int result = -1;
|
||||||
|
|
||||||
|
if (socket != null)
|
||||||
|
{
|
||||||
|
errno = BsdMMsgHdr.Deserialize(out BsdMMsgHdr message, receiveRegion.Memory.Span, vlen);
|
||||||
|
|
||||||
|
if (errno == LinuxError.SUCCESS)
|
||||||
|
{
|
||||||
|
errno = socket.SendMMsg(out result, message, socketFlags);
|
||||||
|
|
||||||
|
if (errno == LinuxError.SUCCESS)
|
||||||
|
{
|
||||||
|
errno = BsdMMsgHdr.Serialize(receiveRegion.Memory.Span, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errno == LinuxError.SUCCESS)
|
||||||
|
{
|
||||||
|
SetResultErrno(socket, result);
|
||||||
|
receiveRegion.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
return WriteBsdResult(context, result, errno);
|
||||||
|
}
|
||||||
|
|
||||||
[CommandHipc(31)] // 7.0.0+
|
[CommandHipc(31)] // 7.0.0+
|
||||||
// EventFd(u64 initval, nn::socket::EventFdFlags flags) -> (i32 ret, u32 bsd_errno)
|
// EventFd(u64 initval, nn::socket::EventFdFlags flags) -> (i32 ret, u32 bsd_errno)
|
||||||
public ResultCode EventFd(ServiceCtx context)
|
public ResultCode EventFd(ServiceCtx context)
|
||||||
|
@ -25,7 +25,12 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
|||||||
|
|
||||||
LinuxError SendTo(out int sendSize, ReadOnlySpan<byte> buffer, int size, BsdSocketFlags flags, IPEndPoint remoteEndPoint);
|
LinuxError SendTo(out int sendSize, ReadOnlySpan<byte> buffer, int size, BsdSocketFlags flags, IPEndPoint remoteEndPoint);
|
||||||
|
|
||||||
|
LinuxError RecvMMsg(out int vlen, BsdMMsgHdr message, BsdSocketFlags flags, TimeVal timeout);
|
||||||
|
|
||||||
|
LinuxError SendMMsg(out int vlen, BsdMMsgHdr message, BsdSocketFlags flags);
|
||||||
|
|
||||||
LinuxError GetSocketOption(BsdSocketOption option, SocketOptionLevel level, Span<byte> optionValue);
|
LinuxError GetSocketOption(BsdSocketOption option, SocketOptionLevel level, Span<byte> optionValue);
|
||||||
|
|
||||||
LinuxError SetSocketOption(BsdSocketOption option, SocketOptionLevel level, ReadOnlySpan<byte> optionValue);
|
LinuxError SetSocketOption(BsdSocketOption option, SocketOptionLevel level, ReadOnlySpan<byte> optionValue);
|
||||||
|
|
||||||
bool Poll(int microSeconds, SelectMode mode);
|
bool Poll(int microSeconds, SelectMode mode);
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
@ -356,5 +358,165 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
|||||||
{
|
{
|
||||||
return Send(out writeSize, buffer, BsdSocketFlags.None);
|
return Send(out writeSize, buffer, BsdSocketFlags.None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool CanSupportMMsgHdr(BsdMMsgHdr message)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < message.Messages.Length; i++)
|
||||||
|
{
|
||||||
|
if (message.Messages[i].Name != null ||
|
||||||
|
message.Messages[i].Control != null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IList<ArraySegment<byte>> ConvertMessagesToBuffer(BsdMMsgHdr message)
|
||||||
|
{
|
||||||
|
int segmentCount = 0;
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
|
foreach (BsdMsgHdr msgHeader in message.Messages)
|
||||||
|
{
|
||||||
|
segmentCount += msgHeader.Iov.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArraySegment<byte>[] buffers = new ArraySegment<byte>[segmentCount];
|
||||||
|
|
||||||
|
foreach (BsdMsgHdr msgHeader in message.Messages)
|
||||||
|
{
|
||||||
|
foreach (byte[] iov in msgHeader.Iov)
|
||||||
|
{
|
||||||
|
buffers[index++] = new ArraySegment<byte>(iov);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear the length
|
||||||
|
msgHeader.Length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffers;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void UpdateMessages(out int vlen, BsdMMsgHdr message, int transferedSize)
|
||||||
|
{
|
||||||
|
int bytesLeft = transferedSize;
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
|
while (bytesLeft > 0)
|
||||||
|
{
|
||||||
|
// First ensure we haven't finished all buffers
|
||||||
|
if (index >= message.Messages.Length)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
BsdMsgHdr msgHeader = message.Messages[index];
|
||||||
|
|
||||||
|
int possiblyTransferedBytes = 0;
|
||||||
|
|
||||||
|
foreach (byte[] iov in msgHeader.Iov)
|
||||||
|
{
|
||||||
|
possiblyTransferedBytes += iov.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
int storedBytes;
|
||||||
|
|
||||||
|
if (bytesLeft > possiblyTransferedBytes)
|
||||||
|
{
|
||||||
|
storedBytes = possiblyTransferedBytes;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
storedBytes = bytesLeft;
|
||||||
|
}
|
||||||
|
|
||||||
|
msgHeader.Length = (uint)storedBytes;
|
||||||
|
bytesLeft -= storedBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.Assert(bytesLeft == 0);
|
||||||
|
|
||||||
|
vlen = index + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Find a way to support passing the timeout somehow without changing the socket ReceiveTimeout.
|
||||||
|
public LinuxError RecvMMsg(out int vlen, BsdMMsgHdr message, BsdSocketFlags flags, TimeVal timeout)
|
||||||
|
{
|
||||||
|
vlen = 0;
|
||||||
|
|
||||||
|
if (message.Messages.Length == 0)
|
||||||
|
{
|
||||||
|
return LinuxError.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CanSupportMMsgHdr(message))
|
||||||
|
{
|
||||||
|
Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported BsdMMsgHdr");
|
||||||
|
|
||||||
|
return LinuxError.EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message.Messages.Length == 0)
|
||||||
|
{
|
||||||
|
return LinuxError.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int receiveSize = Socket.Receive(ConvertMessagesToBuffer(message), ConvertBsdSocketFlags(flags), out SocketError socketError);
|
||||||
|
|
||||||
|
if (receiveSize > 0)
|
||||||
|
{
|
||||||
|
UpdateMessages(out vlen, message, receiveSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
return WinSockHelper.ConvertError((WsaError)socketError);
|
||||||
|
}
|
||||||
|
catch (SocketException exception)
|
||||||
|
{
|
||||||
|
return WinSockHelper.ConvertError((WsaError)exception.ErrorCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public LinuxError SendMMsg(out int vlen, BsdMMsgHdr message, BsdSocketFlags flags)
|
||||||
|
{
|
||||||
|
vlen = 0;
|
||||||
|
|
||||||
|
if (message.Messages.Length == 0)
|
||||||
|
{
|
||||||
|
return LinuxError.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CanSupportMMsgHdr(message))
|
||||||
|
{
|
||||||
|
Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported BsdMMsgHdr");
|
||||||
|
|
||||||
|
return LinuxError.EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message.Messages.Length == 0)
|
||||||
|
{
|
||||||
|
return LinuxError.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int sendSize = Socket.Send(ConvertMessagesToBuffer(message), ConvertBsdSocketFlags(flags), out SocketError socketError);
|
||||||
|
|
||||||
|
if (sendSize > 0)
|
||||||
|
{
|
||||||
|
UpdateMessages(out vlen, message, sendSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
return WinSockHelper.ConvertError((WsaError)socketError);
|
||||||
|
}
|
||||||
|
catch (SocketException exception)
|
||||||
|
{
|
||||||
|
return WinSockHelper.ConvertError((WsaError)exception.ErrorCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,12 +38,13 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
|||||||
{
|
{
|
||||||
ManagedSocket socket = (ManagedSocket)evnt.FileDescriptor;
|
ManagedSocket socket = (ManagedSocket)evnt.FileDescriptor;
|
||||||
|
|
||||||
bool isValidEvent = false;
|
bool isValidEvent = evnt.Data.InputEvents == 0;
|
||||||
|
|
||||||
|
errorEvents.Add(socket.Socket);
|
||||||
|
|
||||||
if ((evnt.Data.InputEvents & PollEventTypeMask.Input) != 0)
|
if ((evnt.Data.InputEvents & PollEventTypeMask.Input) != 0)
|
||||||
{
|
{
|
||||||
readEvents.Add(socket.Socket);
|
readEvents.Add(socket.Socket);
|
||||||
errorEvents.Add(socket.Socket);
|
|
||||||
|
|
||||||
isValidEvent = true;
|
isValidEvent = true;
|
||||||
}
|
}
|
||||||
@ -51,7 +52,6 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
|||||||
if ((evnt.Data.InputEvents & PollEventTypeMask.UrgentInput) != 0)
|
if ((evnt.Data.InputEvents & PollEventTypeMask.UrgentInput) != 0)
|
||||||
{
|
{
|
||||||
readEvents.Add(socket.Socket);
|
readEvents.Add(socket.Socket);
|
||||||
errorEvents.Add(socket.Socket);
|
|
||||||
|
|
||||||
isValidEvent = true;
|
isValidEvent = true;
|
||||||
}
|
}
|
||||||
@ -59,14 +59,6 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
|||||||
if ((evnt.Data.InputEvents & PollEventTypeMask.Output) != 0)
|
if ((evnt.Data.InputEvents & PollEventTypeMask.Output) != 0)
|
||||||
{
|
{
|
||||||
writeEvents.Add(socket.Socket);
|
writeEvents.Add(socket.Socket);
|
||||||
errorEvents.Add(socket.Socket);
|
|
||||||
|
|
||||||
isValidEvent = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((evnt.Data.InputEvents & PollEventTypeMask.Error) != 0)
|
|
||||||
{
|
|
||||||
errorEvents.Add(socket.Socket);
|
|
||||||
|
|
||||||
isValidEvent = true;
|
isValidEvent = true;
|
||||||
}
|
}
|
||||||
@ -93,7 +85,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
|||||||
{
|
{
|
||||||
Socket socket = ((ManagedSocket)evnt.FileDescriptor).Socket;
|
Socket socket = ((ManagedSocket)evnt.FileDescriptor).Socket;
|
||||||
|
|
||||||
PollEventTypeMask outputEvents = 0;
|
PollEventTypeMask outputEvents = evnt.Data.OutputEvents & ~evnt.Data.InputEvents;
|
||||||
|
|
||||||
if (errorEvents.Contains(socket))
|
if (errorEvents.Contains(socket))
|
||||||
{
|
{
|
||||||
|
56
Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdMMsgHdr.cs
Normal file
56
Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdMMsgHdr.cs
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
||||||
|
{
|
||||||
|
class BsdMMsgHdr
|
||||||
|
{
|
||||||
|
public BsdMsgHdr[] Messages { get; }
|
||||||
|
|
||||||
|
private BsdMMsgHdr(BsdMsgHdr[] messages)
|
||||||
|
{
|
||||||
|
Messages = messages;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LinuxError Serialize(Span<byte> rawData, BsdMMsgHdr message)
|
||||||
|
{
|
||||||
|
rawData[0] = 0x8;
|
||||||
|
rawData = rawData[1..];
|
||||||
|
|
||||||
|
for (int index = 0; index < message.Messages.Length; index++)
|
||||||
|
{
|
||||||
|
LinuxError res = BsdMsgHdr.Serialize(ref rawData, message.Messages[index]);
|
||||||
|
|
||||||
|
if (res != LinuxError.SUCCESS)
|
||||||
|
{
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return LinuxError.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LinuxError Deserialize(out BsdMMsgHdr message, ReadOnlySpan<byte> rawData, int vlen)
|
||||||
|
{
|
||||||
|
message = null;
|
||||||
|
|
||||||
|
BsdMsgHdr[] messages = new BsdMsgHdr[vlen];
|
||||||
|
|
||||||
|
// Skip "header" byte (Nintendo also ignore it)
|
||||||
|
rawData = rawData[1..];
|
||||||
|
|
||||||
|
for (int index = 0; index < messages.Length; index++)
|
||||||
|
{
|
||||||
|
LinuxError res = BsdMsgHdr.Deserialize(out messages[index], ref rawData);
|
||||||
|
|
||||||
|
if (res != LinuxError.SUCCESS)
|
||||||
|
{
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message = new BsdMMsgHdr(messages);
|
||||||
|
|
||||||
|
return LinuxError.SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
212
Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdMsgHdr.cs
Normal file
212
Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdMsgHdr.cs
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
||||||
|
{
|
||||||
|
class BsdMsgHdr
|
||||||
|
{
|
||||||
|
public byte[] Name { get; }
|
||||||
|
public byte[][] Iov { get; }
|
||||||
|
public byte[] Control { get; }
|
||||||
|
public BsdSocketFlags Flags { get; }
|
||||||
|
public uint Length;
|
||||||
|
|
||||||
|
private BsdMsgHdr(byte[] name, byte[][] iov, byte[] control, BsdSocketFlags flags, uint length)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
Iov = iov;
|
||||||
|
Control = control;
|
||||||
|
Flags = flags;
|
||||||
|
Length = length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LinuxError Serialize(ref Span<byte> rawData, BsdMsgHdr message)
|
||||||
|
{
|
||||||
|
int msgNameLength = message.Name == null ? 0 : message.Name.Length;
|
||||||
|
int iovCount = message.Iov == null ? 0 : message.Iov.Length;
|
||||||
|
int controlLength = message.Control == null ? 0 : message.Control.Length;
|
||||||
|
BsdSocketFlags flags = message.Flags;
|
||||||
|
|
||||||
|
if (!MemoryMarshal.TryWrite(rawData, ref msgNameLength))
|
||||||
|
{
|
||||||
|
return LinuxError.EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
rawData = rawData[sizeof(uint)..];
|
||||||
|
|
||||||
|
if (msgNameLength > 0)
|
||||||
|
{
|
||||||
|
if (rawData.Length < msgNameLength)
|
||||||
|
{
|
||||||
|
return LinuxError.EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
message.Name.CopyTo(rawData);
|
||||||
|
rawData = rawData[msgNameLength..];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!MemoryMarshal.TryWrite(rawData, ref iovCount))
|
||||||
|
{
|
||||||
|
return LinuxError.EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
rawData = rawData[sizeof(uint)..];
|
||||||
|
|
||||||
|
if (iovCount > 0)
|
||||||
|
{
|
||||||
|
for (int index = 0; index < iovCount; index++)
|
||||||
|
{
|
||||||
|
ulong iovLength = (ulong)message.Iov[index].Length;
|
||||||
|
|
||||||
|
if (!MemoryMarshal.TryWrite(rawData, ref iovLength))
|
||||||
|
{
|
||||||
|
return LinuxError.EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
rawData = rawData[sizeof(ulong)..];
|
||||||
|
|
||||||
|
if (iovLength > 0)
|
||||||
|
{
|
||||||
|
if ((ulong)rawData.Length < iovLength)
|
||||||
|
{
|
||||||
|
return LinuxError.EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
message.Iov[index].CopyTo(rawData);
|
||||||
|
rawData = rawData[(int)iovLength..];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!MemoryMarshal.TryWrite(rawData, ref controlLength))
|
||||||
|
{
|
||||||
|
return LinuxError.EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
rawData = rawData[sizeof(uint)..];
|
||||||
|
|
||||||
|
if (controlLength > 0)
|
||||||
|
{
|
||||||
|
if (rawData.Length < controlLength)
|
||||||
|
{
|
||||||
|
return LinuxError.EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
message.Control.CopyTo(rawData);
|
||||||
|
rawData = rawData[controlLength..];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!MemoryMarshal.TryWrite(rawData, ref flags))
|
||||||
|
{
|
||||||
|
return LinuxError.EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
rawData = rawData[sizeof(BsdSocketFlags)..];
|
||||||
|
|
||||||
|
if (!MemoryMarshal.TryWrite(rawData, ref message.Length))
|
||||||
|
{
|
||||||
|
return LinuxError.EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
rawData = rawData[sizeof(uint)..];
|
||||||
|
|
||||||
|
return LinuxError.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LinuxError Deserialize(out BsdMsgHdr message, ref ReadOnlySpan<byte> rawData)
|
||||||
|
{
|
||||||
|
byte[] name = null;
|
||||||
|
byte[][] iov = null;
|
||||||
|
byte[] control = null;
|
||||||
|
|
||||||
|
message = null;
|
||||||
|
|
||||||
|
if (!MemoryMarshal.TryRead(rawData, out uint msgNameLength))
|
||||||
|
{
|
||||||
|
return LinuxError.EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
rawData = rawData[sizeof(uint)..];
|
||||||
|
|
||||||
|
if (msgNameLength > 0)
|
||||||
|
{
|
||||||
|
if (rawData.Length < msgNameLength)
|
||||||
|
{
|
||||||
|
return LinuxError.EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
name = rawData[..(int)msgNameLength].ToArray();
|
||||||
|
rawData = rawData[(int)msgNameLength..];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!MemoryMarshal.TryRead(rawData, out uint iovCount))
|
||||||
|
{
|
||||||
|
return LinuxError.EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
rawData = rawData[sizeof(uint)..];
|
||||||
|
|
||||||
|
if (iovCount > 0)
|
||||||
|
{
|
||||||
|
iov = new byte[iovCount][];
|
||||||
|
|
||||||
|
for (int index = 0; index < iov.Length; index++)
|
||||||
|
{
|
||||||
|
if (!MemoryMarshal.TryRead(rawData, out ulong iovLength))
|
||||||
|
{
|
||||||
|
return LinuxError.EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
rawData = rawData[sizeof(ulong)..];
|
||||||
|
|
||||||
|
if (iovLength > 0)
|
||||||
|
{
|
||||||
|
if ((ulong)rawData.Length < iovLength)
|
||||||
|
{
|
||||||
|
return LinuxError.EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
iov[index] = rawData[..(int)iovLength].ToArray();
|
||||||
|
rawData = rawData[(int)iovLength..];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!MemoryMarshal.TryRead(rawData, out uint controlLength))
|
||||||
|
{
|
||||||
|
return LinuxError.EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
rawData = rawData[sizeof(uint)..];
|
||||||
|
|
||||||
|
if (controlLength > 0)
|
||||||
|
{
|
||||||
|
if (rawData.Length < controlLength)
|
||||||
|
{
|
||||||
|
return LinuxError.EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
control = rawData[..(int)controlLength].ToArray();
|
||||||
|
rawData = rawData[(int)controlLength..];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!MemoryMarshal.TryRead(rawData, out BsdSocketFlags flags))
|
||||||
|
{
|
||||||
|
return LinuxError.EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
rawData = rawData[sizeof(BsdSocketFlags)..];
|
||||||
|
|
||||||
|
if (!MemoryMarshal.TryRead(rawData, out uint length))
|
||||||
|
{
|
||||||
|
return LinuxError.EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
rawData = rawData[sizeof(uint)..];
|
||||||
|
|
||||||
|
message = new BsdMsgHdr(name, iov, control, flags, length);
|
||||||
|
|
||||||
|
return LinuxError.SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
8
Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/TimeVal.cs
Normal file
8
Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/TimeVal.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
||||||
|
{
|
||||||
|
public struct TimeVal
|
||||||
|
{
|
||||||
|
public ulong TvSec;
|
||||||
|
public ulong TvUsec;
|
||||||
|
}
|
||||||
|
}
|
@ -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 _);
|
||||||
|
@ -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.
|
||||||
|
Reference in New Issue
Block a user