Browse Source

shaderpipeline: Assorted improvements

rdb 1 year ago
parent
commit
a39cb54ae8

+ 5 - 5
panda/src/display/shaderInputBinding_impls.I

@@ -56,7 +56,7 @@ ShaderPackedLightBinding(int index) :
 INLINE ShaderLegacyLightBinding::
 ShaderLegacyLightBinding(CPT_InternalName input, ShaderEnums::StateMatrix matrix,
                          CPT_InternalName arg) :
-  _input(std::move(input)),
+  _input(input.p()),
   _matrix(matrix),
   _arg(std::move(arg)) {
 }
@@ -78,7 +78,7 @@ ShaderTextureStagesBinding(Texture::TextureType desired_type, size_t count,
  */
 INLINE ShaderTextureBinding::
 ShaderTextureBinding(CPT(InternalName) input, Texture::TextureType desired_type) :
-  _input(std::move(input)),
+  _input(input.p()),
   _desired_type(desired_type) {
 }
 
@@ -87,7 +87,7 @@ ShaderTextureBinding(CPT(InternalName) input, Texture::TextureType desired_type)
  */
 INLINE ShaderBufferBinding::
 ShaderBufferBinding(CPT(InternalName) input, size_t min_size) :
-  _input(std::move(input)),
+  _input(input.p()),
   _min_size(min_size) {
 }
 
@@ -95,9 +95,9 @@ ShaderBufferBinding(CPT(InternalName) input, size_t min_size) :
  *
  */
 INLINE ShaderDataBinding::
-ShaderDataBinding(CPT_InternalName input,
+ShaderDataBinding(const InternalName *input,
                   size_t num_elements, size_t num_rows, size_t num_cols) :
-  _input(std::move(input)),
+  _input(input),
   _num_elements(num_elements),
   _num_rows(num_rows),
   _num_cols(num_cols) {

+ 1 - 1
panda/src/display/shaderInputBinding_impls.h

@@ -272,7 +272,7 @@ protected:
  */
 class EXPCL_PANDA_DISPLAY ShaderDataBinding : public ShaderInputBinding {
 public:
-  INLINE ShaderDataBinding(CPT_InternalName input, size_t num_elements,
+  INLINE ShaderDataBinding(const InternalName *input, size_t num_elements,
                            size_t num_rows, size_t num_cols);
 
   virtual int get_state_dep() const override;

+ 8 - 2
panda/src/shaderpipeline/spirVHoistStructResourcesPass.cxx

@@ -66,9 +66,15 @@ transform_definition_op(Instruction op) {
           delete_struct_member(type_id, i - 1);
           changed = true;
         }
+        else if (def._members[i - 1]._builtin != spv::BuiltInMax) {
+          // Leave built-in members untouched--we never add this to the struct
+          // type definition in Panda3D.
+          new_args.push_back(op.args[i]);
+          continue;
+        }
         else {
-          const ShaderType::Struct::Member &member = struct_type->get_member(i - 1);
-          new_struct.add_member(member.type, member.name, member.offset);
+          const MemberDefinition &member_def = def._members[i - 1];
+          new_struct.add_member(resolve_type(member_def._type_id), member_def._name, member_def._offset);
           new_args.push_back(op.args[i]);
         }
       }

+ 25 - 5
panda/src/shaderpipeline/spirVInjectAlphaTestPass.cxx

@@ -97,15 +97,25 @@ transform_function_op(Instruction op) {
     }
 
     if (_alpha_ref_var_id == 0) {
-      _alpha_ref_var_id = define_variable(ShaderType::float_type, spv::StorageClassUniformConstant);
-      if (_ref_location >= 0) {
-        decorate(_alpha_ref_var_id, spv::DecorationLocation, (uint32_t)_ref_location);
+      if (_spec_constant) {
+        _alpha_ref_var_id = define_spec_constant(ShaderType::float_type, 0);
+        if (_ref_location >= 0) {
+          decorate(_alpha_ref_var_id, spv::DecorationSpecId, (uint32_t)_ref_location);
+        }
+      } else {
+        _alpha_ref_var_id = define_variable(ShaderType::float_type, spv::StorageClassUniformConstant);
+        if (_ref_location >= 0) {
+          decorate(_alpha_ref_var_id, spv::DecorationLocation, (uint32_t)_ref_location);
+        }
       }
     }
     uint32_t alpha = op_load(op_access_chain(_var_id, {define_int_constant(3)}));
-    uint32_t ref = op_load(_alpha_ref_var_id);
+    uint32_t ref = _spec_constant ? _alpha_ref_var_id : op_load(_alpha_ref_var_id);
 
-    uint32_t branch = branch_if(op_compare(opcode, alpha, ref));
+    _compare_op_offset = _new_functions.size();
+    uint32_t cond = op_compare(opcode, alpha, ref);
+
+    uint32_t branch = branch_if(cond);
       op_kill();
     branch_endif(branch);
   }
@@ -121,3 +131,13 @@ void SpirVInjectAlphaTestPass::
 end_function(uint32_t function_id) {
   _var_id = 0;
 }
+
+/**
+ * Called after all instructions have been read, this does any post-processing
+ * needed (such as updating the result database to reflect the transformations,
+ * adding names/decorations, etc.)
+ */
+void SpirVInjectAlphaTestPass::
+postprocess() {
+  _compare_op_offset += _new_preamble.size() + _new_annotations.size() + _new_definitions.size();
+}

+ 5 - 2
panda/src/shaderpipeline/spirVInjectAlphaTestPass.h

@@ -34,19 +34,22 @@ public:
     M_always            // Always draw.
   };
 
-  SpirVInjectAlphaTestPass(Mode mode, int ref_location = -1) :
-    _mode(mode), _ref_location(ref_location) {}
+  SpirVInjectAlphaTestPass(Mode mode, int ref_location = -1, bool spec_constant = false) :
+    _mode(mode), _ref_location(ref_location), _spec_constant(spec_constant) {}
 
   virtual bool transform_entry_point(spv::ExecutionModel model, uint32_t id, const char *name, const uint32_t *var_ids, uint16_t num_vars);
   virtual bool begin_function(Instruction op);
   virtual bool transform_function_op(Instruction op);
   virtual void end_function(uint32_t function_id);
+  virtual void postprocess();
 
 public:
   const Mode _mode;
   const int _ref_location;
+  const bool _spec_constant;
 
   uint32_t _alpha_ref_var_id = 0;
+  uint32_t _compare_op_offset = 0;
 
 private:
   uint32_t _var_id = 0;

+ 8 - 0
panda/src/shaderpipeline/spirVResultDatabase.I

@@ -125,3 +125,11 @@ INLINE bool SpirVResultDatabase::Definition::
 has_location() const {
   return _location >= 0;
 }
+
+/**
+ * Returns true if the given id exists.
+ */
+INLINE bool SpirVResultDatabase::
+has_definition(uint32_t id) const {
+  return id < _defs.size() && _defs[id]._dtype != DT_none;
+}

+ 60 - 0
panda/src/shaderpipeline/spirVResultDatabase.cxx

@@ -77,6 +77,66 @@ clear() {
   _flags = 0;
 }
 
+/**
+ * Writes a simple description of this definition to the output stream.
+ */
+void SpirVResultDatabase::Definition::
+output(std::ostream &out) const {
+  switch (_dtype) {
+  case SpirVResultDatabase::DT_none:
+    out << "undefined";
+    break;
+
+  case SpirVResultDatabase::DT_type:
+    if (_type != nullptr) {
+      out << "type " << *_type;
+    } else {
+      out << "unknown type";
+    }
+    break;
+
+  case SpirVResultDatabase::DT_pointer_type:
+    out << "pointer to " << _type_id;
+    break;
+
+  case SpirVResultDatabase::DT_variable:
+    out << "variable of type " << _type_id;
+    break;
+
+  case SpirVResultDatabase::DT_constant:
+    if (is_null_constant()) {
+      out << "null constant of type " << _type_id;
+    } else {
+      out << "constant " << _constant;
+    }
+    break;
+
+  case SpirVResultDatabase::DT_ext_inst:
+    out << "ext inst";
+    break;
+
+  case SpirVResultDatabase::DT_function_parameter:
+    out << "function parameter";
+    break;
+
+  case SpirVResultDatabase::DT_function:
+    out << "function";
+    break;
+
+  case SpirVResultDatabase::DT_temporary:
+    out << "temporary";
+    break;
+
+  case SpirVResultDatabase::DT_spec_constant:
+    out << "spec constant";
+    break;
+
+  default:
+    out << "invalid";
+    break;
+  }
+}
+
 /**
  * Finds the definition with the given name.
  */

+ 3 - 0
panda/src/shaderpipeline/spirVResultDatabase.h

@@ -109,10 +109,13 @@ public:
     const MemberDefinition &get_member(uint32_t i) const;
     MemberDefinition &modify_member(uint32_t i);
     void clear();
+
+    void output(std::ostream &out) const;
   };
   typedef pdeque<Definition> Definitions;
 
   uint32_t find_definition(const std::string &name) const;
+  INLINE bool has_definition(uint32_t id) const;
   const Definition &get_definition(uint32_t id) const;
   Definition &modify_definition(uint32_t id);
 

+ 15 - 4
panda/src/shaderpipeline/spirVTransformPass.I

@@ -29,7 +29,9 @@ get_type_id(uint32_t id) const {
 INLINE uint32_t SpirVTransformPass::
 unwrap_pointer_type(uint32_t id) const {
   const Definition &def = _db.get_definition(id);
-  nassertr(def.is_pointer_type(), 0);
+  if (!def.is_pointer_type()) {
+    return error_expected(id, "a pointer type");
+  }
   uint32_t type_id = def._type_id;
   nassertr(is_defined(id), type_id);
   return type_id;
@@ -42,7 +44,9 @@ unwrap_pointer_type(uint32_t id) const {
 INLINE uint32_t SpirVTransformPass::
 resolve_constant(uint32_t id) const {
   const Definition &def = _db.get_definition(id);
-  nassertr(def.is_constant(), 0);
+  if (!def.is_constant()) {
+    return error_expected(id, "a constant");
+  }
   uint32_t constant = def._constant;
   nassertr(is_defined(id), constant);
   return constant;
@@ -55,7 +59,11 @@ resolve_constant(uint32_t id) const {
 INLINE const ShaderType *SpirVTransformPass::
 resolve_type(uint32_t id) const {
   const Definition &def = _db.get_definition(id);
-  nassertr(def.is_type() && !def.is_pointer_type(), 0);
+  if (!def.is_type() || def.is_pointer_type()) {
+    error_expected(id, "a non-pointer type");
+    return nullptr;
+  }
+  nassertr(def.is_type() && !def.is_pointer_type(), nullptr);
   nassertr(is_defined(id), def._type);
   return def._type;
 }
@@ -67,7 +75,10 @@ resolve_type(uint32_t id) const {
 INLINE const ShaderType *SpirVTransformPass::
 resolve_pointer_type(uint32_t id) const {
   const Definition &def = _db.get_definition(id);
-  nassertr(def.is_pointer_type(), 0);
+  if (!def.is_pointer_type()) {
+    error_expected(id, "a pointer type");
+    return nullptr;
+  }
   nassertr(is_defined(id), def._type);
   return def._type;
 }

+ 35 - 0
panda/src/shaderpipeline/spirVTransformPass.cxx

@@ -955,6 +955,25 @@ define_constant(const ShaderType *type, uint32_t constant) {
   return constant_id;
 }
 
+/**
+ * Defines a new spec constant.  Follow up with a call to decorate() to set the
+ * SpecId.
+ */
+uint32_t SpirVTransformPass::
+define_spec_constant(const ShaderType *type, uint32_t def_value) {
+  uint32_t type_id = define_type(type);
+
+  uint32_t id = allocate_id();
+  if (type == ShaderType::bool_type) {
+    add_definition(def_value ? spv::OpSpecConstantTrue : spv::OpSpecConstantFalse, {type_id, id});
+  } else {
+    add_definition(spv::OpSpecConstant, {type_id, id, def_value});
+  }
+
+  _db.record_spec_constant(id, type_id);
+  return id;
+}
+
 /**
  * Makes sure that the given type has all its structure members correctly laid
  * out using offsets and strides.
@@ -1273,3 +1292,19 @@ void SpirVTransformPass::
 branch_endif(uint32_t false_label) {
   _new_functions.insert(_new_functions.end(), {(2u << spv::WordCountShift) | spv::OpLabel, false_label});
 }
+
+/**
+ * Issues an error about the given id.  Returns 0.
+ */
+uint32_t SpirVTransformPass::
+error_expected(uint32_t id, const char *msg) const {
+  std::ostringstream str;
+  str << id << " (";
+
+  const Definition &def = _db.get_definition(id);
+  def.output(str);
+
+  str << ") was expected to be " << msg << "\n";
+  nassert_raise(str.str());
+  return 0u;
+}

+ 3 - 0
panda/src/shaderpipeline/spirVTransformPass.h

@@ -77,6 +77,7 @@ public:
   uint32_t define_int_constant(int32_t constant);
   uint32_t define_null_constant(const ShaderType *type);
   uint32_t define_constant(const ShaderType *type, uint32_t constant);
+  uint32_t define_spec_constant(const ShaderType *type, uint32_t def_value);
 
   /**
    * Helper class for storing a chain of member or array accesses.
@@ -135,6 +136,8 @@ protected:
   uint32_t branch_if(uint32_t cond);
   void branch_endif(uint32_t label);
 
+  uint32_t error_expected(uint32_t id, const char *msg) const;
+
   // The module is split into sections to make it easier to add instructions
   // to other sections while we are iterating.
   std::vector<uint32_t> _new_preamble;