Browse Source

More efficiently manage which vertex arrays are enabled/disabled

rdb 10 years ago
parent
commit
927a5bd48b

+ 18 - 16
panda/src/glstuff/glCgShaderContext_src.cxx

@@ -43,7 +43,6 @@ CLP(CgShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderConte
   _glgsg = glgsg;
   _cg_program = 0;
   _glsl_program = 0;
-  _has_divisor = false;
   _color_attrib_index = CA_color;
   _transform_table_param = 0;
   _slider_table_param = 0;
@@ -780,10 +779,7 @@ disable_shader_vertex_arrays() {
     GLint p = _attributes[i];
 
     if (p >= 0) {
-      _glgsg->_glDisableVertexAttribArray(p);
-      if (_has_divisor) {
-        _glgsg->_glVertexAttribDivisor(p, 0);
-      }
+      _glgsg->disable_vertex_attrib_array(p);
     } else {
 #ifdef SUPPORT_FIXED_FUNCTION
       switch (p) {
@@ -827,10 +823,6 @@ disable_shader_vertex_arrays() {
 ////////////////////////////////////////////////////////////////////
 bool CLP(CgShaderContext)::
 update_shader_vertex_arrays(ShaderContext *prev, bool force) {
-  if (prev) {
-    prev->disable_shader_vertex_arrays();
-  }
-
   if (!valid()) {
     return true;
   }
@@ -847,6 +839,9 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) {
     Geom::NumericType numeric_type;
     int start, stride, num_values;
     size_t nvarying = _shader->_var_spec.size();
+
+    GLuint max_p = 0;
+
     for (size_t i = 0; i < nvarying; ++i) {
       const Shader::ShaderVarSpec &bind = _shader->_var_spec[i];
       InternalName *name = bind._name;
@@ -878,10 +873,12 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) {
         client_pointer += start;
 
         // We don't use cgGLSetParameterPointer because it is very buggy and
-        // limited in the options we can set.start
+        // limited in the options we can set.
         GLenum type = _glgsg->get_numeric_type(numeric_type);
         if (p >= 0) {
-          _glgsg->_glEnableVertexAttribArray(p);
+          max_p = max(max_p, (GLuint)p + 1);
+
+          _glgsg->enable_vertex_attrib_array(p);
 
           if (bind._integer) {
             _glgsg->_glVertexAttribIPointer(p, num_values, type,
@@ -896,9 +893,8 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) {
                                            normalized, stride, client_pointer);
           }
 
-          if (_glgsg->_supports_vertex_attrib_divisor) {
-            _glgsg->_glVertexAttribDivisor(p, divisor);
-            _has_divisor = true;
+          if (divisor > 0) {
+            _glgsg->set_vertex_attrib_divisor(p, divisor);
           }
 
         } else {
@@ -950,7 +946,7 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) {
           // to be at 0, but we don't have control over that with Cg.  So, we
           // work around this by just binding something silly to 0.
           // This breaks flat colors, but it's better than invisible objects?
-          _glgsg->_glEnableVertexAttribArray(0);
+          _glgsg->enable_vertex_attrib_array(0);
           if (bind._integer) {
             _glgsg->_glVertexAttribIPointer(0, 4, GL_INT, 0, 0);
           } else {
@@ -960,7 +956,7 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) {
         } else
 #endif  // SUPPORT_FIXED_FUNCTION
         if (p >= 0) {
-          _glgsg->_glDisableVertexAttribArray(p);
+          _glgsg->disable_vertex_attrib_array(p);
 
           if (p == _color_attrib_index) {
 #ifdef STDFLOAT_DOUBLE
@@ -1000,6 +996,12 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) {
         }
       }
     }
+
+    // Disable attribute arrays we don't use.
+    GLint highest_p = _glgsg->_enabled_vertex_attrib_arrays.get_highest_on_bit() + 1;
+    for (GLint p = max_p; p < highest_p; ++p) {
+      _glgsg->disable_vertex_attrib_array(p);
+    }
   }
 
   if (_transform_table_param) {

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

@@ -84,8 +84,6 @@ private:
 
   CLP(GraphicsStateGuardian) *_glgsg;
 
-  bool _has_divisor;
-
   void release_resources();
 
 public:

+ 48 - 0
panda/src/glstuff/glGraphicsStateGuardian_src.I

@@ -240,6 +240,54 @@ is_at_least_gles_version(int major_version, int minor_version) const {
 #endif  // OPENGLES
 }
 
+#ifndef OPENGLES_1
+////////////////////////////////////////////////////////////////////
+//     Function: GLGraphicsStateGuardian::enable_vertex_attrib_array
+//       Access: Protected
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE void CLP(GraphicsStateGuardian)::
+enable_vertex_attrib_array(GLuint index) {
+  if (!_enabled_vertex_attrib_arrays.get_bit(index)) {
+    _glEnableVertexAttribArray(index);
+    _enabled_vertex_attrib_arrays.set_bit(index);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GLGraphicsStateGuardian::disable_vertex_attrib_array
+//       Access: Protected
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE void CLP(GraphicsStateGuardian)::
+disable_vertex_attrib_array(GLuint index) {
+  if (_enabled_vertex_attrib_arrays.get_bit(index)) {
+    _glDisableVertexAttribArray(index);
+    _enabled_vertex_attrib_arrays.clear_bit(index);
+
+    if (_vertex_attrib_divisors[index] != 0) {
+      _glVertexAttribDivisor(index, 0);
+      _vertex_attrib_divisors[index] = 0;
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GLGraphicsStateGuardian::set_vertex_attrib_divisor
+//       Access: Protected
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE void CLP(GraphicsStateGuardian)::
+set_vertex_attrib_divisor(GLuint index, GLuint divisor) {
+  if (_supports_vertex_attrib_divisor &&
+      _vertex_attrib_divisors[index] != divisor) {
+    _glVertexAttribDivisor(index, divisor);
+    _vertex_attrib_divisors[index] = divisor;
+  }
+}
+
+#endif
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GLGraphicsStateGuardian::enable_multisample_antialias
 //       Access: Protected

+ 44 - 26
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -2543,6 +2543,11 @@ reset() {
   _active_color_write_mask = ColorWriteAttrib::C_all;
   _tex_gen_point_sprite = false;
 
+#ifndef OPENGLES_1
+  _enabled_vertex_attrib_arrays.clear();
+  memset(_vertex_attrib_divisors, 0, sizeof(GLint) * 32);
+#endif
+
 #ifndef OPENGLES
   // Dither is on by default in GL; let's turn it off
   glDisable(GL_DITHER);
@@ -2936,25 +2941,27 @@ clear(DrawableRegion *clearable) {
     mask |= GL_STENCIL_BUFFER_BIT;
   }
 
-  glClear(mask);
+  if (mask != 0) {
+    glClear(mask);
 
-  if (GLCAT.is_spam()) {
-    string clear_flags;
-    if (mask & GL_COLOR_BUFFER_BIT) {
-      clear_flags += " | GL_COLOR_BUFFER_BIT";
-    }
-    if (mask & GL_DEPTH_BUFFER_BIT) {
-      clear_flags += " | GL_DEPTH_BUFFER_BIT";
-    }
-    if (mask & GL_STENCIL_BUFFER_BIT) {
-      clear_flags += " | GL_STENCIL_BUFFER_BIT";
-    }
-#ifndef OPENGLES
-    if (mask & GL_ACCUM_BUFFER_BIT) {
-      clear_flags += " | GL_ACCUM_BUFFER_BIT";
+    if (GLCAT.is_spam()) {
+      string clear_flags;
+      if (mask & GL_COLOR_BUFFER_BIT) {
+        clear_flags += " | GL_COLOR_BUFFER_BIT";
+      }
+      if (mask & GL_DEPTH_BUFFER_BIT) {
+        clear_flags += " | GL_DEPTH_BUFFER_BIT";
+      }
+      if (mask & GL_STENCIL_BUFFER_BIT) {
+        clear_flags += " | GL_STENCIL_BUFFER_BIT";
+      }
+  #ifndef OPENGLES
+      if (mask & GL_ACCUM_BUFFER_BIT) {
+        clear_flags += " | GL_ACCUM_BUFFER_BIT";
+      }
+  #endif
+      GLCAT.spam() << "glClear(" << (clear_flags.c_str() + 3) << ")\n";
     }
-#endif
-    GLCAT.spam() << "glClear(" << (clear_flags.c_str() + 3) << ")\n";
   }
 
   report_my_gl_errors();
@@ -3088,6 +3095,13 @@ void CLP(GraphicsStateGuardian)::
 clear_before_callback() {
 #ifdef SUPPORT_FIXED_FUNCTION
   disable_standard_vertex_arrays();
+#endif
+#ifndef OPENGLES_1
+  if (_vertex_array_shader_context != 0) {
+    _vertex_array_shader_context->disable_shader_vertex_arrays();
+    _vertex_array_shader = (Shader *)NULL;
+    _vertex_array_shader_context = (ShaderContext *)NULL;
+  }
 #endif
   unbind_buffers();
 
@@ -3642,7 +3656,8 @@ begin_draw_primitives(const GeomPipelineReader *geom_reader,
     } else {
 #ifdef SUPPORT_FIXED_FUNCTION
       // Shader.
-      if (_vertex_array_shader_context == 0 || _vertex_array_shader_context->uses_standard_vertex_arrays()) {
+      if (_vertex_array_shader_context == 0 ||
+          _vertex_array_shader_context->uses_standard_vertex_arrays()) {
         // Previous shader used standard arrays.
         if (_current_shader_context->uses_standard_vertex_arrays()) {
           // So does the current, so update them.
@@ -3654,16 +3669,19 @@ begin_draw_primitives(const GeomPipelineReader *geom_reader,
           disable_standard_vertex_arrays();
         }
       }
-#endif  // SUPPORT_FIXED_FUNCTION
-      if (_current_shader_context->uses_custom_vertex_arrays()) {
-        // The current shader also uses custom vertex arrays.
-        if (!_current_shader_context->
-            update_shader_vertex_arrays(_vertex_array_shader_context, force)) {
-          return false;
-        }
-      } else {
+#ifdef HAVE_CG
+      else if (_vertex_array_shader_context->is_of_type(CLP(CgShaderContext)::get_class_type())) {
+        // The previous shader was a Cg shader, which can leave a messy
+        // situation.
         _vertex_array_shader_context->disable_shader_vertex_arrays();
       }
+#endif
+#endif  // SUPPORT_FIXED_FUNCTION
+      // Now update the vertex arrays for the current shader.
+      if (!_current_shader_context->
+          update_shader_vertex_arrays(_vertex_array_shader_context, force)) {
+        return false;
+      }
     }
 
     _vertex_array_shader = _current_shader;

+ 9 - 0
panda/src/glstuff/glGraphicsStateGuardian_src.h

@@ -451,6 +451,12 @@ protected:
 
   virtual void free_pointers();
 
+#ifndef OPENGLES_1
+  INLINE void enable_vertex_attrib_array(GLuint index);
+  INLINE void disable_vertex_attrib_array(GLuint index);
+  INLINE void set_vertex_attrib_divisor(GLuint index, GLuint divisor);
+#endif
+
   INLINE void enable_multisample_antialias(bool val);
   INLINE void enable_multisample_alpha_one(bool val);
   INLINE void enable_multisample_alpha_mask(bool val);
@@ -602,6 +608,9 @@ protected:
   epvector<LVecBase4i> _scissor_array;
 
 #ifndef OPENGLES_1
+  BitMask32 _enabled_vertex_attrib_arrays;
+  GLint _vertex_attrib_divisors[32];
+
   PT(Shader) _current_shader;
   ShaderContext *_current_shader_context;
   PT(Shader) _vertex_array_shader;

+ 77 - 79
panda/src/glstuff/glShaderContext_src.cxx

@@ -262,7 +262,6 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
   _glgsg = glgsg;
   _glsl_program = 0;
   _uses_standard_vertex_arrays = false;
-  _has_divisor = false;
   _color_attrib_index = -1;
   _transform_table_index = -1;
   _slider_table_index = -1;
@@ -2017,11 +2016,9 @@ disable_shader_vertex_arrays() {
   for (int i=0; i<(int)_shader->_var_spec.size(); i++) {
     const Shader::ShaderVarSpec &bind = _shader->_var_spec[i];
     GLint p = bind._id._seqno;
-    if (_has_divisor) {
-      _glgsg->_glVertexAttribDivisor(p, 0);
-    }
+
     for (int i = 0; i < bind._elements; ++i) {
-      _glgsg->_glDisableVertexAttribArray(p + i);
+      _glgsg->disable_vertex_attrib_array(p + i);
     }
   }
 
@@ -2035,105 +2032,106 @@ disable_shader_vertex_arrays() {
 //               shader, then enables all the vertex arrays needed
 //               by this shader.  Extracts the relevant vertex array
 //               data from the gsg.
-//               The current implementation is inefficient, because
-//               it may unnecessarily disable arrays then immediately
-//               reenable them.  We may optimize this someday.
 ////////////////////////////////////////////////////////////////////
 bool CLP(ShaderContext)::
 update_shader_vertex_arrays(ShaderContext *prev, bool force) {
-  if (prev) {
-    prev->disable_shader_vertex_arrays();
-  }
   if (!valid()) {
     return true;
   }
 
-  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);
+  // 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;
+  Geom::NumericType numeric_type;
+  int start, stride, num_values;
+  size_t nvarying = _shader->_var_spec.size();
 
-    const GeomVertexArrayDataHandle *array_reader;
-    Geom::NumericType numeric_type;
-    int start, stride, num_values;
-    int nvarying = _shader->_var_spec.size();
+  GLuint max_p = 0;
 
-    for (int i = 0; i < nvarying; ++i) {
-      const Shader::ShaderVarSpec &bind = _shader->_var_spec[i];
-      InternalName *name = bind._name;
-      int texslot = bind._append_uv;
+  for (size_t i = 0; i < nvarying; ++i) {
+    const Shader::ShaderVarSpec &bind = _shader->_var_spec[i];
+    InternalName *name = bind._name;
+    int texslot = bind._append_uv;
 
-      if (texslot >= 0 && texslot < _glgsg->_state_texture->get_num_on_stages()) {
-        TextureStage *stage = _glgsg->_state_texture->get_on_stage(texslot);
-        InternalName *texname = stage->get_texcoord_name();
+    if (texslot >= 0 && texslot < _glgsg->_state_texture->get_num_on_stages()) {
+      TextureStage *stage = _glgsg->_state_texture->get_on_stage(texslot);
+      InternalName *texname = stage->get_texcoord_name();
 
-        if (name == InternalName::get_texcoord()) {
-          name = texname;
-        } else if (texname != InternalName::get_texcoord()) {
-          name = name->append(texname->get_basename());
-        }
+      if (name == InternalName::get_texcoord()) {
+        name = texname;
+      } else if (texname != InternalName::get_texcoord()) {
+        name = name->append(texname->get_basename());
       }
-      GLint p = bind._id._seqno;
-
-      // Don't apply vertex colors if they are disabled with a ColorAttrib.
-      int num_elements, element_stride, divisor;
-      bool normalized;
-      if ((p != _color_attrib_index || color_attrib->get_type() == ColorAttrib::T_vertex) &&
-          _glgsg->_data_reader->get_array_info(name, array_reader,
-                                               num_values, numeric_type,
-                                               normalized, start, stride, divisor,
-                                               num_elements, element_stride)) {
-        const unsigned char *client_pointer;
-        if (!_glgsg->setup_array_data(client_pointer, array_reader, force)) {
-          return false;
-        }
-        client_pointer += start;
+    }
 
-        for (int i = 0; i < num_elements; ++i) {
-          _glgsg->_glEnableVertexAttribArray(p);
+    GLuint p = bind._id._seqno;
+    max_p = max(max_p, p + 1);
 
-#ifndef OPENGLES
-          if (bind._integer) {
-            _glgsg->_glVertexAttribIPointer(p, num_values, _glgsg->get_numeric_type(numeric_type),
-                                            stride, client_pointer);
-          } else
-#endif
-          if (numeric_type == GeomEnums::NT_packed_dabc) {
-            // GL_BGRA is a special accepted value available since OpenGL 3.2.
-            // It requires us to pass GL_TRUE for normalized.
-            _glgsg->_glVertexAttribPointer(p, GL_BGRA, GL_UNSIGNED_BYTE,
-                                           GL_TRUE, stride, client_pointer);
-          } else {
-            _glgsg->_glVertexAttribPointer(p, num_values,
-                                           _glgsg->get_numeric_type(numeric_type),
-                                           normalized, stride, client_pointer);
-          }
+    // Don't apply vertex colors if they are disabled with a ColorAttrib.
+    int num_elements, element_stride, divisor;
+    bool normalized;
+    if ((p != _color_attrib_index || color_attrib->get_type() == ColorAttrib::T_vertex) &&
+        _glgsg->_data_reader->get_array_info(name, array_reader,
+                                             num_values, numeric_type,
+                                             normalized, start, stride, divisor,
+                                             num_elements, element_stride)) {
+      const unsigned char *client_pointer;
+      if (!_glgsg->setup_array_data(client_pointer, array_reader, force)) {
+        return false;
+      }
+      client_pointer += start;
 
-          if (_glgsg->_supports_vertex_attrib_divisor && divisor > 0) {
-            _glgsg->_glVertexAttribDivisor(p, divisor);
-            _has_divisor = true;
-          }
+      for (int i = 0; i < num_elements; ++i) {
+        _glgsg->enable_vertex_attrib_array(p);
 
-          ++p;
-          client_pointer += element_stride;
+#ifndef OPENGLES
+        if (bind._integer) {
+          _glgsg->_glVertexAttribIPointer(p, num_values, _glgsg->get_numeric_type(numeric_type),
+                                          stride, client_pointer);
+        } else
+#endif
+        if (numeric_type == GeomEnums::NT_packed_dabc) {
+          // GL_BGRA is a special accepted value available since OpenGL 3.2.
+          // It requires us to pass GL_TRUE for normalized.
+          _glgsg->_glVertexAttribPointer(p, GL_BGRA, GL_UNSIGNED_BYTE,
+                                         GL_TRUE, stride, client_pointer);
+        } else {
+          _glgsg->_glVertexAttribPointer(p, num_values,
+                                         _glgsg->get_numeric_type(numeric_type),
+                                         normalized, stride, client_pointer);
         }
-      } else {
-        for (int i = 0; i < bind._elements; ++i) {
-          _glgsg->_glDisableVertexAttribArray(p + i);
+
+        if (divisor > 0) {
+          _glgsg->set_vertex_attrib_divisor(p, divisor);
         }
-        if (p == _color_attrib_index) {
-          // Vertex colors are disabled or not present.  Apply flat color.
+
+        ++p;
+        client_pointer += element_stride;
+      }
+    } else {
+      for (int i = 0; i < bind._elements; ++i) {
+        _glgsg->disable_vertex_attrib_array(p + i);
+      }
+      if (p == _color_attrib_index) {
+        // Vertex colors are disabled or not present.  Apply flat color.
 #ifdef STDFLOAT_DOUBLE
-          _glgsg->_glVertexAttrib4dv(p, color_attrib->get_color().get_data());
+        _glgsg->_glVertexAttrib4dv(p, color_attrib->get_color().get_data());
 #else
-          _glgsg->_glVertexAttrib4fv(p, color_attrib->get_color().get_data());
+        _glgsg->_glVertexAttrib4fv(p, color_attrib->get_color().get_data());
 #endif
-        }
       }
     }
   }
 
+  // Disable attribute arrays we don't use.
+  GLint highest_p = _glgsg->_enabled_vertex_attrib_arrays.get_highest_on_bit() + 1;
+  for (GLint p = max_p; p < highest_p; ++p) {
+    _glgsg->disable_vertex_attrib_array(p);
+  }
+
   if (_transform_table_index >= 0) {
     const TransformTable *table = _glgsg->_data_reader->get_transform_table();
     update_transform_table(table);

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

@@ -102,7 +102,6 @@ private:
   CLP(GraphicsStateGuardian) *_glgsg;
 
   bool _uses_standard_vertex_arrays;
-  bool _has_divisor;
 
   void glsl_report_shader_errors(GLuint shader, Shader::ShaderType type, bool fatal);
   void glsl_report_program_errors(GLuint program, bool fatal);