From ce1d5be212e6f71a7ca32c3bd7b48e32d9f51b9a Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Sat, 8 Sep 2018 14:51:50 -0300 Subject: Move GPU emulation from Ryujinx.HLE to Ryujinx.Graphics and misc changes (#402) * Move GPU LLE emulation from HLE to Graphics * Graphics: Move Gal/Texture to Texture * Remove Engines/ directory and namespace * Use tables for image formats * Abstract OpCode decoding * Simplify image table * Do not leak Read* symbols in TextureReader * Fixups * Rename IGalFrameBuffer -> IGalRenderTarget * Remove MaxBpp hardcoded value * Change yet again texture data and add G8R8 flipping * Rename GalFrameBufferFormat to GalSurfaceFormat * Unident EnsureSetup in ImageHandler * Add IsCompressed * Address some feedback --- Ryujinx.Graphics/Gal/OpenGL/ImageHandler.cs | 143 ++++--- Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs | 111 +++--- Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs | 496 ----------------------- Ryujinx.Graphics/Gal/OpenGL/OGLRenderTarget.cs | 497 ++++++++++++++++++++++++ Ryujinx.Graphics/Gal/OpenGL/OGLRenderer.cs | 4 +- Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs | 99 +++-- 6 files changed, 690 insertions(+), 660 deletions(-) delete mode 100644 Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs create mode 100644 Ryujinx.Graphics/Gal/OpenGL/OGLRenderTarget.cs (limited to 'Ryujinx.Graphics/Gal/OpenGL') diff --git a/Ryujinx.Graphics/Gal/OpenGL/ImageHandler.cs b/Ryujinx.Graphics/Gal/OpenGL/ImageHandler.cs index 74f18dcd..dda82538 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/ImageHandler.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/ImageHandler.cs @@ -1,13 +1,11 @@ using OpenTK.Graphics.OpenGL; +using Ryujinx.Graphics.Texture; using System; namespace Ryujinx.Graphics.Gal.OpenGL { class ImageHandler { - //TODO: Use a variable value here - public const int MaxBpp = 16; - private static int CopyBuffer = 0; private static int CopyBufferSize = 0; @@ -38,87 +36,124 @@ namespace Ryujinx.Graphics.Gal.OpenGL this.Image = Image; } - public void EnsureSetup(GalImage Image) + public void EnsureSetup(GalImage NewImage) { - if (Width != Image.Width || - Height != Image.Height || - Format != Image.Format || - !Initialized) + if (Width == NewImage.Width && + Height == NewImage.Height && + Format == NewImage.Format && + Initialized) { - (PixelInternalFormat InternalFormat, PixelFormat PixelFormat, PixelType PixelType) = - OGLEnumConverter.GetImageFormat(Image.Format); + return; + } - GL.BindTexture(TextureTarget.Texture2D, Handle); + PixelInternalFormat InternalFmt; + PixelFormat PixelFormat; + PixelType PixelType; - if (Initialized) - { - if (CopyBuffer == 0) - { - CopyBuffer = GL.GenBuffer(); - } + if (ImageUtils.IsCompressed(NewImage.Format)) + { + InternalFmt = (PixelInternalFormat)OGLEnumConverter.GetCompressedImageFormat(NewImage.Format); + + PixelFormat = default(PixelFormat); + PixelType = default(PixelType); + } + else + { + (InternalFmt, PixelFormat, PixelType) = OGLEnumConverter.GetImageFormat(NewImage.Format); + } - int MaxWidth = Math.Max(Image.Width, Width); - int MaxHeight = Math.Max(Image.Height, Height); + GL.BindTexture(TextureTarget.Texture2D, Handle); - int CurrentSize = MaxWidth * MaxHeight * MaxBpp; + if (Initialized) + { + if (CopyBuffer == 0) + { + CopyBuffer = GL.GenBuffer(); + } - GL.BindBuffer(BufferTarget.PixelPackBuffer, CopyBuffer); - GL.BindBuffer(BufferTarget.PixelUnpackBuffer, CopyBuffer); + int CurrentSize = Math.Max(ImageUtils.GetSize(NewImage), + ImageUtils.GetSize(Image)); - if (CopyBufferSize < CurrentSize) - { - CopyBufferSize = CurrentSize; + GL.BindBuffer(BufferTarget.PixelPackBuffer, CopyBuffer); + GL.BindBuffer(BufferTarget.PixelUnpackBuffer, CopyBuffer); - GL.BufferData(BufferTarget.PixelPackBuffer, CurrentSize, IntPtr.Zero, BufferUsageHint.StreamCopy); - } + if (CopyBufferSize < CurrentSize) + { + CopyBufferSize = CurrentSize; + GL.BufferData(BufferTarget.PixelPackBuffer, CurrentSize, IntPtr.Zero, BufferUsageHint.StreamCopy); + } + + if (ImageUtils.IsCompressed(Image.Format)) + { + GL.GetCompressedTexImage(TextureTarget.Texture2D, 0, IntPtr.Zero); + } + else + { GL.GetTexImage(TextureTarget.Texture2D, 0, this.PixelFormat, this.PixelType, IntPtr.Zero); + } - GL.DeleteTexture(Handle); + GL.DeleteTexture(Handle); - Handle = GL.GenTexture(); + Handle = GL.GenTexture(); - GL.BindTexture(TextureTarget.Texture2D, Handle); - } + GL.BindTexture(TextureTarget.Texture2D, Handle); + } - const int MinFilter = (int)TextureMinFilter.Linear; - const int MagFilter = (int)TextureMagFilter.Linear; + const int MinFilter = (int)TextureMinFilter.Linear; + const int MagFilter = (int)TextureMagFilter.Linear; - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, MinFilter); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, MagFilter); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, MinFilter); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, MagFilter); - const int Level = 0; - const int Border = 0; + const int Level = 0; + const int Border = 0; + if (ImageUtils.IsCompressed(NewImage.Format)) + { + Console.WriteLine("Hit"); + + GL.CompressedTexImage2D( + TextureTarget.Texture2D, + Level, + (InternalFormat)InternalFmt, + NewImage.Width, + NewImage.Height, + Border, + ImageUtils.GetSize(NewImage), + IntPtr.Zero); + } + else + { GL.TexImage2D( TextureTarget.Texture2D, Level, - InternalFormat, - Image.Width, - Image.Height, + InternalFmt, + NewImage.Width, + NewImage.Height, Border, PixelFormat, PixelType, IntPtr.Zero); + } - if (Initialized) - { - GL.BindBuffer(BufferTarget.PixelPackBuffer, 0); - GL.BindBuffer(BufferTarget.PixelUnpackBuffer, 0); - } + if (Initialized) + { + GL.BindBuffer(BufferTarget.PixelPackBuffer, 0); + GL.BindBuffer(BufferTarget.PixelUnpackBuffer, 0); + } - this.Image = Image; + Image = NewImage; - this.InternalFormat = InternalFormat; - this.PixelFormat = PixelFormat; - this.PixelType = PixelType; + this.InternalFormat = InternalFmt; + this.PixelFormat = PixelFormat; + this.PixelType = PixelType; - Initialized = true; - } + Initialized = true; } - public bool HasColor { get => ImageFormatConverter.HasColor(Format); } - public bool HasDepth { get => ImageFormatConverter.HasDepth(Format); } - public bool HasStencil { get => ImageFormatConverter.HasStencil(Format); } + public bool HasColor => ImageUtils.HasColor(Image.Format); + public bool HasDepth => ImageUtils.HasDepth(Image.Format); + public bool HasStencil => ImageUtils.HasStencil(Image.Format); } } diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs index 959d0e32..1d4f4cf7 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs @@ -129,52 +129,51 @@ namespace Ryujinx.Graphics.Gal.OpenGL { switch (Format) { - case GalImageFormat.R32G32B32A32_SFLOAT: return (PixelInternalFormat.Rgba32f, PixelFormat.Rgba, PixelType.Float); - case GalImageFormat.R32G32B32A32_SINT: return (PixelInternalFormat.Rgba32i, PixelFormat.RgbaInteger, PixelType.Int); - case GalImageFormat.R32G32B32A32_UINT: return (PixelInternalFormat.Rgba32ui, PixelFormat.RgbaInteger, PixelType.UnsignedInt); - case GalImageFormat.R16G16B16A16_SFLOAT: return (PixelInternalFormat.Rgba16f, PixelFormat.Rgba, PixelType.HalfFloat); - case GalImageFormat.R16G16B16A16_SINT: return (PixelInternalFormat.Rgba16i, PixelFormat.RgbaInteger, PixelType.Short); - case GalImageFormat.R16G16B16A16_UINT: return (PixelInternalFormat.Rgba16ui, PixelFormat.RgbaInteger, PixelType.UnsignedShort); - case GalImageFormat.R32G32_SFLOAT: return (PixelInternalFormat.Rg32f, PixelFormat.Rg, PixelType.Float); - case GalImageFormat.R32G32_SINT: return (PixelInternalFormat.Rg32i, PixelFormat.RgInteger, PixelType.Int); - case GalImageFormat.R32G32_UINT: return (PixelInternalFormat.Rg32ui, PixelFormat.RgInteger, PixelType.UnsignedInt); - case GalImageFormat.A8B8G8R8_SNORM_PACK32: return (PixelInternalFormat.Rgba8Snorm, PixelFormat.Rgba, PixelType.Byte); - case GalImageFormat.A8B8G8R8_UNORM_PACK32: return (PixelInternalFormat.Rgba8, PixelFormat.Rgba, PixelType.UnsignedByte); - case GalImageFormat.A8B8G8R8_SINT_PACK32: return (PixelInternalFormat.Rgba8i, PixelFormat.RgbaInteger, PixelType.Byte); - case GalImageFormat.A8B8G8R8_UINT_PACK32: return (PixelInternalFormat.Rgba8ui, PixelFormat.RgbaInteger, PixelType.UnsignedByte); - case GalImageFormat.A8B8G8R8_SRGB_PACK32: return (PixelInternalFormat.Srgb8Alpha8, PixelFormat.Rgba, PixelType.UnsignedByte); - case GalImageFormat.A2B10G10R10_UINT_PACK32: return (PixelInternalFormat.Rgb10A2ui, PixelFormat.RgbaInteger, PixelType.UnsignedInt2101010Reversed); - case GalImageFormat.A2B10G10R10_UNORM_PACK32: return (PixelInternalFormat.Rgb10A2, PixelFormat.Rgba, PixelType.UnsignedInt2101010Reversed); - case GalImageFormat.R32_SFLOAT: return (PixelInternalFormat.R32f, PixelFormat.Red, PixelType.Float); - case GalImageFormat.R32_SINT: return (PixelInternalFormat.R32i, PixelFormat.Red, PixelType.Int); - case GalImageFormat.R32_UINT: return (PixelInternalFormat.R32ui, PixelFormat.Red, PixelType.UnsignedInt); - case GalImageFormat.A1R5G5B5_UNORM_PACK16: return (PixelInternalFormat.Rgb5A1, PixelFormat.Rgba, PixelType.UnsignedShort5551); - case GalImageFormat.B5G6R5_UNORM_PACK16: return (PixelInternalFormat.Rgba, PixelFormat.Rgb, PixelType.UnsignedShort565); - case GalImageFormat.R16G16_SFLOAT: return (PixelInternalFormat.Rg16f, PixelFormat.Rg, PixelType.HalfFloat); - case GalImageFormat.R16G16_SINT: return (PixelInternalFormat.Rg16i, PixelFormat.RgInteger, PixelType.Short); - case GalImageFormat.R16G16_SNORM: return (PixelInternalFormat.Rg16Snorm, PixelFormat.Rg, PixelType.Byte); - case GalImageFormat.R16G16_UNORM: return (PixelInternalFormat.Rg16, PixelFormat.Rg, PixelType.UnsignedShort); - case GalImageFormat.R8G8_SINT: return (PixelInternalFormat.Rg8i, PixelFormat.RgInteger, PixelType.Byte); - case GalImageFormat.R8G8_SNORM: return (PixelInternalFormat.Rg8Snorm, PixelFormat.Rg, PixelType.Byte); - case GalImageFormat.R8G8_UINT: return (PixelInternalFormat.Rg8ui, PixelFormat.RgInteger, PixelType.UnsignedByte); - case GalImageFormat.R8G8_UNORM: return (PixelInternalFormat.Rg8, PixelFormat.Rg, PixelType.UnsignedByte); - case GalImageFormat.R16_SFLOAT: return (PixelInternalFormat.R16f, PixelFormat.Red, PixelType.HalfFloat); - case GalImageFormat.R16_SINT: return (PixelInternalFormat.R16i, PixelFormat.RedInteger, PixelType.Short); - case GalImageFormat.R16_SNORM: return (PixelInternalFormat.R16Snorm, PixelFormat.Red, PixelType.Byte); - case GalImageFormat.R16_UINT: return (PixelInternalFormat.R16ui, PixelFormat.RedInteger, PixelType.UnsignedShort); - case GalImageFormat.R16_UNORM: return (PixelInternalFormat.R16, PixelFormat.Red, PixelType.UnsignedShort); - case GalImageFormat.R8_SINT: return (PixelInternalFormat.R8i, PixelFormat.RedInteger, PixelType.Byte); - case GalImageFormat.R8_SNORM: return (PixelInternalFormat.R8Snorm, PixelFormat.Red, PixelType.Byte); - case GalImageFormat.R8_UINT: return (PixelInternalFormat.R8ui, PixelFormat.RedInteger, PixelType.UnsignedByte); - case GalImageFormat.R8_UNORM: return (PixelInternalFormat.R8, PixelFormat.Red, PixelType.UnsignedByte); - case GalImageFormat.B10G11R11_UFLOAT_PACK32: return (PixelInternalFormat.R11fG11fB10f, PixelFormat.Rgb, PixelType.UnsignedInt10F11F11FRev); - - case GalImageFormat.R4G4B4A4_UNORM_PACK16_REVERSED: return (PixelInternalFormat.Rgba4, PixelFormat.Rgba, PixelType.UnsignedShort4444Reversed); - - case GalImageFormat.D24_UNORM_S8_UINT: return (PixelInternalFormat.Depth24Stencil8, PixelFormat.DepthStencil, PixelType.UnsignedInt248); - case GalImageFormat.D32_SFLOAT: return (PixelInternalFormat.DepthComponent32f, PixelFormat.DepthComponent, PixelType.Float); - case GalImageFormat.D16_UNORM: return (PixelInternalFormat.DepthComponent16, PixelFormat.DepthComponent, PixelType.UnsignedShort); - case GalImageFormat.D32_SFLOAT_S8_UINT: return (PixelInternalFormat.Depth32fStencil8, PixelFormat.DepthStencil, PixelType.Float32UnsignedInt248Rev); + case GalImageFormat.R32G32B32A32 | GalImageFormat.Sfloat: return (PixelInternalFormat.Rgba32f, PixelFormat.Rgba, PixelType.Float); + case GalImageFormat.R32G32B32A32 | GalImageFormat.Sint: return (PixelInternalFormat.Rgba32i, PixelFormat.RgbaInteger, PixelType.Int); + case GalImageFormat.R32G32B32A32 | GalImageFormat.Uint: return (PixelInternalFormat.Rgba32ui, PixelFormat.RgbaInteger, PixelType.UnsignedInt); + case GalImageFormat.R16G16B16A16 | GalImageFormat.Sfloat: return (PixelInternalFormat.Rgba16f, PixelFormat.Rgba, PixelType.HalfFloat); + case GalImageFormat.R16G16B16A16 | GalImageFormat.Sint: return (PixelInternalFormat.Rgba16i, PixelFormat.RgbaInteger, PixelType.Short); + case GalImageFormat.R16G16B16A16 | GalImageFormat.Uint: return (PixelInternalFormat.Rgba16ui, PixelFormat.RgbaInteger, PixelType.UnsignedShort); + case GalImageFormat.R32G32 | GalImageFormat.Sfloat: return (PixelInternalFormat.Rg32f, PixelFormat.Rg, PixelType.Float); + case GalImageFormat.R32G32 | GalImageFormat.Sint: return (PixelInternalFormat.Rg32i, PixelFormat.RgInteger, PixelType.Int); + case GalImageFormat.R32G32 | GalImageFormat.Uint: return (PixelInternalFormat.Rg32ui, PixelFormat.RgInteger, PixelType.UnsignedInt); + case GalImageFormat.A8B8G8R8 | GalImageFormat.Snorm: return (PixelInternalFormat.Rgba8Snorm, PixelFormat.Rgba, PixelType.Byte); + case GalImageFormat.A8B8G8R8 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba8, PixelFormat.Rgba, PixelType.UnsignedByte); + case GalImageFormat.A8B8G8R8 | GalImageFormat.Sint: return (PixelInternalFormat.Rgba8i, PixelFormat.RgbaInteger, PixelType.Byte); + case GalImageFormat.A8B8G8R8 | GalImageFormat.Uint: return (PixelInternalFormat.Rgba8ui, PixelFormat.RgbaInteger, PixelType.UnsignedByte); + case GalImageFormat.A8B8G8R8_SRGB: return (PixelInternalFormat.Srgb8Alpha8, PixelFormat.Rgba, PixelType.UnsignedByte); + case GalImageFormat.A4B4G4R4 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba4, PixelFormat.Rgba, PixelType.UnsignedShort4444Reversed); + case GalImageFormat.A2B10G10R10 | GalImageFormat.Uint: return (PixelInternalFormat.Rgb10A2ui, PixelFormat.RgbaInteger, PixelType.UnsignedInt2101010Reversed); + case GalImageFormat.A2B10G10R10 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgb10A2, PixelFormat.Rgba, PixelType.UnsignedInt2101010Reversed); + case GalImageFormat.R32 | GalImageFormat.Sfloat: return (PixelInternalFormat.R32f, PixelFormat.Red, PixelType.Float); + case GalImageFormat.R32 | GalImageFormat.Sint: return (PixelInternalFormat.R32i, PixelFormat.Red, PixelType.Int); + case GalImageFormat.R32 | GalImageFormat.Uint: return (PixelInternalFormat.R32ui, PixelFormat.Red, PixelType.UnsignedInt); + case GalImageFormat.A1R5G5B5 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgb5A1, PixelFormat.Rgba, PixelType.UnsignedShort5551); + case GalImageFormat.B5G6R5 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba, PixelFormat.Rgb, PixelType.UnsignedShort565); + case GalImageFormat.R16G16 | GalImageFormat.Sfloat: return (PixelInternalFormat.Rg16f, PixelFormat.Rg, PixelType.HalfFloat); + case GalImageFormat.R16G16 | GalImageFormat.Sint: return (PixelInternalFormat.Rg16i, PixelFormat.RgInteger, PixelType.Short); + case GalImageFormat.R16G16 | GalImageFormat.Snorm: return (PixelInternalFormat.Rg16Snorm, PixelFormat.Rg, PixelType.Byte); + case GalImageFormat.R16G16 | GalImageFormat.Unorm: return (PixelInternalFormat.Rg16, PixelFormat.Rg, PixelType.UnsignedShort); + case GalImageFormat.R8G8 | GalImageFormat.Sint: return (PixelInternalFormat.Rg8i, PixelFormat.RgInteger, PixelType.Byte); + case GalImageFormat.R8G8 | GalImageFormat.Snorm: return (PixelInternalFormat.Rg8Snorm, PixelFormat.Rg, PixelType.Byte); + case GalImageFormat.R8G8 | GalImageFormat.Uint: return (PixelInternalFormat.Rg8ui, PixelFormat.RgInteger, PixelType.UnsignedByte); + case GalImageFormat.R8G8 | GalImageFormat.Unorm: return (PixelInternalFormat.Rg8, PixelFormat.Rg, PixelType.UnsignedByte); + case GalImageFormat.R16 | GalImageFormat.Sfloat: return (PixelInternalFormat.R16f, PixelFormat.Red, PixelType.HalfFloat); + case GalImageFormat.R16 | GalImageFormat.Sint: return (PixelInternalFormat.R16i, PixelFormat.RedInteger, PixelType.Short); + case GalImageFormat.R16 | GalImageFormat.Snorm: return (PixelInternalFormat.R16Snorm, PixelFormat.Red, PixelType.Byte); + case GalImageFormat.R16 | GalImageFormat.Uint: return (PixelInternalFormat.R16ui, PixelFormat.RedInteger, PixelType.UnsignedShort); + case GalImageFormat.R16 | GalImageFormat.Unorm: return (PixelInternalFormat.R16, PixelFormat.Red, PixelType.UnsignedShort); + case GalImageFormat.R8 | GalImageFormat.Sint: return (PixelInternalFormat.R8i, PixelFormat.RedInteger, PixelType.Byte); + case GalImageFormat.R8 | GalImageFormat.Snorm: return (PixelInternalFormat.R8Snorm, PixelFormat.Red, PixelType.Byte); + case GalImageFormat.R8 | GalImageFormat.Uint: return (PixelInternalFormat.R8ui, PixelFormat.RedInteger, PixelType.UnsignedByte); + case GalImageFormat.R8 | GalImageFormat.Unorm: return (PixelInternalFormat.R8, PixelFormat.Red, PixelType.UnsignedByte); + case GalImageFormat.B10G11R11 | GalImageFormat.Sfloat: return (PixelInternalFormat.R11fG11fB10f, PixelFormat.Rgb, PixelType.UnsignedInt10F11F11FRev); + + case GalImageFormat.D24_S8 | GalImageFormat.Unorm: return (PixelInternalFormat.Depth24Stencil8, PixelFormat.DepthStencil, PixelType.UnsignedInt248); + case GalImageFormat.D32 | GalImageFormat.Sfloat: return (PixelInternalFormat.DepthComponent32f, PixelFormat.DepthComponent, PixelType.Float); + case GalImageFormat.D16 | GalImageFormat.Unorm: return (PixelInternalFormat.DepthComponent16, PixelFormat.DepthComponent, PixelType.UnsignedShort); + case GalImageFormat.D32_S8 | GalImageFormat.Uint: return (PixelInternalFormat.Depth32fStencil8, PixelFormat.DepthStencil, PixelType.Float32UnsignedInt248Rev); } throw new NotImplementedException(Format.ToString()); @@ -184,16 +183,16 @@ namespace Ryujinx.Graphics.Gal.OpenGL { switch (Format) { - case GalImageFormat.BC6H_UFLOAT_BLOCK: return InternalFormat.CompressedRgbBptcUnsignedFloat; - case GalImageFormat.BC6H_SFLOAT_BLOCK: return InternalFormat.CompressedRgbBptcSignedFloat; - case GalImageFormat.BC7_UNORM_BLOCK: return InternalFormat.CompressedRgbaBptcUnorm; - case GalImageFormat.BC1_RGBA_UNORM_BLOCK: return InternalFormat.CompressedRgbaS3tcDxt1Ext; - case GalImageFormat.BC2_UNORM_BLOCK: return InternalFormat.CompressedRgbaS3tcDxt3Ext; - case GalImageFormat.BC3_UNORM_BLOCK: return InternalFormat.CompressedRgbaS3tcDxt5Ext; - case GalImageFormat.BC4_SNORM_BLOCK: return InternalFormat.CompressedSignedRedRgtc1; - case GalImageFormat.BC4_UNORM_BLOCK: return InternalFormat.CompressedRedRgtc1; - case GalImageFormat.BC5_SNORM_BLOCK: return InternalFormat.CompressedSignedRgRgtc2; - case GalImageFormat.BC5_UNORM_BLOCK: return InternalFormat.CompressedRgRgtc2; + case GalImageFormat.BC6H_UF16 | GalImageFormat.Unorm: return InternalFormat.CompressedRgbBptcUnsignedFloat; + case GalImageFormat.BC6H_SF16 | GalImageFormat.Unorm: return InternalFormat.CompressedRgbBptcSignedFloat; + case GalImageFormat.BC7 | GalImageFormat.Unorm: return InternalFormat.CompressedRgbaBptcUnorm; + case GalImageFormat.BC1_RGBA | GalImageFormat.Unorm: return InternalFormat.CompressedRgbaS3tcDxt1Ext; + case GalImageFormat.BC2 | GalImageFormat.Unorm: return InternalFormat.CompressedRgbaS3tcDxt3Ext; + case GalImageFormat.BC3 | GalImageFormat.Unorm: return InternalFormat.CompressedRgbaS3tcDxt5Ext; + case GalImageFormat.BC4 | GalImageFormat.Snorm: return InternalFormat.CompressedSignedRedRgtc1; + case GalImageFormat.BC4 | GalImageFormat.Unorm: return InternalFormat.CompressedRedRgtc1; + case GalImageFormat.BC5 | GalImageFormat.Snorm: return InternalFormat.CompressedSignedRgRgtc2; + case GalImageFormat.BC5 | GalImageFormat.Unorm: return InternalFormat.CompressedRgRgtc2; } throw new NotImplementedException(Format.ToString()); diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs deleted file mode 100644 index 12239c4f..00000000 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs +++ /dev/null @@ -1,496 +0,0 @@ -using OpenTK.Graphics.OpenGL; -using System; - -namespace Ryujinx.Graphics.Gal.OpenGL -{ - class OGLFrameBuffer : IGalFrameBuffer - { - private struct Rect - { - public int X { get; private set; } - public int Y { get; private set; } - public int Width { get; private set; } - public int Height { get; private set; } - - public Rect(int X, int Y, int Width, int Height) - { - this.X = X; - this.Y = Y; - this.Width = Width; - this.Height = Height; - } - } - - private const int NativeWidth = 1280; - private const int NativeHeight = 720; - - private const GalImageFormat RawFormat = GalImageFormat.A8B8G8R8_UNORM_PACK32; - - private OGLTexture Texture; - - private ImageHandler RawTex; - private ImageHandler ReadTex; - - private Rect Viewport; - private Rect Window; - - private bool FlipX; - private bool FlipY; - - private int CropTop; - private int CropLeft; - private int CropRight; - private int CropBottom; - - //This framebuffer is used to attach guest rendertargets, - //think of it as a dummy OpenGL VAO - private int DummyFrameBuffer; - - //These framebuffers are used to blit images - private int SrcFb; - private int DstFb; - - //Holds current attachments, used to avoid unnecesary calls to OpenGL - private int[] ColorAttachments; - - private int DepthAttachment; - private int StencilAttachment; - - public OGLFrameBuffer(OGLTexture Texture) - { - ColorAttachments = new int[8]; - - this.Texture = Texture; - } - - public void BindColor(long Key, int Attachment) - { - if (Texture.TryGetImage(Key, out ImageHandler Tex)) - { - EnsureFrameBuffer(); - - Attach(ref ColorAttachments[Attachment], Tex.Handle, FramebufferAttachment.ColorAttachment0 + Attachment); - } - else - { - UnbindColor(Attachment); - } - } - - public void UnbindColor(int Attachment) - { - EnsureFrameBuffer(); - - Attach(ref ColorAttachments[Attachment], 0, FramebufferAttachment.ColorAttachment0 + Attachment); - } - - public void BindZeta(long Key) - { - if (Texture.TryGetImage(Key, out ImageHandler Tex)) - { - EnsureFrameBuffer(); - - 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); - - Attach(ref StencilAttachment, 0, FramebufferAttachment.StencilAttachment); - } - else if (Tex.HasStencil) - { - Attach(ref DepthAttachment, 0, FramebufferAttachment.DepthAttachment); - - Attach(ref StencilAttachment, Tex.Handle, FramebufferAttachment.StencilAttachment); - } - else - { - throw new InvalidOperationException(); - } - } - else - { - UnbindZeta(); - } - } - - public void UnbindZeta() - { - EnsureFrameBuffer(); - - if (DepthAttachment != 0 || - StencilAttachment != 0) - { - GL.FramebufferTexture( - FramebufferTarget.DrawFramebuffer, - FramebufferAttachment.DepthStencilAttachment, - 0, - 0); - - DepthAttachment = 0; - - StencilAttachment = 0; - } - } - - public void BindTexture(long Key, int Index) - { - if (Texture.TryGetImage(Key, out ImageHandler Tex)) - { - GL.ActiveTexture(TextureUnit.Texture0 + Index); - - GL.BindTexture(TextureTarget.Texture2D, Tex.Handle); - } - } - - public void Set(long Key) - { - if (Texture.TryGetImage(Key, out ImageHandler Tex)) - { - ReadTex = Tex; - } - } - - public void Set(byte[] Data, int Width, int Height) - { - if (RawTex == null) - { - RawTex = new ImageHandler(); - } - - RawTex.EnsureSetup(new GalImage(Width, Height, RawFormat)); - - GL.BindTexture(TextureTarget.Texture2D, RawTex.Handle); - - GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, Width, Height, RawTex.PixelFormat, RawTex.PixelType, Data); - - ReadTex = RawTex; - } - - public void SetMap(int[] Map) - { - if (Map != null && Map.Length > 0) - { - DrawBuffersEnum[] Mode = new DrawBuffersEnum[Map.Length]; - - for (int i = 0; i < Map.Length; i++) - { - Mode[i] = DrawBuffersEnum.ColorAttachment0 + Map[i]; - } - - GL.DrawBuffers(Mode.Length, Mode); - } - else - { - GL.DrawBuffer(DrawBufferMode.ColorAttachment0); - } - } - - public void SetTransform(bool FlipX, bool FlipY, int Top, int Left, int Right, int Bottom) - { - this.FlipX = FlipX; - this.FlipY = FlipY; - - CropTop = Top; - CropLeft = Left; - CropRight = Right; - CropBottom = Bottom; - } - - public void SetWindowSize(int Width, int Height) - { - Window = new Rect(0, 0, Width, Height); - } - - public void SetViewport(int X, int Y, int Width, int Height) - { - Viewport = new Rect(X, Y, Width, Height); - - SetViewport(Viewport); - } - - private void SetViewport(Rect Viewport) - { - GL.Viewport( - Viewport.X, - Viewport.Y, - Viewport.Width, - Viewport.Height); - } - - public void Render() - { - if (ReadTex == null) - { - return; - } - - int SrcX0, SrcX1, SrcY0, SrcY1; - - 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)); - - 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 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; - - if (SrcFb == 0) SrcFb = GL.GenFramebuffer(); - - GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, 0); - - GL.Viewport(0, 0, Window.Width, Window.Height); - - GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, SrcFb); - - 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( - long SrcKey, - long DstKey, - int SrcX0, - int SrcY0, - int SrcX1, - int SrcY1, - int DstX0, - int DstY0, - int DstX1, - int DstY1) - { - if (Texture.TryGetImage(SrcKey, out ImageHandler SrcTex) && - Texture.TryGetImage(DstKey, out ImageHandler DstTex)) - { - if (SrcTex.HasColor != DstTex.HasColor || - SrcTex.HasDepth != DstTex.HasDepth || - SrcTex.HasStencil != DstTex.HasStencil) - { - throw new NotImplementedException(); - } - - 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 Callback) - { - if (Texture.TryGetImage(Key, out ImageHandler Tex)) - { - byte[] Data = new byte[Tex.Width * Tex.Height * ImageHandler.MaxBpp]; - - GL.BindTexture(TextureTarget.Texture2D, Tex.Handle); - - GL.GetTexImage( - TextureTarget.Texture2D, - 0, - Tex.PixelFormat, - Tex.PixelType, - Data); - - Callback(Data); - } - } - - public void SetBufferData( - long Key, - int Width, - int Height, - byte[] Buffer) - { - if (Texture.TryGetImage(Key, out ImageHandler Tex)) - { - GL.BindTexture(TextureTarget.Texture2D, Tex.Handle); - - const int Level = 0; - const int Border = 0; - - GL.TexImage2D( - TextureTarget.Texture2D, - Level, - Tex.InternalFormat, - Width, - Height, - Border, - Tex.PixelFormat, - Tex.PixelType, - Buffer); - } - } - - private void EnsureFrameBuffer() - { - if (DummyFrameBuffer == 0) - { - DummyFrameBuffer = GL.GenFramebuffer(); - } - - GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DummyFrameBuffer); - } - - private void Attach(ref int OldHandle, int NewHandle, FramebufferAttachment FbAttachment) - { - if (OldHandle != NewHandle) - { - GL.FramebufferTexture( - FramebufferTarget.DrawFramebuffer, - FbAttachment, - NewHandle, - 0); - - OldHandle = NewHandle; - } - } - - 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) - { - if (SrcFb == 0) SrcFb = GL.GenFramebuffer(); - if (DstFb == 0) DstFb = GL.GenFramebuffer(); - - GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, SrcFb); - GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DstFb); - - GL.FramebufferTexture( - FramebufferTarget.ReadFramebuffer, - Attachment, - SrcTexture, - 0); - - GL.FramebufferTexture( - FramebufferTarget.DrawFramebuffer, - Attachment, - DstTexture, - 0); - - if (Color) - { - GL.DrawBuffer(DrawBufferMode.ColorAttachment0); - } - - GL.Clear(Mask); - - GL.BlitFramebuffer( - SrcX0, SrcY0, SrcX1, SrcY1, - DstX0, DstY0, DstX1, DstY1, - Mask, - Color ? BlitFramebufferFilter.Linear : BlitFramebufferFilter.Nearest); - - EnsureFrameBuffer(); - } - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLRenderTarget.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLRenderTarget.cs new file mode 100644 index 00000000..99bfa350 --- /dev/null +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLRenderTarget.cs @@ -0,0 +1,497 @@ +using OpenTK.Graphics.OpenGL; +using Ryujinx.Graphics.Texture; +using System; + +namespace Ryujinx.Graphics.Gal.OpenGL +{ + class OGLRenderTarget : IGalRenderTarget + { + private struct Rect + { + public int X { get; private set; } + public int Y { get; private set; } + public int Width { get; private set; } + public int Height { get; private set; } + + public Rect(int X, int Y, int Width, int Height) + { + this.X = X; + this.Y = Y; + this.Width = Width; + this.Height = Height; + } + } + + private const int NativeWidth = 1280; + private const int NativeHeight = 720; + + private const GalImageFormat RawFormat = GalImageFormat.A8B8G8R8 | GalImageFormat.Unorm; + + private OGLTexture Texture; + + private ImageHandler RawTex; + private ImageHandler ReadTex; + + private Rect Viewport; + private Rect Window; + + private bool FlipX; + private bool FlipY; + + private int CropTop; + private int CropLeft; + private int CropRight; + private int CropBottom; + + //This framebuffer is used to attach guest rendertargets, + //think of it as a dummy OpenGL VAO + private int DummyFrameBuffer; + + //These framebuffers are used to blit images + private int SrcFb; + private int DstFb; + + //Holds current attachments, used to avoid unnecesary calls to OpenGL + private int[] ColorAttachments; + + private int DepthAttachment; + private int StencilAttachment; + + public OGLRenderTarget(OGLTexture Texture) + { + ColorAttachments = new int[8]; + + this.Texture = Texture; + } + + public void BindColor(long Key, int Attachment) + { + if (Texture.TryGetImage(Key, out ImageHandler Tex)) + { + EnsureFrameBuffer(); + + Attach(ref ColorAttachments[Attachment], Tex.Handle, FramebufferAttachment.ColorAttachment0 + Attachment); + } + else + { + UnbindColor(Attachment); + } + } + + public void UnbindColor(int Attachment) + { + EnsureFrameBuffer(); + + Attach(ref ColorAttachments[Attachment], 0, FramebufferAttachment.ColorAttachment0 + Attachment); + } + + public void BindZeta(long Key) + { + if (Texture.TryGetImage(Key, out ImageHandler Tex)) + { + EnsureFrameBuffer(); + + 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); + + Attach(ref StencilAttachment, 0, FramebufferAttachment.StencilAttachment); + } + else if (Tex.HasStencil) + { + Attach(ref DepthAttachment, 0, FramebufferAttachment.DepthAttachment); + + Attach(ref StencilAttachment, Tex.Handle, FramebufferAttachment.StencilAttachment); + } + else + { + throw new InvalidOperationException(); + } + } + else + { + UnbindZeta(); + } + } + + public void UnbindZeta() + { + EnsureFrameBuffer(); + + if (DepthAttachment != 0 || + StencilAttachment != 0) + { + GL.FramebufferTexture( + FramebufferTarget.DrawFramebuffer, + FramebufferAttachment.DepthStencilAttachment, + 0, + 0); + + DepthAttachment = 0; + + StencilAttachment = 0; + } + } + + public void BindTexture(long Key, int Index) + { + if (Texture.TryGetImage(Key, out ImageHandler Tex)) + { + GL.ActiveTexture(TextureUnit.Texture0 + Index); + + GL.BindTexture(TextureTarget.Texture2D, Tex.Handle); + } + } + + public void Set(long Key) + { + if (Texture.TryGetImage(Key, out ImageHandler Tex)) + { + ReadTex = Tex; + } + } + + public void Set(byte[] Data, int Width, int Height) + { + if (RawTex == null) + { + RawTex = new ImageHandler(); + } + + RawTex.EnsureSetup(new GalImage(Width, Height, RawFormat)); + + GL.BindTexture(TextureTarget.Texture2D, RawTex.Handle); + + GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, Width, Height, RawTex.PixelFormat, RawTex.PixelType, Data); + + ReadTex = RawTex; + } + + public void SetMap(int[] Map) + { + if (Map != null && Map.Length > 0) + { + DrawBuffersEnum[] Mode = new DrawBuffersEnum[Map.Length]; + + for (int i = 0; i < Map.Length; i++) + { + Mode[i] = DrawBuffersEnum.ColorAttachment0 + Map[i]; + } + + GL.DrawBuffers(Mode.Length, Mode); + } + else + { + GL.DrawBuffer(DrawBufferMode.ColorAttachment0); + } + } + + public void SetTransform(bool FlipX, bool FlipY, int Top, int Left, int Right, int Bottom) + { + this.FlipX = FlipX; + this.FlipY = FlipY; + + CropTop = Top; + CropLeft = Left; + CropRight = Right; + CropBottom = Bottom; + } + + public void SetWindowSize(int Width, int Height) + { + Window = new Rect(0, 0, Width, Height); + } + + public void SetViewport(int X, int Y, int Width, int Height) + { + Viewport = new Rect(X, Y, Width, Height); + + SetViewport(Viewport); + } + + private void SetViewport(Rect Viewport) + { + GL.Viewport( + Viewport.X, + Viewport.Y, + Viewport.Width, + Viewport.Height); + } + + public void Render() + { + if (ReadTex == null) + { + return; + } + + int SrcX0, SrcX1, SrcY0, SrcY1; + + 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)); + + 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 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; + + if (SrcFb == 0) SrcFb = GL.GenFramebuffer(); + + GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, 0); + + GL.Viewport(0, 0, Window.Width, Window.Height); + + GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, SrcFb); + + 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( + long SrcKey, + long DstKey, + int SrcX0, + int SrcY0, + int SrcX1, + int SrcY1, + int DstX0, + int DstY0, + int DstX1, + int DstY1) + { + if (Texture.TryGetImage(SrcKey, out ImageHandler SrcTex) && + Texture.TryGetImage(DstKey, out ImageHandler DstTex)) + { + if (SrcTex.HasColor != DstTex.HasColor || + SrcTex.HasDepth != DstTex.HasDepth || + SrcTex.HasStencil != DstTex.HasStencil) + { + throw new NotImplementedException(); + } + + 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 Callback) + { + if (Texture.TryGetImage(Key, out ImageHandler Tex)) + { + byte[] Data = new byte[ImageUtils.GetSize(Tex.Image)]; + + GL.BindTexture(TextureTarget.Texture2D, Tex.Handle); + + GL.GetTexImage( + TextureTarget.Texture2D, + 0, + Tex.PixelFormat, + Tex.PixelType, + Data); + + Callback(Data); + } + } + + public void SetBufferData( + long Key, + int Width, + int Height, + byte[] Buffer) + { + if (Texture.TryGetImage(Key, out ImageHandler Tex)) + { + GL.BindTexture(TextureTarget.Texture2D, Tex.Handle); + + const int Level = 0; + const int Border = 0; + + GL.TexImage2D( + TextureTarget.Texture2D, + Level, + Tex.InternalFormat, + Width, + Height, + Border, + Tex.PixelFormat, + Tex.PixelType, + Buffer); + } + } + + private void EnsureFrameBuffer() + { + if (DummyFrameBuffer == 0) + { + DummyFrameBuffer = GL.GenFramebuffer(); + } + + GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DummyFrameBuffer); + } + + private void Attach(ref int OldHandle, int NewHandle, FramebufferAttachment FbAttachment) + { + if (OldHandle != NewHandle) + { + GL.FramebufferTexture( + FramebufferTarget.DrawFramebuffer, + FbAttachment, + NewHandle, + 0); + + OldHandle = NewHandle; + } + } + + 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) + { + if (SrcFb == 0) SrcFb = GL.GenFramebuffer(); + if (DstFb == 0) DstFb = GL.GenFramebuffer(); + + GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, SrcFb); + GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DstFb); + + GL.FramebufferTexture( + FramebufferTarget.ReadFramebuffer, + Attachment, + SrcTexture, + 0); + + GL.FramebufferTexture( + FramebufferTarget.DrawFramebuffer, + Attachment, + DstTexture, + 0); + + if (Color) + { + GL.DrawBuffer(DrawBufferMode.ColorAttachment0); + } + + GL.Clear(Mask); + + GL.BlitFramebuffer( + SrcX0, SrcY0, SrcX1, SrcY1, + DstX0, DstY0, DstX1, DstY1, + Mask, + Color ? BlitFramebufferFilter.Linear : BlitFramebufferFilter.Nearest); + + EnsureFrameBuffer(); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLRenderer.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLRenderer.cs index 985f1086..a23541f3 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLRenderer.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLRenderer.cs @@ -7,7 +7,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL { public IGalConstBuffer Buffer { get; private set; } - public IGalFrameBuffer FrameBuffer { get; private set; } + public IGalRenderTarget RenderTarget { get; private set; } public IGalRasterizer Rasterizer { get; private set; } @@ -25,7 +25,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL Texture = new OGLTexture(); - FrameBuffer = new OGLFrameBuffer(Texture as OGLTexture); + RenderTarget = new OGLRenderTarget(Texture as OGLTexture); Rasterizer = new OGLRasterizer(); diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs index e4d4bd64..82f9c913 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs @@ -1,5 +1,5 @@ using OpenTK.Graphics.OpenGL; -using Ryujinx.Graphics.Gal.Texture; +using Ryujinx.Graphics.Texture; using System; namespace Ryujinx.Graphics.Gal.OpenGL @@ -39,7 +39,11 @@ namespace Ryujinx.Graphics.Gal.OpenGL const int Level = 0; //TODO: Support mipmap textures. const int Border = 0; - if (IsCompressedTextureFormat(Image.Format)) + GalImageFormat TypeLess = Image.Format & GalImageFormat.FormatMask; + + bool IsASTC = TypeLess >= GalImageFormat.ASTC_BEGIN && TypeLess <= GalImageFormat.ASTC_END; + + if (ImageUtils.IsCompressed(Image.Format) && !IsASTC) { InternalFormat InternalFmt = OGLEnumConverter.GetCompressedImageFormat(Image.Format); @@ -55,7 +59,8 @@ namespace Ryujinx.Graphics.Gal.OpenGL } else { - if (Image.Format >= GalImageFormat.ASTC_BEGIN && Image.Format <= GalImageFormat.ASTC_END) + //TODO: Use KHR_texture_compression_astc_hdr when available + if (IsASTC) { int TextureBlockWidth = GetAstcBlockWidth(Image.Format); int TextureBlockHeight = GetAstcBlockHeight(Image.Format); @@ -67,7 +72,17 @@ namespace Ryujinx.Graphics.Gal.OpenGL Image.Width, Image.Height, 1); - Image.Format = GalImageFormat.A8B8G8R8_UNORM_PACK32; + Image.Format = GalImageFormat.A8B8G8R8 | GalImageFormat.Unorm; + } + else if (TypeLess == GalImageFormat.G8R8) + { + Data = ImageConverter.G8R8ToR8G8( + Data, + Image.Width, + Image.Height, + 1); + + Image.Format = GalImageFormat.R8G8 | (Image.Format & GalImageFormat.FormatMask); } (PixelInternalFormat InternalFormat, PixelFormat Format, PixelType Type) = OGLEnumConverter.GetImageFormat(Image.Format); @@ -123,20 +138,20 @@ namespace Ryujinx.Graphics.Gal.OpenGL { switch (Format) { - case GalImageFormat.ASTC_4x4_UNORM_BLOCK: return 4; - case GalImageFormat.ASTC_5x5_UNORM_BLOCK: return 5; - case GalImageFormat.ASTC_6x6_UNORM_BLOCK: return 6; - case GalImageFormat.ASTC_8x8_UNORM_BLOCK: return 8; - case GalImageFormat.ASTC_10x10_UNORM_BLOCK: return 10; - case GalImageFormat.ASTC_12x12_UNORM_BLOCK: return 12; - case GalImageFormat.ASTC_5x4_UNORM_BLOCK: return 5; - case GalImageFormat.ASTC_6x5_UNORM_BLOCK: return 6; - case GalImageFormat.ASTC_8x6_UNORM_BLOCK: return 8; - case GalImageFormat.ASTC_10x8_UNORM_BLOCK: return 10; - case GalImageFormat.ASTC_12x10_UNORM_BLOCK: return 12; - case GalImageFormat.ASTC_8x5_UNORM_BLOCK: return 8; - case GalImageFormat.ASTC_10x5_UNORM_BLOCK: return 10; - case GalImageFormat.ASTC_10x6_UNORM_BLOCK: return 10; + case GalImageFormat.ASTC_4x4 | GalImageFormat.Unorm: return 4; + case GalImageFormat.ASTC_5x5 | GalImageFormat.Unorm: return 5; + case GalImageFormat.ASTC_6x6 | GalImageFormat.Unorm: return 6; + case GalImageFormat.ASTC_8x8 | GalImageFormat.Unorm: return 8; + case GalImageFormat.ASTC_10x10 | GalImageFormat.Unorm: return 10; + case GalImageFormat.ASTC_12x12 | GalImageFormat.Unorm: return 12; + case GalImageFormat.ASTC_5x4 | GalImageFormat.Unorm: return 5; + case GalImageFormat.ASTC_6x5 | GalImageFormat.Unorm: return 6; + case GalImageFormat.ASTC_8x6 | GalImageFormat.Unorm: return 8; + case GalImageFormat.ASTC_10x8 | GalImageFormat.Unorm: return 10; + case GalImageFormat.ASTC_12x10 | GalImageFormat.Unorm: return 12; + case GalImageFormat.ASTC_8x5 | GalImageFormat.Unorm: return 8; + case GalImageFormat.ASTC_10x5 | GalImageFormat.Unorm: return 10; + case GalImageFormat.ASTC_10x6 | GalImageFormat.Unorm: return 10; } throw new ArgumentException(nameof(Format)); @@ -146,20 +161,20 @@ namespace Ryujinx.Graphics.Gal.OpenGL { switch (Format) { - case GalImageFormat.ASTC_4x4_UNORM_BLOCK: return 4; - case GalImageFormat.ASTC_5x5_UNORM_BLOCK: return 5; - case GalImageFormat.ASTC_6x6_UNORM_BLOCK: return 6; - case GalImageFormat.ASTC_8x8_UNORM_BLOCK: return 8; - case GalImageFormat.ASTC_10x10_UNORM_BLOCK: return 10; - case GalImageFormat.ASTC_12x12_UNORM_BLOCK: return 12; - case GalImageFormat.ASTC_5x4_UNORM_BLOCK: return 4; - case GalImageFormat.ASTC_6x5_UNORM_BLOCK: return 5; - case GalImageFormat.ASTC_8x6_UNORM_BLOCK: return 6; - case GalImageFormat.ASTC_10x8_UNORM_BLOCK: return 8; - case GalImageFormat.ASTC_12x10_UNORM_BLOCK: return 10; - case GalImageFormat.ASTC_8x5_UNORM_BLOCK: return 5; - case GalImageFormat.ASTC_10x5_UNORM_BLOCK: return 5; - case GalImageFormat.ASTC_10x6_UNORM_BLOCK: return 6; + case GalImageFormat.ASTC_4x4 | GalImageFormat.Unorm: return 4; + case GalImageFormat.ASTC_5x5 | GalImageFormat.Unorm: return 5; + case GalImageFormat.ASTC_6x6 | GalImageFormat.Unorm: return 6; + case GalImageFormat.ASTC_8x8 | GalImageFormat.Unorm: return 8; + case GalImageFormat.ASTC_10x10 | GalImageFormat.Unorm: return 10; + case GalImageFormat.ASTC_12x12 | GalImageFormat.Unorm: return 12; + case GalImageFormat.ASTC_5x4 | GalImageFormat.Unorm: return 4; + case GalImageFormat.ASTC_6x5 | GalImageFormat.Unorm: return 5; + case GalImageFormat.ASTC_8x6 | GalImageFormat.Unorm: return 6; + case GalImageFormat.ASTC_10x8 | GalImageFormat.Unorm: return 8; + case GalImageFormat.ASTC_12x10 | GalImageFormat.Unorm: return 10; + case GalImageFormat.ASTC_8x5 | GalImageFormat.Unorm: return 5; + case GalImageFormat.ASTC_10x5 | GalImageFormat.Unorm: return 5; + case GalImageFormat.ASTC_10x6 | GalImageFormat.Unorm: return 6; } throw new ArgumentException(nameof(Format)); @@ -216,25 +231,5 @@ namespace Ryujinx.Graphics.Gal.OpenGL GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureBorderColor, Color); } - - private static bool IsCompressedTextureFormat(GalImageFormat Format) - { - switch (Format) - { - case GalImageFormat.BC6H_UFLOAT_BLOCK: - case GalImageFormat.BC6H_SFLOAT_BLOCK: - case GalImageFormat.BC7_UNORM_BLOCK: - case GalImageFormat.BC1_RGBA_UNORM_BLOCK: - case GalImageFormat.BC2_UNORM_BLOCK: - case GalImageFormat.BC3_UNORM_BLOCK: - case GalImageFormat.BC4_SNORM_BLOCK: - case GalImageFormat.BC4_UNORM_BLOCK: - case GalImageFormat.BC5_SNORM_BLOCK: - case GalImageFormat.BC5_UNORM_BLOCK: - return true; - } - - return false; - } } } -- cgit v1.2.3