aboutsummaryrefslogtreecommitdiff
path: root/GLScreen.cs
diff options
context:
space:
mode:
Diffstat (limited to 'GLScreen.cs')
-rw-r--r--GLScreen.cs366
1 files changed, 366 insertions, 0 deletions
diff --git a/GLScreen.cs b/GLScreen.cs
new file mode 100644
index 00000000..d757db8f
--- /dev/null
+++ b/GLScreen.cs
@@ -0,0 +1,366 @@
+// 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 Gal;
+using OpenTK;
+using OpenTK.Graphics;
+using OpenTK.Graphics.OpenGL;
+using System;
+
+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()
+ {
+ if (Renderer.FrameBufferPtr == 0)
+ {
+ return;
+ }
+
+ byte* SrcPtr = (byte*)IntPtr.Add(Ns.Ram, (int)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;
+
+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;
+
+void main(void) {
+ color = in_color;
+ tex_coord = in_tex_coord;
+ gl_Position = vec4((in_position + vec3(-960, 270, 0)) / vec3(1920, 270, 1), 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 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.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[]
+ {
+ 0xc4700000, 0x80000000, 0x00000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000,
+ 0x45340000, 0x80000000, 0x00000000, 0xffffffff, 0x00000000, 0x3f800000, 0x00000000,
+ 0xc4700000, 0xc4070000, 0x00000000, 0xffffffff, 0x00000000, 0x00000000, 0x3f800000,
+ 0x45340000, 0xc4070000, 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);
+ }
+
+ protected override void OnUpdateFrame(FrameEventArgs e)
+ {
+ unsafe
+ {
+ byte* Ptr = (byte*)IntPtr.Add(Ns.Ram, (int)Ns.Os.HidOffset);
+
+ int State = 0;
+
+ if (Keyboard[OpenTK.Input.Key.Up])
+ {
+ State |= 0x2000;
+ }
+
+ if (Keyboard[OpenTK.Input.Key.Down])
+ {
+ State |= 0x8000;
+ }
+
+ if (Keyboard[OpenTK.Input.Key.Left])
+ {
+ State |= 0x1000;
+ }
+
+ if (Keyboard[OpenTK.Input.Key.Right])
+ {
+ State |= 0x4000;
+ }
+
+ if (Keyboard[OpenTK.Input.Key.A])
+ {
+ State |= 0x1;
+ }
+
+ if (Keyboard[OpenTK.Input.Key.S])
+ {
+ State |= 0x2;
+ }
+
+ if (Keyboard[OpenTK.Input.Key.Z])
+ {
+ State |= 0x4;
+ }
+
+ if (Keyboard[OpenTK.Input.Key.X])
+ {
+ State |= 0x8;
+ }
+
+ if (Keyboard[OpenTK.Input.Key.Enter])
+ {
+ State |= 0x400;
+ }
+
+ if (Keyboard[OpenTK.Input.Key.Tab])
+ {
+ State |= 0x800;
+ }
+
+ *((int*)(Ptr + 0xae38)) = (int)State;
+ }
+
+ if (Keyboard[OpenTK.Input.Key.Escape])
+ {
+ this.Exit();
+ }
+ }
+
+ protected override void OnRenderFrame(FrameEventArgs e)
+ {
+ GL.Viewport(0, 0, 1280, 720);
+
+ GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
+
+ RenderFb();
+
+ GL.UseProgram(PrgShaderHandle);
+
+ Renderer.RunActions();
+ Renderer.BindTexture(0);
+ Renderer.Render();
+
+ SwapBuffers();
+ }
+
+ void RenderFb()
+ {
+ GL.ActiveTexture(TextureUnit.Texture0);
+ GL.BindTexture(TextureTarget.Texture2D, ScreenTex.Texture);
+ GL.BindVertexArray(VaoHandle);
+ GL.DrawArrays(PrimitiveType.TriangleStrip, 0, 4);
+ }
+ }
+} \ No newline at end of file