From 1344a47c774ab2b7491c59e363e04a499fa432f3 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Mon, 23 Jul 2018 11:21:05 -0300 Subject: [PATCH] Blit framebuffer without shaders (#229) * Blit framebuffer without shaders * De-hardcode native size values * Adapt to dehardcoded framebuffers and address feedback * Remove framebuffer rebinding --- Ryujinx.Graphics/Gal/IGalFrameBuffer.cs | 2 +- Ryujinx.Graphics/Gal/OpenGL/FbFragShader.glsl | 13 - Ryujinx.Graphics/Gal/OpenGL/FbVtxShader.glsl | 28 -- Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs | 284 ++++++------------ Ryujinx.Graphics/Ryujinx.Graphics.csproj | 9 - Ryujinx.HLE/OsHle/Services/Vi/NvFlinger.cs | 53 +--- 6 files changed, 101 insertions(+), 288 deletions(-) delete mode 100644 Ryujinx.Graphics/Gal/OpenGL/FbFragShader.glsl delete mode 100644 Ryujinx.Graphics/Gal/OpenGL/FbVtxShader.glsl diff --git a/Ryujinx.Graphics/Gal/IGalFrameBuffer.cs b/Ryujinx.Graphics/Gal/IGalFrameBuffer.cs index 1f62bdb37..c0287ef8b 100644 --- a/Ryujinx.Graphics/Gal/IGalFrameBuffer.cs +++ b/Ryujinx.Graphics/Gal/IGalFrameBuffer.cs @@ -14,7 +14,7 @@ namespace Ryujinx.Graphics.Gal void Set(byte[] Data, int Width, int Height); - void SetTransform(float SX, float SY, float Rotate, float TX, float TY); + void SetTransform(bool FlipX, bool FlipY, int Top, int Left, int Right, int Bottom); void SetWindowSize(int Width, int Height); diff --git a/Ryujinx.Graphics/Gal/OpenGL/FbFragShader.glsl b/Ryujinx.Graphics/Gal/OpenGL/FbFragShader.glsl deleted file mode 100644 index 74e33bd7c..000000000 --- a/Ryujinx.Graphics/Gal/OpenGL/FbFragShader.glsl +++ /dev/null @@ -1,13 +0,0 @@ -#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 deleted file mode 100644 index 35d560c09..000000000 --- a/Ryujinx.Graphics/Gal/OpenGL/FbVtxShader.glsl +++ /dev/null @@ -1,28 +0,0 @@ -#version 330 core - -precision highp float; - -uniform mat2 transform; -uniform vec2 window_size; -uniform vec2 offset; - -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; - vec2 t_pos = (transform * in_position) + offset; - gl_Position = vec4(t_pos * get_scale_ratio(), 0, 1); -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs index cd52762c7..30a3de64a 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs @@ -32,48 +32,45 @@ namespace Ryujinx.Graphics.Gal.OpenGL public int RbHandle { get; private set; } public int TexHandle { get; private set; } - public FrameBuffer(int Width, int Height) + public FrameBuffer(int Width, int Height, bool HasRenderBuffer) { this.Width = Width; this.Height = Height; Handle = GL.GenFramebuffer(); - RbHandle = GL.GenRenderbuffer(); TexHandle = GL.GenTexture(); + + if (HasRenderBuffer) + { + RbHandle = GL.GenRenderbuffer(); + } } } - private struct ShaderProgram - { - public int Handle; - public int VpHandle; - public int FpHandle; - } + private const int NativeWidth = 1280; + private const int NativeHeight = 720; private Dictionary Fbs; - private ShaderProgram Shader; - private Rect Viewport; private Rect Window; - private bool IsInitialized; + private FrameBuffer CurrFb; + private FrameBuffer CurrReadFb; - private int RawFbTexWidth; - private int RawFbTexHeight; - private int RawFbTexHandle; + private FrameBuffer RawFb; - private int CurrFbHandle; - private int CurrTexHandle; + private bool FlipX; + private bool FlipY; - private int VaoHandle; - private int VboHandle; + private int CropTop; + private int CropLeft; + private int CropRight; + private int CropBottom; public OGLFrameBuffer() { Fbs = new Dictionary(); - - Shader = new ShaderProgram(); } public void Create(long Key, int Width, int Height) @@ -92,7 +89,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL return; } - Fb = new FrameBuffer(Width, Height); + Fb = new FrameBuffer(Width, Height, true); SetupTexture(Fb.TexHandle, Width, Height); @@ -129,7 +126,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL { GL.BindFramebuffer(FramebufferTarget.Framebuffer, Fb.Handle); - CurrFbHandle = Fb.Handle; + CurrFb = Fb; } } @@ -147,75 +144,50 @@ namespace Ryujinx.Graphics.Gal.OpenGL { if (Fbs.TryGetValue(Key, out FrameBuffer Fb)) { - CurrTexHandle = Fb.TexHandle; + CurrReadFb = Fb; } } public void Set(byte[] Data, int Width, int Height) { - if (RawFbTexHandle == 0) + if (RawFb == null) { - RawFbTexHandle = GL.GenTexture(); + CreateRawFb(Width, Height); } - if (RawFbTexWidth != Width || - RawFbTexHeight != Height) + if (RawFb.Width != Width || + RawFb.Height != Height) { - SetupTexture(RawFbTexHandle, Width, Height); + SetupTexture(RawFb.TexHandle, Width, Height); - RawFbTexWidth = Width; - RawFbTexHeight = Height; + RawFb.Width = Width; + RawFb.Height = Height; } GL.ActiveTexture(TextureUnit.Texture0); - GL.BindTexture(TextureTarget.Texture2D, RawFbTexHandle); + GL.BindTexture(TextureTarget.Texture2D, RawFb.TexHandle); (PixelFormat Format, PixelType Type) = OGLEnumConverter.GetTextureFormat(GalTextureFormat.A8B8G8R8); GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, Width, Height, Format, Type, Data); - CurrTexHandle = RawFbTexHandle; + CurrReadFb = RawFb; } - public void SetTransform(float SX, float SY, float Rotate, float TX, float TY) + public void SetTransform(bool FlipX, bool FlipY, int Top, int Left, int Right, int Bottom) { - EnsureInitialized(); + this.FlipX = FlipX; + this.FlipY = FlipY; - Matrix2 Transform; - - Transform = Matrix2.CreateScale(SX, SY); - Transform *= Matrix2.CreateRotation(Rotate); - - Vector2 Offs = new Vector2(TX, TY); - - int CurrentProgram = GL.GetInteger(GetPName.CurrentProgram); - - GL.UseProgram(Shader.Handle); - - int TransformUniformLocation = GL.GetUniformLocation(Shader.Handle, "transform"); - - GL.UniformMatrix2(TransformUniformLocation, false, ref Transform); - - int OffsetUniformLocation = GL.GetUniformLocation(Shader.Handle, "offset"); - - GL.Uniform2(OffsetUniformLocation, ref Offs); - - GL.UseProgram(CurrentProgram); + CropTop = Top; + CropLeft = Left; + CropRight = Right; + CropBottom = Bottom; } public void SetWindowSize(int Width, int Height) { - int CurrentProgram = GL.GetInteger(GetPName.CurrentProgram); - - GL.UseProgram(Shader.Handle); - - int WindowSizeUniformLocation = GL.GetUniformLocation(Shader.Handle, "window_size"); - - GL.Uniform2(WindowSizeUniformLocation, new Vector2(Width, Height)); - - GL.UseProgram(CurrentProgram); - Window = new Rect(0, 0, Width, Height); } @@ -237,72 +209,59 @@ namespace Ryujinx.Graphics.Gal.OpenGL public void Render() { - if (CurrTexHandle != 0) + if (CurrReadFb != null) { - EnsureInitialized(); + int SrcX0, SrcX1, SrcY0, SrcY1; - //bool CullFaceEnable = GL.IsEnabled(EnableCap.CullFace); + if (CropLeft == 0 && CropRight == 0) + { + SrcX0 = 0; + SrcX1 = CurrReadFb.Width; + } + else + { + SrcX0 = CropLeft; + SrcX1 = CropRight; + } - bool DepthTestEnable = GL.IsEnabled(EnableCap.DepthTest); + if (CropTop == 0 && CropBottom == 0) + { + SrcY0 = 0; + SrcY1 = CurrReadFb.Height; + } + else + { + SrcY0 = CropTop; + SrcY1 = CropBottom; + } - bool StencilTestEnable = GL.IsEnabled(EnableCap.StencilTest); + float RatioX = MathF.Min(1f, (Window.Height * (float)NativeWidth) / ((float)NativeHeight * Window.Width)); + float RatioY = MathF.Min(1f, (Window.Width * (float)NativeHeight) / ((float)NativeWidth * Window.Height)); - bool AlphaBlendEnable = GL.IsEnabled(EnableCap.Blend); + int DstWidth = (int)(Window.Width * RatioX); + int DstHeight = (int)(Window.Height * RatioY); - //GL.Disable(EnableCap.CullFace); + int DstPaddingX = (Window.Width - DstWidth) / 2; + int DstPaddingY = (Window.Height - DstHeight) / 2; - GL.Disable(EnableCap.DepthTest); + int DstX0 = FlipX ? Window.Width - DstPaddingX : DstPaddingX; + int DstX1 = FlipX ? DstPaddingX : Window.Width - DstPaddingX; - GL.Disable(EnableCap.StencilTest); - - GL.Disable(EnableCap.Blend); - - GL.ActiveTexture(TextureUnit.Texture0); - - GL.BindTexture(TextureTarget.Texture2D, CurrTexHandle); - - int CurrentProgram = GL.GetInteger(GetPName.CurrentProgram); + int DstY0 = FlipY ? DstPaddingY : Window.Height - DstPaddingY; + int DstY1 = FlipY ? Window.Height - DstPaddingY : DstPaddingY; GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0); - SetViewport(Window); + GL.Viewport(0, 0, Window.Width, Window.Height); - GL.Clear( - ClearBufferMask.ColorBufferBit | - ClearBufferMask.DepthBufferBit); + GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, CurrReadFb.Handle); - GL.BindVertexArray(VaoHandle); + GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); - GL.UseProgram(Shader.Handle); - - GL.DrawArrays(PrimitiveType.TriangleStrip, 0, 4); - - //Restore the original state. - GL.BindFramebuffer(FramebufferTarget.Framebuffer, CurrFbHandle); - - GL.UseProgram(CurrentProgram); - - //if (CullFaceEnable) - //{ - // GL.Enable(EnableCap.CullFace); - //} - - if (DepthTestEnable) - { - GL.Enable(EnableCap.DepthTest); - } - - if (StencilTestEnable) - { - GL.Enable(EnableCap.StencilTest); - } - - if (AlphaBlendEnable) - { - GL.Enable(EnableCap.Blend); - } - - SetViewport(Viewport); + GL.BlitFramebuffer( + SrcX0, SrcY0, SrcX1, SrcY1, + DstX0, DstY0, DstX1, DstY1, + ClearBufferMask.ColorBufferBit, BlitFramebufferFilter.Linear); } } @@ -354,8 +313,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL Data); Callback(Data); - - GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, CurrFbHandle); } } @@ -390,86 +347,29 @@ namespace Ryujinx.Graphics.Gal.OpenGL } } - private void EnsureInitialized() + private void CreateRawFb(int Width, int Height) { - if (!IsInitialized) + if (RawFb == null) { - IsInitialized = true; + RawFb = new FrameBuffer(Width, Height, false); - SetupShader(); - SetupVertex(); + SetupTexture(RawFb.TexHandle, Width, Height); + + RawFb.Width = Width; + RawFb.Height = Height; + + GL.BindFramebuffer(FramebufferTarget.Framebuffer, RawFb.Handle); + + GL.FramebufferTexture( + FramebufferTarget.Framebuffer, + FramebufferAttachment.ColorAttachment0, + RawFb.TexHandle, + 0); + + GL.Viewport(0, 0, Width, Height); } } - private void SetupShader() - { - Shader.VpHandle = GL.CreateShader(ShaderType.VertexShader); - Shader.FpHandle = GL.CreateShader(ShaderType.FragmentShader); - - string VpSource = EmbeddedResource.GetString("GlFbVtxShader"); - string FpSource = EmbeddedResource.GetString("GlFbFragShader"); - - GL.ShaderSource(Shader.VpHandle, VpSource); - GL.ShaderSource(Shader.FpHandle, FpSource); - GL.CompileShader(Shader.VpHandle); - GL.CompileShader(Shader.FpHandle); - - Shader.Handle = GL.CreateProgram(); - - GL.AttachShader(Shader.Handle, Shader.VpHandle); - GL.AttachShader(Shader.Handle, Shader.FpHandle); - GL.LinkProgram(Shader.Handle); - GL.UseProgram(Shader.Handle); - - Matrix2 Transform = Matrix2.Identity; - - int TexUniformLocation = GL.GetUniformLocation(Shader.Handle, "tex"); - - GL.Uniform1(TexUniformLocation, 0); - - int WindowSizeUniformLocation = GL.GetUniformLocation(Shader.Handle, "window_size"); - - GL.Uniform2(WindowSizeUniformLocation, new Vector2(1280.0f, 720.0f)); - - int TransformUniformLocation = GL.GetUniformLocation(Shader.Handle, "transform"); - - GL.UniformMatrix2(TransformUniformLocation, false, ref Transform); - } - - 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); - } - private void SetupTexture(int Handle, int Width, int Height) { GL.BindTexture(TextureTarget.Texture2D, Handle); diff --git a/Ryujinx.Graphics/Ryujinx.Graphics.csproj b/Ryujinx.Graphics/Ryujinx.Graphics.csproj index d0fad1076..7d86cbe13 100644 --- a/Ryujinx.Graphics/Ryujinx.Graphics.csproj +++ b/Ryujinx.Graphics/Ryujinx.Graphics.csproj @@ -21,13 +21,4 @@ - - - GlFbVtxShader - - - GlFbFragShader - - - diff --git a/Ryujinx.HLE/OsHle/Services/Vi/NvFlinger.cs b/Ryujinx.HLE/OsHle/Services/Vi/NvFlinger.cs index 5307127be..41f2916f4 100644 --- a/Ryujinx.HLE/OsHle/Services/Vi/NvFlinger.cs +++ b/Ryujinx.HLE/OsHle/Services/Vi/NvFlinger.cs @@ -293,54 +293,17 @@ namespace Ryujinx.HLE.OsHle.Services.Android Rect Crop = BufferQueue[Slot].Crop; - int RealWidth = FbWidth; - int RealHeight = FbHeight; + bool FlipX = BufferQueue[Slot].Transform.HasFlag(HalTransform.FlipX); + bool FlipY = BufferQueue[Slot].Transform.HasFlag(HalTransform.FlipY); - float XSign = BufferQueue[Slot].Transform.HasFlag(HalTransform.FlipX) ? -1 : 1; - float YSign = BufferQueue[Slot].Transform.HasFlag(HalTransform.FlipY) ? -1 : 1; + //Rotation is being ignored - float ScaleX = 1; - float ScaleY = 1; + int Top = Crop.Top; + int Left = Crop.Left; + int Right = Crop.Right; + int Bottom = Crop.Bottom; - float OffsX = 0; - float OffsY = 0; - - if (Crop.Right != 0 && - Crop.Bottom != 0) - { - //Who knows if this is right, I was never good with math... - RealWidth = Crop.Right - Crop.Left; - RealHeight = Crop.Bottom - Crop.Top; - - if (BufferQueue[Slot].Transform.HasFlag(HalTransform.Rotate90)) - { - ScaleY = (float)FbHeight / RealHeight; - ScaleX = (float)FbWidth / RealWidth; - - OffsY = ((-(float)Crop.Left / Crop.Right) + ScaleX - 1) * -XSign; - OffsX = ((-(float)Crop.Top / Crop.Bottom) + ScaleY - 1) * -YSign; - } - else - { - ScaleX = (float)FbWidth / RealWidth; - ScaleY = (float)FbHeight / RealHeight; - - OffsX = ((-(float)Crop.Left / Crop.Right) + ScaleX - 1) * XSign; - OffsY = ((-(float)Crop.Top / Crop.Bottom) + ScaleY - 1) * -YSign; - } - } - - ScaleX *= XSign; - ScaleY *= YSign; - - float Rotate = 0; - - if (BufferQueue[Slot].Transform.HasFlag(HalTransform.Rotate90)) - { - Rotate = -MathF.PI * 0.5f; - } - - Renderer.QueueAction(() => Renderer.FrameBuffer.SetTransform(ScaleX, ScaleY, Rotate, OffsX, OffsY)); + Renderer.QueueAction(() => Renderer.FrameBuffer.SetTransform(FlipX, FlipY, Top, Left, Right, Bottom)); //TODO: Support double buffering here aswell, it is broken for GPU //frame buffers because it seems to be completely out of sync.