Browse Source

Merge branch 'shaderpipeline' into vulkan

rdb 5 years ago
parent
commit
08133d86c4

+ 9 - 9
panda/src/glstuff/glCgShaderContext_src.cxx

@@ -191,7 +191,7 @@ CLP(CgShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderConte
       } else {
       } else {
         loc = cgGetParameterResourceIndex(p);
         loc = cgGetParameterResourceIndex(p);
 
 
-        if (loc != 0 && bind._id._name == "vtx_position") {
+        if (loc != 0 && bind._id._name->get_basename() == "vtx_position") {
           // We really have to bind the vertex position to attribute 0, since
           // We really have to bind the vertex position to attribute 0, since
           // OpenGL will hide the model if attribute 0 is not enabled, and we
           // OpenGL will hide the model if attribute 0 is not enabled, and we
           // can only ever be sure that vtx_position is bound.
           // can only ever be sure that vtx_position is bound.
@@ -228,7 +228,7 @@ CLP(CgShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderConte
       }
       }
       loc = _glgsg->_glGetAttribLocation(_glsl_program, attribname);
       loc = _glgsg->_glGetAttribLocation(_glsl_program, attribname);
 
 
-      if (bind._id._name == "vtx_color") {
+      if (bind._id._name->get_basename() == "vtx_color") {
         _color_attrib_index = loc;
         _color_attrib_index = loc;
       }
       }
 
 
@@ -246,7 +246,7 @@ CLP(CgShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderConte
           GLCAT.debug(false) << " (" << resource << ") in the compiled GLSL program.\n";
           GLCAT.debug(false) << " (" << resource << ") in the compiled GLSL program.\n";
         }
         }
 
 
-      } else if (loc != 0 && bind._id._name == "vtx_position") {
+      } else if (loc != 0 && bind._id._name->get_basename() == "vtx_position") {
         // We really have to bind the vertex position to attribute 0, since
         // We really have to bind the vertex position to attribute 0, since
         // OpenGL will hide the model if attribute 0 is not enabled, and we
         // OpenGL will hide the model if attribute 0 is not enabled, and we
         // can only ever be sure that vtx_position is bound.
         // can only ever be sure that vtx_position is bound.
@@ -554,12 +554,12 @@ issue_parameters(int altered) {
         release_resources();
         release_resources();
         return;
         return;
       }
       }
-      CGparameter p = _cg_parameter_map[spec._id._seqno];
+      CGparameter p = _cg_parameter_map[spec._id._location];
       void *data = ptr_data->_ptr;
       void *data = ptr_data->_ptr;
 
 
       switch (ptr_data->_type) {
       switch (ptr_data->_type) {
       case ShaderType::ST_float:
       case ShaderType::ST_float:
-        if (spec._info._type->as_array() != nullptr) {
+        if (spec._id._type->as_array() != nullptr) {
           switch (spec._dim[1]) {
           switch (spec._dim[1]) {
           case 1: cgGLSetParameterArray1f(p, 0, spec._dim[0], (float *)data); continue;
           case 1: cgGLSetParameterArray1f(p, 0, spec._dim[0], (float *)data); continue;
           case 2: cgGLSetParameterArray2f(p, 0, spec._dim[0], (float *)data); continue;
           case 2: cgGLSetParameterArray2f(p, 0, spec._dim[0], (float *)data); continue;
@@ -583,7 +583,7 @@ issue_parameters(int altered) {
         break;
         break;
 
 
       case ShaderType::ST_double:
       case ShaderType::ST_double:
-        if (spec._info._type->as_array() != nullptr) {
+        if (spec._id._type->as_array() != nullptr) {
           switch (spec._dim[1]) {
           switch (spec._dim[1]) {
           case 1: cgGLSetParameterArray1d(p, 0, spec._dim[0], (double *)data); continue;
           case 1: cgGLSetParameterArray1d(p, 0, spec._dim[0], (double *)data); continue;
           case 2: cgGLSetParameterArray2d(p, 0, spec._dim[0], (double *)data); continue;
           case 2: cgGLSetParameterArray2d(p, 0, spec._dim[0], (double *)data); continue;
@@ -637,7 +637,7 @@ issue_parameters(int altered) {
       if (!val) continue;
       if (!val) continue;
       const PN_stdfloat *data = val->get_data();
       const PN_stdfloat *data = val->get_data();
 
 
-      CGparameter p = _cg_parameter_map[spec._id._seqno];
+      CGparameter p = _cg_parameter_map[spec._id._location];
       switch (spec._piece) {
       switch (spec._piece) {
       case Shader::SMP_whole: GLfc(cgGLSetMatrixParameter)(p, data); continue;
       case Shader::SMP_whole: GLfc(cgGLSetMatrixParameter)(p, data); continue;
       case Shader::SMP_transpose: GLfr(cgGLSetMatrixParameter)(p, data); continue;
       case Shader::SMP_transpose: GLfr(cgGLSetMatrixParameter)(p, data); continue;
@@ -991,7 +991,7 @@ disable_shader_texture_bindings() {
   }
   }
 
 
   for (int i = 0; i < (int)_shader->_tex_spec.size(); ++i) {
   for (int i = 0; i < (int)_shader->_tex_spec.size(); ++i) {
-    CGparameter p = _cg_parameter_map[_shader->_tex_spec[i]._id._seqno];
+    CGparameter p = _cg_parameter_map[_shader->_tex_spec[i]._id._location];
     if (p == 0) continue;
     if (p == 0) continue;
 
 
     int texunit = cgGetParameterResourceIndex(p);
     int texunit = cgGetParameterResourceIndex(p);
@@ -1039,7 +1039,7 @@ update_shader_texture_bindings(ShaderContext *prev) {
   for (int i = 0; i < (int)_shader->_tex_spec.size(); ++i) {
   for (int i = 0; i < (int)_shader->_tex_spec.size(); ++i) {
     Shader::ShaderTexSpec &spec = _shader->_tex_spec[i];
     Shader::ShaderTexSpec &spec = _shader->_tex_spec[i];
 
 
-    CGparameter p = _cg_parameter_map[spec._id._seqno];
+    CGparameter p = _cg_parameter_map[spec._id._location];
     if (p == 0) {
     if (p == 0) {
       continue;
       continue;
     }
     }

File diff suppressed because it is too large
+ 303 - 522
panda/src/glstuff/glShaderContext_src.cxx


+ 0 - 1
panda/src/glstuff/glShaderContext_src.h

@@ -140,7 +140,6 @@ private:
   void report_program_errors(GLuint program, bool fatal);
   void report_program_errors(GLuint program, bool fatal);
   bool attach_shader(const ShaderModule *module);
   bool attach_shader(const ShaderModule *module);
   bool compile_and_link();
   bool compile_and_link();
-  bool parse_and_set_short_hand_shader_vars(Shader::ShaderArgId &arg_id, GLenum param_type, GLint param_size, Shader *s);
   void release_resources();
   void release_resources();
 
 
 public:
 public:

+ 144 - 104
panda/src/gobj/shader.cxx

@@ -675,7 +675,7 @@ cg_parameter_type(CGparameter p) {
       default:
       default:
         return nullptr;
         return nullptr;
       }
       }
-      return ::ShaderType::register_type(::ShaderType::SampledImage(texture_type));
+      return ::ShaderType::register_type(::ShaderType::SampledImage(texture_type, ::ShaderType::ST_float));
     }
     }
 
 
   default:
   default:
@@ -1003,7 +1003,10 @@ cg_analyze_entry_point(CGprogram prog, ShaderType type) {
           success &= bind_vertex_input(name, arg_type, -1);
           success &= bind_vertex_input(name, arg_type, -1);
         }
         }
         else if (vbl == CG_UNIFORM) {
         else if (vbl == CG_UNIFORM) {
-          success &= bind_parameter(name, arg_type, -1);
+          Parameter param;
+          param._name = name;
+          param._type = arg_type;
+          success &= bind_parameter(param);
         }
         }
       }
       }
     } else if (shader_cat.is_debug()) {
     } else if (shader_cat.is_debug()) {
@@ -1091,22 +1094,21 @@ cg_analyze_shader(const ShaderCaps &caps) {
     }
     }
   }
   }
 
 
-  // Assign sequence numbers to all parameters.  GLCgShaderContext relies on
-  // the fact that the varyings start at seqno 0.
-  int seqno = 0;
+  // Assign locations to all parameters.  GLCgShaderContext relies on the fact
+  // that the varyings start at location 0.
+  int location = 0;
   for (size_t i = 0; i < _var_spec.size(); ++i) {
   for (size_t i = 0; i < _var_spec.size(); ++i) {
-    _var_spec[i]._id._seqno = seqno++;
+    _var_spec[i]._id._location = location++;
   }
   }
   for (size_t i = 0; i < _mat_spec.size(); ++i) {
   for (size_t i = 0; i < _mat_spec.size(); ++i) {
-    _mat_spec[i]._id._seqno = seqno++;
+    _mat_spec[i]._id._location = location++;
   }
   }
   for (size_t i = 0; i < _tex_spec.size(); ++i) {
   for (size_t i = 0; i < _tex_spec.size(); ++i) {
-    _tex_spec[i]._id._seqno = seqno++;
+    _tex_spec[i]._id._location = location++;
   }
   }
 
 
   for (size_t i = 0; i < _ptr_spec.size(); ++i) {
   for (size_t i = 0; i < _ptr_spec.size(); ++i) {
-    _ptr_spec[i]._id._seqno = seqno++;
-    _ptr_spec[i]._info._id = _ptr_spec[i]._id;
+    _ptr_spec[i]._id._location = location++;
   }
   }
 
 
   /*
   /*
@@ -1264,12 +1266,12 @@ cg_compile_for(const ShaderCaps &caps, CGcontext context,
     programs_by_type[cgGetProgramDomain(program)] = program;
     programs_by_type[cgGetProgramDomain(program)] = program;
   }
   }
 
 
-  for (size_t i = 0; i < n_mat; ++i) {
-    const ShaderArgId &id = _mat_spec[i]._id;
-    map[id._seqno] = cgGetNamedParameter(programs_by_type[id._type], id._name.c_str());
+  /*for (size_t i = 0; i < n_mat; ++i) {
+    const Parameter &id = _mat_spec[i]._id;
+    map[id._location] = cgGetNamedParameter(programs_by_type[id._type], id._name.c_str());
 
 
     if (shader_cat.is_debug()) {
     if (shader_cat.is_debug()) {
-      const char *resource = cgGetParameterResourceName(map[id._seqno]);
+      const char *resource = cgGetParameterResourceName(map[id._location]);
       if (resource != nullptr) {
       if (resource != nullptr) {
         shader_cat.debug() << "Uniform parameter " << id._name
         shader_cat.debug() << "Uniform parameter " << id._name
                            << " is bound to resource " << resource << "\n";
                            << " is bound to resource " << resource << "\n";
@@ -1278,7 +1280,7 @@ cg_compile_for(const ShaderCaps &caps, CGcontext context,
   }
   }
 
 
   for (size_t i = 0; i < n_tex; ++i) {
   for (size_t i = 0; i < n_tex; ++i) {
-    const ShaderArgId &id = _tex_spec[i]._id;
+    const Parameter &id = _tex_spec[i]._id;
     CGparameter p = cgGetNamedParameter(programs_by_type[id._type], id._name.c_str());
     CGparameter p = cgGetNamedParameter(programs_by_type[id._type], id._name.c_str());
 
 
     if (shader_cat.is_debug()) {
     if (shader_cat.is_debug()) {
@@ -1288,11 +1290,11 @@ cg_compile_for(const ShaderCaps &caps, CGcontext context,
                           << " is bound to resource " << resource << "\n";
                           << " is bound to resource " << resource << "\n";
       }
       }
     }
     }
-    map[id._seqno] = p;
+    map[id._location] = p;
   }
   }
 
 
   for (size_t i = 0; i < n_var; ++i) {
   for (size_t i = 0; i < n_var; ++i) {
-    const ShaderArgId &id = _var_spec[i]._id;
+    const Parameter &id = _var_spec[i]._id;
     CGparameter p = cgGetNamedParameter(programs_by_type[id._type], id._name.c_str());
     CGparameter p = cgGetNamedParameter(programs_by_type[id._type], id._name.c_str());
 
 
     const char *resource = cgGetParameterResourceName(p);
     const char *resource = cgGetParameterResourceName(p);
@@ -1309,21 +1311,21 @@ cg_compile_for(const ShaderCaps &caps, CGcontext context,
       }
       }
     }
     }
 
 
-    map[id._seqno] = p;
+    map[id._location] = p;
   }
   }
 
 
   for (size_t i = 0; i < n_ptr; ++i) {
   for (size_t i = 0; i < n_ptr; ++i) {
-    const ShaderArgId &id = _ptr_spec[i]._id;
-    map[id._seqno] = cgGetNamedParameter(programs_by_type[id._type], id._name.c_str());
+    const Parameter &id = _ptr_spec[i]._id;
+    map[id._location] = cgGetNamedParameter(programs_by_type[id._type], id._name.c_str());
 
 
     if (shader_cat.is_debug()) {
     if (shader_cat.is_debug()) {
-      const char *resource = cgGetParameterResourceName(map[id._seqno]);
+      const char *resource = cgGetParameterResourceName(map[id._location]);
       if (resource != nullptr) {
       if (resource != nullptr) {
         shader_cat.debug() << "Uniform ptr parameter " << id._name
         shader_cat.debug() << "Uniform ptr parameter " << id._name
                            << " is bound to resource " << resource << "\n";
                            << " is bound to resource " << resource << "\n";
       }
       }
     }
     }
-  }
+  }*/
 
 
   // Transfer ownership of the compiled shader.
   // Transfer ownership of the compiled shader.
   if (_cg_vprogram != 0) {
   if (_cg_vprogram != 0) {
@@ -1722,8 +1724,8 @@ do_load_source(ShaderModule::Stage stage, const std::string &source, BamCacheRec
 bool Shader::
 bool Shader::
 link() {
 link() {
   // Go through all the modules to fetch the parameters.
   // Go through all the modules to fetch the parameters.
-  pmap<CPT_InternalName, const ShaderModule::Variable *> parameters_by_name;
-  pvector<const ShaderModule::Variable *> parameters;
+  pmap<CPT_InternalName, Parameter> parameters_by_name;
+  pvector<Parameter *> parameters;
   BitArray used_locations;
   BitArray used_locations;
 
 
   for (COWPT(ShaderModule) &cow_module : _modules) {
   for (COWPT(ShaderModule) &cow_module : _modules) {
@@ -1731,14 +1733,20 @@ link() {
     pmap<int, int> remap;
     pmap<int, int> remap;
 
 
     for (const ShaderModule::Variable &var : module->_parameters) {
     for (const ShaderModule::Variable &var : module->_parameters) {
-      const auto result = parameters_by_name.insert({var.name, &var});
-      const auto &it = result.first;
+      Parameter param;
+      param._name = var.name;
+      param._type = var.type;
+      param._location = var._location;
+      param._stage_mask = (1 << (int)module->get_stage());
+
+      auto result = parameters_by_name.insert({var.name, param});
+      auto &it = result.first;
 
 
       if (!result.second) {
       if (!result.second) {
         // A variable by this name was already added by another stage.  Check
         // A variable by this name was already added by another stage.  Check
         // that it has the same type and location.
         // that it has the same type and location.
-        const ShaderModule::Variable &other = *(it->second);
-        if (other.type != var.type) {
+        Parameter &other = it->second;
+        if (other._type != var.type) {
           shader_cat.error()
           shader_cat.error()
             << "Parameter " << *var.name << " in module " << *module
             << "Parameter " << *var.name << " in module " << *module
             << " is declared in another stage with a mismatching type!\n";
             << " is declared in another stage with a mismatching type!\n";
@@ -1748,10 +1756,11 @@ link() {
         // Aggregate types don't seem to work properly when sharing uniforms
         // Aggregate types don't seem to work properly when sharing uniforms
         // between shader stages.  Needs revisiting.
         // between shader stages.  Needs revisiting.
         if (!var.type->is_aggregate_type()) {
         if (!var.type->is_aggregate_type()) {
-          if (it->second->get_location() != var.get_location()) {
+          if (other._location != param._location) {
             // Different location; need to remap this.
             // Different location; need to remap this.
-            remap[var.get_location()] = it->second->get_location();
+            remap[param._location] = other._location;
           }
           }
+          other._stage_mask |= param._stage_mask;
           continue;
           continue;
         }
         }
       }
       }
@@ -1772,11 +1781,12 @@ link() {
           }
           }
           used_locations.set_range(location, num_locations);
           used_locations.set_range(location, num_locations);
           remap[var.get_location()] = location;
           remap[var.get_location()] = location;
+          it->second._location = location;
         } else {
         } else {
           used_locations.set_range(var.get_location(), num_locations);
           used_locations.set_range(var.get_location(), num_locations);
         }
         }
       }
       }
-      parameters.push_back(&var);
+      parameters.push_back(&(it->second));
     }
     }
 
 
     if (!remap.empty()) {
     if (!remap.empty()) {
@@ -1799,8 +1809,8 @@ link() {
 
 
   // Now bind all of the parameters.
   // Now bind all of the parameters.
   bool success = true;
   bool success = true;
-  for (const ShaderModule::Variable *var : parameters) {
-    if (!bind_parameter(var->name, var->type, var->get_location())) {
+  for (const Parameter *param : parameters) {
+    if (!bind_parameter(*param)) {
       success = false;
       success = false;
     }
     }
   }
   }
@@ -1817,7 +1827,8 @@ bind_vertex_input(const InternalName *name, const ::ShaderType *type, int locati
 
 
   Shader::ShaderVarSpec bind;
   Shader::ShaderVarSpec bind;
   bind._id._name = name_str;
   bind._id._name = name_str;
-  bind._id._seqno = location;
+  bind._id._type = type;
+  bind._id._location = location;
   bind._name = nullptr;
   bind._name = nullptr;
   bind._append_uv = -1;
   bind._append_uv = -1;
 
 
@@ -1906,7 +1917,9 @@ bind_vertex_input(const InternalName *name, const ::ShaderType *type, int locati
  * Binds a uniform parameter with the given type.
  * Binds a uniform parameter with the given type.
  */
  */
 bool Shader::
 bool Shader::
-bind_parameter(CPT_InternalName name, const ::ShaderType *type, int location) {
+bind_parameter(const Parameter &param) {
+  const InternalName *name = param._name;
+  const ::ShaderType *type = param._type;
   std::string name_str = name->get_name();
   std::string name_str = name->get_name();
 
 
   // If this is an empty struct, we bind the individual members.
   // If this is an empty struct, we bind the individual members.
@@ -1914,28 +1927,40 @@ bind_parameter(CPT_InternalName name, const ::ShaderType *type, int location) {
   if (struct_type != nullptr && name_str.empty()) {
   if (struct_type != nullptr && name_str.empty()) {
     bool success = true;
     bool success = true;
 
 
+    int location = param._location;
+
     for (size_t i = 0; i < struct_type->get_num_members(); ++i) {
     for (size_t i = 0; i < struct_type->get_num_members(); ++i) {
       const ::ShaderType::Struct::Member &member = struct_type->get_member(i);
       const ::ShaderType::Struct::Member &member = struct_type->get_member(i);
 
 
       // Recurse.
       // Recurse.
-      if (!bind_parameter(InternalName::make(member.name), member.type, location + i)) {
+      Parameter member_param(param);
+      member_param._name = member.name;
+      member_param._type = member.type;
+      member_param._location = location;
+      if (!bind_parameter(member_param)) {
         success = false;
         success = false;
       }
       }
+
+      location += member.type->get_num_parameter_locations();
     }
     }
 
 
     return success;
     return success;
   }
   }
 
 
   if (shader_cat.is_debug()) {
   if (shader_cat.is_debug()) {
-    shader_cat.debug()
-      << "Binding parameter " << name_str << " with type " << *type
-      << " (location=" << location << ")\n";
+    int num_locations = type->get_num_parameter_locations();
+    if (num_locations < 2) {
+      shader_cat.debug()
+        << "Binding parameter " << name_str << " with type " << *type
+        << " (location=" << param._location << ")\n";
+    } else {
+      shader_cat.debug()
+        << "Binding parameter " << name_str << " with type " << *type
+        << " (location=" << param._location << ".."
+        << param._location + num_locations - 1 << ")\n";
+    }
   }
   }
 
 
-  ShaderArgId arg_id;
-  arg_id._name = name_str;
-  arg_id._seqno = location;
-
   // Split it at the underscores.
   // Split it at the underscores.
   vector_string pieces;
   vector_string pieces;
   tokenize(name_str, pieces, "_");
   tokenize(name_str, pieces, "_");
@@ -1966,7 +1991,7 @@ bind_parameter(CPT_InternalName name, const ::ShaderType *type, int location) {
         matrix_name.compare(matrix_name.size() - 6, 6, "Matrix") == 0) {
         matrix_name.compare(matrix_name.size() - 6, 6, "Matrix") == 0) {
 
 
       ShaderMatSpec bind;
       ShaderMatSpec bind;
-      bind._id = arg_id;
+      bind._id = param;
       bind._func = SMF_compose;
       bind._func = SMF_compose;
       bind._arg[0] = nullptr;
       bind._arg[0] = nullptr;
       bind._arg[1] = nullptr;
       bind._arg[1] = nullptr;
@@ -2061,9 +2086,9 @@ bind_parameter(CPT_InternalName name, const ::ShaderType *type, int location) {
 //          // hard to fix on the 1.10 branch.  We'll have a proper fix on the
 //          // hard to fix on the 1.10 branch.  We'll have a proper fix on the
 //          // master branch.
 //          // master branch.
 //#ifdef __APPLE__
 //#ifdef __APPLE__
-//          bind._id._seqno = p + bind._index * 4;
+//          bind._id._location = p + bind._index * 4;
 //#else
 //#else
-//          bind._id._seqno = p + bind._index;
+//          bind._id._location = p + bind._index;
 //#endif
 //#endif
 //          cp_add_mat_spec(bind);
 //          cp_add_mat_spec(bind);
 //        }
 //        }
@@ -2078,10 +2103,15 @@ bind_parameter(CPT_InternalName name, const ::ShaderType *type, int location) {
     }
     }
     if (pieces[1].compare(0, 7, "Texture") == 0) {
     if (pieces[1].compare(0, 7, "Texture") == 0) {
       ShaderTexSpec bind;
       ShaderTexSpec bind;
-      bind._id = arg_id;
+      bind._id = param;
       bind._part = STO_stage_i;
       bind._part = STO_stage_i;
       bind._name = 0;
       bind._name = 0;
-      bind._desired_type = Texture::TT_2d_texture;
+
+      const ::ShaderType::SampledImage *sampled_image_type = type->as_sampled_image();
+      if (sampled_image_type == nullptr) {
+        return report_parameter_error(name, type, "expected sampled image");
+      }
+      bind._desired_type = sampled_image_type->get_texture_type();
 
 
       std::string tail;
       std::string tail;
       bind._stage = string_to_int(pieces[1].substr(7), tail);
       bind._stage = string_to_int(pieces[1].substr(7), tail);
@@ -2095,7 +2125,7 @@ bind_parameter(CPT_InternalName name, const ::ShaderType *type, int location) {
     }
     }
     if (pieces[1] == "Material") {
     if (pieces[1] == "Material") {
       ShaderMatSpec bind;
       ShaderMatSpec bind;
-      bind._id = arg_id;
+      bind._id = param;
       bind._func = SMF_first;
       bind._func = SMF_first;
       bind._part[0] = SMO_attr_material;
       bind._part[0] = SMO_attr_material;
       bind._arg[0] = nullptr;
       bind._arg[0] = nullptr;
@@ -2111,9 +2141,10 @@ bind_parameter(CPT_InternalName name, const ::ShaderType *type, int location) {
       for (size_t i = 0; i < struct_type->get_num_members(); ++i) {
       for (size_t i = 0; i < struct_type->get_num_members(); ++i) {
         const ::ShaderType::Struct::Member &member = struct_type->get_member(i);
         const ::ShaderType::Struct::Member &member = struct_type->get_member(i);
 
 
-        CPT(InternalName) fqname = ((InternalName *)name.p())->append(member.name);
-        bind._id._seqno = arg_id._seqno + i;
+        CPT(InternalName) fqname = ((InternalName *)name)->append(member.name);
+        bind._id._location = param._location + i;
         bind._id._name = fqname->get_name();
         bind._id._name = fqname->get_name();
+        bind._id._type = member.type;
 
 
         if (member.name == "baseColor") {
         if (member.name == "baseColor") {
           if (expect_float_vector(fqname, member.type, 4, 4)) {
           if (expect_float_vector(fqname, member.type, 4, 4)) {
@@ -2194,7 +2225,7 @@ bind_parameter(CPT_InternalName name, const ::ShaderType *type, int location) {
         return false;
         return false;
       }
       }
       ShaderMatSpec bind;
       ShaderMatSpec bind;
-      bind._id = arg_id;
+      bind._id = param;
       bind._func = SMF_first;
       bind._func = SMF_first;
       bind._part[0] = SMO_attr_colorscale;
       bind._part[0] = SMO_attr_colorscale;
       bind._arg[0] = nullptr;
       bind._arg[0] = nullptr;
@@ -2206,7 +2237,7 @@ bind_parameter(CPT_InternalName name, const ::ShaderType *type, int location) {
     }
     }
     if (pieces[1] == "TexAlphaOnly") {
     if (pieces[1] == "TexAlphaOnly") {
       ShaderMatSpec bind;
       ShaderMatSpec bind;
-      bind._id = arg_id;
+      bind._id = param;
       bind._func = SMF_first;
       bind._func = SMF_first;
       bind._index = 0;
       bind._index = 0;
       bind._part[0] = SMO_tex_is_alpha_i;
       bind._part[0] = SMO_tex_is_alpha_i;
@@ -2229,13 +2260,13 @@ bind_parameter(CPT_InternalName name, const ::ShaderType *type, int location) {
           return report_parameter_error(name, type, "expected 'ambient' member");
           return report_parameter_error(name, type, "expected 'ambient' member");
         }
         }
 
 
-        CPT(InternalName) fqname = ((InternalName *)name.p())->append(member.name);
+        CPT(InternalName) fqname = ((InternalName *)name)->append(member.name);
         if (!expect_float_vector(fqname, member.type, 3, 4)) {
         if (!expect_float_vector(fqname, member.type, 3, 4)) {
           return false;
           return false;
         }
         }
 
 
         ShaderMatSpec bind;
         ShaderMatSpec bind;
-        bind._id = arg_id;
+        bind._id = param;
         bind._func = SMF_first;
         bind._func = SMF_first;
         bind._part[0] = SMO_light_ambient;
         bind._part[0] = SMO_light_ambient;
         bind._arg[0] = nullptr;
         bind._arg[0] = nullptr;
@@ -2263,29 +2294,33 @@ bind_parameter(CPT_InternalName name, const ::ShaderType *type, int location) {
         return report_parameter_error(name, type, "expected array of structs");
         return report_parameter_error(name, type, "expected array of structs");
       }
       }
 
 
+      int location = param._location;
+
       size_t num_members = struct_type->get_num_members();
       size_t num_members = struct_type->get_num_members();
       for (size_t i = 0; i < num_members; ++i) {
       for (size_t i = 0; i < num_members; ++i) {
         const ::ShaderType::Struct::Member &member = struct_type->get_member(i);
         const ::ShaderType::Struct::Member &member = struct_type->get_member(i);
 
 
-        CPT(InternalName) fqname = ((InternalName *)name.p())->append(member.name);
+        CPT(InternalName) fqname = ((InternalName *)name)->append(member.name);
 
 
         if (member.name == "shadowMap") {
         if (member.name == "shadowMap") {
           if (member.type->as_sampled_image() == nullptr) {
           if (member.type->as_sampled_image() == nullptr) {
             return report_parameter_error(name, type, "expected sampler2D");
             return report_parameter_error(name, type, "expected sampler2D");
           }
           }
           ShaderTexSpec bind;
           ShaderTexSpec bind;
-          bind._id = arg_id;
-          bind._id._name = fqname->get_name();
+          bind._id = param;
+          bind._id._name = fqname;
+          bind._id._location = location++;
           bind._part = STO_light_i_shadow_map;
           bind._part = STO_light_i_shadow_map;
           bind._desired_type = Texture::TT_2d_texture;
           bind._desired_type = Texture::TT_2d_texture;
           for (bind._stage = 0; bind._stage < (int)array->get_num_elements(); ++bind._stage) {
           for (bind._stage = 0; bind._stage < (int)array->get_num_elements(); ++bind._stage) {
             _tex_spec.push_back(bind);
             _tex_spec.push_back(bind);
-            bind._id._seqno += num_members;
+            bind._id._location += num_members;
           }
           }
         } else {
         } else {
           ShaderMatSpec bind;
           ShaderMatSpec bind;
-          bind._id = arg_id;
-          bind._id._name = fqname->get_name();
+          bind._id = param;
+          bind._id._name = fqname;
+          bind._id._location = location++;
           bind._func = SMF_first;
           bind._func = SMF_first;
           bind._part[0] = SMO_light_source_i_attrib;
           bind._part[0] = SMO_light_source_i_attrib;
           bind._arg[0] = InternalName::make(member.name);
           bind._arg[0] = InternalName::make(member.name);
@@ -2344,11 +2379,9 @@ bind_parameter(CPT_InternalName name, const ::ShaderType *type, int location) {
           }
           }
           for (bind._index = 0; bind._index < (int)array->get_num_elements(); ++bind._index) {
           for (bind._index = 0; bind._index < (int)array->get_num_elements(); ++bind._index) {
             cp_add_mat_spec(bind);
             cp_add_mat_spec(bind);
-            bind._id._seqno += num_members;
+            bind._id._location += num_members;
           }
           }
         }
         }
-
-        arg_id._seqno += 1;
       }
       }
 
 
       return true;
       return true;
@@ -2364,7 +2397,7 @@ bind_parameter(CPT_InternalName name, const ::ShaderType *type, int location) {
     // These inputs are supported by OpenSceneGraph.  We can support them as
     // These inputs are supported by OpenSceneGraph.  We can support them as
     // well, to increase compatibility.
     // well, to increase compatibility.
     ShaderMatSpec bind;
     ShaderMatSpec bind;
-    bind._id = arg_id;
+    bind._id = param;
     bind._arg[0] = nullptr;
     bind._arg[0] = nullptr;
     bind._arg[1] = nullptr;
     bind._arg[1] = nullptr;
 
 
@@ -2394,7 +2427,7 @@ bind_parameter(CPT_InternalName name, const ::ShaderType *type, int location) {
     }
     }
     else if (pieces[1] == "FrameNumber") {
     else if (pieces[1] == "FrameNumber") {
       if (type == ::ShaderType::int_type) {
       if (type == ::ShaderType::int_type) {
-        _frame_number_loc = location;
+        _frame_number_loc = param._location;
         return true;
         return true;
       } else {
       } else {
         return report_parameter_error(name, type, "expected int");
         return report_parameter_error(name, type, "expected int");
@@ -2457,7 +2490,7 @@ bind_parameter(CPT_InternalName name, const ::ShaderType *type, int location) {
         return false;
         return false;
       }
       }
       ShaderMatSpec bind;
       ShaderMatSpec bind;
-      bind._id = arg_id;
+      bind._id = param;
       bind._piece = SMP_whole;
       bind._piece = SMP_whole;
       bind._func = SMF_compose;
       bind._func = SMF_compose;
       bind._part[1] = SMO_light_source_i_attrib;
       bind._part[1] = SMO_light_source_i_attrib;
@@ -2501,7 +2534,7 @@ bind_parameter(CPT_InternalName name, const ::ShaderType *type, int location) {
       pieces[0] == "col3") {
       pieces[0] == "col3") {
 
 
     ShaderMatSpec bind;
     ShaderMatSpec bind;
-    bind._id = arg_id;
+    bind._id = param;
     bind._func = SMF_compose;
     bind._func = SMF_compose;
 
 
     if (pieces[0] == "trans" || pieces[0] == "tpose") {
     if (pieces[0] == "trans" || pieces[0] == "tpose") {
@@ -2596,7 +2629,7 @@ bind_parameter(CPT_InternalName name, const ::ShaderType *type, int location) {
         return false;
         return false;
       }
       }
       ShaderMatSpec bind;
       ShaderMatSpec bind;
-      bind._id = arg_id;
+      bind._id = param;
       if (pieces[1] == "material") {
       if (pieces[1] == "material") {
         if (!expect_float_matrix(name, type, 4, 4)) {
         if (!expect_float_matrix(name, type, 4, 4)) {
           return false;
           return false;
@@ -2702,7 +2735,7 @@ bind_parameter(CPT_InternalName name, const ::ShaderType *type, int location) {
         return false;
         return false;
       }
       }
       ShaderMatSpec bind;
       ShaderMatSpec bind;
-      bind._id = arg_id;
+      bind._id = param;
       bind._piece = SMP_row3;
       bind._piece = SMP_row3;
       bind._func = SMF_first;
       bind._func = SMF_first;
       bind._part[0] = SMO_alight_x;
       bind._part[0] = SMO_alight_x;
@@ -2720,7 +2753,7 @@ bind_parameter(CPT_InternalName name, const ::ShaderType *type, int location) {
         return false;
         return false;
       }
       }
       ShaderMatSpec bind;
       ShaderMatSpec bind;
-      bind._id = arg_id;
+      bind._id = param;
       bind._piece = SMP_row3;
       bind._piece = SMP_row3;
       bind._func = SMF_first;
       bind._func = SMF_first;
       bind._part[0] = SMO_satten_x;
       bind._part[0] = SMO_satten_x;
@@ -2737,7 +2770,7 @@ bind_parameter(CPT_InternalName name, const ::ShaderType *type, int location) {
         return false;
         return false;
       }
       }
       ShaderMatSpec bind;
       ShaderMatSpec bind;
-      bind._id = arg_id;
+      bind._id = param;
       bind._piece = SMP_transpose;
       bind._piece = SMP_transpose;
       int next = 1;
       int next = 1;
       pieces.push_back("");
       pieces.push_back("");
@@ -2778,7 +2811,7 @@ bind_parameter(CPT_InternalName name, const ::ShaderType *type, int location) {
         return false;
         return false;
       }
       }
       ShaderMatSpec bind;
       ShaderMatSpec bind;
-      bind._id = arg_id;
+      bind._id = param;
       bind._piece = SMP_whole;
       bind._piece = SMP_whole;
       bind._func = SMF_first;
       bind._func = SMF_first;
       bind._part[0] = SMO_texmat_i;
       bind._part[0] = SMO_texmat_i;
@@ -2797,7 +2830,7 @@ bind_parameter(CPT_InternalName name, const ::ShaderType *type, int location) {
         return false;
         return false;
       }
       }
       ShaderMatSpec bind;
       ShaderMatSpec bind;
-      bind._id = arg_id;
+      bind._id = param;
       bind._piece = SMP_row3;
       bind._piece = SMP_row3;
       bind._func = SMF_first;
       bind._func = SMF_first;
       bind._part[0] = SMO_texscale_i;
       bind._part[0] = SMO_texscale_i;
@@ -2816,7 +2849,7 @@ bind_parameter(CPT_InternalName name, const ::ShaderType *type, int location) {
         return false;
         return false;
       }
       }
       ShaderMatSpec bind;
       ShaderMatSpec bind;
-      bind._id = arg_id;
+      bind._id = param;
       bind._piece = SMP_row3;
       bind._piece = SMP_row3;
       bind._func = SMF_first;
       bind._func = SMF_first;
       bind._part[0] = SMO_texcolor_i;
       bind._part[0] = SMO_texcolor_i;
@@ -2835,7 +2868,7 @@ bind_parameter(CPT_InternalName name, const ::ShaderType *type, int location) {
         return false;
         return false;
       }
       }
       ShaderMatSpec bind;
       ShaderMatSpec bind;
-      bind._id = arg_id;
+      bind._id = param;
       bind._piece = SMP_row3;
       bind._piece = SMP_row3;
       bind._func = SMF_first;
       bind._func = SMF_first;
       bind._part[0] = SMO_plane_x;
       bind._part[0] = SMO_plane_x;
@@ -2853,7 +2886,7 @@ bind_parameter(CPT_InternalName name, const ::ShaderType *type, int location) {
         return false;
         return false;
       }
       }
       ShaderMatSpec bind;
       ShaderMatSpec bind;
-      bind._id = arg_id;
+      bind._id = param;
       bind._piece = SMP_row3;
       bind._piece = SMP_row3;
       bind._func = SMF_first;
       bind._func = SMF_first;
       bind._part[0] = SMO_clipplane_x;
       bind._part[0] = SMO_clipplane_x;
@@ -2871,7 +2904,7 @@ bind_parameter(CPT_InternalName name, const ::ShaderType *type, int location) {
         return false;
         return false;
       }
       }
       ShaderMatSpec bind;
       ShaderMatSpec bind;
-      bind._id = arg_id;
+      bind._id = param;
       bind._piece = SMP_row3;
       bind._piece = SMP_row3;
       bind._func = SMF_first;
       bind._func = SMF_first;
       bind._part[1] = SMO_identity;
       bind._part[1] = SMO_identity;
@@ -2913,7 +2946,7 @@ bind_parameter(CPT_InternalName name, const ::ShaderType *type, int location) {
         return report_parameter_error(name, type, "unrecognized parameter name");
         return report_parameter_error(name, type, "unrecognized parameter name");
       }
       }
       ShaderTexSpec bind;
       ShaderTexSpec bind;
-      bind._id = arg_id;
+      bind._id = param;
       bind._name = nullptr;
       bind._name = nullptr;
       bind._stage = atoi(pieces[1].c_str());
       bind._stage = atoi(pieces[1].c_str());
       bind._part = STO_stage_i;
       bind._part = STO_stage_i;
@@ -2938,7 +2971,7 @@ bind_parameter(CPT_InternalName name, const ::ShaderType *type, int location) {
         return report_parameter_error(name, type, "unrecognized parameter name");
         return report_parameter_error(name, type, "unrecognized parameter name");
       }
       }
       ShaderTexSpec bind;
       ShaderTexSpec bind;
-      bind._id = arg_id;
+      bind._id = param;
       bind._name = nullptr;
       bind._name = nullptr;
       bind._stage = atoi(pieces[1].c_str());
       bind._stage = atoi(pieces[1].c_str());
       bind._part = STO_light_i_shadow_map;
       bind._part = STO_light_i_shadow_map;
@@ -2961,7 +2994,7 @@ bind_parameter(CPT_InternalName name, const ::ShaderType *type, int location) {
         return false;
         return false;
       }
       }
       ShaderMatSpec bind;
       ShaderMatSpec bind;
-      bind._id = arg_id;
+      bind._id = param;
       bind._piece = SMP_row3;
       bind._piece = SMP_row3;
       bind._func = SMF_first;
       bind._func = SMF_first;
       bind._part[0] = SMO_texpad_x;
       bind._part[0] = SMO_texpad_x;
@@ -2978,7 +3011,7 @@ bind_parameter(CPT_InternalName name, const ::ShaderType *type, int location) {
         return false;
         return false;
       }
       }
       ShaderMatSpec bind;
       ShaderMatSpec bind;
-      bind._id = arg_id;
+      bind._id = param;
       bind._piece = SMP_row3;
       bind._piece = SMP_row3;
       bind._func = SMF_first;
       bind._func = SMF_first;
       bind._part[0] = SMO_texpix_x;
       bind._part[0] = SMO_texpix_x;
@@ -3007,7 +3040,7 @@ bind_parameter(CPT_InternalName name, const ::ShaderType *type, int location) {
   // user-defined input.
   // user-defined input.
   if (const ::ShaderType::SampledImage *sampler = type->as_sampled_image()) {
   if (const ::ShaderType::SampledImage *sampler = type->as_sampled_image()) {
     ShaderTexSpec bind;
     ShaderTexSpec bind;
-    bind._id = arg_id;
+    bind._id = param;
     bind._part = STO_named_input;
     bind._part = STO_named_input;
     bind._name = name;
     bind._name = name;
     bind._desired_type = sampler->get_texture_type();
     bind._desired_type = sampler->get_texture_type();
@@ -3017,7 +3050,7 @@ bind_parameter(CPT_InternalName name, const ::ShaderType *type, int location) {
   }
   }
   else if (const ::ShaderType::Image *image = type->as_image()) {
   else if (const ::ShaderType::Image *image = type->as_image()) {
     ShaderImgSpec bind;
     ShaderImgSpec bind;
-    bind._id = arg_id;
+    bind._id = param;
     bind._name = name;
     bind._name = name;
     bind._desired_type = image->get_texture_type();
     bind._desired_type = image->get_texture_type();
     bind._writable = image->is_writable();
     bind._writable = image->is_writable();
@@ -3027,7 +3060,7 @@ bind_parameter(CPT_InternalName name, const ::ShaderType *type, int location) {
   else if (const ::ShaderType::Matrix *matrix = type->as_matrix()) {
   else if (const ::ShaderType::Matrix *matrix = type->as_matrix()) {
     if (matrix->get_num_columns() == 3 && matrix->get_num_rows() == 3) {
     if (matrix->get_num_columns() == 3 && matrix->get_num_rows() == 3) {
       ShaderMatSpec bind;
       ShaderMatSpec bind;
-      bind._id = arg_id;
+      bind._id = param;
       bind._piece = SMP_upper3x3;
       bind._piece = SMP_upper3x3;
       bind._func = SMF_first;
       bind._func = SMF_first;
       bind._part[0] = SMO_mat_constant_x;
       bind._part[0] = SMO_mat_constant_x;
@@ -3039,7 +3072,7 @@ bind_parameter(CPT_InternalName name, const ::ShaderType *type, int location) {
     }
     }
     else if (matrix->get_num_columns() == 4 && matrix->get_num_rows() == 4) {
     else if (matrix->get_num_columns() == 4 && matrix->get_num_rows() == 4) {
       ShaderMatSpec bind;
       ShaderMatSpec bind;
-      bind._id = arg_id;
+      bind._id = param;
       bind._piece = SMP_whole;
       bind._piece = SMP_whole;
       bind._func = SMF_first;
       bind._func = SMF_first;
       bind._part[0] = SMO_mat_constant_x;
       bind._part[0] = SMO_mat_constant_x;
@@ -3054,10 +3087,12 @@ bind_parameter(CPT_InternalName name, const ::ShaderType *type, int location) {
     // Is this a struct?  If so, bind the individual members.
     // Is this a struct?  If so, bind the individual members.
     bool success = true;
     bool success = true;
 
 
+    int location = param._location;
+
     for (size_t i = 0; i < struct_type->get_num_members(); ++i) {
     for (size_t i = 0; i < struct_type->get_num_members(); ++i) {
       const ::ShaderType::Struct::Member &member = struct_type->get_member(i);
       const ::ShaderType::Struct::Member &member = struct_type->get_member(i);
 
 
-      PT(InternalName) fqname = ((InternalName *)name.p())->append(member.name);
+      PT(InternalName) fqname = ((InternalName *)name)->append(member.name);
 
 
       // Numeric struct members under GLSL may need a special treatment.
       // Numeric struct members under GLSL may need a special treatment.
       ScalarType scalar_type;
       ScalarType scalar_type;
@@ -3070,8 +3105,8 @@ bind_parameter(CPT_InternalName name, const ::ShaderType *type, int location) {
         // light parameter.  It might also just be a custom struct parameter.
         // light parameter.  It might also just be a custom struct parameter.
         // We can't know yet, so we always have to handle it specially.
         // We can't know yet, so we always have to handle it specially.
         ShaderMatSpec bind;
         ShaderMatSpec bind;
-        bind._id = arg_id;
-        bind._id._seqno += i;
+        bind._id = param;
+        bind._id._location = location;
         if (member.name == "shadowMatrix" && dim[1] == 4 && dim[2] == 4) {
         if (member.name == "shadowMatrix" && dim[1] == 4 && dim[2] == 4) {
           // Special exception for shadowMatrix, which is deprecated because it
           // Special exception for shadowMatrix, which is deprecated because it
           // includes the model transformation.  It is far more efficient to do
           // includes the model transformation.  It is far more efficient to do
@@ -3089,7 +3124,7 @@ bind_parameter(CPT_InternalName name, const ::ShaderType *type, int location) {
           bind._part[0] = SMO_model_to_apiview;
           bind._part[0] = SMO_model_to_apiview;
           bind._arg[0] = nullptr;
           bind._arg[0] = nullptr;
           bind._part[1] = SMO_mat_constant_x_attrib;
           bind._part[1] = SMO_mat_constant_x_attrib;
-          bind._arg[1] = ((InternalName *)name.p())->append("shadowViewMatrix");
+          bind._arg[1] = ((InternalName *)name)->append("shadowViewMatrix");
         }
         }
         else {
         else {
           bind._func = SMF_first;
           bind._func = SMF_first;
@@ -3121,19 +3156,25 @@ bind_parameter(CPT_InternalName name, const ::ShaderType *type, int location) {
           bind._arg[1] = nullptr;
           bind._arg[1] = nullptr;
         }
         }
         cp_add_mat_spec(bind);
         cp_add_mat_spec(bind);
-        continue;
       }
       }
-
-      // Otherwise, recurse.
-      if (!bind_parameter(fqname, member.type, location + i)) {
-        success = false;
+      else {
+        // Otherwise, recurse.
+        Parameter member_param(param);
+        member_param._name = fqname;
+        member_param._type = member.type;
+        member_param._location = location;
+        if (!bind_parameter(member_param)) {
+          success = false;
+        }
       }
       }
+      location += member.type->get_num_parameter_locations();
     }
     }
 
 
     return success;
     return success;
   }
   }
   else if (const ::ShaderType::Array *array_type = type->as_array()) {
   else if (const ::ShaderType::Array *array_type = type->as_array()) {
     // Check if this is an array of structs.
     // Check if this is an array of structs.
+    int location = param._location;
     if (const ::ShaderType::Struct *struct_type = array_type->get_element_type()->as_struct()) {
     if (const ::ShaderType::Struct *struct_type = array_type->get_element_type()->as_struct()) {
       bool success = true;
       bool success = true;
 
 
@@ -3152,10 +3193,15 @@ bind_parameter(CPT_InternalName name, const ::ShaderType *type, int location) {
           const ::ShaderType::Struct::Member &member = struct_type->get_member(mi);
           const ::ShaderType::Struct::Member &member = struct_type->get_member(mi);
 
 
           // Recurse.
           // Recurse.
-          PT(InternalName) fqname = elemname->append(member.name);
-          if (!bind_parameter(fqname, member.type, location++)) {
+          Parameter member_param(param);
+          member_param._name = elemname->append(member.name);
+          member_param._type = member.type;
+          member_param._location = location;
+          if (!bind_parameter(member_param)) {
             success = false;
             success = false;
           }
           }
+
+          location += member.type->get_num_parameter_locations();
         }
         }
       }
       }
       return success;
       return success;
@@ -3164,15 +3210,9 @@ bind_parameter(CPT_InternalName name, const ::ShaderType *type, int location) {
 
 
   ShaderPtrSpec bind;
   ShaderPtrSpec bind;
   if (type->as_scalar_type(bind._type, bind._dim[0], bind._dim[1], bind._dim[2])) {
   if (type->as_scalar_type(bind._type, bind._dim[0], bind._dim[1], bind._dim[2])) {
-    bind._id = arg_id;
+    bind._id = param;
     bind._arg = std::move(name);
     bind._arg = std::move(name);
 
 
-    // We specify SSD_frame because a PTA may be modified by the app from
-    // frame to frame, and we have no way to know.  So, we must respecify a
-    // PTA at least once every frame.
-    bind._dep[0] = SSD_general | SSD_shaderinputs | SSD_frame;
-    bind._dep[1] = SSD_NONE;
-
     //if (k_prefix) {
     //if (k_prefix) {
     //  // Backward compatibility, disables certain checks.
     //  // Backward compatibility, disables certain checks.
     //  bind._dim[0] = -1;
     //  bind._dim[0] = -1;

+ 12 - 18
panda/src/gobj/shader.h

@@ -293,10 +293,11 @@ public:
     SMF_first,
     SMF_first,
   };
   };
 
 
-  struct ShaderArgId {
-    std::string     _name;
-    ShaderType _type;
-    int        _seqno;
+  struct Parameter {
+    CPT_InternalName _name;
+    const ::ShaderType *_type = nullptr;
+    int _location = -1;
+    int _stage_mask = 0;
   };
   };
 
 
   enum ShaderPtrType {
   enum ShaderPtrType {
@@ -307,11 +308,6 @@ public:
     SPT_unknown = ScalarType::ST_unknown,
     SPT_unknown = ScalarType::ST_unknown,
   };
   };
 
 
-  struct ShaderArgInfo {
-    ShaderArgId _id;
-    const ::ShaderType *_type;
-  };
-
   // Container structure for data of parameters ShaderPtrSpec.
   // Container structure for data of parameters ShaderPtrSpec.
   struct ShaderPtrData {
   struct ShaderPtrData {
   private:
   private:
@@ -378,7 +374,7 @@ public:
    */
    */
   struct ShaderMatSpec {
   struct ShaderMatSpec {
     size_t _cache_offset[2];
     size_t _cache_offset[2];
-    ShaderArgId       _id;
+    Parameter         _id;
     ShaderMatFunc     _func;
     ShaderMatFunc     _func;
     ShaderMatInput    _part[2];
     ShaderMatInput    _part[2];
     CPT(InternalName) _arg[2];
     CPT(InternalName) _arg[2];
@@ -389,7 +385,7 @@ public:
   };
   };
 
 
   struct ShaderTexSpec {
   struct ShaderTexSpec {
-    ShaderArgId       _id;
+    Parameter         _id;
     CPT(InternalName) _name;
     CPT(InternalName) _name;
     ShaderTexInput    _part;
     ShaderTexInput    _part;
     int               _stage;
     int               _stage;
@@ -398,14 +394,14 @@ public:
   };
   };
 
 
   struct ShaderImgSpec {
   struct ShaderImgSpec {
-    ShaderArgId       _id;
+    Parameter         _id;
     CPT(InternalName) _name;
     CPT(InternalName) _name;
     int               _desired_type;
     int               _desired_type;
     bool              _writable;
     bool              _writable;
   };
   };
 
 
   struct ShaderVarSpec {
   struct ShaderVarSpec {
-    ShaderArgId       _id;
+    Parameter         _id;
     PT(InternalName)  _name;
     PT(InternalName)  _name;
     int               _append_uv;
     int               _append_uv;
     int               _elements;
     int               _elements;
@@ -413,11 +409,9 @@ public:
   };
   };
 
 
   struct ShaderPtrSpec {
   struct ShaderPtrSpec {
-    ShaderArgId       _id;
+    Parameter         _id;
     uint32_t          _dim[3]; //n_elements,rows,cols
     uint32_t          _dim[3]; //n_elements,rows,cols
-    int               _dep[2];
     CPT(InternalName) _arg;
     CPT(InternalName) _arg;
-    ShaderArgInfo     _info;
     ScalarType        _type;
     ScalarType        _type;
   };
   };
 
 
@@ -482,7 +476,7 @@ public:
   void cp_add_mat_spec(ShaderMatSpec &spec);
   void cp_add_mat_spec(ShaderMatSpec &spec);
   size_t cp_get_mat_cache_size() const;
   size_t cp_get_mat_cache_size() const;
 
 
-  bool compile_parameter(ShaderArgId &p);
+  bool compile_parameter(Parameter &p);
 
 
   void clear_parameters();
   void clear_parameters();
 
 
@@ -589,7 +583,7 @@ private:
 public:
 public:
   bool link();
   bool link();
   bool bind_vertex_input(const InternalName *name, const ::ShaderType *type, int location);
   bool bind_vertex_input(const InternalName *name, const ::ShaderType *type, int location);
-  bool bind_parameter(CPT_InternalName name, const ::ShaderType *type, int location);
+  bool bind_parameter(const Parameter &parameter);
 
 
   bool check_modified() const;
   bool check_modified() const;
   ShaderCompiler *get_compiler(ShaderLanguage lang) const;
   ShaderCompiler *get_compiler(ShaderLanguage lang) const;

+ 38 - 3
panda/src/gobj/shaderType.I

@@ -142,9 +142,26 @@ add_member(const ShaderType *type, std::string name) {
   Member member;
   Member member;
   member.type = type;
   member.type = type;
   member.name = std::move(name);
   member.name = std::move(name);
+  member.offset = _members.empty() ? 0 : _members.back().offset + _members.back().type->get_size_bytes();
   _members.push_back(std::move(member));
   _members.push_back(std::move(member));
 }
 }
 
 
+/**
+ * Adds a member to this struct with a given offset.
+ */
+INLINE void ShaderType::Struct::
+add_member(const ShaderType *type, std::string name, uint32_t offset) {
+  pvector<Member>::iterator it = _members.begin();
+  while (it != _members.end() && it->offset < offset) {
+    ++it;
+  }
+  Member member;
+  member.type = type;
+  member.name = std::move(name);
+  member.offset = offset;
+  _members.insert(it, std::move(member));
+}
+
 /**
 /**
  * Constructs an array type from a base type and number of elements.
  * Constructs an array type from a base type and number of elements.
  */
  */
@@ -174,8 +191,9 @@ get_num_elements() const {
  * Constructs an image type.
  * Constructs an image type.
  */
  */
 INLINE ShaderType::Image::
 INLINE ShaderType::Image::
-Image(Texture::TextureType type, Access access) :
+Image(Texture::TextureType type, ScalarType sampled_type, Access access) :
   _texture_type(type),
   _texture_type(type),
+  _sampled_type(sampled_type),
   _access(access) {
   _access(access) {
 }
 }
 
 
@@ -187,6 +205,14 @@ get_texture_type() const {
   return _texture_type;
   return _texture_type;
 }
 }
 
 
+/**
+ * Returns the type of scalar that sampling this image produces.
+ */
+INLINE ShaderType::ScalarType ShaderType::Image::
+get_sampled_type() const {
+  return _sampled_type;
+}
+
 /**
 /**
  * Returns the way this image is accessed.
  * Returns the way this image is accessed.
  */
  */
@@ -207,8 +233,9 @@ is_writable() const {
  * Constructs a sampled image type.
  * Constructs a sampled image type.
  */
  */
 INLINE ShaderType::SampledImage::
 INLINE ShaderType::SampledImage::
-SampledImage(Texture::TextureType type) :
-  _texture_type(type) {
+SampledImage(Texture::TextureType type, ScalarType sampled_type) :
+  _texture_type(type),
+  _sampled_type(sampled_type) {
 }
 }
 
 
 /**
 /**
@@ -218,3 +245,11 @@ INLINE Texture::TextureType ShaderType::SampledImage::
 get_texture_type() const {
 get_texture_type() const {
   return _texture_type;
   return _texture_type;
 }
 }
+
+/**
+ * Returns the type of scalar that sampling this image produces.
+ */
+INLINE ShaderType::ScalarType ShaderType::SampledImage::
+get_sampled_type() const {
+  return _sampled_type;
+}

+ 94 - 4
panda/src/gobj/shaderType.cxx

@@ -81,6 +81,25 @@ std::ostream &operator << (std::ostream &out, ShaderType::ScalarType scalar_type
 }
 }
 
 
 #ifndef CPPPARSER
 #ifndef CPPPARSER
+/**
+ * Returns the size in bytes of this type in memory, if applicable.  Opaque
+ * types will return -1.
+ */
+int ShaderType::
+get_size_bytes() const {
+  ScalarType type;
+  uint32_t dim[3];
+  if (as_scalar_type(type, dim[0], dim[1], dim[2]) && type != ST_bool) {
+    if (type == ST_double) {
+      return 8 * dim[0] * dim[1] * dim[2];
+    } else {
+      return 4 * dim[0] * dim[1] * dim[2];
+    }
+  } else {
+    return -1;
+  }
+}
+
 /**
 /**
  * Returns true if this type contains the given scalar type.
  * Returns true if this type contains the given scalar type.
  */
  */
@@ -213,6 +232,15 @@ compare_to_impl(const ShaderType &other) const {
        - (_num_columns < other_matrix._num_columns);
        - (_num_columns < other_matrix._num_columns);
 }
 }
 
 
+/**
+ * Returns the number of in/out locations taken up by in/out variables having
+ * this type.
+ */
+int ShaderType::Matrix::
+get_num_interface_locations() const {
+  return _num_rows;
+}
+
 /**
 /**
  * Returns true if this type contains the given scalar type.
  * Returns true if this type contains the given scalar type.
  */
  */
@@ -267,6 +295,28 @@ compare_to_impl(const ShaderType &other) const {
   return 0;
   return 0;
 }
 }
 
 
+/**
+ * Returns the size in bytes of this type in memory, if applicable.  Opaque
+ * types will return -1.
+ */
+int ShaderType::Struct::
+get_size_bytes() const {
+  return _members.empty() ? 0 : _members.back().offset + _members.back().type->get_size_bytes();
+}
+
+/**
+ * Returns the number of in/out locations taken up by in/out variables having
+ * this type.
+ */
+int ShaderType::Struct::
+get_num_interface_locations() const {
+  int total = 0;
+  for (const Member &member : _members) {
+    total += member.type->get_num_interface_locations();
+  }
+  return total;
+}
+
 /**
 /**
  * Returns the number of uniform locations taken up by uniform variables having
  * Returns the number of uniform locations taken up by uniform variables having
  * this type.
  * this type.
@@ -326,6 +376,24 @@ compare_to_impl(const ShaderType &other) const {
        - (_num_elements < other_array._num_elements);
        - (_num_elements < other_array._num_elements);
 }
 }
 
 
+/**
+ * Returns the size in bytes of this type in memory, if applicable.  Opaque
+ * types will return -1.
+ */
+int ShaderType::Array::
+get_size_bytes() const {
+  return _element_type->get_size_bytes() * _num_elements;
+}
+
+/**
+ * Returns the number of in/out locations taken up by in/out variables having
+ * this type.
+ */
+int ShaderType::Array::
+get_num_interface_locations() const {
+  return _element_type->get_num_interface_locations() * _num_elements;
+}
+
 /**
 /**
  * Returns the number of uniform locations taken up by uniform variables having
  * Returns the number of uniform locations taken up by uniform variables having
  * this type.
  * this type.
@@ -340,6 +408,11 @@ get_num_parameter_locations() const {
  */
  */
 void ShaderType::Image::
 void ShaderType::Image::
 output(std::ostream &out) const {
 output(std::ostream &out) const {
+  if (_sampled_type == ST_int) {
+    out << 'i';
+  } else if (_sampled_type == ST_uint) {
+    out << 'u';
+  }
   out << "image" << texture_type_suffixes[_texture_type];
   out << "image" << texture_type_suffixes[_texture_type];
 }
 }
 
 
@@ -350,8 +423,16 @@ output(std::ostream &out) const {
 int ShaderType::Image::
 int ShaderType::Image::
 compare_to_impl(const ShaderType &other) const {
 compare_to_impl(const ShaderType &other) const {
   const Image &other_image = (const Image &)other;
   const Image &other_image = (const Image &)other;
-  return (_texture_type > other_image._texture_type)
-       - (_texture_type < other_image._texture_type);
+  if (_texture_type != other_image._texture_type) {
+    return (_texture_type > other_image._texture_type)
+         - (_texture_type < other_image._texture_type);
+  }
+  if (_sampled_type != other_image._sampled_type) {
+    return (_sampled_type > other_image._sampled_type)
+         - (_sampled_type < other_image._sampled_type);
+  }
+  return (_access > other_image._access)
+       - (_access < other_image._access);
 }
 }
 
 
 /**
 /**
@@ -377,6 +458,11 @@ compare_to_impl(const ShaderType &other) const {
  */
  */
 void ShaderType::SampledImage::
 void ShaderType::SampledImage::
 output(std::ostream &out) const {
 output(std::ostream &out) const {
+  if (_sampled_type == ST_int) {
+    out << 'i';
+  } else if (_sampled_type == ST_uint) {
+    out << 'u';
+  }
   out << "sampler" << texture_type_suffixes[_texture_type];
   out << "sampler" << texture_type_suffixes[_texture_type];
 }
 }
 
 
@@ -387,7 +473,11 @@ output(std::ostream &out) const {
 int ShaderType::SampledImage::
 int ShaderType::SampledImage::
 compare_to_impl(const ShaderType &other) const {
 compare_to_impl(const ShaderType &other) const {
   const SampledImage &other_sampled_image = (const SampledImage &)other;
   const SampledImage &other_sampled_image = (const SampledImage &)other;
-  return (_texture_type > other_sampled_image._texture_type)
-       - (_texture_type < other_sampled_image._texture_type);
+  if (_texture_type != other_sampled_image._texture_type) {
+    return (_texture_type > other_sampled_image._texture_type)
+         - (_texture_type < other_sampled_image._texture_type);
+  }
+  return (_sampled_type > other_sampled_image._sampled_type)
+       - (_sampled_type < other_sampled_image._sampled_type);
 }
 }
 #endif  // CPPPARSER
 #endif  // CPPPARSER

+ 17 - 2
panda/src/gobj/shaderType.h

@@ -34,6 +34,8 @@ public:
 
 
   virtual void output(std::ostream &out) const=0;
   virtual void output(std::ostream &out) const=0;
 
 
+  virtual int get_size_bytes() const;
+  virtual int get_num_interface_locations() const { return 1; }
   virtual int get_num_parameter_locations() const { return 1; }
   virtual int get_num_parameter_locations() const { return 1; }
 
 
   enum ScalarType {
   enum ScalarType {
@@ -197,6 +199,8 @@ public:
   virtual bool as_scalar_type(ScalarType &type, uint32_t &num_elements,
   virtual bool as_scalar_type(ScalarType &type, uint32_t &num_elements,
                               uint32_t &num_rows, uint32_t &num_columns) const override;
                               uint32_t &num_rows, uint32_t &num_columns) const override;
 
 
+  virtual int get_num_interface_locations() const override;
+
   const Matrix *as_matrix() const override { return this; }
   const Matrix *as_matrix() const override { return this; }
 
 
   virtual void output(std::ostream &out) const override;
   virtual void output(std::ostream &out) const override;
@@ -232,10 +236,13 @@ public:
   INLINE size_t get_num_members() const;
   INLINE size_t get_num_members() const;
   INLINE const Member &get_member(size_t i) const;
   INLINE const Member &get_member(size_t i) const;
   INLINE void add_member(const ShaderType *type, std::string name);
   INLINE void add_member(const ShaderType *type, std::string name);
+  INLINE void add_member(const ShaderType *type, std::string name, uint32_t offset);
 
 
   virtual void output(std::ostream &out) const override;
   virtual void output(std::ostream &out) const override;
   virtual int compare_to_impl(const ShaderType &other) const override;
   virtual int compare_to_impl(const ShaderType &other) const override;
 
 
+  virtual int get_size_bytes() const override;
+  virtual int get_num_interface_locations() const override;
   virtual int get_num_parameter_locations() const override;
   virtual int get_num_parameter_locations() const override;
 
 
   bool is_aggregate_type() const override { return true; }
   bool is_aggregate_type() const override { return true; }
@@ -248,6 +255,7 @@ PUBLISHED:
   struct Member {
   struct Member {
     const ShaderType *type;
     const ShaderType *type;
     std::string name;
     std::string name;
+    uint32_t offset;
   };
   };
 
 
 private:
 private:
@@ -284,6 +292,8 @@ public:
   virtual void output(std::ostream &out) const override;
   virtual void output(std::ostream &out) const override;
   virtual int compare_to_impl(const ShaderType &other) const override;
   virtual int compare_to_impl(const ShaderType &other) const override;
 
 
+  virtual int get_size_bytes() const override;
+  virtual int get_num_interface_locations() const override;
   virtual int get_num_parameter_locations() const override;
   virtual int get_num_parameter_locations() const override;
 
 
   bool is_aggregate_type() const override { return true; }
   bool is_aggregate_type() const override { return true; }
@@ -324,9 +334,10 @@ PUBLISHED:
   };
   };
 
 
 public:
 public:
-  INLINE Image(Texture::TextureType texture_type, Access access);
+  INLINE Image(Texture::TextureType texture_type, ScalarType sampled_type, Access access);
 
 
   INLINE Texture::TextureType get_texture_type() const;
   INLINE Texture::TextureType get_texture_type() const;
+  INLINE ScalarType get_sampled_type() const;
   INLINE Access get_access() const;
   INLINE Access get_access() const;
   INLINE bool is_writable() const;
   INLINE bool is_writable() const;
 
 
@@ -337,11 +348,13 @@ public:
 
 
 PUBLISHED:
 PUBLISHED:
   MAKE_PROPERTY(texture_type, get_texture_type);
   MAKE_PROPERTY(texture_type, get_texture_type);
+  MAKE_PROPERTY(sampled_type, get_sampled_type);
   MAKE_PROPERTY(access, get_access);
   MAKE_PROPERTY(access, get_access);
   MAKE_PROPERTY(writable, is_writable);
   MAKE_PROPERTY(writable, is_writable);
 
 
 private:
 private:
   Texture::TextureType _texture_type;
   Texture::TextureType _texture_type;
+  ScalarType _sampled_type;
   Access _access;
   Access _access;
 
 
 public:
 public:
@@ -390,9 +403,10 @@ private:
  */
  */
 class EXPCL_PANDA_GOBJ ShaderType::SampledImage final : public ShaderType {
 class EXPCL_PANDA_GOBJ ShaderType::SampledImage final : public ShaderType {
 public:
 public:
-  INLINE SampledImage(Texture::TextureType texture_type);
+  INLINE SampledImage(Texture::TextureType texture_type, ScalarType sampled_type);
 
 
   INLINE Texture::TextureType get_texture_type() const;
   INLINE Texture::TextureType get_texture_type() const;
+  INLINE ScalarType get_sampled_type() const;
 
 
   virtual void output(std::ostream &out) const override;
   virtual void output(std::ostream &out) const override;
   virtual int compare_to_impl(const ShaderType &other) const override;
   virtual int compare_to_impl(const ShaderType &other) const override;
@@ -401,6 +415,7 @@ public:
 
 
 private:
 private:
   Texture::TextureType _texture_type;
   Texture::TextureType _texture_type;
+  ScalarType _sampled_type;
 
 
 public:
 public:
   static TypeHandle get_class_type() {
   static TypeHandle get_class_type() {

+ 0 - 3
panda/src/shaderpipeline/cg_preamble.hlsl

@@ -17,9 +17,6 @@
  * and types that were supported in Cg but are not available in HLSL.
  * and types that were supported in Cg but are not available in HLSL.
  */
  */
 
 
-// Bug in glslang, see KhronosGroup/glslang#2265
-typedef samplerCube samplerCUBE;
-
 // Cg accepts this type and these functions, despite being GLSL
 // Cg accepts this type and these functions, despite being GLSL
 typedef sampler2D sampler2DShadow;
 typedef sampler2D sampler2DShadow;
 
 

+ 9 - 0
panda/src/shaderpipeline/shaderCompilerGlslang.cxx

@@ -14,6 +14,7 @@
 #include "shaderCompilerGlslang.h"
 #include "shaderCompilerGlslang.h"
 #include "config_shaderpipeline.h"
 #include "config_shaderpipeline.h"
 #include "virtualFile.h"
 #include "virtualFile.h"
+#include "shaderCompilerGlslPreProc.h"
 
 
 #ifndef CPPPARSER
 #ifndef CPPPARSER
 #include <glslang/Public/ShaderLang.h>
 #include <glslang/Public/ShaderLang.h>
@@ -292,6 +293,14 @@ compile_now(ShaderModule::Stage stage, std::istream &in,
     return nullptr;
     return nullptr;
   }
   }
 
 
+  if (!is_cg && glsl_version < 330 && glsl_version != 150) {
+    // Fall back to GlslPreProc handler.  Cleaner way to do this?
+    static ShaderCompilerGlslPreProc preprocessor;
+
+    std::istringstream stream(std::string((const char *)&code[0], code.size()));
+    return preprocessor.compile_now(stage, stream, filename, record);
+  }
+
   static bool is_initialized = false;
   static bool is_initialized = false;
   if (!is_initialized) {
   if (!is_initialized) {
     ShInitialize();
     ShInitialize();

+ 95 - 6
panda/src/shaderpipeline/shaderModuleSpirV.I

@@ -14,7 +14,7 @@
 /**
 /**
  * Returns a pointer to the raw words.
  * Returns a pointer to the raw words.
  */
  */
-const uint32_t *ShaderModuleSpirV::
+INLINE const uint32_t *ShaderModuleSpirV::
 get_data() const {
 get_data() const {
   return _instructions.get_data();
   return _instructions.get_data();
 }
 }
@@ -22,11 +22,41 @@ get_data() const {
 /**
 /**
  * Returns the number of words in the module.
  * Returns the number of words in the module.
  */
  */
-size_t ShaderModuleSpirV::
+INLINE size_t ShaderModuleSpirV::
 get_data_size() const {
 get_data_size() const {
   return _instructions.get_data_size();
   return _instructions.get_data_size();
 }
 }
 
 
+/**
+ * Returns true if this is a debug instruction.
+ */
+INLINE bool ShaderModuleSpirV::Instruction::
+is_debug() const {
+  return
+    opcode == spv::OpSourceContinued ||
+    opcode == spv::OpSource ||
+    opcode == spv::OpSourceExtension ||
+    opcode == spv::OpName ||
+    opcode == spv::OpMemberName ||
+    opcode == spv::OpString ||
+    opcode == spv::OpLine ||
+    opcode == spv::OpNoLine ||
+    opcode == spv::OpModuleProcessed;
+}
+
+/**
+ * Returns true if this is an annotation instruction.
+ */
+INLINE bool ShaderModuleSpirV::Instruction::
+is_annotation() const {
+  return
+    opcode == spv::OpDecorate ||
+    opcode == spv::OpMemberDecorate ||
+    opcode == spv::OpGroupDecorate ||
+    opcode == spv::OpGroupMemberDecorate ||
+    opcode == spv::OpDecorationGroup;
+}
+
 /**
 /**
  * Iterator dereference operator.
  * Iterator dereference operator.
  */
  */
@@ -133,6 +163,35 @@ begin_annotations() {
   return it;
   return it;
 }
 }
 
 
+/**
+ * Returns an iterator to the end of the annotations block.
+ */
+INLINE ShaderModuleSpirV::InstructionIterator ShaderModuleSpirV::InstructionStream::
+end_annotations() {
+  iterator it;
+  for (it = begin_annotations(); it != end(); ++it) {
+    if (!(*it).is_annotation()) {
+      break;
+    }
+  }
+  return it;
+}
+
+/**
+ * Returns an iterator to the beginning of the functions block.
+ */
+INLINE ShaderModuleSpirV::InstructionIterator ShaderModuleSpirV::InstructionStream::
+begin_functions() {
+  iterator it;
+  for (it = begin(); it != end(); ++it) {
+    spv::Op opcode = (*it).opcode;
+    if (opcode == spv::OpFunction) {
+      break;
+    }
+  }
+  return it;
+}
+
 /**
 /**
  * Returns an iterator past the end of the instruction stream.
  * Returns an iterator past the end of the instruction stream.
  */
  */
@@ -147,7 +206,7 @@ end() {
  * instruction.
  * instruction.
  */
  */
 INLINE ShaderModuleSpirV::InstructionIterator ShaderModuleSpirV::InstructionStream::
 INLINE ShaderModuleSpirV::InstructionIterator ShaderModuleSpirV::InstructionStream::
-insert(iterator &it, spv::Op opcode, std::initializer_list<uint32_t > args) {
+insert(const iterator &it, spv::Op opcode, std::initializer_list<uint32_t > args) {
   return insert(it, opcode, args.begin(), args.size());
   return insert(it, opcode, args.begin(), args.size());
 }
 }
 
 
@@ -157,7 +216,7 @@ insert(iterator &it, spv::Op opcode, std::initializer_list<uint32_t > args) {
  * instruction.
  * instruction.
  */
  */
 INLINE ShaderModuleSpirV::InstructionIterator ShaderModuleSpirV::InstructionStream::
 INLINE ShaderModuleSpirV::InstructionIterator ShaderModuleSpirV::InstructionStream::
-insert(iterator &it, spv::Op opcode, const uint32_t *args, uint16_t nargs) {
+insert(const iterator &it, spv::Op opcode, const uint32_t *args, uint16_t nargs) {
   ptrdiff_t offset = it._words - &_words[0];
   ptrdiff_t offset = it._words - &_words[0];
 
 
   // If this triggers, you used an invalid iterator.
   // If this triggers, you used an invalid iterator.
@@ -169,12 +228,42 @@ insert(iterator &it, spv::Op opcode, const uint32_t *args, uint16_t nargs) {
   return iterator(&_words[offset]);
   return iterator(&_words[offset]);
 }
 }
 
 
+/**
+ * Inserts a new instruction before the given other one.  Invalidates existing
+ * iterators, but returns a new one pointing to the location of the inserted
+ * instruction.
+ */
+INLINE ShaderModuleSpirV::InstructionIterator ShaderModuleSpirV::InstructionStream::
+insert(const iterator &it, const Instruction &op) {
+  return insert(it, op.opcode, op.args, op.nargs);
+}
+
+/**
+ * Inserts the given argument of the given instruction.
+ */
+INLINE ShaderModuleSpirV::InstructionIterator ShaderModuleSpirV::InstructionStream::
+insert_arg(const iterator &it, uint16_t arg_index, uint32_t arg) {
+  ptrdiff_t offset = it._words - &_words[0];
+
+  // If this triggers, you used an invalid iterator.
+  assert(offset >= 0 && (size_t)offset <= _words.size());
+
+  uint16_t wcount = _words[offset] >> spv::WordCountShift;
+  nassertr(arg_index < wcount - 1, it);
+
+  spv::Op op = (spv::Op)(_words[offset] & spv::OpCodeMask);
+  _words[offset] = op | ((wcount + 1) << spv::WordCountShift);
+  _words.insert(_words.begin() + offset + 1 + arg_index, arg);
+
+  return iterator(&_words[offset]);
+}
+
 /**
 /**
  * Erases the given instruction.  Invalidates iterators at or after the
  * Erases the given instruction.  Invalidates iterators at or after the
  * insertion point, but returns a new iterator pointing to the next element.
  * insertion point, but returns a new iterator pointing to the next element.
  */
  */
 INLINE ShaderModuleSpirV::InstructionIterator ShaderModuleSpirV::InstructionStream::
 INLINE ShaderModuleSpirV::InstructionIterator ShaderModuleSpirV::InstructionStream::
-erase(iterator &it) {
+erase(const iterator &it) {
   ptrdiff_t offset = it._words - &_words[0];
   ptrdiff_t offset = it._words - &_words[0];
 
 
   // If this triggers, you used an invalid iterator.
   // If this triggers, you used an invalid iterator.
@@ -190,7 +279,7 @@ erase(iterator &it) {
  * Erases the given argument of the given instruction.
  * Erases the given argument of the given instruction.
  */
  */
 INLINE ShaderModuleSpirV::InstructionIterator ShaderModuleSpirV::InstructionStream::
 INLINE ShaderModuleSpirV::InstructionIterator ShaderModuleSpirV::InstructionStream::
-erase_arg(iterator &it, uint16_t arg) {
+erase_arg(const iterator &it, uint16_t arg) {
   ptrdiff_t offset = it._words - &_words[0];
   ptrdiff_t offset = it._words - &_words[0];
 
 
   // If this triggers, you used an invalid iterator.
   // If this triggers, you used an invalid iterator.

File diff suppressed because it is too large
+ 1137 - 599
panda/src/shaderpipeline/shaderModuleSpirV.cxx


+ 82 - 25
panda/src/shaderpipeline/shaderModuleSpirV.h

@@ -41,12 +41,21 @@ public:
 
 
   class InstructionStream;
   class InstructionStream;
 
 
+  /**
+   * A single instruction as returned by the InstructionIterator.
+   */
   struct Instruction {
   struct Instruction {
     const spv::Op opcode;
     const spv::Op opcode;
     const uint32_t nargs;
     const uint32_t nargs;
     uint32_t *args;
     uint32_t *args;
+
+    INLINE bool is_debug() const;
+    INLINE bool is_annotation() const;
   };
   };
 
 
+  /**
+   * Provided by InstructionStream to iterate over the instructions.
+   */
   class InstructionIterator {
   class InstructionIterator {
   public:
   public:
     constexpr InstructionIterator() = default;
     constexpr InstructionIterator() = default;
@@ -79,15 +88,17 @@ public:
 
 
     INLINE operator std::vector<uint32_t> & ();
     INLINE operator std::vector<uint32_t> & ();
 
 
-    InstructionStream strip() const;
-
     INLINE iterator begin();
     INLINE iterator begin();
     INLINE iterator begin_annotations();
     INLINE iterator begin_annotations();
+    INLINE iterator end_annotations();
+    INLINE iterator begin_functions();
     INLINE iterator end();
     INLINE iterator end();
-    INLINE iterator insert(iterator &it, spv::Op opcode, std::initializer_list<uint32_t > args);
-    INLINE iterator insert(iterator &it, spv::Op opcode, const uint32_t *args, uint16_t nargs);
-    INLINE iterator erase(iterator &it);
-    INLINE iterator erase_arg(iterator &it, uint16_t arg);
+    INLINE iterator insert(const iterator &it, spv::Op opcode, std::initializer_list<uint32_t > args);
+    INLINE iterator insert(const iterator &it, spv::Op opcode, const uint32_t *args, uint16_t nargs);
+    INLINE iterator insert(const iterator &it, const Instruction &op);
+    INLINE iterator insert_arg(const iterator &it, uint16_t arg_index, uint32_t arg);
+    INLINE iterator erase(const iterator &it);
+    INLINE iterator erase_arg(const iterator &it, uint16_t arg);
 
 
     INLINE const uint32_t *get_data() const;
     INLINE const uint32_t *get_data() const;
     INLINE size_t get_data_size() const;
     INLINE size_t get_data_size() const;
@@ -103,7 +114,6 @@ public:
 
 
   InstructionStream _instructions;
   InstructionStream _instructions;
 
 
-protected:
   enum DefinitionType {
   enum DefinitionType {
     DT_none,
     DT_none,
     DT_type,
     DT_type,
@@ -113,6 +123,18 @@ protected:
     DT_ext_inst,
     DT_ext_inst,
   };
   };
 
 
+  /**
+   * Used by below Definition struct to hold member info.
+   */
+  struct MemberDefinition {
+    std::string _name;
+    uint32_t _type_id = 0;
+    int _location = -1;
+    int _offset = -1;
+    spv::BuiltIn _builtin = spv::BuiltInMax;
+  };
+  typedef pvector<MemberDefinition> MemberDefinitions;
+
   /**
   /**
    * Temporary structure to hold a single definition, which could be a variable,
    * Temporary structure to hold a single definition, which could be a variable,
    * type or type pointer in the SPIR-V file.
    * type or type pointer in the SPIR-V file.
@@ -124,38 +146,73 @@ protected:
     int _location = -1;
     int _location = -1;
     spv::BuiltIn _builtin = spv::BuiltInMax;
     spv::BuiltIn _builtin = spv::BuiltInMax;
     uint32_t _constant = 0;
     uint32_t _constant = 0;
-    vector_string _member_names;
+    uint32_t _type_id = 0;
+    MemberDefinitions _members;
     bool _used = false;
     bool _used = false;
 
 
     // Only defined for DT_variable.
     // Only defined for DT_variable.
     spv::StorageClass _storage_class;
     spv::StorageClass _storage_class;
 
 
-    void set_name(const char *name);
-    void set_member_name(uint32_t i, const char *name);
+    bool has_builtin() const;
+    const MemberDefinition &get_member(uint32_t i) const;
+    MemberDefinition &modify_member(uint32_t i);
+    void clear();
+  };
+  typedef pvector<Definition> Definitions;
+
+  /**
+   * An InstructionWriter can be used for more advanced transformations on a
+   * SPIR-V instruction stream.  It sets up temporary support structures that
+   * help make changes more efficiently.  Only one writer to a given stream may
+   * exist at any given time, and the stream may not be modified by other means
+   * in the meantime.
+   */
+  class InstructionWriter {
+  public:
+    InstructionWriter(InstructionStream &stream);
 
 
-    void set_type(const ShaderType *type);
-    void set_type_pointer(spv::StorageClass storage_class, const ShaderType *type);
-    void set_variable(const ShaderType *type, spv::StorageClass storage_class);
-    void set_constant(const ShaderType *type, const uint32_t *words, uint32_t nwords);
-    void set_ext_inst(const char *name);
+    uint32_t find_definition(const std::string &name) const;
+    const Definition &get_definition(uint32_t id) const;
+    Definition &modify_definition(uint32_t id);
 
 
-    void mark_used();
+    void assign_locations(Stage stage);
 
 
-    void clear();
+    void flatten_struct(uint32_t type_id);
+    uint32_t make_block(const ShaderType::Struct *block_type, const pvector<int> &locations,
+                        spv::StorageClass storage_class, uint32_t binding=0, uint32_t set=0);
+
+    uint32_t define_variable(const ShaderType *type, spv::StorageClass storage_class);
+    uint32_t define_type_pointer(const ShaderType *type, spv::StorageClass storage_class);
+    uint32_t define_type(const ShaderType *type);
+    uint32_t define_constant(const ShaderType *type, uint32_t constant);
+
+  private:
+    uint32_t r_define_variable(InstructionIterator &it, const ShaderType *type, spv::StorageClass storage_class);
+    uint32_t r_define_type_pointer(InstructionIterator &it, const ShaderType *type, spv::StorageClass storage_class);
+    uint32_t r_define_type(InstructionIterator &it, const ShaderType *type);
+    uint32_t r_define_constant(InstructionIterator &it, const ShaderType *type, uint32_t constant);
+    void r_annotate_struct_layout(InstructionIterator &it, uint32_t type_id);
+
+    void parse_instruction(const Instruction &op);
+    void record_type(uint32_t id, const ShaderType *type);
+    void record_type_pointer(uint32_t id, spv::StorageClass storage_class, uint32_t type_id);
+    void record_variable(uint32_t id, uint32_t type_pointer_id, spv::StorageClass storage_class);
+    void record_constant(uint32_t id, uint32_t type_id, const uint32_t *words, uint32_t nwords);
+    void record_ext_inst_import(uint32_t id, const char *import);
+
+    InstructionStream &_instructions;
+    Definitions _defs;
+
+    // Reverse mapping from type to ID.  Excludes types with BuiltIn decoration.
+    typedef pmap<const ShaderType *, uint32_t> TypeMap;
+    TypeMap _type_map;
   };
   };
-  typedef pvector<Definition> Definitions;
 
 
 private:
 private:
-  bool parse(Definitions &defs);
-  bool parse_instruction(Definitions &defs, spv::Op opcode,
-                         const uint32_t *args, size_t nargs);
-
-  void assign_locations(Definitions &defs);
   void remap_locations(spv::StorageClass storage_class, const pmap<int, int> &locations);
   void remap_locations(spv::StorageClass storage_class, const pmap<int, int> &locations);
-
-  void flatten_struct(Definitions &defs, uint32_t type_id);
   void strip();
   void strip();
 
 
+private:
   int _index;
   int _index;
 
 
 public:
 public:

+ 41 - 0
tests/display/test_glsl_shader.py

@@ -430,6 +430,47 @@ def test_glsl_struct(gsg):
     })
     })
 
 
 
 
+def test_glsl_struct_nested(gsg):
+    preamble = """
+    struct TestSubStruct1 {
+        float a;
+        float b;
+    };
+    struct TestSubStruct2 {
+        float unused;
+        sampler2D a;
+        vec2 b;
+    };
+    uniform struct TestStruct {
+        vec3 a;
+        TestSubStruct1 b;
+        TestSubStruct2 c;
+        float d;
+    } test;
+    """
+    code = """
+    assert(test.a == vec3(1, 2, 3));
+    assert(test.b.a == 4);
+    assert(test.b.b == 5);
+    assert(texture(test.c.a, vec2(0, 0)).r == 6);
+    assert(test.c.b == vec2(7, 8));
+    assert(test.d == 9);
+    """
+    tex_c_a = core.Texture()
+    tex_c_a.setup_2d_texture(1, 1, core.Texture.T_float, core.Texture.F_r32)
+    tex_c_a.set_clear_color((6, 0, 0, 0))
+    run_glsl_test(gsg, code, preamble, {
+        'test.unused': 0,
+        'test.a': (1, 2, 3),
+        'test.b.a': 4,
+        'test.b.b': 5,
+        'test.c.unused': 0,
+        'test.c.a': tex_c_a,
+        'test.c.b': (7, 8),
+        'test.d': 9,
+    })
+
+
 def test_glsl_struct_array(gsg):
 def test_glsl_struct_array(gsg):
     preamble = """
     preamble = """
     uniform struct TestStruct {
     uniform struct TestStruct {

Some files were not shown because too many files changed in this diff