diff options
| author | ReinUsesLisp <reinuseslisp@airmail.cc> | 2018-08-19 22:25:26 -0300 |
|---|---|---|
| committer | gdkchan <gab.dark.100@gmail.com> | 2018-08-19 22:25:26 -0300 |
| commit | 726de8c46ab10f1b0684fe14bca1ca96ba6d2832 (patch) | |
| tree | 5da68699e9062f1c01ef3da9d9eceb75657b2f93 /Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs | |
| parent | 056c2840b1851657c3855fb72776837c89ff59d3 (diff) | |
Rendertarget attachments, texture and image changes (#358)
* Add multiple color outputs for fragment shaders
* Add registers and gal enums
* Use textures for framebuffers and split color and zeta framebuffers
* Abstract texture and framebuffer targets as an image
* Share images between framebuffers and textures
* Unstub formats
* Add some formats
* Disable multiple attachments
* Cache framebuffer attachments
* Handle format types
* Add some rendertarget formats
* Code cleanup
* Fixup half float types
* Address feedback
* Disable multiple attachments in shaders
* Add A4B4G4R4 image format
* Add reversed section for image enums
Diffstat (limited to 'Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs')
| -rw-r--r-- | Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs | 494 |
1 files changed, 292 insertions, 202 deletions
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs index 62f82495..e0f12e4e 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs @@ -1,10 +1,9 @@ using OpenTK.Graphics.OpenGL; using System; -using System.Collections.Generic; namespace Ryujinx.Graphics.Gal.OpenGL { - public class OGLFrameBuffer : IGalFrameBuffer + class OGLFrameBuffer : IGalFrameBuffer { private struct Rect { @@ -15,49 +14,37 @@ namespace Ryujinx.Graphics.Gal.OpenGL public Rect(int X, int Y, int Width, int Height) { - this.X = X; - this.Y = Y; - this.Width = Width; + this.X = X; + this.Y = Y; + this.Width = Width; this.Height = Height; } } - private class FrameBuffer + private static readonly DrawBuffersEnum[] DrawBuffers = new DrawBuffersEnum[] { - 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, bool HasRenderBuffer) - { - this.Width = Width; - this.Height = Height; - - Handle = GL.GenFramebuffer(); - TexHandle = GL.GenTexture(); - - if (HasRenderBuffer) - { - RbHandle = GL.GenRenderbuffer(); - } - } - } + DrawBuffersEnum.ColorAttachment0, + DrawBuffersEnum.ColorAttachment1, + DrawBuffersEnum.ColorAttachment2, + DrawBuffersEnum.ColorAttachment3, + DrawBuffersEnum.ColorAttachment4, + DrawBuffersEnum.ColorAttachment5, + DrawBuffersEnum.ColorAttachment6, + DrawBuffersEnum.ColorAttachment7, + }; private const int NativeWidth = 1280; private const int NativeHeight = 720; - private Dictionary<long, FrameBuffer> Fbs; + private const GalImageFormat RawFormat = GalImageFormat.A8B8G8R8_UNORM_PACK32; - private Rect Viewport; - private Rect Window; + private OGLTexture Texture; - private FrameBuffer CurrFb; - private FrameBuffer CurrReadFb; + private ImageHandler RawTex; + private ImageHandler ReadTex; - private FrameBuffer RawFb; + private Rect Viewport; + private Rect Window; private bool FlipX; private bool FlipY; @@ -67,111 +54,144 @@ namespace Ryujinx.Graphics.Gal.OpenGL private int CropRight; private int CropBottom; - public OGLFrameBuffer() - { - Fbs = new Dictionary<long, FrameBuffer>(); - } + //This framebuffer is used to attach guest rendertargets, + //think of it as a dummy OpenGL VAO + private int DummyFrameBuffer; - public void Create(long Key, int Width, int Height) - { - if (Fbs.TryGetValue(Key, out FrameBuffer Fb)) - { - if (Fb.Width != Width || - Fb.Height != Height) - { - SetupTexture(Fb.TexHandle, Width, Height); + //These framebuffers are used to blit images + private int SrcFb; + private int DstFb; - Fb.Width = Width; - Fb.Height = Height; - } + //Holds current attachments, used to avoid unnecesary calls to OpenGL + private int[] ColorAttachments; - return; - } + private int DepthAttachment; + private int StencilAttachment; - Fb = new FrameBuffer(Width, Height, true); + public OGLFrameBuffer(OGLTexture Texture) + { + ColorAttachments = new int[8]; - SetupTexture(Fb.TexHandle, Width, Height); + this.Texture = Texture; + } - GL.BindFramebuffer(FramebufferTarget.Framebuffer, Fb.Handle); + public void BindColor(long Key, int Attachment) + { + if (Texture.TryGetImage(Key, out ImageHandler Tex)) + { + EnsureFrameBuffer(); - GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, Fb.RbHandle); + Attach(ref ColorAttachments[Attachment], Tex.Handle, FramebufferAttachment.ColorAttachment0 + Attachment); + } + else + { + UnbindColor(Attachment); + } + } - GL.RenderbufferStorage( - RenderbufferTarget.Renderbuffer, - RenderbufferStorage.Depth24Stencil8, - Width, - Height); + public void UnbindColor(int Attachment) + { + EnsureFrameBuffer(); - GL.FramebufferRenderbuffer( - FramebufferTarget.Framebuffer, - FramebufferAttachment.DepthStencilAttachment, - RenderbufferTarget.Renderbuffer, - Fb.RbHandle); + Attach(ref ColorAttachments[Attachment], 0, FramebufferAttachment.ColorAttachment0 + Attachment); + } + + public void BindZeta(long Key) + { + if (Texture.TryGetImage(Key, out ImageHandler Tex)) + { + EnsureFrameBuffer(); - GL.FramebufferTexture( - FramebufferTarget.Framebuffer, - FramebufferAttachment.ColorAttachment0, - Fb.TexHandle, - 0); + if (Tex.HasDepth && Tex.HasStencil) + { + if (DepthAttachment != Tex.Handle || + StencilAttachment != Tex.Handle) + { + GL.FramebufferTexture( + FramebufferTarget.DrawFramebuffer, + FramebufferAttachment.DepthStencilAttachment, + Tex.Handle, + 0); + + DepthAttachment = Tex.Handle; + + StencilAttachment = Tex.Handle; + } + } + else if (Tex.HasDepth) + { + Attach(ref DepthAttachment, Tex.Handle, FramebufferAttachment.DepthAttachment); - GL.DrawBuffer(DrawBufferMode.ColorAttachment0); + Attach(ref StencilAttachment, 0, FramebufferAttachment.StencilAttachment); + } + else if (Tex.HasStencil) + { + Attach(ref DepthAttachment, 0, FramebufferAttachment.DepthAttachment); - Fbs.Add(Key, Fb); + Attach(ref StencilAttachment, Tex.Handle, FramebufferAttachment.StencilAttachment); + } + else + { + throw new InvalidOperationException(); + } + } + else + { + UnbindZeta(); + } } - public void Bind(long Key) + public void UnbindZeta() { - if (Fbs.TryGetValue(Key, out FrameBuffer Fb)) + EnsureFrameBuffer(); + + if (DepthAttachment != 0 || + StencilAttachment != 0) { - GL.BindFramebuffer(FramebufferTarget.Framebuffer, Fb.Handle); + GL.FramebufferTexture( + FramebufferTarget.DrawFramebuffer, + FramebufferAttachment.DepthStencilAttachment, + 0, + 0); + + DepthAttachment = 0; - CurrFb = Fb; + StencilAttachment = 0; } } public void BindTexture(long Key, int Index) { - if (Fbs.TryGetValue(Key, out FrameBuffer Fb)) + if (Texture.TryGetImage(Key, out ImageHandler Tex)) { GL.ActiveTexture(TextureUnit.Texture0 + Index); - GL.BindTexture(TextureTarget.Texture2D, Fb.TexHandle); + GL.BindTexture(TextureTarget.Texture2D, Tex.Handle); } } public void Set(long Key) { - if (Fbs.TryGetValue(Key, out FrameBuffer Fb)) + if (Texture.TryGetImage(Key, out ImageHandler Tex)) { - CurrReadFb = Fb; + ReadTex = Tex; } } public void Set(byte[] Data, int Width, int Height) { - if (RawFb == null) + if (RawTex == null) { - CreateRawFb(Width, Height); + RawTex = new ImageHandler(); } - if (RawFb.Width != Width || - RawFb.Height != Height) - { - SetupTexture(RawFb.TexHandle, Width, Height); - - RawFb.Width = Width; - RawFb.Height = Height; - } - - GL.ActiveTexture(TextureUnit.Texture0); - - GL.BindTexture(TextureTarget.Texture2D, RawFb.TexHandle); + RawTex.EnsureSetup(new GalImage(Width, Height, RawFormat)); - (PixelFormat Format, PixelType Type) = OGLEnumConverter.GetTextureFormat(GalTextureFormat.A8B8G8R8); + GL.BindTexture(TextureTarget.Texture2D, RawTex.Handle); - GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, Width, Height, Format, Type, Data); + GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, Width, Height, RawTex.PixelFormat, RawTex.PixelType, Data); - CurrReadFb = RawFb; + ReadTex = RawTex; } public void SetTransform(bool FlipX, bool FlipY, int Top, int Left, int Right, int Bottom) @@ -208,60 +228,71 @@ namespace Ryujinx.Graphics.Gal.OpenGL public void Render() { - if (CurrReadFb != null) + if (ReadTex == null) { - int SrcX0, SrcX1, SrcY0, SrcY1; + return; + } - if (CropLeft == 0 && CropRight == 0) - { - SrcX0 = 0; - SrcX1 = CurrReadFb.Width; - } - else - { - SrcX0 = CropLeft; - SrcX1 = CropRight; - } + int SrcX0, SrcX1, SrcY0, SrcY1; - if (CropTop == 0 && CropBottom == 0) - { - SrcY0 = 0; - SrcY1 = CurrReadFb.Height; - } - else - { - SrcY0 = CropTop; - SrcY1 = CropBottom; - } + if (CropLeft == 0 && CropRight == 0) + { + SrcX0 = 0; + SrcX1 = ReadTex.Width; + } + else + { + SrcX0 = CropLeft; + SrcX1 = CropRight; + } + + if (CropTop == 0 && CropBottom == 0) + { + SrcY0 = 0; + SrcY1 = ReadTex.Height; + } + else + { + SrcY0 = CropTop; + SrcY1 = CropBottom; + } - 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)); + 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)); - int DstWidth = (int)(Window.Width * RatioX); - int DstHeight = (int)(Window.Height * RatioY); + int DstWidth = (int)(Window.Width * RatioX); + int DstHeight = (int)(Window.Height * RatioY); - int DstPaddingX = (Window.Width - DstWidth) / 2; - int DstPaddingY = (Window.Height - DstHeight) / 2; + int DstPaddingX = (Window.Width - DstWidth) / 2; + int DstPaddingY = (Window.Height - DstHeight) / 2; - int DstX0 = FlipX ? Window.Width - DstPaddingX : DstPaddingX; - int DstX1 = FlipX ? DstPaddingX : Window.Width - DstPaddingX; + int DstX0 = FlipX ? Window.Width - DstPaddingX : DstPaddingX; + int DstX1 = FlipX ? DstPaddingX : Window.Width - DstPaddingX; - int DstY0 = FlipY ? DstPaddingY : Window.Height - DstPaddingY; - int DstY1 = FlipY ? Window.Height - DstPaddingY : DstPaddingY; + int DstY0 = FlipY ? DstPaddingY : Window.Height - DstPaddingY; + int DstY1 = FlipY ? Window.Height - DstPaddingY : DstPaddingY; - GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0); + if (SrcFb == 0) SrcFb = GL.GenFramebuffer(); - GL.Viewport(0, 0, Window.Width, Window.Height); + GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, 0); - GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, CurrReadFb.Handle); + GL.Viewport(0, 0, Window.Width, Window.Height); - GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); + GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, SrcFb); - GL.BlitFramebuffer( - SrcX0, SrcY0, SrcX1, SrcY1, - DstX0, DstY0, DstX1, DstY1, - ClearBufferMask.ColorBufferBit, BlitFramebufferFilter.Linear); - } + GL.FramebufferTexture(FramebufferTarget.ReadFramebuffer, FramebufferAttachment.ColorAttachment0, ReadTex.Handle, 0); + + GL.ReadBuffer(ReadBufferMode.ColorAttachment0); + GL.DrawBuffer(DrawBufferMode.ColorAttachment0); + + GL.Clear(ClearBufferMask.ColorBufferBit); + + GL.BlitFramebuffer( + SrcX0, SrcY0, SrcX1, SrcY1, + DstX0, DstY0, DstX1, DstY1, + ClearBufferMask.ColorBufferBit, BlitFramebufferFilter.Linear); + + EnsureFrameBuffer(); } public void Copy( @@ -276,39 +307,80 @@ namespace Ryujinx.Graphics.Gal.OpenGL int DstX1, int DstY1) { - if (Fbs.TryGetValue(SrcKey, out FrameBuffer SrcFb) && - Fbs.TryGetValue(DstKey, out FrameBuffer DstFb)) + if (Texture.TryGetImage(SrcKey, out ImageHandler SrcTex) && + Texture.TryGetImage(DstKey, out ImageHandler DstTex)) { - GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, SrcFb.Handle); - GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DstFb.Handle); - - GL.Clear(ClearBufferMask.ColorBufferBit); + if (SrcTex.HasColor != DstTex.HasColor || + SrcTex.HasDepth != DstTex.HasDepth || + SrcTex.HasStencil != DstTex.HasStencil) + { + throw new NotImplementedException(); + } - GL.BlitFramebuffer( - SrcX0, SrcY0, SrcX1, SrcY1, - DstX0, DstY0, DstX1, DstY1, - ClearBufferMask.ColorBufferBit, - BlitFramebufferFilter.Linear); + 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(); + } } -} + } public void GetBufferData(long Key, Action<byte[]> Callback) { - if (Fbs.TryGetValue(Key, out FrameBuffer Fb)) + if (Texture.TryGetImage(Key, out ImageHandler Tex)) { - GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, Fb.Handle); + byte[] Data = new byte[Tex.Width * Tex.Height * ImageHandler.MaxBpp]; - byte[] Data = new byte[Fb.Width * Fb.Height * 4]; + GL.BindTexture(TextureTarget.Texture2D, Tex.Handle); - (PixelFormat Format, PixelType Type) = OGLEnumConverter.GetTextureFormat(GalTextureFormat.A8B8G8R8); - - GL.ReadPixels( - 0, + GL.GetTexImage( + TextureTarget.Texture2D, 0, - Fb.Width, - Fb.Height, - Format, - Type, + Tex.PixelFormat, + Tex.PixelType, Data); Callback(Data); @@ -319,83 +391,101 @@ namespace Ryujinx.Graphics.Gal.OpenGL long Key, int Width, int Height, - GalTextureFormat Format, byte[] Buffer) { - if (Fbs.TryGetValue(Key, out FrameBuffer Fb)) + if (Texture.TryGetImage(Key, out ImageHandler Tex)) { - GL.BindTexture(TextureTarget.Texture2D, Fb.TexHandle); + GL.BindTexture(TextureTarget.Texture2D, Tex.Handle); const int Level = 0; const int Border = 0; - const PixelInternalFormat InternalFmt = PixelInternalFormat.Rgba; - - (PixelFormat GlFormat, PixelType Type) = OGLEnumConverter.GetTextureFormat(Format); - GL.TexImage2D( TextureTarget.Texture2D, Level, - InternalFmt, + Tex.InternalFormat, Width, Height, Border, - GlFormat, - Type, + Tex.PixelFormat, + Tex.PixelType, Buffer); } } - private void CreateRawFb(int Width, int Height) + private void EnsureFrameBuffer() { - if (RawFb == null) + if (DummyFrameBuffer == 0) { - RawFb = new FrameBuffer(Width, Height, false); - - SetupTexture(RawFb.TexHandle, Width, Height); + DummyFrameBuffer = GL.GenFramebuffer(); + } - RawFb.Width = Width; - RawFb.Height = Height; + GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DummyFrameBuffer); - GL.BindFramebuffer(FramebufferTarget.Framebuffer, RawFb.Handle); + GL.DrawBuffers(8, DrawBuffers); + } + private void Attach(ref int OldHandle, int NewHandle, FramebufferAttachment FbAttachment) + { + if (OldHandle != NewHandle) + { GL.FramebufferTexture( - FramebufferTarget.Framebuffer, - FramebufferAttachment.ColorAttachment0, - RawFb.TexHandle, + FramebufferTarget.DrawFramebuffer, + FbAttachment, + NewHandle, 0); - GL.Viewport(0, 0, Width, Height); + OldHandle = NewHandle; } } - private void SetupTexture(int Handle, int Width, int Height) + private void CopyTextures( + int SrcX0, + int SrcY0, + int SrcX1, + int SrcY1, + int DstX0, + int DstY0, + int DstX1, + int DstY1, + int SrcTexture, + int DstTexture, + FramebufferAttachment Attachment, + ClearBufferMask Mask, + bool Color) { - GL.BindTexture(TextureTarget.Texture2D, Handle); + if (SrcFb == 0) SrcFb = GL.GenFramebuffer(); + if (DstFb == 0) DstFb = GL.GenFramebuffer(); - const int MinFilter = (int)TextureMinFilter.Linear; - const int MagFilter = (int)TextureMagFilter.Linear; + GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, SrcFb); + GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DstFb); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, MinFilter); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, MagFilter); + GL.FramebufferTexture( + FramebufferTarget.ReadFramebuffer, + Attachment, + SrcTexture, + 0); - (PixelFormat Format, PixelType Type) = OGLEnumConverter.GetTextureFormat(GalTextureFormat.A8B8G8R8); + GL.FramebufferTexture( + FramebufferTarget.DrawFramebuffer, + Attachment, + DstTexture, + 0); + + if (Color) + { + GL.DrawBuffer(DrawBufferMode.ColorAttachment0); + } - const PixelInternalFormat InternalFmt = PixelInternalFormat.Rgba; + GL.Clear(Mask); - const int Level = 0; - const int Border = 0; + GL.BlitFramebuffer( + SrcX0, SrcY0, SrcX1, SrcY1, + DstX0, DstY0, DstX1, DstY1, + Mask, + Color ? BlitFramebufferFilter.Linear : BlitFramebufferFilter.Nearest); - GL.TexImage2D( - TextureTarget.Texture2D, - Level, - InternalFmt, - Width, - Height, - Border, - Format, - Type, - IntPtr.Zero); + EnsureFrameBuffer(); } } }
\ No newline at end of file |
