mirror of
https://git.naxdy.org/Mirror/Ryujinx.git
synced 2025-01-09 12:19:12 +00:00
Start LibraryAppletAccessor Impl
This commit is contained in:
parent
0873c86c58
commit
242eb17fee
10 changed files with 466 additions and 12 deletions
121
src/Ryujinx.Horizon/Am/Ipc/AppletFifo.cs
Normal file
121
src/Ryujinx.Horizon/Am/Ipc/AppletFifo.cs
Normal file
|
@ -0,0 +1,121 @@
|
|||
using Ryujinx.Horizon.Sdk.Am;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Horizon.Am.Ipc
|
||||
{
|
||||
internal class AppletFifo<T> : IAppletFifo<T>
|
||||
{
|
||||
private readonly ConcurrentQueue<T> _dataQueue;
|
||||
|
||||
public event EventHandler DataAvailable;
|
||||
|
||||
public bool IsSynchronized
|
||||
{
|
||||
get { return ((ICollection)_dataQueue).IsSynchronized; }
|
||||
}
|
||||
|
||||
public object SyncRoot
|
||||
{
|
||||
get { return ((ICollection)_dataQueue).SyncRoot; }
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get { return _dataQueue.Count; }
|
||||
}
|
||||
|
||||
public AppletFifo()
|
||||
{
|
||||
_dataQueue = new ConcurrentQueue<T>();
|
||||
}
|
||||
|
||||
public void Push(T item)
|
||||
{
|
||||
_dataQueue.Enqueue(item);
|
||||
|
||||
DataAvailable?.Invoke(this, null);
|
||||
}
|
||||
|
||||
public bool TryAdd(T item)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.Push(item);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public T Pop()
|
||||
{
|
||||
if (_dataQueue.TryDequeue(out T result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("FIFO empty.");
|
||||
}
|
||||
|
||||
public bool TryPop(out T result)
|
||||
{
|
||||
return _dataQueue.TryDequeue(out result);
|
||||
}
|
||||
|
||||
public bool TryTake(out T item)
|
||||
{
|
||||
return this.TryPop(out item);
|
||||
}
|
||||
|
||||
public T Peek()
|
||||
{
|
||||
if (_dataQueue.TryPeek(out T result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("FIFO empty.");
|
||||
}
|
||||
|
||||
public bool TryPeek(out T result)
|
||||
{
|
||||
return _dataQueue.TryPeek(out result);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_dataQueue.Clear();
|
||||
}
|
||||
|
||||
public T[] ToArray()
|
||||
{
|
||||
return _dataQueue.ToArray();
|
||||
}
|
||||
|
||||
public void CopyTo(T[] array, int arrayIndex)
|
||||
{
|
||||
_dataQueue.CopyTo(array, arrayIndex);
|
||||
}
|
||||
|
||||
public void CopyTo(Array array, int index)
|
||||
{
|
||||
this.CopyTo((T[])array, index);
|
||||
}
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return _dataQueue.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return _dataQueue.GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
204
src/Ryujinx.Horizon/Am/Ipc/Controllers/LibraryAppletAccessor.cs
Normal file
204
src/Ryujinx.Horizon/Am/Ipc/Controllers/LibraryAppletAccessor.cs
Normal file
|
@ -0,0 +1,204 @@
|
|||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Horizon.Common;
|
||||
using Ryujinx.Horizon.Sdk.Am;
|
||||
using Ryujinx.Horizon.Sdk.Am.Controllers;
|
||||
using Ryujinx.Horizon.Sdk.Am.Storage;
|
||||
using Ryujinx.Horizon.Sdk.OsTypes;
|
||||
using Ryujinx.Horizon.Sdk.Sf;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Horizon.Am.Ipc.Controllers
|
||||
{
|
||||
partial class LibraryAppletAccessor : ILibraryAppletAccessor
|
||||
{
|
||||
private readonly AppletSession _normalSession;
|
||||
private readonly AppletSession _interactiveSession;
|
||||
|
||||
private SystemEventType _stateChangedEvent;
|
||||
private SystemEventType _normalOutDataEvent;
|
||||
private SystemEventType _interactiveOutDataEvent;
|
||||
|
||||
public LibraryAppletAccessor(AppletId appletId)
|
||||
{
|
||||
Os.CreateSystemEvent(out _stateChangedEvent, EventClearMode.ManualClear, interProcess: true).AbortOnFailure();
|
||||
Os.CreateSystemEvent(out _normalOutDataEvent, EventClearMode.ManualClear, interProcess: true).AbortOnFailure();
|
||||
Os.CreateSystemEvent(out _interactiveOutDataEvent, EventClearMode.ManualClear, interProcess: true).AbortOnFailure();
|
||||
|
||||
_normalSession = new AppletSession();
|
||||
_interactiveSession = new AppletSession();
|
||||
|
||||
_normalSession.DataAvailable += OnNormalOutData;
|
||||
_interactiveSession.DataAvailable += OnInteractiveOutData;
|
||||
}
|
||||
|
||||
private void OnAppletStateChanged(object sender, EventArgs e)
|
||||
{
|
||||
Os.SignalSystemEvent(ref _stateChangedEvent);
|
||||
}
|
||||
|
||||
private void OnNormalOutData(object sender, EventArgs e)
|
||||
{
|
||||
Os.SignalSystemEvent(ref _normalOutDataEvent);
|
||||
}
|
||||
|
||||
private void OnInteractiveOutData(object sender, EventArgs e)
|
||||
{
|
||||
Os.SignalSystemEvent(ref _interactiveOutDataEvent);
|
||||
}
|
||||
|
||||
[CmifCommand(0)]
|
||||
public Result GetAppletStateChangedEvent([CopyHandle] out int arg0)
|
||||
{
|
||||
arg0 = Os.GetReadableHandleOfSystemEvent(ref _stateChangedEvent);
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
[CmifCommand(1)]
|
||||
public Result IsCompleted(out bool arg0)
|
||||
{
|
||||
arg0 = false;
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceAm);
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
[CmifCommand(10)]
|
||||
public Result Start()
|
||||
{
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceAm);
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
[CmifCommand(20)]
|
||||
public Result RequestExit()
|
||||
{
|
||||
Os.SignalSystemEvent(ref _stateChangedEvent);
|
||||
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceAm);
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
[CmifCommand(25)]
|
||||
public Result Terminate()
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
[CmifCommand(30)]
|
||||
public Result GetResult()
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
[CmifCommand(50)]
|
||||
public Result SetOutOfFocusApplicationSuspendingEnabled(bool arg0)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
[CmifCommand(60)]
|
||||
public Result PresetLibraryAppletGpuTimeSliceZero()
|
||||
{
|
||||
// NOTE: This call reset two internal fields to 0 and one internal field to "true".
|
||||
// It seems to be used only with software keyboard inline.
|
||||
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceAm);
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
[CmifCommand(100)]
|
||||
public Result PushInData(IStorage data)
|
||||
{
|
||||
var storage = new Storage.Storage(data);
|
||||
_normalSession.Push(storage.Data);
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
[CmifCommand(101)]
|
||||
public Result PopOutData(out IStorage data)
|
||||
{
|
||||
if (_interactiveSession.TryPop(out byte[] bytes))
|
||||
{
|
||||
data = new Storage.Storage(bytes);
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
data = new Storage.Storage([]);
|
||||
return AmResult.NotAvailable;
|
||||
}
|
||||
|
||||
[CmifCommand(102)]
|
||||
public Result PushExtraStorage(IStorage data)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
[CmifCommand(103)]
|
||||
public Result PushInteractiveInData(IStorage data)
|
||||
{
|
||||
var storage = new Storage.Storage(data);
|
||||
|
||||
_interactiveSession.Push(storage.Data);
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
[CmifCommand(104)]
|
||||
public Result PopInteractiveOutData(out IStorage arg0)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
[CmifCommand(105)]
|
||||
public Result GetPopOutDataEvent(out int handle)
|
||||
{
|
||||
handle = Os.GetReadableHandleOfSystemEvent(ref _normalOutDataEvent);
|
||||
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceAm);
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
[CmifCommand(106)]
|
||||
public Result GetPopInteractiveOutDataEvent(out int handle)
|
||||
{
|
||||
handle = Os.GetReadableHandleOfSystemEvent(ref _interactiveOutDataEvent);
|
||||
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceAm);
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
[CmifCommand(110)]
|
||||
public Result NeedsToExitProcess(out bool arg0)
|
||||
{
|
||||
arg0 = false;
|
||||
|
||||
return AmResult.Stubbed;
|
||||
}
|
||||
|
||||
[CmifCommand(120)]
|
||||
public Result GetLibraryAppletInfo(out LibraryAppletInfo arg0)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
[CmifCommand(150)]
|
||||
public Result RequestForAppletToGetForeground()
|
||||
{
|
||||
return AmResult.Stubbed;
|
||||
}
|
||||
|
||||
[CmifCommand(160)]
|
||||
public Result GetIndirectLayerConsumerHandle(out ulong arg0, ulong arg1, ulong pid)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Horizon.Common;
|
||||
using Ryujinx.Horizon.Sdk.Am.Controllers;
|
||||
using Ryujinx.Horizon.Sdk.Am.Storage;
|
||||
using Ryujinx.Horizon.Sdk.Sf;
|
||||
|
||||
namespace Ryujinx.Horizon.Am.Ipc.Controllers
|
||||
|
@ -8,7 +9,7 @@ namespace Ryujinx.Horizon.Am.Ipc.Controllers
|
|||
partial class LibraryAppletCreator : ILibraryAppletCreator
|
||||
{
|
||||
[CmifCommand(0)]
|
||||
public Result CreateLibraryApplet()
|
||||
public Result CreateLibraryApplet(out ILibraryAppletAccessor arg0, uint arg1, uint arg2)
|
||||
{
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceAm);
|
||||
|
||||
|
@ -16,7 +17,7 @@ namespace Ryujinx.Horizon.Am.Ipc.Controllers
|
|||
}
|
||||
|
||||
[CmifCommand(1)]
|
||||
public Result TerminateAllLibraryApplets()
|
||||
public Result TerminateAllLibraryApplets(out bool arg0)
|
||||
{
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceAm);
|
||||
|
||||
|
@ -32,7 +33,7 @@ namespace Ryujinx.Horizon.Am.Ipc.Controllers
|
|||
}
|
||||
|
||||
[CmifCommand(10)]
|
||||
public Result CreateStorage()
|
||||
public Result CreateStorage(out IStorage arg0, long arg1)
|
||||
{
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceAm);
|
||||
|
||||
|
@ -40,7 +41,7 @@ namespace Ryujinx.Horizon.Am.Ipc.Controllers
|
|||
}
|
||||
|
||||
[CmifCommand(11)]
|
||||
public Result CreateTransferMemoryStorage()
|
||||
public Result CreateTransferMemoryStorage(out IStorage arg0, int arg1, long arg2, bool arg3)
|
||||
{
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceAm);
|
||||
|
||||
|
@ -48,7 +49,7 @@ namespace Ryujinx.Horizon.Am.Ipc.Controllers
|
|||
}
|
||||
|
||||
[CmifCommand(12)]
|
||||
public Result CreateHandleStorage()
|
||||
public Result CreateHandleStorage(out IStorage arg0, int arg1, long arg2)
|
||||
{
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceAm);
|
||||
|
||||
|
|
|
@ -15,6 +15,12 @@ namespace Ryujinx.Horizon.Am.Ipc.Storage
|
|||
Data = data;
|
||||
}
|
||||
|
||||
// TODO: Something for this...
|
||||
public Storage(IStorage handle)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
[CmifCommand(0)]
|
||||
public Result Open(out IStorageAccessor storageAccessor)
|
||||
{
|
||||
|
|
|
@ -5,7 +5,8 @@ namespace Ryujinx.Horizon.Sdk.Am
|
|||
[StructLayout(LayoutKind.Sequential, Size = 0x4)]
|
||||
public struct AppletProcessLaunchReason
|
||||
{
|
||||
// TODO: Better way to rep single bit flag
|
||||
public bool flag;
|
||||
public byte Flag;
|
||||
public ushort Unknown1;
|
||||
public byte Unknown2;
|
||||
}
|
||||
}
|
||||
|
|
77
src/Ryujinx.Horizon/Sdk/Am/AppletSession.cs
Normal file
77
src/Ryujinx.Horizon/Sdk/Am/AppletSession.cs
Normal file
|
@ -0,0 +1,77 @@
|
|||
using Ryujinx.Horizon.Am.Ipc;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Horizon.Sdk.Am
|
||||
{
|
||||
internal class AppletSession
|
||||
{
|
||||
private readonly IAppletFifo<byte[]> _inputData;
|
||||
private readonly IAppletFifo<byte[]> _outputData;
|
||||
|
||||
public event EventHandler DataAvailable;
|
||||
|
||||
public int Length
|
||||
{
|
||||
get { return _inputData.Count; }
|
||||
}
|
||||
|
||||
public AppletSession()
|
||||
{
|
||||
_inputData = new AppletFifo<byte[]>();
|
||||
_outputData = new AppletFifo<byte[]>();
|
||||
}
|
||||
|
||||
public AppletSession(IAppletFifo<byte[]> inputData, IAppletFifo<byte[]> outputData)
|
||||
{
|
||||
_inputData = inputData;
|
||||
_outputData = outputData;
|
||||
|
||||
_inputData.DataAvailable += OnDataAvailable;
|
||||
}
|
||||
|
||||
private void OnDataAvailable(object sender, EventArgs e)
|
||||
{
|
||||
DataAvailable?.Invoke(this, null);
|
||||
}
|
||||
|
||||
public void Push(byte[] item)
|
||||
{
|
||||
if (!this.TryPush(item))
|
||||
{
|
||||
// TODO(jduncanator): Throw a proper exception
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryPush(byte[] item)
|
||||
{
|
||||
return _outputData.TryAdd(item);
|
||||
}
|
||||
|
||||
public byte[] Pop()
|
||||
{
|
||||
if (this.TryPop(out byte[] item))
|
||||
{
|
||||
return item;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("Input data empty.");
|
||||
}
|
||||
|
||||
public bool TryPop(out byte[] item)
|
||||
{
|
||||
return _inputData.TryTake(out item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This returns an AppletSession that can be used at the
|
||||
/// other end of the pipe. Pushing data into this new session
|
||||
/// will put it in the first session's input buffer, and vice
|
||||
/// versa.
|
||||
/// </summary>
|
||||
public AppletSession GetConsumer()
|
||||
{
|
||||
return new AppletSession(this._outputData, this._inputData);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
using Ryujinx.Horizon.Common;
|
||||
using Ryujinx.Horizon.Sdk.Am.Storage;
|
||||
|
||||
namespace Ryujinx.Horizon.Sdk.Am.Controllers
|
||||
{
|
||||
interface ILibraryAppletAccessor : IAppletAccessor
|
||||
{
|
||||
Result SetOutOfFocusApplicationSuspendingEnabled(bool arg0);
|
||||
Result PresetLibraryAppletGpuTimeSliceZero();
|
||||
Result PushInData(IStorage arg0);
|
||||
Result PopOutData(out IStorage data);
|
||||
Result PushExtraStorage(IStorage data);
|
||||
Result PushInteractiveInData(IStorage data);
|
||||
Result PopInteractiveOutData(out IStorage arg0);
|
||||
Result GetPopOutDataEvent(out int handle);
|
||||
Result GetPopInteractiveOutDataEvent(out int handle);
|
||||
Result NeedsToExitProcess(out bool arg0);
|
||||
Result GetLibraryAppletInfo(out LibraryAppletInfo arg0);
|
||||
Result RequestForAppletToGetForeground();
|
||||
Result GetIndirectLayerConsumerHandle(out ulong arg0, ulong arg1, ulong pid);
|
||||
}
|
||||
}
|
|
@ -1,15 +1,16 @@
|
|||
using Ryujinx.Horizon.Common;
|
||||
using Ryujinx.Horizon.Sdk.Am.Storage;
|
||||
using Ryujinx.Horizon.Sdk.Sf;
|
||||
|
||||
namespace Ryujinx.Horizon.Sdk.Am.Controllers
|
||||
{
|
||||
interface ILibraryAppletCreator : IServiceObject
|
||||
{
|
||||
Result CreateLibraryApplet();
|
||||
Result CreateLibraryApplet(out ILibraryAppletAccessor arg0, uint arg1, uint arg2);
|
||||
Result TerminateAllLibraryApplets();
|
||||
Result AreAnyLibraryAppletsLeft();
|
||||
Result CreateStorage();
|
||||
Result CreateTransferMemoryStorage();
|
||||
Result CreateHandleStorage();
|
||||
Result AreAnyLibraryAppletsLeft(out bool arg0);
|
||||
Result CreateStorage(out IStorage arg0, long arg1);
|
||||
Result CreateTransferMemoryStorage(out IStorage arg0, int arg1, long arg2, bool arg3);
|
||||
Result CreateHandleStorage(out IStorage arg0, int arg1, long arg2);
|
||||
}
|
||||
}
|
||||
|
|
10
src/Ryujinx.Horizon/Sdk/Am/IAppletFifo.cs
Normal file
10
src/Ryujinx.Horizon/Sdk/Am/IAppletFifo.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace Ryujinx.Horizon.Sdk.Am
|
||||
{
|
||||
interface IAppletFifo<T> : IProducerConsumerCollection<T>
|
||||
{
|
||||
event EventHandler DataAvailable;
|
||||
}
|
||||
}
|
11
src/Ryujinx.Horizon/Sdk/Am/LibraryAppletInfo.cs
Normal file
11
src/Ryujinx.Horizon/Sdk/Am/LibraryAppletInfo.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Horizon.Sdk.Am
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Size = 0x8)]
|
||||
struct LibraryAppletInfo
|
||||
{
|
||||
public AppletId AppletId;
|
||||
public LibraryAppletMode LibraryAppletMode;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue