diff --git a/Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs b/Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs index 8a5ef4e9c2..4ab64e2ae0 100644 --- a/Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs +++ b/Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs @@ -276,35 +276,24 @@ namespace Ryujinx.Core.OsHle.Services.Android return 0; } - private unsafe void SendFrameBuffer(ServiceCtx Context, int Slot) + private void SendFrameBuffer(ServiceCtx Context, int Slot) { - int FbWidth = BufferQueue[Slot].Data.Width; - int FbHeight = BufferQueue[Slot].Data.Height; - - long FbSize = (uint)FbWidth * FbHeight * 4; + int FbWidth = 1280; + int FbHeight = 720; NvMap Map = GetNvMap(Context, Slot); NvMapFb MapFb = (NvMapFb)INvDrvServices.NvMapsFb.GetData(Context.Process, 0); - long Address = Map.CpuAddress; + long CpuAddr = Map.CpuAddress; + long GpuAddr = Map.GpuAddress; if (MapFb.HasBufferOffset(Slot)) { - Address += MapFb.GetBufferOffset(Slot); - } + CpuAddr += MapFb.GetBufferOffset(Slot); - if ((ulong)(Address + FbSize) > AMemoryMgr.AddrSize) - { - Logging.Error($"Frame buffer address {Address:x16} is invalid!"); - - BufferQueue[Slot].State = BufferState.Free; - - ReleaseEvent.Handle.Set(); - - WaitBufferFree.Set(); - - return; + //TODO: Enable once the frame buffers problems are fixed. + //GpuAddr += MapFb.GetBufferOffset(Slot); } BufferQueue[Slot].State = BufferState.Acquired; @@ -358,17 +347,21 @@ namespace Ryujinx.Core.OsHle.Services.Android Rotate = -MathF.PI * 0.5f; } - if (Context.Ns.Gpu.Engine3d.IsFrameBufferPosition(Map.GpuAddress)) + Renderer.SetFrameBufferTransform(ScaleX, ScaleY, Rotate, OffsX, OffsY); + + //TODO: Support double buffering here aswell, it is broken for GPU + //frame buffers because it seems to be completely out of sync. + if (Context.Ns.Gpu.Engine3d.IsFrameBufferPosition(GpuAddr)) { //Frame buffer is rendered to by the GPU, we can just //bind the frame buffer texture, it's not necessary to read anything. - Renderer.SetFrameBuffer(Map.GpuAddress); + Renderer.SetFrameBuffer(GpuAddr); } else { //Frame buffer is not set on the GPU registers, in this case //assume that the app is manually writing to it. - Texture Texture = new Texture(Address, FbWidth, FbHeight); + Texture Texture = new Texture(CpuAddr, FbWidth, FbHeight); byte[] Data = TextureReader.Read(Context.Memory, Texture); diff --git a/Ryujinx.Graphics/Gal/IGalRenderer.cs b/Ryujinx.Graphics/Gal/IGalRenderer.cs index 36747609fe..c30c79fb38 100644 --- a/Ryujinx.Graphics/Gal/IGalRenderer.cs +++ b/Ryujinx.Graphics/Gal/IGalRenderer.cs @@ -40,6 +40,8 @@ namespace Ryujinx.Graphics.Gal void SetFrameBuffer(byte[] Data, int Width, int Height); + void SetFrameBufferTransform(float SX, float SY, float Rotate, float TX, float TY); + //Rasterizer void ClearBuffers(int RtIndex, GalClearBufferFlags Flags); diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs index a338e75625..818af3b3a8 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs @@ -7,11 +7,24 @@ namespace Ryujinx.Graphics.Gal.OpenGL { class OGLFrameBuffer { - private struct FrameBuffer + private class FrameBuffer { - public int Handle; - public int RbHandle; - public int TexHandle; + public int Width { get; set; } + public int Height { get; set; } + + public int Handle { get; private set; } + public int RbHandle { get; private set; } + public int TexHandle { get; private set; } + + public FrameBuffer(int Width, int Height) + { + this.Width = Width; + this.Height = Height; + + Handle = GL.GenFramebuffer(); + RbHandle = GL.GenRenderbuffer(); + TexHandle = GL.GenTexture(); + } } private struct ShaderProgram @@ -27,9 +40,13 @@ namespace Ryujinx.Graphics.Gal.OpenGL private bool IsInitialized; + private int RawFbTexWidth; + private int RawFbTexHeight; + private int RawFbTexHandle; + private int CurrFbHandle; private int CurrTexHandle; - private int RawFbTexHandle; + private int VaoHandle; private int VboHandle; @@ -42,19 +59,21 @@ namespace Ryujinx.Graphics.Gal.OpenGL public void Create(long Tag, int Width, int Height) { - if (Fbs.ContainsKey(Tag)) + if (Fbs.TryGetValue(Tag, out FrameBuffer Fb)) { + if (Fb.Width != Width || + Fb.Height != Height) + { + SetupTexture(Fb.TexHandle, Width, Height); + + Fb.Width = Width; + Fb.Height = Height; + } + return; } - Width = 1280; - Height = 720; - - FrameBuffer Fb = new FrameBuffer(); - - Fb.Handle = GL.GenFramebuffer(); - Fb.RbHandle = GL.GenRenderbuffer(); - Fb.TexHandle = GL.GenTexture(); + Fb = new FrameBuffer(Width, Height); SetupTexture(Fb.TexHandle, Width, Height); @@ -115,7 +134,19 @@ namespace Ryujinx.Graphics.Gal.OpenGL public void Set(byte[] Data, int Width, int Height) { - EnsureInitialized(); + if (RawFbTexHandle == 0) + { + RawFbTexHandle = GL.GenTexture(); + } + + if (RawFbTexWidth != Width || + RawFbTexHeight != Height) + { + SetupTexture(RawFbTexHandle, Width, Height); + + RawFbTexWidth = Width; + RawFbTexHeight = Height; + } GL.ActiveTexture(TextureUnit.Texture0); @@ -128,6 +159,25 @@ namespace Ryujinx.Graphics.Gal.OpenGL CurrTexHandle = RawFbTexHandle; } + public void SetTransform(Matrix2 Transform, Vector2 Offs) + { + EnsureInitialized(); + + 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); + } + public void Render() { if (CurrTexHandle != 0) @@ -163,10 +213,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL SetupShader(); SetupVertex(); - - RawFbTexHandle = GL.GenTexture(); - - SetupTexture(RawFbTexHandle, 1280, 720); } } @@ -190,7 +236,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL GL.LinkProgram(Shader.Handle); GL.UseProgram(Shader.Handle); - Matrix2 Transform = Matrix2.CreateScale(1, -1); + Matrix2 Transform = Matrix2.Identity; int TexUniformLocation = GL.GetUniformLocation(Shader.Handle, "tex"); diff --git a/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs b/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs index 9923dc398b..b3ccae5f87 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs @@ -1,3 +1,4 @@ +using OpenTK; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -128,6 +129,18 @@ namespace Ryujinx.Graphics.Gal.OpenGL ActionsQueue.Enqueue(() => FrameBuffer.Set(Data, Width, Height)); } + public void SetFrameBufferTransform(float SX, float SY, float Rotate, float TX, float TY) + { + Matrix2 Transform; + + Transform = Matrix2.CreateScale(SX, SY); + Transform *= Matrix2.CreateRotation(Rotate); + + Vector2 Offs = new Vector2(TX, TY); + + ActionsQueue.Enqueue(() => FrameBuffer.SetTransform(Transform, Offs)); + } + public void ClearBuffers(int RtIndex, GalClearBufferFlags Flags) { ActionsQueue.Enqueue(() => Rasterizer.ClearBuffers(RtIndex, Flags)); diff --git a/Ryujinx.Graphics/Gpu/NvGpuEngine3d.cs b/Ryujinx.Graphics/Gpu/NvGpuEngine3d.cs index 1778e8fc1a..1142e4aa69 100644 --- a/Ryujinx.Graphics/Gpu/NvGpuEngine3d.cs +++ b/Ryujinx.Graphics/Gpu/NvGpuEngine3d.cs @@ -24,8 +24,6 @@ namespace Ryujinx.Graphics.Gpu private HashSet FrameBuffers; - private bool HasDataToRender; - public NvGpuEngine3d(NsGpu Gpu) { this.Gpu = Gpu; @@ -80,17 +78,10 @@ namespace Ryujinx.Graphics.Gpu UploadTextures(Memory, Tags); UploadUniforms(Memory); UploadVertexArrays(Memory); - - HasDataToRender = true; } private void ClearBuffers(AMemory Memory, NsGpuPBEntry PBEntry) { - if (HasDataToRender) - { - HasDataToRender = false; - } - int Arg0 = PBEntry.Arguments[0]; int FbIndex = (Arg0 >> 6) & 0xf; @@ -101,6 +92,7 @@ namespace Ryujinx.Graphics.Gpu SetFrameBuffer(0); + //TODO: Enable this once the frame buffer problems are fixed. //Gpu.Renderer.ClearBuffers(Layer, Flags); } @@ -113,7 +105,9 @@ namespace Ryujinx.Graphics.Gpu int Width = ReadRegister(NvGpuEngine3dReg.FrameBufferNWidth + FbIndex * 0x10); int Height = ReadRegister(NvGpuEngine3dReg.FrameBufferNHeight + FbIndex * 0x10); - Gpu.Renderer.CreateFrameBuffer(Address, Width, Height); + //Note: Using the Width/Height results seems to give incorrect results. + //Maybe the size of all frame buffers is hardcoded to screen size? This seems unlikely. + Gpu.Renderer.CreateFrameBuffer(Address, 1280, 720); Gpu.Renderer.BindFrameBuffer(Address); } @@ -405,7 +399,7 @@ namespace Ryujinx.Graphics.Gpu if (Mode == 0) { - //Write. + //Write mode. Memory.WriteInt32(Position, Seq); } }