diff --git a/Ryujinx.Graphics/Gal/GalFrameBufferFormat.cs b/Ryujinx.Graphics/Gal/GalFrameBufferFormat.cs new file mode 100644 index 000000000..3180aeff9 --- /dev/null +++ b/Ryujinx.Graphics/Gal/GalFrameBufferFormat.cs @@ -0,0 +1,68 @@ +namespace Ryujinx.Graphics.Gal +{ + public enum GalFrameBufferFormat + { + Bitmap = 0x1c, + Unknown1D = 0x1d, + RGBA32Float = 0xc0, + RGBA32Sint = 0xc1, + RGBA32Uint = 0xc2, + RGBX32Float = 0xc3, + RGBX32Sint = 0xc4, + RGBX32Uint = 0xc5, + RGBA16Unorm = 0xc6, + RGBA16Snorm = 0xc7, + RGBA16Sint = 0xc8, + RGBA16Uint = 0xc9, + RGBA16Float = 0xca, + RG32Float = 0xcb, + RG32Sint = 0xcc, + RG32Uint = 0xcd, + RGBX16Float = 0xce, + BGRA8Unorm = 0xcf, + BGRA8Srgb = 0xd0, + RGB10A2Unorm = 0xd1, + RGB10A2Uint = 0xd2, + RGBA8Unorm = 0xd5, + RGBA8Srgb = 0xd6, + RGBA8Snorm = 0xd7, + RGBA8Sint = 0xd8, + RGBA8Uint = 0xd9, + RG16Unorm = 0xda, + RG16Snorm = 0xdb, + RG16Sint = 0xdc, + RG16Uint = 0xdd, + RG16Float = 0xde, + BGR10A2Unorm = 0xdf, + R11G11B10Float = 0xe0, + R32Sint = 0xe3, + R32Uint = 0xe4, + R32Float = 0xe5, + BGRX8Unorm = 0xe6, + BGRX8Srgb = 0xe7, + B5G6R5Unorm = 0xe8, + BGR5A1Unorm = 0xe9, + RG8Unorm = 0xea, + RG8Snorm = 0xeb, + RG8Sint = 0xec, + RG8Uint = 0xed, + R16Unorm = 0xee, + R16Snorm = 0xef, + R16Sint = 0xf0, + R16Uint = 0xf1, + R16Float = 0xf2, + R8Unorm = 0xf3, + R8Snorm = 0xf4, + R8Sint = 0xf5, + R8Uint = 0xf6, + A8Unorm = 0xf7, + BGR5X1Unorm = 0xf8, + RGBX8Unorm = 0xf9, + RGBX8Srgb = 0xfa, + BGR5X1UnormUnknownFB = 0xfb, + BGR5X1UnormUnknownFC = 0xfc, + BGRX8UnormUnknownFD = 0xfd, + BGRX8UnormUnknownFE = 0xfe, + Y32UintUnknownFF = 0xff + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/GalTexture.cs b/Ryujinx.Graphics/Gal/GalImage.cs similarity index 61% rename from Ryujinx.Graphics/Gal/GalTexture.cs rename to Ryujinx.Graphics/Gal/GalImage.cs index 2c1be65b2..dc6f02e04 100644 --- a/Ryujinx.Graphics/Gal/GalTexture.cs +++ b/Ryujinx.Graphics/Gal/GalImage.cs @@ -1,25 +1,25 @@ namespace Ryujinx.Graphics.Gal { - public struct GalTexture + public struct GalImage { public int Width; public int Height; - public GalTextureFormat Format; + public GalImageFormat Format; public GalTextureSource XSource; public GalTextureSource YSource; public GalTextureSource ZSource; public GalTextureSource WSource; - public GalTexture( + public GalImage( int Width, int Height, - GalTextureFormat Format, - GalTextureSource XSource, - GalTextureSource YSource, - GalTextureSource ZSource, - GalTextureSource WSource) + GalImageFormat Format, + GalTextureSource XSource = GalTextureSource.Red, + GalTextureSource YSource = GalTextureSource.Green, + GalTextureSource ZSource = GalTextureSource.Blue, + GalTextureSource WSource = GalTextureSource.Alpha) { this.Width = Width; this.Height = Height; diff --git a/Ryujinx.Graphics/Gal/GalImageFormat.cs b/Ryujinx.Graphics/Gal/GalImageFormat.cs new file mode 100644 index 000000000..4e84067bb --- /dev/null +++ b/Ryujinx.Graphics/Gal/GalImageFormat.cs @@ -0,0 +1,204 @@ +namespace Ryujinx.Graphics.Gal +{ + //These are Vulkan-based enumerations, do not take them as Tegra values + public enum GalImageFormat + { + Undefined = 0, + + R4G4_UNORM_PACK8 = 1, + R4G4B4A4_UNORM_PACK16 = 2, + B4G4R4A4_UNORM_PACK16 = 3, + R5G6B5_UNORM_PACK16 = 4, + B5G6R5_UNORM_PACK16 = 5, + R5G5B5A1_UNORM_PACK16 = 6, + B5G5R5A1_UNORM_PACK16 = 7, + A1R5G5B5_UNORM_PACK16 = 8, + R8_UNORM = 9, + R8_SNORM = 10, + R8_USCALED = 11, + R8_SSCALED = 12, + R8_UINT = 13, + R8_SINT = 14, + R8_SRGB = 15, + R8G8_UNORM = 16, + R8G8_SNORM = 17, + R8G8_USCALED = 18, + R8G8_SSCALED = 19, + R8G8_UINT = 20, + R8G8_SINT = 21, + R8G8_SRGB = 22, + R8G8B8_UNORM = 23, + R8G8B8_SNORM = 24, + R8G8B8_USCALED = 25, + R8G8B8_SSCALED = 26, + R8G8B8_UINT = 27, + R8G8B8_SINT = 28, + R8G8B8_SRGB = 29, + B8G8R8_UNORM = 30, + B8G8R8_SNORM = 31, + B8G8R8_USCALED = 32, + B8G8R8_SSCALED = 33, + B8G8R8_UINT = 34, + B8G8R8_SINT = 35, + B8G8R8_SRGB = 36, + R8G8B8A8_UNORM = 37, + R8G8B8A8_SNORM = 38, + R8G8B8A8_USCALED = 39, + R8G8B8A8_SSCALED = 40, + R8G8B8A8_UINT = 41, + R8G8B8A8_SINT = 42, + R8G8B8A8_SRGB = 43, + B8G8R8A8_UNORM = 44, + B8G8R8A8_SNORM = 45, + B8G8R8A8_USCALED = 46, + B8G8R8A8_SSCALED = 47, + B8G8R8A8_UINT = 48, + B8G8R8A8_SINT = 49, + B8G8R8A8_SRGB = 50, + A8B8G8R8_UNORM_PACK32 = 51, + A8B8G8R8_SNORM_PACK32 = 52, + A8B8G8R8_USCALED_PACK32 = 53, + A8B8G8R8_SSCALED_PACK32 = 54, + A8B8G8R8_UINT_PACK32 = 55, + A8B8G8R8_SINT_PACK32 = 56, + A8B8G8R8_SRGB_PACK32 = 57, + A2R10G10B10_UNORM_PACK32 = 58, + A2R10G10B10_SNORM_PACK32 = 59, + A2R10G10B10_USCALED_PACK32 = 60, + A2R10G10B10_SSCALED_PACK32 = 61, + A2R10G10B10_UINT_PACK32 = 62, + A2R10G10B10_SINT_PACK32 = 63, + A2B10G10R10_UNORM_PACK32 = 64, + A2B10G10R10_SNORM_PACK32 = 65, + A2B10G10R10_USCALED_PACK32 = 66, + A2B10G10R10_SSCALED_PACK32 = 67, + A2B10G10R10_UINT_PACK32 = 68, + A2B10G10R10_SINT_PACK32 = 69, + R16_UNORM = 70, + R16_SNORM = 71, + R16_USCALED = 72, + R16_SSCALED = 73, + R16_UINT = 74, + R16_SINT = 75, + R16_SFLOAT = 76, + R16G16_UNORM = 77, + R16G16_SNORM = 78, + R16G16_USCALED = 79, + R16G16_SSCALED = 80, + R16G16_UINT = 81, + R16G16_SINT = 82, + R16G16_SFLOAT = 83, + R16G16B16_UNORM = 84, + R16G16B16_SNORM = 85, + R16G16B16_USCALED = 86, + R16G16B16_SSCALED = 87, + R16G16B16_UINT = 88, + R16G16B16_SINT = 89, + R16G16B16_SFLOAT = 90, + R16G16B16A16_UNORM = 91, + R16G16B16A16_SNORM = 92, + R16G16B16A16_USCALED = 93, + R16G16B16A16_SSCALED = 94, + R16G16B16A16_UINT = 95, + R16G16B16A16_SINT = 96, + R16G16B16A16_SFLOAT = 97, + R32_UINT = 98, + R32_SINT = 99, + R32_SFLOAT = 100, + R32G32_UINT = 101, + R32G32_SINT = 102, + R32G32_SFLOAT = 103, + R32G32B32_UINT = 104, + R32G32B32_SINT = 105, + R32G32B32_SFLOAT = 106, + R32G32B32A32_UINT = 107, + R32G32B32A32_SINT = 108, + R32G32B32A32_SFLOAT = 109, + R64_UINT = 110, + R64_SINT = 111, + R64_SFLOAT = 112, + R64G64_UINT = 113, + R64G64_SINT = 114, + R64G64_SFLOAT = 115, + R64G64B64_UINT = 116, + R64G64B64_SINT = 117, + R64G64B64_SFLOAT = 118, + R64G64B64A64_UINT = 119, + R64G64B64A64_SINT = 120, + R64G64B64A64_SFLOAT = 121, + B10G11R11_UFLOAT_PACK32 = 122, + E5B9G9R9_UFLOAT_PACK32 = 123, + D16_UNORM = 124, + X8_D24_UNORM_PACK32 = 125, + D32_SFLOAT = 126, + S8_UINT = 127, + D16_UNORM_S8_UINT = 128, + D24_UNORM_S8_UINT = 129, + D32_SFLOAT_S8_UINT = 130, + BC1_RGB_UNORM_BLOCK = 131, + BC1_RGB_SRGB_BLOCK = 132, + BC1_RGBA_UNORM_BLOCK = 133, + BC1_RGBA_SRGB_BLOCK = 134, + BC2_UNORM_BLOCK = 135, + BC2_SRGB_BLOCK = 136, + BC3_UNORM_BLOCK = 137, + BC3_SRGB_BLOCK = 138, + BC4_UNORM_BLOCK = 139, + BC4_SNORM_BLOCK = 140, + BC5_UNORM_BLOCK = 141, + BC5_SNORM_BLOCK = 142, + BC6H_UFLOAT_BLOCK = 143, + BC6H_SFLOAT_BLOCK = 144, + BC7_UNORM_BLOCK = 145, + BC7_SRGB_BLOCK = 146, + ETC2_R8G8B8_UNORM_BLOCK = 147, + ETC2_R8G8B8_SRGB_BLOCK = 148, + ETC2_R8G8B8A1_UNORM_BLOCK = 149, + ETC2_R8G8B8A1_SRGB_BLOCK = 150, + ETC2_R8G8B8A8_UNORM_BLOCK = 151, + ETC2_R8G8B8A8_SRGB_BLOCK = 152, + EAC_R11_UNORM_BLOCK = 153, + EAC_R11_SNORM_BLOCK = 154, + EAC_R11G11_UNORM_BLOCK = 155, + EAC_R11G11_SNORM_BLOCK = 156, + + ASTC_BEGIN = ASTC_4x4_UNORM_BLOCK, + + ASTC_4x4_UNORM_BLOCK = 157, + ASTC_4x4_SRGB_BLOCK = 158, + ASTC_5x4_UNORM_BLOCK = 159, + ASTC_5x4_SRGB_BLOCK = 160, + ASTC_5x5_UNORM_BLOCK = 161, + ASTC_5x5_SRGB_BLOCK = 162, + ASTC_6x5_UNORM_BLOCK = 163, + ASTC_6x5_SRGB_BLOCK = 164, + ASTC_6x6_UNORM_BLOCK = 165, + ASTC_6x6_SRGB_BLOCK = 166, + ASTC_8x5_UNORM_BLOCK = 167, + ASTC_8x5_SRGB_BLOCK = 168, + ASTC_8x6_UNORM_BLOCK = 169, + ASTC_8x6_SRGB_BLOCK = 170, + ASTC_8x8_UNORM_BLOCK = 171, + ASTC_8x8_SRGB_BLOCK = 172, + ASTC_10x5_UNORM_BLOCK = 173, + ASTC_10x5_SRGB_BLOCK = 174, + ASTC_10x6_UNORM_BLOCK = 175, + ASTC_10x6_SRGB_BLOCK = 176, + ASTC_10x8_UNORM_BLOCK = 177, + ASTC_10x8_SRGB_BLOCK = 178, + ASTC_10x10_UNORM_BLOCK = 179, + ASTC_10x10_SRGB_BLOCK = 180, + ASTC_12x10_UNORM_BLOCK = 181, + ASTC_12x10_SRGB_BLOCK = 182, + ASTC_12x12_UNORM_BLOCK = 183, + ASTC_12x12_SRGB_BLOCK = 184, + + ASTC_END = ASTC_12x12_SRGB_BLOCK, + + REVERSED_BEGIN, + + R4G4B4A4_UNORM_PACK16_REVERSED = REVERSED_BEGIN, + + REVERSED_END + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/GalTextureFormat.cs b/Ryujinx.Graphics/Gal/GalTextureFormat.cs index 7e3e65e82..5ab7be89b 100644 --- a/Ryujinx.Graphics/Gal/GalTextureFormat.cs +++ b/Ryujinx.Graphics/Gal/GalTextureFormat.cs @@ -9,6 +9,7 @@ namespace Ryujinx.Graphics.Gal R32 = 0xf, BC6H_SF16 = 0x10, BC6H_UF16 = 0x11, + A4B4G4R4 = 0x12, A1B5G5R5 = 0x14, B5G6R5 = 0x15, BC7U = 0x17, diff --git a/Ryujinx.Graphics/Gal/GalTextureType.cs b/Ryujinx.Graphics/Gal/GalTextureType.cs new file mode 100644 index 000000000..f7dd16d15 --- /dev/null +++ b/Ryujinx.Graphics/Gal/GalTextureType.cs @@ -0,0 +1,13 @@ +namespace Ryujinx.Graphics.Gal +{ + public enum GalTextureType + { + Snorm = 1, + Unorm = 2, + Sint = 3, + Uint = 4, + Snorm_Force_Fp16 = 5, + Unorm_Force_Fp16 = 6, + Float = 7 + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/GalZetaFormat.cs b/Ryujinx.Graphics/Gal/GalZetaFormat.cs new file mode 100644 index 000000000..759e31217 --- /dev/null +++ b/Ryujinx.Graphics/Gal/GalZetaFormat.cs @@ -0,0 +1,16 @@ +namespace Ryujinx.Graphics.Gal +{ + public enum GalZetaFormat + { + Z32Float = 0x0a, + Z16Unorm = 0x13, + S8Z24Unorm = 0x14, + Z24X8Unorm = 0x15, + Z24S8Unorm = 0x16, + Z24C8Unorm = 0x18, + Z32S8X24Float = 0x19, + Z24X8S8C8X16Unorm = 0x1d, + Z32X8C8X16Float = 0x1e, + Z32S8C8X16Float = 0x1f + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/IGalFrameBuffer.cs b/Ryujinx.Graphics/Gal/IGalFrameBuffer.cs index c0287ef8b..bce1981a4 100644 --- a/Ryujinx.Graphics/Gal/IGalFrameBuffer.cs +++ b/Ryujinx.Graphics/Gal/IGalFrameBuffer.cs @@ -4,9 +4,13 @@ namespace Ryujinx.Graphics.Gal { public interface IGalFrameBuffer { - void Create(long Key, int Width, int Height); + void BindColor(long Key, int Attachment); - void Bind(long Key); + void UnbindColor(int Attachment); + + void BindZeta(long Key); + + void UnbindZeta(); void BindTexture(long Key, int Index); @@ -40,7 +44,6 @@ namespace Ryujinx.Graphics.Gal long Key, int Width, int Height, - GalTextureFormat Format, byte[] Buffer); } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/IGalRasterizer.cs b/Ryujinx.Graphics/Gal/IGalRasterizer.cs index 89e50b1f1..a20b6f532 100644 --- a/Ryujinx.Graphics/Gal/IGalRasterizer.cs +++ b/Ryujinx.Graphics/Gal/IGalRasterizer.cs @@ -9,6 +9,7 @@ namespace Ryujinx.Graphics.Gal void ClearBuffers( GalClearBufferFlags Flags, + int Attachment, float Red, float Green, float Blue, float Alpha, float Depth, int Stencil); diff --git a/Ryujinx.Graphics/Gal/IGalTexture.cs b/Ryujinx.Graphics/Gal/IGalTexture.cs index 2ab411990..292f59efa 100644 --- a/Ryujinx.Graphics/Gal/IGalTexture.cs +++ b/Ryujinx.Graphics/Gal/IGalTexture.cs @@ -5,9 +5,11 @@ namespace Ryujinx.Graphics.Gal void LockCache(); void UnlockCache(); - void Create(long Key, byte[] Data, GalTexture Texture); + void Create(long Key, byte[] Data, GalImage Image); - bool TryGetCachedTexture(long Key, long DataSize, out GalTexture Texture); + 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 new file mode 100644 index 000000000..2d20a8a0e --- /dev/null +++ b/Ryujinx.Graphics/Gal/ImageFormatConverter.cs @@ -0,0 +1,263 @@ +using System; + +namespace Ryujinx.Graphics.Gal +{ + public static class ImageFormatConverter + { + public static GalImageFormat ConvertTexture( + GalTextureFormat Format, + GalTextureType RType, + GalTextureType GType, + GalTextureType BType, + GalTextureType AType) + { + if (RType != GType || RType != BType || RType != AType) + { + throw new NotImplementedException("Per component types are not implemented"); + } + + GalTextureType Type = RType; + + switch (Type) + { + case GalTextureType.Snorm: + switch (Format) + { + case GalTextureFormat.R16G16B16A16: return GalImageFormat.R16G16B16A16_SNORM; + case GalTextureFormat.A8B8G8R8: return GalImageFormat.A8B8G8R8_SNORM_PACK32; + case GalTextureFormat.A2B10G10R10: return GalImageFormat.A2B10G10R10_SNORM_PACK32; + case GalTextureFormat.G8R8: return GalImageFormat.R8G8_SNORM; + case GalTextureFormat.R16: return GalImageFormat.R16_SNORM; + case GalTextureFormat.R8: return GalImageFormat.R8_SNORM; + case GalTextureFormat.BC4: return GalImageFormat.BC4_SNORM_BLOCK; + case GalTextureFormat.BC5: return GalImageFormat.BC5_SNORM_BLOCK; + } + break; + + case GalTextureType.Unorm: + switch (Format) + { + case GalTextureFormat.R16G16B16A16: return GalImageFormat.R16G16B16A16_UNORM; + case GalTextureFormat.A8B8G8R8: return GalImageFormat.A8B8G8R8_UNORM_PACK32; + case GalTextureFormat.A2B10G10R10: return GalImageFormat.A2B10G10R10_UNORM_PACK32; + case GalTextureFormat.A4B4G4R4: return GalImageFormat.R4G4B4A4_UNORM_PACK16_REVERSED; + case GalTextureFormat.A1B5G5R5: return GalImageFormat.A1R5G5B5_UNORM_PACK16; + case GalTextureFormat.B5G6R5: return GalImageFormat.B5G6R5_UNORM_PACK16; + case GalTextureFormat.BC7U: return GalImageFormat.BC7_UNORM_BLOCK; + case GalTextureFormat.G8R8: return GalImageFormat.R8G8_UNORM; + case GalTextureFormat.R16: return GalImageFormat.R16_UNORM; + case GalTextureFormat.R8: return GalImageFormat.R8_UNORM; + case GalTextureFormat.BC1: return GalImageFormat.BC1_RGBA_UNORM_BLOCK; + case GalTextureFormat.BC2: return GalImageFormat.BC2_UNORM_BLOCK; + case GalTextureFormat.BC3: return GalImageFormat.BC3_UNORM_BLOCK; + case GalTextureFormat.BC4: return GalImageFormat.BC4_UNORM_BLOCK; + case GalTextureFormat.BC5: return GalImageFormat.BC5_UNORM_BLOCK; + case GalTextureFormat.Z24S8: return GalImageFormat.D24_UNORM_S8_UINT; + case GalTextureFormat.Astc2D4x4: return GalImageFormat.ASTC_4x4_UNORM_BLOCK; + case GalTextureFormat.Astc2D5x5: return GalImageFormat.ASTC_5x5_UNORM_BLOCK; + case GalTextureFormat.Astc2D6x6: return GalImageFormat.ASTC_6x6_UNORM_BLOCK; + case GalTextureFormat.Astc2D8x8: return GalImageFormat.ASTC_8x8_UNORM_BLOCK; + case GalTextureFormat.Astc2D10x10: return GalImageFormat.ASTC_10x10_UNORM_BLOCK; + case GalTextureFormat.Astc2D12x12: return GalImageFormat.ASTC_12x12_UNORM_BLOCK; + case GalTextureFormat.Astc2D5x4: return GalImageFormat.ASTC_5x4_UNORM_BLOCK; + case GalTextureFormat.Astc2D6x5: return GalImageFormat.ASTC_6x5_UNORM_BLOCK; + case GalTextureFormat.Astc2D8x6: return GalImageFormat.ASTC_8x6_UNORM_BLOCK; + case GalTextureFormat.Astc2D10x8: return GalImageFormat.ASTC_10x8_UNORM_BLOCK; + case GalTextureFormat.Astc2D12x10: return GalImageFormat.ASTC_12x10_UNORM_BLOCK; + case GalTextureFormat.Astc2D8x5: return GalImageFormat.ASTC_8x5_UNORM_BLOCK; + case GalTextureFormat.Astc2D10x5: return GalImageFormat.ASTC_10x5_UNORM_BLOCK; + case GalTextureFormat.Astc2D10x6: return GalImageFormat.ASTC_10x6_UNORM_BLOCK; + } + break; + + case GalTextureType.Sint: + switch (Format) + { + case GalTextureFormat.R32G32B32A32: return GalImageFormat.R32G32B32A32_SINT; + case GalTextureFormat.R16G16B16A16: return GalImageFormat.R16G16B16A16_SINT; + case GalTextureFormat.A8B8G8R8: return GalImageFormat.A8B8G8R8_SINT_PACK32; + case GalTextureFormat.A2B10G10R10: return GalImageFormat.A2B10G10R10_SINT_PACK32; + case GalTextureFormat.R32: return GalImageFormat.R32_SINT; + case GalTextureFormat.G8R8: return GalImageFormat.R8G8_SINT; + case GalTextureFormat.R16: return GalImageFormat.R16_SINT; + case GalTextureFormat.R8: return GalImageFormat.R8_SINT; + } + break; + + case GalTextureType.Uint: + switch (Format) + { + case GalTextureFormat.R32G32B32A32: return GalImageFormat.R32G32B32A32_UINT; + case GalTextureFormat.R16G16B16A16: return GalImageFormat.R16G16B16A16_UINT; + case GalTextureFormat.A8B8G8R8: return GalImageFormat.A8B8G8R8_UINT_PACK32; + case GalTextureFormat.A2B10G10R10: return GalImageFormat.A2B10G10R10_UINT_PACK32; + case GalTextureFormat.R32: return GalImageFormat.R32_UINT; + case GalTextureFormat.G8R8: return GalImageFormat.R8G8_UINT; + case GalTextureFormat.R16: return GalImageFormat.R16_UINT; + case GalTextureFormat.R8: return GalImageFormat.R8_UINT; + } + break; + + case GalTextureType.Snorm_Force_Fp16: + //TODO + break; + + case GalTextureType.Unorm_Force_Fp16: + //TODO + break; + + case GalTextureType.Float: + switch (Format) + { + case GalTextureFormat.R32G32B32A32: return GalImageFormat.R32G32B32A32_SFLOAT; + case GalTextureFormat.R16G16B16A16: return GalImageFormat.R16G16B16A16_SFLOAT; + case GalTextureFormat.R32: return GalImageFormat.R32_SFLOAT; + case GalTextureFormat.BC6H_SF16: return GalImageFormat.BC6H_SFLOAT_BLOCK; + case GalTextureFormat.BC6H_UF16: return GalImageFormat.BC6H_UFLOAT_BLOCK; + case GalTextureFormat.R16: return GalImageFormat.R16_SFLOAT; + case GalTextureFormat.BF10GF11RF11: return GalImageFormat.B10G11R11_UFLOAT_PACK32; + case GalTextureFormat.ZF32: return GalImageFormat.D32_SFLOAT; + } + break; + } + + throw new NotImplementedException("0x" + Format.ToString("x2") + " " + Type.ToString()); + } + + public static GalImageFormat ConvertFrameBuffer(GalFrameBufferFormat Format) + { + switch (Format) + { + case GalFrameBufferFormat.R32Float: return GalImageFormat.R32_SFLOAT; + case GalFrameBufferFormat.RGB10A2Unorm: return GalImageFormat.A2B10G10R10_UNORM_PACK32; + case GalFrameBufferFormat.RGBA8Srgb: return GalImageFormat.A8B8G8R8_SRGB_PACK32; + case GalFrameBufferFormat.RGBA16Float: return GalImageFormat.R16G16B16A16_SFLOAT; + case GalFrameBufferFormat.R16Float: return GalImageFormat.R16_SFLOAT; + case GalFrameBufferFormat.R8Unorm: return GalImageFormat.R8_UNORM; + case GalFrameBufferFormat.RGBA8Unorm: return GalImageFormat.A8B8G8R8_UNORM_PACK32; + case GalFrameBufferFormat.R11G11B10Float: return GalImageFormat.B10G11R11_UFLOAT_PACK32; + case GalFrameBufferFormat.RGBA32Float: return GalImageFormat.R32G32B32A32_SFLOAT; + case GalFrameBufferFormat.RG16Snorm: return GalImageFormat.R16G16_SNORM; + case GalFrameBufferFormat.RG16Float: return GalImageFormat.R16G16_SFLOAT; + case GalFrameBufferFormat.RG8Snorm: return GalImageFormat.R8_SNORM; + case GalFrameBufferFormat.RGBA8Snorm: return GalImageFormat.A8B8G8R8_SNORM_PACK32; + case GalFrameBufferFormat.RG8Unorm: return GalImageFormat.R8G8_UNORM; + } + + throw new NotImplementedException(Format.ToString()); + } + + public static GalImageFormat ConvertZeta(GalZetaFormat Format) + { + switch (Format) + { + case GalZetaFormat.Z32Float: return GalImageFormat.D32_SFLOAT; + case GalZetaFormat.S8Z24Unorm: return GalImageFormat.D24_UNORM_S8_UINT; + case GalZetaFormat.Z16Unorm: return GalImageFormat.D16_UNORM; + } + + throw new NotImplementedException(Format.ToString()); + } + + public static bool HasColor(GalImageFormat Format) + { + switch (Format) + { + case GalImageFormat.R32G32B32A32_SFLOAT: + case GalImageFormat.R32G32B32A32_SINT: + case GalImageFormat.R32G32B32A32_UINT: + case GalImageFormat.R16G16B16A16_SFLOAT: + case GalImageFormat.R16G16B16A16_SINT: + case GalImageFormat.R16G16B16A16_UINT: + case GalImageFormat.A8B8G8R8_SNORM_PACK32: + case GalImageFormat.A8B8G8R8_UNORM_PACK32: + case GalImageFormat.A8B8G8R8_SINT_PACK32: + case GalImageFormat.A8B8G8R8_UINT_PACK32: + case GalImageFormat.A2B10G10R10_SINT_PACK32: + case GalImageFormat.A2B10G10R10_SNORM_PACK32: + case GalImageFormat.A2B10G10R10_UINT_PACK32: + case GalImageFormat.A2B10G10R10_UNORM_PACK32: + case GalImageFormat.R32_SFLOAT: + case GalImageFormat.R32_SINT: + case GalImageFormat.R32_UINT: + case GalImageFormat.BC6H_SFLOAT_BLOCK: + case GalImageFormat.BC6H_UFLOAT_BLOCK: + case GalImageFormat.A1R5G5B5_UNORM_PACK16: + case GalImageFormat.B5G6R5_UNORM_PACK16: + case GalImageFormat.BC7_UNORM_BLOCK: + case GalImageFormat.R16G16_SFLOAT: + case GalImageFormat.R16G16_SINT: + case GalImageFormat.R16G16_SNORM: + case GalImageFormat.R16G16_UNORM: + case GalImageFormat.R8G8_SINT: + case GalImageFormat.R8G8_SNORM: + case GalImageFormat.R8G8_UINT: + case GalImageFormat.R8G8_UNORM: + case GalImageFormat.R16_SFLOAT: + case GalImageFormat.R16_SINT: + case GalImageFormat.R16_SNORM: + case GalImageFormat.R16_UINT: + case GalImageFormat.R16_UNORM: + case GalImageFormat.R8_SINT: + case GalImageFormat.R8_SNORM: + case GalImageFormat.R8_UINT: + case GalImageFormat.R8_UNORM: + case GalImageFormat.B10G11R11_UFLOAT_PACK32: + case GalImageFormat.BC1_RGBA_UNORM_BLOCK: + case GalImageFormat.BC2_UNORM_BLOCK: + case GalImageFormat.BC3_UNORM_BLOCK: + case GalImageFormat.BC4_UNORM_BLOCK: + case GalImageFormat.BC5_UNORM_BLOCK: + case GalImageFormat.ASTC_4x4_UNORM_BLOCK: + case GalImageFormat.ASTC_5x5_UNORM_BLOCK: + case GalImageFormat.ASTC_6x6_UNORM_BLOCK: + case GalImageFormat.ASTC_8x8_UNORM_BLOCK: + case GalImageFormat.ASTC_10x10_UNORM_BLOCK: + case GalImageFormat.ASTC_12x12_UNORM_BLOCK: + case GalImageFormat.ASTC_5x4_UNORM_BLOCK: + case GalImageFormat.ASTC_6x5_UNORM_BLOCK: + case GalImageFormat.ASTC_8x6_UNORM_BLOCK: + case GalImageFormat.ASTC_10x8_UNORM_BLOCK: + case GalImageFormat.ASTC_12x10_UNORM_BLOCK: + case GalImageFormat.ASTC_8x5_UNORM_BLOCK: + case GalImageFormat.ASTC_10x5_UNORM_BLOCK: + case GalImageFormat.ASTC_10x6_UNORM_BLOCK: + case GalImageFormat.R4G4B4A4_UNORM_PACK16_REVERSED: + return true; + + case GalImageFormat.D24_UNORM_S8_UINT: + case GalImageFormat.D32_SFLOAT: + case GalImageFormat.D16_UNORM: + return true; + } + + throw new NotImplementedException(Format.ToString()); + } + + public static bool HasDepth(GalImageFormat Format) + { + switch (Format) + { + case GalImageFormat.D24_UNORM_S8_UINT: + case GalImageFormat.D32_SFLOAT: + case GalImageFormat.D16_UNORM: + return true; + } + + //Depth formats are fewer than colors, so it's harder to miss one + //Instead of checking for individual formats, return false + return false; + } + + public static bool HasStencil(GalImageFormat Format) + { + switch (Format) + { + case GalImageFormat.D24_UNORM_S8_UINT: + return true; + } + + return false; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/OpenGL/ImageHandler.cs b/Ryujinx.Graphics/Gal/OpenGL/ImageHandler.cs new file mode 100644 index 000000000..74f18dcd3 --- /dev/null +++ b/Ryujinx.Graphics/Gal/OpenGL/ImageHandler.cs @@ -0,0 +1,124 @@ +using OpenTK.Graphics.OpenGL; +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; + + public GalImage Image { get; private set; } + + public int Width => Image.Width; + public int Height => Image.Height; + + public GalImageFormat Format => Image.Format; + + public PixelInternalFormat InternalFormat { get; private set; } + public PixelFormat PixelFormat { get; private set; } + public PixelType PixelType { get; private set; } + + public int Handle { get; private set; } + + private bool Initialized; + + public ImageHandler() + { + Handle = GL.GenTexture(); + } + + public ImageHandler(int Handle, GalImage Image) + { + this.Handle = Handle; + + this.Image = Image; + } + + public void EnsureSetup(GalImage Image) + { + if (Width != Image.Width || + Height != Image.Height || + Format != Image.Format || + !Initialized) + { + (PixelInternalFormat InternalFormat, PixelFormat PixelFormat, PixelType PixelType) = + OGLEnumConverter.GetImageFormat(Image.Format); + + GL.BindTexture(TextureTarget.Texture2D, Handle); + + if (Initialized) + { + 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); + + if (CopyBufferSize < CurrentSize) + { + CopyBufferSize = CurrentSize; + + GL.BufferData(BufferTarget.PixelPackBuffer, CurrentSize, IntPtr.Zero, BufferUsageHint.StreamCopy); + } + + GL.GetTexImage(TextureTarget.Texture2D, 0, this.PixelFormat, this.PixelType, IntPtr.Zero); + + GL.DeleteTexture(Handle); + + Handle = GL.GenTexture(); + + GL.BindTexture(TextureTarget.Texture2D, Handle); + } + + 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); + + const int Level = 0; + const int Border = 0; + + GL.TexImage2D( + TextureTarget.Texture2D, + Level, + InternalFormat, + Image.Width, + Image.Height, + Border, + PixelFormat, + PixelType, + IntPtr.Zero); + + if (Initialized) + { + GL.BindBuffer(BufferTarget.PixelPackBuffer, 0); + GL.BindBuffer(BufferTarget.PixelUnpackBuffer, 0); + } + + this.Image = Image; + + this.InternalFormat = InternalFormat; + this.PixelFormat = PixelFormat; + this.PixelType = PixelType; + + 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.Graphics/Gal/OpenGL/OGLConstBuffer.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLConstBuffer.cs index 508255413..4958b53b3 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLConstBuffer.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLConstBuffer.cs @@ -36,12 +36,10 @@ namespace Ryujinx.Graphics.Gal.OpenGL public void SetData(long Key, long Size, IntPtr HostAddress) { - if (!Cache.TryGetValue(Key, out OGLStreamBuffer Buffer)) + if (Cache.TryGetValue(Key, out OGLStreamBuffer Buffer)) { - throw new InvalidOperationException(); + Buffer.SetData(Size, HostAddress); } - - Buffer.SetData(Size, HostAddress); } public bool TryGetUbo(long Key, out int UboHandle) diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs index 3c42e5d38..e04a59d44 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs @@ -125,40 +125,71 @@ namespace Ryujinx.Graphics.Gal.OpenGL throw new ArgumentException(nameof(Type)); } - public static (PixelFormat, PixelType) GetTextureFormat(GalTextureFormat Format) + public static (PixelInternalFormat, PixelFormat, PixelType) GetImageFormat(GalImageFormat Format) { switch (Format) { - case GalTextureFormat.R32G32B32A32: return (PixelFormat.Rgba, PixelType.Float); - case GalTextureFormat.R16G16B16A16: return (PixelFormat.Rgba, PixelType.HalfFloat); - case GalTextureFormat.A8B8G8R8: return (PixelFormat.Rgba, PixelType.UnsignedByte); - case GalTextureFormat.A2B10G10R10: return (PixelFormat.Rgba, PixelType.UnsignedInt2101010Reversed); - case GalTextureFormat.R32: return (PixelFormat.Red, PixelType.Float); - case GalTextureFormat.A1B5G5R5: return (PixelFormat.Rgba, PixelType.UnsignedShort5551); - case GalTextureFormat.B5G6R5: return (PixelFormat.Rgb, PixelType.UnsignedShort565); - case GalTextureFormat.G8R8: return (PixelFormat.Rg, PixelType.UnsignedByte); - case GalTextureFormat.R16: return (PixelFormat.Red, PixelType.HalfFloat); - case GalTextureFormat.R8: return (PixelFormat.Red, PixelType.UnsignedByte); - case GalTextureFormat.ZF32: return (PixelFormat.DepthComponent, PixelType.Float); - case GalTextureFormat.BF10GF11RF11: return (PixelFormat.Rgb, PixelType.UnsignedInt10F11F11FRev); - case GalTextureFormat.Z24S8: return (PixelFormat.DepthStencil, PixelType.UnsignedInt248); + 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.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); } throw new NotImplementedException(Format.ToString()); } - public static InternalFormat GetCompressedTextureFormat(GalTextureFormat Format) + public static InternalFormat GetCompressedImageFormat(GalImageFormat Format) { switch (Format) { - case GalTextureFormat.BC6H_UF16: return InternalFormat.CompressedRgbBptcUnsignedFloat; - case GalTextureFormat.BC6H_SF16: return InternalFormat.CompressedRgbBptcSignedFloat; - case GalTextureFormat.BC7U: return InternalFormat.CompressedRgbaBptcUnorm; - case GalTextureFormat.BC1: return InternalFormat.CompressedRgbaS3tcDxt1Ext; - case GalTextureFormat.BC2: return InternalFormat.CompressedRgbaS3tcDxt3Ext; - case GalTextureFormat.BC3: return InternalFormat.CompressedRgbaS3tcDxt5Ext; - case GalTextureFormat.BC4: return InternalFormat.CompressedRedRgtc1; - case GalTextureFormat.BC5: return InternalFormat.CompressedRgRgtc2; + 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; } throw new NotImplementedException(Format.ToString()); diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs index 62f82495c..e0f12e4ec 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,50 +14,38 @@ 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 Fbs; + private const GalImageFormat RawFormat = GalImageFormat.A8B8G8R8_UNORM_PACK32; + + private OGLTexture Texture; + + private ImageHandler RawTex; + private ImageHandler ReadTex; private Rect Viewport; private Rect Window; - private FrameBuffer CurrFb; - private FrameBuffer CurrReadFb; - - private FrameBuffer RawFb; - private bool FlipX; private bool FlipY; @@ -67,111 +54,144 @@ namespace Ryujinx.Graphics.Gal.OpenGL private int CropRight; private int CropBottom; - public OGLFrameBuffer() + //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) { - Fbs = new Dictionary(); + ColorAttachments = new int[8]; + + this.Texture = Texture; } - public void Create(long Key, int Width, int Height) + public void BindColor(long Key, int Attachment) { - if (Fbs.TryGetValue(Key, out FrameBuffer Fb)) + if (Texture.TryGetImage(Key, out ImageHandler Tex)) { - if (Fb.Width != Width || - Fb.Height != Height) - { - SetupTexture(Fb.TexHandle, Width, Height); + EnsureFrameBuffer(); - Fb.Width = Width; - Fb.Height = Height; - } - - return; + Attach(ref ColorAttachments[Attachment], Tex.Handle, FramebufferAttachment.ColorAttachment0 + Attachment); + } + else + { + UnbindColor(Attachment); } - - Fb = new FrameBuffer(Width, Height, true); - - SetupTexture(Fb.TexHandle, Width, Height); - - GL.BindFramebuffer(FramebufferTarget.Framebuffer, Fb.Handle); - - GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, Fb.RbHandle); - - GL.RenderbufferStorage( - RenderbufferTarget.Renderbuffer, - RenderbufferStorage.Depth24Stencil8, - Width, - Height); - - GL.FramebufferRenderbuffer( - FramebufferTarget.Framebuffer, - FramebufferAttachment.DepthStencilAttachment, - RenderbufferTarget.Renderbuffer, - Fb.RbHandle); - - GL.FramebufferTexture( - FramebufferTarget.Framebuffer, - FramebufferAttachment.ColorAttachment0, - Fb.TexHandle, - 0); - - GL.DrawBuffer(DrawBufferMode.ColorAttachment0); - - Fbs.Add(Key, Fb); } - public void Bind(long Key) + public void UnbindColor(int Attachment) { - if (Fbs.TryGetValue(Key, out FrameBuffer Fb)) - { - GL.BindFramebuffer(FramebufferTarget.Framebuffer, Fb.Handle); + EnsureFrameBuffer(); - CurrFb = Fb; + 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 (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); + RawTex.EnsureSetup(new GalImage(Width, Height, RawFormat)); - RawFb.Width = Width; - RawFb.Height = Height; - } + GL.BindTexture(TextureTarget.Texture2D, RawTex.Handle); - GL.ActiveTexture(TextureUnit.Texture0); + GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, Width, Height, RawTex.PixelFormat, RawTex.PixelType, Data); - GL.BindTexture(TextureTarget.Texture2D, RawFb.TexHandle); - - (PixelFormat Format, PixelType Type) = OGLEnumConverter.GetTextureFormat(GalTextureFormat.A8B8G8R8); - - GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, Width, Height, Format, Type, 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; - - if (CropLeft == 0 && CropRight == 0) - { - SrcX0 = 0; - SrcX1 = CurrReadFb.Width; - } - else - { - SrcX0 = CropLeft; - SrcX1 = CropRight; - } - - if (CropTop == 0 && CropBottom == 0) - { - SrcY0 = 0; - SrcY1 = CurrReadFb.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; - - GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0); - - GL.Viewport(0, 0, Window.Width, Window.Height); - - GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, CurrReadFb.Handle); - - GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); - - GL.BlitFramebuffer( - SrcX0, SrcY0, SrcX1, SrcY1, - DstX0, DstY0, DstX1, DstY1, - ClearBufferMask.ColorBufferBit, BlitFramebufferFilter.Linear); + 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( @@ -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); + if (SrcTex.HasColor != DstTex.HasColor || + SrcTex.HasDepth != DstTex.HasDepth || + SrcTex.HasStencil != DstTex.HasStencil) + { + throw new NotImplementedException(); + } - GL.Clear(ClearBufferMask.ColorBufferBit); - - 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 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( + GL.GetTexImage( + TextureTarget.Texture2D, 0, - 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); + DummyFrameBuffer = GL.GenFramebuffer(); + } - SetupTexture(RawFb.TexHandle, Width, Height); + GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DummyFrameBuffer); - RawFb.Width = Width; - RawFb.Height = Height; - - 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); - const PixelInternalFormat InternalFmt = PixelInternalFormat.Rgba; + if (Color) + { + GL.DrawBuffer(DrawBufferMode.ColorAttachment0); + } - const int Level = 0; - const int Border = 0; + GL.Clear(Mask); - GL.TexImage2D( - TextureTarget.Texture2D, - Level, - InternalFmt, - Width, - Height, - Border, - Format, - Type, - IntPtr.Zero); + 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/OGLRasterizer.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs index b6e974545..451066928 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs @@ -3,7 +3,7 @@ using System; namespace Ryujinx.Graphics.Gal.OpenGL { - public class OGLRasterizer : IGalRasterizer + class OGLRasterizer : IGalRasterizer { private int[] VertexBuffers; @@ -44,36 +44,29 @@ namespace Ryujinx.Graphics.Gal.OpenGL public void ClearBuffers( GalClearBufferFlags Flags, + int Attachment, float Red, float Green, float Blue, float Alpha, float Depth, int Stencil) { - ClearBufferMask Mask = ClearBufferMask.ColorBufferBit; - GL.ColorMask( Flags.HasFlag(GalClearBufferFlags.ColorRed), Flags.HasFlag(GalClearBufferFlags.ColorGreen), Flags.HasFlag(GalClearBufferFlags.ColorBlue), Flags.HasFlag(GalClearBufferFlags.ColorAlpha)); + GL.ClearBuffer(ClearBuffer.Color, Attachment, new float[] { Red, Green, Blue, Alpha }); + if (Flags.HasFlag(GalClearBufferFlags.Depth)) { - Mask |= ClearBufferMask.DepthBufferBit; + GL.ClearBuffer(ClearBuffer.Depth, 0, ref Depth); } if (Flags.HasFlag(GalClearBufferFlags.Stencil)) { - Mask |= ClearBufferMask.StencilBufferBit; + GL.ClearBuffer(ClearBuffer.Stencil, 0, ref Stencil); } - GL.ClearColor(Red, Green, Blue, Alpha); - - GL.ClearDepth(Depth); - - GL.ClearStencil(Stencil); - - GL.Clear(Mask); - GL.ColorMask(true, true, true, true); } diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLRenderer.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLRenderer.cs index b0f6da45e..985f1086f 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 ac30e6fd8..e4d4bd648 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs @@ -4,26 +4,13 @@ using System; namespace Ryujinx.Graphics.Gal.OpenGL { - public class OGLTexture : IGalTexture + class OGLTexture : IGalTexture { - private class TCE - { - public int Handle; - - public GalTexture Texture; - - public TCE(int Handle, GalTexture Texture) - { - this.Handle = Handle; - this.Texture = Texture; - } - } - - private OGLCachedResource TextureCache; + private OGLCachedResource TextureCache; public OGLTexture() { - TextureCache = new OGLCachedResource(DeleteTexture); + TextureCache = new OGLCachedResource(DeleteTexture); } public void LockCache() @@ -36,73 +23,71 @@ namespace Ryujinx.Graphics.Gal.OpenGL TextureCache.Unlock(); } - private static void DeleteTexture(TCE CachedTexture) + private static void DeleteTexture(ImageHandler CachedImage) { - GL.DeleteTexture(CachedTexture.Handle); + GL.DeleteTexture(CachedImage.Handle); } - public void Create(long Key, byte[] Data, GalTexture Texture) + public void Create(long Key, byte[] Data, GalImage Image) { int Handle = GL.GenTexture(); - TextureCache.AddOrUpdate(Key, new TCE(Handle, Texture), (uint)Data.Length); + TextureCache.AddOrUpdate(Key, new ImageHandler(Handle, Image), (uint)Data.Length); GL.BindTexture(TextureTarget.Texture2D, Handle); const int Level = 0; //TODO: Support mipmap textures. const int Border = 0; - if (IsCompressedTextureFormat(Texture.Format)) + if (IsCompressedTextureFormat(Image.Format)) { - InternalFormat InternalFmt = OGLEnumConverter.GetCompressedTextureFormat(Texture.Format); + InternalFormat InternalFmt = OGLEnumConverter.GetCompressedImageFormat(Image.Format); GL.CompressedTexImage2D( TextureTarget.Texture2D, Level, InternalFmt, - Texture.Width, - Texture.Height, + Image.Width, + Image.Height, Border, Data.Length, Data); } else { - if (Texture.Format >= GalTextureFormat.Astc2D4x4) + if (Image.Format >= GalImageFormat.ASTC_BEGIN && Image.Format <= GalImageFormat.ASTC_END) { - int TextureBlockWidth = GetAstcBlockWidth(Texture.Format); - int TextureBlockHeight = GetAstcBlockHeight(Texture.Format); + int TextureBlockWidth = GetAstcBlockWidth(Image.Format); + int TextureBlockHeight = GetAstcBlockHeight(Image.Format); Data = ASTCDecoder.DecodeToRGBA8888( Data, TextureBlockWidth, TextureBlockHeight, 1, - Texture.Width, - Texture.Height, 1); + Image.Width, + Image.Height, 1); - Texture.Format = GalTextureFormat.A8B8G8R8; + Image.Format = GalImageFormat.A8B8G8R8_UNORM_PACK32; } - const PixelInternalFormat InternalFmt = PixelInternalFormat.Rgba; - - (PixelFormat Format, PixelType Type) = OGLEnumConverter.GetTextureFormat(Texture.Format); + (PixelInternalFormat InternalFormat, PixelFormat Format, PixelType Type) = OGLEnumConverter.GetImageFormat(Image.Format); GL.TexImage2D( TextureTarget.Texture2D, Level, - InternalFmt, - Texture.Width, - Texture.Height, + InternalFormat, + Image.Width, + Image.Height, Border, Format, Type, Data); } - int SwizzleR = (int)OGLEnumConverter.GetTextureSwizzle(Texture.XSource); - int SwizzleG = (int)OGLEnumConverter.GetTextureSwizzle(Texture.YSource); - int SwizzleB = (int)OGLEnumConverter.GetTextureSwizzle(Texture.ZSource); - int SwizzleA = (int)OGLEnumConverter.GetTextureSwizzle(Texture.WSource); + int SwizzleR = (int)OGLEnumConverter.GetTextureSwizzle(Image.XSource); + int SwizzleG = (int)OGLEnumConverter.GetTextureSwizzle(Image.YSource); + int SwizzleB = (int)OGLEnumConverter.GetTextureSwizzle(Image.ZSource); + int SwizzleA = (int)OGLEnumConverter.GetTextureSwizzle(Image.WSource); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleR, SwizzleR); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleG, SwizzleG); @@ -110,76 +95,100 @@ namespace Ryujinx.Graphics.Gal.OpenGL GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleA, SwizzleA); } - private static int GetAstcBlockWidth(GalTextureFormat Format) + public void CreateFb(long Key, long Size, GalImage Image) + { + if (!TryGetImage(Key, out ImageHandler CachedImage)) + { + CachedImage = new ImageHandler(); + + TextureCache.AddOrUpdate(Key, CachedImage, Size); + } + + CachedImage.EnsureSetup(Image); + } + + public bool TryGetImage(long Key, out ImageHandler CachedImage) + { + if (TextureCache.TryGetValue(Key, out CachedImage)) + { + return true; + } + + CachedImage = null; + + return false; + } + + private static int GetAstcBlockWidth(GalImageFormat Format) { switch (Format) { - case GalTextureFormat.Astc2D4x4: return 4; - case GalTextureFormat.Astc2D5x5: return 5; - case GalTextureFormat.Astc2D6x6: return 6; - case GalTextureFormat.Astc2D8x8: return 8; - case GalTextureFormat.Astc2D10x10: return 10; - case GalTextureFormat.Astc2D12x12: return 12; - case GalTextureFormat.Astc2D5x4: return 5; - case GalTextureFormat.Astc2D6x5: return 6; - case GalTextureFormat.Astc2D8x6: return 8; - case GalTextureFormat.Astc2D10x8: return 10; - case GalTextureFormat.Astc2D12x10: return 12; - case GalTextureFormat.Astc2D8x5: return 8; - case GalTextureFormat.Astc2D10x5: return 10; - case GalTextureFormat.Astc2D10x6: return 10; + 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; } throw new ArgumentException(nameof(Format)); } - private static int GetAstcBlockHeight(GalTextureFormat Format) + private static int GetAstcBlockHeight(GalImageFormat Format) { switch (Format) { - case GalTextureFormat.Astc2D4x4: return 4; - case GalTextureFormat.Astc2D5x5: return 5; - case GalTextureFormat.Astc2D6x6: return 6; - case GalTextureFormat.Astc2D8x8: return 8; - case GalTextureFormat.Astc2D10x10: return 10; - case GalTextureFormat.Astc2D12x12: return 12; - case GalTextureFormat.Astc2D5x4: return 4; - case GalTextureFormat.Astc2D6x5: return 5; - case GalTextureFormat.Astc2D8x6: return 6; - case GalTextureFormat.Astc2D10x8: return 8; - case GalTextureFormat.Astc2D12x10: return 10; - case GalTextureFormat.Astc2D8x5: return 5; - case GalTextureFormat.Astc2D10x5: return 5; - case GalTextureFormat.Astc2D10x6: return 6; + 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; } throw new ArgumentException(nameof(Format)); } - public bool TryGetCachedTexture(long Key, long DataSize, out GalTexture Texture) + public bool TryGetCachedTexture(long Key, long DataSize, out GalImage Image) { if (TextureCache.TryGetSize(Key, out long Size) && Size == DataSize) { - if (TextureCache.TryGetValue(Key, out TCE CachedTexture)) + if (TextureCache.TryGetValue(Key, out ImageHandler CachedImage)) { - Texture = CachedTexture.Texture; + Image = CachedImage.Image; return true; } } - Texture = default(GalTexture); + Image = default(GalImage); return false; } public void Bind(long Key, int Index) { - if (TextureCache.TryGetValue(Key, out TCE CachedTexture)) + if (TextureCache.TryGetValue(Key, out ImageHandler CachedImage)) { GL.ActiveTexture(TextureUnit.Texture0 + Index); - GL.BindTexture(TextureTarget.Texture2D, CachedTexture.Handle); + GL.BindTexture(TextureTarget.Texture2D, CachedImage.Handle); } } @@ -208,18 +217,20 @@ namespace Ryujinx.Graphics.Gal.OpenGL GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureBorderColor, Color); } - private static bool IsCompressedTextureFormat(GalTextureFormat Format) + private static bool IsCompressedTextureFormat(GalImageFormat Format) { switch (Format) { - case GalTextureFormat.BC6H_UF16: - case GalTextureFormat.BC6H_SF16: - case GalTextureFormat.BC7U: - case GalTextureFormat.BC1: - case GalTextureFormat.BC2: - case GalTextureFormat.BC3: - case GalTextureFormat.BC4: - case GalTextureFormat.BC5: + 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; } diff --git a/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs b/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs index ccc59e048..56745bc15 100644 --- a/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs +++ b/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs @@ -16,6 +16,7 @@ namespace Ryujinx.Graphics.Gal.Shader public const int VertexIdAttr = 0x2fc; public const int FaceAttr = 0x3fc; + public const int MaxFrameBufferAttachments = 8; public const int MaxUboSize = 1024; public const int GlPositionVec4Index = 7; @@ -99,7 +100,11 @@ namespace Ryujinx.Graphics.Gal.Shader if (ShaderType == GalShaderType.Fragment) { - m_Gprs.Add(0, new ShaderDeclInfo(FragmentOutputName, 0, false, 0, 4)); + //Note: Replace 1 with MaxFrameBufferAttachments when attachments start to work + for (int Index = 0; Index < 1; Index++) + { + m_Gprs.Add(Index * 4, new ShaderDeclInfo(FragmentOutputName + Index, Index * 4, false, 0, 4)); + } } foreach (ShaderIrBlock Block in Blocks) diff --git a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs index 7f1cfabc8..726379846 100644 --- a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs +++ b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs @@ -352,9 +352,9 @@ namespace Ryujinx.Graphics.Gal.Shader { Name = CustomType + " " + DeclInfo.Name + Suffix + ";"; } - else if (DeclInfo.Name == GlslDecl.FragmentOutputName) + else if (DeclInfo.Name.Contains(GlslDecl.FragmentOutputName)) { - Name = "layout (location = 0) out vec4 " + DeclInfo.Name + Suffix + ";" + Environment.NewLine; + Name = "layout (location = " + DeclInfo.Index / 4 + ") out vec4 " + DeclInfo.Name + Suffix + ";"; } else { @@ -829,8 +829,11 @@ namespace Ryujinx.Graphics.Gal.Shader { return "gl_PointSize"; } + } - throw new InvalidOperationException(); + if (DeclInfo.Index >= 16) + { + throw new InvalidOperationException($"Shader attribute offset {Abuf.Offs} is invalid."); } if (Decl.ShaderType == GalShaderType.Geometry) @@ -876,7 +879,7 @@ namespace Ryujinx.Graphics.Gal.Shader private string GetNameWithSwizzle(IReadOnlyDictionary Dict, int Index) { - int VecIndex = Index >> 2; + int VecIndex = Index & ~3; if (Dict.TryGetValue(VecIndex, out ShaderDeclInfo DeclInfo)) { diff --git a/Ryujinx.HLE/Gpu/Engines/NvGpuEngine2d.cs b/Ryujinx.HLE/Gpu/Engines/NvGpuEngine2d.cs index d2c5f1262..7fb5ea8af 100644 --- a/Ryujinx.HLE/Gpu/Engines/NvGpuEngine2d.cs +++ b/Ryujinx.HLE/Gpu/Engines/NvGpuEngine2d.cs @@ -154,16 +154,12 @@ namespace Ryujinx.HLE.Gpu.Engines } else if (IsDstFb) { - //Texture -> Frame Buffer copy. - const GalTextureFormat Format = GalTextureFormat.A8B8G8R8; - byte[] Buffer = TextureReader.Read(Vmm, SrcTexture()); Gpu.Renderer.FrameBuffer.SetBufferData( DstKey, DstWidth, DstHeight, - Format, Buffer); } else diff --git a/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3d.cs b/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3d.cs index 6f6012445..1d0834ddb 100644 --- a/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3d.cs +++ b/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3d.cs @@ -102,7 +102,9 @@ namespace Ryujinx.HLE.Gpu.Engines SetAlphaBlending(State); SetPrimitiveRestart(State); + //Enabling multiple framebuffer attachments cause graphics reggresions SetFrameBuffer(Vmm, 0); + SetZeta(Vmm); long[] Keys = UploadShaders(Vmm); @@ -149,9 +151,11 @@ namespace Ryujinx.HLE.Gpu.Engines int Stencil = ReadRegister(NvGpuEngine3dReg.ClearStencil); SetFrameBuffer(Vmm, FbIndex); + SetZeta(Vmm); Gpu.Renderer.Rasterizer.ClearBuffers( Flags, + FbIndex, Red, Green, Blue, Alpha, Depth, Stencil); @@ -161,6 +165,15 @@ namespace Ryujinx.HLE.Gpu.Engines { long VA = MakeInt64From2xInt32(NvGpuEngine3dReg.FrameBufferNAddress + FbIndex * 0x10); + int Format = ReadRegister(NvGpuEngine3dReg.FrameBufferNFormat + FbIndex * 0x10); + + if (VA == 0 || Format == 0) + { + Gpu.Renderer.FrameBuffer.UnbindColor(FbIndex); + + return; + } + long Key = Vmm.GetPhysicalAddress(VA); FrameBuffers.Add(Key); @@ -168,11 +181,11 @@ namespace Ryujinx.HLE.Gpu.Engines int Width = ReadRegister(NvGpuEngine3dReg.FrameBufferNWidth + FbIndex * 0x10); int Height = ReadRegister(NvGpuEngine3dReg.FrameBufferNHeight + FbIndex * 0x10); - float TX = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNTranslateX + FbIndex * 4); - float TY = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNTranslateY + FbIndex * 4); + float TX = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNTranslateX + FbIndex * 8); + float TY = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNTranslateY + FbIndex * 8); - float SX = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNScaleX + FbIndex * 4); - float SY = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNScaleY + FbIndex * 4); + float SX = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNScaleX + FbIndex * 8); + float SY = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNScaleY + FbIndex * 8); int VpX = (int)MathF.Max(0, TX - MathF.Abs(SX)); int VpY = (int)MathF.Max(0, TY - MathF.Abs(SY)); @@ -180,12 +193,48 @@ namespace Ryujinx.HLE.Gpu.Engines int VpW = (int)(TX + MathF.Abs(SX)) - VpX; int VpH = (int)(TY + MathF.Abs(SY)) - VpY; - Gpu.Renderer.FrameBuffer.Create(Key, Width, Height); - Gpu.Renderer.FrameBuffer.Bind(Key); + 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); } + private void SetZeta(NvGpuVmm Vmm) + { + long ZA = MakeInt64From2xInt32(NvGpuEngine3dReg.ZetaAddress); + + int Format = ReadRegister(NvGpuEngine3dReg.ZetaFormat); + + bool ZetaEnable = (ReadRegister(NvGpuEngine3dReg.ZetaEnable) & 1) != 0; + + if (ZA == 0 || Format == 0 || !ZetaEnable) + { + Gpu.Renderer.FrameBuffer.UnbindZeta(); + + return; + } + + long Key = Vmm.GetPhysicalAddress(ZA); + + int Width = ReadRegister(NvGpuEngine3dReg.ZetaHoriz); + int Height = ReadRegister(NvGpuEngine3dReg.ZetaVert); + + 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); + } + private long[] UploadShaders(NvGpuVmm Vmm) { long[] Keys = new long[5]; @@ -442,15 +491,15 @@ namespace Ryujinx.HLE.Gpu.Engines } else { - GalTexture 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 GalTexture 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); @@ -462,7 +511,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); diff --git a/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3dReg.cs b/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3dReg.cs index 39a5ee8cf..b03aef024 100644 --- a/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3dReg.cs +++ b/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3dReg.cs @@ -22,7 +22,14 @@ namespace Ryujinx.HLE.Gpu.Engines StencilBackFuncRef = 0x3d5, StencilBackMask = 0x3d6, StencilBackFuncMask = 0x3d7, + ZetaAddress = 0x3f8, + ZetaFormat = 0x3fa, + ZetaBlockDimensions = 0x3fb, + ZetaLayerStride = 0x3fc, VertexAttribNFormat = 0x458, + ZetaHoriz = 0x48a, + ZetaVert = 0x48b, + ZetaArrayMode = 0x48c, DepthTestEnable = 0x4b3, IBlendEnable = 0x4b9, DepthTestFunction = 0x4c3, @@ -44,6 +51,7 @@ namespace Ryujinx.HLE.Gpu.Engines StencilFrontFuncMask = 0x4e6, StencilFrontMask = 0x4e7, VertexArrayElemBase = 0x50d, + ZetaEnable = 0x54e, TexHeaderPoolOffset = 0x55d, TexSamplerPoolOffset = 0x557, StencilTwoSideEnable = 0x565, diff --git a/Ryujinx.HLE/Gpu/Texture/TextureFactory.cs b/Ryujinx.HLE/Gpu/Texture/TextureFactory.cs index 4db0b6f10..0ef33d3b7 100644 --- a/Ryujinx.HLE/Gpu/Texture/TextureFactory.cs +++ b/Ryujinx.HLE/Gpu/Texture/TextureFactory.cs @@ -6,11 +6,16 @@ namespace Ryujinx.HLE.Gpu.Texture { static class TextureFactory { - public static GalTexture MakeTexture(NvGpuVmm Vmm, long TicPosition) + public static GalImage MakeTexture(NvGpuVmm Vmm, long TicPosition) { int[] Tic = ReadWords(Vmm, TicPosition, 8); - GalTextureFormat Format = (GalTextureFormat)(Tic[0] & 0x7f); + GalTextureType RType = (GalTextureType)((Tic[0] >> 7) & 7); + GalTextureType GType = (GalTextureType)((Tic[0] >> 10) & 7); + GalTextureType BType = (GalTextureType)((Tic[0] >> 13) & 7); + GalTextureType AType = (GalTextureType)((Tic[0] >> 16) & 7); + + GalImageFormat Format = ImageFormatConverter.ConvertTexture((GalTextureFormat)(Tic[0] & 0x7f), RType, GType, BType, AType); GalTextureSource XSource = (GalTextureSource)((Tic[0] >> 19) & 7); GalTextureSource YSource = (GalTextureSource)((Tic[0] >> 22) & 7); @@ -20,7 +25,7 @@ namespace Ryujinx.HLE.Gpu.Texture int Width = (Tic[4] & 0xffff) + 1; int Height = (Tic[5] & 0xffff) + 1; - return new GalTexture( + return new GalImage( Width, Height, Format, diff --git a/Ryujinx.HLE/Gpu/Texture/TextureHelper.cs b/Ryujinx.HLE/Gpu/Texture/TextureHelper.cs index 10a64f364..92b608a95 100644 --- a/Ryujinx.HLE/Gpu/Texture/TextureHelper.cs +++ b/Ryujinx.HLE/Gpu/Texture/TextureHelper.cs @@ -30,117 +30,151 @@ namespace Ryujinx.HLE.Gpu.Texture throw new NotImplementedException(Texture.Swizzle.ToString()); } - public static int GetTextureSize(GalTexture Texture) + public static int GetTextureSize(GalImage Image) { - switch (Texture.Format) + switch (Image.Format) { - case GalTextureFormat.R32G32B32A32: - return Texture.Width * Texture.Height * 16; + case GalImageFormat.R32G32B32A32_SFLOAT: + case GalImageFormat.R32G32B32A32_SINT: + case GalImageFormat.R32G32B32A32_UINT: + return Image.Width * Image.Height * 16; - case GalTextureFormat.R16G16B16A16: - return Texture.Width * Texture.Height * 8; + case GalImageFormat.R16G16B16A16_SFLOAT: + case GalImageFormat.R16G16B16A16_SINT: + case GalImageFormat.R16G16B16A16_SNORM: + case GalImageFormat.R16G16B16A16_UINT: + case GalImageFormat.R16G16B16A16_UNORM: + return Image.Width * Image.Height * 8; - case GalTextureFormat.A8B8G8R8: - case GalTextureFormat.A2B10G10R10: - case GalTextureFormat.R32: - case GalTextureFormat.ZF32: - case GalTextureFormat.BF10GF11RF11: - case GalTextureFormat.Z24S8: - return Texture.Width * Texture.Height * 4; + case GalImageFormat.A8B8G8R8_SINT_PACK32: + case GalImageFormat.A8B8G8R8_SNORM_PACK32: + case GalImageFormat.A8B8G8R8_UINT_PACK32: + case GalImageFormat.A8B8G8R8_UNORM_PACK32: + case GalImageFormat.A8B8G8R8_SRGB_PACK32: + case GalImageFormat.A2B10G10R10_SINT_PACK32: + case GalImageFormat.A2B10G10R10_SNORM_PACK32: + case GalImageFormat.A2B10G10R10_UINT_PACK32: + case GalImageFormat.A2B10G10R10_UNORM_PACK32: + case GalImageFormat.R16G16_SFLOAT: + case GalImageFormat.R16G16_SINT: + case GalImageFormat.R16G16_SNORM: + case GalImageFormat.R16G16_UINT: + case GalImageFormat.R16G16_UNORM: + case GalImageFormat.R32_SFLOAT: + case GalImageFormat.R32_SINT: + case GalImageFormat.R32_UINT: + case GalImageFormat.D32_SFLOAT: + case GalImageFormat.B10G11R11_UFLOAT_PACK32: + case GalImageFormat.D24_UNORM_S8_UINT: + return Image.Width * Image.Height * 4; - case GalTextureFormat.A1B5G5R5: - case GalTextureFormat.B5G6R5: - case GalTextureFormat.G8R8: - case GalTextureFormat.R16: - return Texture.Width * Texture.Height * 2; + case GalImageFormat.B4G4R4A4_UNORM_PACK16: + case GalImageFormat.A1R5G5B5_UNORM_PACK16: + case GalImageFormat.B5G6R5_UNORM_PACK16: + case GalImageFormat.R8G8_SINT: + case GalImageFormat.R8G8_SNORM: + case GalImageFormat.R8G8_UINT: + case GalImageFormat.R8G8_UNORM: + case GalImageFormat.R16_SFLOAT: + case GalImageFormat.R16_SINT: + case GalImageFormat.R16_SNORM: + case GalImageFormat.R16_UINT: + case GalImageFormat.R16_UNORM: + case GalImageFormat.D16_UNORM: + return Image.Width * Image.Height * 2; - case GalTextureFormat.R8: - return Texture.Width * Texture.Height; + case GalImageFormat.R8_SINT: + case GalImageFormat.R8_SNORM: + case GalImageFormat.R8_UINT: + case GalImageFormat.R8_UNORM: + return Image.Width * Image.Height; - case GalTextureFormat.BC1: - case GalTextureFormat.BC4: + case GalImageFormat.BC1_RGBA_UNORM_BLOCK: + case GalImageFormat.BC4_SNORM_BLOCK: + case GalImageFormat.BC4_UNORM_BLOCK: { - return CompressedTextureSize(Texture.Width, Texture.Height, 4, 4, 8); + return CompressedTextureSize(Image.Width, Image.Height, 4, 4, 8); } - case GalTextureFormat.BC6H_SF16: - case GalTextureFormat.BC6H_UF16: - case GalTextureFormat.BC7U: - case GalTextureFormat.BC2: - case GalTextureFormat.BC3: - case GalTextureFormat.BC5: - case GalTextureFormat.Astc2D4x4: + case GalImageFormat.BC6H_SFLOAT_BLOCK: + case GalImageFormat.BC6H_UFLOAT_BLOCK: + case GalImageFormat.BC7_UNORM_BLOCK: + case GalImageFormat.BC2_UNORM_BLOCK: + case GalImageFormat.BC3_UNORM_BLOCK: + case GalImageFormat.BC5_SNORM_BLOCK: + case GalImageFormat.BC5_UNORM_BLOCK: + case GalImageFormat.ASTC_4x4_UNORM_BLOCK: { - return CompressedTextureSize(Texture.Width, Texture.Height, 4, 4, 16); + return CompressedTextureSize(Image.Width, Image.Height, 4, 4, 16); } - case GalTextureFormat.Astc2D5x5: + case GalImageFormat.ASTC_5x5_UNORM_BLOCK: { - return CompressedTextureSize(Texture.Width, Texture.Height, 5, 5, 16); + return CompressedTextureSize(Image.Width, Image.Height, 5, 5, 16); } - case GalTextureFormat.Astc2D6x6: + case GalImageFormat.ASTC_6x6_UNORM_BLOCK: { - return CompressedTextureSize(Texture.Width, Texture.Height, 6, 6, 16); + return CompressedTextureSize(Image.Width, Image.Height, 6, 6, 16); } - case GalTextureFormat.Astc2D8x8: + case GalImageFormat.ASTC_8x8_UNORM_BLOCK: { - return CompressedTextureSize(Texture.Width, Texture.Height, 8, 8, 16); + return CompressedTextureSize(Image.Width, Image.Height, 8, 8, 16); } - case GalTextureFormat.Astc2D10x10: + case GalImageFormat.ASTC_10x10_UNORM_BLOCK: { - return CompressedTextureSize(Texture.Width, Texture.Height, 10, 10, 16); + return CompressedTextureSize(Image.Width, Image.Height, 10, 10, 16); } - case GalTextureFormat.Astc2D12x12: + case GalImageFormat.ASTC_12x12_UNORM_BLOCK: { - return CompressedTextureSize(Texture.Width, Texture.Height, 12, 12, 16); + return CompressedTextureSize(Image.Width, Image.Height, 12, 12, 16); } - case GalTextureFormat.Astc2D5x4: + case GalImageFormat.ASTC_5x4_UNORM_BLOCK: { - return CompressedTextureSize(Texture.Width, Texture.Height, 5, 4, 16); + return CompressedTextureSize(Image.Width, Image.Height, 5, 4, 16); } - case GalTextureFormat.Astc2D6x5: + case GalImageFormat.ASTC_6x5_UNORM_BLOCK: { - return CompressedTextureSize(Texture.Width, Texture.Height, 6, 5, 16); + return CompressedTextureSize(Image.Width, Image.Height, 6, 5, 16); } - case GalTextureFormat.Astc2D8x6: + case GalImageFormat.ASTC_8x6_UNORM_BLOCK: { - return CompressedTextureSize(Texture.Width, Texture.Height, 8, 6, 16); + return CompressedTextureSize(Image.Width, Image.Height, 8, 6, 16); } - case GalTextureFormat.Astc2D10x8: + case GalImageFormat.ASTC_10x8_UNORM_BLOCK: { - return CompressedTextureSize(Texture.Width, Texture.Height, 10, 8, 16); + return CompressedTextureSize(Image.Width, Image.Height, 10, 8, 16); } - case GalTextureFormat.Astc2D12x10: + case GalImageFormat.ASTC_12x10_UNORM_BLOCK: { - return CompressedTextureSize(Texture.Width, Texture.Height, 12, 10, 16); + return CompressedTextureSize(Image.Width, Image.Height, 12, 10, 16); } - case GalTextureFormat.Astc2D8x5: + case GalImageFormat.ASTC_8x5_UNORM_BLOCK: { - return CompressedTextureSize(Texture.Width, Texture.Height, 8, 5, 16); + return CompressedTextureSize(Image.Width, Image.Height, 8, 5, 16); } - case GalTextureFormat.Astc2D10x5: + case GalImageFormat.ASTC_10x5_UNORM_BLOCK: { - return CompressedTextureSize(Texture.Width, Texture.Height, 10, 5, 16); + return CompressedTextureSize(Image.Width, Image.Height, 10, 5, 16); } - case GalTextureFormat.Astc2D10x6: + case GalImageFormat.ASTC_10x6_UNORM_BLOCK: { - return CompressedTextureSize(Texture.Width, Texture.Height, 10, 6, 16); + return CompressedTextureSize(Image.Width, Image.Height, 10, 6, 16); } } - throw new NotImplementedException("0x" + Texture.Format.ToString("x2")); + throw new NotImplementedException("0x" + Image.Format.ToString("x2")); } public static int CompressedTextureSize(int TextureWidth, int TextureHeight, int BlockWidth, int BlockHeight, int Bpb) diff --git a/Ryujinx.HLE/Gpu/Texture/TextureReader.cs b/Ryujinx.HLE/Gpu/Texture/TextureReader.cs index 0cf055db8..19aa25d74 100644 --- a/Ryujinx.HLE/Gpu/Texture/TextureReader.cs +++ b/Ryujinx.HLE/Gpu/Texture/TextureReader.cs @@ -19,6 +19,7 @@ namespace Ryujinx.HLE.Gpu.Texture case GalTextureFormat.Z24S8: return Read4Bpp (Memory, Texture); case GalTextureFormat.A1B5G5R5: return Read5551 (Memory, Texture); case GalTextureFormat.B5G6R5: return Read565 (Memory, Texture); + case GalTextureFormat.A4B4G4R4: return Read2Bpp (Memory, Texture); case GalTextureFormat.G8R8: return Read2Bpp (Memory, Texture); case GalTextureFormat.R16: return Read2Bpp (Memory, Texture); case GalTextureFormat.R8: return Read1Bpp (Memory, Texture);