Browse Source

shader: Unify ShaderPtrSpec and ShaderMatSpec mechanisms

rdb 1 year ago
parent
commit
99225dfaef

+ 138 - 18
panda/src/display/graphicsStateGuardian.cxx

@@ -925,53 +925,173 @@ update_shader_matrix_cache(Shader *shader, LVecBase4f *cache, int altered) {
  * these values.
  * these values.
  */
  */
 const LVecBase4f *GraphicsStateGuardian::
 const LVecBase4f *GraphicsStateGuardian::
-fetch_specified_value(Shader::ShaderMatSpec &spec, const LVecBase4f *cache, LMatrix4f *scratch) {
+fetch_specified_value(Shader::ShaderMatSpec &spec, const LVecBase4f *cache, LVecBase4f *scratch) {
   LVecBase3f v;
   LVecBase3f v;
 
 
   const LVecBase4f *cache0 = cache + spec._cache_offset[0];
   const LVecBase4f *cache0 = cache + spec._cache_offset[0];
   const LVecBase4f *cache1 = cache + spec._cache_offset[1];
   const LVecBase4f *cache1 = cache + spec._cache_offset[1];
 
 
+  LMatrix4f &m = *(LMatrix4f *)scratch;
+
   switch (spec._func) {
   switch (spec._func) {
   case Shader::SMF_first:
   case Shader::SMF_first:
     return cache0;
     return cache0;
 
 
   case Shader::SMF_compose:
   case Shader::SMF_compose:
-    scratch->multiply(*(LMatrix4f *)cache0, *(LMatrix4f *)cache1);
-    return (LVecBase4f *)scratch;
+    m.multiply(*(LMatrix4f *)cache0, *(LMatrix4f *)cache1);
+    return (LVecBase4f *)&m;
 
 
   case Shader::SMF_transform_dlight:
   case Shader::SMF_transform_dlight:
-    *scratch = *(LMatrix4f *)cache0;
+    m = *(LMatrix4f *)cache0;
     v = (*(LMatrix4f *)cache1).xform_vec(cache0[2].get_xyz());
     v = (*(LMatrix4f *)cache1).xform_vec(cache0[2].get_xyz());
     v.normalize();
     v.normalize();
-    scratch->set_row(2, v);
+    m.set_row(2, v);
     v = (*(LMatrix4f *)cache1).xform_vec(cache0[3].get_xyz());
     v = (*(LMatrix4f *)cache1).xform_vec(cache0[3].get_xyz());
     v.normalize();
     v.normalize();
-    scratch->set_row(3, v);
-    return (LVecBase4f *)scratch;
+    m.set_row(3, v);
+    return (LVecBase4f *)&m;
 
 
   case Shader::SMF_transform_plight:
   case Shader::SMF_transform_plight:
     {
     {
       // Careful not to touch the w component, which contains the near value.
       // Careful not to touch the w component, which contains the near value.
-      *scratch = *(LMatrix4f *)cache0;
+      m = *(LMatrix4f *)cache0;
       LPoint3f point = (*(LMatrix4f *)cache1).xform_point(cache0[2].get_xyz());
       LPoint3f point = (*(LMatrix4f *)cache1).xform_point(cache0[2].get_xyz());
-      (*scratch)(2, 0) = point[0];
-      (*scratch)(2, 1) = point[1];
-      (*scratch)(2, 2) = point[2];
-      return (LVecBase4f *)scratch;
+      m(2, 0) = point[0];
+      m(2, 1) = point[1];
+      m(2, 2) = point[2];
+      return (LVecBase4f *)&m;
     }
     }
 
 
   case Shader::SMF_transform_slight:
   case Shader::SMF_transform_slight:
-    *scratch = *(LMatrix4f *)cache0;
-    scratch->set_row(2, (*(LMatrix4f *)cache1).xform_point(cache0[2].get_xyz()));
+    m = *(LMatrix4f *)cache0;
+    m.set_row(2, (*(LMatrix4f *)cache1).xform_point(cache0[2].get_xyz()));
     v = (*(LMatrix4f *)cache1).xform_vec(cache0[3].get_xyz());
     v = (*(LMatrix4f *)cache1).xform_vec(cache0[3].get_xyz());
     v.normalize();
     v.normalize();
-    scratch->set_row(3, v);
-    return (LVecBase4f *)scratch;
+    m.set_row(3, v);
+    return (LVecBase4f *)&m;
+
+  case Shader::SMF_shader_input_ptr:
+    return (const LVecBase4f *)fetch_ptr_parameter(spec, scratch);
   }
   }
 
 
   // Should never get here
   // Should never get here
-  *scratch = LMatrix4f::ident_mat();
-  return (LVecBase4f *)scratch;
+  m = LMatrix4f::ident_mat();
+  return (LVecBase4f *)&m;
+}
+
+/**
+ * Fetches a numeric shader input, doing conversion as necessary using the
+ * given amount of scratch space.
+ */
+const void *GraphicsStateGuardian::
+fetch_ptr_parameter(Shader::ShaderMatSpec &spec, LVecBase4f *scratch) {
+  Shader::ShaderPtrData ptr_data;
+  if (!_target_shader->get_shader_input_ptr(spec._arg[0], ptr_data)) {
+    return nullptr;
+  }
+
+  nassertr(spec._num_components > 0, nullptr);
+
+  int array_size = std::min(spec._array_count, (int)ptr_data._size / spec._num_components);
+  switch (spec._numeric_type) {
+  case Shader::SPT_float:
+    {
+      float *data = (float *)scratch;
+
+      switch (ptr_data._type) {
+      case Shader::SPT_int:
+        // Convert int data to float data.
+        for (int i = 0; i < (array_size * spec._num_components); ++i) {
+          data[i] = (float)(((int*)ptr_data._ptr)[i]);
+        }
+        return data;
+
+      case Shader::SPT_uint:
+        // Convert unsigned int data to float data.
+        for (int i = 0; i < (array_size * spec._num_components); ++i) {
+          data[i] = (float)(((unsigned int*)ptr_data._ptr)[i]);
+        }
+        return data;
+
+      case Shader::SPT_double:
+        // Downgrade double data to float data.
+        for (int i = 0; i < (array_size * spec._num_components); ++i) {
+          data[i] = (float)(((double*)ptr_data._ptr)[i]);
+        }
+        return data;
+
+      case Shader::SPT_float:
+        return (float *)ptr_data._ptr;
+
+      default:
+#ifndef NDEBUG
+        display_cat.error()
+          << "Invalid ShaderPtrData type " << (int)ptr_data._type
+          << " for shader input '" << spec._id._name << "'\n";
+#endif
+        return nullptr;
+      }
+
+      return data;
+    }
+    break;
+
+  case Shader::SPT_int:
+    if (ptr_data._type != Shader::SPT_int &&
+        ptr_data._type != Shader::SPT_uint) {
+      display_cat.error()
+        << "Cannot pass floating-point data to integer shader input '" << spec._id._name << "'\n";
+
+      // Deactivate it to make sure the user doesn't get flooded with this
+      // error.
+      spec._dep = 0;
+
+    } else {
+      return ptr_data._ptr;
+    }
+    break;
+
+  case Shader::SPT_uint:
+    if (ptr_data._type != Shader::SPT_uint &&
+        ptr_data._type != Shader::SPT_int) {
+      display_cat.error()
+        << "Cannot pass floating-point data to integer shader input '" << spec._id._name << "'\n";
+
+      // Deactivate it to make sure the user doesn't get flooded with this
+      // error.
+      spec._dep = 0;
+      return nullptr;
+
+    } else {
+      return ptr_data._ptr;
+    }
+    break;
+
+  case Shader::SPT_double:
+    display_cat.error()
+      << "Passing double-precision shader inputs to shaders is not currently supported\n";
+
+    // Deactivate it to make sure the user doesn't get flooded with this
+    // error.
+    spec._dep = 0;
+    break;
+
+  case Shader::SPT_bool:
+    if (ptr_data._type == Shader::SPT_double) {
+      unsigned int *data = (unsigned int *)scratch;
+      for (int i = 0; i < (array_size * spec._num_components); ++i) {
+        data[i] = ((double *)ptr_data._ptr)[i] != 0;
+      }
+      return data;
+    } else {
+      return (float *)ptr_data._ptr;
+    }
+
+  case Shader::SPT_unknown:
+    break;
+  }
+
+  return nullptr;
 }
 }
 
 
 /**
 /**

+ 2 - 1
panda/src/display/graphicsStateGuardian.h

@@ -337,7 +337,8 @@ public:
   virtual void clear(DrawableRegion *clearable);
   virtual void clear(DrawableRegion *clearable);
 
 
   void update_shader_matrix_cache(Shader *shader, LVecBase4f *cache, int altered);
   void update_shader_matrix_cache(Shader *shader, LVecBase4f *cache, int altered);
-  const LVecBase4f *fetch_specified_value(Shader::ShaderMatSpec &spec, const LVecBase4f *cache, LMatrix4f *scratch);
+  const LVecBase4f *fetch_specified_value(Shader::ShaderMatSpec &spec, const LVecBase4f *cache, LVecBase4f *scratch);
+  const void *fetch_ptr_parameter(Shader::ShaderMatSpec &spec, LVecBase4f *scratch);
   void fetch_specified_part(Shader::ShaderMatInput input, InternalName *name,
   void fetch_specified_part(Shader::ShaderMatInput input, InternalName *name,
                             LVecBase4f *into, int count = 1);
                             LVecBase4f *into, int count = 1);
   void fetch_specified_member(const NodePath &np, CPT_InternalName member,
   void fetch_specified_member(const NodePath &np, CPT_InternalName member,

+ 3 - 41
panda/src/dxgsg9/dxShaderContext9.cxx

@@ -190,48 +190,10 @@ void DXShaderContext9::
 issue_parameters(GSG *gsg, int altered) {
 issue_parameters(GSG *gsg, int altered) {
 #ifdef HAVE_CG
 #ifdef HAVE_CG
   if (_cg_program) {
   if (_cg_program) {
-
-    // Iterate through _ptr parameters
-    for (size_t i = 0; i < _shader->_ptr_spec.size(); ++i) {
-      const Shader::ShaderPtrSpec &spec = _shader->_ptr_spec[i];
-
-      if (altered & (spec._dep[0] | spec._dep[1])) {
-        const Shader::ShaderPtrData *ptr_data = gsg->fetch_ptr_parameter(spec);
-
-        if (ptr_data == nullptr) { //the input is not contained in ShaderPtrData
-          release_resources();
-          return;
-        }
-
-        // Calculate how many elements to transfer; no more than it expects,
-        // but certainly no more than we have.
-        int input_size = std::min(abs(spec._dim[0] * spec._dim[1] * spec._dim[2]), (int)ptr_data->_size);
-
-        CGparameter p = _cg_parameter_map[spec._id._seqno];
-        switch (ptr_data->_type) {
-        case Shader::SPT_int:
-          cgSetParameterValueic(p, input_size, (int *)ptr_data->_ptr);
-          break;
-
-        case Shader::SPT_double:
-          cgSetParameterValuedc(p, input_size, (double *)ptr_data->_ptr);
-          break;
-
-        case Shader::SPT_float:
-          cgSetParameterValuefc(p, input_size, (float *)ptr_data->_ptr);
-          break;
-
-        default:
-          dxgsg9_cat.error()
-            << spec._id._name << ": unrecognized parameter type\n";
-          release_resources();
-          return;
-        }
-      }
-    }
-
     if (altered & _shader->_mat_deps) {
     if (altered & _shader->_mat_deps) {
-      gsg->update_shader_matrix_cache(_shader, _mat_part_cache, altered);
+      if (altered & _shader->_mat_cache_deps) {
+        gsg->update_shader_matrix_cache(_shader, _mat_part_cache, altered);
+      }
 
 
       LMatrix4f scratch;
       LMatrix4f scratch;
 
 

+ 76 - 27
panda/src/glstuff/glCgShaderContext_src.cxx

@@ -535,7 +535,7 @@ issue_parameters(int altered) {
   // modified every frame and when we switch ShaderAttribs.
   // modified every frame and when we switch ShaderAttribs.
   if (altered & (Shader::SSD_shaderinputs | Shader::SSD_frame)) {
   if (altered & (Shader::SSD_shaderinputs | Shader::SSD_frame)) {
     // Iterate through _ptr parameters
     // Iterate through _ptr parameters
-    for (int i = 0; i < (int)_shader->_ptr_spec.size(); ++i) {
+    /*for (int i = 0; i < (int)_shader->_ptr_spec.size(); ++i) {
       Shader::ShaderPtrSpec &spec = _shader->_ptr_spec[i];
       Shader::ShaderPtrSpec &spec = _shader->_ptr_spec[i];
 
 
       const Shader::ShaderPtrData *ptr_data =_glgsg->fetch_ptr_parameter(spec);
       const Shader::ShaderPtrData *ptr_data =_glgsg->fetch_ptr_parameter(spec);
@@ -690,11 +690,13 @@ issue_parameters(int altered) {
         release_resources();
         release_resources();
         return;
         return;
       }
       }
-    }
+    }*/
   }
   }
 
 
   if (altered & _shader->_mat_deps) {
   if (altered & _shader->_mat_deps) {
-    _glgsg->update_shader_matrix_cache(_shader, _mat_part_cache, altered);
+    if (altered & _shader->_mat_cache_deps) {
+      _glgsg->update_shader_matrix_cache(_shader, _mat_part_cache, altered);
+    }
 
 
     LMatrix4f scratch;
     LMatrix4f scratch;
 
 
@@ -709,32 +711,79 @@ issue_parameters(int altered) {
       data += spec._offset;
       data += spec._offset;
 
 
       CGparameter p = _cg_parameter_map[spec._id._seqno];
       CGparameter p = _cg_parameter_map[spec._id._seqno];
-      switch (spec._piece) {
-      case Shader::SMP_float: cgGLSetParameter1f(p, data[0]); continue;
-      case Shader::SMP_vec2: cgGLSetParameter2fv(p, data); continue;
-      case Shader::SMP_vec3: cgGLSetParameter3fv(p, data); continue;
-      case Shader::SMP_vec4: cgGLSetParameter4fv(p, data); continue;
-      case Shader::SMP_vec4_array: cgGLSetParameterArray4f(p, 0, spec._array_count, data); continue;
-      case Shader::SMP_mat4_whole: cgGLSetMatrixParameterfc(p, data); continue;
-      case Shader::SMP_mat4_array: cgGLSetMatrixParameterArrayfc(p, 0, spec._array_count, data); continue;
-      case Shader::SMP_mat4_transpose: cgGLSetMatrixParameterfr(p, data); continue;
-      case Shader::SMP_mat4_column: cgGLSetParameter4f(p, data[0], data[4], data[ 8], data[12]); continue;
-      case Shader::SMP_mat4_upper3x3:
-        {
-          LMatrix3f upper3(data[0], data[1], data[2], data[4], data[5], data[6], data[8], data[9], data[10]);
-          cgGLSetMatrixParameterfc(p, upper3.get_data());
-          continue;
+      if (spec._numeric_type == Shader::SPT_float) {
+        switch (spec._piece) {
+        case Shader::SMP_scalar: cgGLSetParameter1f(p, data[0]); continue;
+        case Shader::SMP_vec2: cgGLSetParameter2fv(p, data); continue;
+        case Shader::SMP_vec3: cgGLSetParameter3fv(p, data); continue;
+        case Shader::SMP_vec4: cgGLSetParameter4fv(p, data); continue;
+        case Shader::SMP_scalar_array: cgGLSetParameterArray1f(p, 0, spec._array_count, data); continue;
+        case Shader::SMP_vec2_array: cgGLSetParameterArray2f(p, 0, spec._array_count, data); continue;
+        case Shader::SMP_vec3_array: cgGLSetParameterArray3f(p, 0, spec._array_count, data); continue;
+        case Shader::SMP_vec4_array: cgGLSetParameterArray4f(p, 0, spec._array_count, data); continue;
+        case Shader::SMP_mat3_whole:
+        case Shader::SMP_mat4_whole: cgGLSetMatrixParameterfc(p, data); continue;
+        case Shader::SMP_mat3_array:
+        case Shader::SMP_mat4_array: cgGLSetMatrixParameterArrayfc(p, 0, spec._array_count, data); continue;
+        case Shader::SMP_mat4_transpose: cgGLSetMatrixParameterfr(p, data); continue;
+        case Shader::SMP_mat4_column: cgGLSetParameter4f(p, data[0], data[4], data[ 8], data[12]); continue;
+        case Shader::SMP_mat4_upper3x3:
+          {
+            LMatrix3f upper3(data[0], data[1], data[2], data[4], data[5], data[6], data[8], data[9], data[10]);
+            cgGLSetMatrixParameterfc(p, upper3.get_data());
+            continue;
+          }
+        case Shader::SMP_mat4_transpose3x3:
+          {
+            LMatrix3f upper3(data[0], data[1], data[2], data[4], data[5], data[6], data[8], data[9], data[10]);
+            cgGLSetMatrixParameterfr(p, upper3.get_data());
+            continue;
+          }
         }
         }
-      case Shader::SMP_mat4_transpose3x3:
-        {
-          LMatrix3f upper3(data[0], data[1], data[2], data[4], data[5], data[6], data[8], data[9], data[10]);
-          cgGLSetMatrixParameterfr(p, upper3.get_data());
-          continue;
+      }
+      else if (spec._numeric_type == Shader::SPT_double) {
+        const double *datad = (const double *)data;
+        switch (spec._piece) {
+        case Shader::SMP_scalar: cgGLSetParameter1d(p, datad[0]); continue;
+        case Shader::SMP_vec2: cgGLSetParameter2dv(p, datad); continue;
+        case Shader::SMP_vec3: cgGLSetParameter3dv(p, datad); continue;
+        case Shader::SMP_vec4: cgGLSetParameter4dv(p, datad); continue;
+        case Shader::SMP_scalar_array: cgGLSetParameterArray1d(p, 0, spec._array_count, datad); continue;
+        case Shader::SMP_vec2_array: cgGLSetParameterArray2d(p, 0, spec._array_count, datad); continue;
+        case Shader::SMP_vec3_array: cgGLSetParameterArray3d(p, 0, spec._array_count, datad); continue;
+        case Shader::SMP_vec4_array: cgGLSetParameterArray4d(p, 0, spec._array_count, datad); continue;
+        case Shader::SMP_mat3_whole:
+        case Shader::SMP_mat4_whole: cgGLSetMatrixParameterdc(p, datad); continue;
+        case Shader::SMP_mat3_array:
+        case Shader::SMP_mat4_array: cgGLSetMatrixParameterArraydc(p, 0, spec._array_count, datad); continue;
+        case Shader::SMP_mat4_transpose: cgGLSetMatrixParameterdr(p, datad); continue;
+        case Shader::SMP_mat4_column: cgGLSetParameter4d(p, datad[0], datad[4], datad[ 8], datad[12]); continue;
+        case Shader::SMP_mat4_upper3x3:
+          {
+            LMatrix3d upper3(datad[0], datad[1], datad[2], datad[4], datad[5], datad[6], datad[8], datad[9], datad[10]);
+            cgGLSetMatrixParameterdc(p, upper3.get_data());
+            continue;
+          }
+        case Shader::SMP_mat4_transpose3x3:
+          {
+            LMatrix3d upper3(datad[0], datad[1], datad[2], datad[4], datad[5], datad[6], datad[8], datad[9], datad[10]);
+            cgGLSetMatrixParameterdr(p, upper3.get_data());
+            continue;
+          }
+        }
+      }
+      else if (spec._numeric_type == Shader::SPT_int || spec._numeric_type == Shader::SPT_uint) {
+        switch (spec._piece) {
+        case Shader::SMP_scalar_array:
+        case Shader::SMP_scalar: cgSetParameter1i(p, ((int *)data)[0]); continue;
+        case Shader::SMP_vec2_array:
+        case Shader::SMP_vec2: cgSetParameter2iv(p, (int *)data); continue;
+        case Shader::SMP_vec3_array:
+        case Shader::SMP_vec3: cgSetParameter3iv(p, (int *)data); continue;
+        case Shader::SMP_vec4_array:
+        case Shader::SMP_vec4: cgSetParameter4iv(p, (int *)data); continue;
+        default: assert(false);
         }
         }
-      case Shader::SMP_int: cgSetParameter1i(p, ((const int *)data)[0]); continue;
-      case Shader::SMP_ivec2: cgSetParameter2iv(p, (const int *)data); continue;
-      case Shader::SMP_ivec3: cgSetParameter3iv(p, (const int *)data); continue;
-      case Shader::SMP_ivec4: cgSetParameter4iv(p, (const int *)data); continue;
       }
       }
     }
     }
   }
   }

+ 233 - 98
panda/src/glstuff/glShaderContext_src.cxx

@@ -208,7 +208,7 @@ parse_and_set_short_hand_shader_vars(Shader::ShaderArgId &arg_id, GLenum param_t
       // We'll permit this too, simply because we can support it.
       // We'll permit this too, simply because we can support it.
       switch (param_type) {
       switch (param_type) {
       case GL_FLOAT:
       case GL_FLOAT:
-        bind._piece = Shader::SMP_float;
+        bind._piece = Shader::SMP_scalar;
         break;
         break;
       case GL_FLOAT_VEC2:
       case GL_FLOAT_VEC2:
         bind._piece = Shader::SMP_vec2;
         bind._piece = Shader::SMP_vec2;
@@ -404,7 +404,7 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
   param_count = 0;
   param_count = 0;
   _glgsg->_glGetProgramiv(_glsl_program, GL_ACTIVE_UNIFORMS, &param_count);
   _glgsg->_glGetProgramiv(_glsl_program, GL_ACTIVE_UNIFORMS, &param_count);
 
 
-  _shader->_ptr_spec.clear();
+  //_shader->_ptr_spec.clear();
   _shader->_mat_spec.clear();
   _shader->_mat_spec.clear();
   _shader->_tex_spec.clear();
   _shader->_tex_spec.clear();
   for (int i = 0; i < param_count; ++i) {
   for (int i = 0; i < param_count; ++i) {
@@ -421,6 +421,7 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
   }
   }
 
 
   _mat_part_cache = new LVecBase4f[_shader->cp_get_mat_cache_size()];
   _mat_part_cache = new LVecBase4f[_shader->cp_get_mat_cache_size()];
+  _mat_scratch_space = new LVecBase4f[_shader->cp_get_mat_scratch_size()];
 }
 }
 
 
 /**
 /**
@@ -478,6 +479,8 @@ reflect_attribute(int i, char *name_buffer, GLsizei name_buflen) {
   case GL_BOOL_VEC2:
   case GL_BOOL_VEC2:
   case GL_BOOL_VEC3:
   case GL_BOOL_VEC3:
   case GL_BOOL_VEC4:
   case GL_BOOL_VEC4:
+    bind._numeric_type = Shader::SPT_bool;
+    break;
   case GL_UNSIGNED_INT:
   case GL_UNSIGNED_INT:
   case GL_UNSIGNED_INT_VEC2:
   case GL_UNSIGNED_INT_VEC2:
   case GL_UNSIGNED_INT_VEC3:
   case GL_UNSIGNED_INT_VEC3:
@@ -1120,7 +1123,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
           GLCAT.error()
           GLCAT.error()
             << "p3d_Material.shininess should be float\n";
             << "p3d_Material.shininess should be float\n";
         }
         }
-        bind._piece = Shader::SMP_float;
+        bind._piece = Shader::SMP_scalar;
         bind._offset = 15;
         bind._offset = 15;
         _shader->cp_add_mat_spec(bind);
         _shader->cp_add_mat_spec(bind);
         return;
         return;
@@ -1131,7 +1134,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
             << "p3d_Material.roughness should be float\n";
             << "p3d_Material.roughness should be float\n";
         }
         }
         bind._part[0] = Shader::SMO_attr_material2;
         bind._part[0] = Shader::SMO_attr_material2;
-        bind._piece = Shader::SMP_float;
+        bind._piece = Shader::SMP_scalar;
         bind._offset = 7;
         bind._offset = 7;
         _shader->cp_add_mat_spec(bind);
         _shader->cp_add_mat_spec(bind);
         return;
         return;
@@ -1142,7 +1145,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
             << "p3d_Material.metallic should be bool or float\n";
             << "p3d_Material.metallic should be bool or float\n";
         }
         }
         bind._part[0] = Shader::SMO_attr_material2;
         bind._part[0] = Shader::SMO_attr_material2;
-        bind._piece = Shader::SMP_float;
+        bind._piece = Shader::SMP_scalar;
         bind._offset = 4;
         bind._offset = 4;
         _shader->cp_add_mat_spec(bind);
         _shader->cp_add_mat_spec(bind);
         return;
         return;
@@ -1153,7 +1156,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
             << "p3d_Material.refractiveIndex should be float\n";
             << "p3d_Material.refractiveIndex should be float\n";
         }
         }
         bind._part[0] = Shader::SMO_attr_material2;
         bind._part[0] = Shader::SMO_attr_material2;
-        bind._piece = Shader::SMP_float;
+        bind._piece = Shader::SMP_scalar;
         bind._offset = 5;
         bind._offset = 5;
         _shader->cp_add_mat_spec(bind);
         _shader->cp_add_mat_spec(bind);
         return;
         return;
@@ -1244,7 +1247,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
         bind._part[0] = Shader::SMO_attr_fog;
         bind._part[0] = Shader::SMO_attr_fog;
 
 
         if (param_type == GL_FLOAT) {
         if (param_type == GL_FLOAT) {
-          bind._piece = Shader::SMP_float;
+          bind._piece = Shader::SMP_scalar;
         } else {
         } else {
           GLCAT.error()
           GLCAT.error()
             << "p3d_Fog.density should be float\n";
             << "p3d_Fog.density should be float\n";
@@ -1255,7 +1258,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
         bind._part[0] = Shader::SMO_attr_fog;
         bind._part[0] = Shader::SMO_attr_fog;
 
 
         if (param_type == GL_FLOAT) {
         if (param_type == GL_FLOAT) {
-          bind._piece = Shader::SMP_float;
+          bind._piece = Shader::SMP_scalar;
           bind._offset = 1;
           bind._offset = 1;
         } else {
         } else {
           GLCAT.error()
           GLCAT.error()
@@ -1267,7 +1270,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
         bind._part[0] = Shader::SMO_attr_fog;
         bind._part[0] = Shader::SMO_attr_fog;
 
 
         if (param_type == GL_FLOAT) {
         if (param_type == GL_FLOAT) {
-          bind._piece = Shader::SMP_float;
+          bind._piece = Shader::SMP_scalar;
           bind._offset = 2;
           bind._offset = 2;
         } else {
         } else {
           GLCAT.error()
           GLCAT.error()
@@ -1279,7 +1282,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
         bind._part[0] = Shader::SMO_attr_fog;
         bind._part[0] = Shader::SMO_attr_fog;
 
 
         if (param_type == GL_FLOAT) {
         if (param_type == GL_FLOAT) {
-          bind._piece = Shader::SMP_float;
+          bind._piece = Shader::SMP_scalar;
           bind._offset = 3;
           bind._offset = 3;
         } else {
         } else {
           GLCAT.error()
           GLCAT.error()
@@ -1354,7 +1357,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
 
 
           switch (param_type) {
           switch (param_type) {
           case GL_FLOAT:
           case GL_FLOAT:
-            bind._piece = Shader::SMP_float;
+            bind._piece = Shader::SMP_scalar;
             break;
             break;
 
 
           case GL_FLOAT_VEC2:
           case GL_FLOAT_VEC2:
@@ -1442,7 +1445,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
       return;
       return;
 
 
     } else if (noprefix == "FrameTime") {
     } else if (noprefix == "FrameTime") {
-      bind._piece = Shader::SMP_float;
+      bind._piece = Shader::SMP_scalar;
       bind._func = Shader::SMF_first;
       bind._func = Shader::SMF_first;
       bind._part[0] = Shader::SMO_frame_time;
       bind._part[0] = Shader::SMO_frame_time;
       bind._part[1] = Shader::SMO_identity;
       bind._part[1] = Shader::SMO_identity;
@@ -1450,7 +1453,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
       return;
       return;
 
 
     } else if (noprefix == "DeltaFrameTime") {
     } else if (noprefix == "DeltaFrameTime") {
-      bind._piece = Shader::SMP_float;
+      bind._piece = Shader::SMP_scalar;
       bind._func = Shader::SMF_first;
       bind._func = Shader::SMF_first;
       bind._part[0] = Shader::SMO_frame_delta;
       bind._part[0] = Shader::SMO_frame_delta;
       bind._part[1] = Shader::SMO_identity;
       bind._part[1] = Shader::SMO_identity;
@@ -1596,7 +1599,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
           bind._id = arg_id;
           bind._id = arg_id;
           switch (param_type) {
           switch (param_type) {
           case GL_FLOAT:
           case GL_FLOAT:
-            bind._piece = Shader::SMP_float;
+            bind._piece = Shader::SMP_scalar;
             break;
             break;
           case GL_FLOAT_VEC2:
           case GL_FLOAT_VEC2:
             bind._piece = Shader::SMP_vec2;
             bind._piece = Shader::SMP_vec2;
@@ -1628,59 +1631,106 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
       case GL_UNSIGNED_INT_VEC2:
       case GL_UNSIGNED_INT_VEC2:
       case GL_UNSIGNED_INT_VEC3:
       case GL_UNSIGNED_INT_VEC3:
       case GL_UNSIGNED_INT_VEC4: {
       case GL_UNSIGNED_INT_VEC4: {
-        Shader::ShaderPtrSpec bind;
+        Shader::ShaderMatSpec bind;
         bind._id = arg_id;
         bind._id = arg_id;
-        switch (param_type) {
-          case GL_BOOL:
-          case GL_INT:
-          case GL_UNSIGNED_INT:
-          case GL_FLOAT:      bind._dim[1] = 1; break;
-          case GL_BOOL_VEC2:
-          case GL_INT_VEC2:
-          case GL_UNSIGNED_INT_VEC2:
-          case GL_FLOAT_VEC2: bind._dim[1] = 2; break;
-          case GL_BOOL_VEC3:
-          case GL_INT_VEC3:
-          case GL_UNSIGNED_INT_VEC3:
-          case GL_FLOAT_VEC3: bind._dim[1] = 3; break;
-          case GL_BOOL_VEC4:
-          case GL_INT_VEC4:
-          case GL_UNSIGNED_INT_VEC4:
-          case GL_FLOAT_VEC4: bind._dim[1] = 4; break;
-          case GL_FLOAT_MAT3: bind._dim[1] = 9; break;
-          case GL_FLOAT_MAT4: bind._dim[1] = 16; break;
-        }
+        bind._func = Shader::SMF_shader_input_ptr;
         switch (param_type) {
         switch (param_type) {
         case GL_BOOL:
         case GL_BOOL:
+          bind._piece = Shader::SMP_scalar;
+          bind._numeric_type = Shader::SPT_bool;
+          bind._num_components = 1;
+          break;
         case GL_BOOL_VEC2:
         case GL_BOOL_VEC2:
+          bind._piece = Shader::SMP_vec2;
+          bind._numeric_type = Shader::SPT_bool;
+          bind._num_components = 2;
+          break;
         case GL_BOOL_VEC3:
         case GL_BOOL_VEC3:
+          bind._piece = Shader::SMP_vec3;
+          bind._numeric_type = Shader::SPT_bool;
+          bind._num_components = 3;
+          break;
         case GL_BOOL_VEC4:
         case GL_BOOL_VEC4:
+          bind._piece = Shader::SMP_vec4;
+          bind._numeric_type = Shader::SPT_bool;
+          bind._num_components = 4;
+          break;
         case GL_UNSIGNED_INT:
         case GL_UNSIGNED_INT:
+          bind._piece = Shader::SMP_scalar;
+          bind._numeric_type = Shader::SPT_uint;
+          bind._num_components = 1;
+          break;
         case GL_UNSIGNED_INT_VEC2:
         case GL_UNSIGNED_INT_VEC2:
+          bind._piece = Shader::SMP_vec2;
+          bind._numeric_type = Shader::SPT_uint;
+          bind._num_components = 2;
+          break;
         case GL_UNSIGNED_INT_VEC3:
         case GL_UNSIGNED_INT_VEC3:
+          bind._piece = Shader::SMP_vec3;
+          bind._numeric_type = Shader::SPT_uint;
+          bind._num_components = 3;
+          break;
         case GL_UNSIGNED_INT_VEC4:
         case GL_UNSIGNED_INT_VEC4:
-          bind._type = Shader::SPT_uint;
+          bind._piece = Shader::SMP_vec4;
+          bind._numeric_type = Shader::SPT_uint;
+          bind._num_components = 4;
           break;
           break;
         case GL_INT:
         case GL_INT:
+          bind._piece = Shader::SMP_scalar;
+          bind._numeric_type = Shader::SPT_int;
+          bind._num_components = 1;
+          break;
         case GL_INT_VEC2:
         case GL_INT_VEC2:
+          bind._piece = Shader::SMP_vec2;
+          bind._numeric_type = Shader::SPT_int;
+          bind._num_components = 2;
+          break;
         case GL_INT_VEC3:
         case GL_INT_VEC3:
+          bind._piece = Shader::SMP_vec3;
+          bind._numeric_type = Shader::SPT_int;
+          bind._num_components = 3;
+          break;
         case GL_INT_VEC4:
         case GL_INT_VEC4:
-          bind._type = Shader::SPT_int;
+          bind._piece = Shader::SMP_vec4;
+          bind._numeric_type = Shader::SPT_int;
+          bind._num_components = 4;
           break;
           break;
         case GL_FLOAT:
         case GL_FLOAT:
+          bind._piece = Shader::SMP_scalar;
+          bind._numeric_type = Shader::SPT_float;
+          bind._num_components = 1;
+          break;
         case GL_FLOAT_VEC2:
         case GL_FLOAT_VEC2:
+          bind._piece = Shader::SMP_vec2;
+          bind._numeric_type = Shader::SPT_float;
+          bind._num_components = 2;
+          break;
         case GL_FLOAT_VEC3:
         case GL_FLOAT_VEC3:
+          bind._piece = Shader::SMP_vec3;
+          bind._numeric_type = Shader::SPT_float;
+          bind._num_components = 3;
+          break;
         case GL_FLOAT_VEC4:
         case GL_FLOAT_VEC4:
+          bind._piece = Shader::SMP_vec4;
+          bind._numeric_type = Shader::SPT_float;
+          bind._num_components = 4;
+          break;
         case GL_FLOAT_MAT3:
         case GL_FLOAT_MAT3:
+          bind._piece = Shader::SMP_mat3_whole;
+          bind._numeric_type = Shader::SPT_float;
+          bind._num_components = 9;
+          break;
         case GL_FLOAT_MAT4:
         case GL_FLOAT_MAT4:
-          bind._type = Shader::SPT_float;
+          bind._piece = Shader::SMP_mat4_whole;
+          bind._numeric_type = Shader::SPT_float;
+          bind._num_components = 16;
           break;
           break;
         }
         }
-        bind._arg = InternalName::make(param_name);
-        bind._dim[0] = 1;
-        bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs | Shader::SSD_frame;
-        bind._dep[1] = Shader::SSD_NONE;
-        _shader->_ptr_spec.push_back(bind);
+        bind._part[0] = Shader::SMO_INVALID;
+        bind._part[1] = Shader::SMO_INVALID;
+        bind._arg[0] = InternalName::make(param_name);
+        bind._arg[1] = nullptr;
+        _shader->cp_add_mat_spec(bind);
         return;
         return;
       }
       }
       case GL_IMAGE_2D:
       case GL_IMAGE_2D:
@@ -1772,55 +1822,107 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
     case GL_FLOAT_VEC4:
     case GL_FLOAT_VEC4:
     case GL_FLOAT_MAT3:
     case GL_FLOAT_MAT3:
     case GL_FLOAT_MAT4: {
     case GL_FLOAT_MAT4: {
-      Shader::ShaderPtrSpec bind;
+      Shader::ShaderMatSpec bind;
       bind._id = arg_id;
       bind._id = arg_id;
-      switch (param_type) {
-        case GL_BOOL:
-        case GL_INT:
-        case GL_FLOAT:      bind._dim[1] = 1; break;
-        case GL_BOOL_VEC2:
-        case GL_INT_VEC2:
-        case GL_FLOAT_VEC2: bind._dim[1] = 2; break;
-        case GL_BOOL_VEC3:
-        case GL_INT_VEC3:
-        case GL_FLOAT_VEC3: bind._dim[1] = 3; break;
-        case GL_BOOL_VEC4:
-        case GL_INT_VEC4:
-        case GL_FLOAT_VEC4: bind._dim[1] = 4; break;
-        case GL_FLOAT_MAT3: bind._dim[1] = 9; break;
-        case GL_FLOAT_MAT4: bind._dim[1] = 16; break;
-      }
+      bind._func = Shader::SMF_shader_input_ptr;
       switch (param_type) {
       switch (param_type) {
       case GL_BOOL:
       case GL_BOOL:
+        bind._piece = Shader::SMP_scalar_array;
+        bind._numeric_type = Shader::SPT_uint;
+        bind._num_components = 1;
+        break;
       case GL_BOOL_VEC2:
       case GL_BOOL_VEC2:
+        bind._piece = Shader::SMP_vec2_array;
+        bind._numeric_type = Shader::SPT_uint;
+        bind._num_components = 2;
+        break;
       case GL_BOOL_VEC3:
       case GL_BOOL_VEC3:
+        bind._piece = Shader::SMP_vec3_array;
+        bind._numeric_type = Shader::SPT_uint;
+        bind._num_components = 3;
+        break;
       case GL_BOOL_VEC4:
       case GL_BOOL_VEC4:
+        bind._piece = Shader::SMP_vec4_array;
+        bind._numeric_type = Shader::SPT_uint;
+        bind._num_components = 4;
+        break;
       case GL_UNSIGNED_INT:
       case GL_UNSIGNED_INT:
+        bind._piece = Shader::SMP_scalar_array;
+        bind._numeric_type = Shader::SPT_uint;
+        bind._num_components = 1;
+        break;
       case GL_UNSIGNED_INT_VEC2:
       case GL_UNSIGNED_INT_VEC2:
+        bind._piece = Shader::SMP_vec2_array;
+        bind._numeric_type = Shader::SPT_uint;
+        bind._num_components = 2;
+        break;
       case GL_UNSIGNED_INT_VEC3:
       case GL_UNSIGNED_INT_VEC3:
+        bind._piece = Shader::SMP_vec3_array;
+        bind._numeric_type = Shader::SPT_uint;
+        bind._num_components = 3;
+        break;
       case GL_UNSIGNED_INT_VEC4:
       case GL_UNSIGNED_INT_VEC4:
-        bind._type = Shader::SPT_uint;
+        bind._piece = Shader::SMP_vec4_array;
+        bind._numeric_type = Shader::SPT_uint;
+        bind._num_components = 4;
         break;
         break;
       case GL_INT:
       case GL_INT:
+        bind._piece = Shader::SMP_scalar_array;
+        bind._numeric_type = Shader::SPT_int;
+        bind._num_components = 1;
+        break;
       case GL_INT_VEC2:
       case GL_INT_VEC2:
+        bind._piece = Shader::SMP_vec2_array;
+        bind._numeric_type = Shader::SPT_int;
+        bind._num_components = 2;
+        break;
       case GL_INT_VEC3:
       case GL_INT_VEC3:
+        bind._piece = Shader::SMP_vec3_array;
+        bind._numeric_type = Shader::SPT_int;
+        bind._num_components = 3;
+        break;
       case GL_INT_VEC4:
       case GL_INT_VEC4:
-        bind._type = Shader::SPT_int;
+        bind._piece = Shader::SMP_vec4_array;
+        bind._numeric_type = Shader::SPT_int;
+        bind._num_components = 4;
         break;
         break;
       case GL_FLOAT:
       case GL_FLOAT:
+        bind._piece = Shader::SMP_scalar_array;
+        bind._numeric_type = Shader::SPT_float;
+        bind._num_components = 1;
+        break;
       case GL_FLOAT_VEC2:
       case GL_FLOAT_VEC2:
+        bind._piece = Shader::SMP_vec2_array;
+        bind._numeric_type = Shader::SPT_float;
+        bind._num_components = 2;
+        break;
       case GL_FLOAT_VEC3:
       case GL_FLOAT_VEC3:
+        bind._piece = Shader::SMP_vec3_array;
+        bind._numeric_type = Shader::SPT_float;
+        bind._num_components = 3;
+        break;
       case GL_FLOAT_VEC4:
       case GL_FLOAT_VEC4:
+        bind._piece = Shader::SMP_vec4_array;
+        bind._numeric_type = Shader::SPT_float;
+        bind._num_components = 4;
+        break;
       case GL_FLOAT_MAT3:
       case GL_FLOAT_MAT3:
+        bind._piece = Shader::SMP_mat3_array;
+        bind._numeric_type = Shader::SPT_float;
+        bind._num_components = 9;
+        break;
       case GL_FLOAT_MAT4:
       case GL_FLOAT_MAT4:
-        bind._type = Shader::SPT_float;
+        bind._piece = Shader::SMP_mat4_array;
+        bind._numeric_type = Shader::SPT_float;
+        bind._num_components = 16;
         break;
         break;
       }
       }
-      bind._arg = InternalName::make(param_name);
-      bind._dim[0] = param_size;
-      bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs | Shader::SSD_frame;
-      bind._dep[1] = Shader::SSD_NONE;
-      _shader->_ptr_spec.push_back(bind);
+      bind._part[0] = Shader::SMO_INVALID;
+      bind._part[1] = Shader::SMO_INVALID;
+      bind._arg[0] = InternalName::make(param_name);
+      bind._arg[1] = nullptr;
+      bind._array_count = param_size;
+      _shader->cp_add_mat_spec(bind);
       return;
       return;
     }
     }
     default:
     default:
@@ -1967,6 +2069,7 @@ CLP(ShaderContext)::
 ~CLP(ShaderContext)() {
 ~CLP(ShaderContext)() {
   // Don't call release_resources; we may not have an active context.
   // Don't call release_resources; we may not have an active context.
   delete[] _mat_part_cache;
   delete[] _mat_part_cache;
+  delete[] _mat_scratch_space;
 }
 }
 
 
 /**
 /**
@@ -2170,7 +2273,7 @@ issue_parameters(int altered) {
     }
     }
 
 
     // Iterate through _ptr parameters
     // Iterate through _ptr parameters
-    for (int i = 0; i < (int)_shader->_ptr_spec.size(); ++i) {
+    /*for (int i = 0; i < (int)_shader->_ptr_spec.size(); ++i) {
       Shader::ShaderPtrSpec &spec = _shader->_ptr_spec[i];
       Shader::ShaderPtrSpec &spec = _shader->_ptr_spec[i];
 
 
       Shader::ShaderPtrData ptr_data;
       Shader::ShaderPtrData ptr_data;
@@ -2293,51 +2396,83 @@ issue_parameters(int altered) {
       default:
       default:
         continue;
         continue;
       }
       }
-    }
+    }*/
   }
   }
 
 
   if (altered & _shader->_mat_deps) {
   if (altered & _shader->_mat_deps) {
-    _glgsg->update_shader_matrix_cache(_shader, _mat_part_cache, altered);
-
-    LMatrix4f scratch;
+    if (altered & _shader->_mat_cache_deps) {
+      _glgsg->update_shader_matrix_cache(_shader, _mat_part_cache, altered);
+    }
 
 
     for (Shader::ShaderMatSpec &spec : _shader->_mat_spec) {
     for (Shader::ShaderMatSpec &spec : _shader->_mat_spec) {
       if ((altered & spec._dep) == 0) {
       if ((altered & spec._dep) == 0) {
         continue;
         continue;
       }
       }
 
 
-      const LVecBase4f *val = _glgsg->fetch_specified_value(spec, _mat_part_cache, &scratch);
+      const LVecBase4f *val = _glgsg->fetch_specified_value(spec, _mat_part_cache, _mat_scratch_space);
       if (!val) continue;
       if (!val) continue;
       const float *data = val->get_data();
       const float *data = val->get_data();
       data += spec._offset;
       data += spec._offset;
 
 
       GLint p = spec._id._seqno;
       GLint p = spec._id._seqno;
-      switch (spec._piece) {
-      case Shader::SMP_float: _glgsg->_glUniform1fv(p, 1, data); continue;
-      case Shader::SMP_vec2: _glgsg->_glUniform2fv(p, 1, data); continue;
-      case Shader::SMP_vec3: _glgsg->_glUniform3fv(p, 1, data); continue;
-      case Shader::SMP_vec4: _glgsg->_glUniform4fv(p, 1, data); continue;
-      case Shader::SMP_vec4_array: _glgsg->_glUniform4fv(p, spec._array_count, data); continue;
-      case Shader::SMP_mat4_whole: _glgsg->_glUniformMatrix4fv(p, 1, GL_FALSE, data); continue;
-      case Shader::SMP_mat4_array: _glgsg->_glUniformMatrix4fv(p, spec._array_count, GL_FALSE, data); continue;
-      case Shader::SMP_mat4_transpose: _glgsg->_glUniformMatrix4fv(p, 1, GL_TRUE, data); continue;
-      case Shader::SMP_mat4_column: _glgsg->_glUniform4f(p, data[0], data[4], data[8], data[12]); continue;
-      case Shader::SMP_mat4_upper3x3:
-        {
-          LMatrix3f upper3(data[0], data[1], data[2], data[4], data[5], data[6], data[8], data[9], data[10]);
-          _glgsg->_glUniformMatrix3fv(p, 1, false, upper3.get_data());
-          continue;
+      if (spec._numeric_type == Shader::SPT_float) {
+        switch (spec._piece) {
+        case Shader::SMP_scalar: _glgsg->_glUniform1fv(p, 1, data); continue;
+        case Shader::SMP_vec2: _glgsg->_glUniform2fv(p, 1, data); continue;
+        case Shader::SMP_vec3: _glgsg->_glUniform3fv(p, 1, data); continue;
+        case Shader::SMP_vec4: _glgsg->_glUniform4fv(p, 1, data); continue;
+        case Shader::SMP_scalar_array: _glgsg->_glUniform1fv(p, spec._array_count, data); continue;
+        case Shader::SMP_vec2_array: _glgsg->_glUniform2fv(p, spec._array_count, data); continue;
+        case Shader::SMP_vec3_array: _glgsg->_glUniform3fv(p, spec._array_count, data); continue;
+        case Shader::SMP_vec4_array: _glgsg->_glUniform4fv(p, spec._array_count, data); continue;
+        case Shader::SMP_mat3_whole: _glgsg->_glUniformMatrix3fv(p, 1, GL_FALSE, data); continue;
+        case Shader::SMP_mat3_array: _glgsg->_glUniformMatrix3fv(p, spec._array_count, GL_FALSE, data); continue;
+        case Shader::SMP_mat4_whole: _glgsg->_glUniformMatrix4fv(p, 1, GL_FALSE, data); continue;
+        case Shader::SMP_mat4_array: _glgsg->_glUniformMatrix4fv(p, spec._array_count, GL_FALSE, data); continue;
+        case Shader::SMP_mat4_transpose: _glgsg->_glUniformMatrix4fv(p, 1, GL_TRUE, data); continue;
+        case Shader::SMP_mat4_column: _glgsg->_glUniform4f(p, data[0], data[4], data[8], data[12]); continue;
+        case Shader::SMP_mat4_upper3x3:
+          {
+            LMatrix3f upper3(data[0], data[1], data[2], data[4], data[5], data[6], data[8], data[9], data[10]);
+            _glgsg->_glUniformMatrix3fv(p, 1, false, upper3.get_data());
+            continue;
+          }
+        case Shader::SMP_mat4_transpose3x3:
+          {
+            LMatrix3f upper3(data[0], data[1], data[2], data[4], data[5], data[6], data[8], data[9], data[10]);
+            _glgsg->_glUniformMatrix3fv(p, 1, true, upper3.get_data());
+            continue;
+          }
         }
         }
-      case Shader::SMP_mat4_transpose3x3:
-        {
-          LMatrix3f upper3(data[0], data[1], data[2], data[4], data[5], data[6], data[8], data[9], data[10]);
-          _glgsg->_glUniformMatrix3fv(p, 1, true, upper3.get_data());
-          continue;
+      }
+      else if (spec._numeric_type == Shader::SPT_int) {
+        switch (spec._piece) {
+        case Shader::SMP_scalar: _glgsg->_glUniform1iv(p, 1, (const GLint *)data); continue;
+        case Shader::SMP_vec2: _glgsg->_glUniform2iv(p, 1, (const GLint *)data); continue;
+        case Shader::SMP_vec3: _glgsg->_glUniform3iv(p, 1, (const GLint *)data); continue;
+        case Shader::SMP_vec4: _glgsg->_glUniform4iv(p, 1, (const GLint *)data); continue;
+        case Shader::SMP_scalar_array: _glgsg->_glUniform1iv(p, spec._array_count, (const GLint *)data); continue;
+        case Shader::SMP_vec2_array: _glgsg->_glUniform2iv(p, spec._array_count, (const GLint *)data); continue;
+        case Shader::SMP_vec3_array: _glgsg->_glUniform3iv(p, spec._array_count, (const GLint *)data); continue;
+        case Shader::SMP_vec4_array: _glgsg->_glUniform4iv(p, spec._array_count, (const GLint *)data); continue;
+        default: assert(false);
+        }
+      }
+      else if (spec._numeric_type == Shader::SPT_uint || spec._numeric_type == Shader::SPT_bool) {
+        switch (spec._piece) {
+        case Shader::SMP_scalar: _glgsg->_glUniform1uiv(p, 1, (const GLuint *)data); continue;
+        case Shader::SMP_vec2: _glgsg->_glUniform2uiv(p, 1, (const GLuint *)data); continue;
+        case Shader::SMP_vec3: _glgsg->_glUniform3uiv(p, 1, (const GLuint *)data); continue;
+        case Shader::SMP_vec4: _glgsg->_glUniform4uiv(p, 1, (const GLuint *)data); continue;
+        case Shader::SMP_scalar_array: _glgsg->_glUniform1uiv(p, spec._array_count, (const GLuint *)data); continue;
+        case Shader::SMP_vec2_array: _glgsg->_glUniform2uiv(p, spec._array_count, (const GLuint *)data); continue;
+        case Shader::SMP_vec3_array: _glgsg->_glUniform3uiv(p, spec._array_count, (const GLuint *)data); continue;
+        case Shader::SMP_vec4_array: _glgsg->_glUniform4uiv(p, spec._array_count, (const GLuint *)data); continue;
+        default: assert(false);
         }
         }
-      case Shader::SMP_int: _glgsg->_glUniform1i(p, ((int *)data)[0]); continue;
-      case Shader::SMP_ivec2: _glgsg->_glUniform2iv(p, 1, (int *)data); continue;
-      case Shader::SMP_ivec3: _glgsg->_glUniform3iv(p, 1, (int *)data); continue;
-      case Shader::SMP_ivec4: _glgsg->_glUniform4iv(p, 1, (int *)data); continue;
+      }
+      else {
+        nassert_raise("double-precision uniform passing not supported");
       }
       }
     }
     }
   }
   }

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

@@ -113,6 +113,7 @@ private:
   pvector<ImageInput> _glsl_img_inputs;
   pvector<ImageInput> _glsl_img_inputs;
 
 
   LVecBase4f *_mat_part_cache = nullptr;
   LVecBase4f *_mat_part_cache = nullptr;
+  LVecBase4f *_mat_scratch_space = nullptr;
 
 
   CLP(GraphicsStateGuardian) *_glgsg;
   CLP(GraphicsStateGuardian) *_glgsg;
 
 

+ 38 - 36
panda/src/gobj/shader.cxx

@@ -602,6 +602,9 @@ cp_add_mat_spec(ShaderMatSpec &spec) {
   int num_parts = (spec._func != SMF_first) ? 2 : 1;
   int num_parts = (spec._func != SMF_first) ? 2 : 1;
 
 
   for (int p = 0; p < num_parts; ++p) {
   for (int p = 0; p < num_parts; ++p) {
+    if (spec._part[p] == SMO_INVALID) {
+      continue;
+    }
     int dep = cp_dependency(spec._part[p]);
     int dep = cp_dependency(spec._part[p]);
     spec._dep |= dep;
     spec._dep |= dep;
 
 
@@ -724,10 +727,19 @@ cp_add_mat_spec(ShaderMatSpec &spec) {
         assert(part._size == 4);
         assert(part._size == 4);
       }
       }
 
 
+      _mat_cache_deps |= part._dep;
       _mat_parts.push_back(std::move(part));
       _mat_parts.push_back(std::move(part));
     }
     }
     spec._cache_offset[p] = offset + begin[p];
     spec._cache_offset[p] = offset + begin[p];
   }
   }
+  if (spec._func == SMF_shader_input_ptr) {
+    _mat_scratch_size = std::max(_mat_scratch_size, spec._array_count);
+
+    // 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.
+    spec._dep |= SSD_general | SSD_shaderinputs | SSD_frame;
+  }
 
 
   _mat_spec.push_back(spec);
   _mat_spec.push_back(spec);
   _mat_deps |= spec._dep;
   _mat_deps |= spec._dep;
@@ -746,6 +758,15 @@ cp_get_mat_cache_size() const {
   return size;
   return size;
 }
 }
 
 
+/**
+ * Returns the total amount of scratch space required to fetch the largest
+ * shader input of this shader.
+ */
+size_t Shader::
+cp_get_mat_scratch_size() const {
+  return _mat_scratch_size;
+}
+
 #ifdef HAVE_CG
 #ifdef HAVE_CG
 /**
 /**
  *
  *
@@ -1483,7 +1504,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
       if (!cp_errchk_parameter_float(p, 1, 1)) {
       if (!cp_errchk_parameter_float(p, 1, 1)) {
         return false;
         return false;
       }
       }
-      bind._piece = SMP_float;
+      bind._piece = SMP_scalar;
       bind._part[0] = SMO_frame_time;
       bind._part[0] = SMO_frame_time;
       bind._arg[0] = nullptr;
       bind._arg[0] = nullptr;
 
 
@@ -1635,25 +1656,25 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
   case SAC_matrix:
   case SAC_matrix:
   case SAC_scalar:
   case SAC_scalar:
   case SAC_array: {
   case SAC_array: {
-    if (!cp_errchk_parameter_ptr(p))
+    if (!cp_errchk_parameter_ptr(p)) {
       return false;
       return false;
+    }
 
 
-    ShaderPtrSpec bind;
-    bind._id      = p._id;
-    bind._arg     = kinputname;
-    bind._info    = p;
-
-    // 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;
-
-    memcpy(bind._dim,arg_dim,sizeof(int)*3);
+    ShaderMatSpec bind;
+    bind._id = p._id;
+    bind._func = SMF_shader_input_ptr;
+    bind._part[0] = SMO_INVALID;
+    bind._part[1] = SMO_INVALID;
+    bind._arg[0] = kinputname;
+    bind._arg[1] = nullptr;
+    bind._array_count = arg_dim[0] * arg_dim[1];
+    bind._num_components = arg_dim[2];
+    bind._numeric_type = p._numeric_type;
+    bind._piece = (ShaderMatPiece)(SMP_scalar + (arg_dim[2] - 1));
 
 
     // if dim[0] = -1,  glShaderContext will not check the param size
     // if dim[0] = -1,  glShaderContext will not check the param size
-    if (k_prefix) bind._dim[0] = -1;
-    _ptr_spec.push_back(bind);
+    //if (k_prefix) bind._dim[0] = -1;
+    cp_add_mat_spec(bind);
     return true;
     return true;
   }
   }
 
 
@@ -2285,11 +2306,6 @@ cg_analyze_shader(const ShaderCaps &caps) {
     _tex_spec[i]._id._seqno = seqno++;
     _tex_spec[i]._id._seqno = seqno++;
   }
   }
 
 
-  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;
-  }
-
   /*
   /*
   // The following code is present to work around a bug in the Cg compiler.
   // The following code is present to work around a bug in the Cg compiler.
   // It does not generate correct code for shadow map lookups when using arbfp1.
   // It does not generate correct code for shadow map lookups when using arbfp1.
@@ -2452,9 +2468,8 @@ cg_compile_for(const ShaderCaps &caps, CGcontext context,
   size_t n_mat = _mat_spec.size();
   size_t n_mat = _mat_spec.size();
   size_t n_tex = _tex_spec.size();
   size_t n_tex = _tex_spec.size();
   size_t n_var = _var_spec.size();
   size_t n_var = _var_spec.size();
-  size_t n_ptr = _ptr_spec.size();
 
 
-  map.resize(n_mat + n_tex + n_var + n_ptr);
+  map.resize(n_mat + n_tex + n_var);
 
 
   // This is a bit awkward, we have to go in and seperate out the combined
   // This is a bit awkward, we have to go in and seperate out the combined
   // program, since all the parameter bindings have changed.
   // program, since all the parameter bindings have changed.
@@ -2513,19 +2528,6 @@ cg_compile_for(const ShaderCaps &caps, CGcontext context,
     map[id._seqno] = p;
     map[id._seqno] = p;
   }
   }
 
 
-  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());
-
-    if (shader_cat.is_debug()) {
-      const char *resource = cgGetParameterResourceName(map[id._seqno]);
-      if (resource != nullptr) {
-        shader_cat.debug() << "Uniform ptr parameter " << id._name
-                           << " 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) {
     cgDestroyProgram(_cg_vprogram);
     cgDestroyProgram(_cg_vprogram);

+ 13 - 7
panda/src/gobj/shader.h

@@ -292,21 +292,22 @@ public:
   };
   };
 
 
   enum ShaderMatPiece {
   enum ShaderMatPiece {
-    SMP_float,
+    SMP_scalar,
     SMP_vec2,
     SMP_vec2,
     SMP_vec3,
     SMP_vec3,
     SMP_vec4,
     SMP_vec4,
+    SMP_scalar_array,
+    SMP_vec2_array,
+    SMP_vec3_array,
     SMP_vec4_array,
     SMP_vec4_array,
+    SMP_mat3_whole,
+    SMP_mat3_array,
     SMP_mat4_whole,
     SMP_mat4_whole,
     SMP_mat4_array,
     SMP_mat4_array,
     SMP_mat4_transpose,
     SMP_mat4_transpose,
     SMP_mat4_column,
     SMP_mat4_column,
     SMP_mat4_upper3x3,
     SMP_mat4_upper3x3,
     SMP_mat4_transpose3x3,
     SMP_mat4_transpose3x3,
-    SMP_int,
-    SMP_ivec2,
-    SMP_ivec3,
-    SMP_ivec4,
   };
   };
 
 
   enum ShaderStateDep {
   enum ShaderStateDep {
@@ -339,6 +340,7 @@ public:
     SMF_transform_dlight,
     SMF_transform_dlight,
     SMF_transform_plight,
     SMF_transform_plight,
     SMF_transform_slight,
     SMF_transform_slight,
+    SMF_shader_input_ptr,
   };
   };
 
 
   struct ShaderArgId {
   struct ShaderArgId {
@@ -352,6 +354,7 @@ public:
     SPT_double,
     SPT_double,
     SPT_int,
     SPT_int,
     SPT_uint,
     SPT_uint,
+    SPT_bool,
     SPT_unknown
     SPT_unknown
   };
   };
 
 
@@ -443,6 +446,8 @@ public:
     ShaderMatPiece    _piece;
     ShaderMatPiece    _piece;
     int               _offset = 0;
     int               _offset = 0;
     int               _array_count = 1;
     int               _array_count = 1;
+    int               _num_components;
+    ShaderPtrType     _numeric_type = SPT_float;
   };
   };
 
 
   struct ShaderTexSpec {
   struct ShaderTexSpec {
@@ -547,6 +552,7 @@ public:
   int cp_dependency(ShaderMatInput inp);
   int cp_dependency(ShaderMatInput inp);
   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;
+  size_t cp_get_mat_scratch_size() const;
 
 
 #ifdef HAVE_CG
 #ifdef HAVE_CG
   void cg_recurse_parameters(CGparameter parameter,
   void cg_recurse_parameters(CGparameter parameter,
@@ -606,13 +612,13 @@ public:
 #endif
 #endif
 
 
 public:
 public:
-  pvector<ShaderPtrSpec> _ptr_spec;
   pvector<ShaderMatSpec> _mat_spec;
   pvector<ShaderMatSpec> _mat_spec;
   pvector<ShaderTexSpec> _tex_spec;
   pvector<ShaderTexSpec> _tex_spec;
   pvector<ShaderVarSpec> _var_spec;
   pvector<ShaderVarSpec> _var_spec;
   pvector<ShaderMatPart> _mat_parts;
   pvector<ShaderMatPart> _mat_parts;
+  int _mat_cache_deps = 0;
   int _mat_deps = 0;
   int _mat_deps = 0;
-  int _mat_cache_size = 0;
+  int _mat_scratch_size = 4;
 
 
   bool _error_flag;
   bool _error_flag;
   ShaderFile _text;
   ShaderFile _text;

+ 20 - 0
tests/display/test_glsl_shader.py

@@ -463,6 +463,26 @@ def test_glsl_pta_ivec4(gsg):
     run_glsl_test(gsg, code, preamble, {'pta': pta})
     run_glsl_test(gsg, code, preamble, {'pta': pta})
 
 
 
 
+def test_glsl_pta_mat3(gsg):
+    pta = core.PTA_LMatrix3f((
+        (0, 1, 2, 3, 4, 5, 6, 7, 8),
+        (9, 10, 11, 12, 13, 14, 15, 16, 17),
+    ))
+
+    preamble = """
+    uniform mat3 pta[2];
+    """
+    code = """
+    assert(pta[0][0] == vec3(0, 1, 2));
+    assert(pta[0][1] == vec3(3, 4, 5));
+    assert(pta[0][2] == vec3(6, 7, 8));
+    assert(pta[1][0] == vec3(9, 10, 11));
+    assert(pta[1][1] == vec3(12, 13, 14));
+    assert(pta[1][2] == vec3(15, 16, 17));
+    """
+    run_glsl_test(gsg, code, preamble, {'pta': pta})
+
+
 def test_glsl_pta_mat4(gsg):
 def test_glsl_pta_mat4(gsg):
     pta = core.PTA_LMatrix4f((
     pta = core.PTA_LMatrix4f((
         (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15),
         (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15),