diff options
| author | gdkchan <gab.dark.100@gmail.com> | 2018-02-23 18:48:27 -0300 |
|---|---|---|
| committer | gdkchan <gab.dark.100@gmail.com> | 2018-02-23 18:48:27 -0300 |
| commit | 2ed733b1d5addad027f48acfdd407e64b71427fc (patch) | |
| tree | 1254df3ab2bace8de561b5a3549f668fabcf4aa9 /Ryujinx.Graphics/Gal/OpenGL/FrameBuffer.cs | |
| parent | eafc58c9f2e2e0c19d22f0da2a93ab5372aeef29 (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.cs | 228 |
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 |
