aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics/Gal/OpenGL/FrameBuffer.cs
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.Graphics/Gal/OpenGL/FrameBuffer.cs
parenteafc58c9f2e2e0c19d22f0da2a93ab5372aeef29 (diff)
Somewhat better NvFlinger (I guess) (fixes #30)
Diffstat (limited to 'Ryujinx.Graphics/Gal/OpenGL/FrameBuffer.cs')
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/FrameBuffer.cs228
1 files changed, 228 insertions, 0 deletions
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