Browse Source

Shader context input state tracking system, for more efficiently updating shader inputs

rdb 10 years ago
parent
commit
e4c3301bd0

+ 0 - 10
panda/src/glstuff/glCgShaderContext_src.I

@@ -52,15 +52,5 @@ uses_custom_vertex_arrays() {
   return true;
   return true;
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: GLCgShaderContext::uses_custom_texture_bindings
-//       Access: Public
-//  Description: Always true, for now.
-////////////////////////////////////////////////////////////////////
-INLINE bool CLP(CgShaderContext)::
-uses_custom_texture_bindings() {
-  return true;
-}
-
 #endif  // OPENGLES_1
 #endif  // OPENGLES_1
 
 

+ 139 - 56
panda/src/glstuff/glCgShaderContext_src.cxx

@@ -46,6 +46,7 @@ CLP(CgShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderConte
   _color_attrib_index = CA_color;
   _color_attrib_index = CA_color;
   _transform_table_param = 0;
   _transform_table_param = 0;
   _slider_table_param = 0;
   _slider_table_param = 0;
+  _frame_number = -1;
 
 
   nassertv(s->get_language() == Shader::SL_Cg);
   nassertv(s->get_language() == Shader::SL_Cg);
 
 
@@ -361,13 +362,8 @@ release_resources() {
 //               input parameters.
 //               input parameters.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CLP(CgShaderContext)::
 void CLP(CgShaderContext)::
-bind(bool reissue_parameters) {
+bind() {
   if (_cg_program != 0) {
   if (_cg_program != 0) {
-    if (reissue_parameters) {
-      // Pass in k-parameters and transform-parameters
-      issue_parameters(Shader::SSD_general);
-    }
-
     // Bind the shaders.
     // Bind the shaders.
     cgGLEnableProgramProfiles(_cg_program);
     cgGLEnableProgramProfiles(_cg_program);
     cgGLBindProgram(_cg_program);
     cgGLBindProgram(_cg_program);
@@ -397,6 +393,88 @@ unbind() {
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GLCgShaderContext::set_state_and_transform
+//       Access: Public
+//  Description: This function gets called whenever the RenderState
+//               or TransformState has changed, but the Shader
+//               itself has not changed.  It loads new values into the
+//               shader's parameters.
+////////////////////////////////////////////////////////////////////
+void CLP(CgShaderContext)::
+set_state_and_transform(const RenderState *target_rs,
+                        const TransformState *modelview_transform,
+                        const TransformState *projection_transform) {
+
+  if (!valid()) {
+    return;
+  }
+
+  // Find out which state properties have changed.
+  int altered = 0;
+
+  if (_modelview_transform != modelview_transform) {
+    _modelview_transform = modelview_transform;
+    altered |= Shader::SSD_transform;
+  }
+  if (_projection_transform != projection_transform) {
+    _projection_transform = projection_transform;
+    altered |= Shader::SSD_projection;
+  }
+
+  if (_state_rs != target_rs) {
+    if (_state_rs == NULL) {
+      // We haven't set any state yet.
+      altered |= Shader::SSD_general;
+    } else {
+      if (_state_rs->get_attrib(ColorAttrib::get_class_slot()) !=
+          target_rs->get_attrib(ColorAttrib::get_class_slot())) {
+        altered |= Shader::SSD_color;
+      }
+      if (_state_rs->get_attrib(ColorScaleAttrib::get_class_slot()) !=
+          target_rs->get_attrib(ColorScaleAttrib::get_class_slot())) {
+        altered |= Shader::SSD_colorscale;
+      }
+      if (_state_rs->get_attrib(MaterialAttrib::get_class_slot()) !=
+          target_rs->get_attrib(MaterialAttrib::get_class_slot())) {
+        altered |= Shader::SSD_material;
+      }
+      if (_state_rs->get_attrib(ShaderAttrib::get_class_slot()) !=
+          target_rs->get_attrib(ShaderAttrib::get_class_slot())) {
+        altered |= Shader::SSD_shaderinputs;
+      }
+      if (_state_rs->get_attrib(FogAttrib::get_class_slot()) !=
+          target_rs->get_attrib(FogAttrib::get_class_slot())) {
+        altered |= Shader::SSD_fog;
+      }
+      if (_state_rs->get_attrib(LightAttrib::get_class_slot()) !=
+          target_rs->get_attrib(LightAttrib::get_class_slot())) {
+        altered |= Shader::SSD_light;
+      }
+      if (_state_rs->get_attrib(ClipPlaneAttrib::get_class_slot()) !=
+          target_rs->get_attrib(ClipPlaneAttrib::get_class_slot())) {
+        altered |= Shader::SSD_clip_planes;
+      }
+      if (_state_rs->get_attrib(TexMatrixAttrib::get_class_slot()) !=
+          target_rs->get_attrib(TexMatrixAttrib::get_class_slot())) {
+        altered |= Shader::SSD_tex_matrix;
+      }
+    }
+    _state_rs = target_rs;
+  }
+
+  // Is this the first time this shader is used this frame?
+  int frame_number = ClockObject::get_global_clock()->get_frame_count();
+  if (frame_number != _frame_number) {
+     altered |= Shader::SSD_frame;
+    _frame_number = frame_number;
+  }
+
+  if (altered != 0) {
+    issue_parameters(altered);
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GLCgShaderContext::issue_parameters
 //     Function: GLCgShaderContext::issue_parameters
 //       Access: Public
 //       Access: Public
@@ -414,49 +492,48 @@ unbind() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CLP(CgShaderContext)::
 void CLP(CgShaderContext)::
 issue_parameters(int altered) {
 issue_parameters(int altered) {
-  //PStatGPUTimer timer(_glgsg, _glgsg->_draw_set_state_shader_parameters_pcollector);
+  PStatGPUTimer timer(_glgsg, _glgsg->_draw_set_state_shader_parameters_pcollector);
 
 
-  if (!valid()) {
-    return;
+  if (GLCAT.is_spam()) {
+    GLCAT.spam()
+      << "Setting uniforms for " << _shader->get_filename()
+      << " (altered 0x" << hex << altered << dec << ")\n";
   }
   }
 
 
-  // Iterate through _ptr parameters
-  for (int i=0; i<(int)_shader->_ptr_spec.size(); i++) {
-    if (altered & (_shader->_ptr_spec[i]._dep[0] | _shader->_ptr_spec[i]._dep[1])) {
-      const Shader::ShaderPtrSpec& _ptr = _shader->_ptr_spec[i];
-      Shader::ShaderPtrData* ptr_data =
-        const_cast< Shader::ShaderPtrData*>(_glgsg->fetch_ptr_parameter(_ptr));
+  // We have no way to track modifications to PTAs, so we assume that
+  // they are modified every frame and when we switch ShaderAttribs.
+  if (altered & (Shader::SSD_shaderinputs | Shader::SSD_frame)) {
+    // Iterate through _ptr parameters
+    for (int i = 0; i < (int)_shader->_ptr_spec.size(); ++i) {
+      Shader::ShaderPtrSpec &spec = _shader->_ptr_spec[i];
 
 
+      const Shader::ShaderPtrData *ptr_data =_glgsg->fetch_ptr_parameter(spec);
       if (ptr_data == NULL){ //the input is not contained in ShaderPtrData
       if (ptr_data == NULL){ //the input is not contained in ShaderPtrData
         release_resources();
         release_resources();
         return;
         return;
       }
       }
-      //check if the data must be shipped to the GPU
-      /*if (!ptr_data->_updated)
-        continue;
-        ptr_data->_updated = false;*/
 
 
       //Check if the size of the shader input and ptr_data match
       //Check if the size of the shader input and ptr_data match
-      int input_size = _ptr._dim[0] * _ptr._dim[1] * _ptr._dim[2];
+      int input_size = spec._dim[0] * spec._dim[1] * spec._dim[2];
 
 
       // dimension is negative only if the parameter had the (deprecated)k_ prefix.
       // dimension is negative only if the parameter had the (deprecated)k_ prefix.
-      if ((input_size > ptr_data->_size) && (_ptr._dim[0] > 0)) {
-        GLCAT.error() << _ptr._id._name << ": incorrect number of elements, expected "
+      if ((input_size > ptr_data->_size) && (spec._dim[0] > 0)) {
+        GLCAT.error() << spec._id._name << ": incorrect number of elements, expected "
                       <<  input_size <<" got " <<  ptr_data->_size << "\n";
                       <<  input_size <<" got " <<  ptr_data->_size << "\n";
         release_resources();
         release_resources();
         return;
         return;
       }
       }
-      CGparameter p = _cg_parameter_map[_ptr._id._seqno];
+      CGparameter p = _cg_parameter_map[spec._id._seqno];
 
 
       switch (ptr_data->_type) {
       switch (ptr_data->_type) {
       case Shader::SPT_float:
       case Shader::SPT_float:
-        switch(_ptr._info._class) {
+        switch (spec._info._class) {
         case Shader::SAC_scalar:
         case Shader::SAC_scalar:
           cgSetParameter1fv(p, (float*)ptr_data->_ptr);
           cgSetParameter1fv(p, (float*)ptr_data->_ptr);
           continue;
           continue;
 
 
         case Shader::SAC_vector:
         case Shader::SAC_vector:
-          switch (_ptr._info._type) {
+          switch (spec._info._type) {
           case Shader::SAT_vec1:
           case Shader::SAT_vec1:
             cgSetParameter1fv(p, (float*)ptr_data->_ptr);
             cgSetParameter1fv(p, (float*)ptr_data->_ptr);
             continue;
             continue;
@@ -479,22 +556,22 @@ issue_parameters(int altered) {
           continue;
           continue;
 
 
         case Shader::SAC_array:
         case Shader::SAC_array:
-          switch (_ptr._info._subclass) {
+          switch (spec._info._subclass) {
           case Shader::SAC_scalar:
           case Shader::SAC_scalar:
-            cgGLSetParameterArray1f(p, 0, _ptr._dim[0], (float*)ptr_data->_ptr);
+            cgGLSetParameterArray1f(p, 0, spec._dim[0], (float*)ptr_data->_ptr);
             continue;
             continue;
           case Shader::SAC_vector:
           case Shader::SAC_vector:
-            switch (_ptr._dim[2]) {
-            case 1: cgGLSetParameterArray1f(p, 0, _ptr._dim[0], (float*)ptr_data->_ptr); continue;
-            case 2: cgGLSetParameterArray2f(p, 0, _ptr._dim[0], (float*)ptr_data->_ptr); continue;
-            case 3: cgGLSetParameterArray3f(p, 0, _ptr._dim[0], (float*)ptr_data->_ptr); continue;
-            case 4: cgGLSetParameterArray4f(p, 0, _ptr._dim[0], (float*)ptr_data->_ptr); continue;
+            switch (spec._dim[2]) {
+            case 1: cgGLSetParameterArray1f(p, 0, spec._dim[0], (float*)ptr_data->_ptr); continue;
+            case 2: cgGLSetParameterArray2f(p, 0, spec._dim[0], (float*)ptr_data->_ptr); continue;
+            case 3: cgGLSetParameterArray3f(p, 0, spec._dim[0], (float*)ptr_data->_ptr); continue;
+            case 4: cgGLSetParameterArray4f(p, 0, spec._dim[0], (float*)ptr_data->_ptr); continue;
             default:
             default:
-              nassertd(_ptr._dim[2] > 0 && _ptr._dim[2] <= 4) continue;
+              nassertd(spec._dim[2] > 0 && spec._dim[2] <= 4) continue;
             }
             }
             continue;
             continue;
           case Shader::SAC_matrix:
           case Shader::SAC_matrix:
-            cgGLSetMatrixParameterArrayfc(p, 0, _ptr._dim[0], (float*)ptr_data->_ptr);
+            cgGLSetMatrixParameterArrayfc(p, 0, spec._dim[0], (float*)ptr_data->_ptr);
             continue;
             continue;
           default:
           default:
             nassertd(false) continue;
             nassertd(false) continue;
@@ -504,13 +581,13 @@ issue_parameters(int altered) {
         }
         }
 
 
       case Shader::SPT_double:
       case Shader::SPT_double:
-        switch(_ptr._info._class) {
+        switch (spec._info._class) {
         case Shader::SAC_scalar:
         case Shader::SAC_scalar:
           cgSetParameter1dv(p, (double*)ptr_data->_ptr);
           cgSetParameter1dv(p, (double*)ptr_data->_ptr);
           continue;
           continue;
 
 
         case Shader::SAC_vector:
         case Shader::SAC_vector:
-          switch (_ptr._info._type) {
+          switch (spec._info._type) {
           case Shader::SAT_vec1:
           case Shader::SAT_vec1:
             cgSetParameter1dv(p, (double*)ptr_data->_ptr);
             cgSetParameter1dv(p, (double*)ptr_data->_ptr);
             continue;
             continue;
@@ -533,22 +610,22 @@ issue_parameters(int altered) {
           continue;
           continue;
 
 
         case Shader::SAC_array:
         case Shader::SAC_array:
-          switch (_ptr._info._subclass) {
+          switch (spec._info._subclass) {
           case Shader::SAC_scalar:
           case Shader::SAC_scalar:
-            cgGLSetParameterArray1d(p, 0, _ptr._dim[0], (double*)ptr_data->_ptr);
+            cgGLSetParameterArray1d(p, 0, spec._dim[0], (double*)ptr_data->_ptr);
             continue;
             continue;
           case Shader::SAC_vector:
           case Shader::SAC_vector:
-            switch (_ptr._dim[2]) {
-            case 1: cgGLSetParameterArray1d(p, 0, _ptr._dim[0], (double*)ptr_data->_ptr); continue;
-            case 2: cgGLSetParameterArray2d(p, 0, _ptr._dim[0], (double*)ptr_data->_ptr); continue;
-            case 3: cgGLSetParameterArray3d(p, 0, _ptr._dim[0], (double*)ptr_data->_ptr); continue;
-            case 4: cgGLSetParameterArray4d(p, 0, _ptr._dim[0], (double*)ptr_data->_ptr); continue;
+            switch (spec._dim[2]) {
+            case 1: cgGLSetParameterArray1d(p, 0, spec._dim[0], (double*)ptr_data->_ptr); continue;
+            case 2: cgGLSetParameterArray2d(p, 0, spec._dim[0], (double*)ptr_data->_ptr); continue;
+            case 3: cgGLSetParameterArray3d(p, 0, spec._dim[0], (double*)ptr_data->_ptr); continue;
+            case 4: cgGLSetParameterArray4d(p, 0, spec._dim[0], (double*)ptr_data->_ptr); continue;
             default:
             default:
-              nassertd(_ptr._dim[2] > 0 && _ptr._dim[2] <= 4) continue;
+              nassertd(spec._dim[2] > 0 && spec._dim[2] <= 4) continue;
             }
             }
             continue;
             continue;
           case Shader::SAC_matrix:
           case Shader::SAC_matrix:
-            cgGLSetMatrixParameterArraydc(p, 0, _ptr._dim[0], (double*)ptr_data->_ptr);
+            cgGLSetMatrixParameterArraydc(p, 0, spec._dim[0], (double*)ptr_data->_ptr);
             continue;
             continue;
           default:
           default:
             nassertd(false) continue;
             nassertd(false) continue;
@@ -559,12 +636,12 @@ issue_parameters(int altered) {
         continue;
         continue;
 
 
       case Shader::SPT_int:
       case Shader::SPT_int:
-        switch(_ptr._info._class) {
+        switch (spec._info._class) {
         case Shader::SAC_scalar:
         case Shader::SAC_scalar:
           cgSetParameter1iv(p, (int*)ptr_data->_ptr);
           cgSetParameter1iv(p, (int*)ptr_data->_ptr);
           continue;
           continue;
         case Shader::SAC_vector:
         case Shader::SAC_vector:
-          switch(_ptr._info._type) {
+          switch (spec._info._type) {
           case Shader::SAT_vec1: cgSetParameter1iv(p, (int*)ptr_data->_ptr); continue;
           case Shader::SAT_vec1: cgSetParameter1iv(p, (int*)ptr_data->_ptr); continue;
           case Shader::SAT_vec2: cgSetParameter2iv(p, (int*)ptr_data->_ptr); continue;
           case Shader::SAT_vec2: cgSetParameter2iv(p, (int*)ptr_data->_ptr); continue;
           case Shader::SAT_vec3: cgSetParameter3iv(p, (int*)ptr_data->_ptr); continue;
           case Shader::SAT_vec3: cgSetParameter3iv(p, (int*)ptr_data->_ptr); continue;
@@ -576,21 +653,27 @@ issue_parameters(int altered) {
           nassertd(false) continue;
           nassertd(false) continue;
         }
         }
       default:
       default:
-        GLCAT.error() << _ptr._id._name << ":" << "unrecognized parameter type\n";
+        GLCAT.error() << spec._id._name << ":" << "unrecognized parameter type\n";
         release_resources();
         release_resources();
         return;
         return;
       }
       }
     }
     }
   }
   }
 
 
-  for (int i=0; i<(int)_shader->_mat_spec.size(); i++) {
-    if (altered & (_shader->_mat_spec[i]._dep[0] | _shader->_mat_spec[i]._dep[1])) {
-      const LMatrix4 *val = _glgsg->fetch_specified_value(_shader->_mat_spec[i], altered);
+  if (altered & _shader->_mat_deps) {
+    for (int i = 0; i < (int)_shader->_mat_spec.size(); ++i) {
+      Shader::ShaderMatSpec &spec = _shader->_mat_spec[i];
+
+      if ((altered & (spec._dep[0] | spec._dep[1])) == 0) {
+        continue;
+      }
+
+      const LMatrix4 *val = _glgsg->fetch_specified_value(spec, 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[_shader->_mat_spec[i]._id._seqno];
-      switch (_shader->_mat_spec[i]._piece) {
+      CGparameter p = _cg_parameter_map[spec._id._seqno];
+      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;
       case Shader::SMP_col0: GLf(cgGLSetParameter4)(p, data[0], data[4], data[ 8], data[12]); continue;
       case Shader::SMP_col0: GLf(cgGLSetParameter4)(p, data[0], data[4], data[ 8], data[12]); continue;
@@ -981,9 +1064,9 @@ disable_shader_texture_bindings() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CLP(CgShaderContext)::
 void CLP(CgShaderContext)::
 update_shader_texture_bindings(ShaderContext *prev) {
 update_shader_texture_bindings(ShaderContext *prev) {
-  if (prev) {
-    prev->disable_shader_texture_bindings();
-  }
+  //if (prev) {
+  //  prev->disable_shader_texture_bindings();
+  //}
 
 
   if (!valid()) {
   if (!valid()) {
     return;
     return;

+ 17 - 8
panda/src/glstuff/glCgShaderContext_src.h

@@ -38,19 +38,23 @@ public:
   ALLOC_DELETED_CHAIN(CLP(CgShaderContext));
   ALLOC_DELETED_CHAIN(CLP(CgShaderContext));
 
 
   INLINE bool valid(void);
   INLINE bool valid(void);
-  void bind(bool reissue_parameters = true);
-  void unbind();
-  void issue_parameters(int altered);
+  void bind() OVERRIDE;
+  void unbind() OVERRIDE;
+
+  void set_state_and_transform(const RenderState *state,
+                               const TransformState *modelview_transform,
+                               const TransformState *projection_transform);
+
+  void issue_parameters(int altered) OVERRIDE;
   void update_transform_table(const TransformTable *table);
   void update_transform_table(const TransformTable *table);
   void update_slider_table(const SliderTable *table);
   void update_slider_table(const SliderTable *table);
-  void disable_shader_vertex_arrays();
-  bool update_shader_vertex_arrays(ShaderContext *prev, bool force);
-  void disable_shader_texture_bindings();
-  void update_shader_texture_bindings(ShaderContext *prev);
+  void disable_shader_vertex_arrays() OVERRIDE;
+  bool update_shader_vertex_arrays(ShaderContext *prev, bool force) OVERRIDE;
+  void disable_shader_texture_bindings() OVERRIDE;
+  void update_shader_texture_bindings(ShaderContext *prev) OVERRIDE;
 
 
   INLINE bool uses_standard_vertex_arrays(void);
   INLINE bool uses_standard_vertex_arrays(void);
   INLINE bool uses_custom_vertex_arrays(void);
   INLINE bool uses_custom_vertex_arrays(void);
-  INLINE bool uses_custom_texture_bindings(void);
 
 
   // Special values for location to indicate conventional attrib slots.
   // Special values for location to indicate conventional attrib slots.
   enum ConventionalAttrib {
   enum ConventionalAttrib {
@@ -74,6 +78,11 @@ private:
 
 
   pvector<CGparameter> _cg_parameter_map;
   pvector<CGparameter> _cg_parameter_map;
 
 
+  CPT(RenderState) _state_rs;
+  CPT(TransformState) _modelview_transform;
+  CPT(TransformState) _projection_transform;
+  GLint _frame_number;
+
   CLP(GraphicsStateGuardian) *_glgsg;
   CLP(GraphicsStateGuardian) *_glgsg;
 
 
   bool _has_divisor;
   bool _has_divisor;

+ 1 - 1
panda/src/glstuff/glGraphicsBuffer_src.cxx

@@ -307,7 +307,7 @@ rebuild_bitplanes() {
       RenderTexturePlane plane = rt._plane;
       RenderTexturePlane plane = rt._plane;
       Texture *tex = rt._texture;
       Texture *tex = rt._texture;
 
 
-      if (rtm_mode == RTM_bind_layered) {
+      if (rtm_mode == RTM_bind_layered && glgsg->_supports_geometry_shaders) {
         if (tex->get_z_size() != _rb_size_z) {
         if (tex->get_z_size() != _rb_size_z) {
           GLCAT.warning()
           GLCAT.warning()
            << "All textures attached to layered FBO should have the same layer count!\n";
            << "All textures attached to layered FBO should have the same layer count!\n";

+ 99 - 71
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -1527,11 +1527,15 @@ reset() {
   _glVertexAttribLPointer = NULL;
   _glVertexAttribLPointer = NULL;
 #endif
 #endif
 
 
-#ifndef OPENGLES_1
   // We need to have a default shader to apply in case
   // We need to have a default shader to apply in case
   // something didn't happen to have a shader applied, or
   // something didn't happen to have a shader applied, or
   // if it failed to compile. This default shader just outputs
   // if it failed to compile. This default shader just outputs
   // a red color, indicating that something went wrong.
   // a red color, indicating that something went wrong.
+#ifndef SUPPORT_FIXED_FUNCTION
+  if (_default_shader == NULL) {
+    _default_shader = Shader::make(Shader::SL_GLSL, default_vshader, default_fshader);
+  }
+#elif !defined(OPENGLES)
   if (_default_shader == NULL && core_profile) {
   if (_default_shader == NULL && core_profile) {
     _default_shader = Shader::make(Shader::SL_GLSL, default_vshader, default_fshader);
     _default_shader = Shader::make(Shader::SL_GLSL, default_vshader, default_fshader);
   }
   }
@@ -2926,6 +2930,11 @@ clear_before_callback() {
 #ifndef OPENGLES
 #ifndef OPENGLES
   if (_supports_sampler_objects) {
   if (_supports_sampler_objects) {
     _glBindSampler(0, 0);
     _glBindSampler(0, 0);
+
+    if (GLCAT.is_spam()) {
+      GLCAT.spam()
+        << "glBindSampler(0, 0)\n";
+    }
   }
   }
 #endif
 #endif
 }
 }
@@ -5548,6 +5557,11 @@ framebuffer_copy_to_texture(Texture *tex, int view, int z,
   if (new_image && gtc->_immutable) {
   if (new_image && gtc->_immutable) {
     gtc->reset_data();
     gtc->reset_data();
     glBindTexture(target, gtc->_index);
     glBindTexture(target, gtc->_index);
+
+    if (GLCAT.is_spam()) {
+      GLCAT.spam()
+        << "glBindTexture(0x" << hex << target << dec << ", " << gtc->_index << ")\n";
+    }
   }
   }
 
 
 #ifndef OPENGLES
 #ifndef OPENGLES
@@ -5844,12 +5858,6 @@ do_issue_transform() {
 #endif
 #endif
   _transform_stale = false;
   _transform_stale = false;
 
 
-#ifndef OPENGLES_1
-  if (_current_shader_context) {
-    _current_shader_context->issue_parameters(Shader::SSD_transform);
-  }
-#endif
-
   report_my_gl_errors();
   report_my_gl_errors();
 }
 }
 
 
@@ -5885,9 +5893,9 @@ do_issue_shade_model() {
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsStateGuardian)::
 void CLP(GraphicsStateGuardian)::
-do_issue_shader(bool state_has_changed) {
+do_issue_shader() {
   ShaderContext *context = 0;
   ShaderContext *context = 0;
-  Shader *shader = (Shader *)(_target_shader->get_shader());
+  Shader *shader = (Shader *)_target_shader->get_shader();
 
 
 #ifndef SUPPORT_FIXED_FUNCTION
 #ifndef SUPPORT_FIXED_FUNCTION
   // If we don't have a shader, apply the default shader.
   // If we don't have a shader, apply the default shader.
@@ -5919,18 +5927,13 @@ do_issue_shader(bool state_has_changed) {
     if (context != _current_shader_context) {
     if (context != _current_shader_context) {
       // Use a completely different shader than before.
       // Use a completely different shader than before.
       // Unbind old shader, bind the new one.
       // Unbind old shader, bind the new one.
-      if (_current_shader_context != 0) {
+      if (_current_shader_context != NULL &&
+          _current_shader->get_language() != shader->get_language()) {
         _current_shader_context->unbind();
         _current_shader_context->unbind();
       }
       }
       context->bind();
       context->bind();
       _current_shader = shader;
       _current_shader = shader;
       _current_shader_context = context;
       _current_shader_context = context;
-      context->issue_parameters(Shader::SSD_shaderinputs);
-    } else {
-      if (state_has_changed) {
-        // Use the same shader as before, but with new input arguments.
-        context->issue_parameters(Shader::SSD_shaderinputs);
-      }
     }
     }
   }
   }
 
 
@@ -6410,6 +6413,11 @@ do_issue_blending() {
       _glBlendEquation(GL_FUNC_ADD);
       _glBlendEquation(GL_FUNC_ADD);
       glBlendFunc(GL_ZERO, GL_ONE);
       glBlendFunc(GL_ZERO, GL_ONE);
     }
     }
+
+    if (GLCAT.is_spam()) {
+      GLCAT.spam() << "glBlendEquation(GL_FUNC_ADD)\n";
+      GLCAT.spam() << "glBlendFunc(GL_ZERO, GL_ONE)\n";
+    }
     return;
     return;
   } else {
   } else {
     set_color_write_mask(color_channels);
     set_color_write_mask(color_channels);
@@ -6433,16 +6441,23 @@ do_issue_blending() {
     enable_blend(true);
     enable_blend(true);
     _glBlendEquation(get_blend_equation_type(color_blend_mode));
     _glBlendEquation(get_blend_equation_type(color_blend_mode));
     glBlendFunc(get_blend_func(color_blend->get_operand_a()),
     glBlendFunc(get_blend_func(color_blend->get_operand_a()),
-                   get_blend_func(color_blend->get_operand_b()));
+                get_blend_func(color_blend->get_operand_b()));
 
 
+    LColor c;
     if (_color_blend_involves_color_scale) {
     if (_color_blend_involves_color_scale) {
       // Apply the current color scale to the blend mode.
       // Apply the current color scale to the blend mode.
-      _glBlendColor(_current_color_scale[0], _current_color_scale[1],
-                    _current_color_scale[2], _current_color_scale[3]);
-
+      c = _current_color_scale;
     } else {
     } else {
-      LColor c = color_blend->get_color();
-      _glBlendColor(c[0], c[1], c[2], c[3]);
+      c = color_blend->get_color();
+    }
+
+    _glBlendColor(c[0], c[1], c[2], c[3]);
+
+    if (GLCAT.is_spam()) {
+      GLCAT.spam() << "glBlendEquation(" << color_blend_mode << ")\n";
+      GLCAT.spam() << "glBlendFunc(" << color_blend->get_operand_a()
+                                     << color_blend->get_operand_b() << ")\n";
+      GLCAT.spam() << "glBlendColor(" << c << ")\n";
     }
     }
     return;
     return;
   }
   }
@@ -6460,6 +6475,11 @@ do_issue_blending() {
     enable_blend(true);
     enable_blend(true);
     _glBlendEquation(GL_FUNC_ADD);
     _glBlendEquation(GL_FUNC_ADD);
     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+    if (GLCAT.is_spam()) {
+      GLCAT.spam() << "glBlendEquation(GL_FUNC_ADD)\n";
+      GLCAT.spam() << "glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)\n";
+    }
     return;
     return;
 
 
   case TransparencyAttrib::M_multisample:
   case TransparencyAttrib::M_multisample:
@@ -6489,6 +6509,11 @@ do_issue_blending() {
     enable_blend(true);
     enable_blend(true);
     _glBlendEquation(GL_FUNC_ADD);
     _glBlendEquation(GL_FUNC_ADD);
     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+    if (GLCAT.is_spam()) {
+      GLCAT.spam() << "glBlendEquation(GL_FUNC_ADD)\n";
+      GLCAT.spam() << "glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)\n";
+    }
     return;
     return;
   }
   }
 
 
@@ -9224,10 +9249,27 @@ set_state_and_transform(const RenderState *target,
   }
   }
   _target_rs = target;
   _target_rs = target;
 
 
+#ifndef OPENGLES_1
   _target_shader = (const ShaderAttrib *)
   _target_shader = (const ShaderAttrib *)
     _target_rs->get_attrib_def(ShaderAttrib::get_class_slot());
     _target_rs->get_attrib_def(ShaderAttrib::get_class_slot());
-#ifndef OPENGLES_1
   _instance_count = _target_shader->get_instance_count();
   _instance_count = _target_shader->get_instance_count();
+
+  if (_target_shader != _state_shader) {
+    //PStatGPUTimer timer(this, _draw_set_state_shader_pcollector);
+    do_issue_shader();
+    _state_shader = _target_shader;
+    _state_mask.clear_bit(TextureAttrib::get_class_slot());
+  }
+#ifndef SUPPORT_FIXED_FUNCTION
+  else { // In the case of OpenGL ES 2.x, we need to glUseShader before we draw anything.
+    do_issue_shader();
+    _state_mask.clear_bit(TextureAttrib::get_class_slot());
+  }
+#endif
+
+  if (_current_shader_context != NULL) {
+    _current_shader_context->set_state_and_transform(target, transform, _projection_mat);
+  }
 #endif
 #endif
 
 
 #ifdef SUPPORT_FIXED_FUNCTION
 #ifdef SUPPORT_FIXED_FUNCTION
@@ -9256,11 +9298,6 @@ set_state_and_transform(const RenderState *target,
     //PStatGPUTimer timer(this, _draw_set_state_clip_plane_pcollector);
     //PStatGPUTimer timer(this, _draw_set_state_clip_plane_pcollector);
     do_issue_clip_plane();
     do_issue_clip_plane();
     _state_mask.set_bit(clip_plane_slot);
     _state_mask.set_bit(clip_plane_slot);
-#ifndef OPENGLES_1
-    if (_current_shader_context) {
-      _current_shader_context->issue_parameters(Shader::SSD_clip_planes);
-    }
-#endif
   }
   }
 
 
   int color_slot = ColorAttrib::get_class_slot();
   int color_slot = ColorAttrib::get_class_slot();
@@ -9274,12 +9311,6 @@ set_state_and_transform(const RenderState *target,
     do_issue_color_scale();
     do_issue_color_scale();
     _state_mask.set_bit(color_slot);
     _state_mask.set_bit(color_slot);
     _state_mask.set_bit(color_scale_slot);
     _state_mask.set_bit(color_scale_slot);
-#ifndef OPENGLES_1
-    if (_current_shader_context) {
-      _current_shader_context->issue_parameters(Shader::SSD_color);
-      _current_shader_context->issue_parameters(Shader::SSD_colorscale);
-    }
-#endif
   }
   }
 
 
   int cull_face_slot = CullFaceAttrib::get_class_slot();
   int cull_face_slot = CullFaceAttrib::get_class_slot();
@@ -9360,20 +9391,6 @@ set_state_and_transform(const RenderState *target,
     _state_mask.set_bit(color_blend_slot);
     _state_mask.set_bit(color_blend_slot);
   }
   }
 
 
-  if (_target_shader != _state_shader) {
-    //PStatGPUTimer timer(this, _draw_set_state_shader_pcollector);
-#ifndef OPENGLES_1
-    do_issue_shader(true);
-#endif
-    _state_shader = _target_shader;
-    _state_mask.clear_bit(TextureAttrib::get_class_slot());
-  }
-#ifndef SUPPORT_FIXED_FUNCTION
-  else { // In the case of OpenGL ES 2.x, we need to glUseShader before we draw anything.
-    do_issue_shader(false);
-  }
-#endif
-
   int texture_slot = TextureAttrib::get_class_slot();
   int texture_slot = TextureAttrib::get_class_slot();
   if (_target_rs->get_attrib(texture_slot) != _state_rs->get_attrib(texture_slot) ||
   if (_target_rs->get_attrib(texture_slot) != _state_rs->get_attrib(texture_slot) ||
       !_state_mask.get_bit(texture_slot)) {
       !_state_mask.get_bit(texture_slot)) {
@@ -9441,11 +9458,6 @@ set_state_and_transform(const RenderState *target,
     do_issue_material();
     do_issue_material();
 #endif
 #endif
     _state_mask.set_bit(material_slot);
     _state_mask.set_bit(material_slot);
-#ifndef OPENGLES_1
-    if (_current_shader_context) {
-      _current_shader_context->issue_parameters(Shader::SSD_material);
-    }
-#endif
   }
   }
 
 
   int light_slot = LightAttrib::get_class_slot();
   int light_slot = LightAttrib::get_class_slot();
@@ -9456,11 +9468,6 @@ set_state_and_transform(const RenderState *target,
     do_issue_light();
     do_issue_light();
 #endif
 #endif
     _state_mask.set_bit(light_slot);
     _state_mask.set_bit(light_slot);
-#ifndef OPENGLES_1
-    if (_current_shader_context) {
-      _current_shader_context->issue_parameters(Shader::SSD_light);
-    }
-#endif
   }
   }
 
 
   int stencil_slot = StencilAttrib::get_class_slot();
   int stencil_slot = StencilAttrib::get_class_slot();
@@ -9479,11 +9486,6 @@ set_state_and_transform(const RenderState *target,
     do_issue_fog();
     do_issue_fog();
 #endif
 #endif
     _state_mask.set_bit(fog_slot);
     _state_mask.set_bit(fog_slot);
-#ifndef OPENGLES_1
-    if (_current_shader_context) {
-      _current_shader_context->issue_parameters(Shader::SSD_fog);
-    }
-#endif
   }
   }
 
 
   int scissor_slot = ScissorAttrib::get_class_slot();
   int scissor_slot = ScissorAttrib::get_class_slot();
@@ -9528,7 +9530,7 @@ do_issue_texture() {
 #ifdef OPENGLES_1
 #ifdef OPENGLES_1
   update_standard_texture_bindings();
   update_standard_texture_bindings();
 #else
 #else
-  if (_current_shader_context == 0 || !_current_shader_context->uses_custom_texture_bindings()) {
+  if (_current_shader_context == 0) {
     // No shader, or a non-Cg shader.
     // No shader, or a non-Cg shader.
     if (_texture_binding_shader_context != 0) {
     if (_texture_binding_shader_context != 0) {
       _texture_binding_shader_context->disable_shader_texture_bindings();
       _texture_binding_shader_context->disable_shader_texture_bindings();
@@ -9909,9 +9911,9 @@ update_show_usage_texture_bindings(int show_stage_index) {
 
 
     UsageTextureKey key(texture->get_x_size(), texture->get_y_size());
     UsageTextureKey key(texture->get_x_size(), texture->get_y_size());
     UsageTextures::iterator ui = _usage_textures.find(key);
     UsageTextures::iterator ui = _usage_textures.find(key);
+    GLuint index;
     if (ui == _usage_textures.end()) {
     if (ui == _usage_textures.end()) {
       // Need to create a new texture for this size.
       // Need to create a new texture for this size.
-      GLuint index;
       glGenTextures(1, &index);
       glGenTextures(1, &index);
       glBindTexture(GL_TEXTURE_2D, index);
       glBindTexture(GL_TEXTURE_2D, index);
       //TODO: this could be a lot simpler with glTexStorage2D
       //TODO: this could be a lot simpler with glTexStorage2D
@@ -9921,10 +9923,15 @@ update_show_usage_texture_bindings(int show_stage_index) {
 
 
     } else {
     } else {
       // Just bind the previously-created texture.
       // Just bind the previously-created texture.
-      GLuint index = (*ui).second;
+      index = (*ui).second;
       glBindTexture(GL_TEXTURE_2D, index);
       glBindTexture(GL_TEXTURE_2D, index);
     }
     }
 
 
+    if (GLCAT.is_spam()) {
+      GLCAT.spam()
+        << "glBindTexture(GL_TEXTURE_2D, " << index << ")\n";
+    }
+
     //TODO: glBindSampler(0) ?
     //TODO: glBindSampler(0) ?
   }
   }
 
 
@@ -10468,9 +10475,14 @@ specify_texture(CLP(TextureContext) *gtc, const SamplerState &sampler) {
 #endif
 #endif
 
 
 #ifndef OPENGLES
 #ifndef OPENGLES
-  glTexParameterf(target, GL_TEXTURE_MIN_LOD, sampler.get_min_lod());
-  glTexParameterf(target, GL_TEXTURE_MAX_LOD, sampler.get_max_lod());
-  glTexParameterf(target, GL_TEXTURE_LOD_BIAS, sampler.get_lod_bias());
+  if (is_at_least_gl_version(1, 2)) {
+    glTexParameterf(target, GL_TEXTURE_MIN_LOD, sampler.get_min_lod());
+    glTexParameterf(target, GL_TEXTURE_MAX_LOD, sampler.get_max_lod());
+
+    if (is_at_least_gl_version(1, 4)) {
+      glTexParameterf(target, GL_TEXTURE_LOD_BIAS, sampler.get_lod_bias());
+    }
+  }
 #endif
 #endif
 
 
   report_my_gl_errors();
   report_my_gl_errors();
@@ -10505,7 +10517,12 @@ apply_texture(CLP(TextureContext) *gtc) {
     gtc->reset_data();
     gtc->reset_data();
     gtc->_target = target;
     gtc->_target = target;
   }
   }
+
   glBindTexture(target, gtc->_index);
   glBindTexture(target, gtc->_index);
+  if (GLCAT.is_spam()) {
+    GLCAT.spam()
+      << "glBindTexture(0x" << hex << target << dec << ", " << gtc->_index << ")\n";
+  }
 
 
   report_my_gl_errors();
   report_my_gl_errors();
   return true;
   return true;
@@ -10537,8 +10554,8 @@ apply_sampler(GLuint unit, const SamplerState &sampler, CLP(TextureContext) *gtc
     _glBindSampler(unit, gsc->_index);
     _glBindSampler(unit, gsc->_index);
 
 
     if (GLCAT.is_spam()) {
     if (GLCAT.is_spam()) {
-      GLCAT.spam()
-        << "bind " << unit << " " << sampler << "\n";
+      GLCAT.spam() << "glBindSampler(" << unit << ", "
+                   << gsc->_index << "): " << sampler << "\n";
     }
     }
 
 
   } else
   } else
@@ -10791,6 +10808,11 @@ upload_texture(CLP(TextureContext) *gtc, bool force, bool uses_mipmaps) {
     GLCAT.warning() << "Attempt to modify texture with immutable storage, recreating texture.\n";
     GLCAT.warning() << "Attempt to modify texture with immutable storage, recreating texture.\n";
     gtc->reset_data();
     gtc->reset_data();
     glBindTexture(target, gtc->_index);
     glBindTexture(target, gtc->_index);
+
+    if (GLCAT.is_spam()) {
+      GLCAT.spam()
+        << "glBindTexture(0x" << hex << target << dec << ", " << gtc->_index << ")\n";
+    }
   }
   }
 
 
 #ifndef OPENGLES
 #ifndef OPENGLES
@@ -11045,6 +11067,8 @@ upload_texture(CLP(TextureContext) *gtc, bool force, bool uses_mipmaps) {
       gtc->update_data_size_bytes(get_texture_memory_size(tex));
       gtc->update_data_size_bytes(get_texture_memory_size(tex));
     }
     }
 
 
+    nassertr(gtc->_has_storage, false);
+
     if (tex->get_post_load_store_cache()) {
     if (tex->get_post_load_store_cache()) {
       tex->set_post_load_store_cache(false);
       tex->set_post_load_store_cache(false);
       // OK, get the RAM image, and save it in a BamCache record.
       // OK, get the RAM image, and save it in a BamCache record.
@@ -11752,6 +11776,10 @@ do_extract_texture_data(CLP(TextureContext) *gtc) {
 #endif
 #endif
 
 
   glBindTexture(target, gtc->_index);
   glBindTexture(target, gtc->_index);
+  if (GLCAT.is_spam()) {
+    GLCAT.spam()
+      << "glBindTexture(0x" << hex << target << dec << ", " << gtc->_index << ")\n";
+  }
 
 
   Texture *tex = gtc->get_texture();
   Texture *tex = gtc->get_texture();
 
 

+ 3 - 1
panda/src/glstuff/glGraphicsStateGuardian_src.h

@@ -399,7 +399,7 @@ protected:
   void do_issue_depth_offset();
   void do_issue_depth_offset();
   void do_issue_shade_model();
   void do_issue_shade_model();
 #ifndef OPENGLES_1
 #ifndef OPENGLES_1
-  void do_issue_shader(bool state_has_changed = false);
+  void do_issue_shader();
 #endif
 #endif
 #ifdef SUPPORT_FIXED_FUNCTION
 #ifdef SUPPORT_FIXED_FUNCTION
   void do_issue_material();
   void do_issue_material();
@@ -462,8 +462,10 @@ protected:
   INLINE void enable_stencil_test(bool val);
   INLINE void enable_stencil_test(bool val);
   INLINE void enable_blend(bool val);
   INLINE void enable_blend(bool val);
   INLINE void enable_depth_test(bool val);
   INLINE void enable_depth_test(bool val);
+#ifdef SUPPORT_FIXED_FUNCTION
   INLINE void enable_fog(bool val);
   INLINE void enable_fog(bool val);
   INLINE void enable_alpha_test(bool val);
   INLINE void enable_alpha_test(bool val);
+#endif
   INLINE void enable_polygon_offset(bool val);
   INLINE void enable_polygon_offset(bool val);
 
 
   INLINE void set_color_write_mask(int mask);
   INLINE void set_color_write_mask(int mask);

+ 0 - 10
panda/src/glstuff/glShaderContext_src.I

@@ -55,13 +55,3 @@ INLINE bool CLP(ShaderContext)::
 uses_custom_vertex_arrays() {
 uses_custom_vertex_arrays() {
   return true;
   return true;
 }
 }
-
-////////////////////////////////////////////////////////////////////
-//     Function: GLShaderContext::uses_custom_texture_bindings
-//       Access: Public
-//  Description: Always true, for now.
-////////////////////////////////////////////////////////////////////
-INLINE bool CLP(ShaderContext)::
-uses_custom_texture_bindings() {
-  return true;
-}

+ 175 - 72
panda/src/glstuff/glShaderContext_src.cxx

@@ -18,17 +18,15 @@
 
 
 #include "pStatGPUTimer.h"
 #include "pStatGPUTimer.h"
 
 
-TypeHandle CLP(ShaderContext)::_type_handle;
+#include "colorAttrib.h"
+#include "colorScaleAttrib.h"
+#include "materialAttrib.h"
+#include "shaderAttrib.h"
+#include "fogAttrib.h"
+#include "lightAttrib.h"
+#include "clipPlaneAttrib.h"
 
 
-#ifndef GL_GEOMETRY_SHADER_EXT
-#define GL_GEOMETRY_SHADER_EXT 0x8DD9
-#endif
-#ifndef GL_GEOMETRY_VERTICES_OUT_EXT
-#define GL_GEOMETRY_VERTICES_OUT_EXT 0x8DDA
-#endif
-#ifndef GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT
-#define GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT 0x8DE0
-#endif
+TypeHandle CLP(ShaderContext)::_type_handle;
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GLShaderContext::ParseAndSetShaderUniformVars
 //     Function: GLShaderContext::ParseAndSetShaderUniformVars
@@ -228,6 +226,7 @@ parse_and_set_short_hand_shader_vars(Shader::ShaderArgId &arg_id, GLenum param_t
 
 
     objShader->cp_optimize_mat_spec(bind);
     objShader->cp_optimize_mat_spec(bind);
     objShader->_mat_spec.push_back(bind);
     objShader->_mat_spec.push_back(bind);
+    objShader->_mat_deps |= bind._dep[0] | bind._dep[1];
 
 
     if (param_size > 1) {
     if (param_size > 1) {
       // We support arrays of rows and arrays of columns, so we can
       // We support arrays of rows and arrays of columns, so we can
@@ -338,8 +337,14 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
     reflect_attribute(i, name_buffer, name_buflen);
     reflect_attribute(i, name_buffer, name_buflen);
   }
   }
 
 
-  _glgsg->_glUseProgram(0);
   _glgsg->report_my_gl_errors();
   _glgsg->report_my_gl_errors();
+
+  // Restore the active shader.
+  if (_glgsg->_current_shader_context == NULL) {
+    _glgsg->_glUseProgram(0);
+  } else {
+    _glgsg->_current_shader_context->bind();
+  }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -715,8 +720,6 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
       }
       }
       bind._arg[0] = NULL;
       bind._arg[0] = NULL;
       bind._arg[1] = NULL;
       bind._arg[1] = NULL;
-      bind._dep[0] = Shader::SSD_general | Shader::SSD_transform;
-      bind._dep[1] = Shader::SSD_general | Shader::SSD_transform;
 
 
       if (matrix_name == "ModelViewProjectionMatrix") {
       if (matrix_name == "ModelViewProjectionMatrix") {
         if (inverse) {
         if (inverse) {
@@ -802,7 +805,9 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
         GLCAT.error() << "Unrecognized uniform matrix name '" << matrix_name << "'!\n";
         GLCAT.error() << "Unrecognized uniform matrix name '" << matrix_name << "'!\n";
         return;
         return;
       }
       }
+      _shader->cp_optimize_mat_spec(bind);
       _shader->_mat_spec.push_back(bind);
       _shader->_mat_spec.push_back(bind);
+      _shader->_mat_deps |= bind._dep[0] | bind._dep[1];
       return;
       return;
     }
     }
     if (size > 7 && noprefix.substr(0, 7) == "Texture") {
     if (size > 7 && noprefix.substr(0, 7) == "Texture") {
@@ -846,6 +851,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
         }
         }
         bind._piece = Shader::SMP_row0;
         bind._piece = Shader::SMP_row0;
         _shader->_mat_spec.push_back(bind);
         _shader->_mat_spec.push_back(bind);
+        _shader->_mat_deps |= bind._dep[0];
         return;
         return;
 
 
       } else if (noprefix == "Material.diffuse") {
       } else if (noprefix == "Material.diffuse") {
@@ -855,6 +861,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
         }
         }
         bind._piece = Shader::SMP_row1;
         bind._piece = Shader::SMP_row1;
         _shader->_mat_spec.push_back(bind);
         _shader->_mat_spec.push_back(bind);
+        _shader->_mat_deps |= bind._dep[0];
         return;
         return;
 
 
       } else if (noprefix == "Material.emission") {
       } else if (noprefix == "Material.emission") {
@@ -864,6 +871,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
         }
         }
         bind._piece = Shader::SMP_row2;
         bind._piece = Shader::SMP_row2;
         _shader->_mat_spec.push_back(bind);
         _shader->_mat_spec.push_back(bind);
+        _shader->_mat_deps |= bind._dep[0];
         return;
         return;
 
 
       } else if (noprefix == "Material.specular") {
       } else if (noprefix == "Material.specular") {
@@ -873,6 +881,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
         }
         }
         bind._piece = Shader::SMP_row3x3;
         bind._piece = Shader::SMP_row3x3;
         _shader->_mat_spec.push_back(bind);
         _shader->_mat_spec.push_back(bind);
+        _shader->_mat_deps |= bind._dep[0];
         return;
         return;
 
 
       } else if (noprefix == "Material.shininess") {
       } else if (noprefix == "Material.shininess") {
@@ -882,6 +891,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
         }
         }
         bind._piece = Shader::SMP_cell15;
         bind._piece = Shader::SMP_cell15;
         _shader->_mat_spec.push_back(bind);
         _shader->_mat_spec.push_back(bind);
+        _shader->_mat_deps |= bind._dep[0];
         return;
         return;
       }
       }
     }
     }
@@ -906,6 +916,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
         return;
         return;
       }
       }
       _shader->_mat_spec.push_back(bind);
       _shader->_mat_spec.push_back(bind);
+      _shader->_mat_deps |= bind._dep[0];
       return;
       return;
     }
     }
     if (noprefix == "Color") {
     if (noprefix == "Color") {
@@ -929,6 +940,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
         return;
         return;
       }
       }
       _shader->_mat_spec.push_back(bind);
       _shader->_mat_spec.push_back(bind);
+      _shader->_mat_deps |= bind._dep[0];
       return;
       return;
     }
     }
     if (noprefix == "ClipPlane") {
     if (noprefix == "ClipPlane") {
@@ -951,6 +963,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
         bind._arg[1] = NULL;
         bind._arg[1] = NULL;
         bind._dep[1] = Shader::SSD_NONE;
         bind._dep[1] = Shader::SSD_NONE;
         _shader->_mat_spec.push_back(bind);
         _shader->_mat_spec.push_back(bind);
+        _shader->_mat_deps |= bind._dep[0];
       }
       }
       return;
       return;
     }
     }
@@ -975,6 +988,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
         return;
         return;
       }
       }
       _shader->_mat_spec.push_back(bind);
       _shader->_mat_spec.push_back(bind);
+      _shader->_mat_deps |= bind._dep[0];
       return;
       return;
     }
     }
     if (noprefix == "TransformTable") {
     if (noprefix == "TransformTable") {
@@ -1016,8 +1030,9 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
       bind._part[0] = Shader::SMO_world_to_view;
       bind._part[0] = Shader::SMO_world_to_view;
       bind._part[1] = Shader::SMO_view_to_apiview;
       bind._part[1] = Shader::SMO_view_to_apiview;
       bind._dep[0] = Shader::SSD_general | Shader::SSD_transform;
       bind._dep[0] = Shader::SSD_general | Shader::SSD_transform;
-      bind._dep[1] = Shader::SSD_general | Shader::SSD_transform;
+      bind._dep[1] = Shader::SSD_general;
       _shader->_mat_spec.push_back(bind);
       _shader->_mat_spec.push_back(bind);
+      _shader->_mat_deps |= bind._dep[0] | bind._dep[1];
       return;
       return;
 
 
     } else if (noprefix == "InverseViewMatrix" || noprefix == "ViewMatrixInverse") {
     } else if (noprefix == "InverseViewMatrix" || noprefix == "ViewMatrixInverse") {
@@ -1025,9 +1040,10 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
       bind._func = Shader::SMF_compose;
       bind._func = Shader::SMF_compose;
       bind._part[0] = Shader::SMO_apiview_to_view;
       bind._part[0] = Shader::SMO_apiview_to_view;
       bind._part[1] = Shader::SMO_view_to_world;
       bind._part[1] = Shader::SMO_view_to_world;
-      bind._dep[0] = Shader::SSD_general | Shader::SSD_transform;
+      bind._dep[0] = Shader::SSD_general;
       bind._dep[1] = Shader::SSD_general | Shader::SSD_transform;
       bind._dep[1] = Shader::SSD_general | Shader::SSD_transform;
       _shader->_mat_spec.push_back(bind);
       _shader->_mat_spec.push_back(bind);
+      _shader->_mat_deps |= bind._dep[0] | bind._dep[1];
       return;
       return;
 
 
     } else if (noprefix == "FrameTime") {
     } else if (noprefix == "FrameTime") {
@@ -1035,9 +1051,10 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
       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;
-      bind._dep[0] = Shader::SSD_general;
+      bind._dep[0] = Shader::SSD_general | Shader::SSD_frame;
       bind._dep[1] = Shader::SSD_NONE;
       bind._dep[1] = Shader::SSD_NONE;
       _shader->_mat_spec.push_back(bind);
       _shader->_mat_spec.push_back(bind);
+      _shader->_mat_deps |= bind._dep[0] | bind._dep[1];
       return;
       return;
 
 
     } else if (noprefix == "DeltaFrameTime") {
     } else if (noprefix == "DeltaFrameTime") {
@@ -1045,9 +1062,10 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
       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;
-      bind._dep[0] = Shader::SSD_general;
+      bind._dep[0] = Shader::SSD_general | Shader::SSD_frame;
       bind._dep[1] = Shader::SSD_NONE;
       bind._dep[1] = Shader::SSD_NONE;
       _shader->_mat_spec.push_back(bind);
       _shader->_mat_spec.push_back(bind);
+      _shader->_mat_deps |= bind._dep[0] | bind._dep[1];
       return;
       return;
 
 
     } else if (noprefix == "FrameNumber") {
     } else if (noprefix == "FrameNumber") {
@@ -1124,11 +1142,12 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
         bind._func = Shader::SMF_first;
         bind._func = Shader::SMF_first;
         bind._part[0] = Shader::SMO_mat_constant_x;
         bind._part[0] = Shader::SMO_mat_constant_x;
         bind._arg[0] = InternalName::make(param_name);
         bind._arg[0] = InternalName::make(param_name);
-        bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs;
+        bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs | Shader::SSD_frame;
         bind._part[1] = Shader::SMO_identity;
         bind._part[1] = Shader::SMO_identity;
         bind._arg[1] = NULL;
         bind._arg[1] = NULL;
         bind._dep[1] = Shader::SSD_NONE;
         bind._dep[1] = Shader::SSD_NONE;
         _shader->_mat_spec.push_back(bind);
         _shader->_mat_spec.push_back(bind);
+        _shader->_mat_deps |= bind._dep[0];
         return;
         return;
       }
       }
       case GL_FLOAT_MAT4: {
       case GL_FLOAT_MAT4: {
@@ -1138,11 +1157,12 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
         bind._func = Shader::SMF_first;
         bind._func = Shader::SMF_first;
         bind._part[0] = Shader::SMO_mat_constant_x;
         bind._part[0] = Shader::SMO_mat_constant_x;
         bind._arg[0] = InternalName::make(param_name);
         bind._arg[0] = InternalName::make(param_name);
-        bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs;
+        bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs | Shader::SSD_frame;
         bind._part[1] = Shader::SMO_identity;
         bind._part[1] = Shader::SMO_identity;
         bind._arg[1] = NULL;
         bind._arg[1] = NULL;
         bind._dep[1] = Shader::SSD_NONE;
         bind._dep[1] = Shader::SSD_NONE;
         _shader->_mat_spec.push_back(bind);
         _shader->_mat_spec.push_back(bind);
+        _shader->_mat_deps |= bind._dep[0];
         return;
         return;
       }
       }
       case GL_FLOAT:
       case GL_FLOAT:
@@ -1172,11 +1192,12 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
           bind._func = Shader::SMF_first;
           bind._func = Shader::SMF_first;
           bind._part[0] = Shader::SMO_vec_constant_x_attrib;
           bind._part[0] = Shader::SMO_vec_constant_x_attrib;
           bind._arg[0] = iname;
           bind._arg[0] = iname;
-          bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs;
+          bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs | Shader::SSD_frame;
           bind._part[1] = Shader::SMO_identity;
           bind._part[1] = Shader::SMO_identity;
           bind._arg[1] = NULL;
           bind._arg[1] = NULL;
           bind._dep[1] = Shader::SSD_NONE;
           bind._dep[1] = Shader::SSD_NONE;
           _shader->_mat_spec.push_back(bind);
           _shader->_mat_spec.push_back(bind);
+          _shader->_mat_deps |= bind._dep[0];
           return;
           return;
         } // else fall through
         } // else fall through
       }
       }
@@ -1228,7 +1249,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
         }
         }
         bind._arg = InternalName::make(param_name);
         bind._arg = InternalName::make(param_name);
         bind._dim[0] = 1;
         bind._dim[0] = 1;
-        bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs;
+        bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs | Shader::SSD_frame;
         bind._dep[1] = Shader::SSD_NONE;
         bind._dep[1] = Shader::SSD_NONE;
         _shader->_ptr_spec.push_back(bind);
         _shader->_ptr_spec.push_back(bind);
         return;
         return;
@@ -1335,7 +1356,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
       }
       }
       bind._arg = InternalName::make(param_name);
       bind._arg = InternalName::make(param_name);
       bind._dim[0] = param_size;
       bind._dim[0] = param_size;
-      bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs;
+      bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs | Shader::SSD_frame;
       bind._dep[1] = Shader::SSD_NONE;
       bind._dep[1] = Shader::SSD_NONE;
       _shader->_ptr_spec.push_back(bind);
       _shader->_ptr_spec.push_back(bind);
       return;
       return;
@@ -1507,23 +1528,22 @@ release_resources() {
 //               input parameters.
 //               input parameters.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CLP(ShaderContext)::
 void CLP(ShaderContext)::
-bind(bool reissue_parameters) {
-  // GLSL shaders need to be bound before passing parameters.
-  if (!_shader->get_error_flag()) {
-    _glgsg->_glUseProgram(_glsl_program);
-  }
-
-  if (reissue_parameters) {
-    // Pass in k-parameters and transform-parameters
-    issue_parameters(Shader::SSD_general);
-  }
-
+bind() {
   if (!_validated) {
   if (!_validated) {
     _glgsg->_glValidateProgram(_glsl_program);
     _glgsg->_glValidateProgram(_glsl_program);
     glsl_report_program_errors(_glsl_program, false);
     glsl_report_program_errors(_glsl_program, false);
     _validated = true;
     _validated = true;
   }
   }
 
 
+  if (!_shader->get_error_flag()) {
+    _glgsg->_glUseProgram(_glsl_program);
+  }
+
+  if (GLCAT.is_spam()) {
+    GLCAT.spam() << "glUseProgram(" << _glsl_program << "): "
+                 << _shader->get_filename() << "\n";
+  }
+
   _glgsg->report_my_gl_errors();
   _glgsg->report_my_gl_errors();
 }
 }
 
 
@@ -1534,10 +1554,92 @@ bind(bool reissue_parameters) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CLP(ShaderContext)::
 void CLP(ShaderContext)::
 unbind() {
 unbind() {
+  if (GLCAT.is_spam()) {
+    GLCAT.spam() << "glUseProgram(0)\n";
+  }
+
   _glgsg->_glUseProgram(0);
   _glgsg->_glUseProgram(0);
   _glgsg->report_my_gl_errors();
   _glgsg->report_my_gl_errors();
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GLShaderContext::set_state_and_transform
+//       Access: Public
+//  Description: This function gets called whenever the RenderState
+//               or TransformState has changed, but the Shader
+//               itself has not changed.  It loads new values into the
+//               shader's parameters.
+////////////////////////////////////////////////////////////////////
+void CLP(ShaderContext)::
+set_state_and_transform(const RenderState *target_rs,
+                        const TransformState *modelview_transform,
+                        const TransformState *projection_transform) {
+
+  // Find out which state properties have changed.
+  int altered = 0;
+
+  if (_modelview_transform != modelview_transform) {
+    _modelview_transform = modelview_transform;
+    altered |= Shader::SSD_transform;
+  }
+  if (_projection_transform != projection_transform) {
+    _projection_transform = projection_transform;
+    altered |= Shader::SSD_projection;
+  }
+
+  if (_state_rs != target_rs) {
+    if (_state_rs == NULL) {
+      // We haven't set any state yet.
+      altered |= Shader::SSD_general;
+    } else {
+      if (_state_rs->get_attrib(ColorAttrib::get_class_slot()) !=
+          target_rs->get_attrib(ColorAttrib::get_class_slot())) {
+        altered |= Shader::SSD_color;
+      }
+      if (_state_rs->get_attrib(ColorScaleAttrib::get_class_slot()) !=
+          target_rs->get_attrib(ColorScaleAttrib::get_class_slot())) {
+        altered |= Shader::SSD_colorscale;
+      }
+      if (_state_rs->get_attrib(MaterialAttrib::get_class_slot()) !=
+          target_rs->get_attrib(MaterialAttrib::get_class_slot())) {
+        altered |= Shader::SSD_material;
+      }
+      if (_state_rs->get_attrib(ShaderAttrib::get_class_slot()) !=
+          target_rs->get_attrib(ShaderAttrib::get_class_slot())) {
+        altered |= Shader::SSD_shaderinputs;
+      }
+      if (_state_rs->get_attrib(FogAttrib::get_class_slot()) !=
+          target_rs->get_attrib(FogAttrib::get_class_slot())) {
+        altered |= Shader::SSD_fog;
+      }
+      if (_state_rs->get_attrib(LightAttrib::get_class_slot()) !=
+          target_rs->get_attrib(LightAttrib::get_class_slot())) {
+        altered |= Shader::SSD_light;
+      }
+      if (_state_rs->get_attrib(ClipPlaneAttrib::get_class_slot()) !=
+          target_rs->get_attrib(ClipPlaneAttrib::get_class_slot())) {
+        altered |= Shader::SSD_clip_planes;
+      }
+      if (_state_rs->get_attrib(TexMatrixAttrib::get_class_slot()) !=
+          target_rs->get_attrib(TexMatrixAttrib::get_class_slot())) {
+        altered |= Shader::SSD_tex_matrix;
+      }
+    }
+    _state_rs = target_rs;
+  }
+
+  // Is this the first time this shader is used this frame?
+  int frame_number = ClockObject::get_global_clock()->get_frame_count();
+  if (frame_number != _frame_number) {
+     altered |= Shader::SSD_frame;
+    _frame_number = frame_number;
+  }
+
+  if (altered != 0) {
+    issue_parameters(altered);
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GLShaderContext::issue_parameters
 //     Function: GLShaderContext::issue_parameters
 //       Access: Public
 //       Access: Public
@@ -1545,35 +1647,30 @@ unbind() {
 //               or TransformState has changed, but the Shader
 //               or TransformState has changed, but the Shader
 //               itself has not changed.  It loads new values into the
 //               itself has not changed.  It loads new values into the
 //               shader's parameters.
 //               shader's parameters.
-//
-//               If "altered" is false, that means you promise that
-//               the parameters for this shader context have already
-//               been issued once, and that since the last time the
-//               parameters were issued, no part of the render
-//               state has changed except the external and internal
-//               transforms.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CLP(ShaderContext)::
 void CLP(ShaderContext)::
 issue_parameters(int altered) {
 issue_parameters(int altered) {
-  //PStatGPUTimer timer(_glgsg, _glgsg->_draw_set_state_shader_parameters_pcollector);
+  PStatGPUTimer timer(_glgsg, _glgsg->_draw_set_state_shader_parameters_pcollector);
 
 
-  if (!valid()) {
-    return;
+  if (GLCAT.is_spam()) {
+    GLCAT.spam()
+      << "Setting uniforms for " << _shader->get_filename()
+      << " (altered 0x" << hex << altered << dec << ")\n";
   }
   }
 
 
-  if (_frame_number_loc != -1) {
-    int current_frame = ClockObject::get_global_clock()->get_frame_count();
-    if (current_frame != _frame_number) {
-      _glgsg->_glUniform1i(_frame_number_loc, current_frame);
-      _frame_number = current_frame;
+  // We have no way to track modifications to PTAs, so we assume that
+  // they are modified every frame and when we switch ShaderAttribs.
+  if (altered & (Shader::SSD_shaderinputs | Shader::SSD_frame)) {
+
+    // If we have an osg_FrameNumber input, set it now.
+    if ((altered | Shader::SSD_frame) != 0 && _frame_number_loc >= 0) {
+      _glgsg->_glUniform1i(_frame_number_loc, _frame_number);
     }
     }
-  }
 
 
-  // Iterate through _ptr parameters
-  for (int i = 0; i < (int)_shader->_ptr_spec.size(); ++i) {
-    Shader::ShaderPtrSpec &spec = _shader->_ptr_spec[i];
+    // Iterate through _ptr parameters
+    for (int i = 0; i < (int)_shader->_ptr_spec.size(); ++i) {
+      Shader::ShaderPtrSpec &spec = _shader->_ptr_spec[i];
 
 
-    if (altered & (spec._dep[0] | spec._dep[1])) {
       const Shader::ShaderPtrData* ptr_data = _glgsg->fetch_ptr_parameter(spec);
       const Shader::ShaderPtrData* ptr_data = _glgsg->fetch_ptr_parameter(spec);
       if (ptr_data == NULL) { //the input is not contained in ShaderPtrData
       if (ptr_data == NULL) { //the input is not contained in ShaderPtrData
         release_resources();
         release_resources();
@@ -1657,10 +1754,14 @@ issue_parameters(int altered) {
     }
     }
   }
   }
 
 
-  for (int i = 0; i < (int)_shader->_mat_spec.size(); ++i) {
-    Shader::ShaderMatSpec &spec = _shader->_mat_spec[i];
+  if (altered & _shader->_mat_deps) {
+    for (int i = 0; i < (int)_shader->_mat_spec.size(); ++i) {
+      Shader::ShaderMatSpec &spec = _shader->_mat_spec[i];
+
+      if ((altered & (spec._dep[0] | spec._dep[1])) == 0) {
+        continue;
+      }
 
 
-    if (altered & (spec._dep[0] | spec._dep[1])) {
       const LMatrix4 *val = _glgsg->fetch_specified_value(spec, altered);
       const LMatrix4 *val = _glgsg->fetch_specified_value(spec, altered);
       if (!val) continue;
       if (!val) continue;
 #ifndef STDFLOAT_DOUBLE
 #ifndef STDFLOAT_DOUBLE
@@ -1814,12 +1915,12 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) {
     return true;
     return true;
   }
   }
 
 
-#ifdef SUPPORT_IMMEDIATE_MODE
-  if (_glgsg->_use_sender) {
-    GLCAT.error() << "immediate mode shaders not implemented yet\n";
-  } else
-#endif // SUPPORT_IMMEDIATE_MODE
-  {
+  if (valid()) {
+    // Get the active ColorAttrib.  We'll need it to determine how to
+    // apply vertex colors.
+    const ColorAttrib *color_attrib;
+    _state_rs->get_attrib_def(color_attrib);
+
     const GeomVertexArrayDataHandle *array_reader;
     const GeomVertexArrayDataHandle *array_reader;
     Geom::NumericType numeric_type;
     Geom::NumericType numeric_type;
     int start, stride, num_values;
     int start, stride, num_values;
@@ -1845,7 +1946,7 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) {
       // Don't apply vertex colors if they are disabled with a ColorAttrib.
       // Don't apply vertex colors if they are disabled with a ColorAttrib.
       int num_elements, element_stride, divisor;
       int num_elements, element_stride, divisor;
       bool normalized;
       bool normalized;
-      if ((p != _color_attrib_index || _glgsg->_vertex_colors_enabled) &&
+      if ((p != _color_attrib_index || color_attrib->get_type() == ColorAttrib::T_vertex) &&
           _glgsg->_data_reader->get_array_info(name, array_reader,
           _glgsg->_data_reader->get_array_info(name, array_reader,
                                                num_values, numeric_type,
                                                num_values, numeric_type,
                                                normalized, start, stride, divisor,
                                                normalized, start, stride, divisor,
@@ -1891,9 +1992,9 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) {
         if (p == _color_attrib_index) {
         if (p == _color_attrib_index) {
           // Vertex colors are disabled or not present.  Apply flat color.
           // Vertex colors are disabled or not present.  Apply flat color.
 #if defined(STDFLOAT_DOUBLE) && !defined(OPENGLES)
 #if defined(STDFLOAT_DOUBLE) && !defined(OPENGLES)
-          _glgsg->_glVertexAttrib4dv(p, _glgsg->_scene_graph_color.get_data());
+          _glgsg->_glVertexAttrib4dv(p, color_attrib->get_color().get_data());
 #else
 #else
-          _glgsg->_glVertexAttrib4fv(p, _glgsg->_scene_graph_color.get_data());
+          _glgsg->_glVertexAttrib4fv(p, color_attrib->get_color().get_data());
 #endif
 #endif
         }
         }
       }
       }
@@ -1926,6 +2027,8 @@ disable_shader_texture_bindings() {
     return;
     return;
   }
   }
 
 
+  DO_PSTATS_STUFF(_glgsg->_texture_state_pcollector.add_level(1));
+
   for (int i = 0; i < _shader->_tex_spec.size(); ++i) {
   for (int i = 0; i < _shader->_tex_spec.size(); ++i) {
 #ifndef OPENGLES
 #ifndef OPENGLES
     // Check if bindless was used, if so, there's nothing to unbind.
     // Check if bindless was used, if so, there's nothing to unbind.
@@ -1960,9 +2063,7 @@ disable_shader_texture_bindings() {
       break;
       break;
 
 
     case Texture::TT_3d_texture:
     case Texture::TT_3d_texture:
-#ifndef OPENGLES_1
       glBindTexture(GL_TEXTURE_3D, 0);
       glBindTexture(GL_TEXTURE_3D, 0);
-#endif
       break;
       break;
 
 
     case Texture::TT_2d_texture_array:
     case Texture::TT_2d_texture_array:
@@ -2026,9 +2127,9 @@ disable_shader_texture_bindings() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CLP(ShaderContext)::
 void CLP(ShaderContext)::
 update_shader_texture_bindings(ShaderContext *prev) {
 update_shader_texture_bindings(ShaderContext *prev) {
-  if (prev) {
-    prev->disable_shader_texture_bindings();
-  }
+  //if (prev) {
+  //  prev->disable_shader_texture_bindings();
+  //}
 
 
   if (!valid()) {
   if (!valid()) {
     return;
     return;
@@ -2134,8 +2235,10 @@ update_shader_texture_bindings(ShaderContext *prev) {
 
 
   // We get the TextureAttrib directly from the _target_rs, not the
   // We get the TextureAttrib directly from the _target_rs, not the
   // filtered TextureAttrib in _target_texture.
   // filtered TextureAttrib in _target_texture.
-  const TextureAttrib *texattrib = DCAST(TextureAttrib, _glgsg->_target_rs->get_attrib_def(TextureAttrib::get_class_slot()));
-  nassertv(texattrib != (TextureAttrib *)NULL);
+  const TextureAttrib *texattrib;
+  _glgsg->_target_rs->get_attrib_def(texattrib);
+  //const TextureAttrib *texattrib;
+  //_state_rs->get_attrib_def(TextureAttrib::get_class_slot());
 
 
   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];

+ 12 - 4
panda/src/glstuff/glShaderContext_src.h

@@ -45,19 +45,23 @@ public:
   bool get_sampler_texture_type(int &out, GLenum param_type);
   bool get_sampler_texture_type(int &out, GLenum param_type);
 
 
   INLINE bool valid(void);
   INLINE bool valid(void);
-  void bind(bool reissue_parameters = true);
+  void bind();
   void unbind();
   void unbind();
+
+  void set_state_and_transform(const RenderState *state,
+                               const TransformState *modelview_transform,
+                               const TransformState *projection_transform);
+
   void issue_parameters(int altered);
   void issue_parameters(int altered);
   void update_transform_table(const TransformTable *table);
   void update_transform_table(const TransformTable *table);
   void update_slider_table(const SliderTable *table);
   void update_slider_table(const SliderTable *table);
   void disable_shader_vertex_arrays();
   void disable_shader_vertex_arrays();
   bool update_shader_vertex_arrays(ShaderContext *prev, bool force);
   bool update_shader_vertex_arrays(ShaderContext *prev, bool force);
-  void disable_shader_texture_bindings();
-  void update_shader_texture_bindings(ShaderContext *prev);
+  void disable_shader_texture_bindings() OVERRIDE;
+  void update_shader_texture_bindings(ShaderContext *prev) OVERRIDE;
 
 
   INLINE bool uses_standard_vertex_arrays(void);
   INLINE bool uses_standard_vertex_arrays(void);
   INLINE bool uses_custom_vertex_arrays(void);
   INLINE bool uses_custom_vertex_arrays(void);
-  INLINE bool uses_custom_texture_bindings(void);
 
 
 private:
 private:
   bool _validated;
   bool _validated;
@@ -65,6 +69,10 @@ private:
   typedef pvector<GLuint> GLSLShaders;
   typedef pvector<GLuint> GLSLShaders;
   GLSLShaders _glsl_shaders;
   GLSLShaders _glsl_shaders;
 
 
+  CPT(RenderState) _state_rs;
+  CPT(TransformState) _modelview_transform;
+  CPT(TransformState) _projection_transform;
+
   //struct ParamContext {
   //struct ParamContext {
   //  CPT(InternalName) _name;
   //  CPT(InternalName) _name;
   //  GLint _location;
   //  GLint _location;

+ 65 - 4
panda/src/gobj/shader.cxx

@@ -416,7 +416,17 @@ cp_dependency(ShaderMatInput inp) {
   if ((inp == SMO_model_to_view) ||
   if ((inp == SMO_model_to_view) ||
       (inp == SMO_view_to_model) ||
       (inp == SMO_view_to_model) ||
       (inp == SMO_model_to_apiview) ||
       (inp == SMO_model_to_apiview) ||
-      (inp == SMO_apiview_to_model)) {
+      (inp == SMO_apiview_to_model) ||
+      (inp == SMO_view_to_world) ||
+      (inp == SMO_world_to_view) ||
+      (inp == SMO_view_x_to_view) ||
+      (inp == SMO_view_to_view_x) ||
+      (inp == SMO_apiview_x_to_view) ||
+      (inp == SMO_view_to_apiview_x) ||
+      (inp == SMO_clip_x_to_view) ||
+      (inp == SMO_view_to_clip_x) ||
+      (inp == SMO_apiclip_x_to_view) ||
+      (inp == SMO_view_to_apiclip_x)) {
     dep |= SSD_transform;
     dep |= SSD_transform;
   }
   }
   if ((inp == SMO_texpad_x) ||
   if ((inp == SMO_texpad_x) ||
@@ -438,6 +448,25 @@ cp_dependency(ShaderMatInput inp) {
       (inp == SMO_apiclip_x_to_view) ||
       (inp == SMO_apiclip_x_to_view) ||
       (inp == SMO_view_to_apiclip_x)) {
       (inp == SMO_view_to_apiclip_x)) {
     dep |= SSD_shaderinputs;
     dep |= SSD_shaderinputs;
+
+    if ((inp == SMO_alight_x) ||
+        (inp == SMO_dlight_x) ||
+        (inp == SMO_plight_x) ||
+        (inp == SMO_slight_x) ||
+        (inp == SMO_satten_x) ||
+        (inp == SMO_vec_constant_x_attrib) ||
+        (inp == SMO_view_x_to_view) ||
+        (inp == SMO_view_to_view_x) ||
+        (inp == SMO_apiview_x_to_view) ||
+        (inp == SMO_view_to_apiview_x) ||
+        (inp == SMO_clip_x_to_view) ||
+        (inp == SMO_view_to_clip_x) ||
+        (inp == SMO_apiclip_x_to_view) ||
+        (inp == SMO_view_to_apiclip_x)) {
+      // We can't track changes to these yet, so we have to assume that
+      // they are modified every frame.
+      dep |= SSD_frame;
+    }
   }
   }
   if ((inp == SMO_light_ambient) ||
   if ((inp == SMO_light_ambient) ||
       (inp == SMO_light_source_i_attrib)) {
       (inp == SMO_light_source_i_attrib)) {
@@ -455,6 +484,21 @@ cp_dependency(ShaderMatInput inp) {
   if (inp == SMO_texmat_i || inp == SMO_inv_texmat_i) {
   if (inp == SMO_texmat_i || inp == SMO_inv_texmat_i) {
     dep |= SSD_tex_matrix;
     dep |= SSD_tex_matrix;
   }
   }
+  if ((inp == SMO_window_size) ||
+      (inp == SMO_pixel_size) ||
+      (inp == SMO_frame_number) ||
+      (inp == SMO_frame_time) ||
+      (inp == SMO_frame_delta)) {
+    dep |= SSD_frame;
+  }
+  if ((inp == SMO_clip_to_view) ||
+      (inp == SMO_view_to_clip) ||
+      (inp == SMO_apiclip_to_view) ||
+      (inp == SMO_view_to_apiclip) ||
+      (inp == SMO_apiview_to_apiclip) ||
+      (inp == SMO_apiclip_to_apiview)) {
+    dep |= SSD_projection;
+  }
 
 
   return dep;
   return dep;
 }
 }
@@ -857,6 +901,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
     }
     }
     cp_optimize_mat_spec(bind);
     cp_optimize_mat_spec(bind);
     _mat_spec.push_back(bind);
     _mat_spec.push_back(bind);
+    _mat_deps |= bind._dep[0] | bind._dep[1];
     return true;
     return true;
   }
   }
 
 
@@ -931,6 +976,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
 
 
     cp_optimize_mat_spec(bind);
     cp_optimize_mat_spec(bind);
     _mat_spec.push_back(bind);
     _mat_spec.push_back(bind);
+    _mat_deps |= bind._dep[0] | bind._dep[1];
     return true;
     return true;
   }
   }
 
 
@@ -944,6 +990,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
 
 
     cp_optimize_mat_spec(bind);
     cp_optimize_mat_spec(bind);
     _mat_spec.push_back(bind);
     _mat_spec.push_back(bind);
+    _mat_deps |= bind._dep[0] | bind._dep[1];
     return true;
     return true;
   }
   }
 
 
@@ -967,6 +1014,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
 
 
     cp_optimize_mat_spec(bind);
     cp_optimize_mat_spec(bind);
     _mat_spec.push_back(bind);
     _mat_spec.push_back(bind);
+    _mat_deps |= bind._dep[0] | bind._dep[1];
     return true;
     return true;
   }
   }
 
 
@@ -988,6 +1036,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
 
 
     cp_optimize_mat_spec(bind);
     cp_optimize_mat_spec(bind);
     _mat_spec.push_back(bind);
     _mat_spec.push_back(bind);
+    _mat_deps |= bind._dep[0] | bind._dep[1];
     return true;
     return true;
   }
   }
 
 
@@ -1029,6 +1078,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
     }
     }
     cp_optimize_mat_spec(bind);
     cp_optimize_mat_spec(bind);
     _mat_spec.push_back(bind);
     _mat_spec.push_back(bind);
+    _mat_deps |= bind._dep[0] | bind._dep[1];
     return true;
     return true;
   }
   }
 
 
@@ -1051,6 +1101,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
 
 
     cp_optimize_mat_spec(bind);
     cp_optimize_mat_spec(bind);
     _mat_spec.push_back(bind);
     _mat_spec.push_back(bind);
+    _mat_deps |= bind._dep[0] | bind._dep[1];
     return true;
     return true;
   }
   }
 
 
@@ -1072,6 +1123,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
 
 
     cp_optimize_mat_spec(bind);
     cp_optimize_mat_spec(bind);
     _mat_spec.push_back(bind);
     _mat_spec.push_back(bind);
+    _mat_deps |= bind._dep[0] | bind._dep[1];
     return true;
     return true;
   }
   }
 
 
@@ -1093,6 +1145,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
 
 
     cp_optimize_mat_spec(bind);
     cp_optimize_mat_spec(bind);
     _mat_spec.push_back(bind);
     _mat_spec.push_back(bind);
+    _mat_deps |= bind._dep[0] | bind._dep[1];
     return true;
     return true;
   }
   }
 
 
@@ -1139,6 +1192,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
 
 
     cp_optimize_mat_spec(bind);
     cp_optimize_mat_spec(bind);
     _mat_spec.push_back(bind);
     _mat_spec.push_back(bind);
+    _mat_deps |= bind._dep[0] | bind._dep[1];
     return true;
     return true;
   }
   }
 
 
@@ -1195,6 +1249,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
     bind._arg[1] = NULL;
     bind._arg[1] = NULL;
     cp_optimize_mat_spec(bind);
     cp_optimize_mat_spec(bind);
     _mat_spec.push_back(bind);
     _mat_spec.push_back(bind);
+    _mat_deps |= bind._dep[0] | bind._dep[1];
     return true;
     return true;
   }
   }
 
 
@@ -1215,6 +1270,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
     bind._arg[1] = NULL;
     bind._arg[1] = NULL;
     cp_optimize_mat_spec(bind);
     cp_optimize_mat_spec(bind);
     _mat_spec.push_back(bind);
     _mat_spec.push_back(bind);
+    _mat_deps |= bind._dep[0] | bind._dep[1];
     return true;
     return true;
   }
   }
 
 
@@ -1261,8 +1317,12 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
     bind._id      = p._id;
     bind._id      = p._id;
     bind._arg     = kinputname;
     bind._arg     = kinputname;
     bind._info    = p;
     bind._info    = p;
-    bind._dep[0]  = SSD_general | SSD_shaderinputs;
-    bind._dep[1]  = SSD_general | SSD_NONE;
+
+    // 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);
     memcpy(bind._dim,arg_dim,sizeof(int)*3);
 
 
@@ -2050,7 +2110,8 @@ Shader(ShaderLanguage lang) :
   _parse(0),
   _parse(0),
   _loaded(false),
   _loaded(false),
   _language(lang),
   _language(lang),
-  _last_modified(0)
+  _last_modified(0),
+  _mat_deps(0)
 {
 {
 #ifdef HAVE_CG
 #ifdef HAVE_CG
   _cg_vprogram = 0;
   _cg_vprogram = 0;

+ 3 - 0
panda/src/gobj/shader.h

@@ -273,6 +273,8 @@ public:
     SSD_light         = 0x080,
     SSD_light         = 0x080,
     SSD_clip_planes   = 0x100,
     SSD_clip_planes   = 0x100,
     SSD_tex_matrix    = 0x200,
     SSD_tex_matrix    = 0x200,
+    SSD_frame         = 0x400,
+    SSD_projection    = 0x800,
   };
   };
 
 
   enum ShaderBug {
   enum ShaderBug {
@@ -529,6 +531,7 @@ public:
   epvector <ShaderMatSpec> _mat_spec;
   epvector <ShaderMatSpec> _mat_spec;
   pvector <ShaderTexSpec> _tex_spec;
   pvector <ShaderTexSpec> _tex_spec;
   pvector <ShaderVarSpec> _var_spec;
   pvector <ShaderVarSpec> _var_spec;
+  int _mat_deps;
 
 
   bool _error_flag;
   bool _error_flag;
   ShaderFile _text;
   ShaderFile _text;

+ 3 - 2
panda/src/gobj/shaderContext.h

@@ -36,8 +36,10 @@ class EXPCL_PANDA_GOBJ ShaderContext: public SavedContext {
 public:
 public:
   INLINE ShaderContext(Shader *se);
   INLINE ShaderContext(Shader *se);
 
 
+  INLINE virtual void set_state_and_transform(const RenderState *, const TransformState *, const TransformState*) {};
+
   INLINE virtual bool valid() { return false; }
   INLINE virtual bool valid() { return false; }
-  INLINE virtual void bind(bool reissue_parameters = true) {};
+  INLINE virtual void bind() {};
   INLINE virtual void unbind() {};
   INLINE virtual void unbind() {};
   INLINE virtual void issue_parameters(int altered) {};
   INLINE virtual void issue_parameters(int altered) {};
   INLINE virtual void disable_shader_vertex_arrays() {};
   INLINE virtual void disable_shader_vertex_arrays() {};
@@ -47,7 +49,6 @@ public:
 
 
   INLINE virtual bool uses_standard_vertex_arrays(void) { return true; };
   INLINE virtual bool uses_standard_vertex_arrays(void) { return true; };
   INLINE virtual bool uses_custom_vertex_arrays(void) { return false; };
   INLINE virtual bool uses_custom_vertex_arrays(void) { return false; };
-  INLINE virtual bool uses_custom_texture_bindings(void) { return false; };
 
 
 PUBLISHED:
 PUBLISHED:
   INLINE Shader *get_shader() const;
   INLINE Shader *get_shader() const;

+ 2 - 3
panda/src/pgraph/colorBlendAttrib.h

@@ -141,10 +141,9 @@ private:
   static int _attrib_slot;
   static int _attrib_slot;
 };
 };
 
 
-ostream &operator << (ostream &out, ColorBlendAttrib::Mode mode);
-ostream &operator << (ostream &out, ColorBlendAttrib::Operand operand);
+EXPCL_PANDA_PGRAPH ostream &operator << (ostream &out, ColorBlendAttrib::Mode mode);
+EXPCL_PANDA_PGRAPH ostream &operator << (ostream &out, ColorBlendAttrib::Operand operand);
 
 
 #include "colorBlendAttrib.I"
 #include "colorBlendAttrib.I"
 
 
 #endif
 #endif
-