diff --git a/Ryujinx.Graphics/Gal/IGalFrameBuffer.cs b/Ryujinx.Graphics/Gal/IGalFrameBuffer.cs index 91608ffa77..bce1981a47 100644 --- a/Ryujinx.Graphics/Gal/IGalFrameBuffer.cs +++ b/Ryujinx.Graphics/Gal/IGalFrameBuffer.cs @@ -4,14 +4,10 @@ namespace Ryujinx.Graphics.Gal { public interface IGalFrameBuffer { - void CreateColor(long Key, int Width, int Height, GalFrameBufferFormat Format); - void BindColor(long Key, int Attachment); void UnbindColor(int Attachment); - void CreateZeta(long Key, int Width, int Height, GalZetaFormat Format); - void BindZeta(long Key); void UnbindZeta(); diff --git a/Ryujinx.Graphics/Gal/IGalTexture.cs b/Ryujinx.Graphics/Gal/IGalTexture.cs index f6caa29791..292f59efa1 100644 --- a/Ryujinx.Graphics/Gal/IGalTexture.cs +++ b/Ryujinx.Graphics/Gal/IGalTexture.cs @@ -7,6 +7,8 @@ namespace Ryujinx.Graphics.Gal void Create(long Key, byte[] Data, GalImage Image); + void CreateFb(long Key, long Size, GalImage Image); + bool TryGetCachedTexture(long Key, long DataSize, out GalImage Image); void Bind(long Key, int Index); diff --git a/Ryujinx.Graphics/Gal/ImageFormatConverter.cs b/Ryujinx.Graphics/Gal/ImageFormatConverter.cs index 6e38292208..af0f2caecf 100644 --- a/Ryujinx.Graphics/Gal/ImageFormatConverter.cs +++ b/Ryujinx.Graphics/Gal/ImageFormatConverter.cs @@ -50,12 +50,22 @@ namespace Ryujinx.Graphics.Gal public static GalImageFormat ConvertFrameBuffer(GalFrameBufferFormat Format) { + switch (Format) + { + case GalFrameBufferFormat.R32Float: return GalImageFormat.R32; + } + //Stubbed. return GalImageFormat.A8B8G8R8; } public static GalImageFormat ConvertZeta(GalZetaFormat Format) { + switch (Format) + { + case GalZetaFormat.Z32Float: return GalImageFormat.ZF32; + } + //Stubbed. return GalImageFormat.Z24S8; } diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs index 9e915cbc5e..a73c6935b7 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs @@ -5,7 +5,7 @@ using System.Collections.Generic; namespace Ryujinx.Graphics.Gal.OpenGL { - public class OGLFrameBuffer : IGalFrameBuffer + class OGLFrameBuffer : IGalFrameBuffer { private struct Rect { @@ -23,8 +23,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL } } - - private static readonly DrawBuffersEnum[] DrawBuffers = new DrawBuffersEnum[] { DrawBuffersEnum.ColorAttachment0, @@ -42,8 +40,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL private const GalImageFormat RawFormat = GalImageFormat.A8B8G8R8; - private Dictionary ColorTextures; - private Dictionary ZetaTextures; + private OGLTexture Texture; private TCE RawTex; private TCE ReadTex; @@ -64,35 +61,19 @@ namespace Ryujinx.Graphics.Gal.OpenGL private int SrcFb; private int DstFb; - public OGLFrameBuffer() + public OGLFrameBuffer(OGLTexture Texture) { - ColorTextures = new Dictionary(); - - ZetaTextures = new Dictionary(); - } - - public void CreateColor(long Key, int Width, int Height, GalFrameBufferFormat Format) - { - if (!ColorTextures.TryGetValue(Key, out TCE Tex)) - { - Tex = new TCE(); - - ColorTextures.Add(Key, Tex); - } - - GalImageFormat ImageFormat = ImageFormatConverter.ConvertFrameBuffer(Format); - - Tex.EnsureSetup(new GalImage(Width, Height, ImageFormat)); + this.Texture = Texture; } public void BindColor(long Key, int Attachment) { - if (ColorTextures.TryGetValue(Key, out TCE Tex)) + if (Texture.TryGetTCE(Key, out TCE Tex)) { EnsureFrameBuffer(); GL.FramebufferTexture( - FramebufferTarget.Framebuffer, + FramebufferTarget.DrawFramebuffer, FramebufferAttachment.ColorAttachment0 + Attachment, Tex.Handle, 0); @@ -108,37 +89,58 @@ namespace Ryujinx.Graphics.Gal.OpenGL EnsureFrameBuffer(); GL.FramebufferTexture( - FramebufferTarget.Framebuffer, + FramebufferTarget.DrawFramebuffer, FramebufferAttachment.ColorAttachment0 + Attachment, 0, 0); } - - public void CreateZeta(long Key, int Width, int Height, GalZetaFormat Format) - { - if (!ZetaTextures.TryGetValue(Key, out TCE Tex)) - { - Tex = new TCE(); - - ZetaTextures.Add(Key, Tex); - } - - GalImageFormat ImageFormat = ImageFormatConverter.ConvertZeta(Format); - - Tex.EnsureSetup(new GalImage(Width, Height, ImageFormat)); - } - + public void BindZeta(long Key) { - if (ZetaTextures.TryGetValue(Key, out TCE Tex)) + if (Texture.TryGetTCE(Key, out TCE Tex)) { EnsureFrameBuffer(); - GL.FramebufferTexture( - FramebufferTarget.Framebuffer, - FramebufferAttachment.DepthStencilAttachment, - Tex.Handle, - 0); + if (Tex.HasDepth && Tex.HasStencil) + { + GL.FramebufferTexture( + FramebufferTarget.DrawFramebuffer, + FramebufferAttachment.DepthStencilAttachment, + Tex.Handle, + 0); + } + else if (Tex.HasDepth) + { + GL.FramebufferTexture( + FramebufferTarget.DrawFramebuffer, + FramebufferAttachment.DepthAttachment, + Tex.Handle, + 0); + + GL.FramebufferTexture( + FramebufferTarget.DrawFramebuffer, + FramebufferAttachment.StencilAttachment, + 0, + 0); + } + else if (Tex.HasStencil) + { + GL.FramebufferTexture( + FramebufferTarget.DrawFramebuffer, + FramebufferAttachment.DepthAttachment, + Tex.Handle, + 0); + + GL.FramebufferTexture( + FramebufferTarget.DrawFramebuffer, + FramebufferAttachment.StencilAttachment, + 0, + 0); + } + else + { + throw new InvalidOperationException(); + } } else { @@ -151,7 +153,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL EnsureFrameBuffer(); GL.FramebufferTexture( - FramebufferTarget.Framebuffer, + FramebufferTarget.DrawFramebuffer, FramebufferAttachment.DepthStencilAttachment, 0, 0); @@ -159,10 +161,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL public void BindTexture(long Key, int Index) { - TCE Tex; - - if (ColorTextures.TryGetValue(Key, out Tex) || - ZetaTextures.TryGetValue(Key, out Tex)) + if (Texture.TryGetTCE(Key, out TCE Tex)) { GL.ActiveTexture(TextureUnit.Texture0 + Index); @@ -172,7 +171,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL public void Set(long Key) { - if (ColorTextures.TryGetValue(Key, out TCE Tex)) + if (Texture.TryGetTCE(Key, out TCE Tex)) { ReadTex = Tex; } @@ -307,50 +306,72 @@ namespace Ryujinx.Graphics.Gal.OpenGL int DstX1, int DstY1) { - bool Found = false; - - if (ColorTextures.TryGetValue(SrcKey, out TCE SrcTex) && - ColorTextures.TryGetValue(DstKey, out TCE DstTex)) + if (Texture.TryGetTCE(SrcKey, out TCE SrcTex) && + Texture.TryGetTCE(DstKey, out TCE DstTex)) { - CopyTextures( - SrcX0, SrcY0, SrcX1, SrcY1, - DstX0, DstY0, DstX1, DstY1, - SrcTex.Handle, - DstTex.Handle, - FramebufferAttachment.ColorAttachment0, - ClearBufferMask.ColorBufferBit, - true); + if (SrcTex.HasColor != DstTex.HasColor || + SrcTex.HasDepth != DstTex.HasDepth || + SrcTex.HasStencil != DstTex.HasStencil) + { + throw new NotImplementedException(); + } - Found = true; - } + if (SrcTex.HasColor) + { + CopyTextures( + SrcX0, SrcY0, SrcX1, SrcY1, + DstX0, DstY0, DstX1, DstY1, + SrcTex.Handle, + DstTex.Handle, + FramebufferAttachment.ColorAttachment0, + ClearBufferMask.ColorBufferBit, + true); + } + else if (SrcTex.HasDepth && SrcTex.HasStencil) + { + CopyTextures( + SrcX0, SrcY0, SrcX1, SrcY1, + DstX0, DstY0, DstX1, DstY1, + SrcTex.Handle, + DstTex.Handle, + FramebufferAttachment.DepthStencilAttachment, + ClearBufferMask.DepthBufferBit | ClearBufferMask.StencilBufferBit, + false); + } + else if (SrcTex.HasDepth) + { + CopyTextures( + SrcX0, SrcY0, SrcX1, SrcY1, + DstX0, DstY0, DstX1, DstY1, + SrcTex.Handle, + DstTex.Handle, + FramebufferAttachment.DepthAttachment, + ClearBufferMask.DepthBufferBit, + false); + } + else if (SrcTex.HasStencil) + { + CopyTextures( + SrcX0, SrcY0, SrcX1, SrcY1, + DstX0, DstY0, DstX1, DstY1, + SrcTex.Handle, + DstTex.Handle, + FramebufferAttachment.StencilAttachment, + ClearBufferMask.StencilBufferBit, + false); + } + else + { + throw new InvalidOperationException(); + } - if (ZetaTextures.TryGetValue(SrcKey, out TCE ZetaSrcTex) && - ZetaTextures.TryGetValue(DstKey, out TCE ZetaDstTex)) - { - CopyTextures( - SrcX0, SrcY0, SrcX1, SrcY1, - DstX0, DstY0, DstX1, DstY1, - ZetaSrcTex.Handle, - ZetaDstTex.Handle, - FramebufferAttachment.DepthStencilAttachment, - ClearBufferMask.DepthBufferBit | ClearBufferMask.StencilBufferBit, - false); - - Found = true; - } - - if (Found) - { EnsureFrameBuffer(); } } public void GetBufferData(long Key, Action Callback) { - TCE Tex; - - if (ColorTextures.TryGetValue(Key, out Tex) || - ZetaTextures.TryGetValue(Key, out Tex)) + if (Texture.TryGetTCE(Key, out TCE Tex)) { byte[] Data = new byte[Tex.Width * Tex.Height * TCE.MaxBpp]; @@ -373,10 +394,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL int Height, byte[] Buffer) { - TCE Tex; - - if (ColorTextures.TryGetValue(Key, out Tex) || - ZetaTextures.TryGetValue(Key, out Tex)) + if (Texture.TryGetTCE(Key, out TCE Tex)) { GL.BindTexture(TextureTarget.Texture2D, Tex.Handle); @@ -403,7 +421,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL DummyFrameBuffer = GL.GenFramebuffer(); } - GL.BindFramebuffer(FramebufferTarget.Framebuffer, DummyFrameBuffer); + GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DummyFrameBuffer); GL.DrawBuffers(8, DrawBuffers); } diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs index c0e4bd0f53..3cb362cfbf 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs @@ -50,33 +50,23 @@ namespace Ryujinx.Graphics.Gal.OpenGL float Depth, int Stencil) { - //TODO: Handle attachment - - ClearBufferMask Mask = ClearBufferMask.ColorBufferBit; - - if (Flags.HasFlag(GalClearBufferFlags.Depth)) - { - Mask |= ClearBufferMask.DepthBufferBit; - } - - if (Flags.HasFlag(GalClearBufferFlags.Stencil)) - { - Mask |= ClearBufferMask.StencilBufferBit; - } - GL.ColorMask( Flags.HasFlag(GalClearBufferFlags.ColorRed), Flags.HasFlag(GalClearBufferFlags.ColorGreen), Flags.HasFlag(GalClearBufferFlags.ColorBlue), Flags.HasFlag(GalClearBufferFlags.ColorAlpha)); - GL.ClearColor(Red, Green, Blue, Alpha); + GL.ClearBuffer(ClearBuffer.Color, Attachment, new float[] { Red, Green, Blue, Alpha }); - GL.ClearDepth(Depth); + if (Flags.HasFlag(GalClearBufferFlags.Depth)) + { + GL.ClearBuffer(ClearBuffer.Depth, 0, ref Depth); + } - GL.ClearStencil(Stencil); - - GL.Clear(Mask); + if (Flags.HasFlag(GalClearBufferFlags.Stencil)) + { + GL.ClearBuffer(ClearBuffer.Stencil, 0, ref Stencil); + } GL.ColorMask(true, true, true, true); } diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLRenderer.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLRenderer.cs index b0f6da45e5..985f1086f0 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLRenderer.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLRenderer.cs @@ -23,7 +23,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL { Buffer = new OGLConstBuffer(); - FrameBuffer = new OGLFrameBuffer(); + Texture = new OGLTexture(); + + FrameBuffer = new OGLFrameBuffer(Texture as OGLTexture); Rasterizer = new OGLRasterizer(); @@ -31,8 +33,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL Pipeline = new OGLPipeline(Buffer as OGLConstBuffer, Rasterizer as OGLRasterizer, Shader as OGLShader); - Texture = new OGLTexture(); - ActionsQueue = new ConcurrentQueue(); } diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs index 95f12acd03..24dd83b006 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs @@ -4,7 +4,7 @@ using System; namespace Ryujinx.Graphics.Gal.OpenGL { - public class OGLTexture : IGalTexture + class OGLTexture : IGalTexture { private OGLCachedResource TextureCache; @@ -95,6 +95,30 @@ namespace Ryujinx.Graphics.Gal.OpenGL GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleA, SwizzleA); } + public void CreateFb(long Key, long Size, GalImage Image) + { + if (!TryGetTCE(Key, out TCE Texture)) + { + Texture = new TCE(); + + TextureCache.AddOrUpdate(Key, Texture, Size); + } + + Texture.EnsureSetup(Image); + } + + public bool TryGetTCE(long Key, out TCE CachedTexture) + { + if (TextureCache.TryGetValue(Key, out CachedTexture)) + { + return true; + } + + CachedTexture = null; + + return false; + } + private static int GetAstcBlockWidth(GalImageFormat Format) { switch (Format) diff --git a/Ryujinx.Graphics/Gal/OpenGL/TCE.cs b/Ryujinx.Graphics/Gal/OpenGL/TCE.cs index d39dba7d0e..2b60f01155 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/TCE.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/TCE.cs @@ -8,6 +8,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL //TODO: Use a variable value here public const int MaxBpp = 16; + private static int CopyBuffer = 0; + private static int CopyBufferSize = 0; + public GalImage Image { get; private set; } public int Width { get => Image.Width; } @@ -36,31 +39,37 @@ namespace Ryujinx.Graphics.Gal.OpenGL public void EnsureSetup(GalImage Image) { - if (this.Width != Image.Width || - this.Height != Image.Height || - this.Format != Image.Format || + if (Width != Image.Width || + Height != Image.Height || + Format != Image.Format || !Initialized) { (PixelInternalFormat InternalFormat, PixelFormat PixelFormat, PixelType PixelType) = OGLEnumConverter.GetImageFormat(Image.Format); - int CopyBuffer = 0; - - bool ChangingFormat = Initialized && this.InternalFormat != InternalFormat; - GL.BindTexture(TextureTarget.Texture2D, Handle); - if (ChangingFormat) + if (Initialized) { - CopyBuffer = GL.GenBuffer(); + if (CopyBuffer == 0) + { + CopyBuffer = GL.GenBuffer(); + } + + int MaxWidth = Math.Max(Image.Width, Width); + int MaxHeight = Math.Max(Image.Height, Height); + + int CurrentSize = MaxWidth * MaxHeight * MaxBpp; GL.BindBuffer(BufferTarget.PixelPackBuffer, CopyBuffer); GL.BindBuffer(BufferTarget.PixelUnpackBuffer, CopyBuffer); - int MaxWidth = Math.Max(Image.Width, this.Width); - int MaxHeight = Math.Max(Image.Height, this.Height); + if (CopyBufferSize < CurrentSize) + { + CopyBufferSize = CurrentSize; - GL.BufferData(BufferTarget.PixelPackBuffer, MaxWidth * MaxHeight * MaxBpp, IntPtr.Zero, BufferUsageHint.StaticCopy); + GL.BufferData(BufferTarget.PixelPackBuffer, CurrentSize, IntPtr.Zero, BufferUsageHint.DynamicCopy); + } GL.GetTexImage(TextureTarget.Texture2D, 0, this.PixelFormat, this.PixelType, IntPtr.Zero); @@ -91,12 +100,10 @@ namespace Ryujinx.Graphics.Gal.OpenGL PixelType, IntPtr.Zero); - if (ChangingFormat) + if (Initialized) { GL.BindBuffer(BufferTarget.PixelPackBuffer, 0); GL.BindBuffer(BufferTarget.PixelUnpackBuffer, 0); - - GL.DeleteBuffer(CopyBuffer); } this.Image = Image; @@ -108,5 +115,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL Initialized = true; } } + + public bool HasColor { get => ImageFormatConverter.HasColor(Format); } + public bool HasDepth { get => ImageFormatConverter.HasDepth(Format); } + public bool HasStencil { get => ImageFormatConverter.HasStencil(Format); } } } diff --git a/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3d.cs b/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3d.cs index a3c79d4a15..f89ac0595c 100644 --- a/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3d.cs +++ b/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3d.cs @@ -102,8 +102,10 @@ namespace Ryujinx.HLE.Gpu.Engines SetAlphaBlending(State); SetPrimitiveRestart(State); - SetFrameBuffer(Vmm, 0); - + for (int FbIndex = 0; FbIndex < 8; FbIndex++) + { + SetFrameBuffer(Vmm, FbIndex); + } SetZeta(Vmm); long[] Keys = UploadShaders(Vmm); @@ -151,6 +153,7 @@ namespace Ryujinx.HLE.Gpu.Engines int Stencil = ReadRegister(NvGpuEngine3dReg.ClearStencil); SetFrameBuffer(Vmm, FbIndex); + SetZeta(Vmm); Gpu.Renderer.Rasterizer.ClearBuffers( Flags, @@ -166,7 +169,7 @@ namespace Ryujinx.HLE.Gpu.Engines int Format = ReadRegister(NvGpuEngine3dReg.FrameBufferNFormat + FbIndex * 0x10); - if (VA == 0/* || Format == 0*/) + if (VA == 0 || Format == 0) { Gpu.Renderer.FrameBuffer.UnbindColor(FbIndex); @@ -192,7 +195,13 @@ namespace Ryujinx.HLE.Gpu.Engines int VpW = (int)(TX + MathF.Abs(SX)) - VpX; int VpH = (int)(TY + MathF.Abs(SY)) - VpY; - Gpu.Renderer.FrameBuffer.CreateColor(Key, Width, Height, (GalFrameBufferFormat)Format); + GalImageFormat ImageFormat = ImageFormatConverter.ConvertFrameBuffer((GalFrameBufferFormat)Format); + + GalImage Image = new GalImage(Width, Height, ImageFormat); + + long Size = TextureHelper.GetTextureSize(Image); + + Gpu.Renderer.Texture.CreateFb(Key, Size, Image); Gpu.Renderer.FrameBuffer.BindColor(Key, FbIndex); Gpu.Renderer.FrameBuffer.SetViewport(VpX, VpY, VpW, VpH); @@ -214,12 +223,17 @@ namespace Ryujinx.HLE.Gpu.Engines } long Key = Vmm.GetPhysicalAddress(ZA); - + int Width = ReadRegister(NvGpuEngine3dReg.ZetaHoriz); int Height = ReadRegister(NvGpuEngine3dReg.ZetaVert); - Gpu.Renderer.FrameBuffer.CreateZeta(Key, Width, Height, (GalZetaFormat)Format); + GalImageFormat ImageFormat = ImageFormatConverter.ConvertZeta((GalZetaFormat)Format); + GalImage Image = new GalImage(Width, Height, ImageFormat); + + long Size = TextureHelper.GetTextureSize(Image); + + Gpu.Renderer.Texture.CreateFb(Key, Size, Image); Gpu.Renderer.FrameBuffer.BindZeta(Key); } @@ -479,15 +493,15 @@ namespace Ryujinx.HLE.Gpu.Engines } else { - GalImage NewTexture = TextureFactory.MakeTexture(Vmm, TicPosition); + GalImage NewImage = TextureFactory.MakeTexture(Vmm, TicPosition); - long Size = (uint)TextureHelper.GetTextureSize(NewTexture); + long Size = (uint)TextureHelper.GetTextureSize(NewImage); bool HasCachedTexture = false; - if (Gpu.Renderer.Texture.TryGetCachedTexture(Key, Size, out GalImage Texture)) + if (Gpu.Renderer.Texture.TryGetCachedTexture(Key, Size, out GalImage Image)) { - if (NewTexture.Equals(Texture) && !QueryKeyUpload(Vmm, Key, Size, NvGpuBufferType.Texture)) + if (NewImage.Equals(Image) && !QueryKeyUpload(Vmm, Key, Size, NvGpuBufferType.Texture)) { Gpu.Renderer.Texture.Bind(Key, TexIndex); @@ -499,7 +513,7 @@ namespace Ryujinx.HLE.Gpu.Engines { byte[] Data = TextureFactory.GetTextureData(Vmm, TicPosition); - Gpu.Renderer.Texture.Create(Key, Data, NewTexture); + Gpu.Renderer.Texture.Create(Key, Data, NewImage); } Gpu.Renderer.Texture.Bind(Key, TexIndex);