diff --git a/Ryujinx.Graphics/Gal/GalPipelineState.cs b/Ryujinx.Graphics/Gal/GalPipelineState.cs index 2be5f4517a..a23b69093c 100644 --- a/Ryujinx.Graphics/Gal/GalPipelineState.cs +++ b/Ryujinx.Graphics/Gal/GalPipelineState.cs @@ -19,6 +19,9 @@ public GalVertexBinding[] VertexBindings; + public float FlipX; + public float FlipY; + public GalFrontFace FrontFace; public bool CullFaceEnabled; diff --git a/Ryujinx.Graphics/Gal/IGalShader.cs b/Ryujinx.Graphics/Gal/IGalShader.cs index 4f351e0b9c..a9bd13811f 100644 --- a/Ryujinx.Graphics/Gal/IGalShader.cs +++ b/Ryujinx.Graphics/Gal/IGalShader.cs @@ -13,8 +13,6 @@ namespace Ryujinx.Graphics.Gal void EnsureTextureBinding(string UniformName, int Value); - void SetFlip(float X, float Y); - void Bind(long Key); void Unbind(GalShaderType Type); diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLPipeline.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLPipeline.cs index ba4a1f0a82..fca5ab4be7 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLPipeline.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLPipeline.cs @@ -108,10 +108,15 @@ namespace Ryujinx.Graphics.Gal.OpenGL { //O stands for Older, S for (current) State - BindUniforms(S); + BindConstBuffers(S); BindVertexLayout(S); + if (S.FlipX != O.FlipX || S.FlipY != O.FlipY) + { + Shader.SetFlip(S.FlipX, S.FlipY); + } + //Note: Uncomment SetFrontFace and SetCullFace when flipping issues are solved //if (S.FrontFace != O.FrontFace) @@ -279,9 +284,10 @@ namespace Ryujinx.Graphics.Gal.OpenGL O = S; } - private void BindUniforms(GalPipelineState S) + private void BindConstBuffers(GalPipelineState S) { - int FreeBinding = 0; + //Index 0 is reserved + int FreeBinding = 1; void BindIfNotNull(OGLShaderStage Stage) { diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs index 895a9b79e3..4792bc5e8a 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs @@ -5,8 +5,6 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; -using Buffer = System.Buffer; - namespace Ryujinx.Graphics.Gal.OpenGL { class OGLShader : IGalShader @@ -21,6 +19,8 @@ namespace Ryujinx.Graphics.Gal.OpenGL private OGLConstBuffer Buffer; + private int ExtraUboHandle; + public OGLShader(OGLConstBuffer Buffer) { this.Buffer = Buffer; @@ -95,13 +95,22 @@ namespace Ryujinx.Graphics.Gal.OpenGL GL.Uniform1(Location, Value); } - public void SetFlip(float X, float Y) + public unsafe void SetFlip(float X, float Y) { BindProgram(); - int Location = GL.GetUniformLocation(CurrentProgramHandle, GlslDecl.FlipUniformName); + EnsureExtraBlock(); - GL.Uniform2(Location, X, Y); + GL.BindBuffer(BufferTarget.UniformBuffer, ExtraUboHandle); + + float* Data = stackalloc float[4]; + Data[0] = X; + Data[1] = Y; + + //Invalidate buffer + GL.BufferData(BufferTarget.UniformBuffer, 4 * sizeof(float), IntPtr.Zero, BufferUsageHint.StreamDraw); + + GL.BufferSubData(BufferTarget.UniformBuffer, IntPtr.Zero, 4 * sizeof(float), (IntPtr)Data); } public void Bind(long Key) @@ -178,6 +187,20 @@ namespace Ryujinx.Graphics.Gal.OpenGL CurrentProgramHandle = Handle; } + private void EnsureExtraBlock() + { + if (ExtraUboHandle == 0) + { + ExtraUboHandle = GL.GenBuffer(); + + GL.BindBuffer(BufferTarget.UniformBuffer, ExtraUboHandle); + + GL.BufferData(BufferTarget.UniformBuffer, 4 * sizeof(float), IntPtr.Zero, BufferUsageHint.StreamDraw); + + GL.BindBufferBase(BufferRangeTarget.UniformBuffer, 0, ExtraUboHandle); + } + } + private void AttachIfNotNull(int ProgramHandle, OGLShaderStage Stage) { if (Stage != null) @@ -190,7 +213,12 @@ namespace Ryujinx.Graphics.Gal.OpenGL private void BindUniformBlocks(int ProgramHandle) { - int FreeBinding = 0; + int ExtraBlockindex = GL.GetUniformBlockIndex(ProgramHandle, GlslDecl.ExtraUniformBlockName); + + GL.UniformBlockBinding(ProgramHandle, ExtraBlockindex, 0); + + //First index is reserved + int FreeBinding = 1; void BindUniformBlocksIfNotNull(OGLShaderStage Stage) { diff --git a/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs b/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs index 7688545c02..a0c747bac4 100644 --- a/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs +++ b/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs @@ -35,6 +35,7 @@ namespace Ryujinx.Graphics.Gal.Shader public const string FragmentOutputName = "FragColor"; + public const string ExtraUniformBlockName = "Extra"; public const string FlipUniformName = "flip"; public const string ProgramName = "program"; diff --git a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs index a338f40413..87fcfb67d1 100644 --- a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs +++ b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs @@ -222,7 +222,11 @@ namespace Ryujinx.Graphics.Gal.Shader { if (Decl.ShaderType == GalShaderType.Vertex) { - SB.AppendLine("uniform vec2 " + GlslDecl.FlipUniformName + ";"); + SB.AppendLine("layout (std140) uniform " + GlslDecl.ExtraUniformBlockName + "{"); + + SB.AppendLine(IdentationStr + "vec2 " + GlslDecl.FlipUniformName + ";"); + + SB.AppendLine("};"); } SB.AppendLine(); diff --git a/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3d.cs b/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3d.cs index 8fe8c7be67..fe24a41bed 100644 --- a/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3d.cs +++ b/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3d.cs @@ -86,12 +86,7 @@ namespace Ryujinx.HLE.Gpu.Engines GalPipelineState State = new GalPipelineState(); - SetFrameBuffer(Vmm, 0); - - long[] Keys = UploadShaders(Vmm); - - Gpu.Renderer.Shader.BindProgram(); - + SetFlip(State); SetFrontFace(State); SetCullFace(State); SetDepth(State); @@ -99,6 +94,12 @@ namespace Ryujinx.HLE.Gpu.Engines SetAlphaBlending(State); SetPrimitiveRestart(State); + SetFrameBuffer(Vmm, 0); + + long[] Keys = UploadShaders(Vmm); + + Gpu.Renderer.Shader.BindProgram(); + UploadTextures(Vmm, State, Keys); UploadConstBuffers(Vmm, State); UploadVertexArrays(Vmm, State); @@ -190,6 +191,8 @@ namespace Ryujinx.HLE.Gpu.Engines long VpAPos = BasePosition + (uint)VpAOffset; long VpBPos = BasePosition + (uint)VpBOffset; + Keys[(int)GalShaderType.Vertex] = VpBPos; + Gpu.Renderer.Shader.Create(Vmm, VpAPos, VpBPos, GalShaderType.Vertex); Gpu.Renderer.Shader.Bind(VpBPos); @@ -221,11 +224,6 @@ namespace Ryujinx.HLE.Gpu.Engines Gpu.Renderer.Shader.Bind(Key); } - float SignX = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleX); - float SignY = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleY); - - Gpu.Renderer.Shader.SetFlip(SignX, SignY); - return Keys; } @@ -244,6 +242,12 @@ namespace Ryujinx.HLE.Gpu.Engines throw new ArgumentOutOfRangeException(nameof(Program)); } + private void SetFlip(GalPipelineState State) + { + State.FlipX = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleX); + State.FlipY = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleY); + } + private void SetFrontFace(GalPipelineState State) { float SignX = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleX);