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 | |
| parent | eafc58c9f2e2e0c19d22f0da2a93ab5372aeef29 (diff) | |
Somewhat better NvFlinger (I guess) (fixes #30)
Diffstat (limited to 'Ryujinx.Graphics')
| -rw-r--r-- | Ryujinx.Graphics/Gal/EmbeddedResource.cs | 20 | ||||
| -rw-r--r-- | Ryujinx.Graphics/Gal/IGalRenderer.cs | 7 | ||||
| -rw-r--r-- | Ryujinx.Graphics/Gal/OpenGL/FbFragShader.glsl | 13 | ||||
| -rw-r--r-- | Ryujinx.Graphics/Gal/OpenGL/FbVtxShader.glsl | 26 | ||||
| -rw-r--r-- | Ryujinx.Graphics/Gal/OpenGL/FrameBuffer.cs | 228 | ||||
| -rw-r--r-- | Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs | 40 | ||||
| -rw-r--r-- | Ryujinx.Graphics/Ryujinx.Graphics.csproj | 17 |
7 files changed, 345 insertions, 6 deletions
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> |
