From 6577a63d368afa57d5f29df40e524af30eaabffa Mon Sep 17 00:00:00 2001
From: ameerj <52414509+ameerj@users.noreply.github.com>
Date: Wed, 2 Jun 2021 00:48:49 -0400
Subject: glsl: skip gl_ViewportIndex write if device does not support it

---
 src/shader_recompiler/backend/glsl/emit_context.cpp    | 18 ++++++++++--------
 src/shader_recompiler/backend/glsl/emit_context.h      |  1 +
 .../backend/glsl/emit_glsl_context_get_set.cpp         |  5 +++++
 src/shader_recompiler/profile.h                        |  1 +
 src/video_core/renderer_opengl/gl_shader_cache.cpp     |  1 +
 5 files changed, 18 insertions(+), 8 deletions(-)

(limited to 'src')

diff --git a/src/shader_recompiler/backend/glsl/emit_context.cpp b/src/shader_recompiler/backend/glsl/emit_context.cpp
index 58355d5e33..846d38bfc8 100644
--- a/src/shader_recompiler/backend/glsl/emit_context.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_context.cpp
@@ -148,23 +148,24 @@ std::string_view OutputPrimitive(OutputTopology topology) {
     throw InvalidArgument("Invalid output topology {}", topology);
 }
 
-void SetupOutPerVertex(Stage stage, const Info& info, std::string& header) {
-    if (!StoresPerVertexAttributes(stage)) {
+void SetupOutPerVertex(EmitContext& ctx, std::string& header) {
+    if (!StoresPerVertexAttributes(ctx.stage)) {
         return;
     }
     header += "out gl_PerVertex{";
     header += "vec4 gl_Position;";
-    if (info.stores_point_size) {
+    if (ctx.info.stores_point_size) {
         header += "float gl_PointSize;";
     }
-    if (info.stores_clip_distance) {
+    if (ctx.info.stores_clip_distance) {
         header += "float gl_ClipDistance[];";
     }
-    if (info.stores_viewport_index && stage != Stage::Geometry) {
+    if (ctx.info.stores_viewport_index && ctx.supports_viewport_layer &&
+        ctx.stage != Stage::Geometry) {
         header += "int gl_ViewportIndex;";
     }
     header += "};\n";
-    if (info.stores_viewport_index && stage == Stage::Geometry) {
+    if (ctx.info.stores_viewport_index && ctx.stage == Stage::Geometry) {
         header += "out int gl_ViewportIndex;";
     }
 }
@@ -173,6 +174,7 @@ void SetupOutPerVertex(Stage stage, const Info& info, std::string& header) {
 EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile& profile_,
                          const RuntimeInfo& runtime_info_)
     : info{program.info}, profile{profile_}, runtime_info{runtime_info_} {
+    supports_viewport_layer = profile.support_gl_vertex_viewport_layer;
     SetupExtensions(header);
     stage = program.stage;
     switch (program.stage) {
@@ -206,7 +208,7 @@ EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile
                               program.workgroup_size[2]);
         break;
     }
-    SetupOutPerVertex(stage, info, header);
+    SetupOutPerVertex(*this, header);
     for (size_t index = 0; index < info.input_generics.size(); ++index) {
         const auto& generic{info.input_generics[index]};
         if (generic.used) {
@@ -276,7 +278,7 @@ void EmitContext::SetupExtensions(std::string&) {
             header += "#extension GL_ARB_gpu_shader_int64 : enable\n";
         }
     }
-    if (info.stores_viewport_index && stage != Stage::Geometry) {
+    if (info.stores_viewport_index && supports_viewport_layer && stage != Stage::Geometry) {
         header += "#extension GL_ARB_shader_viewport_layer_array : enable\n";
     }
 }
diff --git a/src/shader_recompiler/backend/glsl/emit_context.h b/src/shader_recompiler/backend/glsl/emit_context.h
index 5d48675e6b..26a76f8a37 100644
--- a/src/shader_recompiler/backend/glsl/emit_context.h
+++ b/src/shader_recompiler/backend/glsl/emit_context.h
@@ -159,6 +159,7 @@ public:
 
     bool uses_y_direction{};
     bool uses_cc_carry{};
+    bool supports_viewport_layer{};
 
 private:
     void SetupExtensions(std::string& header);
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp
index c48492a17c..ebaf50abde 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp
@@ -226,6 +226,11 @@ void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, std::string_view val
         ctx.Add("gl_Position.{}={};", swizzle, value);
         break;
     case IR::Attribute::ViewportIndex:
+        if (ctx.stage != Stage::Geometry && !ctx.supports_viewport_layer) {
+            // LOG_WARNING(..., "Shader stores viewport index but device does not support viewport
+            // layer extension");
+            break;
+        }
         ctx.Add("gl_ViewportIndex=floatBitsToInt({});", value);
         break;
     case IR::Attribute::ClipDistance0:
diff --git a/src/shader_recompiler/profile.h b/src/shader_recompiler/profile.h
index 5d269368ae..4201171327 100644
--- a/src/shader_recompiler/profile.h
+++ b/src/shader_recompiler/profile.h
@@ -85,6 +85,7 @@ struct Profile {
     bool support_derivative_control{};
     bool support_gl_nv_gpu_shader_5{};
     bool support_gl_amd_gpu_shader_half_float{};
+    bool support_gl_vertex_viewport_layer{};
 
     bool warp_size_potentially_larger_than_guest{};
 
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp
index 0a1ba363b6..77681594ad 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp
@@ -225,6 +225,7 @@ ShaderCache::ShaderCache(RasterizerOpenGL& rasterizer_, Core::Frontend::EmuWindo
           .support_derivative_control = device.HasDerivativeControl(),
           .support_gl_nv_gpu_shader_5 = device.HasNvGpuShader5(),
           .support_gl_amd_gpu_shader_half_float = device.HasAmdShaderHalfFloat(),
+          .support_gl_vertex_viewport_layer = device.HasVertexViewportLayer(),
 
           .warp_size_potentially_larger_than_guest = device.IsWarpSizePotentiallyLargerThanGuest(),
 
-- 
cgit v1.2.3-70-g09d2