aboutsummaryrefslogtreecommitdiff
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
parenteafc58c9f2e2e0c19d22f0da2a93ab5372aeef29 (diff)
Somewhat better NvFlinger (I guess) (fixes #30)
-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
-rw-r--r--Ryujinx.Graphics/Gal/EmbeddedResource.cs20
-rw-r--r--Ryujinx.Graphics/Gal/IGalRenderer.cs7
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/FbFragShader.glsl13
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/FbVtxShader.glsl26
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/FrameBuffer.cs228
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs40
-rw-r--r--Ryujinx.Graphics/Ryujinx.Graphics.csproj17
-rw-r--r--Ryujinx/Ui/GLScreen.cs280
14 files changed, 820 insertions, 444 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
diff --git a/Ryujinx.Graphics/Gal/EmbeddedResource.cs b/Ryujinx.Graphics/Gal/EmbeddedResource.cs
new file mode 100644
index 00000000..45b77da7
--- /dev/null
+++ b/Ryujinx.Graphics/Gal/EmbeddedResource.cs
@@ -0,0 +1,20 @@
+using System.IO;
+using System.Reflection;
+
+namespace Ryujinx.Graphics.Gal
+{
+ static class EmbeddedResource
+ {
+ public static string GetString(string Name)
+ {
+ Assembly Asm = typeof(EmbeddedResource).Assembly;
+
+ using (Stream ResStream = Asm.GetManifestResourceStream(Name))
+ {
+ StreamReader Reader = new StreamReader(ResStream);
+
+ return Reader.ReadToEnd();
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/IGalRenderer.cs b/Ryujinx.Graphics/Gal/IGalRenderer.cs
index 1870aca5..5854c54a 100644
--- a/Ryujinx.Graphics/Gal/IGalRenderer.cs
+++ b/Ryujinx.Graphics/Gal/IGalRenderer.cs
@@ -2,14 +2,15 @@ using System;
namespace Ryujinx.Graphics.Gal
{
- public interface IGalRenderer
+ public unsafe interface IGalRenderer
{
- long FrameBufferPtr { get; set; }
-
void QueueAction(Action ActionMthd);
void RunActions();
+ void InitializeFrameBuffer();
void Render();
+ void SetWindowSize(int Width, int Height);
+ void SetFrameBuffer(byte* Fb, int Width, int Height, float SX, float SY, float R);
void SendVertexBuffer(int Index, byte[] Buffer, int Stride, GalVertexAttrib[] Attribs);
void SendR8G8B8A8Texture(int Index, byte[] Buffer, int Width, int Height);
void BindTexture(int Index);
diff --git a/Ryujinx.Graphics/Gal/OpenGL/FbFragShader.glsl b/Ryujinx.Graphics/Gal/OpenGL/FbFragShader.glsl
new file mode 100644
index 00000000..74e33bd7
--- /dev/null
+++ b/Ryujinx.Graphics/Gal/OpenGL/FbFragShader.glsl
@@ -0,0 +1,13 @@
+#version 330 core
+
+precision highp float;
+
+uniform sampler2D tex;
+
+in vec2 tex_coord;
+
+out vec4 out_frag_color;
+
+void main(void) {
+ out_frag_color = texture(tex, tex_coord);
+} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/OpenGL/FbVtxShader.glsl b/Ryujinx.Graphics/Gal/OpenGL/FbVtxShader.glsl
new file mode 100644
index 00000000..933fa6aa
--- /dev/null
+++ b/Ryujinx.Graphics/Gal/OpenGL/FbVtxShader.glsl
@@ -0,0 +1,26 @@
+#version 330 core
+
+precision highp float;
+
+uniform vec2 window_size;
+uniform mat2 transform;
+
+layout(location = 0) in vec2 in_position;
+layout(location = 1) in vec2 in_tex_coord;
+
+out vec2 tex_coord;
+
+// Have a fixed aspect ratio, fit the image within the available space.
+vec2 get_scale_ratio(void) {
+ vec2 native_size = vec2(1280, 720);
+ vec2 ratio = vec2(
+ (window_size.y * native_size.x) / (native_size.y * window_size.x),
+ (window_size.x * native_size.y) / (native_size.x * window_size.y)
+ );
+ return min(ratio, 1);
+}
+
+void main(void) {
+ tex_coord = in_tex_coord;
+ gl_Position = vec4((transform * in_position) * get_scale_ratio(), 0, 1);
+} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/OpenGL/FrameBuffer.cs b/Ryujinx.Graphics/Gal/OpenGL/FrameBuffer.cs
new file mode 100644
index 00000000..c66c0cb7
--- /dev/null
+++ b/Ryujinx.Graphics/Gal/OpenGL/FrameBuffer.cs
@@ -0,0 +1,228 @@
+using OpenTK;
+using OpenTK.Graphics.OpenGL;
+using System;
+
+namespace Ryujinx.Graphics.Gal.OpenGL
+{
+ unsafe class FrameBuffer
+ {
+ public int WindowWidth { get; set; }
+ public int WindowHeight { get; set; }
+
+ private int VtxShaderHandle;
+ private int FragShaderHandle;
+ private int PrgShaderHandle;
+
+ private int TexHandle;
+ private int TexWidth;
+ private int TexHeight;
+
+ private int VaoHandle;
+ private int VboHandle;
+
+ private int[] Pixels;
+
+ private byte* FbPtr;
+
+ public FrameBuffer(int Width, int Height)
+ {
+ if (Width < 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(Width));
+ }
+
+ if (Height < 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(Height));
+ }
+
+ TexWidth = Width;
+ TexHeight = Height;
+
+ WindowWidth = Width;
+ WindowHeight = Height;
+
+ SetupShaders();
+ SetupTexture();
+ SetupVertex();
+ }
+
+ private void SetupShaders()
+ {
+ VtxShaderHandle = GL.CreateShader(ShaderType.VertexShader);
+ FragShaderHandle = GL.CreateShader(ShaderType.FragmentShader);
+
+ string VtxShaderSource = EmbeddedResource.GetString("GlFbVtxShader");
+ string FragShaderSource = EmbeddedResource.GetString("GlFbFragShader");
+
+ GL.ShaderSource(VtxShaderHandle, VtxShaderSource);
+ GL.ShaderSource(FragShaderHandle, FragShaderSource);
+ GL.CompileShader(VtxShaderHandle);
+ GL.CompileShader(FragShaderHandle);
+
+ PrgShaderHandle = GL.CreateProgram();
+
+ GL.AttachShader(PrgShaderHandle, VtxShaderHandle);
+ GL.AttachShader(PrgShaderHandle, FragShaderHandle);
+ GL.LinkProgram(PrgShaderHandle);
+ GL.UseProgram(PrgShaderHandle);
+
+ int TexUniformLocation = GL.GetUniformLocation(PrgShaderHandle, "tex");
+
+ GL.Uniform1(TexUniformLocation, 0);
+
+ int WindowSizeUniformLocation = GL.GetUniformLocation(PrgShaderHandle, "window_size");
+
+ GL.Uniform2(WindowSizeUniformLocation, new Vector2(1280.0f, 720.0f));
+ }
+
+ private void SetupTexture()
+ {
+ Pixels = new int[TexWidth * TexHeight];
+
+ if (TexHandle == 0)
+ {
+ TexHandle = GL.GenTexture();
+ }
+
+ GL.BindTexture(TextureTarget.Texture2D, TexHandle);
+ GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
+ GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
+ GL.TexImage2D(TextureTarget.Texture2D,
+ 0,
+ PixelInternalFormat.Rgba,
+ TexWidth,
+ TexHeight,
+ 0,
+ PixelFormat.Rgba,
+ PixelType.UnsignedByte,
+ IntPtr.Zero);
+ }
+
+ private void SetupVertex()
+ {
+ VaoHandle = GL.GenVertexArray();
+ VboHandle = GL.GenBuffer();
+
+ float[] Buffer = new float[]
+ {
+ -1, 1, 0, 0,
+ 1, 1, 1, 0,
+ -1, -1, 0, 1,
+ 1, -1, 1, 1
+ };
+
+ IntPtr Length = new IntPtr(Buffer.Length * 4);
+
+ GL.BindBuffer(BufferTarget.ArrayBuffer, VboHandle);
+ GL.BufferData(BufferTarget.ArrayBuffer, Length, Buffer, BufferUsageHint.StreamDraw);
+ GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
+
+ GL.BindVertexArray(VaoHandle);
+
+ GL.EnableVertexAttribArray(0);
+
+ GL.BindBuffer(BufferTarget.ArrayBuffer, VboHandle);
+
+ GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, false, 16, 0);
+
+ GL.EnableVertexAttribArray(1);
+
+ GL.BindBuffer(BufferTarget.ArrayBuffer, VboHandle);
+
+ GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, 16, 8);
+
+ GL.BindVertexArray(0);
+ }
+
+ public unsafe void Set(byte* Fb, int Width, int Height, Matrix2 Transform)
+ {
+ if (Fb == null)
+ {
+ throw new ArgumentNullException(nameof(Fb));
+ }
+
+ if (Width < 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(Width));
+ }
+
+ if (Height < 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(Height));
+ }
+
+ FbPtr = Fb;
+
+ if (Width != TexWidth ||
+ Height != TexHeight)
+ {
+ TexWidth = Width;
+ TexHeight = Height;
+
+ SetupTexture();
+ }
+
+ GL.UseProgram(PrgShaderHandle);
+
+ int TransformUniformLocation = GL.GetUniformLocation(PrgShaderHandle, "transform");
+
+ GL.UniformMatrix2(TransformUniformLocation, false, ref Transform);
+
+ int WindowSizeUniformLocation = GL.GetUniformLocation(PrgShaderHandle, "window_size");
+
+ GL.Uniform2(WindowSizeUniformLocation, new Vector2(WindowWidth, WindowHeight));
+ }
+
+ public void Render()
+ {
+ if (FbPtr == null)
+ {
+ return;
+ }
+
+ for (int Y = 0; Y < TexHeight; Y++)
+ for (int X = 0; X < TexWidth; X++)
+ {
+ Pixels[X + Y * TexWidth] = *((int*)(FbPtr + GetSwizzleOffset(X, Y)));
+ }
+
+ GL.BindTexture(TextureTarget.Texture2D, TexHandle);
+ GL.TexSubImage2D(TextureTarget.Texture2D,
+ 0,
+ 0,
+ 0,
+ TexWidth,
+ TexHeight,
+ PixelFormat.Rgba,
+ PixelType.UnsignedByte,
+ Pixels);
+
+ GL.ActiveTexture(TextureUnit.Texture0);
+
+ GL.BindVertexArray(VaoHandle);
+
+ GL.UseProgram(PrgShaderHandle);
+
+ GL.DrawArrays(PrimitiveType.TriangleStrip, 0, 4);
+ }
+
+ private int GetSwizzleOffset(int X, int Y)
+ {
+ int Pos;
+
+ Pos = (Y & 0x7f) >> 4;
+ Pos += (X >> 4) << 3;
+ Pos += (Y >> 7) * ((TexWidth >> 4) << 3);
+ Pos *= 1024;
+ Pos += ((Y & 0xf) >> 3) << 9;
+ Pos += ((X & 0xf) >> 3) << 8;
+ Pos += ((Y & 0x7) >> 1) << 6;
+ Pos += ((X & 0x7) >> 2) << 5;
+ Pos += ((Y & 0x1) >> 0) << 4;
+ Pos += ((X & 0x3) >> 0) << 2;
+
+ return Pos;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs b/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs
index 7429569b..6bf17d09 100644
--- a/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs
+++ b/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs
@@ -1,7 +1,9 @@
+using OpenTK;
using OpenTK.Graphics.OpenGL;
using System;
using System.Collections.Generic;
+
namespace Ryujinx.Graphics.Gal.OpenGL
{
public class OpenGLRenderer : IGalRenderer
@@ -25,6 +27,8 @@ namespace Ryujinx.Graphics.Gal.OpenGL
private Queue<Action> ActionsQueue;
+ private FrameBuffer FbRenderer;
+
public long FrameBufferPtr { get; set; }
public OpenGLRenderer()
@@ -36,6 +40,11 @@ namespace Ryujinx.Graphics.Gal.OpenGL
ActionsQueue = new Queue<Action>();
}
+ public void InitializeFrameBuffer()
+ {
+ FbRenderer = new FrameBuffer(1280, 720);
+ }
+
public void QueueAction(Action ActionMthd)
{
ActionsQueue.Enqueue(ActionMthd);
@@ -43,14 +52,18 @@ namespace Ryujinx.Graphics.Gal.OpenGL
public void RunActions()
{
- while (ActionsQueue.Count > 0)
+ int Count = ActionsQueue.Count;
+
+ while (Count-- > 0)
{
ActionsQueue.Dequeue()();
}
- }
+ }
public void Render()
{
+ FbRenderer.Render();
+
for (int Index = 0; Index < VertexBuffers.Count; Index++)
{
VertexBuffer Vb = VertexBuffers[Index];
@@ -62,7 +75,28 @@ namespace Ryujinx.Graphics.Gal.OpenGL
GL.DrawArrays(PrimitiveType.TriangleStrip, 0, Vb.PrimCount);
}
}
-
+ }
+
+ public void SetWindowSize(int Width, int Height)
+ {
+ FbRenderer.WindowWidth = Width;
+ FbRenderer.WindowHeight = Height;
+ }
+
+ public unsafe void SetFrameBuffer(
+ byte* Fb,
+ int Width,
+ int Height,
+ float ScaleX,
+ float ScaleY,
+ float Rotate)
+ {
+ Matrix2 Transform;
+
+ Transform = Matrix2.CreateScale(ScaleX, ScaleY);
+ Transform *= Matrix2.CreateRotation(Rotate);
+
+ FbRenderer.Set(Fb, Width, Height, Transform);
}
public void SendVertexBuffer(int Index, byte[] Buffer, int Stride, GalVertexAttrib[] Attribs)
diff --git a/Ryujinx.Graphics/Ryujinx.Graphics.csproj b/Ryujinx.Graphics/Ryujinx.Graphics.csproj
index 657beb82..01bf41f8 100644
--- a/Ryujinx.Graphics/Ryujinx.Graphics.csproj
+++ b/Ryujinx.Graphics/Ryujinx.Graphics.csproj
@@ -4,6 +4,14 @@
<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ </PropertyGroup>
+
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ </PropertyGroup>
+
<ItemGroup>
<PackageReference Include="OpenTK.NETCore" Version="1.1.2749.6433" />
</ItemGroup>
@@ -12,4 +20,13 @@
<ProjectReference Include="..\ChocolArm64\ChocolArm64.csproj" />
</ItemGroup>
+ <ItemGroup>
+ <EmbeddedResource Include="Gal\OpenGL\FbVtxShader.glsl">
+ <LogicalName>GlFbVtxShader</LogicalName>
+ </EmbeddedResource>
+ <EmbeddedResource Include="Gal\OpenGL\FbFragShader.glsl">
+ <LogicalName>GlFbFragShader</LogicalName>
+ </EmbeddedResource>
+ </ItemGroup>
+
</Project>
diff --git a/Ryujinx/Ui/GLScreen.cs b/Ryujinx/Ui/GLScreen.cs
index 325e38cd..3219303e 100644
--- a/Ryujinx/Ui/GLScreen.cs
+++ b/Ryujinx/Ui/GLScreen.cs
@@ -1,7 +1,3 @@
-// This code was written for the OpenTK library and has been released
-// to the Public Domain.
-// It is provided "as is" without express or implied warranty of any kind.
-
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
@@ -13,281 +9,25 @@ namespace Ryujinx
{
public class GLScreen : GameWindow
{
- class ScreenTexture : IDisposable
- {
- private Switch Ns;
- private IGalRenderer Renderer;
-
- private int Width;
- private int Height;
- private int TexHandle;
-
- private int[] Pixels;
-
- public ScreenTexture(Switch Ns, IGalRenderer Renderer, int Width, int Height)
- {
- this.Ns = Ns;
- this.Renderer = Renderer;
- this.Width = Width;
- this.Height = Height;
-
- Pixels = new int[Width * Height];
-
- TexHandle = GL.GenTexture();
-
- GL.BindTexture(TextureTarget.Texture2D, TexHandle);
- GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
- GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
- GL.TexImage2D(TextureTarget.Texture2D,
- 0,
- PixelInternalFormat.Rgba,
- Width,
- Height,
- 0,
- PixelFormat.Rgba,
- PixelType.UnsignedByte,
- IntPtr.Zero);
- }
-
- public int Texture
- {
- get
- {
- UploadBitmap();
-
- return TexHandle;
- }
- }
-
- unsafe void UploadBitmap()
- {
- int FbSize = Width * Height * 4;
-
- if (Renderer.FrameBufferPtr == 0 || Renderer.FrameBufferPtr + FbSize > uint.MaxValue)
- {
- return;
- }
-
- byte* SrcPtr = (byte*)Ns.Ram + (uint)Renderer.FrameBufferPtr;
-
- for (int Y = 0; Y < Height; Y++)
- {
- for (int X = 0; X < Width; X++)
- {
- int SrcOffs = GetSwizzleOffset(X, Y, 4);
-
- Pixels[X + Y * Width] = *((int*)(SrcPtr + SrcOffs));
- }
- }
-
- GL.BindTexture(TextureTarget.Texture2D, TexHandle);
- GL.TexSubImage2D(TextureTarget.Texture2D,
- 0,
- 0,
- 0,
- Width,
- Height,
- PixelFormat.Rgba,
- PixelType.UnsignedByte,
- Pixels);
- }
-
- private int GetSwizzleOffset(int X, int Y, int Bpp)
- {
- int Pos;
-
- Pos = (Y & 0x7f) >> 4;
- Pos += (X >> 4) << 3;
- Pos += (Y >> 7) * ((Width >> 4) << 3);
- Pos *= 1024;
- Pos += ((Y & 0xf) >> 3) << 9;
- Pos += ((X & 0xf) >> 3) << 8;
- Pos += ((Y & 0x7) >> 1) << 6;
- Pos += ((X & 0x7) >> 2) << 5;
- Pos += ((Y & 0x1) >> 0) << 4;
- Pos += ((X & 0x3) >> 0) << 2;
-
- return Pos;
- }
-
- private bool disposed;
-
- public void Dispose()
- {
- Dispose(true);
-
- GC.SuppressFinalize(this);
- }
-
- void Dispose(bool disposing)
- {
- if (!disposed)
- {
- if (disposing)
- {
- GL.DeleteTexture(TexHandle);
- }
-
- disposed = true;
- }
- }
- }
-
- private string VtxShaderSource = @"
-#version 330 core
-
-precision highp float;
-
-uniform vec2 window_size;
-
-layout(location = 0) in vec3 in_position;
-layout(location = 1) in vec4 in_color;
-layout(location = 2) in vec2 in_tex_coord;
-
-out vec4 color;
-out vec2 tex_coord;
-
-// Have a fixed aspect ratio, fit the image within the available space.
-vec3 get_scale_ratio() {
- vec2 native_size = vec2(1280, 720);
- vec2 ratio = vec2(
- (window_size.y * native_size.x) / (native_size.y * window_size.x),
- (window_size.x * native_size.y) / (native_size.x * window_size.y)
- );
- return vec3(min(ratio, vec2(1, 1)) * vec2(1, -1), 1);
-}
-
-void main(void) {
- color = in_color;
- tex_coord = in_tex_coord;
- gl_Position = vec4(in_position * get_scale_ratio(), 1);
-}";
-
- private string FragShaderSource = @"
-#version 330 core
-
-precision highp float;
-
-uniform sampler2D tex;
-
-in vec4 color;
-in vec2 tex_coord;
-out vec4 out_frag_color;
-
-void main(void) {
- out_frag_color = vec4(texture(tex, tex_coord).rgb, color.a);
-}";
-
- private int VtxShaderHandle,
- FragShaderHandle,
- PrgShaderHandle;
-
- private int WindowSizeUniformLocation;
-
- private int VaoHandle;
- private int VboHandle;
-
private Switch Ns;
private IGalRenderer Renderer;
- private ScreenTexture ScreenTex;
-
public GLScreen(Switch Ns, IGalRenderer Renderer)
: base(1280, 720,
new GraphicsMode(), "Ryujinx", 0,
DisplayDevice.Default, 3, 3,
GraphicsContextFlags.ForwardCompatible)
{
- this.Ns = Ns;
+ this.Ns = Ns;
this.Renderer = Renderer;
-
- ScreenTex = new ScreenTexture(Ns, Renderer, 1280, 720);
}
protected override void OnLoad(EventArgs e)
{
VSync = VSyncMode.On;
- CreateShaders();
- CreateVbo();
-
- GL.Enable(EnableCap.Blend);
- GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
- }
-
- protected override void OnUnload(EventArgs e)
- {
- ScreenTex.Dispose();
-
- GL.DeleteVertexArray(VaoHandle);
- GL.DeleteBuffer(VboHandle);
- }
-
- private void CreateVbo()
- {
- VaoHandle = GL.GenVertexArray();
- VboHandle = GL.GenBuffer();
-
- uint[] Buffer = new uint[]
- {
- 0xbf800000, 0x3f800000, 0x00000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000,
- 0x3f800000, 0x3f800000, 0x00000000, 0xffffffff, 0x00000000, 0x3f800000, 0x00000000,
- 0xbf800000, 0xbf800000, 0x00000000, 0xffffffff, 0x00000000, 0x00000000, 0x3f800000,
- 0x3f800000, 0xbf800000, 0x00000000, 0xffffffff, 0x00000000, 0x3f800000, 0x3f800000
- };
-
- IntPtr Length = new IntPtr(Buffer.Length * 4);
-
- GL.BindBuffer(BufferTarget.ArrayBuffer, VboHandle);
- GL.BufferData(BufferTarget.ArrayBuffer, Length, Buffer, BufferUsageHint.StreamDraw);
- GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
-
- GL.BindVertexArray(VaoHandle);
-
- GL.EnableVertexAttribArray(0);
-
- GL.BindBuffer(BufferTarget.ArrayBuffer, VboHandle);
-
- GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, 28, 0);
-
- GL.EnableVertexAttribArray(1);
-
- GL.BindBuffer(BufferTarget.ArrayBuffer, VboHandle);
-
- GL.VertexAttribPointer(1, 4, VertexAttribPointerType.UnsignedByte, false, 28, 12);
-
- GL.EnableVertexAttribArray(2);
-
- GL.BindBuffer(BufferTarget.ArrayBuffer, VboHandle);
-
- GL.VertexAttribPointer(2, 2, VertexAttribPointerType.Float, false, 28, 20);
-
- GL.BindVertexArray(0);
- }
-
- private void CreateShaders()
- {
- VtxShaderHandle = GL.CreateShader(ShaderType.VertexShader);
- FragShaderHandle = GL.CreateShader(ShaderType.FragmentShader);
-
- GL.ShaderSource(VtxShaderHandle, VtxShaderSource);
- GL.ShaderSource(FragShaderHandle, FragShaderSource);
- GL.CompileShader(VtxShaderHandle);
- GL.CompileShader(FragShaderHandle);
-
- PrgShaderHandle = GL.CreateProgram();
-
- GL.AttachShader(PrgShaderHandle, VtxShaderHandle);
- GL.AttachShader(PrgShaderHandle, FragShaderHandle);
- GL.LinkProgram(PrgShaderHandle);
- GL.UseProgram(PrgShaderHandle);
-
- int TexLocation = GL.GetUniformLocation(PrgShaderHandle, "tex");
- GL.Uniform1(TexLocation, 0);
-
- WindowSizeUniformLocation = GL.GetUniformLocation(PrgShaderHandle, "window_size");
- GL.Uniform2(WindowSizeUniformLocation, new Vector2(1280.0f, 720.0f));
+ Renderer.InitializeFrameBuffer();
}
protected override void OnUpdateFrame(FrameEventArgs e)
@@ -382,12 +122,7 @@ void main(void) {
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
- RenderFb();
-
- GL.UseProgram(PrgShaderHandle);
-
Renderer.RunActions();
- Renderer.BindTexture(0);
Renderer.Render();
SwapBuffers();
@@ -395,16 +130,7 @@ void main(void) {
protected override void OnResize(EventArgs e)
{
- GL.UseProgram(PrgShaderHandle);
- GL.Uniform2(WindowSizeUniformLocation, new Vector2(Width, Height));
- }
-
- void RenderFb()
- {
- GL.ActiveTexture(TextureUnit.Texture0);
- GL.BindTexture(TextureTarget.Texture2D, ScreenTex.Texture);
- GL.BindVertexArray(VaoHandle);
- GL.DrawArrays(PrimitiveType.TriangleStrip, 0, 4);
+ Renderer.SetWindowSize(Width, Height);
}
}
} \ No newline at end of file