diff --git a/Ryujinx.Graphics.GAL/Capabilities.cs b/Ryujinx.Graphics.GAL/Capabilities.cs
index e388f0e55a..d0c63bf257 100644
--- a/Ryujinx.Graphics.GAL/Capabilities.cs
+++ b/Ryujinx.Graphics.GAL/Capabilities.cs
@@ -4,8 +4,9 @@ namespace Ryujinx.Graphics.GAL
{
public bool SupportsAstcCompression { get; }
public bool SupportsImageLoadFormatted { get; }
- public bool SupportsNonConstantTextureOffset { get; }
public bool SupportsMismatchingViewFormat { get; }
+ public bool SupportsNonConstantTextureOffset { get; }
+ public bool SupportsTextureShadowLod { get; }
public bool SupportsViewportSwizzle { get; }
public int MaximumComputeSharedMemorySize { get; }
@@ -15,8 +16,9 @@ namespace Ryujinx.Graphics.GAL
public Capabilities(
bool supportsAstcCompression,
bool supportsImageLoadFormatted,
- bool supportsNonConstantTextureOffset,
bool supportsMismatchingViewFormat,
+ bool supportsNonConstantTextureOffset,
+ bool supportsTextureShadowLod,
bool supportsViewportSwizzle,
int maximumComputeSharedMemorySize,
float maximumSupportedAnisotropy,
@@ -24,8 +26,9 @@ namespace Ryujinx.Graphics.GAL
{
SupportsAstcCompression = supportsAstcCompression;
SupportsImageLoadFormatted = supportsImageLoadFormatted;
- SupportsNonConstantTextureOffset = supportsNonConstantTextureOffset;
SupportsMismatchingViewFormat = supportsMismatchingViewFormat;
+ SupportsNonConstantTextureOffset = supportsNonConstantTextureOffset;
+ SupportsTextureShadowLod = supportsTextureShadowLod;
SupportsViewportSwizzle = supportsViewportSwizzle;
MaximumComputeSharedMemorySize = maximumComputeSharedMemorySize;
MaximumSupportedAnisotropy = maximumSupportedAnisotropy;
diff --git a/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs b/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs
index 75ff037e15..4381301b15 100644
--- a/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs
@@ -180,6 +180,12 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// True if the GPU and driver supports non-constant texture offsets, false otherwise
public bool QuerySupportsNonConstantTextureOffset() => _context.Capabilities.SupportsNonConstantTextureOffset;
+ ///
+ /// Queries host GPU texture shadow LOD support.
+ ///
+ /// True if the GPU and driver supports texture shadow LOD, false otherwise
+ public bool QuerySupportsTextureShadowLod() => _context.Capabilities.SupportsTextureShadowLod;
+
///
/// Gets the texture descriptor for a given texture on the pool.
///
diff --git a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
index f9ad0ad28e..6813a44026 100644
--- a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
@@ -36,7 +36,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
///
/// Version of the codegen (to be changed when codegen or guest format change).
///
- private const ulong ShaderCodeGenVersion = 2397;
+ private const ulong ShaderCodeGenVersion = 2404;
// Progress reporting helpers
private volatile int _shaderCount;
diff --git a/Ryujinx.Graphics.OpenGL/HwCapabilities.cs b/Ryujinx.Graphics.OpenGL/HwCapabilities.cs
index 97574aea92..a971d5fcc9 100644
--- a/Ryujinx.Graphics.OpenGL/HwCapabilities.cs
+++ b/Ryujinx.Graphics.OpenGL/HwCapabilities.cs
@@ -7,11 +7,12 @@ namespace Ryujinx.Graphics.OpenGL
{
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 _supportsPolygonOffsetClamp = new Lazy(() => HasExtension("GL_EXT_polygon_offset_clamp"));
- private static readonly Lazy _supportsViewportSwizzle = new Lazy(() => HasExtension("GL_NV_viewport_swizzle"));
- private static readonly Lazy _supportsSeamlessCubemapPerTexture = new Lazy(() => HasExtension("GL_ARB_seamless_cubemap_per_texture"));
private static readonly Lazy _supportsParallelShaderCompile = new Lazy(() => HasExtension("GL_ARB_parallel_shader_compile"));
+ private static readonly Lazy _supportsPolygonOffsetClamp = new Lazy(() => HasExtension("GL_EXT_polygon_offset_clamp"));
private static readonly Lazy _supportsQuads = new Lazy(SupportsQuadsCheck);
+ private static readonly Lazy _supportsSeamlessCubemapPerTexture = new Lazy(() => HasExtension("GL_ARB_seamless_cubemap_per_texture"));
+ private static readonly Lazy _supportsTextureShadowLod = new Lazy(() => HasExtension("GL_EXT_texture_shadow_lod"));
+ private static readonly Lazy _supportsViewportSwizzle = new Lazy(() => HasExtension("GL_NV_viewport_swizzle"));
private static readonly Lazy _maximumComputeSharedMemorySize = new Lazy(() => GetLimit(All.MaxComputeSharedMemorySize));
private static readonly Lazy _storageBufferOffsetAlignment = new Lazy(() => GetLimit(All.ShaderStorageBufferOffsetAlignment));
@@ -33,14 +34,16 @@ namespace Ryujinx.Graphics.OpenGL
public static bool SupportsAstcCompression => _supportsAstcCompression.Value;
public static bool SupportsImageLoadFormatted => _supportsImageLoadFormatted.Value;
- public static bool SupportsPolygonOffsetClamp => _supportsPolygonOffsetClamp.Value;
- public static bool SupportsViewportSwizzle => _supportsViewportSwizzle.Value;
- public static bool SupportsSeamlessCubemapPerTexture => _supportsSeamlessCubemapPerTexture.Value;
public static bool SupportsParallelShaderCompile => _supportsParallelShaderCompile.Value;
+ public static bool SupportsPolygonOffsetClamp => _supportsPolygonOffsetClamp.Value;
public static bool SupportsQuads => _supportsQuads.Value;
- public static bool SupportsNonConstantTextureOffset => _gpuVendor.Value == GpuVendor.Nvidia;
- public static bool RequiresSyncFlush => _gpuVendor.Value == GpuVendor.Amd || _gpuVendor.Value == GpuVendor.IntelWindows || _gpuVendor.Value == GpuVendor.IntelUnix;
- public static bool SupportsMismatchingViewFormat => _gpuVendor.Value != GpuVendor.Amd && _gpuVendor.Value != GpuVendor.IntelWindows;
+ public static bool SupportsSeamlessCubemapPerTexture => _supportsSeamlessCubemapPerTexture.Value;
+ public static bool SupportsTextureShadowLod => _supportsTextureShadowLod.Value;
+ public static bool SupportsViewportSwizzle => _supportsViewportSwizzle.Value;
+
+ public static bool SupportsMismatchingViewFormat => _gpuVendor.Value != GpuVendor.Amd && _gpuVendor.Value != GpuVendor.IntelWindows;
+ public static bool SupportsNonConstantTextureOffset => _gpuVendor.Value == GpuVendor.Nvidia;
+ public static bool RequiresSyncFlush => _gpuVendor.Value == GpuVendor.Amd || _gpuVendor.Value == GpuVendor.IntelWindows || _gpuVendor.Value == GpuVendor.IntelUnix;
public static int MaximumComputeSharedMemorySize => _maximumComputeSharedMemorySize.Value;
public static int StorageBufferOffsetAlignment => _storageBufferOffsetAlignment.Value;
@@ -78,7 +81,7 @@ namespace Ryujinx.Graphics.OpenGL
else if (vendor == "intel")
{
string renderer = GL.GetString(StringName.Renderer).ToLower();
-
+
return renderer.Contains("mesa") ? GpuVendor.IntelUnix : GpuVendor.IntelWindows;
}
else if (vendor == "ati technologies inc." || vendor == "advanced micro devices, inc.")
diff --git a/Ryujinx.Graphics.OpenGL/Renderer.cs b/Ryujinx.Graphics.OpenGL/Renderer.cs
index 7416cdd7ad..a2be43730b 100644
--- a/Ryujinx.Graphics.OpenGL/Renderer.cs
+++ b/Ryujinx.Graphics.OpenGL/Renderer.cs
@@ -1,4 +1,4 @@
-using OpenTK.Graphics;
+using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
@@ -96,8 +96,9 @@ namespace Ryujinx.Graphics.OpenGL
return new Capabilities(
HwCapabilities.SupportsAstcCompression,
HwCapabilities.SupportsImageLoadFormatted,
- HwCapabilities.SupportsNonConstantTextureOffset,
HwCapabilities.SupportsMismatchingViewFormat,
+ HwCapabilities.SupportsNonConstantTextureOffset,
+ HwCapabilities.SupportsTextureShadowLod,
HwCapabilities.SupportsViewportSwizzle,
HwCapabilities.MaximumComputeSharedMemorySize,
HwCapabilities.MaximumSupportedAnisotropy,
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
index 2e993ef0ba..4471fa3223 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
@@ -20,6 +20,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
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");
+ context.AppendLine("#extension GL_EXT_texture_shadow_lod : enable");
if (context.Config.Stage == ShaderStage.Compute)
{
@@ -32,7 +33,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
}
context.AppendLine("#pragma optionNV(fastmath off)");
-
context.AppendLine();
context.AppendLine($"const int {DefaultNames.UndefinedName} = 0;");
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs
index 911c7b0566..cb99bdcc43 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs
@@ -309,20 +309,32 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
bool isMultisample = (texOp.Type & SamplerType.Multisample) != 0;
bool isShadow = (texOp.Type & SamplerType.Shadow) != 0;
+ SamplerType type = texOp.Type & SamplerType.Mask;
+
+ bool is2D = type == SamplerType.Texture2D;
+ bool isCube = type == SamplerType.TextureCube;
+
+ // 2D Array and Cube shadow samplers with LOD level or bias requires an extension.
+ // If the extension is not supported, just remove the LOD parameter.
+ if (isArray && isShadow && (is2D || isCube) && !context.Config.GpuAccessor.QuerySupportsTextureShadowLod())
+ {
+ hasLodBias = false;
+ hasLodLevel = false;
+ }
+
+ // Cube shadow samplers with LOD level requires an extension.
+ // If the extension is not supported, just remove the LOD level parameter.
+ if (isShadow && isCube && !context.Config.GpuAccessor.QuerySupportsTextureShadowLod())
+ {
+ hasLodLevel = false;
+ }
+
// TODO: Bindless texture support. For now we just return 0.
if (isBindless)
{
return NumberFormatter.FormatFloat(0);
}
- // This combination is valid, but not available on GLSL.
- // For now, ignore the LOD level and do a normal sample.
- // TODO: How to implement it properly?
- if (hasLodLevel && isArray && isShadow)
- {
- hasLodLevel = false;
- }
-
string texCall = intCoords ? "texelFetch" : "texture";
if (isGather)
diff --git a/Ryujinx.Graphics.Shader/IGpuAccessor.cs b/Ryujinx.Graphics.Shader/IGpuAccessor.cs
index 6b584e533e..26a8cafdb0 100644
--- a/Ryujinx.Graphics.Shader/IGpuAccessor.cs
+++ b/Ryujinx.Graphics.Shader/IGpuAccessor.cs
@@ -74,6 +74,11 @@
return true;
}
+ bool QuerySupportsTextureShadowLod()
+ {
+ return true;
+ }
+
TextureFormat QueryTextureFormat(int handle, int cbufSlot = -1)
{
return TextureFormat.R8G8B8A8Unorm;