aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Core
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2018-02-23 18:48:27 -0300
committergdkchan <gab.dark.100@gmail.com>2018-02-23 18:48:27 -0300
commit2ed733b1d5addad027f48acfdd407e64b71427fc (patch)
tree1254df3ab2bace8de561b5a3549f668fabcf4aa9 /Ryujinx.Core
parenteafc58c9f2e2e0c19d22f0da2a93ab5372aeef29 (diff)
Somewhat better NvFlinger (I guess) (fixes #30)
Diffstat (limited to 'Ryujinx.Core')
-rw-r--r--Ryujinx.Core/OsHle/Objects/Android/GbpBuffer.cs60
-rw-r--r--Ryujinx.Core/OsHle/Objects/Android/NvFlinger.cs392
-rw-r--r--Ryujinx.Core/OsHle/Objects/Android/Parcel.cs (renamed from Ryujinx.Core/OsHle/Objects/Parcel.cs)0
-rw-r--r--Ryujinx.Core/OsHle/Objects/ErrorCode.cs2
-rw-r--r--Ryujinx.Core/OsHle/Objects/Hid/IActiveVibrationDeviceList.cs1
-rw-r--r--Ryujinx.Core/OsHle/Objects/Vi/IHOSBinderDriver.cs178
6 files changed, 472 insertions, 161 deletions
diff --git a/Ryujinx.Core/OsHle/Objects/Android/GbpBuffer.cs b/Ryujinx.Core/OsHle/Objects/Android/GbpBuffer.cs
new file mode 100644
index 00000000..edd11523
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Objects/Android/GbpBuffer.cs
@@ -0,0 +1,60 @@
+using System.IO;
+
+namespace Ryujinx.Core.OsHle.Objects.Android
+{
+ struct GbpBuffer
+ {
+ public int Magic { get; private set; }
+ public int Width { get; private set; }
+ public int Height { get; private set; }
+ public int Stride { get; private set; }
+ public int Format { get; private set; }
+ public int Usage { get; private set; }
+
+ public int Pid { get; private set; }
+ public int RefCount { get; private set; }
+
+ public int FdsCount { get; private set; }
+ public int IntsCount { get; private set; }
+
+ public byte[] RawData { get; private set; }
+
+ public int Size => RawData.Length + 10 * 4;
+
+ public GbpBuffer(BinaryReader Reader)
+ {
+ Magic = Reader.ReadInt32();
+ Width = Reader.ReadInt32();
+ Height = Reader.ReadInt32();
+ Stride = Reader.ReadInt32();
+ Format = Reader.ReadInt32();
+ Usage = Reader.ReadInt32();
+
+ Pid = Reader.ReadInt32();
+ RefCount = Reader.ReadInt32();
+
+ FdsCount = Reader.ReadInt32();
+ IntsCount = Reader.ReadInt32();
+
+ RawData = Reader.ReadBytes((FdsCount + IntsCount) * 4);
+ }
+
+ public void Write(BinaryWriter Writer)
+ {
+ Writer.Write(Magic);
+ Writer.Write(Width);
+ Writer.Write(Height);
+ Writer.Write(Stride);
+ Writer.Write(Format);
+ Writer.Write(Usage);
+
+ Writer.Write(Pid);
+ Writer.Write(RefCount);
+
+ Writer.Write(FdsCount);
+ Writer.Write(IntsCount);
+
+ Writer.Write(RawData);
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Objects/Android/NvFlinger.cs b/Ryujinx.Core/OsHle/Objects/Android/NvFlinger.cs
new file mode 100644
index 00000000..23863099
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Objects/Android/NvFlinger.cs
@@ -0,0 +1,392 @@
+using ChocolArm64.Memory;
+using Ryujinx.Core.OsHle.Handles;
+using System;
+using System.IO;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading;
+
+using static Ryujinx.Core.OsHle.Objects.Android.Parcel;
+
+namespace Ryujinx.Core.OsHle.Objects.Android
+{
+ class NvFlinger : IDisposable
+ {
+ private delegate long ServiceProcessParcel(ServiceCtx Context, BinaryReader ParcelReader);
+
+ private Dictionary<(string, int), ServiceProcessParcel> Commands;
+
+ private const int BufferQueueCount = 0x40;
+ private const int BufferQueueMask = BufferQueueCount - 1;
+
+ [Flags]
+ private enum HalTransform
+ {
+ FlipX = 1 << 0,
+ FlipY = 1 << 1,
+ Rotate90 = 1 << 2
+ }
+
+ private enum BufferState
+ {
+ Free,
+ Dequeued,
+ Queued,
+ Acquired
+ }
+
+ private struct BufferEntry
+ {
+ public BufferState State;
+
+ public HalTransform Transform;
+
+ public GbpBuffer Data;
+ }
+
+ private BufferEntry[] BufferQueue;
+
+ private ManualResetEvent WaitBufferFree;
+
+ private bool KeepRunning;
+
+ public NvFlinger()
+ {
+ Commands = new Dictionary<(string, int), ServiceProcessParcel>()
+ {
+ { ("android.gui.IGraphicBufferProducer", 0x1), GbpRequestBuffer },
+ { ("android.gui.IGraphicBufferProducer", 0x3), GbpDequeueBuffer },
+ { ("android.gui.IGraphicBufferProducer", 0x7), GbpQueueBuffer },
+ { ("android.gui.IGraphicBufferProducer", 0x8), GbpCancelBuffer },
+ { ("android.gui.IGraphicBufferProducer", 0x9), GbpQuery },
+ { ("android.gui.IGraphicBufferProducer", 0xa), GbpConnect },
+ { ("android.gui.IGraphicBufferProducer", 0xe), GbpPreallocBuffer }
+ };
+
+ BufferQueue = new BufferEntry[0x40];
+
+ WaitBufferFree = new ManualResetEvent(false);
+
+ KeepRunning = true;
+ }
+
+ public long ProcessParcelRequest(ServiceCtx Context, byte[] ParcelData, int Code)
+ {
+ using (MemoryStream MS = new MemoryStream(ParcelData))
+ {
+ BinaryReader Reader = new BinaryReader(MS);
+
+ MS.Seek(4, SeekOrigin.Current);
+
+ int StrSize = Reader.ReadInt32();
+
+ string InterfaceName = Encoding.Unicode.GetString(Reader.ReadBytes(StrSize * 2));
+
+ long Remainder = MS.Position & 0xf;
+
+ if (Remainder != 0)
+ {
+ MS.Seek(0x10 - Remainder, SeekOrigin.Current);
+ }
+
+ MS.Seek(0x50, SeekOrigin.Begin);
+
+ if (Commands.TryGetValue((InterfaceName, Code), out ServiceProcessParcel ProcReq))
+ {
+ Logging.Debug($"{InterfaceName} {ProcReq.Method.Name}");
+
+ return ProcReq(Context, Reader);
+ }
+ else
+ {
+ throw new NotImplementedException($"{InterfaceName} {Code}");
+ }
+ }
+ }
+
+ private long GbpRequestBuffer(ServiceCtx Context, BinaryReader ParcelReader)
+ {
+ int Slot = ParcelReader.ReadInt32();
+
+ using (MemoryStream MS = new MemoryStream())
+ {
+ BinaryWriter Writer = new BinaryWriter(MS);
+
+ BufferEntry Entry = BufferQueue[Slot];
+
+ int BufferCount = 1; //?
+ long BufferSize = Entry.Data.Size;
+
+ Writer.Write(BufferCount);
+ Writer.Write(BufferSize);
+
+ Entry.Data.Write(Writer);
+
+ Writer.Write(0);
+
+ return MakeReplyParcel(Context, MS.ToArray());
+ }
+ }
+
+ private long GbpDequeueBuffer(ServiceCtx Context, BinaryReader ParcelReader)
+ {
+ //TODO: Errors.
+ int Format = ParcelReader.ReadInt32();
+ int Width = ParcelReader.ReadInt32();
+ int Height = ParcelReader.ReadInt32();
+ int GetTimestamps = ParcelReader.ReadInt32();
+ int Usage = ParcelReader.ReadInt32();
+
+ int Slot = GetFreeSlotBlocking(Width, Height);
+
+ return MakeReplyParcel(Context, Slot, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ }
+
+ private long GbpQueueBuffer(ServiceCtx Context, BinaryReader ParcelReader)
+ {
+ //TODO: Errors.
+ int Slot = ParcelReader.ReadInt32();
+ int Unknown4 = ParcelReader.ReadInt32();
+ int Unknown8 = ParcelReader.ReadInt32();
+ int Unknownc = ParcelReader.ReadInt32();
+ int Timestamp = ParcelReader.ReadInt32();
+ int IsAutoTimestamp = ParcelReader.ReadInt32();
+ int CropTop = ParcelReader.ReadInt32();
+ int CropLeft = ParcelReader.ReadInt32();
+ int CropRight = ParcelReader.ReadInt32();
+ int CropBottom = ParcelReader.ReadInt32();
+ int ScalingMode = ParcelReader.ReadInt32();
+ int Transform = ParcelReader.ReadInt32();
+ int StickyTransform = ParcelReader.ReadInt32();
+ int Unknown34 = ParcelReader.ReadInt32();
+ int Unknown38 = ParcelReader.ReadInt32();
+ int IsFenceValid = ParcelReader.ReadInt32();
+ int Fence0Id = ParcelReader.ReadInt32();
+ int Fence0Value = ParcelReader.ReadInt32();
+ int Fence1Id = ParcelReader.ReadInt32();
+ int Fence1Value = ParcelReader.ReadInt32();
+
+ BufferQueue[Slot].Transform = (HalTransform)Transform;
+
+ BufferQueue[Slot].State = BufferState.Queued;
+
+ SendFrameBuffer(Context, Slot);
+
+ return MakeReplyParcel(Context, 1280, 720, 0, 0, 0);
+ }
+
+ private long GbpCancelBuffer(ServiceCtx Context, BinaryReader ParcelReader)
+ {
+ //TODO: Errors.
+ int Slot = ParcelReader.ReadInt32();
+
+ BufferQueue[Slot].State = BufferState.Free;
+
+ return MakeReplyParcel(Context, 0);
+ }
+
+ private long GbpQuery(ServiceCtx Context, BinaryReader ParcelReader)
+ {
+ return MakeReplyParcel(Context, 0, 0);
+ }
+
+ private long GbpConnect(ServiceCtx Context, BinaryReader ParcelReader)
+ {
+ return MakeReplyParcel(Context, 1280, 720, 0, 0, 0);
+ }
+
+ private long GbpPreallocBuffer(ServiceCtx Context, BinaryReader ParcelReader)
+ {
+ int Slot = ParcelReader.ReadInt32();
+
+ int BufferCount = ParcelReader.ReadInt32();
+ long BufferSize = ParcelReader.ReadInt64();
+
+ BufferQueue[Slot].State = BufferState.Free;
+
+ BufferQueue[Slot].Data = new GbpBuffer(ParcelReader);
+
+ return MakeReplyParcel(Context, 0);
+ }
+
+ private long MakeReplyParcel(ServiceCtx Context, params int[] Ints)
+ {
+ using (MemoryStream MS = new MemoryStream())
+ {
+ BinaryWriter Writer = new BinaryWriter(MS);
+
+ foreach (int Int in Ints)
+ {
+ Writer.Write(Int);
+ }
+
+ return MakeReplyParcel(Context, MS.ToArray());
+ }
+ }
+
+ private long MakeReplyParcel(ServiceCtx Context, byte[] Data)
+ {
+ long ReplyPos = Context.Request.ReceiveBuff[0].Position;
+ long ReplySize = Context.Request.ReceiveBuff[0].Size;
+
+ byte[] Reply = MakeParcel(Data, new byte[0]);
+
+ AMemoryHelper.WriteBytes(Context.Memory, ReplyPos, Reply);
+
+ return 0;
+ }
+
+ private unsafe void SendFrameBuffer(ServiceCtx Context, int Slot)
+ {
+ int FbWidth = BufferQueue[Slot].Data.Width;
+ int FbHeight = BufferQueue[Slot].Data.Height;
+
+ int FbSize = FbWidth * FbHeight * 4;
+
+ HNvMap NvMap = GetNvMap(Context, Slot);
+
+ if (NvMap.Address < 0 || NvMap.Address + FbSize > AMemoryMgr.AddrSize)
+ {
+ Logging.Error($"Frame buffer address {NvMap.Address:x16} is invalid!");
+
+ BufferQueue[Slot].State = BufferState.Free;
+
+ WaitBufferFree.Set();
+
+ return;
+ }
+
+ BufferQueue[Slot].State = BufferState.Acquired;
+
+ float ScaleX = 1;
+ float ScaleY = 1;
+ float Rotate = 0;
+
+ if (BufferQueue[Slot].Transform.HasFlag(HalTransform.FlipX))
+ {
+ ScaleX = -1;
+ }
+
+ if (BufferQueue[Slot].Transform.HasFlag(HalTransform.FlipY))
+ {
+ ScaleY = -1;
+ }
+
+ if (BufferQueue[Slot].Transform.HasFlag(HalTransform.Rotate90))
+ {
+ Rotate = MathF.PI * 0.5f;
+ }
+
+ byte* Fb = (byte*)Context.Ns.Ram + NvMap.Address;
+
+ Context.Ns.Gpu.Renderer.QueueAction(delegate()
+ {
+ Context.Ns.Gpu.Renderer.SetFrameBuffer(
+ Fb,
+ FbWidth,
+ FbHeight,
+ ScaleX,
+ ScaleY,
+ Rotate);
+
+ BufferQueue[Slot].State = BufferState.Free;
+
+ WaitBufferFree.Set();
+ });
+ }
+
+ private HNvMap GetNvMap(ServiceCtx Context, int Slot)
+ {
+ int NvMapHandle = BitConverter.ToInt32(BufferQueue[Slot].Data.RawData, 0x4c);
+
+ if (!BitConverter.IsLittleEndian)
+ {
+ byte[] RawValue = BitConverter.GetBytes(NvMapHandle);
+
+ Array.Reverse(RawValue);
+
+ NvMapHandle = BitConverter.ToInt32(RawValue, 0);
+ }
+
+ return Context.Ns.Os.Handles.GetData<HNvMap>(NvMapHandle);
+ }
+
+ private int GetFreeSlotBlocking(int Width, int Height)
+ {
+ int Slot;
+
+ do
+ {
+ if ((Slot = GetFreeSlot(Width, Height)) != -1)
+ {
+ break;
+ }
+
+ Logging.Debug("Waiting for a free BufferQueue slot...");
+
+ lock (WaitBufferFree)
+ {
+ if (!KeepRunning)
+ {
+ break;
+ }
+
+ WaitBufferFree.Reset();
+ }
+
+ WaitBufferFree.WaitOne();
+ }
+ while (KeepRunning);
+
+ Logging.Debug($"Found free BufferQueue slot {Slot}!");
+
+ return Slot;
+ }
+
+ private int GetFreeSlot(int Width, int Height)
+ {
+ lock (BufferQueue)
+ {
+ for (int Slot = 0; Slot < BufferQueue.Length; Slot++)
+ {
+ if (BufferQueue[Slot].State != BufferState.Free)
+ {
+ continue;
+ }
+
+ GbpBuffer Data = BufferQueue[Slot].Data;
+
+ if (Data.Width == Width &&
+ Data.Height == Height)
+ {
+ BufferQueue[Slot].State = BufferState.Dequeued;
+
+ return Slot;
+ }
+ }
+ }
+
+ return -1;
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ lock (WaitBufferFree)
+ {
+ KeepRunning = false;
+
+ WaitBufferFree.Set();
+ }
+
+ WaitBufferFree.Dispose();
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Objects/Parcel.cs b/Ryujinx.Core/OsHle/Objects/Android/Parcel.cs
index cd7179e1..cd7179e1 100644
--- a/Ryujinx.Core/OsHle/Objects/Parcel.cs
+++ b/Ryujinx.Core/OsHle/Objects/Android/Parcel.cs
diff --git a/Ryujinx.Core/OsHle/Objects/ErrorCode.cs b/Ryujinx.Core/OsHle/Objects/ErrorCode.cs
index 20f97f84..659ed8b9 100644
--- a/Ryujinx.Core/OsHle/Objects/ErrorCode.cs
+++ b/Ryujinx.Core/OsHle/Objects/ErrorCode.cs
@@ -1,5 +1,3 @@
-using System;
-
namespace Ryujinx.Core.OsHle.Objects
{
static class ErrorCode
diff --git a/Ryujinx.Core/OsHle/Objects/Hid/IActiveVibrationDeviceList.cs b/Ryujinx.Core/OsHle/Objects/Hid/IActiveVibrationDeviceList.cs
index 1f0c8592..aae3c38d 100644
--- a/Ryujinx.Core/OsHle/Objects/Hid/IActiveVibrationDeviceList.cs
+++ b/Ryujinx.Core/OsHle/Objects/Hid/IActiveVibrationDeviceList.cs
@@ -1,4 +1,3 @@
-using Ryujinx.Core.OsHle.Handles;
using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic;
diff --git a/Ryujinx.Core/OsHle/Objects/Vi/IHOSBinderDriver.cs b/Ryujinx.Core/OsHle/Objects/Vi/IHOSBinderDriver.cs
index cfd271e8..bbea3368 100644
--- a/Ryujinx.Core/OsHle/Objects/Vi/IHOSBinderDriver.cs
+++ b/Ryujinx.Core/OsHle/Objects/Vi/IHOSBinderDriver.cs
@@ -1,34 +1,18 @@
using ChocolArm64.Memory;
-using Ryujinx.Core.OsHle.Handles;
using Ryujinx.Core.OsHle.Ipc;
-using Ryujinx.Core.OsHle.Utilities;
+using Ryujinx.Core.OsHle.Objects.Android;
using System;
using System.Collections.Generic;
-using System.IO;
-using System.Text;
-
-using static Ryujinx.Core.OsHle.Objects.Android.Parcel;
namespace Ryujinx.Core.OsHle.Objects.Vi
{
- class IHOSBinderDriver : IIpcInterface
+ class IHOSBinderDriver : IIpcInterface, IDisposable
{
- private delegate long ServiceProcessParcel(ServiceCtx Context, byte[] ParcelData);
-
private Dictionary<int, ServiceProcessRequest> m_Commands;
- private Dictionary<(string, int), ServiceProcessParcel> m_Methods;
-
- public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+ public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
- private class BufferObj
- {
-
- }
-
- private IdPoolWithObj BufferSlots;
-
- private byte[] Gbfr;
+ private NvFlinger Flinger;
public IHOSBinderDriver()
{
@@ -39,18 +23,7 @@ namespace Ryujinx.Core.OsHle.Objects.Vi
{ 2, GetNativeHandle }
};
- m_Methods = new Dictionary<(string, int), ServiceProcessParcel>()
- {
- { ("android.gui.IGraphicBufferProducer", 0x1), GraphicBufferProducerRequestBuffer },
- { ("android.gui.IGraphicBufferProducer", 0x3), GraphicBufferProducerDequeueBuffer },
- { ("android.gui.IGraphicBufferProducer", 0x7), GraphicBufferProducerQueueBuffer },
- { ("android.gui.IGraphicBufferProducer", 0x8), GraphicBufferProducerCancelBuffer },
- { ("android.gui.IGraphicBufferProducer", 0x9), GraphicBufferProducerQuery },
- { ("android.gui.IGraphicBufferProducer", 0xa), GraphicBufferProducerConnect },
- { ("android.gui.IGraphicBufferProducer", 0xe), GraphicBufferPreallocateBuffer }
- };
-
- BufferSlots = new IdPoolWithObj();
+ Flinger = new NvFlinger();
}
public long TransactParcel(ServiceCtx Context)
@@ -63,133 +36,9 @@ namespace Ryujinx.Core.OsHle.Objects.Vi
byte[] Data = AMemoryHelper.ReadBytes(Context.Memory, DataPos, (int)DataSize);
- Data = GetParcelData(Data);
-
- using (MemoryStream MS = new MemoryStream(Data))
- {
- BinaryReader Reader = new BinaryReader(MS);
-
- MS.Seek(4, SeekOrigin.Current);
-
- int StrSize = Reader.ReadInt32();
-
- string InterfaceName = Encoding.Unicode.GetString(Data, 8, StrSize * 2);
-
- if (m_Methods.TryGetValue((InterfaceName, Code), out ServiceProcessParcel ProcReq))
- {
- return ProcReq(Context, Data);
- }
- else
- {
- throw new NotImplementedException($"{InterfaceName} {Code}");
- }
- }
- }
-
- private long GraphicBufferProducerRequestBuffer(ServiceCtx Context, byte[] ParcelData)
- {
- int GbfrSize = Gbfr?.Length ?? 0;
-
- byte[] Data = new byte[GbfrSize + 4];
-
- if (Gbfr != null)
- {
- Buffer.BlockCopy(Gbfr, 0, Data, 0, GbfrSize);
- }
-
- return MakeReplyParcel(Context, Data);
- }
-
- private long GraphicBufferProducerDequeueBuffer(ServiceCtx Context, byte[] ParcelData)
- {
- //Note: It seems that the maximum number of slots is 64, because if we return
- //a Slot number > 63, it seems to cause a buffer overrun and it reads garbage.
- //Note 2: The size of each object associated with the slot is 0x30.
- int Slot = BufferSlots.GenerateId(new BufferObj());
-
- return MakeReplyParcel(Context, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
- }
-
- private long GraphicBufferProducerQueueBuffer(ServiceCtx Context, byte[] ParcelData)
- {
- return MakeReplyParcel(Context, 1280, 720, 0, 0, 0);
- }
-
- private long GraphicBufferProducerCancelBuffer(ServiceCtx Context, byte[] ParcelData)
- {
- using (MemoryStream MS = new MemoryStream(ParcelData))
- {
- BinaryReader Reader = new BinaryReader(MS);
-
- MS.Seek(0x50, SeekOrigin.Begin);
-
- int Slot = Reader.ReadInt32();
-
- BufferSlots.Delete(Slot);
-
- return MakeReplyParcel(Context, 0);
- }
- }
-
- private long GraphicBufferProducerQuery(ServiceCtx Context, byte[] ParcelData)
- {
- return MakeReplyParcel(Context, 0, 0);
- }
+ Data = Parcel.GetParcelData(Data);
- private long GraphicBufferProducerConnect(ServiceCtx Context, byte[] ParcelData)
- {
- return MakeReplyParcel(Context, 1280, 720, 0, 0, 0);
- }
-
- private long GraphicBufferPreallocateBuffer(ServiceCtx Context, byte[] ParcelData)
- {
- int GbfrSize = ParcelData.Length - 0x54;
-
- Gbfr = new byte[GbfrSize];
-
- Buffer.BlockCopy(ParcelData, 0x54, Gbfr, 0, GbfrSize);
-
- using (MemoryStream MS = new MemoryStream(ParcelData))
- {
- BinaryReader Reader = new BinaryReader(MS);
-
- MS.Seek(0xd4, SeekOrigin.Begin);
-
- int Handle = Reader.ReadInt32();
-
- HNvMap NvMap = Context.Ns.Os.Handles.GetData<HNvMap>(Handle);
-
- Context.Ns.Gpu.Renderer.FrameBufferPtr = NvMap.Address;
- }
-
- return MakeReplyParcel(Context, 0);
- }
-
- private long MakeReplyParcel(ServiceCtx Context, params int[] Ints)
- {
- using (MemoryStream MS = new MemoryStream())
- {
- BinaryWriter Writer = new BinaryWriter(MS);
-
- foreach (int Int in Ints)
- {
- Writer.Write(Int);
- }
-
- return MakeReplyParcel(Context, MS.ToArray());
- }
- }
-
- private long MakeReplyParcel(ServiceCtx Context, byte[] Data)
- {
- long ReplyPos = Context.Request.ReceiveBuff[0].Position;
- long ReplySize = Context.Request.ReceiveBuff[0].Position;
-
- byte[] Reply = MakeParcel(Data, new byte[0]);
-
- AMemoryHelper.WriteBytes(Context.Memory, ReplyPos, Reply);
-
- return 0;
+ return Flinger.ProcessParcelRequest(Context, Data, Code);
}
public long AdjustRefcount(ServiceCtx Context)
@@ -210,5 +59,18 @@ namespace Ryujinx.Core.OsHle.Objects.Vi
return 0;
}
+
+ public void Dispose()
+ {
+ Dispose(true);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ Flinger.Dispose();
+ }
+ }
}
} \ No newline at end of file