diff --git a/Ryujinx.Graphics.GAL/Capabilities.cs b/Ryujinx.Graphics.GAL/Capabilities.cs index 8ea4c02a..a42cbb07 100644 --- a/Ryujinx.Graphics.GAL/Capabilities.cs +++ b/Ryujinx.Graphics.GAL/Capabilities.cs @@ -3,6 +3,7 @@ namespace Ryujinx.Graphics.GAL public struct Capabilities { public bool SupportsAstcCompression { get; } + public bool SupportsImageLoadFormatted { get; } public bool SupportsNonConstantTextureOffset { get; } public int MaximumComputeSharedMemorySize { get; } @@ -12,12 +13,14 @@ namespace Ryujinx.Graphics.GAL public Capabilities( bool supportsAstcCompression, + bool supportsImageLoadFormatted, bool supportsNonConstantTextureOffset, int maximumComputeSharedMemorySize, int storageBufferOffsetAlignment, float maxSupportedAnisotropy) { SupportsAstcCompression = supportsAstcCompression; + SupportsImageLoadFormatted = supportsImageLoadFormatted; SupportsNonConstantTextureOffset = supportsNonConstantTextureOffset; MaximumComputeSharedMemorySize = maximumComputeSharedMemorySize; StorageBufferOffsetAlignment = storageBufferOffsetAlignment; diff --git a/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs b/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs index 7dc175e1..76b06ea5 100644 --- a/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs +++ b/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs @@ -175,6 +175,12 @@ namespace Ryujinx.Graphics.Gpu.Shader /// Host storage buffer alignment in bytes public int QueryStorageBufferOffsetAlignment() => _context.Capabilities.StorageBufferOffsetAlignment; + /// + /// Queries host support for readable images without a explicit format declaration on the shader. + /// + /// True if formatted image load is supported, false otherwise + public bool QuerySupportsImageLoadFormatted() => _context.Capabilities.SupportsImageLoadFormatted; + /// /// Queries host GPU non-constant texture offset support. /// diff --git a/Ryujinx.Graphics.OpenGL/HwCapabilities.cs b/Ryujinx.Graphics.OpenGL/HwCapabilities.cs index 4b572af8..229b3561 100644 --- a/Ryujinx.Graphics.OpenGL/HwCapabilities.cs +++ b/Ryujinx.Graphics.OpenGL/HwCapabilities.cs @@ -5,7 +5,8 @@ namespace Ryujinx.Graphics.OpenGL { static class HwCapabilities { - private static readonly Lazy _supportsAstcCompression = new Lazy(() => HasExtension("GL_KHR_texture_compression_astc_ldr")); + private static readonly Lazy _supportsAstcCompression = new Lazy(() => HasExtension("GL_KHR_texture_compression_astc_ldr")); + private static readonly Lazy _supportsImageLoadFormatted = new Lazy(() => HasExtension("GL_EXT_shader_image_load_formatted")); private static readonly Lazy _maximumComputeSharedMemorySize = new Lazy(() => GetLimit(All.MaxComputeSharedMemorySize)); private static readonly Lazy _storageBufferOffsetAlignment = new Lazy(() => GetLimit(All.ShaderStorageBufferOffsetAlignment)); @@ -25,6 +26,7 @@ namespace Ryujinx.Graphics.OpenGL private static Lazy _maxSupportedAnisotropy = new Lazy(GL.GetFloat((GetPName)All.MaxTextureMaxAnisotropy)); public static bool SupportsAstcCompression => _supportsAstcCompression.Value; + public static bool SupportsImageLoadFormatted => _supportsImageLoadFormatted.Value; public static bool SupportsNonConstantTextureOffset => _gpuVendor.Value == GpuVendor.Nvidia; public static int MaximumComputeSharedMemorySize => _maximumComputeSharedMemorySize.Value; diff --git a/Ryujinx.Graphics.OpenGL/Renderer.cs b/Ryujinx.Graphics.OpenGL/Renderer.cs index 15b223f5..c839c296 100644 --- a/Ryujinx.Graphics.OpenGL/Renderer.cs +++ b/Ryujinx.Graphics.OpenGL/Renderer.cs @@ -73,6 +73,7 @@ namespace Ryujinx.Graphics.OpenGL { return new Capabilities( HwCapabilities.SupportsAstcCompression, + HwCapabilities.SupportsImageLoadFormatted, HwCapabilities.SupportsNonConstantTextureOffset, HwCapabilities.MaximumComputeSharedMemorySize, HwCapabilities.StorageBufferOffsetAlignment, diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs index da902aa3..a45c10c3 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs +++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs @@ -19,6 +19,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl context.AppendLine("#extension GL_ARB_gpu_shader_int64 : enable"); context.AppendLine("#extension GL_ARB_shader_ballot : enable"); context.AppendLine("#extension GL_ARB_shader_group_vote : enable"); + context.AppendLine("#extension GL_EXT_shader_image_load_formatted : enable"); if (context.Config.Stage == ShaderStage.Compute) { diff --git a/Ryujinx.Graphics.Shader/Decoders/OpCodeImage.cs b/Ryujinx.Graphics.Shader/Decoders/OpCodeImage.cs index 42fe677b..265d45a9 100644 --- a/Ryujinx.Graphics.Shader/Decoders/OpCodeImage.cs +++ b/Ryujinx.Graphics.Shader/Decoders/OpCodeImage.cs @@ -37,7 +37,7 @@ namespace Ryujinx.Graphics.Shader.Decoders Size = (IntegerSize)opCode.Extract(20, 4); } - ByteAddress = !opCode.Extract(23); + ByteAddress = opCode.Extract(23); Dimensions = (ImageDimensions)opCode.Extract(33, 3); diff --git a/Ryujinx.Graphics.Shader/IGpuAccessor.cs b/Ryujinx.Graphics.Shader/IGpuAccessor.cs index 13281bf0..e10d869b 100644 --- a/Ryujinx.Graphics.Shader/IGpuAccessor.cs +++ b/Ryujinx.Graphics.Shader/IGpuAccessor.cs @@ -54,6 +54,11 @@ return 16; } + public bool QuerySupportsImageLoadFormatted() + { + return true; + } + public bool QuerySupportsNonConstantTextureOffset() { return true; diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs index af5122be..7bed3f30 100644 --- a/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs +++ b/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs @@ -1217,6 +1217,13 @@ namespace Ryujinx.Graphics.Shader.Instructions private static TextureFormat GetTextureFormat(EmitterContext context, int handle) { + // When the formatted load extension is supported, we don't need to + // specify a format, we can just declare it without a format and the GPU will handle it. + if (context.Config.GpuAccessor.QuerySupportsImageLoadFormatted()) + { + return TextureFormat.Unknown; + } + var format = context.Config.GpuAccessor.QueryTextureFormat(handle); if (format == TextureFormat.Unknown)