Browse Source

gl-show-texture-usage

David Rose 17 years ago
parent
commit
4d0d86c7cb

+ 55 - 26
panda/src/glstuff/glGraphicsStateGuardian_src.I

@@ -14,7 +14,7 @@
 
 
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: CLP(GraphicsStateGuardian)::draw_display_list
+//     Function: GLGraphicsStateGuardian::draw_display_list
 //       Access: Public
 //       Access: Public
 //  Description: If the GeomContext is non-NULL and contains a valid
 //  Description: If the GeomContext is non-NULL and contains a valid
 //               display list, uses it to draw the geometry if
 //               display list, uses it to draw the geometry if
@@ -38,7 +38,7 @@ draw_display_list(GeomContext *gc) {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: CLP(GraphicsStateGuardian)::report_errors
+//     Function: GLGraphicsStateGuardian::report_errors
 //       Access: Public, Static
 //       Access: Public, Static
 //  Description: Checks for any outstanding error codes and outputs
 //  Description: Checks for any outstanding error codes and outputs
 //               them, if found.  If NDEBUG is defined, this function
 //               them, if found.  If NDEBUG is defined, this function
@@ -61,7 +61,7 @@ report_errors(int line, const char *source_file) {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: CLP(GraphicsStateGuardian)::report_my_errors
+//     Function: GLGraphicsStateGuardian::report_my_errors
 //       Access: Public
 //       Access: Public
 //  Description: Like report_errors(), above, but non-static so we can
 //  Description: Like report_errors(), above, but non-static so we can
 //               throw an event on failure.
 //               throw an event on failure.
@@ -79,7 +79,7 @@ report_my_errors(int line, const char *source_file) {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: CLP(GraphicsStateGuardian)::get_gl_vendor
+//     Function: GLGraphicsStateGuardian::get_gl_vendor
 //       Access: Public
 //       Access: Public
 //  Description: Returns the GL vendor string reported by the driver.
 //  Description: Returns the GL vendor string reported by the driver.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -89,7 +89,7 @@ get_gl_vendor() const {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: CLP(GraphicsStateGuardian)::get_gl_renderer
+//     Function: GLGraphicsStateGuardian::get_gl_renderer
 //       Access: Public
 //       Access: Public
 //  Description: Returns the GL renderer string reported by the driver.
 //  Description: Returns the GL renderer string reported by the driver.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -99,7 +99,7 @@ get_gl_renderer() const {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: CLP(GraphicsStateGuardian)::get_gl_version
+//     Function: GLGraphicsStateGuardian::get_gl_version
 //       Access: Public
 //       Access: Public
 //  Description: Returns the GL version string reported by the driver.
 //  Description: Returns the GL version string reported by the driver.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -109,7 +109,7 @@ get_gl_version() const {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: CLP(GraphicsStateGuardian)::get_gl_version_major
+//     Function: GLGraphicsStateGuardian::get_gl_version_major
 //       Access: Public
 //       Access: Public
 //  Description: Returns the major part of the reported GL version
 //  Description: Returns the major part of the reported GL version
 //               number.
 //               number.
@@ -120,7 +120,7 @@ get_gl_version_major() const {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: CLP(GraphicsStateGuardian)::get_gl_version_minor
+//     Function: GLGraphicsStateGuardian::get_gl_version_minor
 //       Access: Public
 //       Access: Public
 //  Description: Returns the minor part of the reported GL version
 //  Description: Returns the minor part of the reported GL version
 //               number.
 //               number.
@@ -131,7 +131,7 @@ get_gl_version_minor() const {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: CLP(GraphicsStateGuardian)::get_gl_version_release
+//     Function: GLGraphicsStateGuardian::get_gl_version_release
 //       Access: Public
 //       Access: Public
 //  Description: Returns the release part of the reported GL version
 //  Description: Returns the release part of the reported GL version
 //               number.
 //               number.
@@ -157,7 +157,7 @@ maybe_gl_finish() const {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: CLP(GraphicsStateGuardian)::enable_multisample_antialias
+//     Function: GLGraphicsStateGuardian::enable_multisample_antialias
 //       Access: Protected
 //       Access: Protected
 //  Description: Specifies whether multisample should be enabled for
 //  Description: Specifies whether multisample should be enabled for
 //               antialiasing purposes.
 //               antialiasing purposes.
@@ -182,7 +182,7 @@ enable_multisample_antialias(bool val) {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: CLP(GraphicsStateGuardian)::enable_multisample_alpha_one
+//     Function: GLGraphicsStateGuardian::enable_multisample_alpha_one
 //       Access: Protected
 //       Access: Protected
 //  Description: Specifies whether multisample should be enabled for
 //  Description: Specifies whether multisample should be enabled for
 //               transparency purposes, using the sample_alpha_to_one
 //               transparency purposes, using the sample_alpha_to_one
@@ -210,7 +210,7 @@ enable_multisample_alpha_one(bool val) {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: CLP(GraphicsStateGuardian)::enable_multisample_alpha_mask
+//     Function: GLGraphicsStateGuardian::enable_multisample_alpha_mask
 //       Access: Protected
 //       Access: Protected
 //  Description: Specifies whether multisample should be enabled for
 //  Description: Specifies whether multisample should be enabled for
 //               transparency purposes, using the sample_alpha_to_mask
 //               transparency purposes, using the sample_alpha_to_mask
@@ -238,7 +238,7 @@ enable_multisample_alpha_mask(bool val) {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: CLP(GraphicsStateGuardian)::enable_line_smooth
+//     Function: GLGraphicsStateGuardian::enable_line_smooth
 //       Access:
 //       Access:
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -256,7 +256,7 @@ enable_line_smooth(bool val) {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: CLP(GraphicsStateGuardian)::enable_point_smooth
+//     Function: GLGraphicsStateGuardian::enable_point_smooth
 //       Access:
 //       Access:
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -274,7 +274,7 @@ enable_point_smooth(bool val) {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: CLP(GraphicsStateGuardian)::enable_polygon_smooth
+//     Function: GLGraphicsStateGuardian::enable_polygon_smooth
 //       Access:
 //       Access:
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -291,7 +291,7 @@ enable_polygon_smooth(bool val) {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: CLP(GraphicsStateGuardian)::setup_antialias_line
+//     Function: GLGraphicsStateGuardian::setup_antialias_line
 //       Access: Protected
 //       Access: Protected
 //  Description: Sets the appropriate antialiasing modes to render a
 //  Description: Sets the appropriate antialiasing modes to render a
 //               series of line primitives, according to
 //               series of line primitives, according to
@@ -308,7 +308,7 @@ setup_antialias_line() {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: CLP(GraphicsStateGuardian)::setup_antialias_point
+//     Function: GLGraphicsStateGuardian::setup_antialias_point
 //       Access: Protected
 //       Access: Protected
 //  Description: Sets the appropriate antialiasing modes to render a
 //  Description: Sets the appropriate antialiasing modes to render a
 //               series of point primitives, according to
 //               series of point primitives, according to
@@ -325,7 +325,7 @@ setup_antialias_point() {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: CLP(GraphicsStateGuardian)::setup_antialias_polygon
+//     Function: GLGraphicsStateGuardian::setup_antialias_polygon
 //       Access: Protected
 //       Access: Protected
 //  Description: Sets the appropriate antialiasing modes to render a
 //  Description: Sets the appropriate antialiasing modes to render a
 //               series of point primitives, according to
 //               series of point primitives, according to
@@ -362,7 +362,7 @@ setup_antialias_polygon() {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: CLP(GraphicsStateGuardian)::enable_stencil_test
+//     Function: GLGraphicsStateGuardian::enable_stencil_test
 //       Access:
 //       Access:
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -387,7 +387,7 @@ enable_stencil_test(bool val) {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: CLP(GraphicsStateGuardian)::enable_blend
+//     Function: GLGraphicsStateGuardian::enable_blend
 //       Access:
 //       Access:
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -412,7 +412,7 @@ enable_blend(bool val) {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: CLP(GraphicsStateGuardian)::enable_depth_test
+//     Function: GLGraphicsStateGuardian::enable_depth_test
 //       Access:
 //       Access:
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -437,7 +437,7 @@ enable_depth_test(bool val) {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: CLP(GraphicsStateGuardian)::enable_fog
+//     Function: GLGraphicsStateGuardian::enable_fog
 //       Access:
 //       Access:
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -462,7 +462,7 @@ enable_fog(bool val) {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: CLP(GraphicsStateGuardian)::enable_alpha_test
+//     Function: GLGraphicsStateGuardian::enable_alpha_test
 //       Access:
 //       Access:
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -488,7 +488,7 @@ enable_alpha_test(bool val) {
 
 
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: CLP(GraphicsStateGuardian)::enable_polygon_offset
+//     Function: GLGraphicsStateGuardian::enable_polygon_offset
 //       Access:
 //       Access:
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -517,7 +517,7 @@ enable_polygon_offset(bool val) {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: CLP(GraphicsStateGuardian)::get_light_id
+//     Function: GLGraphicsStateGuardian::get_light_id
 //       Access: Public
 //       Access: Public
 //  Description: Convert index to gl light id
 //  Description: Convert index to gl light id
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -526,7 +526,7 @@ INLINE GLenum CLP(GraphicsStateGuardian)::get_light_id(int index) const {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: CLP(GraphicsStateGuardian)::get_clip_plane_id
+//     Function: GLGraphicsStateGuardian::get_clip_plane_id
 //       Access: Public
 //       Access: Public
 //  Description: Convert index to gl clip plane id
 //  Description: Convert index to gl clip plane id
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -534,3 +534,32 @@ INLINE GLenum CLP(GraphicsStateGuardian)::
 get_clip_plane_id(int index) const {
 get_clip_plane_id(int index) const {
   return GL_CLIP_PLANE0 + index;
   return GL_CLIP_PLANE0 + index;
 }
 }
+
+#ifndef NDEBUG
+////////////////////////////////////////////////////////////////////
+//     Function: GLGraphicsStateGuardian::UsageTextureKey::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE CLP(GraphicsStateGuardian)::UsageTextureKey::
+UsageTextureKey(int x_size, int y_size) :
+  _x_size(x_size),
+  _y_size(y_size)
+{
+}
+#endif  // NDEBUG
+
+#ifndef NDEBUG
+////////////////////////////////////////////////////////////////////
+//     Function: GLGraphicsStateGuardian::UsageTextureKey::operator <
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE bool CLP(GraphicsStateGuardian)::UsageTextureKey::
+operator < (const CLP(GraphicsStateGuardian)::UsageTextureKey &other) const {
+  if (_x_size != other._x_size) {
+    return _x_size < other._x_size;
+  }
+  return _y_size < other._y_size;
+}
+#endif  // NDEBUG

+ 261 - 22
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -1628,6 +1628,35 @@ begin_frame(Thread *current_thread) {
   _primitive_batches_display_list_pcollector.clear_level();
   _primitive_batches_display_list_pcollector.clear_level();
 #endif
 #endif
 
 
+#ifndef NDEBUG
+  _show_texture_usage = false;
+  if (CLP(show_texture_usage)) {
+    // When this is true, then every other second, we show the usage
+    // textures instead of the real textures.
+    double now = ClockObject::get_global_clock()->get_frame_time();
+    int this_second = (int)floor(now);
+    if (this_second & 1) {
+      _show_texture_usage = true;
+      _show_texture_usage_index = this_second >> 1;
+
+      int max_size = CLP(show_texture_usage_max_size);
+      if (max_size != _show_texture_usage_max_size) {
+        // Remove the cache of usage textures; we've changed the max
+        // size.
+        UsageTextures::iterator ui;
+        for (ui = _usage_textures.begin();
+             ui != _usage_textures.end();
+             ++ui) {
+          GLuint index = (*ui).second;
+          GLP(DeleteLists)(index, 1);
+        }
+        _usage_textures.clear();
+        _show_texture_usage_max_size = max_size;
+      }
+    }
+  }
+#endif  // NDEBUG
+
   report_my_gl_errors();
   report_my_gl_errors();
   return true;
   return true;
 }
 }
@@ -2055,11 +2084,18 @@ update_standard_vertex_arrays(bool force) {
 
 
     _sender.add_column(_data_reader, InternalName::get_normal(),
     _sender.add_column(_data_reader, InternalName::get_normal(),
                        NULL, NULL, GLP(Normal3f), NULL);
                        NULL, NULL, GLP(Normal3f), NULL);
-    if (!_sender.add_column(_data_reader, InternalName::get_color(),
-                            NULL, NULL, GLP(Color3f), GLP(Color4f))) {
-      // If we didn't have a color column, the item color is white.
+#ifndef NDEBUG
+    if (_show_texture_usage) {
+      // In show_texture_usage mode, all colors are white, so as not
+      // to contaminate the texture color.
       GLP(Color4f)(1.0f, 1.0f, 1.0f, 1.0f);
       GLP(Color4f)(1.0f, 1.0f, 1.0f, 1.0f);
-    }
+    } else
+#endif // NDEBUG
+      if (!_sender.add_column(_data_reader, InternalName::get_color(),
+                              NULL, NULL, GLP(Color3f), GLP(Color4f))) {
+        // If we didn't have a color column, the item color is white.
+        GLP(Color4f)(1.0f, 1.0f, 1.0f, 1.0f);
+      }
 
 
     // Now set up each of the active texture coordinate stages--or at
     // Now set up each of the active texture coordinate stages--or at
     // least those for which we're not generating texture coordinates
     // least those for which we're not generating texture coordinates
@@ -2140,22 +2176,30 @@ update_standard_vertex_arrays(bool force) {
       GLP(DisableClientState)(GL_NORMAL_ARRAY);
       GLP(DisableClientState)(GL_NORMAL_ARRAY);
     }
     }
     
     
-    if (_data_reader->get_color_info(array_reader, num_values, numeric_type,
-                                     start, stride) &&
-        numeric_type != Geom::NT_packed_dabc) {
-      if (!setup_array_data(client_pointer, array_reader, force)) {
-        return false;
-      }
-      GLP(ColorPointer)(num_values, get_numeric_type(numeric_type),
-                        stride, client_pointer + start);
-      GLP(EnableClientState)(GL_COLOR_ARRAY);
-    } else {
+#ifndef NDEBUG
+    if (_show_texture_usage) {
+      // In show_texture_usage mode, all colors are white, so as not
+      // to contaminate the texture color.
       GLP(DisableClientState)(GL_COLOR_ARRAY);
       GLP(DisableClientState)(GL_COLOR_ARRAY);
-      
-      // Since we don't have per-vertex color, the implicit color is
-      // white.
       GLP(Color4f)(1.0f, 1.0f, 1.0f, 1.0f);
       GLP(Color4f)(1.0f, 1.0f, 1.0f, 1.0f);
-    }
+    } else
+#endif // NDEBUG
+      if (_data_reader->get_color_info(array_reader, num_values, numeric_type,
+                                       start, stride) &&
+          numeric_type != Geom::NT_packed_dabc) {
+        if (!setup_array_data(client_pointer, array_reader, force)) {
+          return false;
+        }
+        GLP(ColorPointer)(num_values, get_numeric_type(numeric_type),
+                          stride, client_pointer + start);
+        GLP(EnableClientState)(GL_COLOR_ARRAY);
+      } else {
+        GLP(DisableClientState)(GL_COLOR_ARRAY);
+        
+        // Since we don't have per-vertex color, the implicit color is
+        // white.
+        GLP(Color4f)(1.0f, 1.0f, 1.0f, 1.0f);
+      }
     
     
     // Now set up each of the active texture coordinate stages--or at
     // Now set up each of the active texture coordinate stages--or at
     // least those for which we're not generating texture coordinates
     // least those for which we're not generating texture coordinates
@@ -4005,6 +4049,18 @@ do_issue_material() {
     material = target_material->get_material();
     material = target_material->get_material();
   }
   }
 
 
+  bool has_material_force_color = _has_material_force_color;
+
+#ifndef NDEBUG
+  if (_show_texture_usage) {
+    // In show_texture_usage mode, all colors are white, so as not
+    // to contaminate the texture color.  This means we disable
+    // lighting materials too.
+    material = &empty;
+    has_material_force_color = false;
+  }
+#endif  // NDEBUG
+
   GLenum face = material->get_twoside() ? GL_FRONT_AND_BACK : GL_FRONT;
   GLenum face = material->get_twoside() ? GL_FRONT_AND_BACK : GL_FRONT;
 
 
   GLP(Materialfv)(face, GL_SPECULAR, material->get_specular().get_data());
   GLP(Materialfv)(face, GL_SPECULAR, material->get_specular().get_data());
@@ -4022,7 +4078,7 @@ do_issue_material() {
     // The material specifies an ambient, but not a diffuse component.
     // The material specifies an ambient, but not a diffuse component.
     // The diffuse component comes from the object's color.
     // The diffuse component comes from the object's color.
     GLP(Materialfv)(face, GL_AMBIENT, material->get_ambient().get_data());
     GLP(Materialfv)(face, GL_AMBIENT, material->get_ambient().get_data());
-    if (_has_material_force_color) {
+    if (has_material_force_color) {
       GLP(Disable)(GL_COLOR_MATERIAL);
       GLP(Disable)(GL_COLOR_MATERIAL);
       GLP(Materialfv)(face, GL_DIFFUSE, _material_force_color.get_data());
       GLP(Materialfv)(face, GL_DIFFUSE, _material_force_color.get_data());
     } else {
     } else {
@@ -4034,7 +4090,7 @@ do_issue_material() {
     // The material specifies a diffuse, but not an ambient component.
     // The material specifies a diffuse, but not an ambient component.
     // The ambient component comes from the object's color.
     // The ambient component comes from the object's color.
     GLP(Materialfv)(face, GL_DIFFUSE, material->get_diffuse().get_data());
     GLP(Materialfv)(face, GL_DIFFUSE, material->get_diffuse().get_data());
-    if (_has_material_force_color) {
+    if (has_material_force_color) {
       GLP(Disable)(GL_COLOR_MATERIAL);
       GLP(Disable)(GL_COLOR_MATERIAL);
       GLP(Materialfv)(face, GL_AMBIENT, _material_force_color.get_data());
       GLP(Materialfv)(face, GL_AMBIENT, _material_force_color.get_data());
     } else {
     } else {
@@ -4045,7 +4101,7 @@ do_issue_material() {
   } else {
   } else {
     // The material specifies neither a diffuse nor an ambient
     // The material specifies neither a diffuse nor an ambient
     // component.  Both components come from the object's color.
     // component.  Both components come from the object's color.
-    if (_has_material_force_color) {
+    if (has_material_force_color) {
       GLP(Disable)(GL_COLOR_MATERIAL);
       GLP(Disable)(GL_COLOR_MATERIAL);
       GLP(Materialfv)(face, GL_AMBIENT, _material_force_color.get_data());
       GLP(Materialfv)(face, GL_AMBIENT, _material_force_color.get_data());
       GLP(Materialfv)(face, GL_DIFFUSE, _material_force_color.get_data());
       GLP(Materialfv)(face, GL_DIFFUSE, _material_force_color.get_data());
@@ -5780,6 +5836,18 @@ print_gfx_visual() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 float *CLP(GraphicsStateGuardian)::
 float *CLP(GraphicsStateGuardian)::
 get_light_color(float light_color[4], Light *light) const {
 get_light_color(float light_color[4], Light *light) const {
+#ifndef NDEBUG
+  if (_show_texture_usage) {
+    // In show_texture_usage mode, all lights are white, so as not to
+    // contaminate the texture color.
+    light_color[0] = 1.0f;
+    light_color[1] = 1.0f;
+    light_color[2] = 1.0f;
+    light_color[3] = 1.0f;
+    return light_color;
+  }
+#endif  // NDEBUG
+
   const Colorf &c = light->get_color();
   const Colorf &c = light->get_color();
 
 
   light_color[0] = c[0] * _light_color_scale[0];
   light_color[0] = c[0] * _light_color_scale[0];
@@ -6347,10 +6415,19 @@ do_issue_texture() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GLGraphicsStateGuardian::update_standard_texture_bindings
 //     Function: GLGraphicsStateGuardian::update_standard_texture_bindings
 //       Access: Private
 //       Access: Private
-//  Description:
+//  Description: Applies the appropriate set of textures for the
+//               current state, using the standard fixed-function
+//               pipeline.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsStateGuardian)::
 void CLP(GraphicsStateGuardian)::
 update_standard_texture_bindings() {
 update_standard_texture_bindings() {
+#ifndef NDEBUG
+  if (_show_texture_usage) {
+    update_show_usage_texture_bindings();
+    return;
+  }
+#endif // NDEBUG
+
   int num_stages = _target_texture->get_num_on_ff_stages();
   int num_stages = _target_texture->get_num_on_ff_stages();
 
 
   nassertv(num_stages <= _max_texture_stages &&
   nassertv(num_stages <= _max_texture_stages &&
@@ -6540,6 +6617,168 @@ update_standard_texture_bindings() {
 }
 }
 
 
 
 
+#ifndef NDEBUG
+////////////////////////////////////////////////////////////////////
+//     Function: GLGraphicsStateGuardian::update_show_usage_texture_bindings
+//       Access: Private
+//  Description: This is a special function that loads the usage
+//               textures in gl-show-texture-usage mode, instead of
+//               loading the actual used textures.
+////////////////////////////////////////////////////////////////////
+void CLP(GraphicsStateGuardian)::
+update_show_usage_texture_bindings() {
+  int num_stages = _target_texture->get_num_on_ff_stages();
+
+  nassertv(num_stages <= _max_texture_stages &&
+           _num_active_texture_stages <= _max_texture_stages);
+
+  _texture_involves_color_scale = false;
+
+  // First, we walk through the list of textures and pretend to render
+  // them all, even though we don't actually render them, just so
+  // Panda will keep track of the list of "active" textures correctly
+  // during the flash.
+  int i;
+  for (i = 0; i < num_stages; i++) {
+    TextureStage *stage = _target_texture->get_on_ff_stage(i);
+    Texture *texture = _target_texture->get_on_texture(stage);
+    nassertv(texture != (Texture *)NULL);
+
+    TextureContext *tc = texture->prepare_now(_prepared_objects, this);
+    if (tc == (TextureContext *)NULL) {
+      // Something wrong with this texture; skip it.
+      break;
+    }
+    tc->enqueue_lru(&_prepared_objects->_graphics_memory_lru);
+  }
+
+  // Disable all texture stages.
+  for (i = 0; i < _num_active_texture_stages; i++) {
+    _glActiveTexture(GL_TEXTURE0 + i);
+    GLP(Disable)(GL_TEXTURE_1D);
+    GLP(Disable)(GL_TEXTURE_2D);
+    if (_supports_3d_texture) {
+      GLP(Disable)(GL_TEXTURE_3D);
+    }
+    if (_supports_cube_map) {
+      GLP(Disable)(GL_TEXTURE_CUBE_MAP);
+    }
+  }
+  
+  // Save the count of texture stages for next time.
+  _num_active_texture_stages = num_stages;
+
+  if (num_stages > 0) {
+    // Now, pick just one texture stage to apply.
+    i = _show_texture_usage_index % num_stages;
+
+    TextureStage *stage = _target_texture->get_on_ff_stage(i);
+    Texture *texture = _target_texture->get_on_texture(stage);
+    nassertv(texture != (Texture *)NULL);
+
+    // Choose the corresponding usage texture and apply it.
+    _glActiveTexture(GL_TEXTURE0 + i);
+    GLP(Enable)(GL_TEXTURE_2D);
+
+    UsageTextureKey key(texture->get_x_size(), texture->get_y_size());
+    UsageTextures::iterator ui = _usage_textures.find(key);
+    if (ui == _usage_textures.end()) {
+      // Need to create a new texture for this size.
+      GLuint index;
+      GLP(GenTextures)(1, &index);
+      GLP(BindTexture)(GL_TEXTURE_2D, index);
+      upload_usage_texture(texture->get_x_size(), texture->get_y_size());
+      _usage_textures[key] = index;
+
+    } else {
+      // Just bind the previously-created texture.
+      GLuint index = (*ui).second;
+      GLP(BindTexture)(GL_TEXTURE_2D, index);
+    }
+  }
+
+  report_my_gl_errors();
+}
+#endif  // NDEBUG
+
+#ifndef NDEBUG
+////////////////////////////////////////////////////////////////////
+//     Function: GLGraphicsStateGuardian::upload_usage_texture
+//       Access: Protected
+//  Description: Uploads a special "usage" texture intended to be
+//               applied only in gl-show-texture-usage mode, to reveal
+//               where texure memory is being spent.
+////////////////////////////////////////////////////////////////////
+void CLP(GraphicsStateGuardian)::
+upload_usage_texture(int width, int height) {
+  GLP(TexParameteri)(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+  GLP(TexParameteri)(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+  GLP(TexParameteri)(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+  GLP(TexParameteri)(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+  // Get the color and scale appropriate to this level.
+  int max_size = _show_texture_usage_max_size;
+  float scale = (double)(width * height) / (max_size * max_size);
+  scale = csqrt(min(scale, 1.0f)) * 0.8f + 0.2f;
+
+  if (GLCAT.is_debug()) {
+    GLCAT.debug()
+      << "upload_usage_texture(" << width << ", " << height
+      << "), scale = " << scale << "\n";
+  }
+
+  static Colorf colors[3] = {
+    Colorf(0.0f, 0.0f, 1.0f, 1.0f),   // mipmap 0: blue
+    Colorf(1.0f, 1.0f, 1.0f, 1.0f),   // mipmap 1: white
+    Colorf(1.0f, 0.0f, 0.0f, 1.0f),   // mipmap 2 and higher: red
+  };
+
+
+  // Allocate a temporary array large enough to contain the toplevel
+  // mipmap.
+  PN_uint32 *buffer = (PN_uint32 *)PANDA_MALLOC_ARRAY(width * height * 4);
+
+  int n = 0;
+  while (true) {
+    // Choose the color for the nth mipmap.
+    Colorf c = colors[min(n, 2)] * scale;
+
+    // A simple union to store the colors values bytewise, and get the
+    // answer wordwise, independently of machine byte-ordernig.
+    union {
+      struct { 
+        char r, g, b, a;
+      } b;
+      PN_uint32 w;
+    } store;
+
+    store.b.r = (int)(c[0] * 255.0f);
+    store.b.g = (int)(c[1] * 255.0f);
+    store.b.b = (int)(c[2] * 255.0f);
+    store.b.a = 0xff;
+
+    // Fill in the array.
+    int num_pixels = width * height;
+    for (int p = 0; p < num_pixels; ++p) {
+      buffer[p] = store.w;
+    }
+    
+    GLP(TexImage2D)(GL_TEXTURE_2D, n, GL_RGBA, width, height, 0,
+                    GL_RGBA, GL_UNSIGNED_BYTE, buffer);
+    if (width == 1 && height == 1) {
+      // That was the last mipmap level.
+      break;
+    }
+
+    width = max(width >> 1, 1);
+    height = max(height >> 1, 1);
+    ++n;
+  }
+
+  PANDA_FREE_ARRAY(buffer);
+}
+#endif  // NDEBUG
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GLGraphicsStateGuardian::disable_standard_texture_bindings
 //     Function: GLGraphicsStateGuardian::disable_standard_texture_bindings
 //       Access: Private
 //       Access: Private

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

@@ -323,6 +323,11 @@ protected:
   void disable_standard_texture_bindings();
   void disable_standard_texture_bindings();
   void update_standard_texture_bindings();
   void update_standard_texture_bindings();
 
 
+#ifndef NDEBUG
+  void update_show_usage_texture_bindings();
+  void upload_usage_texture(int width, int height);
+#endif  // NDEBUG
+
   void do_auto_rescale_normal();
   void do_auto_rescale_normal();
   bool specify_texture(CLP(TextureContext) *gtc);
   bool specify_texture(CLP(TextureContext) *gtc);
   bool apply_texture(TextureContext *tc);
   bool apply_texture(TextureContext *tc);
@@ -521,6 +526,23 @@ public:
 
 
   RenderState::SlotMask _inv_state_mask;
   RenderState::SlotMask _inv_state_mask;
 
 
+#ifndef NDEBUG
+  bool _show_texture_usage;
+  int _show_texture_usage_max_size;
+  int _show_texture_usage_index;
+
+  class UsageTextureKey {
+  public:
+    INLINE UsageTextureKey(int x_size, int y_size);
+    INLINE bool operator < (const UsageTextureKey &other) const;
+
+    int _x_size;
+    int _y_size;
+  };
+  typedef pmap<UsageTextureKey, GLuint> UsageTextures;
+  UsageTextures _usage_textures;
+#endif  // NDEBUG
+
   static PStatCollector _load_display_list_pcollector;
   static PStatCollector _load_display_list_pcollector;
   static PStatCollector _primitive_batches_display_list_pcollector;
   static PStatCollector _primitive_batches_display_list_pcollector;
   static PStatCollector _vertices_display_list_pcollector;
   static PStatCollector _vertices_display_list_pcollector;

+ 15 - 0
panda/src/glstuff/glmisc_src.cxx

@@ -52,6 +52,21 @@ ConfigVariableBool CLP(force_mipmaps)
    PRC_DESC("Configure this true to enable full trilinear mipmapping on every "
    PRC_DESC("Configure this true to enable full trilinear mipmapping on every "
             "texture, whether it asks for it or not."));
             "texture, whether it asks for it or not."));
 
 
+ConfigVariableBool CLP(show_texture_usage)
+  ("gl-show-texture-usage", false,
+   PRC_DESC("If you set this true, the screen will flash with textures drawn "
+            "in a special mode that shows the mipmap detail level and texture "
+            "size for each texture.  Textures will be drawn in blue for "
+            "mipmap level 0, gray for mipmap level 1, and red for all higher "
+            "mipmap levels.  Brighter colors represent larger textures."));
+
+ConfigVariableInt CLP(show_texture_usage_max_size)
+  ("gl-show-texture-usage-max-size", 1024,
+   PRC_DESC("Specifies the texture size (along one side) of the largest "
+            "texture expected to be loaded.  This controls the assignment "
+            "of the texture color in gl-show-texture-usage mode; colors "
+            "will be fully bright for textures of this size or larger."));
+
 ConfigVariableBool CLP(color_mask)
 ConfigVariableBool CLP(color_mask)
   ("gl-color-mask", true,
   ("gl-color-mask", true,
    PRC_DESC("Configure this false if your GL's implementation of glColorMask() "
    PRC_DESC("Configure this false if your GL's implementation of glColorMask() "

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

@@ -26,6 +26,8 @@ extern ConfigVariableBool CLP(support_clamp_to_border);
 extern ConfigVariableBool CLP(ignore_filters);
 extern ConfigVariableBool CLP(ignore_filters);
 extern ConfigVariableBool CLP(ignore_mipmaps);
 extern ConfigVariableBool CLP(ignore_mipmaps);
 extern ConfigVariableBool CLP(force_mipmaps);
 extern ConfigVariableBool CLP(force_mipmaps);
+extern ConfigVariableBool CLP(show_texture_usage);
+extern ConfigVariableInt CLP(show_texture_usage_max_size);
 extern ConfigVariableBool CLP(color_mask);
 extern ConfigVariableBool CLP(color_mask);
 extern ConfigVariableBool CLP(support_occlusion_query);
 extern ConfigVariableBool CLP(support_occlusion_query);
 extern ConfigVariableBool CLP(compile_and_execute);
 extern ConfigVariableBool CLP(compile_and_execute);