瀏覽代碼

shader: separate shader matrix input cache from ShaderMatSpec

If multiple ShaderMatSpec entries use the same state matrix, this should result in a reduction in the number of times that state matrix is fetched.  This is especially so for arrays, which are now fetched once rather than once for every item.

This is the first step towards trying to solve #846.
rdb 5 年之前
父節點
當前提交
a1c5d83584

文件差異過大導致無法顯示
+ 346 - 266
panda/src/display/graphicsStateGuardian.cxx


+ 6 - 4
panda/src/display/graphicsStateGuardian.h

@@ -336,10 +336,12 @@ public:
 
   virtual void clear(DrawableRegion *clearable);
 
-  const LMatrix4 *fetch_specified_value(Shader::ShaderMatSpec &spec, int altered);
-  const LMatrix4 *fetch_specified_part(Shader::ShaderMatInput input, InternalName *name,
-                                       LMatrix4 &t, int index);
-  const LMatrix4 *fetch_specified_member(const NodePath &np, CPT_InternalName member, LMatrix4 &t);
+  void update_shader_matrix_cache(Shader *shader, LMatrix4 *cache, int altered);
+  const LMatrix4 *fetch_specified_value(Shader::ShaderMatSpec &spec, const LMatrix4 *cache, int altered);
+  void fetch_specified_part(Shader::ShaderMatInput input, InternalName *name,
+                            LMatrix4 *into, int count = 1);
+  void fetch_specified_member(const NodePath &np, CPT_InternalName member,
+                              LMatrix4 &t);
   PT(Texture) fetch_specified_texture(Shader::ShaderTexSpec &spec,
                                       SamplerState &sampler, int &view);
   const Shader::ShaderPtrData *fetch_ptr_parameter(const Shader::ShaderPtrSpec& spec);

+ 13 - 4
panda/src/dxgsg9/dxShaderContext9.cxx

@@ -74,6 +74,8 @@ DXShaderContext9(Shader *s, GSG *gsg) : ShaderContext(s) {
     }
   }
 #endif
+
+  _mat_part_cache = new LMatrix4[s->cp_get_mat_cache_size()];
 }
 
 /**
@@ -92,6 +94,8 @@ DXShaderContext9::
     delete _vertex_element_array;
     _vertex_element_array = nullptr;
   }
+
+  delete[] _mat_part_cache;
 }
 
 /**
@@ -232,15 +236,20 @@ issue_parameters(GSG *gsg, int altered) {
       }
     }
 
-    for (size_t i = 0; i < _shader->_mat_spec.size(); ++i) {
-      Shader::ShaderMatSpec &spec = _shader->_mat_spec[i];
+    if (altered & _shader->_mat_deps) {
+      gsg->update_shader_matrix_cache(_shader, _mat_part_cache, altered);
+
+      for (Shader::ShaderMatSpec &spec : _shader->_mat_spec) {
+        if ((altered & spec._dep) == 0) {
+          continue;
+        }
 
-      if (altered & (spec._dep[0] | spec._dep[1])) {
         CGparameter p = _cg_parameter_map[spec._id._seqno];
         if (p == nullptr) {
           continue;
         }
-        const LMatrix4 *val = gsg->fetch_specified_value(spec, altered);
+
+        const LMatrix4 *val = gsg->fetch_specified_value(spec, _mat_part_cache, altered);
         if (val) {
           HRESULT hr;
           PN_stdfloat v [4];

+ 2 - 0
panda/src/dxgsg9/dxShaderContext9.h

@@ -87,6 +87,8 @@ private:
   pvector <CGparameter> _cg_parameter_map;
 #endif
 
+  LMatrix4 *_mat_part_cache = nullptr;
+
 private:
   void release_resources(void);
 

+ 7 - 4
panda/src/glstuff/glCgShaderContext_src.cxx

@@ -338,6 +338,8 @@ CLP(CgShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderConte
     }
   }
 
+  _mat_part_cache = new LMatrix4[_shader->cp_get_mat_cache_size()];
+
   _glgsg->report_my_gl_errors();
 }
 
@@ -347,6 +349,7 @@ CLP(CgShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderConte
 CLP(CgShaderContext)::
 ~CLP(CgShaderContext)() {
   // Don't call release_resources; we may not have an active context.
+  delete[] _mat_part_cache;
 }
 
 /**
@@ -690,14 +693,14 @@ issue_parameters(int altered) {
   }
 
   if (altered & _shader->_mat_deps) {
-    for (int i = 0; i < (int)_shader->_mat_spec.size(); ++i) {
-      Shader::ShaderMatSpec &spec = _shader->_mat_spec[i];
+    _glgsg->update_shader_matrix_cache(_shader, _mat_part_cache, altered);
 
-      if ((altered & (spec._dep[0] | spec._dep[1])) == 0) {
+    for (Shader::ShaderMatSpec &spec : _shader->_mat_spec) {
+      if ((altered & spec._dep) == 0) {
         continue;
       }
 
-      const LMatrix4 *val = _glgsg->fetch_specified_value(spec, altered);
+      const LMatrix4 *val = _glgsg->fetch_specified_value(spec, _mat_part_cache, altered);
       if (!val) continue;
       const PN_stdfloat *data = val->get_data();
 

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

@@ -75,6 +75,7 @@ private:
   long _transform_table_size;
   long _slider_table_size;
 
+  LMatrix4 *_mat_part_cache = nullptr;
   pvector<CGparameter> _cg_parameter_map;
 
   WCPT(RenderState) _state_rs;

+ 34 - 102
panda/src/glstuff/glShaderContext_src.cxx

@@ -228,9 +228,7 @@ parse_and_set_short_hand_shader_vars(Shader::ShaderArgId &arg_id, GLenum param_t
       bind._part[1] = Shader::SMO_apiclip_to_view;
     }
 
-    objShader->cp_optimize_mat_spec(bind);
-    objShader->_mat_spec.push_back(bind);
-    objShader->_mat_deps |= bind._dep[0] | bind._dep[1];
+    objShader->cp_add_mat_spec(bind);
 
     if (param_size > 1) {
       // We support arrays of rows and arrays of columns, so we can run the
@@ -243,7 +241,7 @@ parse_and_set_short_hand_shader_vars(Shader::ShaderArgId &arg_id, GLenum param_t
         for (int i = 1; i < param_size; ++i) {
           bind._id._seqno += 1;
           bind._piece = (Shader::ShaderMatPiece)((int)bind._piece + 1);
-          objShader->_mat_spec.push_back(bind);
+          objShader->cp_add_mat_spec(bind);
         }
       } else {
         GLCAT.warning() << basename << "[" << param_size << "] should not be an array, only the first element will be defined\n";
@@ -380,6 +378,8 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
   } else {
     _glgsg->_current_shader_context->bind();
   }
+
+  _mat_part_cache = new LMatrix4[_shader->cp_get_mat_cache_size()];
 }
 
 /**
@@ -885,15 +885,12 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
         bind._part[0] = inverse ? Shader::SMO_inv_texmat_i
                                 : Shader::SMO_texmat_i;
         bind._part[1] = Shader::SMO_identity;
-        bind._dep[0] = Shader::SSD_general | Shader::SSD_tex_matrix;
-        bind._dep[1] = 0;
 
         // Add it once for each index.
         for (bind._index = 0; bind._index < param_size; ++bind._index) {
           bind._id._seqno = p + bind._index;
-          _shader->_mat_spec.push_back(bind);
+          _shader->cp_add_mat_spec(bind);
         }
-        _shader->_mat_deps |= bind._dep[0];
         return;
 
       } else if (matrix_name.size() > 15 &&
@@ -938,9 +935,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
         GLCAT.error() << "Unrecognized uniform matrix name '" << matrix_name << "'!\n";
         return;
       }
-      _shader->cp_optimize_mat_spec(bind);
-      _shader->_mat_spec.push_back(bind);
-      _shader->_mat_deps |= bind._dep[0] | bind._dep[1];
+      _shader->cp_add_mat_spec(bind);
       return;
     }
     if (size > 7 && noprefix.substr(0, 7) == "Texture") {
@@ -973,10 +968,8 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
       bind._func = Shader::SMF_first;
       bind._part[0] = Shader::SMO_attr_material;
       bind._arg[0] = nullptr;
-      bind._dep[0] = Shader::SSD_general | Shader::SSD_material | Shader::SSD_frame;
       bind._part[1] = Shader::SMO_identity;
       bind._arg[1] = nullptr;
-      bind._dep[1] = Shader::SSD_NONE;
 
       if (noprefix == "Material.baseColor") {
         if (param_type != GL_FLOAT_VEC4) {
@@ -985,9 +978,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
         }
         bind._part[0] = Shader::SMO_attr_material2;
         bind._piece = Shader::SMP_row0;
-        bind._dep[0] |= Shader::SSD_color;
-        _shader->_mat_spec.push_back(bind);
-        _shader->_mat_deps |= bind._dep[0];
+        _shader->cp_add_mat_spec(bind);
         return;
 
       } else if (noprefix == "Material.ambient") {
@@ -996,8 +987,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
             << "p3d_Material.ambient should be vec4\n";
         }
         bind._piece = Shader::SMP_row0;
-        _shader->_mat_spec.push_back(bind);
-        _shader->_mat_deps |= bind._dep[0];
+        _shader->cp_add_mat_spec(bind);
         return;
 
       } else if (noprefix == "Material.diffuse") {
@@ -1006,8 +996,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
             << "p3d_Material.diffuse should be vec4\n";
         }
         bind._piece = Shader::SMP_row1;
-        _shader->_mat_spec.push_back(bind);
-        _shader->_mat_deps |= bind._dep[0];
+        _shader->cp_add_mat_spec(bind);
         return;
 
       } else if (noprefix == "Material.emission") {
@@ -1016,8 +1005,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
             << "p3d_Material.emission should be vec4\n";
         }
         bind._piece = Shader::SMP_row2;
-        _shader->_mat_spec.push_back(bind);
-        _shader->_mat_deps |= bind._dep[0];
+        _shader->cp_add_mat_spec(bind);
         return;
 
       } else if (noprefix == "Material.specular") {
@@ -1026,8 +1014,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
             << "p3d_Material.specular should be vec3\n";
         }
         bind._piece = Shader::SMP_row3x3;
-        _shader->_mat_spec.push_back(bind);
-        _shader->_mat_deps |= bind._dep[0];
+        _shader->cp_add_mat_spec(bind);
         return;
 
       } else if (noprefix == "Material.shininess") {
@@ -1036,8 +1023,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
             << "p3d_Material.shininess should be float\n";
         }
         bind._piece = Shader::SMP_cell15;
-        _shader->_mat_spec.push_back(bind);
-        _shader->_mat_deps |= bind._dep[0];
+        _shader->cp_add_mat_spec(bind);
         return;
 
       } else if (noprefix == "Material.roughness") {
@@ -1047,8 +1033,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
         }
         bind._part[0] = Shader::SMO_attr_material2;
         bind._piece = Shader::SMP_cell15;
-        _shader->_mat_spec.push_back(bind);
-        _shader->_mat_deps |= bind._dep[0];
+        _shader->cp_add_mat_spec(bind);
         return;
 
       } else if (noprefix == "Material.metallic") {
@@ -1058,8 +1043,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
         }
         bind._part[0] = Shader::SMO_attr_material2;
         bind._piece = Shader::SMP_row3x1;
-        _shader->_mat_spec.push_back(bind);
-        _shader->_mat_deps |= bind._dep[0];
+        _shader->cp_add_mat_spec(bind);
         return;
 
       } else if (noprefix == "Material.refractiveIndex") {
@@ -1069,8 +1053,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
         }
         bind._part[0] = Shader::SMO_attr_material2;
         bind._piece = Shader::SMP_cell13;
-        _shader->_mat_spec.push_back(bind);
-        _shader->_mat_deps |= bind._dep[0];
+        _shader->cp_add_mat_spec(bind);
         return;
       }
     }
@@ -1080,10 +1063,8 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
       bind._func = Shader::SMF_first;
       bind._part[0] = Shader::SMO_attr_colorscale;
       bind._arg[0] = nullptr;
-      bind._dep[0] = Shader::SSD_general | Shader::SSD_colorscale;
       bind._part[1] = Shader::SMO_identity;
       bind._arg[1] = nullptr;
-      bind._dep[1] = Shader::SSD_NONE;
 
       if (param_type == GL_FLOAT_VEC3) {
         bind._piece = Shader::SMP_row3x3;
@@ -1094,8 +1075,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
           << "p3d_ColorScale should be vec3 or vec4\n";
         return;
       }
-      _shader->_mat_spec.push_back(bind);
-      _shader->_mat_deps |= bind._dep[0];
+      _shader->cp_add_mat_spec(bind);
       return;
     }
     if (noprefix == "Color") {
@@ -1104,10 +1084,8 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
       bind._func = Shader::SMF_first;
       bind._part[0] = Shader::SMO_attr_color;
       bind._arg[0] = nullptr;
-      bind._dep[0] = Shader::SSD_general | Shader::SSD_color;
       bind._part[1] = Shader::SMO_identity;
       bind._arg[1] = nullptr;
-      bind._dep[1] = Shader::SSD_NONE;
 
       if (param_type == GL_FLOAT_VEC3) {
         bind._piece = Shader::SMP_row3x3;
@@ -1118,8 +1096,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
           << "p3d_Color should be vec3 or vec4\n";
         return;
       }
-      _shader->_mat_spec.push_back(bind);
-      _shader->_mat_deps |= bind._dep[0];
+      _shader->cp_add_mat_spec(bind);
       return;
     }
     if (noprefix == "ClipPlane") {
@@ -1137,12 +1114,9 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
         bind._index = i;
         bind._part[0] = Shader::SMO_apiview_clipplane_i;
         bind._arg[0] = nullptr;
-        bind._dep[0] = Shader::SSD_general | Shader::SSD_clip_planes;
         bind._part[1] = Shader::SMO_identity;
         bind._arg[1] = nullptr;
-        bind._dep[1] = Shader::SSD_NONE;
-        _shader->_mat_spec.push_back(bind);
-        _shader->_mat_deps |= bind._dep[0];
+        _shader->cp_add_mat_spec(bind);
       }
       return;
     }
@@ -1151,10 +1125,8 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
       bind._id = arg_id;
       bind._func = Shader::SMF_first;
       bind._arg[0] = nullptr;
-      bind._dep[0] = Shader::SSD_general | Shader::SSD_fog;
       bind._part[1] = Shader::SMO_identity;
       bind._arg[1] = nullptr;
-      bind._dep[1] = Shader::SSD_NONE;
 
       if (noprefix == "Fog.color") {
         bind._part[0] = Shader::SMO_attr_fogcolor;
@@ -1214,8 +1186,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
         }
       }
 
-      _shader->_mat_spec.push_back(bind);
-      _shader->_mat_deps |= bind._dep[0];
+      _shader->cp_add_mat_spec(bind);
       return;
     }
     if (noprefix == "LightModel.ambient") {
@@ -1224,10 +1195,8 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
       bind._func = Shader::SMF_first;
       bind._part[0] = Shader::SMO_light_ambient;
       bind._arg[0] = nullptr;
-      bind._dep[0] = Shader::SSD_general | Shader::SSD_light;
       bind._part[1] = Shader::SMO_identity;
       bind._arg[1] = nullptr;
-      bind._dep[1] = Shader::SSD_NONE;
 
       if (param_type == GL_FLOAT_VEC3) {
         bind._piece = Shader::SMP_row3x3;
@@ -1238,8 +1207,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
           << "p3d_LightModel.ambient should be vec3 or vec4\n";
         return;
       }
-      _shader->_mat_spec.push_back(bind);
-      _shader->_mat_deps |= bind._dep[0];
+      _shader->cp_add_mat_spec(bind);
       return;
     }
     if (size > 15 && noprefix.substr(0, 12) == "LightSource[") {
@@ -1279,15 +1247,8 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
           bind._index = index;
           bind._part[0] = Shader::SMO_light_source_i_attrib;
           bind._arg[0] = InternalName::make(member_name);
-          bind._dep[0] = Shader::SSD_general | Shader::SSD_light | Shader::SSD_frame;
           bind._part[1] = Shader::SMO_identity;
           bind._arg[1] = nullptr;
-          bind._dep[1] = Shader::SSD_NONE;
-
-          if (member_name == "position" || member_name == "halfVector" ||
-              member_name == "spotDirection") {
-            bind._dep[0] |= Shader::SSD_view_transform;
-          }
 
           switch (param_type) {
           case GL_FLOAT:
@@ -1311,8 +1272,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
               << "p3d_LightSource[]." << member_name << " should be float or vec\n";
             return;
           }
-          _shader->_mat_spec.push_back(bind);
-          _shader->_mat_deps |= bind._dep[0] | bind._dep[1];
+          _shader->cp_add_mat_spec(bind);
           return;
         }
       }
@@ -1344,13 +1304,10 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
       bind._index = 0;
       bind._part[0] = Shader::SMO_tex_is_alpha_i;
       bind._arg[0] = nullptr;
-      bind._dep[0] = Shader::SSD_general | Shader::SSD_texture | Shader::SSD_frame;
       bind._part[1] = Shader::SMO_identity;
       bind._arg[1] = nullptr;
-      bind._dep[1] = Shader::SSD_NONE;
       bind._piece = Shader::SMP_row3;
-      _shader->_mat_spec.push_back(bind);
-      _shader->_mat_deps |= bind._dep[0] | bind._dep[1];
+      _shader->cp_add_mat_spec(bind);
       return;
     }
     GLCAT.error() << "Unrecognized uniform name '" << param_name << "'!\n";
@@ -1371,10 +1328,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
       bind._func = Shader::SMF_compose;
       bind._part[0] = Shader::SMO_world_to_view;
       bind._part[1] = Shader::SMO_view_to_apiview;
-      bind._dep[0] = Shader::SSD_general | Shader::SSD_view_transform;
-      bind._dep[1] = Shader::SSD_general;
-      _shader->_mat_spec.push_back(bind);
-      _shader->_mat_deps |= bind._dep[0] | bind._dep[1];
+      _shader->cp_add_mat_spec(bind);
       return;
 
     } else if (noprefix == "InverseViewMatrix" || noprefix == "ViewMatrixInverse") {
@@ -1382,10 +1336,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
       bind._func = Shader::SMF_compose;
       bind._part[0] = Shader::SMO_apiview_to_view;
       bind._part[1] = Shader::SMO_view_to_world;
-      bind._dep[0] = Shader::SSD_general;
-      bind._dep[1] = Shader::SSD_general | Shader::SSD_view_transform;
-      _shader->_mat_spec.push_back(bind);
-      _shader->_mat_deps |= bind._dep[0] | bind._dep[1];
+      _shader->cp_add_mat_spec(bind);
       return;
 
     } else if (noprefix == "FrameTime") {
@@ -1393,10 +1344,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
       bind._func = Shader::SMF_first;
       bind._part[0] = Shader::SMO_frame_time;
       bind._part[1] = Shader::SMO_identity;
-      bind._dep[0] = Shader::SSD_general | Shader::SSD_frame;
-      bind._dep[1] = Shader::SSD_NONE;
-      _shader->_mat_spec.push_back(bind);
-      _shader->_mat_deps |= bind._dep[0] | bind._dep[1];
+      _shader->cp_add_mat_spec(bind);
       return;
 
     } else if (noprefix == "DeltaFrameTime") {
@@ -1404,10 +1352,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
       bind._func = Shader::SMF_first;
       bind._part[0] = Shader::SMO_frame_delta;
       bind._part[1] = Shader::SMO_identity;
-      bind._dep[0] = Shader::SSD_general | Shader::SSD_frame;
-      bind._dep[1] = Shader::SSD_NONE;
-      _shader->_mat_spec.push_back(bind);
-      _shader->_mat_deps |= bind._dep[0] | bind._dep[1];
+      _shader->cp_add_mat_spec(bind);
       return;
 
     } else if (noprefix == "FrameNumber") {
@@ -1491,12 +1436,9 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
         bind._func = Shader::SMF_first;
         bind._part[0] = Shader::SMO_mat_constant_x;
         bind._arg[0] = InternalName::make(param_name);
-        bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs | Shader::SSD_frame;
         bind._part[1] = Shader::SMO_identity;
         bind._arg[1] = nullptr;
-        bind._dep[1] = Shader::SSD_NONE;
-        _shader->_mat_spec.push_back(bind);
-        _shader->_mat_deps |= bind._dep[0];
+        _shader->cp_add_mat_spec(bind);
         return;
       }
       case GL_FLOAT_MAT4: {
@@ -1506,7 +1448,6 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
         bind._func = Shader::SMF_first;
         bind._part[1] = Shader::SMO_identity;
         bind._arg[1] = nullptr;
-        bind._dep[1] = Shader::SSD_NONE;
         PT(InternalName) iname = InternalName::make(param_name);
         if (iname->get_parent() != InternalName::get_root()) {
           // It might be something like an attribute of a shader input, like a
@@ -1527,22 +1468,17 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
             bind._func = Shader::SMF_compose;
             bind._part[0] = Shader::SMO_model_to_apiview;
             bind._arg[0] = nullptr;
-            bind._dep[0] = Shader::SSD_general | Shader::SSD_transform;
             bind._part[1] = Shader::SMO_mat_constant_x_attrib;
             bind._arg[1] = iname->get_parent()->append("shadowViewMatrix");
-            bind._dep[1] = Shader::SSD_general | Shader::SSD_shaderinputs | Shader::SSD_frame | Shader::SSD_view_transform;
           } else {
             bind._part[0] = Shader::SMO_mat_constant_x_attrib;
             bind._arg[0] = InternalName::make(param_name);
-            bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs | Shader::SSD_frame | Shader::SSD_view_transform;
           }
         } else {
           bind._part[0] = Shader::SMO_mat_constant_x;
           bind._arg[0] = InternalName::make(param_name);
-          bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs | Shader::SSD_frame;
         }
-        _shader->_mat_spec.push_back(bind);
-        _shader->_mat_deps |= bind._dep[0];
+        _shader->cp_add_mat_spec(bind);
         return;
       }
       case GL_FLOAT:
@@ -1572,14 +1508,9 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
           bind._func = Shader::SMF_first;
           bind._part[0] = Shader::SMO_vec_constant_x_attrib;
           bind._arg[0] = iname;
-          // We need SSD_view_transform since some attributes (eg. light
-          // position) have to be transformed to view space.
-          bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs | Shader::SSD_frame | Shader::SSD_view_transform;
           bind._part[1] = Shader::SMO_identity;
           bind._arg[1] = nullptr;
-          bind._dep[1] = Shader::SSD_NONE;
-          _shader->_mat_spec.push_back(bind);
-          _shader->_mat_deps |= bind._dep[0];
+          _shader->cp_add_mat_spec(bind);
           return;
         } // else fall through
       }
@@ -1913,6 +1844,7 @@ get_sampler_texture_type(int &out, GLenum param_type) {
 CLP(ShaderContext)::
 ~CLP(ShaderContext)() {
   // Don't call release_resources; we may not have an active context.
+  delete[] _mat_part_cache;
 }
 
 /**
@@ -2230,14 +2162,14 @@ issue_parameters(int altered) {
   }
 
   if (altered & _shader->_mat_deps) {
-    for (int i = 0; i < (int)_shader->_mat_spec.size(); ++i) {
-      Shader::ShaderMatSpec &spec = _shader->_mat_spec[i];
+    _glgsg->update_shader_matrix_cache(_shader, _mat_part_cache, altered);
 
-      if ((altered & (spec._dep[0] | spec._dep[1])) == 0) {
+    for (Shader::ShaderMatSpec &spec : _shader->_mat_spec) {
+      if ((altered & spec._dep) == 0) {
         continue;
       }
 
-      const LMatrix4 *val = _glgsg->fetch_specified_value(spec, altered);
+      const LMatrix4 *val = _glgsg->fetch_specified_value(spec, _mat_part_cache, altered);
       if (!val) continue;
 #ifndef STDFLOAT_DOUBLE
       // In this case, the data is already single-precision.

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

@@ -114,6 +114,8 @@ private:
   };
   pvector<ImageInput> _glsl_img_inputs;
 
+  LMatrix4 *_mat_part_cache = nullptr;
+
   CLP(GraphicsStateGuardian) *_glgsg;
 
   bool _uses_standard_vertex_arrays;

+ 114 - 60
panda/src/gobj/shader.cxx

@@ -384,7 +384,7 @@ cp_dependency(ShaderMatInput inp) {
   if (inp == SMO_attr_material || inp == SMO_attr_material2) {
     dep |= SSD_material | SSD_frame;
   }
-  if (inp == SMO_attr_color) {
+  if (inp == SMO_attr_color || inp == SMO_attr_material2) {
     dep |= SSD_color;
   }
   if (inp == SMO_attr_colorscale) {
@@ -422,6 +422,7 @@ cp_dependency(ShaderMatInput inp) {
       (inp == SMO_slight_x) ||
       (inp == SMO_satten_x) ||
       (inp == SMO_mat_constant_x) ||
+      (inp == SMO_mat_constant_x_attrib) ||
       (inp == SMO_vec_constant_x) ||
       (inp == SMO_vec_constant_x_attrib) ||
       (inp == SMO_view_x_to_view) ||
@@ -441,6 +442,8 @@ cp_dependency(ShaderMatInput inp) {
         (inp == SMO_plight_x) ||
         (inp == SMO_slight_x) ||
         (inp == SMO_satten_x) ||
+        (inp == SMO_mat_constant_x) ||
+        (inp == SMO_mat_constant_x_attrib) ||
         (inp == SMO_vec_constant_x_attrib) ||
         (inp == SMO_view_x_to_view) ||
         (inp == SMO_view_to_view_x) ||
@@ -459,10 +462,13 @@ cp_dependency(ShaderMatInput inp) {
       (inp == SMO_light_source_i_attrib) ||
       (inp == SMO_light_source_i_packed)) {
     dep |= SSD_light | SSD_frame;
-    if (inp == SMO_light_source_i_attrib ||
-        inp == SMO_light_source_i_packed) {
-      dep |= SSD_view_transform;
-    }
+  }
+  if (inp == SMO_light_source_i_attrib ||
+      inp == SMO_light_source_i_packed ||
+      inp == SMO_mat_constant_x_attrib ||
+      inp == SMO_vec_constant_x_attrib) {
+    // Some light attribs (eg. position) need to be transformed to view space.
+    dep |= SSD_view_transform;
   }
   if ((inp == SMO_light_product_i_ambient) ||
       (inp == SMO_light_product_i_diffuse) ||
@@ -499,14 +505,10 @@ cp_dependency(ShaderMatInput inp) {
 }
 
 /**
- * Analyzes a ShaderMatSpec and decides what it should use its cache for.  It
- * can cache the results of any one opcode, or, it can cache the entire
- * result.  This routine needs to be smart enough to know which data items can
- * be correctly cached, and which cannot.
+ * Adds the given ShaderMatSpec to the shader's mat spec table.
  */
 void Shader::
-cp_optimize_mat_spec(ShaderMatSpec &spec) {
-
+cp_add_mat_spec(ShaderMatSpec &spec) {
   // If we're composing with identity, simplify.
 
   if (spec._func == SMF_first) {
@@ -563,10 +565,93 @@ cp_optimize_mat_spec(ShaderMatSpec &spec) {
     }
   }
 
-  // Calculate state and transform dependencies.
+  // Determine which part is an array, for determining which one the count and
+  // index refer to.  (It can't be the case that both parts are arrays.)
+  int begin[2] = {0, 0};
+  int end[2] = {1, 1};
+  if (spec._index > 0) {
+    for (int i = 0; i < 2; ++i) {
+      if (spec._part[i] == SMO_texmat_i ||
+          spec._part[i] == SMO_inv_texmat_i ||
+          spec._part[i] == SMO_light_source_i_attrib ||
+          spec._part[i] == SMO_light_product_i_ambient ||
+          spec._part[i] == SMO_light_product_i_diffuse ||
+          spec._part[i] == SMO_light_product_i_specular ||
+          spec._part[i] == SMO_apiview_clipplane_i ||
+          spec._part[i] == SMO_tex_is_alpha_i ||
+          spec._part[i] == SMO_transform_i ||
+          spec._part[i] == SMO_slider_i ||
+          spec._part[i] == SMO_light_source_i_packed ||
+          spec._part[i] == SMO_texscale_i ||
+          spec._part[i] == SMO_texcolor_i) {
+        begin[i] = spec._index;
+        end[i] = spec._index + 1;
+      }
+    }
+    nassertv(end[0] == 1 || end[1] == 1);
+  }
+
+  // Make sure that we have a place in the part cache for both parts.
+  int num_parts = (spec._func != SMF_first) ? 2 : 1;
+
+  for (int p = 0; p < num_parts; ++p) {
+    int dep = cp_dependency(spec._part[p]);
+    spec._dep |= dep;
+
+    // Do we already have a spot in the cache for this part?
+    size_t i;
+    size_t offset = 0;
+    for (i = 0; i < _mat_parts.size(); ++i) {
+      ShaderMatPart &part = _mat_parts[i];
+      if (part._part == spec._part[p] && part._arg == spec._arg[p]) {
+        int diff = end[p] - part._count;
+        if (diff <= 0) {
+          // The existing cache entry is big enough.
+          break;
+        } else {
+          // It's not big enough.  Enlarge it, which means we have to change the
+          // offset of some of the other spec entries.
+          for (ShaderMatSpec &spec : _mat_spec) {
+            if (spec._cache_offset[0] >= offset + part._count) {
+              spec._cache_offset[0] += diff;
+            }
+            if (spec._cache_offset[1] >= offset + part._count) {
+              spec._cache_offset[1] += diff;
+            }
+          }
+          part._count = end[p];
+          break;
+        }
+      }
+      offset += part._count;
+    }
+    if (i == _mat_parts.size()) {
+      // Didn't find this part yet, create a new one.
+      ShaderMatPart part;
+      part._part = spec._part[p];
+      part._count = end[p];
+      part._arg = spec._arg[p];
+      part._dep = dep;
+      _mat_parts.push_back(std::move(part));
+    }
+    spec._cache_offset[p] = offset + begin[p];
+  }
+
+  _mat_spec.push_back(spec);
+  _mat_deps |= spec._dep;
+}
 
-  spec._dep[0] = cp_dependency(spec._part[0]);
-  spec._dep[1] = cp_dependency(spec._part[1]);
+/**
+ * Returns the total size of the matrix part cache.
+ */
+size_t Shader::
+cp_get_mat_cache_size() const {
+  size_t size = 0;
+  for (const ShaderMatPart &part : _mat_parts) {
+    size += part._count;
+  }
+  std::cerr << "mat cache size is " << size << "\n";
+  return size;
 }
 
 #ifdef HAVE_CG
@@ -776,9 +861,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
     bind._arg[0] = nullptr;
     bind._index = atoi(pieces[2].c_str());
 
-    cp_optimize_mat_spec(bind);
-    _mat_spec.push_back(bind);
-    _mat_deps |= bind._dep[0] | bind._dep[1];
+    cp_add_mat_spec(bind);
     return true;
   }
 
@@ -931,9 +1014,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
     if (!cp_parse_eol(p, pieces, next)) {
       return false;
     }
-    cp_optimize_mat_spec(bind);
-    _mat_spec.push_back(bind);
-    _mat_deps |= bind._dep[0] | bind._dep[1];
+    cp_add_mat_spec(bind);
     return true;
   }
 
@@ -1041,9 +1122,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
       return false;
     }
 
-    cp_optimize_mat_spec(bind);
-    _mat_spec.push_back(bind);
-    _mat_deps |= bind._dep[0] | bind._dep[1];
+    cp_add_mat_spec(bind);
     return true;
   }
 
@@ -1055,9 +1134,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
     }
     ShaderMatSpec bind;
 
-    cp_optimize_mat_spec(bind);
-    _mat_spec.push_back(bind);
-    _mat_deps |= bind._dep[0] | bind._dep[1];
+    cp_add_mat_spec(bind);
     return true;
   }
 
@@ -1079,9 +1156,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
     bind._part[1] = SMO_identity;
     bind._arg[1] = nullptr;
 
-    cp_optimize_mat_spec(bind);
-    _mat_spec.push_back(bind);
-    _mat_deps |= bind._dep[0] | bind._dep[1];
+    cp_add_mat_spec(bind);
     return true;
   }
 
@@ -1101,9 +1176,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
     bind._part[1] = SMO_identity;
     bind._arg[1] = nullptr;
 
-    cp_optimize_mat_spec(bind);
-    _mat_spec.push_back(bind);
-    _mat_deps |= bind._dep[0] | bind._dep[1];
+    cp_add_mat_spec(bind);
     return true;
   }
 
@@ -1143,9 +1216,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
     if (!cp_parse_eol(p, pieces, next)) {
       return false;
     }
-    cp_optimize_mat_spec(bind);
-    _mat_spec.push_back(bind);
-    _mat_deps |= bind._dep[0] | bind._dep[1];
+    cp_add_mat_spec(bind);
     return true;
   }
 
@@ -1166,9 +1237,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
     bind._arg[1] = nullptr;
     bind._index = atoi(pieces[1].c_str());
 
-    cp_optimize_mat_spec(bind);
-    _mat_spec.push_back(bind);
-    _mat_deps |= bind._dep[0] | bind._dep[1];
+    cp_add_mat_spec(bind);
     return true;
   }
 
@@ -1189,9 +1258,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
     bind._arg[1] = nullptr;
     bind._index = atoi(pieces[1].c_str());
 
-    cp_optimize_mat_spec(bind);
-    _mat_spec.push_back(bind);
-    _mat_deps |= bind._dep[0] | bind._dep[1];
+    cp_add_mat_spec(bind);
     return true;
   }
 
@@ -1212,9 +1279,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
     bind._arg[1] = nullptr;
     bind._index = atoi(pieces[1].c_str());
 
-    cp_optimize_mat_spec(bind);
-    _mat_spec.push_back(bind);
-    _mat_deps |= bind._dep[0] | bind._dep[1];
+    cp_add_mat_spec(bind);
     return true;
   }
 
@@ -1234,9 +1299,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
     bind._part[1] = SMO_identity;
     bind._arg[1] = nullptr;
 
-    cp_optimize_mat_spec(bind);
-    _mat_spec.push_back(bind);
-    _mat_deps |= bind._dep[0] | bind._dep[1];
+    cp_add_mat_spec(bind);
     return true;
   }
 
@@ -1256,9 +1319,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
     bind._part[1] = SMO_identity;
     bind._arg[1] = nullptr;
 
-    cp_optimize_mat_spec(bind);
-    _mat_spec.push_back(bind);
-    _mat_deps |= bind._dep[0] | bind._dep[1];
+    cp_add_mat_spec(bind);
     return true;
   }
 
@@ -1303,9 +1364,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
       return false;
     }
 
-    cp_optimize_mat_spec(bind);
-    _mat_spec.push_back(bind);
-    _mat_deps |= bind._dep[0] | bind._dep[1];
+    cp_add_mat_spec(bind);
     return true;
   }
 
@@ -1388,9 +1447,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
     bind._arg[0] = InternalName::make(pieces[1]);
     bind._part[1] = SMO_identity;
     bind._arg[1] = nullptr;
-    cp_optimize_mat_spec(bind);
-    _mat_spec.push_back(bind);
-    _mat_deps |= bind._dep[0] | bind._dep[1];
+    cp_add_mat_spec(bind);
     return true;
   }
 
@@ -1409,9 +1466,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
     bind._arg[0] = InternalName::make(pieces[1]);
     bind._part[1] = SMO_identity;
     bind._arg[1] = nullptr;
-    cp_optimize_mat_spec(bind);
-    _mat_spec.push_back(bind);
-    _mat_deps |= bind._dep[0] | bind._dep[1];
+    cp_add_mat_spec(bind);
     return true;
   }
 
@@ -2362,7 +2417,6 @@ Shader(ShaderLanguage lang) :
   _loaded(false),
   _language(lang),
   _last_modified(0),
-  _mat_deps(0),
   _cache_compiled_shader(false)
 {
 #ifdef HAVE_CG

+ 31 - 6
panda/src/gobj/shader.h

@@ -402,15 +402,37 @@ public:
     INLINE void read_datagram(DatagramIterator &source);
   };
 
+  /**
+   * Describes a matrix making up a single part of the ShaderMatInput cache.
+   * The cache is made up of a continuous array of matrices, as described by
+   * a successive list of ShaderMatPart (each of which takes up _count matrices)
+   */
+  struct ShaderMatPart {
+    ShaderMatInput _part;
+    PT(InternalName) _arg;
+    int _count = 1;
+    int _dep = SSD_NONE;
+
+    bool operator < (const ShaderMatPart &other) const {
+      if (_part != other._part) {
+        return _part < other._part;
+      }
+      return _arg < other._arg;
+    }
+  };
+
+  /**
+   * Describes a shader input that is sourced from the render state.
+   */
   struct ShaderMatSpec {
-    LMatrix4          _cache[2];
-    LMatrix4          _value;
+    size_t _cache_offset[2];
     ShaderArgId       _id;
     ShaderMatFunc     _func;
     ShaderMatInput    _part[2];
     PT(InternalName)  _arg[2];
-    int               _dep[2];
-    int               _index;
+    LMatrix4          _value;
+    int               _dep = SSD_NONE;
+    int               _index = 0;
     ShaderMatPiece    _piece;
   };
 
@@ -514,7 +536,8 @@ public:
                           vector_string &pieces, int &next,
                           ShaderMatSpec &spec, bool fromflag);
   int cp_dependency(ShaderMatInput inp);
-  void cp_optimize_mat_spec(ShaderMatSpec &spec);
+  void cp_add_mat_spec(ShaderMatSpec &spec);
+  size_t cp_get_mat_cache_size() const;
 
 #ifdef HAVE_CG
   void cg_recurse_parameters(CGparameter parameter,
@@ -578,7 +601,9 @@ public:
   epvector<ShaderMatSpec> _mat_spec;
   pvector<ShaderTexSpec> _tex_spec;
   pvector<ShaderVarSpec> _var_spec;
-  int _mat_deps;
+  pvector<ShaderMatPart> _mat_parts;
+  int _mat_deps = 0;
+  int _mat_cache_size = 0;
 
   bool _error_flag;
   ShaderFile _text;

+ 2 - 1
panda/src/pgraph/shaderAttrib.cxx

@@ -530,7 +530,8 @@ get_shader_input_matrix(const InternalName *id, LMatrix4 &matrix) const {
     if (p.get_value_type() == ShaderInput::M_nodepath) {
       const NodePath &np = p.get_nodepath();
       nassertr(!np.is_empty(), LMatrix4::ident_mat());
-      return np.get_transform()->get_mat();
+      matrix = np.get_transform()->get_mat();
+      return matrix;
 
     } else if (p.get_value_type() == ShaderInput::M_numeric &&
                p.get_ptr()._size >= 16 && (p.get_ptr()._size & 15) == 0) {

部分文件因文件數量過多而無法顯示