Browse Source

glsl: Use textureGrad fallback when EXT_texture_shadow_lod is unsupported

ameerj 5 years ago
parent
commit
747b8556a4

+ 3 - 1
src/shader_recompiler/backend/glsl/emit_context.cpp

@@ -282,8 +282,10 @@ EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile
 void EmitContext::SetupExtensions(std::string&) {
     // TODO: track this usage
     header += "#extension GL_ARB_sparse_texture2 : enable\n"
-              "#extension GL_EXT_texture_shadow_lod : enable\n"
               "#extension GL_EXT_shader_image_load_formatted : enable\n";
+    if (profile.support_gl_texture_shadow_lod) {
+        header += "#extension GL_EXT_texture_shadow_lod : enable\n";
+    }
     if (info.uses_int64) {
         header += "#extension GL_ARB_gpu_shader_int64 : enable\n";
     }

+ 37 - 7
src/shader_recompiler/backend/glsl/emit_glsl_image.cpp

@@ -8,6 +8,7 @@
 #include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
 #include "shader_recompiler/frontend/ir/modifiers.h"
 #include "shader_recompiler/frontend/ir/value.h"
+#include "shader_recompiler/profile.h"
 
 namespace Shader::Backend::GLSL {
 namespace {
@@ -67,14 +68,14 @@ std::string TexelFetchCastToInt(std::string_view value, const IR::TextureInstInf
     }
 }
 
-std::string ShadowSamplerVecCast(TextureType type) {
+bool NeedsShadowLodExt(TextureType type) {
     switch (type) {
     case TextureType::ColorArray2D:
     case TextureType::ColorCube:
     case TextureType::ColorArrayCube:
-        return "vec4";
+        return true;
     default:
-        return "vec3";
+        return false;
     }
 }
 
@@ -221,7 +222,22 @@ void EmitImageSampleDrefImplicitLod([[maybe_unused]] EmitContext& ctx,
     }
     const auto texture{Texture(ctx, info, index)};
     const auto bias{info.has_bias ? fmt::format(",{}", bias_lc) : ""};
-    const auto cast{ShadowSamplerVecCast(info.type)};
+    const bool needs_shadow_ext{NeedsShadowLodExt(info.type)};
+    const auto cast{needs_shadow_ext ? "vec4" : "vec3"};
+    const bool use_grad{!ctx.profile.support_gl_texture_shadow_lod &&
+                        ctx.stage != Stage::Fragment && needs_shadow_ext};
+    if (use_grad) {
+        // LOG_WARNING(..., "Device lacks GL_EXT_texture_shadow_lod. Using textureGrad fallback");
+        if (info.type == TextureType::ColorArrayCube) {
+            // LOG_WARNING(..., "textureGrad does not support ColorArrayCube. Stubbing");
+            ctx.AddF32("{}=0.0f;", inst);
+            return;
+        }
+        const auto d_cast{info.type == TextureType::ColorArray2D ? "vec2" : "vec3"};
+        ctx.AddF32("{}=textureGrad({},{}({},{}),{}(0),{}(0));", inst, texture, cast, coords, dref,
+                   d_cast, d_cast);
+        return;
+    }
     if (!offset.IsEmpty()) {
         const auto offset_str{GetOffsetVec(ctx, offset)};
         if (ctx.stage == Stage::Fragment) {
@@ -263,15 +279,29 @@ void EmitImageSampleDrefExplicitLod([[maybe_unused]] EmitContext& ctx,
         throw NotImplementedException("EmitImageSampleDrefExplicitLod Lod clamp samples");
     }
     const auto texture{Texture(ctx, info, index)};
-    const auto cast{ShadowSamplerVecCast(info.type)};
+    const bool needs_shadow_ext{NeedsShadowLodExt(info.type)};
+    const bool use_grad{!ctx.profile.support_gl_texture_shadow_lod && needs_shadow_ext};
+    const auto cast{needs_shadow_ext ? "vec4" : "vec3"};
+    if (use_grad) {
+        // LOG_WARNING(..., "Device lacks GL_EXT_texture_shadow_lod. Using textureGrad fallback");
+        if (info.type == TextureType::ColorArrayCube) {
+            // LOG_WARNING(..., "textureGrad does not support ColorArrayCube. Stubbing");
+            ctx.AddF32("{}=0.0f;", inst);
+            return;
+        }
+        const auto d_cast{info.type == TextureType::ColorArray2D ? "vec2" : "vec3"};
+        ctx.AddF32("{}=textureGrad({},{}({},{}),{}(0),{}(0));", inst, texture, cast, coords, dref,
+                   d_cast, d_cast);
+        return;
+    }
     if (!offset.IsEmpty()) {
         const auto offset_str{GetOffsetVec(ctx, offset)};
         if (info.type == TextureType::ColorArrayCube) {
             ctx.AddF32("{}=textureLodOffset({},{},{},{},{});", inst, texture, coords, dref, lod_lc,
                        offset_str);
         } else {
-            ctx.AddF32("{}=textureLodOffset({},vec3({},{}),{},{});", inst, texture, coords, dref,
-                       lod_lc, offset_str);
+            ctx.AddF32("{}=textureLodOffset({},{}({},{}),{},{});", inst, texture, cast, coords,
+                       dref, lod_lc, offset_str);
         }
     } else {
         if (info.type == TextureType::ColorArrayCube) {

+ 1 - 0
src/shader_recompiler/profile.h

@@ -86,6 +86,7 @@ struct Profile {
     bool support_gl_nv_gpu_shader_5{};
     bool support_gl_amd_gpu_shader_half_float{};
     bool support_gl_vertex_viewport_layer{};
+    bool support_gl_texture_shadow_lod{};
 
     bool warp_size_potentially_larger_than_guest{};
 

+ 1 - 0
src/video_core/renderer_opengl/gl_shader_cache.cpp

@@ -226,6 +226,7 @@ ShaderCache::ShaderCache(RasterizerOpenGL& rasterizer_, Core::Frontend::EmuWindo
           .support_gl_nv_gpu_shader_5 = device.HasNvGpuShader5(),
           .support_gl_amd_gpu_shader_half_float = device.HasAmdShaderHalfFloat(),
           .support_gl_vertex_viewport_layer = device.HasVertexViewportLayer(),
+          .support_gl_texture_shadow_lod = device.HasTextureShadowLod(),
 
           .warp_size_potentially_larger_than_guest = device.IsWarpSizePotentiallyLargerThanGuest(),