Add support for events, move concept of domains to IpcService

This commit is contained in:
gdkchan 2018-03-19 02:01:08 -03:00
commit 44e847c1c1
95 changed files with 1002 additions and 712 deletions

View file

@ -2,7 +2,11 @@ namespace Ryujinx.Audio
{ {
public interface IAalOutput public interface IAalOutput
{ {
int OpenTrack(int SampleRate, int Channels, out AudioFormat Format); int OpenTrack(
int SampleRate,
int Channels,
ReleaseCallback Callback,
out AudioFormat Format);
void CloseTrack(int Track); void CloseTrack(int Track);

View file

@ -3,6 +3,7 @@ using OpenTK.Audio.OpenAL;
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading;
namespace Ryujinx.Audio.OpenAL namespace Ryujinx.Audio.OpenAL
{ {
@ -22,20 +23,27 @@ namespace Ryujinx.Audio.OpenAL
public ALFormat Format { get; private set; } public ALFormat Format { get; private set; }
private ReleaseCallback Callback;
public PlaybackState State { get; set; } public PlaybackState State { get; set; }
private bool ShouldCallReleaseCallback;
private ConcurrentDictionary<long, int> Buffers; private ConcurrentDictionary<long, int> Buffers;
private Queue<long> QueuedTagsQueue; private Queue<long> QueuedTagsQueue;
private Queue<long> ReleasedTagsQueue; private Queue<long> ReleasedTagsQueue;
private int LastReleasedCount;
private bool Disposed; private bool Disposed;
public Track(int SampleRate, ALFormat Format) public Track(int SampleRate, ALFormat Format, ReleaseCallback Callback)
{ {
this.SampleRate = SampleRate; this.SampleRate = SampleRate;
this.Format = Format; this.Format = Format;
this.Callback = Callback;
State = PlaybackState.Stopped; State = PlaybackState.Stopped;
@ -109,12 +117,43 @@ namespace Ryujinx.Audio.OpenAL
AL.GetSource(SourceId, ALGetSourcei.BuffersProcessed, out int ReleasedCount); AL.GetSource(SourceId, ALGetSourcei.BuffersProcessed, out int ReleasedCount);
CheckReleaseChanges(ReleasedCount);
if (ReleasedCount > 0) if (ReleasedCount > 0)
{ {
AL.SourceUnqueueBuffers(SourceId, ReleasedCount); AL.SourceUnqueueBuffers(SourceId, ReleasedCount);
} }
} }
public void CallReleaseCallbackIfNeeded()
{
CheckReleaseChanges();
if (ShouldCallReleaseCallback)
{
ShouldCallReleaseCallback = false;
Callback();
}
}
private void CheckReleaseChanges()
{
AL.GetSource(SourceId, ALGetSourcei.BuffersProcessed, out int ReleasedCount);
CheckReleaseChanges(ReleasedCount);
}
private void CheckReleaseChanges(int NewReleasedCount)
{
if (LastReleasedCount != NewReleasedCount)
{
LastReleasedCount = NewReleasedCount;
ShouldCallReleaseCallback = true;
}
}
private void SyncQueuedTags() private void SyncQueuedTags()
{ {
AL.GetSource(SourceId, ALGetSourcei.BuffersQueued, out int QueuedCount); AL.GetSource(SourceId, ALGetSourcei.BuffersQueued, out int QueuedCount);
@ -156,18 +195,46 @@ namespace Ryujinx.Audio.OpenAL
private ConcurrentDictionary<int, Track> Tracks; private ConcurrentDictionary<int, Track> Tracks;
private Thread AudioPollerThread;
private bool KeepPolling;
public OpenALAudioOut() public OpenALAudioOut()
{ {
Context = new AudioContext(); Context = new AudioContext();
Tracks = new ConcurrentDictionary<int, Track>(); Tracks = new ConcurrentDictionary<int, Track>();
KeepPolling = true;
AudioPollerThread = new Thread(AudioPollerWork);
AudioPollerThread.Start();
} }
public int OpenTrack(int SampleRate, int Channels, out AudioFormat Format) private void AudioPollerWork()
{
do
{
foreach (Track Td in Tracks.Values)
{
Td.CallReleaseCallbackIfNeeded();
}
Thread.Yield();
}
while (KeepPolling);
}
public int OpenTrack(
int SampleRate,
int Channels,
ReleaseCallback Callback,
out AudioFormat Format)
{ {
Format = AudioFormat.PcmInt16; Format = AudioFormat.PcmInt16;
Track Td = new Track(SampleRate, GetALFormat(Channels, Format)); Track Td = new Track(SampleRate, GetALFormat(Channels, Format), Callback);
for (int Id = 0; Id < MaxTracks; Id++) for (int Id = 0; Id < MaxTracks; Id++)
{ {
@ -292,5 +359,7 @@ namespace Ryujinx.Audio.OpenAL
return PlaybackState.Stopped; return PlaybackState.Stopped;
} }
} }
} }

View file

@ -0,0 +1,4 @@
namespace Ryujinx.Audio
{
public delegate void ReleaseCallback();
}

View file

@ -0,0 +1,62 @@
using Ryujinx.Core.OsHle.IpcServices.Am;
using Ryujinx.Core.OsHle.Handles;
using System;
using System.Collections.Concurrent;
namespace Ryujinx.Core.OsHle
{
class AppletStateMgr : IDisposable
{
private ConcurrentQueue<MessageInfo> Messages;
public FocusState FocusState { get; private set; }
public KEvent MessageEvent { get; private set; }
public AppletStateMgr()
{
Messages = new ConcurrentQueue<MessageInfo>();
MessageEvent = new KEvent();
}
public void SetFocus(bool IsFocused)
{
FocusState = IsFocused
? FocusState.InFocus
: FocusState.OutOfFocus;
EnqueueMessage(MessageInfo.FocusStateChanged);
}
public void EnqueueMessage(MessageInfo Message)
{
Messages.Enqueue(Message);
MessageEvent.Handle.Set();
}
public bool TryDequeueMessage(out MessageInfo Message)
{
if (Messages.Count < 2)
{
MessageEvent.Handle.Reset();
}
return Messages.TryDequeue(out Message);
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool Disposing)
{
if (Disposing)
{
MessageEvent.Dispose();
}
}
}
}

View file

@ -1,12 +0,0 @@
namespace Ryujinx.Core.OsHle
{
class FileDesc
{
public string Name { get; private set; }
public FileDesc(string Name)
{
this.Name = Name;
}
}
}

View file

@ -0,0 +1,51 @@
using System.Collections.Concurrent;
namespace Ryujinx.Core.OsHle
{
class GlobalStateTable
{
private ConcurrentDictionary<Process, IdDictionary> DictByProcess;
public GlobalStateTable()
{
DictByProcess = new ConcurrentDictionary<Process, IdDictionary>();
}
public int Add(Process Process, object Obj)
{
IdDictionary Dict = DictByProcess.GetOrAdd(Process, (Key) => new IdDictionary());
return Dict.Add(Obj);
}
public object GetData(Process Process, int Id)
{
if (DictByProcess.TryGetValue(Process, out IdDictionary Dict))
{
return Dict.GetData(Id);
}
return null;
}
public T GetData<T>(Process Process, int Id)
{
if (DictByProcess.TryGetValue(Process, out IdDictionary Dict))
{
return Dict.GetData<T>(Id);
}
return default(T);
}
public bool Delete(Process Process, int Id)
{
if (DictByProcess.TryGetValue(Process, out IdDictionary Dict))
{
return Dict.Delete(Id);
}
return false;
}
}
}

View file

@ -1,48 +0,0 @@
using System;
namespace Ryujinx.Core.OsHle.Handles
{
class HDomain : HSession, IDisposable
{
private IdDictionary Objects;
public HDomain(HSession Session) : base(Session)
{
Objects = new IdDictionary();
}
public int Add(object Obj)
{
return Objects.Add(Obj);
}
public bool Delete(int Id)
{
return Objects.Delete(Id);
}
public object GetObject(int Id)
{
return Objects.GetData(Id);
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool Disposing)
{
if (Disposing)
{
foreach (object Obj in Objects)
{
if (Obj != this && Obj is IDisposable DisposableObj)
{
DisposableObj.Dispose();
}
}
}
}
}
}

View file

@ -1,7 +0,0 @@
namespace Ryujinx.Core.OsHle.Handles
{
class HEvent
{
}
}

View file

@ -1,29 +0,0 @@
using Ryujinx.Core.OsHle.IpcServices;
namespace Ryujinx.Core.OsHle.Handles
{
class HSession
{
public IIpcService Service { get; private set; }
public bool IsInitialized { get; private set; }
public int State { get; set; }
public HSession(IIpcService Service)
{
this.Service = Service;
}
public HSession(HSession Session)
{
Service = Session.Service;
IsInitialized = Session.IsInitialized;
}
public void Initialize()
{
IsInitialized = true;
}
}
}

View file

@ -1,30 +0,0 @@
using System;
namespace Ryujinx.Core.OsHle.Handles
{
class HSessionObj : HSession, IDisposable
{
public object Obj { get; private set; }
public HSessionObj(HSession Session, object Obj) : base(Session)
{
this.Obj = Obj;
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool Disposing)
{
if (Disposing && Obj != null)
{
if (Obj is IDisposable DisposableObj)
{
DisposableObj.Dispose();
}
}
}
}
}

View file

@ -0,0 +1,4 @@
namespace Ryujinx.Core.OsHle.Handles
{
class KEvent : KSynchronizationObject { }
}

View file

@ -13,7 +13,14 @@ namespace Ryujinx.Core.OsHle.Handles
public int OpenHandle(object Obj) public int OpenHandle(object Obj)
{ {
return Handles.Add(Obj); int h = Handles.Add(Obj);
/*if (h == 0x1d)
{
throw new System.Exception("bad handle");
}*/
return h;
} }
public T GetData<T>(int Handle) public T GetData<T>(int Handle)
@ -21,11 +28,6 @@ namespace Ryujinx.Core.OsHle.Handles
return Handles.GetData<T>(Handle); return Handles.GetData<T>(Handle);
} }
public bool ReplaceData(int Id, object Data)
{
return Handles.ReplaceData(Id, Data);
}
public bool CloseHandle(int Handle) public bool CloseHandle(int Handle)
{ {
object Data = Handles.GetData(Handle); object Data = Handles.GetData(Handle);

View file

@ -0,0 +1,28 @@
using Ryujinx.Core.OsHle.IpcServices;
using System;
namespace Ryujinx.Core.OsHle.Handles
{
class KSession : IDisposable
{
public IpcService Service { get; private set; }
public KSession(IpcService Service)
{
this.Service = Service;
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool Disposing)
{
if (Disposing && Service is IDisposable DisposableService)
{
DisposableService.Dispose();
}
}
}
}

View file

@ -0,0 +1,28 @@
using System;
using System.Threading;
namespace Ryujinx.Core.OsHle.Handles
{
class KSynchronizationObject : IDisposable
{
public ManualResetEvent Handle { get; private set; }
public KSynchronizationObject()
{
Handle = new ManualResetEvent(false);
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool Disposing)
{
if (Disposing)
{
Handle.Dispose();
}
}
}
}

View file

@ -16,8 +16,10 @@ namespace Ryujinx.Core.OsHle
private ConcurrentDictionary<int, Process> Processes; private ConcurrentDictionary<int, Process> Processes;
internal HSharedMem HidSharedMem; internal HSharedMem HidSharedMem { get; private set; }
internal HSharedMem FontSharedMem; internal HSharedMem FontSharedMem { get; private set; }
internal KEvent VsyncEvent { get; private set; }
private Switch Ns; private Switch Ns;
@ -32,6 +34,8 @@ namespace Ryujinx.Core.OsHle
HidSharedMem = new HSharedMem(); HidSharedMem = new HSharedMem();
FontSharedMem = new HSharedMem(); FontSharedMem = new HSharedMem();
VsyncEvent = new KEvent();
} }
public void LoadCart(string ExeFsDir, string RomFsFile = null) public void LoadCart(string ExeFsDir, string RomFsFile = null)
@ -91,6 +95,8 @@ namespace Ryujinx.Core.OsHle
MainProcess.Run(IsNro); MainProcess.Run(IsNro);
} }
public void SignalVsync() => VsyncEvent.Handle.Set();
private Process MakeProcess() private Process MakeProcess()
{ {
Process Process; Process Process;
@ -109,9 +115,16 @@ namespace Ryujinx.Core.OsHle
Processes.TryAdd(ProcessId, Process); Processes.TryAdd(ProcessId, Process);
} }
InitializeProcess(Process);
return Process; return Process;
} }
private void InitializeProcess(Process Process)
{
Process.AppletState.SetFocus(true);
}
internal void ExitProcess(int ProcessId) internal void ExitProcess(int ProcessId)
{ {
if (Processes.TryGetValue(ProcessId, out Process Process) && Process.NeedsHbAbi) if (Processes.TryGetValue(ProcessId, out Process Process) && Process.NeedsHbAbi)
@ -171,6 +184,8 @@ namespace Ryujinx.Core.OsHle
Process.StopAllThreadsAsync(); Process.StopAllThreadsAsync();
Process.Dispose(); Process.Dispose();
} }
VsyncEvent.Dispose();
} }
} }
} }

View file

@ -1,3 +1,4 @@
using Ryujinx.Core.OsHle.Handles;
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Concurrent; using System.Collections.Concurrent;
@ -39,18 +40,6 @@ namespace Ryujinx.Core.OsHle
throw new InvalidOperationException(); throw new InvalidOperationException();
} }
public bool ReplaceData(int Id, object Data)
{
if (Objs.ContainsKey(Id))
{
Objs[Id] = Data;
return true;
}
return false;
}
public object GetData(int Id) public object GetData(int Id)
{ {
if (Objs.TryGetValue(Id, out object Data)) if (Objs.TryGetValue(Id, out object Data))
@ -75,7 +64,7 @@ namespace Ryujinx.Core.OsHle
{ {
if (Objs.TryRemove(Id, out object Obj)) if (Objs.TryRemove(Id, out object Obj))
{ {
if (Obj is IDisposable DisposableObj) if (Obj is IDisposable DisposableObj && !(Obj is KEvent))
{ {
DisposableObj.Dispose(); DisposableObj.Dispose();
} }

View file

@ -1,8 +0,0 @@
namespace Ryujinx.Core.OsHle.Ipc
{
enum IpcDomCmd
{
SendMsg = 1,
DeleteObj = 2
}
}

View file

@ -1,6 +1,5 @@
using ChocolArm64.Memory; using ChocolArm64.Memory;
using Ryujinx.Core.OsHle.Handles; using Ryujinx.Core.OsHle.Handles;
using Ryujinx.Core.OsHle.IpcServices;
using System; using System;
using System.IO; using System.IO;
@ -8,20 +7,16 @@ namespace Ryujinx.Core.OsHle.Ipc
{ {
static class IpcHandler static class IpcHandler
{ {
private const long SfciMagic = 'S' << 0 | 'F' << 8 | 'C' << 16 | 'I' << 24;
private const long SfcoMagic = 'S' << 0 | 'F' << 8 | 'C' << 16 | 'O' << 24;
public static void IpcCall( public static void IpcCall(
Switch Ns, Switch Ns,
Process Process, Process Process,
AMemory Memory, AMemory Memory,
HSession Session, KSession Session,
IpcMessage Request, IpcMessage Request,
int ThreadId,
long CmdPtr, long CmdPtr,
int HndId) int HndId)
{ {
IpcMessage Response = new IpcMessage(Request.IsDomain && Request.Type == IpcMessageType.Request); IpcMessage Response = new IpcMessage();
using (MemoryStream Raw = new MemoryStream(Request.RawData)) using (MemoryStream Raw = new MemoryStream(Request.RawData))
{ {
@ -29,94 +24,25 @@ namespace Ryujinx.Core.OsHle.Ipc
if (Request.Type == IpcMessageType.Request) if (Request.Type == IpcMessageType.Request)
{ {
string ServiceName = Session.Service.GetType().Name; Response.Type = IpcMessageType.Response;
ServiceProcessRequest ProcReq = null; using (MemoryStream ResMS = new MemoryStream())
bool IgnoreNullPR = false;
string DbgServiceName = string.Empty;
if (Session is HDomain Dom)
{ {
if (Request.DomCmd == IpcDomCmd.SendMsg) BinaryWriter ResWriter = new BinaryWriter(ResMS);
{
long Magic = ReqReader.ReadInt64();
int CmdId = (int)ReqReader.ReadInt64();
object Obj = Dom.GetObject(Request.DomObjId); ServiceCtx Context = new ServiceCtx(
Ns,
Process,
Memory,
Session,
Request,
Response,
ReqReader,
ResWriter);
if (Obj is HDomain) Session.Service.CallMethod(Context);
{
Session.Service.Commands.TryGetValue(CmdId, out ProcReq);
DbgServiceName = $"{ProcReq?.Method.Name ?? CmdId.ToString()}"; Response.RawData = ResMS.ToArray();
}
else if (Obj != null)
{
((IIpcService)Obj).Commands.TryGetValue(CmdId, out ProcReq);
DbgServiceName = $"{Obj.GetType().Name} {ProcReq?.Method.Name ?? CmdId.ToString()}";
}
}
else if (Request.DomCmd == IpcDomCmd.DeleteObj)
{
Dom.Delete(Request.DomObjId);
Response = FillResponse(Response, 0);
IgnoreNullPR = true;
}
}
else
{
long Magic = ReqReader.ReadInt64();
int CmdId = (int)ReqReader.ReadInt64();
if (Session is HSessionObj)
{
object Obj = ((HSessionObj)Session).Obj;
((IIpcService)Obj).Commands.TryGetValue(CmdId, out ProcReq);
DbgServiceName = $"{Obj.GetType().Name} {ProcReq?.Method.Name ?? CmdId.ToString()}";
}
else
{
Session.Service.Commands.TryGetValue(CmdId, out ProcReq);
DbgServiceName = $"{ProcReq?.Method.Name ?? CmdId.ToString()}";
}
}
DbgServiceName = $"Tid {ThreadId} {ServiceName} {DbgServiceName}";
Logging.Debug($"IpcMessage: {DbgServiceName}");
if (ProcReq != null)
{
using (MemoryStream ResMS = new MemoryStream())
{
BinaryWriter ResWriter = new BinaryWriter(ResMS);
ServiceCtx Context = new ServiceCtx(
Ns,
Process,
Memory,
Session,
Request,
Response,
ReqReader,
ResWriter);
long Result = ProcReq(Context);
Response = FillResponse(Response, Result, ResMS.ToArray());
}
}
else if (!IgnoreNullPR)
{
throw new NotImplementedException(DbgServiceName);
} }
} }
else if (Request.Type == IpcMessageType.Control) else if (Request.Type == IpcMessageType.Control)
@ -128,11 +54,7 @@ namespace Ryujinx.Core.OsHle.Ipc
{ {
case 0: case 0:
{ {
HDomain Dom = new HDomain(Session); Request = FillResponse(Response, 0, Session.Service.ConvertToDomain());
Process.HandleTable.ReplaceData(HndId, Dom);
Request = FillResponse(Response, 0, Dom.Add(Dom));
break; break;
} }
@ -198,7 +120,7 @@ namespace Ryujinx.Core.OsHle.Ipc
{ {
BinaryWriter Writer = new BinaryWriter(MS); BinaryWriter Writer = new BinaryWriter(MS);
Writer.Write(SfcoMagic); Writer.Write(IpcMagic.Sfco);
Writer.Write(Result); Writer.Write(Result);
if (Data != null) if (Data != null)

View file

@ -125,8 +125,7 @@ namespace Ryujinx.Core.OsHle.Ipc
Reader.ReadInt64(); //Padding Reader.ReadInt64(); //Padding
IpcMessage += Environment.NewLine + $" Domain:" + Environment.NewLine + IpcMessage += Environment.NewLine + $" Domain:" + Environment.NewLine + Environment.NewLine +
$" DomCmd: {Enum.GetName(typeof(IpcDomCmd), DomCmd)}" + Environment.NewLine +
$" DomObjId: {DomObjId.ToString()}" + Environment.NewLine; $" DomObjId: {DomObjId.ToString()}" + Environment.NewLine;
} }

View file

@ -0,0 +1,8 @@
namespace Ryujinx.Core.OsHle.Ipc
{
abstract class IpcMagic
{
public const long Sfci = 'S' << 0 | 'F' << 8 | 'C' << 16 | 'I' << 24;
public const long Sfco = 'S' << 0 | 'F' << 8 | 'C' << 16 | 'O' << 24;
}
}

View file

@ -17,10 +17,6 @@ namespace Ryujinx.Core.OsHle.Ipc
public List<int> ResponseObjIds { get; private set; } public List<int> ResponseObjIds { get; private set; }
public bool IsDomain { get; private set; }
public IpcDomCmd DomCmd { get; private set; }
public int DomObjId { get; private set; }
public byte[] RawData { get; set; } public byte[] RawData { get; set; }
public IpcMessage() public IpcMessage()
@ -34,27 +30,18 @@ namespace Ryujinx.Core.OsHle.Ipc
ResponseObjIds = new List<int>(); ResponseObjIds = new List<int>();
} }
public IpcMessage(bool Domain) : this() public IpcMessage(byte[] Data, long CmdPtr) : this()
{ {
IsDomain = Domain;
}
public IpcMessage(byte[] Data, long CmdPtr, bool Domain) : this()
{
Logging.Ipc(Data, CmdPtr, Domain);
using (MemoryStream MS = new MemoryStream(Data)) using (MemoryStream MS = new MemoryStream(Data))
{ {
BinaryReader Reader = new BinaryReader(MS); BinaryReader Reader = new BinaryReader(MS);
Initialize(Reader, CmdPtr, Domain); Initialize(Reader, CmdPtr);
} }
} }
private void Initialize(BinaryReader Reader, long CmdPtr, bool Domain) private void Initialize(BinaryReader Reader, long CmdPtr)
{ {
IsDomain = Domain;
int Word0 = Reader.ReadInt32(); int Word0 = Reader.ReadInt32();
int Word1 = Reader.ReadInt32(); int Word1 = Reader.ReadInt32();
@ -110,19 +97,6 @@ namespace Ryujinx.Core.OsHle.Ipc
RecvListCount = 0; RecvListCount = 0;
} }
if (Domain && Type == IpcMessageType.Request)
{
int DomWord0 = Reader.ReadInt32();
DomCmd = (IpcDomCmd)(DomWord0 & 0xff);
RawDataSize = (DomWord0 >> 16) & 0xffff;
DomObjId = Reader.ReadInt32();
Reader.ReadInt64(); //Padding
}
RawData = Reader.ReadBytes(RawDataSize); RawData = Reader.ReadBytes(RawDataSize);
Reader.BaseStream.Seek(RecvListPos, SeekOrigin.Begin); Reader.BaseStream.Seek(RecvListPos, SeekOrigin.Begin);
@ -165,9 +139,7 @@ namespace Ryujinx.Core.OsHle.Ipc
//This is the weirdest padding I've seen so far... //This is the weirdest padding I've seen so far...
int Pad1 = 0x10 - Pad0; int Pad1 = 0x10 - Pad0;
DataLength = (DataLength + Pad0 + Pad1 + (IsDomain ? 0x10 : 0)) / 4; DataLength = (DataLength + Pad0 + Pad1) / 4;
DataLength += ResponseObjIds.Count;
Word1 = DataLength & 0x3ff; Word1 = DataLength & 0x3ff;
@ -182,23 +154,11 @@ namespace Ryujinx.Core.OsHle.Ipc
MS.Seek(Pad0, SeekOrigin.Current); MS.Seek(Pad0, SeekOrigin.Current);
if (IsDomain)
{
Writer.Write(ResponseObjIds.Count);
Writer.Write(0);
Writer.Write(0L);
}
if (RawData != null) if (RawData != null)
{ {
Writer.Write(RawData); Writer.Write(RawData);
} }
foreach (int Id in ResponseObjIds)
{
Writer.Write(Id);
}
Writer.Write(new byte[Pad1]); Writer.Write(new byte[Pad1]);
return MS.ToArray(); return MS.ToArray();

View file

@ -6,6 +6,5 @@ namespace Ryujinx.Core.OsHle
public const int InvalidHandle = 114; public const int InvalidHandle = 114;
public const int Timeout = 117; public const int Timeout = 117;
public const int InvalidInfo = 120; public const int InvalidInfo = 120;
public const int InvalidIpcReq = 123;
} }
} }

View file

@ -31,12 +31,12 @@ namespace Ryujinx.Core.OsHle
public AMemory Memory { get; private set; } public AMemory Memory { get; private set; }
public ServiceMgr Services { get; private set; }
public KProcessScheduler Scheduler { get; private set; } public KProcessScheduler Scheduler { get; private set; }
public KProcessHandleTable HandleTable { get; private set; } public KProcessHandleTable HandleTable { get; private set; }
public AppletStateMgr AppletState { get; private set; }
private SvcHandler SvcHandler; private SvcHandler SvcHandler;
private ConcurrentDictionary<int, AThread> TlsSlots; private ConcurrentDictionary<int, AThread> TlsSlots;
@ -60,12 +60,12 @@ namespace Ryujinx.Core.OsHle
Memory = new AMemory(); Memory = new AMemory();
Services = new ServiceMgr();
HandleTable = new KProcessHandleTable(); HandleTable = new KProcessHandleTable();
Scheduler = new KProcessScheduler(); Scheduler = new KProcessScheduler();
AppletState = new AppletStateMgr();
SvcHandler = new SvcHandler(Ns, this); SvcHandler = new SvcHandler(Ns, this);
TlsSlots = new ConcurrentDictionary<int, AThread>(); TlsSlots = new ConcurrentDictionary<int, AThread>();
@ -345,10 +345,14 @@ namespace Ryujinx.Core.OsHle
Disposed = true; Disposed = true;
Services.Dispose();
HandleTable.Dispose(); HandleTable.Dispose();
Scheduler.Dispose(); Scheduler.Dispose();
AppletState.Dispose();
SvcHandler.Dispose(); SvcHandler.Dispose();
Memory.Dispose(); Memory.Dispose();
Logging.Info($"Process {ProcessId} exiting..."); Logging.Info($"Process {ProcessId} exiting...");

View file

@ -10,7 +10,7 @@ namespace Ryujinx.Core.OsHle
public Switch Ns { get; private set; } public Switch Ns { get; private set; }
public Process Process { get; private set; } public Process Process { get; private set; }
public AMemory Memory { get; private set; } public AMemory Memory { get; private set; }
public HSession Session { get; private set; } public KSession Session { get; private set; }
public IpcMessage Request { get; private set; } public IpcMessage Request { get; private set; }
public IpcMessage Response { get; private set; } public IpcMessage Response { get; private set; }
public BinaryReader RequestData { get; private set; } public BinaryReader RequestData { get; private set; }
@ -20,7 +20,7 @@ namespace Ryujinx.Core.OsHle
Switch Ns, Switch Ns,
Process Process, Process Process,
AMemory Memory, AMemory Memory,
HSession Session, KSession Session,
IpcMessage Request, IpcMessage Request,
IpcMessage Response, IpcMessage Response,
BinaryReader RequestData, BinaryReader RequestData,

View file

@ -1,128 +0,0 @@
using Ryujinx.Core.OsHle.IpcServices;
using Ryujinx.Core.OsHle.IpcServices.Acc;
using Ryujinx.Core.OsHle.IpcServices.Am;
using Ryujinx.Core.OsHle.IpcServices.Apm;
using Ryujinx.Core.OsHle.IpcServices.Aud;
using Ryujinx.Core.OsHle.IpcServices.Bsd;
using Ryujinx.Core.OsHle.IpcServices.Friend;
using Ryujinx.Core.OsHle.IpcServices.FspSrv;
using Ryujinx.Core.OsHle.IpcServices.Hid;
using Ryujinx.Core.OsHle.IpcServices.Lm;
using Ryujinx.Core.OsHle.IpcServices.Nifm;
using Ryujinx.Core.OsHle.IpcServices.Ns;
using Ryujinx.Core.OsHle.IpcServices.NvServices;
using Ryujinx.Core.OsHle.IpcServices.Pctl;
using Ryujinx.Core.OsHle.IpcServices.Pl;
using Ryujinx.Core.OsHle.IpcServices.Set;
using Ryujinx.Core.OsHle.IpcServices.Sfdnsres;
using Ryujinx.Core.OsHle.IpcServices.Sm;
using Ryujinx.Core.OsHle.IpcServices.Ssl;
using Ryujinx.Core.OsHle.IpcServices.Time;
using Ryujinx.Core.OsHle.IpcServices.Vi;
using System;
using System.Collections.Generic;
namespace Ryujinx.Core.OsHle
{
class ServiceMgr : IDisposable
{
private Dictionary<string, IIpcService> Services;
public ServiceMgr()
{
Services = new Dictionary<string, IIpcService>();
}
public IIpcService GetService(string Name)
{
lock (Services)
{
string LookUpName;
//Same service with different privileges.
if (Name.EndsWith(":a") ||
Name.EndsWith(":m") ||
Name.EndsWith(":s") ||
Name.EndsWith(":su") ||
Name.EndsWith(":u") ||
Name.EndsWith(":u0") ||
Name.EndsWith(":u1"))
{
LookUpName = Name.Substring(0, Name.IndexOf(':'));
}
else
{
LookUpName = Name;
}
if (!Services.TryGetValue(LookUpName, out IIpcService Service))
{
switch (Name)
{
case "acc:u0": Service = new ServiceAcc(); break;
case "aoc:u": Service = new ServiceNs(); break;
case "apm": Service = new ServiceApm(); break;
case "apm:p": Service = new ServiceApm(); break;
case "appletOE": Service = new ServiceAppletOE(); break;
case "audout:u": Service = new ServiceAudOut(); break;
case "audren:u": Service = new ServiceAudRen(); break;
case "bsd:s": Service = new ServiceBsd(); break;
case "bsd:u": Service = new ServiceBsd(); break;
case "friend:a": Service = new ServiceFriend(); break;
case "fsp-srv": Service = new ServiceFspSrv(); break;
case "hid": Service = new ServiceHid(); break;
case "lm": Service = new ServiceLm(); break;
case "nifm:u": Service = new ServiceNifm(); break;
case "nvdrv": Service = new ServiceNvDrv(); break;
case "nvdrv:a": Service = new ServiceNvDrv(); break;
case "pctl:a": Service = new ServicePctl(); break;
case "pl:u": Service = new ServicePl(); break;
case "set": Service = new ServiceSet(); break;
case "set:sys": Service = new ServiceSetSys(); break;
case "sfdnsres": Service = new ServiceSfdnsres(); break;
case "sm:": Service = new ServiceSm(); break;
case "ssl": Service = new ServiceSsl(); break;
case "time:s": Service = new ServiceTime(); break;
case "time:u": Service = new ServiceTime(); break;
case "vi:m": Service = new ServiceVi(); break;
case "vi:s": Service = new ServiceVi(); break;
case "vi:u": Service = new ServiceVi(); break;
}
if (Service == null)
{
throw new NotImplementedException(Name);
}
Services.Add(LookUpName, Service);
}
return Service;
}
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool Disposing)
{
if (Disposing)
{
lock (Services)
{
foreach (IIpcService Service in Services.Values)
{
if (Service is IDisposable DisposableSrv)
{
DisposableSrv.Dispose();
}
}
Services.Clear();
}
}
}
}
}

View file

@ -3,11 +3,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Acc namespace Ryujinx.Core.OsHle.IpcServices.Acc
{ {
class IManagerForApplication : IIpcService class IManagerForApplication : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public IManagerForApplication() public IManagerForApplication()
{ {

View file

@ -3,11 +3,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Acc namespace Ryujinx.Core.OsHle.IpcServices.Acc
{ {
class IProfile : IIpcService class IProfile : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public IProfile() public IProfile()
{ {

View file

@ -1,15 +1,13 @@
using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic; using System.Collections.Generic;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Acc namespace Ryujinx.Core.OsHle.IpcServices.Acc
{ {
class ServiceAcc : IIpcService class ServiceAcc : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServiceAcc() public ServiceAcc()
{ {

View file

@ -0,0 +1,7 @@
namespace Ryujinx.Core.OsHle.IpcServices.Am
{
static class AmErr
{
public const int NoMessages = 3;
}
}

View file

@ -0,0 +1,8 @@
namespace Ryujinx.Core.OsHle.IpcServices.Am
{
enum FocusState
{
InFocus = 1,
OutOfFocus = 2
}
}

View file

@ -2,15 +2,13 @@ using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Am namespace Ryujinx.Core.OsHle.IpcServices.Am
{ {
class IApplicationFunctions : IIpcService class IApplicationFunctions : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public IApplicationFunctions() public IApplicationFunctions()
{ {

View file

@ -1,15 +1,13 @@
using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic; using System.Collections.Generic;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Am namespace Ryujinx.Core.OsHle.IpcServices.Am
{ {
class IApplicationProxy : IIpcService class IApplicationProxy : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public IApplicationProxy() public IApplicationProxy()
{ {

View file

@ -3,11 +3,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Am namespace Ryujinx.Core.OsHle.IpcServices.Am
{ {
class IAudioController : IIpcService class IAudioController : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public IAudioController() public IAudioController()
{ {

View file

@ -1,13 +1,16 @@
using Ryujinx.Core.OsHle.Handles;
using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic; using System.Collections.Generic;
using static Ryujinx.Core.OsHle.ErrorCode;
namespace Ryujinx.Core.OsHle.IpcServices.Am namespace Ryujinx.Core.OsHle.IpcServices.Am
{ {
class ICommonStateGetter : IIpcService class ICommonStateGetter : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ICommonStateGetter() public ICommonStateGetter()
{ {
@ -17,37 +20,31 @@ namespace Ryujinx.Core.OsHle.IpcServices.Am
{ 1, ReceiveMessage }, { 1, ReceiveMessage },
{ 5, GetOperationMode }, { 5, GetOperationMode },
{ 6, GetPerformanceMode }, { 6, GetPerformanceMode },
{ 9, GetCurrentFocusState }, { 9, GetCurrentFocusState }
}; };
} }
private enum FocusState
{
InFocus = 1,
OutOfFocus = 2
}
private enum OperationMode
{
Handheld = 0,
Docked = 1
}
public long GetEventHandle(ServiceCtx Context) public long GetEventHandle(ServiceCtx Context)
{ {
Context.ResponseData.Write(0L); KEvent Event = Context.Process.AppletState.MessageEvent;
int Handle = Context.Process.HandleTable.OpenHandle(Event);
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
return 0; return 0;
} }
public long ReceiveMessage(ServiceCtx Context) public long ReceiveMessage(ServiceCtx Context)
{ {
//Program expects 0xF at 0x17ae70 on puyo sdk, if (!Context.Process.AppletState.TryDequeueMessage(out MessageInfo Message))
//otherwise runs on a infinite loop until it reads said value. {
//What it means is still unknown. return MakeError(ErrorModule.Am, AmErr.NoMessages);
Context.ResponseData.Write(0xfL); }
return 0; //0x680; Context.ResponseData.Write((int)Message);
return 0;
} }
public long GetOperationMode(ServiceCtx Context) public long GetOperationMode(ServiceCtx Context)
@ -66,7 +63,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Am
public long GetCurrentFocusState(ServiceCtx Context) public long GetCurrentFocusState(ServiceCtx Context)
{ {
Context.ResponseData.Write((byte)FocusState.InFocus); Context.ResponseData.Write((byte)Context.Process.AppletState.FocusState);
return 0; return 0;
} }

View file

@ -3,11 +3,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Am namespace Ryujinx.Core.OsHle.IpcServices.Am
{ {
class IDebugFunctions : IIpcService class IDebugFunctions : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public IDebugFunctions() public IDebugFunctions()
{ {

View file

@ -3,11 +3,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Am namespace Ryujinx.Core.OsHle.IpcServices.Am
{ {
class IDisplayController : IIpcService class IDisplayController : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public IDisplayController() public IDisplayController()
{ {

View file

@ -3,11 +3,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Am namespace Ryujinx.Core.OsHle.IpcServices.Am
{ {
class ILibraryAppletCreator : IIpcService class ILibraryAppletCreator : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ILibraryAppletCreator() public ILibraryAppletCreator()
{ {

View file

@ -3,11 +3,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Am namespace Ryujinx.Core.OsHle.IpcServices.Am
{ {
class ISelfController : IIpcService class ISelfController : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ISelfController() public ISelfController()
{ {

View file

@ -1,15 +1,13 @@
using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic; using System.Collections.Generic;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Am namespace Ryujinx.Core.OsHle.IpcServices.Am
{ {
class IStorage : IIpcService class IStorage : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public byte[] Data { get; private set; } public byte[] Data { get; private set; }

View file

@ -5,11 +5,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Am namespace Ryujinx.Core.OsHle.IpcServices.Am
{ {
class IStorageAccessor : IIpcService class IStorageAccessor : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
private IStorage Storage; private IStorage Storage;

View file

@ -3,11 +3,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Am namespace Ryujinx.Core.OsHle.IpcServices.Am
{ {
class IWindowController : IIpcService class IWindowController : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public IWindowController() public IWindowController()
{ {

View file

@ -0,0 +1,9 @@
namespace Ryujinx.Core.OsHle.IpcServices.Am
{
enum MessageInfo
{
FocusStateChanged = 0xf,
OperationModeChanged = 0x1e,
PerformanceModeChanged = 0x1f
}
}

View file

@ -0,0 +1,8 @@
namespace Ryujinx.Core.OsHle.IpcServices.Am
{
enum OperationMode
{
Handheld = 0,
Docked = 1
}
}

View file

@ -1,15 +1,13 @@
using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic; using System.Collections.Generic;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Am namespace Ryujinx.Core.OsHle.IpcServices.Am
{ {
class ServiceAppletOE : IIpcService class ServiceAppletOE : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServiceAppletOE() public ServiceAppletOE()
{ {

View file

@ -3,11 +3,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Apm namespace Ryujinx.Core.OsHle.IpcServices.Apm
{ {
class ISession : IIpcService class ISession : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ISession() public ISession()
{ {

View file

@ -1,15 +1,13 @@
using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic; using System.Collections.Generic;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Apm namespace Ryujinx.Core.OsHle.IpcServices.Apm
{ {
class ServiceApm : IIpcService class ServiceApm : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServiceApm() public ServiceApm()
{ {

View file

@ -5,11 +5,11 @@ using System.Text;
namespace Ryujinx.Core.OsHle.IpcServices.Aud namespace Ryujinx.Core.OsHle.IpcServices.Aud
{ {
class IAudioDevice : IIpcService class IAudioDevice : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public IAudioDevice() public IAudioDevice()
{ {

View file

@ -7,17 +7,19 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Aud namespace Ryujinx.Core.OsHle.IpcServices.Aud
{ {
class IAudioOut : IIpcService, IDisposable class IAudioOut : IpcService, IDisposable
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
private IAalOutput AudioOut; private IAalOutput AudioOut;
private KEvent ReleaseEvent;
private int Track; private int Track;
public IAudioOut(IAalOutput AudioOut, int Track) public IAudioOut(IAalOutput AudioOut, KEvent ReleaseEvent, int Track)
{ {
m_Commands = new Dictionary<int, ServiceProcessRequest>() m_Commands = new Dictionary<int, ServiceProcessRequest>()
{ {
@ -32,8 +34,9 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud
{ 8, GetReleasedAudioOutBufferEx } { 8, GetReleasedAudioOutBufferEx }
}; };
this.AudioOut = AudioOut; this.AudioOut = AudioOut;
this.Track = Track; this.ReleaseEvent = ReleaseEvent;
this.Track = Track;
} }
public long GetAudioOutState(ServiceCtx Context) public long GetAudioOutState(ServiceCtx Context)
@ -77,7 +80,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud
public long RegisterBufferEvent(ServiceCtx Context) public long RegisterBufferEvent(ServiceCtx Context)
{ {
int Handle = Context.Process.HandleTable.OpenHandle(new HEvent()); int Handle = Context.Process.HandleTable.OpenHandle(ReleaseEvent);
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
@ -143,6 +146,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud
if (Disposing) if (Disposing)
{ {
AudioOut.CloseTrack(Track); AudioOut.CloseTrack(Track);
ReleaseEvent.Dispose();
} }
} }
} }

View file

@ -1,14 +1,17 @@
using Ryujinx.Core.OsHle.Handles; using Ryujinx.Core.OsHle.Handles;
using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.Ipc;
using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Aud namespace Ryujinx.Core.OsHle.IpcServices.Aud
{ {
class IAudioRenderer : IIpcService class IAudioRenderer : IpcService, IDisposable
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
private KEvent UpdateEvent;
public IAudioRenderer() public IAudioRenderer()
{ {
@ -19,6 +22,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud
{ 6, StopAudioRenderer }, { 6, StopAudioRenderer },
{ 7, QuerySystemEvent } { 7, QuerySystemEvent }
}; };
UpdateEvent = new KEvent();
} }
public long RequestUpdateAudioRenderer(ServiceCtx Context) public long RequestUpdateAudioRenderer(ServiceCtx Context)
@ -41,6 +46,9 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud
Context.Memory.WriteInt32(Position + Offset, 5); Context.Memory.WriteInt32(Position + Offset, 5);
} }
//TODO: We shouldn't be signaling this here.
UpdateEvent.Handle.Set();
return 0; return 0;
} }
@ -56,11 +64,24 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud
public long QuerySystemEvent(ServiceCtx Context) public long QuerySystemEvent(ServiceCtx Context)
{ {
int Handle = Context.Process.HandleTable.OpenHandle(new HEvent()); int Handle = Context.Process.HandleTable.OpenHandle(UpdateEvent);
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
return 0; return 0;
} }
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool Disposing)
{
if (Disposing)
{
UpdateEvent.Dispose();
}
}
} }
} }

View file

@ -1,18 +1,17 @@
using ChocolArm64.Memory; using ChocolArm64.Memory;
using Ryujinx.Audio; using Ryujinx.Audio;
using Ryujinx.Core.OsHle.Handles;
using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Aud namespace Ryujinx.Core.OsHle.IpcServices.Aud
{ {
class ServiceAudOut : IIpcService class ServiceAudOut : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServiceAudOut() public ServiceAudOut()
{ {
@ -73,9 +72,16 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud
Channels = 2; Channels = 2;
} }
int Track = AudioOut.OpenTrack(SampleRate, Channels, out AudioFormat Format); KEvent ReleaseEvent = new KEvent();
MakeObject(Context, new IAudioOut(AudioOut, Track)); ReleaseCallback Callback = () =>
{
ReleaseEvent.Handle.Set();
};
int Track = AudioOut.OpenTrack(SampleRate, Channels, Callback, out AudioFormat Format);
MakeObject(Context, new IAudioOut(AudioOut, ReleaseEvent, Track));
Context.ResponseData.Write(SampleRate); Context.ResponseData.Write(SampleRate);
Context.ResponseData.Write(Channels); Context.ResponseData.Write(Channels);

View file

@ -1,15 +1,13 @@
using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic; using System.Collections.Generic;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Aud namespace Ryujinx.Core.OsHle.IpcServices.Aud
{ {
class ServiceAudRen : IIpcService class ServiceAudRen : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServiceAudRen() public ServiceAudRen()
{ {

View file

@ -51,11 +51,11 @@ namespace Ryujinx.Core.OsHle.IpcServices.Bsd
public Socket Handle; public Socket Handle;
} }
class ServiceBsd : IIpcService class ServiceBsd : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
private List<SocketBsd> Sockets = new List<SocketBsd>(); private List<SocketBsd> Sockets = new List<SocketBsd>();

View file

@ -3,11 +3,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Friend namespace Ryujinx.Core.OsHle.IpcServices.Friend
{ {
class IFriendService : IIpcService class IFriendService : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public IFriendService() public IFriendService()
{ {

View file

@ -1,15 +1,13 @@
using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic; using System.Collections.Generic;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Friend namespace Ryujinx.Core.OsHle.IpcServices.Friend
{ {
class ServiceFriend : IIpcService class ServiceFriend : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServiceFriend() public ServiceFriend()
{ {

View file

@ -7,13 +7,13 @@ using System.Text;
namespace Ryujinx.Core.OsHle.IpcServices.FspSrv namespace Ryujinx.Core.OsHle.IpcServices.FspSrv
{ {
class IDirectory : IIpcService, IDisposable class IDirectory : IpcService, IDisposable
{ {
private const int DirectoryEntrySize = 0x310; private const int DirectoryEntrySize = 0x310;
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
private List<string> DirectoryEntries; private List<string> DirectoryEntries;

View file

@ -6,11 +6,11 @@ using System.IO;
namespace Ryujinx.Core.OsHle.IpcServices.FspSrv namespace Ryujinx.Core.OsHle.IpcServices.FspSrv
{ {
class IFile : IIpcService, IDisposable class IFile : IpcService, IDisposable
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
private Stream BaseStream; private Stream BaseStream;

View file

@ -5,15 +5,14 @@ using System.IO;
using System.Text; using System.Text;
using static Ryujinx.Core.OsHle.ErrorCode; using static Ryujinx.Core.OsHle.ErrorCode;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.FspSrv namespace Ryujinx.Core.OsHle.IpcServices.FspSrv
{ {
class IFileSystem : IIpcService class IFileSystem : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
private HashSet<string> OpenPaths; private HashSet<string> OpenPaths;

View file

@ -5,11 +5,11 @@ using System.IO;
namespace Ryujinx.Core.OsHle.IpcServices.FspSrv namespace Ryujinx.Core.OsHle.IpcServices.FspSrv
{ {
class IStorage : IIpcService class IStorage : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
private Stream BaseStream; private Stream BaseStream;

View file

@ -1,15 +1,13 @@
using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic; using System.Collections.Generic;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.FspSrv namespace Ryujinx.Core.OsHle.IpcServices.FspSrv
{ {
class ServiceFspSrv : IIpcService class ServiceFspSrv : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServiceFspSrv() public ServiceFspSrv()
{ {

View file

@ -3,11 +3,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Hid namespace Ryujinx.Core.OsHle.IpcServices.Hid
{ {
class IActiveApplicationDeviceList : IIpcService class IActiveApplicationDeviceList : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public IActiveApplicationDeviceList() public IActiveApplicationDeviceList()
{ {

View file

@ -4,11 +4,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Hid namespace Ryujinx.Core.OsHle.IpcServices.Hid
{ {
class IAppletResource : IIpcService class IAppletResource : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
private HSharedMem HidSharedMem; private HSharedMem HidSharedMem;

View file

@ -2,15 +2,13 @@ using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic; using System.Collections.Generic;
using Ryujinx.Core.Input; using Ryujinx.Core.Input;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Hid namespace Ryujinx.Core.OsHle.IpcServices.Hid
{ {
class ServiceHid : IIpcService class ServiceHid : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServiceHid() public ServiceHid()
{ {

View file

@ -0,0 +1,144 @@
using Ryujinx.Core.OsHle.Ipc;
using Ryujinx.Core.OsHle.Handles;
using System;
using System.Collections.Generic;
using System.IO;
namespace Ryujinx.Core.OsHle.IpcServices
{
abstract class IpcService : IIpcService
{
public abstract IReadOnlyDictionary<int, ServiceProcessRequest> Commands { get; }
private IdDictionary DomainObjects;
private int SelfId;
private bool IsDomain;
public IpcService()
{
DomainObjects = new IdDictionary();
SelfId = -1;
}
public int ConvertToDomain()
{
if (SelfId == -1)
{
SelfId = DomainObjects.Add(this);
}
IsDomain = true;
return SelfId;
}
public void ConvertToSession()
{
IsDomain = false;
}
private int Add(IIpcService Obj)
{
return DomainObjects.Add(Obj);
}
private bool Delete(int Id)
{
return DomainObjects.Delete(Id);
}
private IIpcService GetObject(int Id)
{
return DomainObjects.GetData<IIpcService>(Id);
}
public void CallMethod(ServiceCtx Context)
{
IIpcService Service = this;
if (IsDomain)
{
int DomainWord0 = Context.RequestData.ReadInt32();
int DomainObjId = Context.RequestData.ReadInt32();
long Padding = Context.RequestData.ReadInt64();
int DomainCmd = DomainWord0 & 0xff;
if (DomainCmd == 1)
{
Service = GetObject(DomainObjId);
Context.ResponseData.Write(0L);
Context.ResponseData.Write(0L);
}
else if (DomainCmd == 2)
{
Delete(DomainObjId);
Context.ResponseData.Write(0L);
return;
}
else
{
throw new NotImplementedException($"Domain command: {DomainCmd}");
}
}
long SfciMagic = Context.RequestData.ReadInt64();
int CommandId = (int)Context.RequestData.ReadInt64();
if (Service.Commands.TryGetValue(CommandId, out ServiceProcessRequest ProcessRequest))
{
Context.ResponseData.BaseStream.Seek(IsDomain ? 0x20 : 0x10, SeekOrigin.Begin);
Logging.Trace($"{Service.GetType().Name}: {ProcessRequest.Method.Name}");
long Result = ProcessRequest(Context);
if (IsDomain)
{
foreach (int Id in Context.Response.ResponseObjIds)
{
Context.ResponseData.Write(Id);
}
Context.ResponseData.BaseStream.Seek(0, SeekOrigin.Begin);
Context.ResponseData.Write(Context.Response.ResponseObjIds.Count);
}
Context.ResponseData.BaseStream.Seek(IsDomain ? 0x10 : 0, SeekOrigin.Begin);
Context.ResponseData.Write(IpcMagic.Sfco);
Context.ResponseData.Write(Result);
}
else
{
throw new NotImplementedException($"{Service.GetType().Name}: {CommandId}");
}
}
protected static void MakeObject(ServiceCtx Context, IpcService Obj)
{
IpcService Service = Context.Session.Service;
if (Service.IsDomain)
{
Context.Response.ResponseObjIds.Add(Service.Add(Obj));
}
else
{
KSession Session = new KSession(Obj);
int Handle = Context.Process.HandleTable.OpenHandle(Session);
Context.Response.HandleDesc = IpcHandleDesc.MakeMove(Handle);
}
}
}
}

View file

@ -7,11 +7,11 @@ using System.Text;
namespace Ryujinx.Core.OsHle.IpcServices.Lm namespace Ryujinx.Core.OsHle.IpcServices.Lm
{ {
class ILogger : IIpcService class ILogger : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ILogger() public ILogger()
{ {

View file

@ -1,15 +1,13 @@
using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic; using System.Collections.Generic;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Lm namespace Ryujinx.Core.OsHle.IpcServices.Lm
{ {
class ServiceLm : IIpcService class ServiceLm : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServiceLm() public ServiceLm()
{ {
@ -21,8 +19,6 @@ namespace Ryujinx.Core.OsHle.IpcServices.Lm
public long Initialize(ServiceCtx Context) public long Initialize(ServiceCtx Context)
{ {
Context.Session.Initialize();
MakeObject(Context, new ILogger()); MakeObject(Context, new ILogger());
return 0; return 0;

View file

@ -1,15 +1,13 @@
using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic; using System.Collections.Generic;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Nifm namespace Ryujinx.Core.OsHle.IpcServices.Nifm
{ {
class IGeneralService : IIpcService class IGeneralService : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public IGeneralService() public IGeneralService()
{ {

View file

@ -1,13 +1,17 @@
using Ryujinx.Core.OsHle.Handles;
using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.Ipc;
using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Nifm namespace Ryujinx.Core.OsHle.IpcServices.Nifm
{ {
class IRequest : IIpcService class IRequest : IpcService, IDisposable
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
private KEvent Event;
public IRequest() public IRequest()
{ {
@ -17,9 +21,10 @@ namespace Ryujinx.Core.OsHle.IpcServices.Nifm
{ 1, GetResult }, { 1, GetResult },
{ 2, GetSystemEventReadableHandles } { 2, GetSystemEventReadableHandles }
}; };
Event = new KEvent();
} }
// -> i32
public long GetRequestState(ServiceCtx Context) public long GetRequestState(ServiceCtx Context)
{ {
Context.ResponseData.Write(0); Context.ResponseData.Write(0);
@ -39,11 +44,25 @@ namespace Ryujinx.Core.OsHle.IpcServices.Nifm
//GetSystemEventReadableHandles() -> (KObject, KObject) //GetSystemEventReadableHandles() -> (KObject, KObject)
public long GetSystemEventReadableHandles(ServiceCtx Context) public long GetSystemEventReadableHandles(ServiceCtx Context)
{ {
Context.Response.HandleDesc = IpcHandleDesc.MakeMove(0xbadcafe); //FIXME: Is this supposed to return 2 events?
int Handle = Context.Process.HandleTable.OpenHandle(Event);
//Todo: Stub Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
return 0; return 0;
} }
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool Disposing)
{
if (Disposing)
{
Event.Dispose();
}
}
} }
} }

View file

@ -1,15 +1,13 @@
using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic; using System.Collections.Generic;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Nifm namespace Ryujinx.Core.OsHle.IpcServices.Nifm
{ {
class ServiceNifm : IIpcService class ServiceNifm : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServiceNifm() public ServiceNifm()
{ {

View file

@ -3,11 +3,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Ns namespace Ryujinx.Core.OsHle.IpcServices.Ns
{ {
class ServiceNs : IIpcService class ServiceNs : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServiceNs() public ServiceNs()
{ {

View file

@ -1,4 +1,5 @@
using ChocolArm64.Memory; using ChocolArm64.Memory;
using Ryujinx.Core.OsHle.Handles;
using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.Ipc;
using Ryujinx.Core.OsHle.Utilities; using Ryujinx.Core.OsHle.Utilities;
using Ryujinx.Graphics.Gpu; using Ryujinx.Graphics.Gpu;
@ -7,20 +8,22 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.NvServices namespace Ryujinx.Core.OsHle.IpcServices.NvServices
{ {
class ServiceNvDrv : IIpcService class ServiceNvDrv : IpcService, IDisposable
{ {
private delegate long ServiceProcessIoctl(ServiceCtx Context); private delegate long ServiceProcessIoctl(ServiceCtx Context);
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
private Dictionary<(string, int), ServiceProcessIoctl> IoctlCmds; private Dictionary<(string, int), ServiceProcessIoctl> IoctlCmds;
private IdDictionary Fds; private static GlobalStateTable Fds;
private IdDictionary NvMaps; public static GlobalStateTable NvMaps { get; private set; }
private IdDictionary NvMapsById; public static GlobalStateTable NvMapsById { get; private set; }
private KEvent Event;
public ServiceNvDrv() public ServiceNvDrv()
{ {
@ -64,10 +67,15 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
{ ("/dev/nvmap", 0x010e), NvMapIocGetId }, { ("/dev/nvmap", 0x010e), NvMapIocGetId },
}; };
Fds = new IdDictionary(); Event = new KEvent();
}
NvMaps = new IdDictionary(); static ServiceNvDrv()
NvMapsById = new IdDictionary(); {
Fds = new GlobalStateTable();
NvMaps = new GlobalStateTable();
NvMapsById = new GlobalStateTable();
} }
public long Open(ServiceCtx Context) public long Open(ServiceCtx Context)
@ -76,7 +84,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
string Name = AMemoryHelper.ReadAsciiString(Context.Memory, NamePtr); string Name = AMemoryHelper.ReadAsciiString(Context.Memory, NamePtr);
int Fd = Fds.Add(new NvFd(Name)); int Fd = Fds.Add(Context.Process, new NvFd(Name));
Context.ResponseData.Write(Fd); Context.ResponseData.Write(Fd);
Context.ResponseData.Write(0); Context.ResponseData.Write(0);
@ -89,7 +97,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
int Fd = Context.RequestData.ReadInt32(); int Fd = Context.RequestData.ReadInt32();
int Cmd = Context.RequestData.ReadInt32() & 0xffff; int Cmd = Context.RequestData.ReadInt32() & 0xffff;
NvFd FdData = Fds.GetData<NvFd>(Fd); NvFd FdData = Fds.GetData<NvFd>(Context.Process, Fd);
long Position = Context.Request.GetSendBuffPtr(); long Position = Context.Request.GetSendBuffPtr();
@ -109,7 +117,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
{ {
int Fd = Context.RequestData.ReadInt32(); int Fd = Context.RequestData.ReadInt32();
Fds.Delete(Fd); Fds.Delete(Context.Process, Fd);
Context.ResponseData.Write(0); Context.ResponseData.Write(0);
@ -131,7 +139,10 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
int Fd = Context.RequestData.ReadInt32(); int Fd = Context.RequestData.ReadInt32();
int EventId = Context.RequestData.ReadInt32(); int EventId = Context.RequestData.ReadInt32();
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(0xcafe); //TODO: Use Fd/EventId, different channels have different events.
int Handle = Context.Process.HandleTable.OpenHandle(Event);
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
Context.ResponseData.Write(0); Context.ResponseData.Write(0);
@ -203,7 +214,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
return 0; return 0;
} }
NvMap Map = NvMaps.GetData<NvMap>(Handle); NvMap Map = NvMaps.GetData<NvMap>(Context.Process, Handle);
if (Map == null) if (Map == null)
{ {
@ -550,9 +561,9 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
NvMap Map = new NvMap() { Size = Size }; NvMap Map = new NvMap() { Size = Size };
Map.Handle = NvMaps.Add(Map); Map.Handle = NvMaps.Add(Context.Process, Map);
Map.Id = NvMapsById.Add(Map); Map.Id = NvMapsById.Add(Context.Process, Map);
Context.Memory.WriteInt32(Position + 4, Map.Handle); Context.Memory.WriteInt32(Position + 4, Map.Handle);
@ -567,7 +578,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
int Id = Context.Memory.ReadInt32(Position); int Id = Context.Memory.ReadInt32(Position);
NvMap Map = NvMapsById.GetData<NvMap>(Id); NvMap Map = NvMapsById.GetData<NvMap>(Context.Process, Id);
if (Map == null) if (Map == null)
{ {
@ -594,7 +605,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
byte Kind = (byte)Reader.ReadInt64(); byte Kind = (byte)Reader.ReadInt64();
long Addr = Reader.ReadInt64(); long Addr = Reader.ReadInt64();
NvMap Map = NvMaps.GetData<NvMap>(Handle); NvMap Map = NvMaps.GetData<NvMap>(Context.Process, Handle);
if (Map == null) if (Map == null)
{ {
@ -620,7 +631,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
int Handle = Reader.ReadInt32(); int Handle = Reader.ReadInt32();
int Padding = Reader.ReadInt32(); int Padding = Reader.ReadInt32();
NvMap Map = NvMaps.GetData<NvMap>(Handle); NvMap Map = NvMaps.GetData<NvMap>(Context.Process, Handle);
if (Map == null) if (Map == null)
{ {
@ -645,7 +656,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
int Handle = Reader.ReadInt32(); int Handle = Reader.ReadInt32();
int Param = Reader.ReadInt32(); int Param = Reader.ReadInt32();
NvMap Map = NvMaps.GetData<NvMap>(Handle); NvMap Map = NvMaps.GetData<NvMap>(Context.Process, Handle);
if (Map == null) if (Map == null)
{ {
@ -675,7 +686,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
int Handle = Context.Memory.ReadInt32(Position + 4); int Handle = Context.Memory.ReadInt32(Position + 4);
NvMap Map = NvMaps.GetData<NvMap>(Handle); NvMap Map = NvMaps.GetData<NvMap>(Context.Process, Handle);
if (Map == null) if (Map == null)
{ {
@ -689,9 +700,17 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
return 0; return 0;
} }
public NvMap GetNvMap(int Handle) public void Dispose()
{ {
return NvMaps.GetData<NvMap>(Handle); Dispose(true);
}
protected virtual void Dispose(bool Disposing)
{
if (Disposing)
{
Event.Dispose();
}
} }
} }
} }

View file

@ -1,24 +0,0 @@
using Ryujinx.Core.OsHle.Handles;
using Ryujinx.Core.OsHle.Ipc;
namespace Ryujinx.Core.OsHle.IpcServices
{
static class ObjHelper
{
public static void MakeObject(ServiceCtx Context, object Obj)
{
if (Context.Session is HDomain Dom)
{
Context.Response.ResponseObjIds.Add(Dom.Add(Obj));
}
else
{
HSessionObj HndData = new HSessionObj(Context.Session, Obj);
int VHandle = Context.Process.HandleTable.OpenHandle(HndData);
Context.Response.HandleDesc = IpcHandleDesc.MakeMove(VHandle);
}
}
}
}

View file

@ -3,11 +3,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Pctl namespace Ryujinx.Core.OsHle.IpcServices.Pctl
{ {
class IParentalControlService : IIpcService class IParentalControlService : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public IParentalControlService() public IParentalControlService()
{ {

View file

@ -1,15 +1,13 @@
using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic; using System.Collections.Generic;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Pctl namespace Ryujinx.Core.OsHle.IpcServices.Pctl
{ {
class ServicePctl : IIpcService class ServicePctl : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServicePctl() public ServicePctl()
{ {

View file

@ -3,11 +3,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Pl namespace Ryujinx.Core.OsHle.IpcServices.Pl
{ {
class ServicePl : IIpcService class ServicePl : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServicePl() public ServicePl()
{ {

View file

@ -0,0 +1,119 @@
using Ryujinx.Core.OsHle.IpcServices.Acc;
using Ryujinx.Core.OsHle.IpcServices.Am;
using Ryujinx.Core.OsHle.IpcServices.Apm;
using Ryujinx.Core.OsHle.IpcServices.Aud;
using Ryujinx.Core.OsHle.IpcServices.Bsd;
using Ryujinx.Core.OsHle.IpcServices.Friend;
using Ryujinx.Core.OsHle.IpcServices.FspSrv;
using Ryujinx.Core.OsHle.IpcServices.Hid;
using Ryujinx.Core.OsHle.IpcServices.Lm;
using Ryujinx.Core.OsHle.IpcServices.Nifm;
using Ryujinx.Core.OsHle.IpcServices.Ns;
using Ryujinx.Core.OsHle.IpcServices.NvServices;
using Ryujinx.Core.OsHle.IpcServices.Pctl;
using Ryujinx.Core.OsHle.IpcServices.Pl;
using Ryujinx.Core.OsHle.IpcServices.Set;
using Ryujinx.Core.OsHle.IpcServices.Sfdnsres;
using Ryujinx.Core.OsHle.IpcServices.Sm;
using Ryujinx.Core.OsHle.IpcServices.Ssl;
using Ryujinx.Core.OsHle.IpcServices.Time;
using Ryujinx.Core.OsHle.IpcServices.Vi;
using System;
namespace Ryujinx.Core.OsHle.IpcServices
{
static class ServiceFactory
{
public static IpcService MakeService(string Name)
{
switch (Name)
{
case "acc:u0":
return new ServiceAcc();
case "aoc:u":
return new ServiceNs();
case "apm":
return new ServiceApm();
case "apm:p":
return new ServiceApm();
case "appletOE":
return new ServiceAppletOE();
case "audout:u":
return new ServiceAudOut();
case "audren:u":
return new ServiceAudRen();
case "bsd:s":
return new ServiceBsd();
case "bsd:u":
return new ServiceBsd();
case "friend:a":
return new ServiceFriend();
case "fsp-srv":
return new ServiceFspSrv();
case "hid":
return new ServiceHid();
case "lm":
return new ServiceLm();
case "nifm:u":
return new ServiceNifm();
case "nvdrv":
return new ServiceNvDrv();
case "nvdrv:a":
return new ServiceNvDrv();
case "pctl:a":
return new ServicePctl();
case "pl:u":
return new ServicePl();
case "set":
return new ServiceSet();
case "set:sys":
return new ServiceSetSys();
case "sfdnsres":
return new ServiceSfdnsres();
case "sm:":
return new ServiceSm();
case "ssl":
return new ServiceSsl();
case "time:s":
return new ServiceTime();
case "time:u":
return new ServiceTime();
case "vi:m":
return new ServiceVi();
case "vi:s":
return new ServiceVi();
case "vi:u":
return new ServiceVi();
}
throw new NotImplementedException(Name);
}
}
}

View file

@ -5,11 +5,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Set namespace Ryujinx.Core.OsHle.IpcServices.Set
{ {
class ServiceSet : IIpcService class ServiceSet : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServiceSet() public ServiceSet()
{ {

View file

@ -3,11 +3,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Set namespace Ryujinx.Core.OsHle.IpcServices.Set
{ {
class ServiceSetSys : IIpcService class ServiceSetSys : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServiceSetSys() public ServiceSetSys()
{ {

View file

@ -3,11 +3,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Sfdnsres namespace Ryujinx.Core.OsHle.IpcServices.Sfdnsres
{ {
class ServiceSfdnsres : IIpcService class ServiceSfdnsres : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServiceSfdnsres() public ServiceSfdnsres()
{ {

View file

@ -4,11 +4,13 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Sm namespace Ryujinx.Core.OsHle.IpcServices.Sm
{ {
class ServiceSm : IIpcService class ServiceSm : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
private bool IsInitialized;
public ServiceSm() public ServiceSm()
{ {
@ -23,7 +25,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Sm
public long Initialize(ServiceCtx Context) public long Initialize(ServiceCtx Context)
{ {
Context.Session.Initialize(); IsInitialized = true;
return 0; return 0;
} }
@ -31,7 +33,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Sm
public long GetService(ServiceCtx Context) public long GetService(ServiceCtx Context)
{ {
//Only for kernel version > 3.0.0. //Only for kernel version > 3.0.0.
if (!Context.Session.IsInitialized) if (!IsInitialized)
{ {
//return SmNotInitialized; //return SmNotInitialized;
} }
@ -55,7 +57,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Sm
return 0; return 0;
} }
HSession Session = new HSession(Context.Process.Services.GetService(Name)); KSession Session = new KSession(ServiceFactory.MakeService(Name));
int Handle = Context.Process.HandleTable.OpenHandle(Session); int Handle = Context.Process.HandleTable.OpenHandle(Session);

View file

@ -3,11 +3,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Ssl namespace Ryujinx.Core.OsHle.IpcServices.Ssl
{ {
class ServiceSsl : IIpcService class ServiceSsl : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServiceSsl() public ServiceSsl()
{ {

View file

@ -3,11 +3,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Time namespace Ryujinx.Core.OsHle.IpcServices.Time
{ {
class ISteadyClock : IIpcService class ISteadyClock : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ISteadyClock() public ISteadyClock()
{ {

View file

@ -4,11 +4,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Time namespace Ryujinx.Core.OsHle.IpcServices.Time
{ {
class ISystemClock : IIpcService class ISystemClock : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
private static DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); private static DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);

View file

@ -4,11 +4,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Time namespace Ryujinx.Core.OsHle.IpcServices.Time
{ {
class ITimeZoneService : IIpcService class ITimeZoneService : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
private static DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Local); private static DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Local);

View file

@ -1,15 +1,13 @@
using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic; using System.Collections.Generic;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Time namespace Ryujinx.Core.OsHle.IpcServices.Time
{ {
class ServiceTime : IIpcService class ServiceTime : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServiceTime() public ServiceTime()
{ {

View file

@ -1,19 +1,17 @@
using ChocolArm64.Memory; using ChocolArm64.Memory;
using Ryujinx.Core.OsHle.Handles;
using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using static Ryujinx.Core.OsHle.IpcServices.Android.Parcel; using static Ryujinx.Core.OsHle.IpcServices.Android.Parcel;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Vi namespace Ryujinx.Core.OsHle.IpcServices.Vi
{ {
class IApplicationDisplayService : IIpcService class IApplicationDisplayService : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
private IdDictionary Displays; private IdDictionary Displays;
@ -145,7 +143,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi
{ {
string Name = GetDisplayName(Context); string Name = GetDisplayName(Context);
int Handle = Context.Process.HandleTable.OpenHandle(new HEvent()); int Handle = Context.Process.HandleTable.OpenHandle(Context.Ns.Os.VsyncEvent);
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);

View file

@ -7,11 +7,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Vi namespace Ryujinx.Core.OsHle.IpcServices.Vi
{ {
class IHOSBinderDriver : IIpcService, IDisposable class IHOSBinderDriver : IpcService, IDisposable
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
private NvFlinger Flinger; private NvFlinger Flinger;

View file

@ -3,11 +3,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Vi namespace Ryujinx.Core.OsHle.IpcServices.Vi
{ {
class IManagerDisplayService : IIpcService class IManagerDisplayService : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public IManagerDisplayService() public IManagerDisplayService()
{ {

View file

@ -3,11 +3,11 @@ using System.Collections.Generic;
namespace Ryujinx.Core.OsHle.IpcServices.Vi namespace Ryujinx.Core.OsHle.IpcServices.Vi
{ {
class ISystemDisplayService : IIpcService class ISystemDisplayService : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ISystemDisplayService() public ISystemDisplayService()
{ {

View file

@ -397,9 +397,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android
NvMapHandle = BitConverter.ToInt32(RawValue, 0); NvMapHandle = BitConverter.ToInt32(RawValue, 0);
} }
ServiceNvDrv NvDrv = (ServiceNvDrv)Context.Process.Services.GetService("nvdrv"); return ServiceNvDrv.NvMaps.GetData<NvMap>(Context.Process, NvMapHandle);
return NvDrv.GetNvMap(NvMapHandle);
} }
private int GetFreeSlotBlocking(int Width, int Height) private int GetFreeSlotBlocking(int Width, int Height)

View file

@ -1,15 +1,13 @@
using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic; using System.Collections.Generic;
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
namespace Ryujinx.Core.OsHle.IpcServices.Vi namespace Ryujinx.Core.OsHle.IpcServices.Vi
{ {
class ServiceVi : IIpcService class ServiceVi : IpcService
{ {
private Dictionary<int, ServiceProcessRequest> m_Commands; private Dictionary<int, ServiceProcessRequest> m_Commands;
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands; public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
public ServiceVi() public ServiceVi()
{ {

View file

@ -3,6 +3,7 @@ using ChocolArm64.State;
using Ryujinx.Core.OsHle.Exceptions; using Ryujinx.Core.OsHle.Exceptions;
using Ryujinx.Core.OsHle.Handles; using Ryujinx.Core.OsHle.Handles;
using Ryujinx.Core.OsHle.Ipc; using Ryujinx.Core.OsHle.Ipc;
using Ryujinx.Core.OsHle.IpcServices;
using System; using System;
using System.Threading; using System.Threading;
@ -43,25 +44,78 @@ namespace Ryujinx.Core.OsHle.Svc
{ {
int Handle = (int)ThreadState.X0; int Handle = (int)ThreadState.X0;
//TODO: Implement events. KEvent Event = Process.HandleTable.GetData<KEvent>(Handle);
ThreadState.X0 = 0; if (Event != null)
{
Event.Handle.Reset();
ThreadState.X0 = 0;
}
else
{
Logging.Warn($"Tried to ResetSignal on invalid event handle 0x{Handle:x8}!");
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
}
} }
private void SvcWaitSynchronization(AThreadState ThreadState) private void SvcWaitSynchronization(AThreadState ThreadState)
{ {
long HandlesPtr = (long)ThreadState.X0; long HandlesPtr = (long)ThreadState.X1;
int HandlesCount = (int)ThreadState.X2; int HandlesCount = (int)ThreadState.X2;
long Timeout = (long)ThreadState.X3; long Timeout = (long)ThreadState.X3;
//TODO: Implement events.
HThread CurrThread = Process.GetThread(ThreadState.Tpidr); HThread CurrThread = Process.GetThread(ThreadState.Tpidr);
WaitHandle[] Handles = new WaitHandle[HandlesCount];
for (int Index = 0; Index < HandlesCount; Index++)
{
int Handle = Memory.ReadInt32(HandlesPtr + Index * 4);
KSynchronizationObject SyncObj = Process.HandleTable.GetData<KSynchronizationObject>(Handle);
if (SyncObj == null)
{
Logging.Warn($"Tried to WaitSynchronization on invalid handle 0x{Handle:x8}!");
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
return;
}
Handles[Index] = SyncObj.Handle;
}
Process.Scheduler.Suspend(CurrThread.ProcessorId); Process.Scheduler.Suspend(CurrThread.ProcessorId);
int HandleIndex;
ulong Result = 0;
if (Timeout != -1)
{
HandleIndex = WaitHandle.WaitAny(Handles, (int)(Timeout / 1000000));
if (HandleIndex == WaitHandle.WaitTimeout)
{
Result = MakeError(ErrorModule.Kernel, KernelErr.Timeout);
}
}
else
{
HandleIndex = WaitHandle.WaitAny(Handles);
}
Process.Scheduler.Resume(CurrThread); Process.Scheduler.Resume(CurrThread);
ThreadState.X0 = 0; ThreadState.X0 = Result;
if (Result == 0)
{
ThreadState.X1 = (ulong)HandleIndex;
}
} }
private void SvcGetSystemTick(AThreadState ThreadState) private void SvcGetSystemTick(AThreadState ThreadState)
@ -78,8 +132,7 @@ namespace Ryujinx.Core.OsHle.Svc
//TODO: Validate that app has perms to access the service, and that the service //TODO: Validate that app has perms to access the service, and that the service
//actually exists, return error codes otherwise. //actually exists, return error codes otherwise.
KSession Session = new KSession(ServiceFactory.MakeService(Name));
HSession Session = new HSession(Process.Services.GetService(Name));
ulong Handle = (ulong)Process.HandleTable.OpenHandle(Session); ulong Handle = (ulong)Process.HandleTable.OpenHandle(Session);
@ -116,38 +169,37 @@ namespace Ryujinx.Core.OsHle.Svc
HThread CurrThread = Process.GetThread(ThreadState.Tpidr); HThread CurrThread = Process.GetThread(ThreadState.Tpidr);
Process.Scheduler.Suspend(CurrThread.ProcessorId);
byte[] CmdData = AMemoryHelper.ReadBytes(Memory, CmdPtr, Size); byte[] CmdData = AMemoryHelper.ReadBytes(Memory, CmdPtr, Size);
HSession Session = Process.HandleTable.GetData<HSession>(Handle); KSession Session = Process.HandleTable.GetData<KSession>(Handle);
IpcMessage Cmd = new IpcMessage(CmdData, CmdPtr, Session is HDomain);
if (Session != null) if (Session != null)
{ {
Process.Scheduler.Suspend(CurrThread.ProcessorId);
IpcMessage Cmd = new IpcMessage(CmdData, CmdPtr);
IpcHandler.IpcCall( IpcHandler.IpcCall(
Ns, Ns,
Process, Process,
Memory, Memory,
Session, Session,
Cmd, Cmd,
ThreadState.ThreadId,
CmdPtr, CmdPtr,
Handle); Handle);
byte[] Response = AMemoryHelper.ReadBytes(Memory, CmdPtr, Size); Thread.Yield();
Process.Scheduler.Resume(CurrThread);
ThreadState.X0 = 0; ThreadState.X0 = 0;
} }
else else
{ {
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidIpcReq); Logging.Warn($"Tried to SendSyncRequest on invalid session handle 0x{Handle:x8}!");
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
} }
Thread.Yield();
Process.Scheduler.Resume(CurrThread);
} }
private void SvcBreak(AThreadState ThreadState) private void SvcBreak(AThreadState ThreadState)

View file

@ -14,10 +14,10 @@ namespace Ryujinx.Core
internal NsGpu Gpu { get; private set; } internal NsGpu Gpu { get; private set; }
internal Horizon Os { get; private set; }
internal VirtualFileSystem VFs { get; private set; } internal VirtualFileSystem VFs { get; private set; }
public Horizon Os { get; private set; }
public SystemSettings Settings { get; private set; } public SystemSettings Settings { get; private set; }
public PerformanceStatistics Statistics { get; private set; } public PerformanceStatistics Statistics { get; private set; }
@ -42,10 +42,10 @@ namespace Ryujinx.Core
Gpu = new NsGpu(Renderer); Gpu = new NsGpu(Renderer);
Os = new Horizon(this);
VFs = new VirtualFileSystem(); VFs = new VirtualFileSystem();
Os = new Horizon(this);
Settings = new SystemSettings(); Settings = new SystemSettings();
Statistics = new PerformanceStatistics(); Statistics = new PerformanceStatistics();

View file

@ -1,6 +1,7 @@
using ChocolArm64.Memory; using ChocolArm64.Memory;
using Ryujinx.Graphics.Gal; using Ryujinx.Graphics.Gal;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
namespace Ryujinx.Graphics.Gpu namespace Ryujinx.Graphics.Gpu
{ {
@ -8,7 +9,7 @@ namespace Ryujinx.Graphics.Gpu
{ {
private NsGpu Gpu; private NsGpu Gpu;
private int[] Registers; private uint[] Registers;
public NsGpuEngine[] SubChannels; public NsGpuEngine[] SubChannels;
@ -18,7 +19,7 @@ namespace Ryujinx.Graphics.Gpu
{ {
this.Gpu = Gpu; this.Gpu = Gpu;
Registers = new int[0x1000]; Registers = new uint[0x1000];
SubChannels = new NsGpuEngine[8]; SubChannels = new NsGpuEngine[8];
@ -33,7 +34,7 @@ namespace Ryujinx.Graphics.Gpu
{ {
if (Entry.Arguments.Count == 1) if (Entry.Arguments.Count == 1)
{ {
SetRegister(Entry.Register, Entry.Arguments[0]); SetRegister(Entry.Register, (uint)Entry.Arguments[0]);
} }
switch (Entry.Register) switch (Entry.Register)
@ -45,6 +46,24 @@ namespace Ryujinx.Graphics.Gpu
} }
break; break;
case (NsGpuRegister)0x114:
uint BindId = GetRegister((NsGpuRegister)0x11c);
if (BindId == 0xd)
{
using (FileStream FS = new FileStream("D:\\macro.bin", FileMode.Create))
{
BinaryWriter Writer = new BinaryWriter(FS);
foreach (int arg in Entry.Arguments)
{
Writer.Write(arg);
}
}
}
//System.Console.WriteLine("macro bind " + Entry.Arguments[0].ToString("x8"));
break;
case NsGpuRegister._3dVertexArray0Fetch: case NsGpuRegister._3dVertexArray0Fetch:
SendVertexBuffers(Memory); SendVertexBuffers(Memory);
break; break;
@ -62,6 +81,22 @@ namespace Ryujinx.Graphics.Gpu
case NsGpuRegister._3dQueryGet: case NsGpuRegister._3dQueryGet:
HasQuery = true; HasQuery = true;
break; break;
case NsGpuRegister._3dSetShader:
uint ShaderPrg = (uint)Entry.Arguments[0];
uint ShaderId = (uint)Entry.Arguments[1];
uint CodeAddr = (uint)Entry.Arguments[2];
uint ShaderType = (uint)Entry.Arguments[3];
uint CodeEnd = (uint)Entry.Arguments[4];
SendShader(
Memory,
ShaderPrg,
ShaderId,
CodeAddr,
ShaderType,
CodeEnd);
break;
} }
} }
@ -71,10 +106,10 @@ namespace Ryujinx.Graphics.Gpu
(long)GetRegister(NsGpuRegister._3dQueryAddressHigh) << 32 | (long)GetRegister(NsGpuRegister._3dQueryAddressHigh) << 32 |
(long)GetRegister(NsGpuRegister._3dQueryAddressLow) << 0; (long)GetRegister(NsGpuRegister._3dQueryAddressLow) << 0;
int Seq = GetRegister(NsGpuRegister._3dQuerySequence); uint Seq = GetRegister(NsGpuRegister._3dQuerySequence);
int Get = GetRegister(NsGpuRegister._3dQueryGet); uint Get = GetRegister(NsGpuRegister._3dQueryGet);
int Mode = Get & 3; uint Mode = Get & 3;
if (Mode == 0) if (Mode == 0)
{ {
@ -85,7 +120,7 @@ namespace Ryujinx.Graphics.Gpu
{ {
Gpu.Renderer.QueueAction(delegate() Gpu.Renderer.QueueAction(delegate()
{ {
Memory.WriteInt32(Position, Seq); Memory.WriteUInt32(Position, Seq);
}); });
} }
} }
@ -119,13 +154,13 @@ namespace Ryujinx.Graphics.Gpu
{ {
byte[] Buffer = AMemoryHelper.ReadBytes(Memory, Position, Size); byte[] Buffer = AMemoryHelper.ReadBytes(Memory, Position, Size);
int Stride = GetRegister(NsGpuRegister._3dVertexArray0Fetch) & 0xfff; int Stride = (int)GetRegister(NsGpuRegister._3dVertexArray0Fetch) & 0xfff;
List<GalVertexAttrib> Attribs = new List<GalVertexAttrib>(); List<GalVertexAttrib> Attribs = new List<GalVertexAttrib>();
for (int Attr = 0; Attr < 16; Attr++) for (int Attr = 0; Attr < 16; Attr++)
{ {
int Packed = GetRegister(NsGpuRegister._3dVertexAttrib0Format + Attr * 4); int Packed = (int)GetRegister(NsGpuRegister._3dVertexAttrib0Format + Attr * 4);
GalVertexAttrib Attrib = new GalVertexAttrib(Attr, GalVertexAttrib Attrib = new GalVertexAttrib(Attr,
(Packed >> 0) & 0x1f, (Packed >> 0) & 0x1f,
@ -154,10 +189,10 @@ namespace Ryujinx.Graphics.Gpu
long TicPos = (long)GetRegister(NsGpuRegister._3dTicAddressHigh) << 32 | long TicPos = (long)GetRegister(NsGpuRegister._3dTicAddressHigh) << 32 |
(long)GetRegister(NsGpuRegister._3dTicAddressLow) << 0; (long)GetRegister(NsGpuRegister._3dTicAddressLow) << 0;
int CbData = GetRegister(NsGpuRegister._3dCbData0); uint CbData = GetRegister(NsGpuRegister._3dCbData0);
int TicIndex = (CbData >> 0) & 0xfffff; uint TicIndex = (CbData >> 0) & 0xfffff;
int TscIndex = (CbData >> 20) & 0xfff; //I guess? uint TscIndex = (CbData >> 20) & 0xfff; //I guess?
TicPos = Gpu.MemoryMgr.GetCpuAddr(TicPos + TicIndex * 0x20); TicPos = Gpu.MemoryMgr.GetCpuAddr(TicPos + TicIndex * 0x20);
@ -198,6 +233,19 @@ namespace Ryujinx.Graphics.Gpu
} }
} }
private void SendShader(
AMemory Memory,
uint ShaderPrg,
uint ShaderId,
uint CodeAddr,
uint ShaderType,
uint CodeEnd)
{
long CodePos = Gpu.MemoryMgr.GetCpuAddr(CodeAddr);
byte[] Data = AMemoryHelper.ReadBytes(Memory, CodePos, 0x300);
}
private static byte[] GetDecodedTexture( private static byte[] GetDecodedTexture(
AMemory Memory, AMemory Memory,
NsGpuTextureFormat Format, NsGpuTextureFormat Format,
@ -263,12 +311,12 @@ namespace Ryujinx.Graphics.Gpu
return Data; return Data;
} }
public int GetRegister(NsGpuRegister Register) public uint GetRegister(NsGpuRegister Register)
{ {
return Registers[((int)Register >> 2) & 0xfff]; return Registers[((int)Register >> 2) & 0xfff];
} }
public void SetRegister(NsGpuRegister Register, int Value) public void SetRegister(NsGpuRegister Register, uint Value)
{ {
Registers[((int)Register >> 2) & 0xfff] = Value; Registers[((int)Register >> 2) & 0xfff] = Value;
} }

View file

@ -89,5 +89,6 @@ namespace Ryujinx.Graphics.Gpu
_3dCbData13 = 0x23c4, _3dCbData13 = 0x23c4,
_3dCbData14 = 0x23c8, _3dCbData14 = 0x23c8,
_3dCbData15 = 0x23cc, _3dCbData15 = 0x23cc,
_3dSetShader = 0x3890
} }
} }

View file

@ -181,6 +181,8 @@ namespace Ryujinx
SwapBuffers(); SwapBuffers();
Ns.Statistics.EndSystemFrame(); Ns.Statistics.EndSystemFrame();
Ns.Os.SignalVsync();
} }
protected override void OnResize(EventArgs e) protected override void OnResize(EventArgs e)