Browse Source

glgsg: More efficient alpha test injection for spirv-cross case

It's worth doing it this way rather than creating a SPIR-V transformation pipeline just for this one thing, which is slower

I'll try to get this upstreamed to SPIRV-Cross in some form when I have time so we don't have to subclass CompilerGLSL
rdb 1 year ago
parent
commit
2308c63415
1 changed files with 63 additions and 21 deletions
  1. 63 21
      panda/src/glstuff/glShaderContext_src.cxx

+ 63 - 21
panda/src/glstuff/glShaderContext_src.cxx

@@ -43,6 +43,49 @@ using std::max;
 using std::min;
 using std::string;
 
+// Inject alpha test into generated shaders.
+class Compiler final : public spirv_cross::CompilerGLSL {
+public:
+  explicit Compiler(std::vector<uint32_t> spirv_,
+                    RenderAttrib::PandaCompareFunc alpha_test_mode)
+    : CompilerGLSL(std::move(spirv_)),
+      _alpha_test_mode(alpha_test_mode) {
+  }
+
+private:
+  virtual void emit_fixup() override {
+    switch (_alpha_test_mode) {
+    case RenderAttrib::M_never:
+      statement("discard;");
+      break;
+    case RenderAttrib::M_less:
+      statement("if (o0.a >= aref) discard;");
+      break;
+    case RenderAttrib::M_equal:
+      statement("if (o0.a != aref) discard;");
+      break;
+    case RenderAttrib::M_less_equal:
+      statement("if (o0.a > aref) discard;");
+      break;
+    case RenderAttrib::M_greater:
+      statement("if (o0.a <= aref) discard;");
+      break;
+    case RenderAttrib::M_not_equal:
+      statement("if (o0.a == aref) discard;");
+      break;
+    case RenderAttrib::M_greater_equal:
+      statement("if (o0.a < aref) discard;");
+      break;
+    case RenderAttrib::M_none:
+    case RenderAttrib::M_always:
+      break;
+    }
+    CompilerGLSL::emit_fixup();
+  }
+
+  RenderAttrib::PandaCompareFunc _alpha_test_mode;
+};
+
 TypeHandle CLP(ShaderContext)::_type_handle;
 
 /**
@@ -75,7 +118,7 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
     // alpha test mode that may be applied.  This doesn't apply to the legacy
     // pipeline since we can't modify shaders there.
     if (s->_module_mask & (1u << (uint32_t)Shader::Stage::FRAGMENT)) {
-      _inject_alpha_test = !glgsg->has_fixed_function_pipeline();
+      _inject_alpha_test = !s->_subsumes_alpha_test && !glgsg->has_fixed_function_pipeline();
     }
 
     // Ignoring any locations that may have already been set, we assign a new
@@ -2696,20 +2739,7 @@ create_shader(GLuint program, const ShaderModule *module,
         _emulate_float_attribs = true;
       }
 
-      uint32_t alpha_ref_var_id = 0;
-      ShaderModuleSpirV::InstructionStream stream;
-      if (stage == ShaderModule::Stage::FRAGMENT &&
-          alpha_test_mode != RenderAttrib::M_none) {
-        SpirVTransformer transformer(spv->_instructions);
-        {
-          SpirVInjectAlphaTestPass pass((SpirVInjectAlphaTestPass::Mode)alpha_test_mode);
-          transformer.run(pass);
-          alpha_ref_var_id = pass._alpha_ref_var_id;
-        }
-        stream = transformer.get_result();
-      } else {
-        stream = spv->_instructions;
-      }
+      ShaderModuleSpirV::InstructionStream stream = spv->_instructions;
 
       // It's really important that we don't have any member name decorations
       // if we're going to end up remapping the locations, because we rely on
@@ -2731,9 +2761,25 @@ create_shader(GLuint program, const ShaderModule *module,
         }
       }
 
-      spirv_cross::CompilerGLSL compiler(std::move(stream._words));
+      if (stage != ShaderModule::Stage::FRAGMENT) {
+        alpha_test_mode = RenderAttrib::M_none;
+      }
+
+      Compiler compiler(std::move(stream._words), alpha_test_mode);
       compiler.set_common_options(options);
 
+      if (alpha_test_mode != RenderAttrib::M_none &&
+          alpha_test_mode != RenderAttrib::M_always &&
+          alpha_test_mode != RenderAttrib::M_never) {
+        if ((!options.es && options.version < 430) ||
+            (options.es && options.version < 310)) {
+          compiler.add_header_line("uniform float aref;");
+          _remap_locations = true;
+        } else {
+          compiler.add_header_line("layout(location=0) uniform float aref;");
+        }
+      }
+
       // At this time, SPIRV-Cross doesn't always add these automatically.
       uint64_t used_caps = module->get_used_capabilities();
 #ifndef OPENGLES
@@ -2778,11 +2824,7 @@ create_shader(GLuint program, const ShaderModule *module,
         spv::StorageClass sc = compiler.get_storage_class(id);
 
         char buf[1024];
-        if (id != 0 && id == alpha_ref_var_id) {
-          compiler.set_name(id, "aref");
-          compiler.set_decoration(id, spv::DecorationLocation, 0);
-        }
-        else if (sc == spv::StorageClassUniformConstant) {
+        if (sc == spv::StorageClassUniformConstant) {
           auto it = id_to_location.find(id);
           if (it != id_to_location.end()) {
             sprintf(buf, "p%u", it->second);