Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
ff43f32ce3
134 changed files with 1898 additions and 1087 deletions
|
@ -139,6 +139,7 @@ namespace ChocolArm64
|
|||
Set("0x001110001xxxxx000111xxxxxxxxxx", AInstEmit.And_V, typeof(AOpCodeSimdReg));
|
||||
Set("0x001110011xxxxx000111xxxxxxxxxx", AInstEmit.Bic_V, typeof(AOpCodeSimdReg));
|
||||
Set("0x10111100000xxx<<x101xxxxxxxxxx", AInstEmit.Bic_Vi, typeof(AOpCodeSimdImm));
|
||||
Set("0x101110111xxxxx000111xxxxxxxxxx", AInstEmit.Bif_V, typeof(AOpCodeSimdReg));
|
||||
Set("0x101110011xxxxx000111xxxxxxxxxx", AInstEmit.Bsl_V, typeof(AOpCodeSimdReg));
|
||||
Set("0>101110<<1xxxxx100011xxxxxxxxxx", AInstEmit.Cmeq_V, typeof(AOpCodeSimdReg));
|
||||
Set("0>001110<<100000100110xxxxxxxxxx", AInstEmit.Cmeq_V, typeof(AOpCodeSimd));
|
||||
|
@ -229,6 +230,7 @@ namespace ChocolArm64
|
|||
Set("xx111100x11xxxxxxxxx10xxxxxxxxxx", AInstEmit.Ldr, typeof(AOpCodeSimdMemReg));
|
||||
Set("xx011100xxxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.LdrLit, typeof(AOpCodeSimdMemLit));
|
||||
Set("0x001110<<1xxxxx100101xxxxxxxxxx", AInstEmit.Mla_V, typeof(AOpCodeSimdReg));
|
||||
Set("0x101111xxxxxxxx0000x0xxxxxxxxxx", AInstEmit.Mla_Ve, typeof(AOpCodeSimdRegElem));
|
||||
Set("0x101110<<1xxxxx100101xxxxxxxxxx", AInstEmit.Mls_V, typeof(AOpCodeSimdReg));
|
||||
Set("0x00111100000xxx0xx001xxxxxxxxxx", AInstEmit.Movi_V, typeof(AOpCodeSimdImm));
|
||||
Set("0x00111100000xxx10x001xxxxxxxxxx", AInstEmit.Movi_V, typeof(AOpCodeSimdImm));
|
||||
|
|
|
@ -82,6 +82,7 @@ namespace ChocolArm64.Decoder
|
|||
}
|
||||
}
|
||||
|
||||
this.Index = Index;
|
||||
this.SElems = SElems;
|
||||
this.Size = Scale;
|
||||
|
||||
|
|
|
@ -11,9 +11,8 @@ namespace ChocolArm64.Decoder
|
|||
switch (Size)
|
||||
{
|
||||
case 1:
|
||||
Index = (OpCode >> 21) & 1 |
|
||||
(OpCode >> 10) & 2 |
|
||||
(OpCode >> 18) & 4;
|
||||
Index = (OpCode >> 20) & 3 |
|
||||
(OpCode >> 9) & 4;
|
||||
|
||||
Rm &= 0xf;
|
||||
|
||||
|
|
|
@ -360,6 +360,15 @@ namespace ChocolArm64.Instruction
|
|||
});
|
||||
}
|
||||
|
||||
public static void Mla_Ve(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorTernaryOpByElemZx(Context, () =>
|
||||
{
|
||||
Context.Emit(OpCodes.Mul);
|
||||
Context.Emit(OpCodes.Add);
|
||||
});
|
||||
}
|
||||
|
||||
public static void Mls_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorTernaryOpZx(Context, () =>
|
||||
|
|
|
@ -381,13 +381,16 @@ namespace ChocolArm64.Instruction
|
|||
}
|
||||
|
||||
EmitVectorExtract(Context, Op.Rn, Index, Op.Size, Signed);
|
||||
EmitVectorExtract(Context, Op.Rm, Index, Op.Size, Signed);
|
||||
EmitVectorExtract(Context, Op.Rm, Elem, Op.Size, Signed);
|
||||
|
||||
Emit();
|
||||
|
||||
EmitVectorInsert(Context, Op.Rd, Index, Op.Size);
|
||||
EmitVectorInsertTmp(Context, Index, Op.Size);
|
||||
}
|
||||
|
||||
Context.EmitLdvectmp();
|
||||
Context.EmitStvec(Op.Rd);
|
||||
|
||||
if (Op.RegisterSize == ARegisterSize.SIMD64)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
|
|
|
@ -32,6 +32,36 @@ namespace ChocolArm64.Instruction
|
|||
});
|
||||
}
|
||||
|
||||
public static void Bif_V(AILEmitterCtx Context)
|
||||
{
|
||||
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
|
||||
|
||||
int Bytes = Context.CurrOp.GetBitsCount() >> 3;
|
||||
|
||||
for (int Index = 0; Index < (Bytes >> Op.Size); Index++)
|
||||
{
|
||||
EmitVectorExtractZx(Context, Op.Rd, Index, Op.Size);
|
||||
EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size);
|
||||
|
||||
Context.Emit(OpCodes.Xor);
|
||||
|
||||
EmitVectorExtractZx(Context, Op.Rm, Index, Op.Size);
|
||||
|
||||
Context.Emit(OpCodes.And);
|
||||
|
||||
EmitVectorExtractZx(Context, Op.Rd, Index, Op.Size);
|
||||
|
||||
Context.Emit(OpCodes.Xor);
|
||||
|
||||
EmitVectorInsert(Context, Op.Rd, Index, Op.Size);
|
||||
}
|
||||
|
||||
if (Op.RegisterSize == ARegisterSize.SIMD64)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Bsl_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorTernaryOpZx(Context, () =>
|
||||
|
|
|
@ -41,15 +41,15 @@ namespace ChocolArm64.Instruction
|
|||
private const uint Crc32RevPoly = 0xedb88320;
|
||||
private const uint Crc32cRevPoly = 0x82f63b78;
|
||||
|
||||
public static uint Crc32b(uint Crc, byte Val) => Crc32 (Crc, Crc32RevPoly, Val);
|
||||
public static uint Crc32h(uint Crc, byte Val) => Crc32h(Crc, Crc32RevPoly, Val);
|
||||
public static uint Crc32w(uint Crc, byte Val) => Crc32w(Crc, Crc32RevPoly, Val);
|
||||
public static uint Crc32x(uint Crc, byte Val) => Crc32x(Crc, Crc32RevPoly, Val);
|
||||
public static uint Crc32b(uint Crc, byte Val) => Crc32 (Crc, Crc32RevPoly, Val);
|
||||
public static uint Crc32h(uint Crc, ushort Val) => Crc32h(Crc, Crc32RevPoly, Val);
|
||||
public static uint Crc32w(uint Crc, uint Val) => Crc32w(Crc, Crc32RevPoly, Val);
|
||||
public static uint Crc32x(uint Crc, ulong Val) => Crc32x(Crc, Crc32RevPoly, Val);
|
||||
|
||||
public static uint Crc32cb(uint Crc, byte Val) => Crc32 (Crc, Crc32cRevPoly, Val);
|
||||
public static uint Crc32ch(uint Crc, byte Val) => Crc32h(Crc, Crc32cRevPoly, Val);
|
||||
public static uint Crc32cw(uint Crc, byte Val) => Crc32w(Crc, Crc32cRevPoly, Val);
|
||||
public static uint Crc32cx(uint Crc, byte Val) => Crc32x(Crc, Crc32cRevPoly, Val);
|
||||
public static uint Crc32cb(uint Crc, byte Val) => Crc32 (Crc, Crc32cRevPoly, Val);
|
||||
public static uint Crc32ch(uint Crc, ushort Val) => Crc32h(Crc, Crc32cRevPoly, Val);
|
||||
public static uint Crc32cw(uint Crc, uint Val) => Crc32w(Crc, Crc32cRevPoly, Val);
|
||||
public static uint Crc32cx(uint Crc, ulong Val) => Crc32x(Crc, Crc32cRevPoly, Val);
|
||||
|
||||
private static uint Crc32h(uint Crc, uint Poly, ushort Val)
|
||||
{
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace ChocolArm64.Memory
|
||||
|
@ -20,11 +22,11 @@ namespace ChocolArm64.Memory
|
|||
}
|
||||
}
|
||||
|
||||
public static byte[] ReadBytes(AMemory Memory, long Position, int Size)
|
||||
public static byte[] ReadBytes(AMemory Memory, long Position, long Size)
|
||||
{
|
||||
byte[] Data = new byte[Size];
|
||||
|
||||
for (int Offs = 0; Offs < Size; Offs++)
|
||||
for (long Offs = 0; Offs < Size; Offs++)
|
||||
{
|
||||
Data[Offs] = (byte)Memory.ReadByte(Position + Offs);
|
||||
}
|
||||
|
@ -40,11 +42,39 @@ namespace ChocolArm64.Memory
|
|||
}
|
||||
}
|
||||
|
||||
public static string ReadAsciiString(AMemory Memory, long Position, int MaxSize = -1)
|
||||
public unsafe static T Read<T>(AMemory Memory, long Position) where T : struct
|
||||
{
|
||||
long Size = Marshal.SizeOf<T>();
|
||||
|
||||
if ((ulong)(Position + Size) > AMemoryMgr.AddrSize)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(Position));
|
||||
}
|
||||
|
||||
IntPtr Ptr = new IntPtr((byte*)Memory.Ram + Position);
|
||||
|
||||
return Marshal.PtrToStructure<T>(Ptr);
|
||||
}
|
||||
|
||||
public unsafe static void Write<T>(AMemory Memory, long Position, T Value) where T : struct
|
||||
{
|
||||
long Size = Marshal.SizeOf<T>();
|
||||
|
||||
if ((ulong)(Position + Size) > AMemoryMgr.AddrSize)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(Position));
|
||||
}
|
||||
|
||||
IntPtr Ptr = new IntPtr((byte*)Memory.Ram + Position);
|
||||
|
||||
Marshal.StructureToPtr<T>(Value, Ptr, false);
|
||||
}
|
||||
|
||||
public static string ReadAsciiString(AMemory Memory, long Position, long MaxSize = -1)
|
||||
{
|
||||
using (MemoryStream MS = new MemoryStream())
|
||||
{
|
||||
for (int Offs = 0; Offs < MaxSize || MaxSize == -1; Offs++)
|
||||
for (long Offs = 0; Offs < MaxSize || MaxSize == -1; Offs++)
|
||||
{
|
||||
byte Value = (byte)Memory.ReadByte(Position + Offs);
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ using System;
|
|||
namespace ChocolArm64
|
||||
{
|
||||
using System.Reflection.Emit;
|
||||
|
||||
|
||||
static class ILGeneratorEx
|
||||
{
|
||||
public static void EmitLdc_I4(this ILGenerator Generator,int Value)
|
||||
|
|
13
Ryujinx.Audio/AudioFormat.cs
Normal file
13
Ryujinx.Audio/AudioFormat.cs
Normal file
|
@ -0,0 +1,13 @@
|
|||
namespace Ryujinx.Audio
|
||||
{
|
||||
public enum AudioFormat
|
||||
{
|
||||
Invalid = 0,
|
||||
PcmInt8 = 1,
|
||||
PcmInt16 = 2,
|
||||
PcmImt24 = 3,
|
||||
PcmImt32 = 4,
|
||||
PcmFloat = 5,
|
||||
Adpcm = 6
|
||||
}
|
||||
}
|
24
Ryujinx.Audio/IAalOutput.cs
Normal file
24
Ryujinx.Audio/IAalOutput.cs
Normal file
|
@ -0,0 +1,24 @@
|
|||
namespace Ryujinx.Audio
|
||||
{
|
||||
public interface IAalOutput
|
||||
{
|
||||
int OpenTrack(
|
||||
int SampleRate,
|
||||
int Channels,
|
||||
ReleaseCallback Callback,
|
||||
out AudioFormat Format);
|
||||
|
||||
void CloseTrack(int Track);
|
||||
|
||||
bool ContainsBuffer(int Track, long Tag);
|
||||
|
||||
long[] GetReleasedBuffers(int Track, int MaxCount);
|
||||
|
||||
void AppendBuffer(int Track, long Tag, byte[] Buffer);
|
||||
|
||||
void Start(int Track);
|
||||
void Stop(int Track);
|
||||
|
||||
PlaybackState GetState(int Track);
|
||||
}
|
||||
}
|
365
Ryujinx.Audio/OpenAL/OpenALAudioOut.cs
Normal file
365
Ryujinx.Audio/OpenAL/OpenALAudioOut.cs
Normal file
|
@ -0,0 +1,365 @@
|
|||
using OpenTK.Audio;
|
||||
using OpenTK.Audio.OpenAL;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace Ryujinx.Audio.OpenAL
|
||||
{
|
||||
public class OpenALAudioOut : IAalOutput
|
||||
{
|
||||
private const int MaxTracks = 256;
|
||||
|
||||
private const int MaxReleased = 32;
|
||||
|
||||
private AudioContext Context;
|
||||
|
||||
private class Track : IDisposable
|
||||
{
|
||||
public int SourceId { get; private set; }
|
||||
|
||||
public int SampleRate { get; private set; }
|
||||
|
||||
public ALFormat Format { get; private set; }
|
||||
|
||||
private ReleaseCallback Callback;
|
||||
|
||||
public PlaybackState State { get; set; }
|
||||
|
||||
private bool ShouldCallReleaseCallback;
|
||||
|
||||
private ConcurrentDictionary<long, int> Buffers;
|
||||
|
||||
private Queue<long> QueuedTagsQueue;
|
||||
|
||||
private Queue<long> ReleasedTagsQueue;
|
||||
|
||||
private int LastReleasedCount;
|
||||
|
||||
private bool Disposed;
|
||||
|
||||
public Track(int SampleRate, ALFormat Format, ReleaseCallback Callback)
|
||||
{
|
||||
this.SampleRate = SampleRate;
|
||||
this.Format = Format;
|
||||
this.Callback = Callback;
|
||||
|
||||
State = PlaybackState.Stopped;
|
||||
|
||||
SourceId = AL.GenSource();
|
||||
|
||||
Buffers = new ConcurrentDictionary<long, int>();
|
||||
|
||||
QueuedTagsQueue = new Queue<long>();
|
||||
|
||||
ReleasedTagsQueue = new Queue<long>();
|
||||
}
|
||||
|
||||
public bool ContainsBuffer(long Tag)
|
||||
{
|
||||
SyncQueuedTags();
|
||||
|
||||
foreach (long QueuedTag in QueuedTagsQueue)
|
||||
{
|
||||
if (QueuedTag == Tag)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public long[] GetReleasedBuffers(int MaxCount)
|
||||
{
|
||||
ClearReleased();
|
||||
|
||||
List<long> Tags = new List<long>();
|
||||
|
||||
HashSet<long> Unique = new HashSet<long>();
|
||||
|
||||
while (MaxCount-- > 0 && ReleasedTagsQueue.TryDequeue(out long Tag))
|
||||
{
|
||||
if (Unique.Add(Tag))
|
||||
{
|
||||
Tags.Add(Tag);
|
||||
}
|
||||
}
|
||||
|
||||
return Tags.ToArray();
|
||||
}
|
||||
|
||||
public int AppendBuffer(long Tag)
|
||||
{
|
||||
if (Disposed)
|
||||
{
|
||||
throw new ObjectDisposedException(nameof(Track));
|
||||
}
|
||||
|
||||
int Id = AL.GenBuffer();
|
||||
|
||||
Buffers.AddOrUpdate(Tag, Id, (Key, OldId) =>
|
||||
{
|
||||
AL.DeleteBuffer(OldId);
|
||||
|
||||
return Id;
|
||||
});
|
||||
|
||||
QueuedTagsQueue.Enqueue(Tag);
|
||||
|
||||
return Id;
|
||||
}
|
||||
|
||||
public void ClearReleased()
|
||||
{
|
||||
SyncQueuedTags();
|
||||
|
||||
AL.GetSource(SourceId, ALGetSourcei.BuffersProcessed, out int ReleasedCount);
|
||||
|
||||
CheckReleaseChanges(ReleasedCount);
|
||||
|
||||
if (ReleasedCount > 0)
|
||||
{
|
||||
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()
|
||||
{
|
||||
AL.GetSource(SourceId, ALGetSourcei.BuffersQueued, out int QueuedCount);
|
||||
AL.GetSource(SourceId, ALGetSourcei.BuffersProcessed, out int ReleasedCount);
|
||||
|
||||
QueuedCount -= ReleasedCount;
|
||||
|
||||
while (QueuedTagsQueue.Count > QueuedCount)
|
||||
{
|
||||
ReleasedTagsQueue.Enqueue(QueuedTagsQueue.Dequeue());
|
||||
}
|
||||
|
||||
while (ReleasedTagsQueue.Count > MaxReleased)
|
||||
{
|
||||
ReleasedTagsQueue.Dequeue();
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool Disposing)
|
||||
{
|
||||
if (Disposing && !Disposed)
|
||||
{
|
||||
Disposed = true;
|
||||
|
||||
AL.DeleteSource(SourceId);
|
||||
|
||||
foreach (int Id in Buffers.Values)
|
||||
{
|
||||
AL.DeleteBuffer(Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ConcurrentDictionary<int, Track> Tracks;
|
||||
|
||||
private Thread AudioPollerThread;
|
||||
|
||||
private bool KeepPolling;
|
||||
|
||||
public OpenALAudioOut()
|
||||
{
|
||||
Context = new AudioContext();
|
||||
|
||||
Tracks = new ConcurrentDictionary<int, Track>();
|
||||
|
||||
KeepPolling = true;
|
||||
|
||||
AudioPollerThread = new Thread(AudioPollerWork);
|
||||
|
||||
AudioPollerThread.Start();
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
Track Td = new Track(SampleRate, GetALFormat(Channels, Format), Callback);
|
||||
|
||||
for (int Id = 0; Id < MaxTracks; Id++)
|
||||
{
|
||||
if (Tracks.TryAdd(Id, Td))
|
||||
{
|
||||
return Id;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private ALFormat GetALFormat(int Channels, AudioFormat Format)
|
||||
{
|
||||
if (Channels < 1 || Channels > 2)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(Channels));
|
||||
}
|
||||
|
||||
if (Channels == 1)
|
||||
{
|
||||
switch (Format)
|
||||
{
|
||||
case AudioFormat.PcmInt8: return ALFormat.Mono8;
|
||||
case AudioFormat.PcmInt16: return ALFormat.Mono16;
|
||||
}
|
||||
}
|
||||
else /* if (Channels == 2) */
|
||||
{
|
||||
switch (Format)
|
||||
{
|
||||
case AudioFormat.PcmInt8: return ALFormat.Stereo8;
|
||||
case AudioFormat.PcmInt16: return ALFormat.Stereo16;
|
||||
}
|
||||
}
|
||||
|
||||
throw new ArgumentException(nameof(Format));
|
||||
}
|
||||
|
||||
public void CloseTrack(int Track)
|
||||
{
|
||||
if (Tracks.TryRemove(Track, out Track Td))
|
||||
{
|
||||
Td.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public bool ContainsBuffer(int Track, long Tag)
|
||||
{
|
||||
if (Tracks.TryGetValue(Track, out Track Td))
|
||||
{
|
||||
return Td.ContainsBuffer(Tag);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public long[] GetReleasedBuffers(int Track, int MaxCount)
|
||||
{
|
||||
if (Tracks.TryGetValue(Track, out Track Td))
|
||||
{
|
||||
return Td.GetReleasedBuffers(MaxCount);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void AppendBuffer(int Track, long Tag, byte[] Buffer)
|
||||
{
|
||||
if (Tracks.TryGetValue(Track, out Track Td))
|
||||
{
|
||||
int BufferId = Td.AppendBuffer(Tag);
|
||||
|
||||
AL.BufferData(BufferId, Td.Format, Buffer, Buffer.Length, Td.SampleRate);
|
||||
|
||||
AL.SourceQueueBuffer(Td.SourceId, BufferId);
|
||||
|
||||
StartPlaybackIfNeeded(Td);
|
||||
}
|
||||
}
|
||||
|
||||
public void Start(int Track)
|
||||
{
|
||||
if (Tracks.TryGetValue(Track, out Track Td))
|
||||
{
|
||||
Td.State = PlaybackState.Playing;
|
||||
|
||||
StartPlaybackIfNeeded(Td);
|
||||
}
|
||||
}
|
||||
|
||||
private void StartPlaybackIfNeeded(Track Td)
|
||||
{
|
||||
AL.GetSource(Td.SourceId, ALGetSourcei.SourceState, out int StateInt);
|
||||
|
||||
ALSourceState State = (ALSourceState)StateInt;
|
||||
|
||||
if (State != ALSourceState.Playing && Td.State == PlaybackState.Playing)
|
||||
{
|
||||
Td.ClearReleased();
|
||||
|
||||
AL.SourcePlay(Td.SourceId);
|
||||
}
|
||||
}
|
||||
|
||||
public void Stop(int Track)
|
||||
{
|
||||
if (Tracks.TryGetValue(Track, out Track Td))
|
||||
{
|
||||
Td.State = PlaybackState.Stopped;
|
||||
|
||||
AL.SourceStop(Td.SourceId);
|
||||
}
|
||||
}
|
||||
|
||||
public PlaybackState GetState(int Track)
|
||||
{
|
||||
if (Tracks.TryGetValue(Track, out Track Td))
|
||||
{
|
||||
return Td.State;
|
||||
}
|
||||
|
||||
return PlaybackState.Stopped;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
8
Ryujinx.Audio/PlaybackState.cs
Normal file
8
Ryujinx.Audio/PlaybackState.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
namespace Ryujinx.Audio
|
||||
{
|
||||
public enum PlaybackState
|
||||
{
|
||||
Playing = 0,
|
||||
Stopped = 1
|
||||
}
|
||||
}
|
4
Ryujinx.Audio/ReleaseCallback.cs
Normal file
4
Ryujinx.Audio/ReleaseCallback.cs
Normal file
|
@ -0,0 +1,4 @@
|
|||
namespace Ryujinx.Audio
|
||||
{
|
||||
public delegate void ReleaseCallback();
|
||||
}
|
11
Ryujinx.Audio/Ryujinx.Audio.csproj
Normal file
11
Ryujinx.Audio/Ryujinx.Audio.csproj
Normal file
|
@ -0,0 +1,11 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="OpenTK.NETCore" Version="1.1.2749.6433" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -9,6 +9,7 @@ namespace Ryujinx.Core
|
|||
{
|
||||
public static class Config
|
||||
{
|
||||
public static bool EnableMemoryChecks { get; private set; }
|
||||
public static bool LoggingEnableInfo { get; private set; }
|
||||
public static bool LoggingEnableTrace { get; private set; }
|
||||
public static bool LoggingEnableDebug { get; private set; }
|
||||
|
@ -26,6 +27,7 @@ namespace Ryujinx.Core
|
|||
var iniPath = Path.Combine(iniFolder, "Ryujinx.conf");
|
||||
IniParser Parser = new IniParser(iniPath);
|
||||
|
||||
EnableMemoryChecks = Convert.ToBoolean(Parser.Value("Enable_Memory_Checks"));
|
||||
LoggingEnableInfo = Convert.ToBoolean(Parser.Value("Logging_Enable_Info"));
|
||||
LoggingEnableTrace = Convert.ToBoolean(Parser.Value("Logging_Enable_Trace"));
|
||||
LoggingEnableDebug = Convert.ToBoolean(Parser.Value("Logging_Enable_Debug"));
|
||||
|
|
62
Ryujinx.Core/OsHle/AppletStateMgr.cs
Normal file
62
Ryujinx.Core/OsHle/AppletStateMgr.cs
Normal file
|
@ -0,0 +1,62 @@
|
|||
using Ryujinx.Core.OsHle.Handles;
|
||||
using Ryujinx.Core.OsHle.Services.Am;
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,7 +13,7 @@ namespace Ryujinx.Core.OsHle
|
|||
|
||||
private bool OwnsCondVarValue;
|
||||
|
||||
private List<HThread> WaitingThreads;
|
||||
private List<KThread> WaitingThreads;
|
||||
|
||||
public CondVar(Process Process, long CondVarAddress, long Timeout)
|
||||
{
|
||||
|
@ -21,10 +21,10 @@ namespace Ryujinx.Core.OsHle
|
|||
this.CondVarAddress = CondVarAddress;
|
||||
this.Timeout = Timeout;
|
||||
|
||||
WaitingThreads = new List<HThread>();
|
||||
WaitingThreads = new List<KThread>();
|
||||
}
|
||||
|
||||
public bool WaitForSignal(HThread Thread)
|
||||
public bool WaitForSignal(KThread Thread)
|
||||
{
|
||||
int Count = Process.Memory.ReadInt32(CondVarAddress);
|
||||
|
||||
|
@ -66,7 +66,7 @@ namespace Ryujinx.Core.OsHle
|
|||
return true;
|
||||
}
|
||||
|
||||
public void SetSignal(HThread Thread, int Count)
|
||||
public void SetSignal(KThread Thread, int Count)
|
||||
{
|
||||
lock (WaitingThreads)
|
||||
{
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
namespace Ryujinx.Core.OsHle
|
||||
{
|
||||
class FileDesc
|
||||
{
|
||||
public string Name { get; private set; }
|
||||
|
||||
public FileDesc(string Name)
|
||||
{
|
||||
this.Name = Name;
|
||||
}
|
||||
}
|
||||
}
|
69
Ryujinx.Core/OsHle/GlobalStateTable.cs
Normal file
69
Ryujinx.Core/OsHle/GlobalStateTable.cs
Normal file
|
@ -0,0 +1,69 @@
|
|||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Core.OsHle
|
||||
{
|
||||
class GlobalStateTable
|
||||
{
|
||||
private ConcurrentDictionary<Process, IdDictionary> DictByProcess;
|
||||
|
||||
public GlobalStateTable()
|
||||
{
|
||||
DictByProcess = new ConcurrentDictionary<Process, IdDictionary>();
|
||||
}
|
||||
|
||||
public bool Add(Process Process, int Id, object Data)
|
||||
{
|
||||
IdDictionary Dict = DictByProcess.GetOrAdd(Process, (Key) => new IdDictionary());
|
||||
|
||||
return Dict.Add(Id, Data);
|
||||
}
|
||||
|
||||
public int Add(Process Process, object Data)
|
||||
{
|
||||
IdDictionary Dict = DictByProcess.GetOrAdd(Process, (Key) => new IdDictionary());
|
||||
|
||||
return Dict.Add(Data);
|
||||
}
|
||||
|
||||
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 object Delete(Process Process, int Id)
|
||||
{
|
||||
if (DictByProcess.TryGetValue(Process, out IdDictionary Dict))
|
||||
{
|
||||
return Dict.Delete(Id);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public ICollection<object> DeleteProcess(Process Process)
|
||||
{
|
||||
if (DictByProcess.TryRemove(Process, out IdDictionary Dict))
|
||||
{
|
||||
return Dict.Clear();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
namespace Ryujinx.Core.OsHle.Handles
|
||||
{
|
||||
class HEvent
|
||||
{
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
4
Ryujinx.Core/OsHle/Handles/KEvent.cs
Normal file
4
Ryujinx.Core/OsHle/Handles/KEvent.cs
Normal file
|
@ -0,0 +1,4 @@
|
|||
namespace Ryujinx.Core.OsHle.Handles
|
||||
{
|
||||
class KEvent : KSynchronizationObject { }
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.Handles
|
||||
{
|
||||
class KProcessHandleTable : IDisposable
|
||||
class KProcessHandleTable
|
||||
{
|
||||
private IdDictionary Handles;
|
||||
|
||||
|
@ -21,43 +21,14 @@ namespace Ryujinx.Core.OsHle.Handles
|
|||
return Handles.GetData<T>(Handle);
|
||||
}
|
||||
|
||||
public bool ReplaceData(int Id, object Data)
|
||||
public object CloseHandle(int Handle)
|
||||
{
|
||||
return Handles.ReplaceData(Id, Data);
|
||||
}
|
||||
|
||||
public bool CloseHandle(int Handle)
|
||||
{
|
||||
object Data = Handles.GetData(Handle);
|
||||
|
||||
if (Data is HTransferMem TMem)
|
||||
{
|
||||
TMem.Memory.Manager.Reprotect(
|
||||
TMem.Position,
|
||||
TMem.Size,
|
||||
TMem.Perm);
|
||||
}
|
||||
|
||||
return Handles.Delete(Handle);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
public ICollection<object> Clear()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool Disposing)
|
||||
{
|
||||
if (Disposing)
|
||||
{
|
||||
foreach (object Obj in Handles)
|
||||
{
|
||||
if (Obj is IDisposable DisposableObj)
|
||||
{
|
||||
DisposableObj.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
return Handles.Clear();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,15 +5,15 @@ using System.Threading;
|
|||
|
||||
namespace Ryujinx.Core.OsHle.Handles
|
||||
{
|
||||
public class KProcessScheduler : IDisposable
|
||||
class KProcessScheduler : IDisposable
|
||||
{
|
||||
private class SchedulerThread : IDisposable
|
||||
{
|
||||
public HThread Thread { get; private set; }
|
||||
public KThread Thread { get; private set; }
|
||||
|
||||
public AutoResetEvent WaitEvent { get; private set; }
|
||||
|
||||
public SchedulerThread(HThread Thread)
|
||||
public SchedulerThread(KThread Thread)
|
||||
{
|
||||
this.Thread = Thread;
|
||||
|
||||
|
@ -95,7 +95,7 @@ namespace Ryujinx.Core.OsHle.Handles
|
|||
}
|
||||
}
|
||||
|
||||
private ConcurrentDictionary<HThread, SchedulerThread> AllThreads;
|
||||
private ConcurrentDictionary<KThread, SchedulerThread> AllThreads;
|
||||
|
||||
private ThreadQueue[] WaitingToRun;
|
||||
|
||||
|
@ -105,7 +105,7 @@ namespace Ryujinx.Core.OsHle.Handles
|
|||
|
||||
public KProcessScheduler()
|
||||
{
|
||||
AllThreads = new ConcurrentDictionary<HThread, SchedulerThread>();
|
||||
AllThreads = new ConcurrentDictionary<KThread, SchedulerThread>();
|
||||
|
||||
WaitingToRun = new ThreadQueue[4];
|
||||
|
||||
|
@ -119,7 +119,7 @@ namespace Ryujinx.Core.OsHle.Handles
|
|||
SchedLock = new object();
|
||||
}
|
||||
|
||||
public void StartThread(HThread Thread)
|
||||
public void StartThread(KThread Thread)
|
||||
{
|
||||
lock (SchedLock)
|
||||
{
|
||||
|
@ -164,7 +164,7 @@ namespace Ryujinx.Core.OsHle.Handles
|
|||
}
|
||||
}
|
||||
|
||||
public void Resume(HThread CurrThread)
|
||||
public void Resume(KThread CurrThread)
|
||||
{
|
||||
SchedulerThread SchedThread;
|
||||
|
||||
|
@ -183,7 +183,7 @@ namespace Ryujinx.Core.OsHle.Handles
|
|||
TryResumingExecution(SchedThread);
|
||||
}
|
||||
|
||||
public bool WaitForSignal(HThread Thread, int Timeout = -1)
|
||||
public bool WaitForSignal(KThread Thread, int Timeout = -1)
|
||||
{
|
||||
SchedulerThread SchedThread;
|
||||
|
||||
|
@ -230,7 +230,7 @@ namespace Ryujinx.Core.OsHle.Handles
|
|||
|
||||
private void TryResumingExecution(SchedulerThread SchedThread)
|
||||
{
|
||||
HThread Thread = SchedThread.Thread;
|
||||
KThread Thread = SchedThread.Thread;
|
||||
|
||||
lock (SchedLock)
|
||||
{
|
||||
|
@ -249,7 +249,7 @@ namespace Ryujinx.Core.OsHle.Handles
|
|||
Logging.Debug($"{GetDbgThreadInfo(Thread)} resuming execution...");
|
||||
}
|
||||
|
||||
public void Yield(HThread Thread)
|
||||
public void Yield(KThread Thread)
|
||||
{
|
||||
SchedulerThread SchedThread;
|
||||
|
||||
|
@ -295,11 +295,11 @@ namespace Ryujinx.Core.OsHle.Handles
|
|||
}
|
||||
}
|
||||
|
||||
public void Signal(params HThread[] Threads)
|
||||
public void Signal(params KThread[] Threads)
|
||||
{
|
||||
lock (SchedLock)
|
||||
{
|
||||
foreach (HThread Thread in Threads)
|
||||
foreach (KThread Thread in Threads)
|
||||
{
|
||||
if (AllThreads.TryGetValue(Thread, out SchedulerThread SchedThread))
|
||||
{
|
||||
|
@ -314,7 +314,7 @@ namespace Ryujinx.Core.OsHle.Handles
|
|||
}
|
||||
}
|
||||
|
||||
private string GetDbgThreadInfo(HThread Thread)
|
||||
private string GetDbgThreadInfo(KThread Thread)
|
||||
{
|
||||
return $"Thread {Thread.ThreadId} (core {Thread.ProcessorId}) prio {Thread.Priority}";
|
||||
}
|
||||
|
|
28
Ryujinx.Core/OsHle/Handles/KSession.cs
Normal file
28
Ryujinx.Core/OsHle/Handles/KSession.cs
Normal file
|
@ -0,0 +1,28 @@
|
|||
using Ryujinx.Core.OsHle.Services;
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
28
Ryujinx.Core/OsHle/Handles/KSynchronizationObject.cs
Normal file
28
Ryujinx.Core/OsHle/Handles/KSynchronizationObject.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@ using ChocolArm64;
|
|||
|
||||
namespace Ryujinx.Core.OsHle.Handles
|
||||
{
|
||||
public class HThread
|
||||
class KThread : KSynchronizationObject
|
||||
{
|
||||
public AThread Thread { get; private set; }
|
||||
|
||||
|
@ -11,7 +11,7 @@ namespace Ryujinx.Core.OsHle.Handles
|
|||
|
||||
public int ThreadId => Thread.ThreadId;
|
||||
|
||||
public HThread(AThread Thread, int ProcessorId, int Priority)
|
||||
public KThread(AThread Thread, int ProcessorId, int Priority)
|
||||
{
|
||||
this.Thread = Thread;
|
||||
this.ProcessorId = ProcessorId;
|
|
@ -51,7 +51,7 @@ namespace Ryujinx.Core.OsHle
|
|||
long Value0 = Memory.ReadInt64(Position + 0x08);
|
||||
long Value1 = Memory.ReadInt64(Position + 0x10);
|
||||
|
||||
FileName = AMemoryHelper.ReadAsciiString(Memory, Value0, (int)(Value1 - Value0));
|
||||
FileName = AMemoryHelper.ReadAsciiString(Memory, Value0, Value1 - Value0);
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -16,8 +16,10 @@ namespace Ryujinx.Core.OsHle
|
|||
|
||||
private ConcurrentDictionary<int, Process> Processes;
|
||||
|
||||
internal HSharedMem HidSharedMem;
|
||||
internal HSharedMem FontSharedMem;
|
||||
internal HSharedMem HidSharedMem { get; private set; }
|
||||
internal HSharedMem FontSharedMem { get; private set; }
|
||||
|
||||
internal KEvent VsyncEvent { get; private set; }
|
||||
|
||||
private Switch Ns;
|
||||
|
||||
|
@ -32,6 +34,8 @@ namespace Ryujinx.Core.OsHle
|
|||
|
||||
HidSharedMem = new HSharedMem();
|
||||
FontSharedMem = new HSharedMem();
|
||||
|
||||
VsyncEvent = new KEvent();
|
||||
}
|
||||
|
||||
public void LoadCart(string ExeFsDir, string RomFsFile = null)
|
||||
|
@ -91,6 +95,8 @@ namespace Ryujinx.Core.OsHle
|
|||
MainProcess.Run(IsNro);
|
||||
}
|
||||
|
||||
public void SignalVsync() => VsyncEvent.Handle.Set();
|
||||
|
||||
private Process MakeProcess()
|
||||
{
|
||||
Process Process;
|
||||
|
@ -109,9 +115,16 @@ namespace Ryujinx.Core.OsHle
|
|||
Processes.TryAdd(ProcessId, Process);
|
||||
}
|
||||
|
||||
InitializeProcess(Process);
|
||||
|
||||
return Process;
|
||||
}
|
||||
|
||||
private void InitializeProcess(Process Process)
|
||||
{
|
||||
Process.AppletState.SetFocus(true);
|
||||
}
|
||||
|
||||
internal void ExitProcess(int ProcessId)
|
||||
{
|
||||
if (Processes.TryGetValue(ProcessId, out Process Process) && Process.NeedsHbAbi)
|
||||
|
@ -171,6 +184,8 @@ namespace Ryujinx.Core.OsHle
|
|||
Process.StopAllThreadsAsync();
|
||||
Process.Dispose();
|
||||
}
|
||||
|
||||
VsyncEvent.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Core.OsHle
|
||||
{
|
||||
class IdDictionary : IEnumerable<object>
|
||||
class IdDictionary
|
||||
{
|
||||
private ConcurrentDictionary<int, object> Objs;
|
||||
|
||||
|
@ -16,6 +15,11 @@ namespace Ryujinx.Core.OsHle
|
|||
Objs = new ConcurrentDictionary<int, object>();
|
||||
}
|
||||
|
||||
public bool Add(int Id, object Data)
|
||||
{
|
||||
return Objs.TryAdd(Id, Data);
|
||||
}
|
||||
|
||||
public int Add(object Data)
|
||||
{
|
||||
if (Objs.TryAdd(FreeIdHint, Data))
|
||||
|
@ -39,18 +43,6 @@ namespace Ryujinx.Core.OsHle
|
|||
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)
|
||||
{
|
||||
if (Objs.TryGetValue(Id, out object Data))
|
||||
|
@ -71,31 +63,25 @@ namespace Ryujinx.Core.OsHle
|
|||
return default(T);
|
||||
}
|
||||
|
||||
public bool Delete(int Id)
|
||||
public object Delete(int Id)
|
||||
{
|
||||
if (Objs.TryRemove(Id, out object Obj))
|
||||
{
|
||||
if (Obj is IDisposable DisposableObj)
|
||||
{
|
||||
DisposableObj.Dispose();
|
||||
}
|
||||
|
||||
FreeIdHint = Id;
|
||||
|
||||
return true;
|
||||
return Obj;
|
||||
}
|
||||
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
|
||||
IEnumerator<object> IEnumerable<object>.GetEnumerator()
|
||||
public ICollection<object> Clear()
|
||||
{
|
||||
return Objs.Values.GetEnumerator();
|
||||
}
|
||||
ICollection<object> Values = Objs.Values;
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return Objs.Values.GetEnumerator();
|
||||
Objs.Clear();
|
||||
|
||||
return Values;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
namespace Ryujinx.Core.OsHle.Ipc
|
||||
{
|
||||
enum IpcDomCmd
|
||||
{
|
||||
SendMsg = 1,
|
||||
DeleteObj = 2
|
||||
}
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
using ChocolArm64.Memory;
|
||||
using Ryujinx.Core.OsHle.Handles;
|
||||
using Ryujinx.Core.OsHle.IpcServices;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
|
@ -8,20 +7,15 @@ namespace Ryujinx.Core.OsHle.Ipc
|
|||
{
|
||||
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(
|
||||
Switch Ns,
|
||||
Process Process,
|
||||
AMemory Memory,
|
||||
HSession Session,
|
||||
KSession Session,
|
||||
IpcMessage Request,
|
||||
int ThreadId,
|
||||
long CmdPtr,
|
||||
int HndId)
|
||||
long CmdPtr)
|
||||
{
|
||||
IpcMessage Response = new IpcMessage(Request.IsDomain && Request.Type == IpcMessageType.Request);
|
||||
IpcMessage Response = new IpcMessage();
|
||||
|
||||
using (MemoryStream Raw = new MemoryStream(Request.RawData))
|
||||
{
|
||||
|
@ -29,94 +23,25 @@ namespace Ryujinx.Core.OsHle.Ipc
|
|||
|
||||
if (Request.Type == IpcMessageType.Request)
|
||||
{
|
||||
string ServiceName = Session.Service.GetType().Name;
|
||||
Response.Type = IpcMessageType.Response;
|
||||
|
||||
ServiceProcessRequest ProcReq = null;
|
||||
|
||||
bool IgnoreNullPR = false;
|
||||
|
||||
string DbgServiceName = string.Empty;
|
||||
|
||||
if (Session is HDomain Dom)
|
||||
using (MemoryStream ResMS = new MemoryStream())
|
||||
{
|
||||
if (Request.DomCmd == IpcDomCmd.SendMsg)
|
||||
{
|
||||
long Magic = ReqReader.ReadInt64();
|
||||
int CmdId = (int)ReqReader.ReadInt64();
|
||||
BinaryWriter ResWriter = new BinaryWriter(ResMS);
|
||||
|
||||
object Obj = Dom.GetObject(Request.DomObjId);
|
||||
ServiceCtx Context = new ServiceCtx(
|
||||
Ns,
|
||||
Process,
|
||||
Memory,
|
||||
Session,
|
||||
Request,
|
||||
Response,
|
||||
ReqReader,
|
||||
ResWriter);
|
||||
|
||||
if (Obj is HDomain)
|
||||
{
|
||||
Session.Service.Commands.TryGetValue(CmdId, out ProcReq);
|
||||
Session.Service.CallMethod(Context);
|
||||
|
||||
DbgServiceName = $"{ProcReq?.Method.Name ?? CmdId.ToString()}";
|
||||
}
|
||||
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);
|
||||
Response.RawData = ResMS.ToArray();
|
||||
}
|
||||
}
|
||||
else if (Request.Type == IpcMessageType.Control)
|
||||
|
@ -128,11 +53,7 @@ namespace Ryujinx.Core.OsHle.Ipc
|
|||
{
|
||||
case 0:
|
||||
{
|
||||
HDomain Dom = new HDomain(Session);
|
||||
|
||||
Process.HandleTable.ReplaceData(HndId, Dom);
|
||||
|
||||
Request = FillResponse(Response, 0, Dom.Add(Dom));
|
||||
Request = FillResponse(Response, 0, Session.Service.ConvertToDomain());
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -198,7 +119,7 @@ namespace Ryujinx.Core.OsHle.Ipc
|
|||
{
|
||||
BinaryWriter Writer = new BinaryWriter(MS);
|
||||
|
||||
Writer.Write(SfcoMagic);
|
||||
Writer.Write(IpcMagic.Sfco);
|
||||
Writer.Write(Result);
|
||||
|
||||
if (Data != null)
|
||||
|
|
|
@ -125,8 +125,7 @@ namespace Ryujinx.Core.OsHle.Ipc
|
|||
|
||||
Reader.ReadInt64(); //Padding
|
||||
|
||||
IpcMessage += Environment.NewLine + $" Domain:" + Environment.NewLine +
|
||||
$" DomCmd: {Enum.GetName(typeof(IpcDomCmd), DomCmd)}" + Environment.NewLine +
|
||||
IpcMessage += Environment.NewLine + $" Domain:" + Environment.NewLine + Environment.NewLine +
|
||||
$" DomObjId: {DomObjId.ToString()}" + Environment.NewLine;
|
||||
}
|
||||
|
||||
|
|
8
Ryujinx.Core/OsHle/Ipc/IpcMagic.cs
Normal file
8
Ryujinx.Core/OsHle/Ipc/IpcMagic.cs
Normal 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;
|
||||
}
|
||||
}
|
|
@ -17,10 +17,6 @@ namespace Ryujinx.Core.OsHle.Ipc
|
|||
|
||||
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 IpcMessage()
|
||||
|
@ -34,27 +30,18 @@ namespace Ryujinx.Core.OsHle.Ipc
|
|||
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))
|
||||
{
|
||||
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 Word1 = Reader.ReadInt32();
|
||||
|
||||
|
@ -110,19 +97,6 @@ namespace Ryujinx.Core.OsHle.Ipc
|
|||
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);
|
||||
|
||||
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...
|
||||
int Pad1 = 0x10 - Pad0;
|
||||
|
||||
DataLength = (DataLength + Pad0 + Pad1 + (IsDomain ? 0x10 : 0)) / 4;
|
||||
|
||||
DataLength += ResponseObjIds.Count;
|
||||
DataLength = (DataLength + Pad0 + Pad1) / 4;
|
||||
|
||||
Word1 = DataLength & 0x3ff;
|
||||
|
||||
|
@ -182,23 +154,11 @@ namespace Ryujinx.Core.OsHle.Ipc
|
|||
|
||||
MS.Seek(Pad0, SeekOrigin.Current);
|
||||
|
||||
if (IsDomain)
|
||||
{
|
||||
Writer.Write(ResponseObjIds.Count);
|
||||
Writer.Write(0);
|
||||
Writer.Write(0L);
|
||||
}
|
||||
|
||||
if (RawData != null)
|
||||
{
|
||||
Writer.Write(RawData);
|
||||
}
|
||||
|
||||
foreach (int Id in ResponseObjIds)
|
||||
{
|
||||
Writer.Write(Id);
|
||||
}
|
||||
|
||||
Writer.Write(new byte[Pad1]);
|
||||
|
||||
return MS.ToArray();
|
||||
|
|
|
@ -6,7 +6,7 @@ namespace Ryujinx.Core.OsHle.Ipc
|
|||
{
|
||||
public long Position { get; private set; }
|
||||
public int Index { get; private set; }
|
||||
public short Size { get; private set; }
|
||||
public long Size { get; private set; }
|
||||
|
||||
public IpcPtrBuffDesc(BinaryReader Reader)
|
||||
{
|
||||
|
@ -20,7 +20,7 @@ namespace Ryujinx.Core.OsHle.Ipc
|
|||
Index = ((int)Word0 >> 0) & 0x03f;
|
||||
Index |= ((int)Word0 >> 3) & 0x1c0;
|
||||
|
||||
Size = (short)(Word0 >> 16);
|
||||
Size = (ushort)(Word0 >> 16);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,6 +6,5 @@ namespace Ryujinx.Core.OsHle
|
|||
public const int InvalidHandle = 114;
|
||||
public const int Timeout = 117;
|
||||
public const int InvalidInfo = 120;
|
||||
public const int InvalidIpcReq = 123;
|
||||
}
|
||||
}
|
|
@ -16,7 +16,7 @@ namespace Ryujinx.Core.OsHle
|
|||
|
||||
private object EnterWaitLock;
|
||||
|
||||
private ConcurrentQueue<HThread> WaitingThreads;
|
||||
private ConcurrentQueue<KThread> WaitingThreads;
|
||||
|
||||
public Mutex(Process Process, long MutexAddress, int OwnerThreadHandle)
|
||||
{
|
||||
|
@ -27,10 +27,10 @@ namespace Ryujinx.Core.OsHle
|
|||
|
||||
EnterWaitLock = new object();
|
||||
|
||||
WaitingThreads = new ConcurrentQueue<HThread>();
|
||||
WaitingThreads = new ConcurrentQueue<KThread>();
|
||||
}
|
||||
|
||||
public void WaitForLock(HThread RequestingThread, int RequestingThreadHandle)
|
||||
public void WaitForLock(KThread RequestingThread, int RequestingThreadHandle)
|
||||
{
|
||||
AcquireMutexValue();
|
||||
|
||||
|
@ -83,11 +83,11 @@ namespace Ryujinx.Core.OsHle
|
|||
|
||||
ReleaseMutexValue();
|
||||
|
||||
HThread[] UnlockedThreads = new HThread[WaitingThreads.Count];
|
||||
KThread[] UnlockedThreads = new KThread[WaitingThreads.Count];
|
||||
|
||||
int Index = 0;
|
||||
|
||||
while (WaitingThreads.TryDequeue(out HThread Thread))
|
||||
while (WaitingThreads.TryDequeue(out KThread Thread))
|
||||
{
|
||||
UnlockedThreads[Index++] = Thread;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ using Ryujinx.Core.Loaders;
|
|||
using Ryujinx.Core.Loaders.Executables;
|
||||
using Ryujinx.Core.OsHle.Exceptions;
|
||||
using Ryujinx.Core.OsHle.Handles;
|
||||
using Ryujinx.Core.OsHle.Services.Nv;
|
||||
using Ryujinx.Core.OsHle.Svc;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
|
@ -31,21 +32,21 @@ namespace Ryujinx.Core.OsHle
|
|||
|
||||
public AMemory Memory { get; private set; }
|
||||
|
||||
public ServiceMgr Services { get; private set; }
|
||||
|
||||
public KProcessScheduler Scheduler { get; private set; }
|
||||
|
||||
public KProcessHandleTable HandleTable { get; private set; }
|
||||
|
||||
public AppletStateMgr AppletState { get; private set; }
|
||||
|
||||
private SvcHandler SvcHandler;
|
||||
|
||||
private ConcurrentDictionary<int, AThread> TlsSlots;
|
||||
|
||||
private ConcurrentDictionary<long, HThread> ThreadsByTpidr;
|
||||
private ConcurrentDictionary<long, KThread> ThreadsByTpidr;
|
||||
|
||||
private List<Executable> Executables;
|
||||
|
||||
private HThread MainThread;
|
||||
private KThread MainThread;
|
||||
|
||||
private long ImageBase;
|
||||
|
||||
|
@ -60,17 +61,17 @@ namespace Ryujinx.Core.OsHle
|
|||
|
||||
Memory = new AMemory();
|
||||
|
||||
Services = new ServiceMgr();
|
||||
|
||||
HandleTable = new KProcessHandleTable();
|
||||
|
||||
Scheduler = new KProcessScheduler();
|
||||
Scheduler = new KProcessScheduler();
|
||||
|
||||
AppletState = new AppletStateMgr();
|
||||
|
||||
SvcHandler = new SvcHandler(Ns, this);
|
||||
|
||||
TlsSlots = new ConcurrentDictionary<int, AThread>();
|
||||
|
||||
ThreadsByTpidr = new ConcurrentDictionary<long, HThread>();
|
||||
ThreadsByTpidr = new ConcurrentDictionary<long, KThread>();
|
||||
|
||||
Executables = new List<Executable>();
|
||||
|
||||
|
@ -132,7 +133,7 @@ namespace Ryujinx.Core.OsHle
|
|||
return false;
|
||||
}
|
||||
|
||||
MainThread = HandleTable.GetData<HThread>(Handle);
|
||||
MainThread = HandleTable.GetData<KThread>(Handle);
|
||||
|
||||
if (NeedsHbAbi)
|
||||
{
|
||||
|
@ -186,7 +187,7 @@ namespace Ryujinx.Core.OsHle
|
|||
|
||||
AThread Thread = new AThread(GetTranslator(), Memory, EntryPoint);
|
||||
|
||||
HThread ThreadHnd = new HThread(Thread, ProcessorId, Priority);
|
||||
KThread ThreadHnd = new KThread(Thread, ProcessorId, Priority);
|
||||
|
||||
int Handle = HandleTable.OpenHandle(ThreadHnd);
|
||||
|
||||
|
@ -311,9 +312,9 @@ namespace Ryujinx.Core.OsHle
|
|||
return (int)((Position - MemoryRegions.TlsPagesAddress) / TlsSize);
|
||||
}
|
||||
|
||||
public HThread GetThread(long Tpidr)
|
||||
public KThread GetThread(long Tpidr)
|
||||
{
|
||||
if (!ThreadsByTpidr.TryGetValue(Tpidr, out HThread Thread))
|
||||
if (!ThreadsByTpidr.TryGetValue(Tpidr, out KThread Thread))
|
||||
{
|
||||
Logging.Error($"Thread with TPIDR 0x{Tpidr:x16} not found!");
|
||||
}
|
||||
|
@ -344,11 +345,27 @@ namespace Ryujinx.Core.OsHle
|
|||
}
|
||||
|
||||
Disposed = true;
|
||||
|
||||
Services.Dispose();
|
||||
HandleTable.Dispose();
|
||||
|
||||
foreach (object Obj in HandleTable.Clear())
|
||||
{
|
||||
if (Obj is KSession Session)
|
||||
{
|
||||
Session.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
ServiceNvDrv.Fds.DeleteProcess(this);
|
||||
|
||||
ServiceNvDrv.NvMaps .DeleteProcess(this);
|
||||
ServiceNvDrv.NvMapsById.DeleteProcess(this);
|
||||
ServiceNvDrv.NvMapsFb .DeleteProcess(this);
|
||||
|
||||
Scheduler.Dispose();
|
||||
|
||||
AppletState.Dispose();
|
||||
|
||||
SvcHandler.Dispose();
|
||||
|
||||
Memory.Dispose();
|
||||
|
||||
Logging.Info($"Process {ProcessId} exiting...");
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace Ryujinx.Core.OsHle
|
|||
public Switch Ns { get; private set; }
|
||||
public Process Process { 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 Response { get; private set; }
|
||||
public BinaryReader RequestData { get; private set; }
|
||||
|
@ -20,7 +20,7 @@ namespace Ryujinx.Core.OsHle
|
|||
Switch Ns,
|
||||
Process Process,
|
||||
AMemory Memory,
|
||||
HSession Session,
|
||||
KSession Session,
|
||||
IpcMessage Request,
|
||||
IpcMessage Response,
|
||||
BinaryReader RequestData,
|
||||
|
|
|
@ -1,110 +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)
|
||||
{
|
||||
if (!Services.TryGetValue(Name, 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(Name, 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,13 +1,13 @@
|
|||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.IpcServices.Acc
|
||||
namespace Ryujinx.Core.OsHle.Services.Acc
|
||||
{
|
||||
class IManagerForApplication : IIpcService
|
||||
class IManagerForApplication : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IManagerForApplication()
|
||||
{
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.IpcServices.Acc
|
||||
namespace Ryujinx.Core.OsHle.Services.Acc
|
||||
{
|
||||
class IProfile : IIpcService
|
||||
class IProfile : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IProfile()
|
||||
{
|
||||
|
|
|
@ -1,15 +1,13 @@
|
|||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.IpcServices.Acc
|
||||
namespace Ryujinx.Core.OsHle.Services.Acc
|
||||
{
|
||||
class ServiceAcc : IIpcService
|
||||
class ServiceAcc : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ServiceAcc()
|
||||
{
|
||||
|
|
7
Ryujinx.Core/OsHle/Services/Am/AmErr.cs
Normal file
7
Ryujinx.Core/OsHle/Services/Am/AmErr.cs
Normal file
|
@ -0,0 +1,7 @@
|
|||
namespace Ryujinx.Core.OsHle.Services.Am
|
||||
{
|
||||
static class AmErr
|
||||
{
|
||||
public const int NoMessages = 3;
|
||||
}
|
||||
}
|
8
Ryujinx.Core/OsHle/Services/Am/FocusState.cs
Normal file
8
Ryujinx.Core/OsHle/Services/Am/FocusState.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
namespace Ryujinx.Core.OsHle.Services.Am
|
||||
{
|
||||
enum FocusState
|
||||
{
|
||||
InFocus = 1,
|
||||
OutOfFocus = 2
|
||||
}
|
||||
}
|
|
@ -2,15 +2,13 @@ using Ryujinx.Core.OsHle.Ipc;
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.IpcServices.Am
|
||||
namespace Ryujinx.Core.OsHle.Services.Am
|
||||
{
|
||||
class IApplicationFunctions : IIpcService
|
||||
class IApplicationFunctions : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IApplicationFunctions()
|
||||
{
|
||||
|
|
|
@ -1,15 +1,13 @@
|
|||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.IpcServices.Am
|
||||
namespace Ryujinx.Core.OsHle.Services.Am
|
||||
{
|
||||
class IApplicationProxy : IIpcService
|
||||
class IApplicationProxy : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IApplicationProxy()
|
||||
{
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.IpcServices.Am
|
||||
namespace Ryujinx.Core.OsHle.Services.Am
|
||||
{
|
||||
class IAudioController : IIpcService
|
||||
class IAudioController : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IAudioController()
|
||||
{
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
using Ryujinx.Core.OsHle.Handles;
|
||||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.IpcServices.Am
|
||||
using static Ryujinx.Core.OsHle.ErrorCode;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.Services.Am
|
||||
{
|
||||
class ICommonStateGetter : IIpcService
|
||||
class ICommonStateGetter : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ICommonStateGetter()
|
||||
{
|
||||
|
@ -17,37 +20,31 @@ namespace Ryujinx.Core.OsHle.IpcServices.Am
|
|||
{ 1, ReceiveMessage },
|
||||
{ 5, GetOperationMode },
|
||||
{ 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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
public long ReceiveMessage(ServiceCtx Context)
|
||||
{
|
||||
//Program expects 0xF at 0x17ae70 on puyo sdk,
|
||||
//otherwise runs on a infinite loop until it reads said value.
|
||||
//What it means is still unknown.
|
||||
Context.ResponseData.Write(0xfL);
|
||||
if (!Context.Process.AppletState.TryDequeueMessage(out MessageInfo Message))
|
||||
{
|
||||
return MakeError(ErrorModule.Am, AmErr.NoMessages);
|
||||
}
|
||||
|
||||
return 0; //0x680;
|
||||
Context.ResponseData.Write((int)Message);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetOperationMode(ServiceCtx Context)
|
||||
|
@ -66,7 +63,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Am
|
|||
|
||||
public long GetCurrentFocusState(ServiceCtx Context)
|
||||
{
|
||||
Context.ResponseData.Write((byte)FocusState.InFocus);
|
||||
Context.ResponseData.Write((byte)Context.Process.AppletState.FocusState);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.IpcServices.Am
|
||||
namespace Ryujinx.Core.OsHle.Services.Am
|
||||
{
|
||||
class IDebugFunctions : IIpcService
|
||||
class IDebugFunctions : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IDebugFunctions()
|
||||
{
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.IpcServices.Am
|
||||
namespace Ryujinx.Core.OsHle.Services.Am
|
||||
{
|
||||
class IDisplayController : IIpcService
|
||||
class IDisplayController : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IDisplayController()
|
||||
{
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.IpcServices.Am
|
||||
namespace Ryujinx.Core.OsHle.Services.Am
|
||||
{
|
||||
class ILibraryAppletCreator : IIpcService
|
||||
class ILibraryAppletCreator : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ILibraryAppletCreator()
|
||||
{
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.IpcServices.Am
|
||||
namespace Ryujinx.Core.OsHle.Services.Am
|
||||
{
|
||||
class ISelfController : IIpcService
|
||||
class ISelfController : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ISelfController()
|
||||
{
|
||||
|
|
|
@ -1,15 +1,13 @@
|
|||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.IpcServices.Am
|
||||
namespace Ryujinx.Core.OsHle.Services.Am
|
||||
{
|
||||
class IStorage : IIpcService
|
||||
class IStorage : IpcService
|
||||
{
|
||||
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; }
|
||||
|
||||
|
|
|
@ -3,13 +3,13 @@ using Ryujinx.Core.OsHle.Ipc;
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.IpcServices.Am
|
||||
namespace Ryujinx.Core.OsHle.Services.Am
|
||||
{
|
||||
class IStorageAccessor : IIpcService
|
||||
class IStorageAccessor : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
private IStorage Storage;
|
||||
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.IpcServices.Am
|
||||
namespace Ryujinx.Core.OsHle.Services.Am
|
||||
{
|
||||
class IWindowController : IIpcService
|
||||
class IWindowController : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IWindowController()
|
||||
{
|
||||
|
|
9
Ryujinx.Core/OsHle/Services/Am/MessageInfo.cs
Normal file
9
Ryujinx.Core/OsHle/Services/Am/MessageInfo.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
namespace Ryujinx.Core.OsHle.Services.Am
|
||||
{
|
||||
enum MessageInfo
|
||||
{
|
||||
FocusStateChanged = 0xf,
|
||||
OperationModeChanged = 0x1e,
|
||||
PerformanceModeChanged = 0x1f
|
||||
}
|
||||
}
|
8
Ryujinx.Core/OsHle/Services/Am/OperationMode.cs
Normal file
8
Ryujinx.Core/OsHle/Services/Am/OperationMode.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
namespace Ryujinx.Core.OsHle.Services.Am
|
||||
{
|
||||
enum OperationMode
|
||||
{
|
||||
Handheld = 0,
|
||||
Docked = 1
|
||||
}
|
||||
}
|
|
@ -1,15 +1,13 @@
|
|||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.IpcServices.Am
|
||||
namespace Ryujinx.Core.OsHle.Services.Am
|
||||
{
|
||||
class ServiceAppletOE : IIpcService
|
||||
class ServiceAppletOE : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ServiceAppletOE()
|
||||
{
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.IpcServices.Apm
|
||||
namespace Ryujinx.Core.OsHle.Services.Apm
|
||||
{
|
||||
class ISession : IIpcService
|
||||
class ISession : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ISession()
|
||||
{
|
||||
|
|
|
@ -1,15 +1,13 @@
|
|||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.IpcServices.Apm
|
||||
namespace Ryujinx.Core.OsHle.Services.Apm
|
||||
{
|
||||
class ServiceApm : IIpcService
|
||||
class ServiceApm : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ServiceApm()
|
||||
{
|
||||
|
|
14
Ryujinx.Core/OsHle/Services/Aud/AudioOutData.cs
Normal file
14
Ryujinx.Core/OsHle/Services/Aud/AudioOutData.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.Services.Aud
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct AudioOutData
|
||||
{
|
||||
public long NextBufferPtr;
|
||||
public long SampleBufferPtr;
|
||||
public long SampleBufferCapacity;
|
||||
public long SampleBufferSize;
|
||||
public long SampleBufferInnerOffset;
|
||||
}
|
||||
}
|
|
@ -3,13 +3,13 @@ using Ryujinx.Core.OsHle.Ipc;
|
|||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.IpcServices.Aud
|
||||
namespace Ryujinx.Core.OsHle.Services.Aud
|
||||
{
|
||||
class IAudioDevice : IIpcService
|
||||
class IAudioDevice : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IAudioDevice()
|
||||
{
|
||||
|
@ -55,7 +55,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud
|
|||
long Position = Context.Request.SendBuff[0].Position;
|
||||
long Size = Context.Request.SendBuff[0].Size;
|
||||
|
||||
string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position, (int)Size);
|
||||
string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position, Size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,145 +1,86 @@
|
|||
using ChocolArm64.Memory;
|
||||
using Ryujinx.Audio;
|
||||
using Ryujinx.Core.OsHle.Handles;
|
||||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using OpenTK.Audio;
|
||||
using OpenTK.Audio.OpenAL;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.IpcServices.Aud
|
||||
namespace Ryujinx.Core.OsHle.Services.Aud
|
||||
{
|
||||
class IAudioOut : IIpcService, IDisposable
|
||||
class IAudioOut : IpcService, IDisposable
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IAudioOut()
|
||||
private IAalOutput AudioOut;
|
||||
|
||||
private KEvent ReleaseEvent;
|
||||
|
||||
private int Track;
|
||||
|
||||
public IAudioOut(IAalOutput AudioOut, KEvent ReleaseEvent, int Track)
|
||||
{
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, GetAudioOutState },
|
||||
{ 1, StartAudioOut },
|
||||
{ 2, StopAudioOut },
|
||||
{ 3, AppendAudioOutBuffer },
|
||||
{ 4, RegisterBufferEvent },
|
||||
{ 5, GetReleasedAudioOutBuffer },
|
||||
{ 6, ContainsAudioOutBuffer },
|
||||
{ 7, AppendAudioOutBuffer_ex },
|
||||
{ 8, GetReleasedAudioOutBuffer_ex }
|
||||
{ 0, GetAudioOutState },
|
||||
{ 1, StartAudioOut },
|
||||
{ 2, StopAudioOut },
|
||||
{ 3, AppendAudioOutBuffer },
|
||||
{ 4, RegisterBufferEvent },
|
||||
{ 5, GetReleasedAudioOutBuffer },
|
||||
{ 6, ContainsAudioOutBuffer },
|
||||
{ 7, AppendAudioOutBufferEx },
|
||||
{ 8, GetReleasedAudioOutBufferEx }
|
||||
};
|
||||
|
||||
this.AudioOut = AudioOut;
|
||||
this.ReleaseEvent = ReleaseEvent;
|
||||
this.Track = Track;
|
||||
}
|
||||
|
||||
enum AudioOutState
|
||||
{
|
||||
Started,
|
||||
Stopped
|
||||
};
|
||||
|
||||
//IAudioOut
|
||||
private AudioOutState State = AudioOutState.Stopped;
|
||||
private Queue<long> BufferIdQueue = new Queue<long>();
|
||||
|
||||
//OpenAL
|
||||
private bool OpenALInstalled = true;
|
||||
private AudioContext AudioCtx;
|
||||
private int Source;
|
||||
private int Buffer;
|
||||
|
||||
//Return State of IAudioOut
|
||||
public long GetAudioOutState(ServiceCtx Context)
|
||||
{
|
||||
Context.ResponseData.Write((int)State);
|
||||
Context.ResponseData.Write((int)AudioOut.GetState(Track));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long StartAudioOut(ServiceCtx Context)
|
||||
{
|
||||
if (State == AudioOutState.Stopped)
|
||||
{
|
||||
State = AudioOutState.Started;
|
||||
|
||||
try
|
||||
{
|
||||
AudioCtx = new AudioContext(); //Create the audio context
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Logging.Warn("OpenAL Error! PS: Install OpenAL Core SDK!");
|
||||
OpenALInstalled = false;
|
||||
}
|
||||
|
||||
if (OpenALInstalled) AL.Listener(ALListenerf.Gain, 8.0f); //Add more gain to it
|
||||
}
|
||||
AudioOut.Start(Track);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long StopAudioOut(ServiceCtx Context)
|
||||
{
|
||||
if (State == AudioOutState.Started)
|
||||
{
|
||||
if (OpenALInstalled)
|
||||
{
|
||||
if (AudioCtx == null) //Needed to call the instance of AudioContext()
|
||||
return 0;
|
||||
|
||||
AL.SourceStop(Source);
|
||||
AL.DeleteSource(Source);
|
||||
AL.DeleteBuffers(1, ref Buffer);
|
||||
}
|
||||
State = AudioOutState.Stopped;
|
||||
}
|
||||
AudioOut.Stop(Track);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long AppendAudioOutBuffer(ServiceCtx Context)
|
||||
{
|
||||
long BufferId = Context.RequestData.ReadInt64();
|
||||
long Tag = Context.RequestData.ReadInt64();
|
||||
|
||||
byte[] AudioOutBuffer = AMemoryHelper.ReadBytes(Context.Memory, Context.Request.SendBuff[0].Position, sizeof(long) * 5);
|
||||
AudioOutData Data = AMemoryHelper.Read<AudioOutData>(
|
||||
Context.Memory,
|
||||
Context.Request.SendBuff[0].Position);
|
||||
|
||||
byte[] Buffer = AMemoryHelper.ReadBytes(
|
||||
Context.Memory,
|
||||
Data.SampleBufferPtr,
|
||||
Data.SampleBufferSize);
|
||||
|
||||
using (MemoryStream MS = new MemoryStream(AudioOutBuffer))
|
||||
{
|
||||
BinaryReader Reader = new BinaryReader(MS);
|
||||
long PointerNextBuffer = Reader.ReadInt64();
|
||||
long PointerSampleBuffer = Reader.ReadInt64();
|
||||
long CapacitySampleBuffer = Reader.ReadInt64();
|
||||
long SizeDataInSampleBuffer = Reader.ReadInt64();
|
||||
long OffsetDataInSampleBuffer = Reader.ReadInt64();
|
||||
|
||||
if (SizeDataInSampleBuffer > 0)
|
||||
{
|
||||
BufferIdQueue.Enqueue(BufferId);
|
||||
|
||||
byte[] AudioSampleBuffer = AMemoryHelper.ReadBytes(Context.Memory, PointerSampleBuffer + OffsetDataInSampleBuffer, (int)SizeDataInSampleBuffer);
|
||||
|
||||
if (OpenALInstalled)
|
||||
{
|
||||
if (AudioCtx == null) //Needed to call the instance of AudioContext()
|
||||
return 0;
|
||||
|
||||
EnsureAudioFinalized();
|
||||
|
||||
Source = AL.GenSource();
|
||||
Buffer = AL.GenBuffer();
|
||||
|
||||
AL.BufferData(Buffer, ALFormat.Stereo16, AudioSampleBuffer, AudioSampleBuffer.Length, 48000);
|
||||
AL.SourceQueueBuffer(Source, Buffer);
|
||||
AL.SourcePlay(Source);
|
||||
}
|
||||
}
|
||||
}
|
||||
AudioOut.AppendBuffer(Track, Tag, Buffer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
|
@ -148,62 +89,65 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud
|
|||
|
||||
public long GetReleasedAudioOutBuffer(ServiceCtx Context)
|
||||
{
|
||||
int ReleasedBuffersCount = 0;
|
||||
long Position = Context.Request.ReceiveBuff[0].Position;
|
||||
long Size = Context.Request.ReceiveBuff[0].Size;
|
||||
|
||||
for(int i = 0; i < BufferIdQueue.Count; i++)
|
||||
uint Count = (uint)((ulong)Size >> 3);
|
||||
|
||||
long[] ReleasedBuffers = AudioOut.GetReleasedBuffers(Track, (int)Count);
|
||||
|
||||
for (uint Index = 0; Index < Count; Index++)
|
||||
{
|
||||
long BufferId = BufferIdQueue.Dequeue();
|
||||
long Tag = 0;
|
||||
|
||||
AMemoryHelper.WriteBytes(Context.Memory, Context.Request.ReceiveBuff[0].Position + (8 * i), BitConverter.GetBytes(BufferId));
|
||||
if (Index < ReleasedBuffers.Length)
|
||||
{
|
||||
Tag = ReleasedBuffers[Index];
|
||||
}
|
||||
|
||||
ReleasedBuffersCount++;
|
||||
Context.Memory.WriteInt64(Position + Index * 8, Tag);
|
||||
}
|
||||
|
||||
Context.ResponseData.Write(ReleasedBuffersCount);
|
||||
Context.ResponseData.Write(ReleasedBuffers.Length);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long ContainsAudioOutBuffer(ServiceCtx Context)
|
||||
{
|
||||
long Tag = Context.RequestData.ReadInt64();
|
||||
|
||||
Context.ResponseData.Write(AudioOut.ContainsBuffer(Track, Tag) ? 1 : 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long AppendAudioOutBuffer_ex(ServiceCtx Context)
|
||||
public long AppendAudioOutBufferEx(ServiceCtx Context)
|
||||
{
|
||||
Logging.Warn("Not implemented!");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetReleasedAudioOutBuffer_ex(ServiceCtx Context)
|
||||
public long GetReleasedAudioOutBufferEx(ServiceCtx Context)
|
||||
{
|
||||
Logging.Warn("Not implemented!");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private void EnsureAudioFinalized()
|
||||
{
|
||||
if (Source != 0 ||
|
||||
Buffer != 0)
|
||||
{
|
||||
AL.SourceStop(Source);
|
||||
AL.SourceUnqueueBuffer(Buffer);
|
||||
AL.DeleteSource(Source);
|
||||
AL.DeleteBuffers(1, ref Buffer);
|
||||
|
||||
Source = 0;
|
||||
Buffer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
protected virtual void Dispose(bool Disposing)
|
||||
{
|
||||
if (disposing)
|
||||
if (Disposing)
|
||||
{
|
||||
EnsureAudioFinalized();
|
||||
AudioOut.CloseTrack(Track);
|
||||
|
||||
ReleaseEvent.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
using Ryujinx.Core.OsHle.Handles;
|
||||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.IpcServices.Aud
|
||||
namespace Ryujinx.Core.OsHle.Services.Aud
|
||||
{
|
||||
class IAudioRenderer : IIpcService
|
||||
class IAudioRenderer : IpcService, IDisposable
|
||||
{
|
||||
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()
|
||||
{
|
||||
|
@ -19,6 +22,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud
|
|||
{ 6, StopAudioRenderer },
|
||||
{ 7, QuerySystemEvent }
|
||||
};
|
||||
|
||||
UpdateEvent = new KEvent();
|
||||
}
|
||||
|
||||
public long RequestUpdateAudioRenderer(ServiceCtx Context)
|
||||
|
@ -41,6 +46,9 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud
|
|||
Context.Memory.WriteInt32(Position + Offset, 5);
|
||||
}
|
||||
|
||||
//TODO: We shouldn't be signaling this here.
|
||||
UpdateEvent.Handle.Set();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -56,11 +64,24 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud
|
|||
|
||||
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);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool Disposing)
|
||||
{
|
||||
if (Disposing)
|
||||
{
|
||||
UpdateEvent.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,24 +1,24 @@
|
|||
using ChocolArm64.Memory;
|
||||
using Ryujinx.Audio;
|
||||
using Ryujinx.Core.OsHle.Handles;
|
||||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.IpcServices.Aud
|
||||
namespace Ryujinx.Core.OsHle.Services.Aud
|
||||
{
|
||||
class ServiceAudOut : IIpcService
|
||||
class ServiceAudOut : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ServiceAudOut()
|
||||
{
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, ListAudioOuts },
|
||||
{ 1, OpenAudioOut },
|
||||
{ 1, OpenAudioOut }
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -35,21 +35,58 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud
|
|||
|
||||
public long OpenAudioOut(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(Context, new IAudioOut());
|
||||
IAalOutput AudioOut = Context.Ns.AudioOut;
|
||||
|
||||
Context.ResponseData.Write(48000); //Sample Rate
|
||||
Context.ResponseData.Write(2); //Channel Count
|
||||
Context.ResponseData.Write(2); //PCM Format
|
||||
/*
|
||||
0 - Invalid
|
||||
1 - INT8
|
||||
2 - INT16
|
||||
3 - INT24
|
||||
4 - INT32
|
||||
5 - PCM Float
|
||||
6 - ADPCM
|
||||
*/
|
||||
Context.ResponseData.Write(0); //Unknown
|
||||
string DeviceName = AMemoryHelper.ReadAsciiString(
|
||||
Context.Memory,
|
||||
Context.Request.SendBuff[0].Position,
|
||||
Context.Request.SendBuff[0].Size);
|
||||
|
||||
if (DeviceName == string.Empty)
|
||||
{
|
||||
DeviceName = "FIXME";
|
||||
}
|
||||
|
||||
long DeviceNamePosition = Context.Request.ReceiveBuff[0].Position;
|
||||
long DeviceNameSize = Context.Request.ReceiveBuff[0].Size;
|
||||
|
||||
byte[] DeviceNameBuffer = Encoding.ASCII.GetBytes(DeviceName);
|
||||
|
||||
if (DeviceName.Length <= DeviceNameSize)
|
||||
{
|
||||
AMemoryHelper.WriteBytes(Context.Memory, DeviceNamePosition, DeviceNameBuffer);
|
||||
}
|
||||
|
||||
int SampleRate = Context.RequestData.ReadInt32();
|
||||
int Channels = Context.RequestData.ReadInt32();
|
||||
|
||||
Channels = (ushort)(Channels >> 16);
|
||||
|
||||
if (SampleRate == 0)
|
||||
{
|
||||
SampleRate = 48000;
|
||||
}
|
||||
|
||||
if (Channels < 1 || Channels > 2)
|
||||
{
|
||||
Channels = 2;
|
||||
}
|
||||
|
||||
KEvent ReleaseEvent = new KEvent();
|
||||
|
||||
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(Channels);
|
||||
Context.ResponseData.Write((int)Format);
|
||||
Context.ResponseData.Write((int)PlaybackState.Stopped);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,15 +1,13 @@
|
|||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.IpcServices.Aud
|
||||
namespace Ryujinx.Core.OsHle.Services.Aud
|
||||
{
|
||||
class ServiceAudRen : IIpcService
|
||||
class ServiceAudRen : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ServiceAudRen()
|
||||
{
|
||||
|
|
|
@ -8,7 +8,7 @@ using System.Net;
|
|||
using System.Net.Sockets;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.IpcServices.Bsd
|
||||
namespace Ryujinx.Core.OsHle.Services.Bsd
|
||||
{
|
||||
|
||||
//bsd_errno == (SocketException.ErrorCode - 10000)
|
||||
|
@ -51,11 +51,11 @@ namespace Ryujinx.Core.OsHle.IpcServices.Bsd
|
|||
public Socket Handle;
|
||||
}
|
||||
|
||||
class ServiceBsd : IIpcService
|
||||
class ServiceBsd : IpcService
|
||||
{
|
||||
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>();
|
||||
|
||||
|
@ -151,7 +151,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Bsd
|
|||
|
||||
byte[] SentBuffer = AMemoryHelper.ReadBytes(Context.Memory,
|
||||
Context.Request.SendBuff[0].Position,
|
||||
(int)Context.Request.SendBuff[0].Size);
|
||||
Context.Request.SendBuff[0].Size);
|
||||
int SocketId = Get32(SentBuffer, 0);
|
||||
short RequestedEvents = (short)Get16(SentBuffer, 4);
|
||||
short ReturnedEvents = (short)Get16(SentBuffer, 6);
|
||||
|
@ -197,7 +197,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Bsd
|
|||
int SocketFlags = Context.RequestData.ReadInt32();
|
||||
byte[] SentBuffer = AMemoryHelper.ReadBytes(Context.Memory,
|
||||
Context.Request.SendBuff[0].Position,
|
||||
(int)Context.Request.SendBuff[0].Size);
|
||||
Context.Request.SendBuff[0].Size);
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -224,10 +224,10 @@ namespace Ryujinx.Core.OsHle.IpcServices.Bsd
|
|||
int SocketFlags = Context.RequestData.ReadInt32();
|
||||
byte[] SentBuffer = AMemoryHelper.ReadBytes(Context.Memory,
|
||||
Context.Request.SendBuff[0].Position,
|
||||
(int)Context.Request.SendBuff[0].Size);
|
||||
Context.Request.SendBuff[0].Size);
|
||||
byte[] AddressBuffer = AMemoryHelper.ReadBytes(Context.Memory,
|
||||
Context.Request.SendBuff[1].Position,
|
||||
(int)Context.Request.SendBuff[1].Size);
|
||||
Context.Request.SendBuff[1].Size);
|
||||
|
||||
if (!Sockets[SocketId].Handle.Connected)
|
||||
{
|
||||
|
@ -333,7 +333,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Bsd
|
|||
|
||||
byte[] AddressBuffer = AMemoryHelper.ReadBytes(Context.Memory,
|
||||
Context.Request.SendBuff[0].Position,
|
||||
(int)Context.Request.SendBuff[0].Size);
|
||||
Context.Request.SendBuff[0].Size);
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -358,7 +358,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Bsd
|
|||
|
||||
byte[] AddressBuffer = AMemoryHelper.ReadBytes(Context.Memory,
|
||||
Context.Request.SendBuff[0].Position,
|
||||
(int)Context.Request.SendBuff[0].Size);
|
||||
Context.Request.SendBuff[0].Size);
|
||||
|
||||
try
|
||||
{
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.IpcServices.Friend
|
||||
namespace Ryujinx.Core.OsHle.Services.Friend
|
||||
{
|
||||
class IFriendService : IIpcService
|
||||
class IFriendService : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IFriendService()
|
||||
{
|
||||
|
|
|
@ -1,15 +1,13 @@
|
|||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.IpcServices.Friend
|
||||
namespace Ryujinx.Core.OsHle.Services.Friend
|
||||
{
|
||||
class ServiceFriend : IIpcService
|
||||
class ServiceFriend : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ServiceFriend()
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace Ryujinx.Core.OsHle.IpcServices.FspSrv
|
||||
namespace Ryujinx.Core.OsHle.Services.FspSrv
|
||||
{
|
||||
static class FsErr
|
||||
{
|
||||
|
|
|
@ -5,15 +5,15 @@ using System.Collections.Generic;
|
|||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.IpcServices.FspSrv
|
||||
namespace Ryujinx.Core.OsHle.Services.FspSrv
|
||||
{
|
||||
class IDirectory : IIpcService, IDisposable
|
||||
class IDirectory : IpcService, IDisposable
|
||||
{
|
||||
private const int DirectoryEntrySize = 0x310;
|
||||
|
||||
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;
|
||||
|
||||
|
|
|
@ -4,13 +4,13 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.IpcServices.FspSrv
|
||||
namespace Ryujinx.Core.OsHle.Services.FspSrv
|
||||
{
|
||||
class IFile : IIpcService, IDisposable
|
||||
class IFile : IpcService, IDisposable
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
private Stream BaseStream;
|
||||
|
||||
|
@ -62,7 +62,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.FspSrv
|
|||
long Offset = Context.RequestData.ReadInt64();
|
||||
long Size = Context.RequestData.ReadInt64();
|
||||
|
||||
byte[] Data = AMemoryHelper.ReadBytes(Context.Memory, Position, (int)Size);
|
||||
byte[] Data = AMemoryHelper.ReadBytes(Context.Memory, Position, Size);
|
||||
|
||||
BaseStream.Seek(Offset, SeekOrigin.Begin);
|
||||
BaseStream.Write(Data, 0, (int)Size);
|
||||
|
|
|
@ -5,15 +5,14 @@ using System.IO;
|
|||
using System.Text;
|
||||
|
||||
using static Ryujinx.Core.OsHle.ErrorCode;
|
||||
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.IpcServices.FspSrv
|
||||
namespace Ryujinx.Core.OsHle.Services.FspSrv
|
||||
{
|
||||
class IFileSystem : IIpcService
|
||||
class IFileSystem : IpcService
|
||||
{
|
||||
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;
|
||||
|
||||
|
|
|
@ -3,13 +3,13 @@ using Ryujinx.Core.OsHle.Ipc;
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.IpcServices.FspSrv
|
||||
namespace Ryujinx.Core.OsHle.Services.FspSrv
|
||||
{
|
||||
class IStorage : IIpcService
|
||||
class IStorage : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
private Stream BaseStream;
|
||||
|
||||
|
|
|
@ -1,15 +1,13 @@
|
|||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.IpcServices.FspSrv
|
||||
namespace Ryujinx.Core.OsHle.Services.FspSrv
|
||||
{
|
||||
class ServiceFspSrv : IIpcService
|
||||
class ServiceFspSrv : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ServiceFspSrv()
|
||||
{
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.IpcServices.Hid
|
||||
namespace Ryujinx.Core.OsHle.Services.Hid
|
||||
{
|
||||
class IActiveApplicationDeviceList : IIpcService
|
||||
class IActiveApplicationDeviceList : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IActiveApplicationDeviceList()
|
||||
{
|
||||
|
|
|
@ -2,13 +2,13 @@ using Ryujinx.Core.OsHle.Handles;
|
|||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.IpcServices.Hid
|
||||
namespace Ryujinx.Core.OsHle.Services.Hid
|
||||
{
|
||||
class IAppletResource : IIpcService
|
||||
class IAppletResource : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
private HSharedMem HidSharedMem;
|
||||
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
using Ryujinx.Core.Input;
|
||||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using System.Collections.Generic;
|
||||
using Ryujinx.Core.Input;
|
||||
|
||||
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.IpcServices.Hid
|
||||
namespace Ryujinx.Core.OsHle.Services.Hid
|
||||
{
|
||||
class ServiceHid : IIpcService
|
||||
class ServiceHid : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ServiceHid()
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.IpcServices
|
||||
namespace Ryujinx.Core.OsHle.Services
|
||||
{
|
||||
interface IIpcService
|
||||
{
|
||||
|
|
151
Ryujinx.Core/OsHle/Services/IpcService.cs
Normal file
151
Ryujinx.Core/OsHle/Services/IpcService.cs
Normal file
|
@ -0,0 +1,151 @@
|
|||
using Ryujinx.Core.OsHle.Handles;
|
||||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.Services
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
private int Add(IIpcService Obj)
|
||||
{
|
||||
return DomainObjects.Add(Obj);
|
||||
}
|
||||
|
||||
private bool Delete(int Id)
|
||||
{
|
||||
object Obj = DomainObjects.Delete(Id);
|
||||
|
||||
if (Obj is IDisposable DisposableObj)
|
||||
{
|
||||
DisposableObj.Dispose();
|
||||
}
|
||||
|
||||
return Obj != null;
|
||||
}
|
||||
|
||||
private IIpcService GetObject(int Id)
|
||||
{
|
||||
return DomainObjects.GetData<IIpcService>(Id);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,13 +5,13 @@ using System.Collections.Generic;
|
|||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.IpcServices.Lm
|
||||
namespace Ryujinx.Core.OsHle.Services.Lm
|
||||
{
|
||||
class ILogger : IIpcService
|
||||
class ILogger : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ILogger()
|
||||
{
|
||||
|
@ -54,7 +54,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Lm
|
|||
long BufferPosition = Context.Request.PtrBuff[0].Position;
|
||||
long BufferLen = Context.Request.PtrBuff[0].Size;
|
||||
|
||||
byte[] LogBuffer = AMemoryHelper.ReadBytes(Context.Memory, BufferPosition, (int)BufferLen);
|
||||
byte[] LogBuffer = AMemoryHelper.ReadBytes(Context.Memory, BufferPosition, BufferLen);
|
||||
|
||||
MemoryStream LogMessage = new MemoryStream(LogBuffer);
|
||||
BinaryReader bReader = new BinaryReader(LogMessage);
|
||||
|
|
|
@ -1,15 +1,13 @@
|
|||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.IpcServices.Lm
|
||||
namespace Ryujinx.Core.OsHle.Services.Lm
|
||||
{
|
||||
class ServiceLm : IIpcService
|
||||
class ServiceLm : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ServiceLm()
|
||||
{
|
||||
|
@ -21,8 +19,6 @@ namespace Ryujinx.Core.OsHle.IpcServices.Lm
|
|||
|
||||
public long Initialize(ServiceCtx Context)
|
||||
{
|
||||
Context.Session.Initialize();
|
||||
|
||||
MakeObject(Context, new ILogger());
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -1,15 +1,13 @@
|
|||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.IpcServices.Nifm
|
||||
namespace Ryujinx.Core.OsHle.Services.Nifm
|
||||
{
|
||||
class IGeneralService : IIpcService
|
||||
class IGeneralService : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IGeneralService()
|
||||
{
|
||||
|
|
|
@ -1,13 +1,17 @@
|
|||
using Ryujinx.Core.OsHle.Handles;
|
||||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.IpcServices.Nifm
|
||||
namespace Ryujinx.Core.OsHle.Services.Nifm
|
||||
{
|
||||
class IRequest : IIpcService
|
||||
class IRequest : IpcService, IDisposable
|
||||
{
|
||||
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()
|
||||
{
|
||||
|
@ -17,9 +21,10 @@ namespace Ryujinx.Core.OsHle.IpcServices.Nifm
|
|||
{ 1, GetResult },
|
||||
{ 2, GetSystemEventReadableHandles }
|
||||
};
|
||||
|
||||
Event = new KEvent();
|
||||
}
|
||||
|
||||
// -> i32
|
||||
public long GetRequestState(ServiceCtx Context)
|
||||
{
|
||||
Context.ResponseData.Write(0);
|
||||
|
@ -39,11 +44,25 @@ namespace Ryujinx.Core.OsHle.IpcServices.Nifm
|
|||
//GetSystemEventReadableHandles() -> (KObject, KObject)
|
||||
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.MakeMove(Handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool Disposing)
|
||||
{
|
||||
if (Disposing)
|
||||
{
|
||||
Event.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,15 +1,13 @@
|
|||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.IpcServices.Nifm
|
||||
namespace Ryujinx.Core.OsHle.Services.Nifm
|
||||
{
|
||||
class ServiceNifm : IIpcService
|
||||
class ServiceNifm : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ServiceNifm()
|
||||
{
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.IpcServices.Ns
|
||||
namespace Ryujinx.Core.OsHle.Services.Ns
|
||||
{
|
||||
class ServiceNs : IIpcService
|
||||
class ServiceNs : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ServiceNs()
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
||||
namespace Ryujinx.Core.OsHle.Services.Nv
|
||||
{
|
||||
class NvFd
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
||||
namespace Ryujinx.Core.OsHle.Services.Nv
|
||||
{
|
||||
class NvMap
|
||||
{
|
||||
|
@ -7,6 +7,6 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
|||
public int Size;
|
||||
public int Align;
|
||||
public int Kind;
|
||||
public long Address;
|
||||
public long CpuAddress;
|
||||
}
|
||||
}
|
40
Ryujinx.Core/OsHle/Services/Nv/NvMapFb.cs
Normal file
40
Ryujinx.Core/OsHle/Services/Nv/NvMapFb.cs
Normal file
|
@ -0,0 +1,40 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.Services.Nv
|
||||
{
|
||||
class NvMapFb
|
||||
{
|
||||
private List<long> BufferOffs;
|
||||
|
||||
public NvMapFb()
|
||||
{
|
||||
BufferOffs = new List<long>();
|
||||
}
|
||||
|
||||
public void AddBufferOffset(long Offset)
|
||||
{
|
||||
BufferOffs.Add(Offset);
|
||||
}
|
||||
|
||||
public bool HasBufferOffset(int Index)
|
||||
{
|
||||
if ((uint)Index >= BufferOffs.Count)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public long GetBufferOffset(int Index)
|
||||
{
|
||||
if ((uint)Index >= BufferOffs.Count)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(Index));
|
||||
}
|
||||
|
||||
return BufferOffs[Index];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,26 +1,30 @@
|
|||
using ChocolArm64.Memory;
|
||||
using Ryujinx.Core.OsHle.Handles;
|
||||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using Ryujinx.Core.OsHle.Utilities;
|
||||
using Ryujinx.Graphics.Gpu;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
||||
namespace Ryujinx.Core.OsHle.Services.Nv
|
||||
{
|
||||
class ServiceNvDrv : IIpcService
|
||||
class ServiceNvDrv : IpcService, IDisposable
|
||||
{
|
||||
private delegate long ServiceProcessIoctl(ServiceCtx Context);
|
||||
|
||||
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 IdDictionary Fds;
|
||||
public static GlobalStateTable Fds { get; private set; }
|
||||
|
||||
private IdDictionary NvMaps;
|
||||
private IdDictionary NvMapsById;
|
||||
public static GlobalStateTable NvMaps { get; private set; }
|
||||
public static GlobalStateTable NvMapsById { get; private set; }
|
||||
public static GlobalStateTable NvMapsFb { get; private set; }
|
||||
|
||||
private KEvent Event;
|
||||
|
||||
public ServiceNvDrv()
|
||||
{
|
||||
|
@ -64,10 +68,16 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
|||
{ ("/dev/nvmap", 0x010e), NvMapIocGetId },
|
||||
};
|
||||
|
||||
Fds = new IdDictionary();
|
||||
Event = new KEvent();
|
||||
}
|
||||
|
||||
NvMaps = new IdDictionary();
|
||||
NvMapsById = new IdDictionary();
|
||||
static ServiceNvDrv()
|
||||
{
|
||||
Fds = new GlobalStateTable();
|
||||
|
||||
NvMaps = new GlobalStateTable();
|
||||
NvMapsById = new GlobalStateTable();
|
||||
NvMapsFb = new GlobalStateTable();
|
||||
}
|
||||
|
||||
public long Open(ServiceCtx Context)
|
||||
|
@ -76,7 +86,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
|||
|
||||
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(0);
|
||||
|
@ -89,7 +99,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
|||
int Fd = Context.RequestData.ReadInt32();
|
||||
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();
|
||||
|
||||
|
@ -109,7 +119,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
|||
{
|
||||
int Fd = Context.RequestData.ReadInt32();
|
||||
|
||||
Fds.Delete(Fd);
|
||||
Fds.Delete(Context.Process, Fd);
|
||||
|
||||
Context.ResponseData.Write(0);
|
||||
|
||||
|
@ -123,6 +133,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
|||
|
||||
Context.ResponseData.Write(0);
|
||||
|
||||
NvMapsFb.Add(Context.Process, 0, new NvMapFb());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -131,7 +143,10 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
|||
int Fd = 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);
|
||||
|
||||
|
@ -198,12 +213,15 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
|||
|
||||
if (Handle == 0)
|
||||
{
|
||||
//Handle 0 is valid here, but it refers to something else.
|
||||
//TODO: Figure out what, for now just return success.
|
||||
//This is used to store offsets for the Framebuffer(s);
|
||||
NvMapFb MapFb = (NvMapFb)NvMapsFb.GetData(Context.Process, 0);
|
||||
|
||||
MapFb.AddBufferOffset(BuffAddr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
NvMap Map = NvMaps.GetData<NvMap>(Handle);
|
||||
NvMap Map = NvMaps.GetData<NvMap>(Context.Process, Handle);
|
||||
|
||||
if (Map == null)
|
||||
{
|
||||
|
@ -214,11 +232,11 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
|||
|
||||
if ((Flags & 1) != 0)
|
||||
{
|
||||
Offset = Context.Ns.Gpu.MapMemory(Map.Address, Offset, Map.Size);
|
||||
Offset = Context.Ns.Gpu.MapMemory(Map.CpuAddress, Offset, Map.Size);
|
||||
}
|
||||
else
|
||||
{
|
||||
Offset = Context.Ns.Gpu.MapMemory(Map.Address, Map.Size);
|
||||
Offset = Context.Ns.Gpu.MapMemory(Map.CpuAddress, Map.Size);
|
||||
}
|
||||
|
||||
Context.Memory.WriteInt64(Position + 0x20, Offset);
|
||||
|
@ -550,9 +568,9 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
|||
|
||||
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);
|
||||
|
||||
|
@ -567,7 +585,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
|||
|
||||
int Id = Context.Memory.ReadInt32(Position);
|
||||
|
||||
NvMap Map = NvMapsById.GetData<NvMap>(Id);
|
||||
NvMap Map = NvMapsById.GetData<NvMap>(Context.Process, Id);
|
||||
|
||||
if (Map == null)
|
||||
{
|
||||
|
@ -594,7 +612,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
|||
byte Kind = (byte)Reader.ReadInt64();
|
||||
long Addr = Reader.ReadInt64();
|
||||
|
||||
NvMap Map = NvMaps.GetData<NvMap>(Handle);
|
||||
NvMap Map = NvMaps.GetData<NvMap>(Context.Process, Handle);
|
||||
|
||||
if (Map == null)
|
||||
{
|
||||
|
@ -603,7 +621,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
|||
return -1; //TODO: Corrent error code.
|
||||
}
|
||||
|
||||
Map.Address = Addr;
|
||||
Map.CpuAddress = Addr;
|
||||
Map.Align = Align;
|
||||
Map.Kind = Kind;
|
||||
|
||||
|
@ -620,7 +638,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
|||
int Handle = Reader.ReadInt32();
|
||||
int Padding = Reader.ReadInt32();
|
||||
|
||||
NvMap Map = NvMaps.GetData<NvMap>(Handle);
|
||||
NvMap Map = NvMaps.GetData<NvMap>(Context.Process, Handle);
|
||||
|
||||
if (Map == null)
|
||||
{
|
||||
|
@ -645,7 +663,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
|||
int Handle = Reader.ReadInt32();
|
||||
int Param = Reader.ReadInt32();
|
||||
|
||||
NvMap Map = NvMaps.GetData<NvMap>(Handle);
|
||||
NvMap Map = NvMaps.GetData<NvMap>(Context.Process, Handle);
|
||||
|
||||
if (Map == null)
|
||||
{
|
||||
|
@ -675,7 +693,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
|||
|
||||
int Handle = Context.Memory.ReadInt32(Position + 4);
|
||||
|
||||
NvMap Map = NvMaps.GetData<NvMap>(Handle);
|
||||
NvMap Map = NvMaps.GetData<NvMap>(Context.Process, Handle);
|
||||
|
||||
if (Map == null)
|
||||
{
|
||||
|
@ -689,9 +707,17 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
|
|||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,13 +1,13 @@
|
|||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.IpcServices.Pctl
|
||||
namespace Ryujinx.Core.OsHle.Services.Pctl
|
||||
{
|
||||
class IParentalControlService : IIpcService
|
||||
class IParentalControlService : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IParentalControlService()
|
||||
{
|
||||
|
|
|
@ -1,15 +1,13 @@
|
|||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.IpcServices.Pctl
|
||||
namespace Ryujinx.Core.OsHle.Services.Pctl
|
||||
{
|
||||
class ServicePctl : IIpcService
|
||||
class ServicePctl : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ServicePctl()
|
||||
{
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.IpcServices.Pl
|
||||
namespace Ryujinx.Core.OsHle.Services.Pl
|
||||
{
|
||||
class ServicePl : IIpcService
|
||||
class ServicePl : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ServicePl()
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace Ryujinx.Core.OsHle.IpcServices.Pl
|
||||
namespace Ryujinx.Core.OsHle.Services.Pl
|
||||
{
|
||||
enum SharedFontType
|
||||
{
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue