Ver código fonte

better pstats tracking of texture/vbuffer memory

David Rose 20 anos atrás
pai
commit
83a6c42496
56 arquivos alterados com 1362 adições e 716 exclusões
  1. 2 136
      panda/src/display/graphicsStateGuardian.cxx
  2. 0 35
      panda/src/display/graphicsStateGuardian.h
  3. 19 37
      panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx
  4. 2 2
      panda/src/dxgsg8/dxIndexBufferContext8.cxx
  5. 1 1
      panda/src/dxgsg8/dxIndexBufferContext8.h
  6. 59 60
      panda/src/dxgsg8/dxTextureContext8.cxx
  7. 1 1
      panda/src/dxgsg8/dxTextureContext8.h
  8. 2 2
      panda/src/dxgsg8/dxVertexBufferContext8.cxx
  9. 1 1
      panda/src/dxgsg8/dxVertexBufferContext8.h
  10. 19 36
      panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx
  11. 2 2
      panda/src/dxgsg9/dxIndexBufferContext9.cxx
  12. 1 1
      panda/src/dxgsg9/dxIndexBufferContext9.h
  13. 61 62
      panda/src/dxgsg9/dxTextureContext9.cxx
  14. 1 1
      panda/src/dxgsg9/dxTextureContext9.h
  15. 2 2
      panda/src/dxgsg9/dxVertexBufferContext9.cxx
  16. 1 1
      panda/src/dxgsg9/dxVertexBufferContext9.h
  17. 4 4
      panda/src/express/pipelineCyclerLinks.I
  18. 65 24
      panda/src/glstuff/glGraphicsStateGuardian_src.cxx
  19. 1 0
      panda/src/glstuff/glGraphicsStateGuardian_src.h
  20. 2 2
      panda/src/glstuff/glIndexBufferContext_src.I
  21. 2 1
      panda/src/glstuff/glIndexBufferContext_src.h
  22. 2 3
      panda/src/glstuff/glTextureContext_src.I
  23. 0 17
      panda/src/glstuff/glTextureContext_src.cxx
  24. 1 5
      panda/src/glstuff/glTextureContext_src.h
  25. 2 2
      panda/src/glstuff/glVertexBufferContext_src.I
  26. 2 1
      panda/src/glstuff/glVertexBufferContext_src.h
  27. 9 0
      panda/src/gobj/Sources.pp
  28. 158 0
      panda/src/gobj/bufferContext.I
  29. 36 0
      panda/src/gobj/bufferContext.cxx
  30. 97 0
      panda/src/gobj/bufferContext.h
  31. 73 0
      panda/src/gobj/bufferContextChain.I
  32. 62 0
      panda/src/gobj/bufferContextChain.cxx
  33. 61 0
      panda/src/gobj/bufferContextChain.h
  34. 58 0
      panda/src/gobj/bufferResidencyTracker.I
  35. 92 0
      panda/src/gobj/bufferResidencyTracker.cxx
  36. 92 0
      panda/src/gobj/bufferResidencyTracker.h
  37. 2 0
      panda/src/gobj/config_gobj.cxx
  38. 3 1
      panda/src/gobj/gobj_composite1.cxx
  39. 10 33
      panda/src/gobj/indexBufferContext.I
  40. 6 10
      panda/src/gobj/indexBufferContext.h
  41. 12 0
      panda/src/gobj/preparedGraphicsObjects.I
  42. 49 31
      panda/src/gobj/preparedGraphicsObjects.cxx
  43. 16 3
      panda/src/gobj/preparedGraphicsObjects.h
  44. 12 0
      panda/src/gobj/texture.I
  45. 13 60
      panda/src/gobj/texture.cxx
  46. 4 18
      panda/src/gobj/texture.h
  47. 28 49
      panda/src/gobj/textureContext.I
  48. 15 14
      panda/src/gobj/textureContext.h
  49. 10 33
      panda/src/gobj/vertexBufferContext.I
  50. 7 10
      panda/src/gobj/vertexBufferContext.h
  51. 1 15
      panda/src/pstatclient/pStatProperties.cxx
  52. 3 0
      panda/src/putil/Sources.pp
  53. 108 0
      panda/src/putil/linkedListNode.I
  54. 19 0
      panda/src/putil/linkedListNode.cxx
  55. 50 0
      panda/src/putil/linkedListNode.h
  56. 1 0
      panda/src/putil/putil_composite1.cxx

+ 2 - 136
panda/src/display/graphicsStateGuardian.cxx

@@ -39,10 +39,6 @@
 #include <algorithm>
 #include <algorithm>
 #include <limits.h>
 #include <limits.h>
 
 
-PStatCollector GraphicsStateGuardian::_total_texusage_pcollector("Texture usage");
-PStatCollector GraphicsStateGuardian::_active_texusage_pcollector("Texture usage:Active");
-PStatCollector GraphicsStateGuardian::_texture_count_pcollector("Prepared Textures");
-PStatCollector GraphicsStateGuardian::_active_texture_count_pcollector("Prepared Textures:Active");
 PStatCollector GraphicsStateGuardian::_vertex_buffer_switch_pcollector("Vertex buffer switch:Vertex");
 PStatCollector GraphicsStateGuardian::_vertex_buffer_switch_pcollector("Vertex buffer switch:Vertex");
 PStatCollector GraphicsStateGuardian::_index_buffer_switch_pcollector("Vertex buffer switch:Index");
 PStatCollector GraphicsStateGuardian::_index_buffer_switch_pcollector("Vertex buffer switch:Index");
 PStatCollector GraphicsStateGuardian::_load_vertex_buffer_pcollector("Draw:Transfer data:Vertex buffer");
 PStatCollector GraphicsStateGuardian::_load_vertex_buffer_pcollector("Draw:Transfer data:Vertex buffer");
@@ -51,15 +47,6 @@ PStatCollector GraphicsStateGuardian::_create_vertex_buffer_pcollector("Draw:Tra
 PStatCollector GraphicsStateGuardian::_create_index_buffer_pcollector("Draw:Transfer data:Create Index buffer");
 PStatCollector GraphicsStateGuardian::_create_index_buffer_pcollector("Draw:Transfer data:Create Index buffer");
 PStatCollector GraphicsStateGuardian::_load_texture_pcollector("Draw:Transfer data:Texture");
 PStatCollector GraphicsStateGuardian::_load_texture_pcollector("Draw:Transfer data:Texture");
 PStatCollector GraphicsStateGuardian::_data_transferred_pcollector("Data transferred");
 PStatCollector GraphicsStateGuardian::_data_transferred_pcollector("Data transferred");
-PStatCollector GraphicsStateGuardian::_total_geom_pcollector("Prepared Geoms");
-PStatCollector GraphicsStateGuardian::_active_geom_pcollector("Prepared Geoms:Active");
-PStatCollector GraphicsStateGuardian::_total_buffers_pcollector("Vertex buffer size");
-PStatCollector GraphicsStateGuardian::_active_vertex_buffers_pcollector("Vertex buffer size:Active vertex");
-PStatCollector GraphicsStateGuardian::_active_index_buffers_pcollector("Vertex buffer size:Active index");
-PStatCollector GraphicsStateGuardian::_total_geom_node_pcollector("Prepared GeomNodes");
-PStatCollector GraphicsStateGuardian::_active_geom_node_pcollector("Prepared GeomNodes:Active");
-PStatCollector GraphicsStateGuardian::_total_texmem_pcollector("Texture memory");
-PStatCollector GraphicsStateGuardian::_used_texmem_pcollector("Texture memory:In use");
 PStatCollector GraphicsStateGuardian::_texmgrmem_total_pcollector("Texture manager");
 PStatCollector GraphicsStateGuardian::_texmgrmem_total_pcollector("Texture manager");
 PStatCollector GraphicsStateGuardian::_texmgrmem_resident_pcollector("Texture manager:Resident");
 PStatCollector GraphicsStateGuardian::_texmgrmem_resident_pcollector("Texture manager:Resident");
 PStatCollector GraphicsStateGuardian::_primitive_batches_pcollector("Primitive batches");
 PStatCollector GraphicsStateGuardian::_primitive_batches_pcollector("Primitive batches");
@@ -964,11 +951,7 @@ prepare_lens() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool GraphicsStateGuardian::
 bool GraphicsStateGuardian::
 begin_frame() {
 begin_frame() {
-  // Now we know the GSG is the currently active context, so this is a
-  // good time to release any textures or geoms that had been queued
-  // up to release in the past frame, and load up any newly requested
-  // textures.
-  _prepared_objects->update(this);
+  _prepared_objects->begin_frame(this);
 
 
 #ifdef DO_PSTATS
 #ifdef DO_PSTATS
   // For Pstats to track our current texture memory usage, we have to
   // For Pstats to track our current texture memory usage, we have to
@@ -1005,6 +988,7 @@ begin_frame() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool GraphicsStateGuardian::
 bool GraphicsStateGuardian::
 begin_scene() {
 begin_scene() {
+  _prepared_objects->end_frame();
   return true;
   return true;
 }
 }
 
 
@@ -1879,7 +1863,6 @@ determine_light_color_scale() {
 }
 }
 
 
 #ifdef DO_PSTATS
 #ifdef DO_PSTATS
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::init_frame_pstats
 //     Function: GraphicsStateGuardian::init_frame_pstats
 //       Access: Protected
 //       Access: Protected
@@ -1889,16 +1872,7 @@ determine_light_color_scale() {
 void GraphicsStateGuardian::
 void GraphicsStateGuardian::
 init_frame_pstats() {
 init_frame_pstats() {
   if (PStatClient::is_connected()) {
   if (PStatClient::is_connected()) {
-    _current_textures.clear();
-    _current_geoms.clear();
-    _current_vertex_buffers.clear();
-    _current_index_buffers.clear();
-    _active_texusage_pcollector.clear_level();
     _data_transferred_pcollector.clear_level();
     _data_transferred_pcollector.clear_level();
-    _active_geom_pcollector.clear_level();
-    _active_geom_node_pcollector.clear_level();
-    _active_vertex_buffers_pcollector.clear_level();
-    _active_index_buffers_pcollector.clear_level();
     _vertex_buffer_switch_pcollector.clear_level();
     _vertex_buffer_switch_pcollector.clear_level();
     _index_buffer_switch_pcollector.clear_level();
     _index_buffer_switch_pcollector.clear_level();
     
     
@@ -1918,114 +1892,6 @@ init_frame_pstats() {
     _texture_state_pcollector.clear_level();
     _texture_state_pcollector.clear_level();
   }
   }
 }
 }
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsStateGuardian::add_to_texture_record
-//       Access: Protected
-//  Description: Records that the indicated texture has been applied
-//               this frame, and thus must be present in current
-//               texture memory.  This function is only used to update
-//               the PStats current_texmem collector; it gets compiled
-//               out if we aren't using PStats.
-////////////////////////////////////////////////////////////////////
-void GraphicsStateGuardian::
-add_to_texture_record(TextureContext *tc) {
-  if (PStatClient::is_connected()) {
-    if (_current_textures.insert(tc).second) {
-      _active_texusage_pcollector.add_level(tc->estimate_texture_memory());
-    }
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsStateGuardian::add_to_geom_record
-//       Access: Protected
-//  Description: Records that the indicated Geom has been drawn this
-//               frame.  This function is only used to update the
-//               PStats active_geom collector; it gets compiled out
-//               if we aren't using PStats.
-////////////////////////////////////////////////////////////////////
-void GraphicsStateGuardian::
-add_to_geom_record(GeomContext *gc) {
-  if (PStatClient::is_connected()) {
-    if (gc != (GeomContext *)NULL && _current_geoms.insert(gc).second) {
-      _active_geom_pcollector.add_level(1);
-    }
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsStateGuardian::add_to_vertex_buffer_record
-//       Access: Protected
-//  Description: Records that the indicated data array has been drawn
-//               this frame.  This function is only used to update the
-//               PStats active_vertex_buffers collector; it gets
-//               compiled out if we aren't using PStats.
-////////////////////////////////////////////////////////////////////
-void GraphicsStateGuardian::
-add_to_vertex_buffer_record(VertexBufferContext *vbc) {
-  if (vbc != (VertexBufferContext *)NULL) {
-    if (PStatClient::is_connected()) {
-      _vertex_buffer_switch_pcollector.add_level(1);
-      if (_current_vertex_buffers.insert(vbc).second) {
-        _active_vertex_buffers_pcollector.add_level(vbc->get_data()->get_data_size_bytes());
-      }
-    }
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsStateGuardian::add_to_index_buffer_record
-//       Access: Protected
-//  Description: Records that the indicated data array has been drawn
-//               this frame.  This function is only used to update the
-//               PStats active_index_buffers collector; it gets compiled out
-//               if we aren't using PStats.
-////////////////////////////////////////////////////////////////////
-void GraphicsStateGuardian::
-add_to_index_buffer_record(IndexBufferContext *ibc) {
-  if (ibc != (IndexBufferContext *)NULL) {
-    if (PStatClient::is_connected()) {
-      _index_buffer_switch_pcollector.add_level(1);
-      if (_current_index_buffers.insert(ibc).second) {
-        _active_index_buffers_pcollector.add_level(ibc->get_data()->get_data_size_bytes());
-      }
-    }
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsStateGuardian::add_to_total_buffer_record
-//       Access: Protected
-//  Description: Records that the indicated data array has been loaded
-//               this frame.  This function is only used to update the
-//               PStats total_buffers collector; it gets
-//               compiled out if we aren't using PStats.
-////////////////////////////////////////////////////////////////////
-void GraphicsStateGuardian::
-add_to_total_buffer_record(VertexBufferContext *vbc) {
-  if (vbc != (VertexBufferContext *)NULL) {
-    int delta = vbc->get_data()->get_data_size_bytes() - vbc->get_data_size_bytes();
-    _total_buffers_pcollector.add_level(delta);
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsStateGuardian::add_to_total_buffer_record
-//       Access: Protected
-//  Description: Records that the indicated data array has been loaded
-//               this frame.  This function is only used to update the
-//               PStats total_buffers collector; it gets
-//               compiled out if we aren't using PStats.
-////////////////////////////////////////////////////////////////////
-void GraphicsStateGuardian::
-add_to_total_buffer_record(IndexBufferContext *ibc) {
-  if (ibc != (IndexBufferContext *)NULL) {
-    int delta = ibc->get_data()->get_data_size_bytes() - ibc->get_data_size_bytes();
-    _total_buffers_pcollector.add_level(delta);
-  }
-}
-
 #endif  // DO_PSTATS
 #endif  // DO_PSTATS
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 0 - 35
panda/src/display/graphicsStateGuardian.h

@@ -247,29 +247,7 @@ protected:
   INLINE void set_properties(const FrameBufferProperties &properties);
   INLINE void set_properties(const FrameBufferProperties &properties);
 
 
 #ifdef DO_PSTATS
 #ifdef DO_PSTATS
-  // These functions are used to update the active texture memory
-  // usage record (and other frame-based measurements) in Pstats.
   void init_frame_pstats();
   void init_frame_pstats();
-  void add_to_texture_record(TextureContext *tc);
-  void add_to_geom_record(GeomContext *gc);
-  void add_to_vertex_buffer_record(VertexBufferContext *vbc);
-  void add_to_index_buffer_record(IndexBufferContext *ibc);
-  void add_to_total_buffer_record(VertexBufferContext *vbc);
-  void add_to_total_buffer_record(IndexBufferContext *ibc);
-
-  pset<TextureContext *> _current_textures;
-  pset<GeomContext *> _current_geoms;
-  pset<VertexBufferContext *> _current_vertex_buffers;
-  pset<IndexBufferContext *> _current_index_buffers;
-#else
-  INLINE void init_frame_pstats() { }
-  INLINE void add_to_texture_record(TextureContext *) { }
-  INLINE void add_to_geom_record(GeomContext *) { }
-  INLINE void record_state_change(TypeHandle) { }
-  INLINE void add_to_vertex_buffer_record(VertexBufferContext *) { }
-  INLINE void add_to_index_buffer_record(IndexBufferContext *) { }
-  INLINE void add_to_total_buffer_record(VertexBufferContext *) { };
-  INLINE void add_to_total_buffer_record(IndexBufferContext *) { };
 #endif
 #endif
 
 
   static CPT(RenderState) get_unlit_state();
   static CPT(RenderState) get_unlit_state();
@@ -374,10 +352,6 @@ protected:
   
   
 public:
 public:
   // Statistics
   // Statistics
-  static PStatCollector _total_texusage_pcollector;
-  static PStatCollector _active_texusage_pcollector;
-  static PStatCollector _texture_count_pcollector;
-  static PStatCollector _active_texture_count_pcollector;
   static PStatCollector _vertex_buffer_switch_pcollector;
   static PStatCollector _vertex_buffer_switch_pcollector;
   static PStatCollector _index_buffer_switch_pcollector;
   static PStatCollector _index_buffer_switch_pcollector;
   static PStatCollector _load_vertex_buffer_pcollector;
   static PStatCollector _load_vertex_buffer_pcollector;
@@ -386,15 +360,6 @@ public:
   static PStatCollector _create_index_buffer_pcollector;
   static PStatCollector _create_index_buffer_pcollector;
   static PStatCollector _load_texture_pcollector;
   static PStatCollector _load_texture_pcollector;
   static PStatCollector _data_transferred_pcollector;
   static PStatCollector _data_transferred_pcollector;
-  static PStatCollector _total_geom_pcollector;
-  static PStatCollector _active_geom_pcollector;
-  static PStatCollector _total_buffers_pcollector;
-  static PStatCollector _active_vertex_buffers_pcollector;
-  static PStatCollector _active_index_buffers_pcollector;
-  static PStatCollector _total_geom_node_pcollector;
-  static PStatCollector _active_geom_node_pcollector;
-  static PStatCollector _total_texmem_pcollector;
-  static PStatCollector _used_texmem_pcollector;
   static PStatCollector _texmgrmem_total_pcollector;
   static PStatCollector _texmgrmem_total_pcollector;
   static PStatCollector _texmgrmem_resident_pcollector;
   static PStatCollector _texmgrmem_resident_pcollector;
   static PStatCollector _primitive_batches_pcollector;
   static PStatCollector _primitive_batches_pcollector;

+ 19 - 37
panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx

@@ -147,11 +147,11 @@ DXGraphicsStateGuardian8::
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 TextureContext *DXGraphicsStateGuardian8::
 TextureContext *DXGraphicsStateGuardian8::
 prepare_texture(Texture *tex) {
 prepare_texture(Texture *tex) {
-  DXTextureContext8 *dtc = new DXTextureContext8(tex);
+  DXTextureContext8 *dtc = new DXTextureContext8(_prepared_objects, tex);
 
 
   if (!get_supports_compressed_texture_format(tex->get_ram_image_compression())) {
   if (!get_supports_compressed_texture_format(tex->get_ram_image_compression())) {
     dxgsg8_cat.error()
     dxgsg8_cat.error()
-      << *dtc->_texture << " is stored in an unsupported compressed format.\n";
+      << *dtc->get_texture() << " is stored in an unsupported compressed format.\n";
     return NULL;
     return NULL;
   }
   }
   
   
@@ -178,30 +178,17 @@ apply_texture(int i, TextureContext *tc) {
     return;
     return;
   }
   }
 
 
-#ifdef DO_PSTATS
-  add_to_texture_record(tc);
-#endif
+  tc->set_active(true);
 
 
   DXTextureContext8 *dtc = DCAST(DXTextureContext8, tc);
   DXTextureContext8 *dtc = DCAST(DXTextureContext8, tc);
 
 
-  int dirty = dtc->get_dirty_flags();
-
   // If the texture image has changed, or if its use of mipmaps has
   // If the texture image has changed, or if its use of mipmaps has
-  // changed, we need to re-create the image.  Ignore other types of
-  // changes, which aren't significant for DX.
+  // changed, we need to re-create the image.
 
 
-  if ((dirty & (Texture::DF_image | Texture::DF_mipmap)) != 0) {
-    // If this is *only* because of a mipmap change, issue a
-    // warning--it is likely that this change is the result of an
-    // error or oversight.
-    if ((dirty & Texture::DF_image) == 0) {
-      dxgsg8_cat.warning()
-        << *dtc->_texture << " has changed mipmap state.\n";
-    }
-
-    if (!get_supports_compressed_texture_format(tc->_texture->get_ram_image_compression())) {
+  if (dtc->was_modified()) {
+    if (!get_supports_compressed_texture_format(tc->get_texture()->get_ram_image_compression())) {
       dxgsg8_cat.error()
       dxgsg8_cat.error()
-        << *dtc->_texture << " is stored in an unsupported compressed format.\n";
+        << *dtc->get_texture() << " is stored in an unsupported compressed format.\n";
       _d3d_device->SetTextureStageState(i, D3DTSS_COLOROP, D3DTOP_DISABLE);
       _d3d_device->SetTextureStageState(i, D3DTSS_COLOROP, D3DTOP_DISABLE);
       return;
       return;
     }
     }
@@ -209,13 +196,13 @@ apply_texture(int i, TextureContext *tc) {
     if (!dtc->create_texture(*_screen)) {
     if (!dtc->create_texture(*_screen)) {
       // Oops, we can't re-create the texture for some reason.
       // Oops, we can't re-create the texture for some reason.
       dxgsg8_cat.error()
       dxgsg8_cat.error()
-        << "Unable to re-create texture " << *dtc->_texture << endl;
+        << "Unable to re-create texture " << *dtc->get_texture() << endl;
       _d3d_device->SetTextureStageState(i, D3DTSS_COLOROP, D3DTOP_DISABLE);
       _d3d_device->SetTextureStageState(i, D3DTSS_COLOROP, D3DTOP_DISABLE);
       return;
       return;
     }
     }
   }
   }
 
 
-  Texture *tex = tc->_texture;
+  Texture *tex = tc->get_texture();
   Texture::WrapMode wrap_u, wrap_v, wrap_w;
   Texture::WrapMode wrap_u, wrap_v, wrap_w;
   wrap_u = tex->get_wrap_u();
   wrap_u = tex->get_wrap_u();
   wrap_v = tex->get_wrap_v();
   wrap_v = tex->get_wrap_v();
@@ -303,7 +290,7 @@ release_texture(TextureContext *tc) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 VertexBufferContext *DXGraphicsStateGuardian8::
 VertexBufferContext *DXGraphicsStateGuardian8::
 prepare_vertex_buffer(GeomVertexArrayData *data) {
 prepare_vertex_buffer(GeomVertexArrayData *data) {
-  DXVertexBufferContext8 *dvbc = new DXVertexBufferContext8(data);
+  DXVertexBufferContext8 *dvbc = new DXVertexBufferContext8(_prepared_objects, data);
   return dvbc;
   return dvbc;
 }
 }
 
 
@@ -327,14 +314,13 @@ apply_vertex_buffer(VertexBufferContext *vbc) {
     if (dvbc->_vbuffer != NULL) {
     if (dvbc->_vbuffer != NULL) {
       dvbc->upload_data();
       dvbc->upload_data();
 
 
-      add_to_total_buffer_record(dvbc);
       dvbc->mark_loaded();
       dvbc->mark_loaded();
 
 
       _d3d_device->SetStreamSource
       _d3d_device->SetStreamSource
         (0, dvbc->_vbuffer, dvbc->get_data()->get_array_format()->get_stride());
         (0, dvbc->_vbuffer, dvbc->get_data()->get_array_format()->get_stride());
       _active_vbuffer = dvbc;
       _active_vbuffer = dvbc;
       _active_ibuffer = NULL;
       _active_ibuffer = NULL;
-      add_to_vertex_buffer_record(dvbc);
+      dvbc->set_active(true);
 
 
     } else {
     } else {
       _active_vbuffer = NULL;
       _active_vbuffer = NULL;
@@ -349,8 +335,6 @@ apply_vertex_buffer(VertexBufferContext *vbc) {
       }
       }
 
 
       dvbc->upload_data();
       dvbc->upload_data();
-
-      add_to_total_buffer_record(dvbc);
       dvbc->mark_loaded();
       dvbc->mark_loaded();
       _active_vbuffer = NULL;
       _active_vbuffer = NULL;
     }
     }
@@ -360,7 +344,7 @@ apply_vertex_buffer(VertexBufferContext *vbc) {
         (0, dvbc->_vbuffer, dvbc->get_data()->get_array_format()->get_stride());
         (0, dvbc->_vbuffer, dvbc->get_data()->get_array_format()->get_stride());
       _active_vbuffer = dvbc;
       _active_vbuffer = dvbc;
       _active_ibuffer = NULL;
       _active_ibuffer = NULL;
-      add_to_vertex_buffer_record(dvbc);
+      dvbc->set_active(true);
     }
     }
   }
   }
 
 
@@ -403,7 +387,7 @@ release_vertex_buffer(VertexBufferContext *vbc) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 IndexBufferContext *DXGraphicsStateGuardian8::
 IndexBufferContext *DXGraphicsStateGuardian8::
 prepare_index_buffer(GeomPrimitive *data) {
 prepare_index_buffer(GeomPrimitive *data) {
-  DXIndexBufferContext8 *dibc = new DXIndexBufferContext8(data);
+  DXIndexBufferContext8 *dibc = new DXIndexBufferContext8(_prepared_objects, data);
   return dibc;
   return dibc;
 }
 }
 
 
@@ -423,12 +407,11 @@ apply_index_buffer(IndexBufferContext *ibc) {
 
 
     if (dibc->_ibuffer != NULL) {
     if (dibc->_ibuffer != NULL) {
       dibc->upload_data();
       dibc->upload_data();
-      add_to_total_buffer_record(dibc);
       dibc->mark_loaded();
       dibc->mark_loaded();
 
 
       _d3d_device->SetIndices(dibc->_ibuffer, 0);
       _d3d_device->SetIndices(dibc->_ibuffer, 0);
       _active_ibuffer = dibc;
       _active_ibuffer = dibc;
-      add_to_index_buffer_record(dibc);
+      dibc->set_active(true);
 
 
     } else {
     } else {
       _d3d_device->SetIndices(NULL, 0);
       _d3d_device->SetIndices(NULL, 0);
@@ -445,7 +428,6 @@ apply_index_buffer(IndexBufferContext *ibc) {
 
 
       dibc->upload_data();
       dibc->upload_data();
 
 
-      add_to_total_buffer_record(dibc);
       dibc->mark_loaded();
       dibc->mark_loaded();
       _active_ibuffer = NULL;
       _active_ibuffer = NULL;
     }
     }
@@ -453,7 +435,7 @@ apply_index_buffer(IndexBufferContext *ibc) {
     if (_active_ibuffer != dibc) {
     if (_active_ibuffer != dibc) {
       _d3d_device->SetIndices(dibc->_ibuffer, 0);
       _d3d_device->SetIndices(dibc->_ibuffer, 0);
       _active_ibuffer = dibc;
       _active_ibuffer = dibc;
-      add_to_index_buffer_record(dibc);
+      dibc->set_active(true);
     }
     }
   }
   }
 }
 }
@@ -1396,7 +1378,7 @@ framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
       if (!dtc->create_texture(*_screen)) {
       if (!dtc->create_texture(*_screen)) {
         // Oops, we can't re-create the texture for some reason.
         // Oops, we can't re-create the texture for some reason.
         dxgsg8_cat.error()
         dxgsg8_cat.error()
-          << "Unable to re-create texture " << *dtc->_texture << endl;
+          << "Unable to re-create texture " << *dtc->get_texture() << endl;
         return;
         return;
       }
       }
       hr = dtc->get_d3d_2d_texture()->GetSurfaceLevel(0, &tex_level_0);
       hr = dtc->get_d3d_2d_texture()->GetSurfaceLevel(0, &tex_level_0);
@@ -1415,7 +1397,7 @@ framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
       // If it's still the wrong size, it's because driver can't create size
       // If it's still the wrong size, it's because driver can't create size
       // that we want.  In that case, there's no helping it, we have to give up.
       // that we want.  In that case, there's no helping it, we have to give up.
       dxgsg8_cat.error()
       dxgsg8_cat.error()
-        << "Unable to copy to texture, texture is wrong size: " << *dtc->_texture << endl;
+        << "Unable to copy to texture, texture is wrong size: " << *dtc->get_texture() << endl;
       SAFE_RELEASE(tex_level_0);
       SAFE_RELEASE(tex_level_0);
       return;
       return;
     }
     }
@@ -3435,7 +3417,7 @@ reset_d3d_device(D3DPRESENT_PARAMETERS *presentation_params,
     release_all_vertex_buffers();
     release_all_vertex_buffers();
     release_all_index_buffers();
     release_all_index_buffers();
 
 
-    _prepared_objects->update(this);
+    _prepared_objects->begin_frame(this);
 
 
     hr = _d3d_device->Reset(&_presentation_reset);
     hr = _d3d_device->Reset(&_presentation_reset);
     if (FAILED(hr)) {
     if (FAILED(hr)) {
@@ -3493,7 +3475,7 @@ check_cooperative_level() {
     _dx_is_ready = false;
     _dx_is_ready = false;
 
 
     // call this just in case
     // call this just in case
-    _prepared_objects->update (this);
+    _prepared_objects->begin_frame(this);
 
 
     hr = reset_d3d_device(&_screen->_presentation_params);
     hr = reset_d3d_device(&_screen->_presentation_params);
     if (FAILED(hr)) {
     if (FAILED(hr)) {

+ 2 - 2
panda/src/dxgsg8/dxIndexBufferContext8.cxx

@@ -31,8 +31,8 @@ TypeHandle DXIndexBufferContext8::_type_handle;
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 DXIndexBufferContext8::
 DXIndexBufferContext8::
-DXIndexBufferContext8(GeomPrimitive *data) :
-  IndexBufferContext(data),
+DXIndexBufferContext8(PreparedGraphicsObjects *pgo, GeomPrimitive *data) :
+  IndexBufferContext(pgo, data),
   _ibuffer(NULL)
   _ibuffer(NULL)
 {
 {
 }
 }

+ 1 - 1
panda/src/dxgsg8/dxIndexBufferContext8.h

@@ -30,7 +30,7 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDADX DXIndexBufferContext8 : public IndexBufferContext {
 class EXPCL_PANDADX DXIndexBufferContext8 : public IndexBufferContext {
 public:
 public:
-  DXIndexBufferContext8(GeomPrimitive *data);
+  DXIndexBufferContext8(PreparedGraphicsObjects *pgo, GeomPrimitive *data);
   virtual ~DXIndexBufferContext8();
   virtual ~DXIndexBufferContext8();
 
 
   void create_ibuffer(DXScreenData &scrn);
   void create_ibuffer(DXScreenData &scrn);

+ 59 - 60
panda/src/dxgsg8/dxTextureContext8.cxx

@@ -35,8 +35,8 @@ static const DWORD g_LowByteMask = 0x000000FF;
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 DXTextureContext8::
 DXTextureContext8::
-DXTextureContext8(Texture *tex) :
-  TextureContext(tex) {
+DXTextureContext8(PreparedGraphicsObjects *pgo, Texture *tex) :
+  TextureContext(pgo, tex) {
 
 
   if (dxgsg8_cat.is_spam()) {
   if (dxgsg8_cat.is_spam()) {
     dxgsg8_cat.spam()
     dxgsg8_cat.spam()
@@ -59,7 +59,7 @@ DXTextureContext8::
 ~DXTextureContext8() {
 ~DXTextureContext8() {
   if (dxgsg8_cat.is_spam()) {
   if (dxgsg8_cat.is_spam()) {
     dxgsg8_cat.spam()
     dxgsg8_cat.spam()
-      << "Deleting texture context for " << _texture->get_name() << "\n";
+      << "Deleting texture context for " << get_texture()->get_name() << "\n";
   }
   }
   delete_texture();
   delete_texture();
   TextureContext::~TextureContext();
   TextureContext::~TextureContext();
@@ -82,32 +82,31 @@ create_texture(DXScreenData &scrn) {
   D3DFORMAT target_pixel_format = D3DFMT_UNKNOWN;
   D3DFORMAT target_pixel_format = D3DFMT_UNKNOWN;
   bool needs_luminance = false;
   bool needs_luminance = false;
 
 
-  nassertr(IS_VALID_PTR(_texture), false);
+  nassertr(IS_VALID_PTR(get_texture()), false);
 
 
   delete_texture();
   delete_texture();
-
-  clear_dirty_flags(Texture::DF_image | Texture::DF_mipmap);
+  mark_loaded();
 
 
   // bpp indicates requested fmt, not texture fmt
   // bpp indicates requested fmt, not texture fmt
-  DWORD target_bpp = get_bits_per_pixel(_texture->get_format(), &num_alpha_bits);
-  DWORD num_color_channels = _texture->get_num_components();
+  DWORD target_bpp = get_bits_per_pixel(get_texture()->get_format(), &num_alpha_bits);
+  DWORD num_color_channels = get_texture()->get_num_components();
 
 
   //PRINT_REFCNT(dxgsg8, scrn._d3d8);
   //PRINT_REFCNT(dxgsg8, scrn._d3d8);
 
 
-  DWORD orig_width = (DWORD)_texture->get_x_size();
-  DWORD orig_height = (DWORD)_texture->get_y_size();
-  DWORD orig_depth = (DWORD)_texture->get_z_size();
+  DWORD orig_width = (DWORD)get_texture()->get_x_size();
+  DWORD orig_height = (DWORD)get_texture()->get_y_size();
+  DWORD orig_depth = (DWORD)get_texture()->get_z_size();
 
 
-  if ((_texture->get_format() == Texture::F_luminance_alpha)||
-      (_texture->get_format() == Texture::F_luminance_alphamask) ||
-      (_texture->get_format() == Texture::F_luminance)) {
+  if ((get_texture()->get_format() == Texture::F_luminance_alpha)||
+      (get_texture()->get_format() == Texture::F_luminance_alphamask) ||
+      (get_texture()->get_format() == Texture::F_luminance)) {
     needs_luminance = true;
     needs_luminance = true;
   }
   }
 
 
   if (num_alpha_bits > 0) {
   if (num_alpha_bits > 0) {
     if (num_color_channels == 3) {
     if (num_color_channels == 3) {
       dxgsg8_cat.error()
       dxgsg8_cat.error()
-        << "texture " << _texture->get_name()
+        << "texture " << get_texture()->get_name()
         << " has no inherent alpha channel, but alpha format is requested!\n";
         << " has no inherent alpha channel, but alpha format is requested!\n";
     }
     }
   }
   }
@@ -145,7 +144,7 @@ create_texture(DXScreenData &scrn) {
 
 
   DWORD filter_caps;
   DWORD filter_caps;
 
 
-  switch (_texture->get_texture_type()) {
+  switch (get_texture()->get_texture_type()) {
   case Texture::TT_1d_texture:
   case Texture::TT_1d_texture:
   case Texture::TT_2d_texture:
   case Texture::TT_2d_texture:
     filter_caps = scrn._d3dcaps.TextureFilterCaps;
     filter_caps = scrn._d3dcaps.TextureFilterCaps;
@@ -239,15 +238,15 @@ create_texture(DXScreenData &scrn) {
 
 
   if (orig_width != target_width || orig_height != target_height ||
   if (orig_width != target_width || orig_height != target_height ||
       orig_depth != target_depth) {
       orig_depth != target_depth) {
-    if (_texture->get_texture_type() == Texture::TT_3d_texture) {
+    if (get_texture()->get_texture_type() == Texture::TT_3d_texture) {
       dxgsg8_cat.info()
       dxgsg8_cat.info()
-        << "Reducing size of " << _texture->get_name()
+        << "Reducing size of " << get_texture()->get_name()
         << " from " << orig_width << "x" << orig_height << "x" << orig_depth
         << " from " << orig_width << "x" << orig_height << "x" << orig_depth
         << " to " << target_width << "x" << target_height
         << " to " << target_width << "x" << target_height
         << "x" << target_depth << "\n";
         << "x" << target_depth << "\n";
     } else {
     } else {
       dxgsg8_cat.info()
       dxgsg8_cat.info()
-        << "Reducing size of " << _texture->get_name()
+        << "Reducing size of " << get_texture()->get_name()
         << " from " << orig_width << "x" << orig_height
         << " from " << orig_width << "x" << orig_height
         << " to " << target_width << "x" << target_height << "\n";
         << " to " << target_width << "x" << target_height << "\n";
     }
     }
@@ -457,7 +456,7 @@ create_texture(DXScreenData &scrn) {
 
 
   // if we've gotten here, haven't found a match
   // if we've gotten here, haven't found a match
   dxgsg8_cat.error()
   dxgsg8_cat.error()
-    << error_message << ": " << _texture->get_name() << endl
+    << error_message << ": " << get_texture()->get_name() << endl
     << "NumColorChannels: " << num_color_channels << "; NumAlphaBits: "
     << "NumColorChannels: " << num_color_channels << "; NumAlphaBits: "
     << num_alpha_bits << "; targetbpp: " <<target_bpp
     << num_alpha_bits << "; targetbpp: " <<target_bpp
     << "; _supported_tex_formats_mask: 0x"
     << "; _supported_tex_formats_mask: 0x"
@@ -470,7 +469,7 @@ create_texture(DXScreenData &scrn) {
  found_matching_format:
  found_matching_format:
   // We found a suitable format that matches the texture's format.
   // We found a suitable format that matches the texture's format.
 
 
-  if (_texture->get_match_framebuffer_format()) {
+  if (get_texture()->get_match_framebuffer_format()) {
     // Instead of creating a texture with the found format, we will
     // Instead of creating a texture with the found format, we will
     // need to make one that exactly matches the framebuffer's
     // need to make one that exactly matches the framebuffer's
     // format.  Look up what that format is.
     // format.  Look up what that format is.
@@ -505,7 +504,7 @@ create_texture(DXScreenData &scrn) {
 
 
   Texture::FilterType ft;
   Texture::FilterType ft;
 
 
-  ft = _texture->get_magfilter();
+  ft = get_texture()->get_magfilter();
   if ((ft != Texture::FT_linear) && ft != Texture::FT_nearest) {
   if ((ft != Texture::FT_linear) && ft != Texture::FT_nearest) {
     // mipmap settings make no sense for magfilter
     // mipmap settings make no sense for magfilter
     if (ft == Texture::FT_nearest_mipmap_nearest) {
     if (ft == Texture::FT_nearest_mipmap_nearest) {
@@ -519,10 +518,10 @@ create_texture(DXScreenData &scrn) {
       (filter_caps & D3DPTFILTERCAPS_MAGFLINEAR) == 0) {
       (filter_caps & D3DPTFILTERCAPS_MAGFLINEAR) == 0) {
     ft = Texture::FT_nearest;
     ft = Texture::FT_nearest;
   }
   }
-  _texture->set_magfilter(ft);
+  get_texture()->set_magfilter(ft);
 
 
   // figure out if we are mipmapping this texture
   // figure out if we are mipmapping this texture
-  ft = _texture->get_minfilter();
+  ft = get_texture()->get_minfilter();
   _has_mipmaps = false;
   _has_mipmaps = false;
 
 
   if (!dx_ignore_mipmaps) {  // set if no HW mipmap capable
   if (!dx_ignore_mipmaps) {  // set if no HW mipmap capable
@@ -540,11 +539,11 @@ create_texture(DXScreenData &scrn) {
         if (ft != Texture::FT_linear_mipmap_linear) {
         if (ft != Texture::FT_linear_mipmap_linear) {
           dxgsg8_cat.spam()
           dxgsg8_cat.spam()
             << "Forcing trilinear mipmapping on DX texture ["
             << "Forcing trilinear mipmapping on DX texture ["
-            << _texture->get_name() << "]\n";
+            << get_texture()->get_name() << "]\n";
         }
         }
       }
       }
       ft = Texture::FT_linear_mipmap_linear;
       ft = Texture::FT_linear_mipmap_linear;
-      _texture->set_minfilter(ft);
+      get_texture()->set_minfilter(ft);
     }
     }
 
 
   } else if ((ft == Texture::FT_nearest_mipmap_nearest) ||   // cvt to no-mipmap filter types
   } else if ((ft == Texture::FT_nearest_mipmap_nearest) ||   // cvt to no-mipmap filter types
@@ -596,23 +595,23 @@ create_texture(DXScreenData &scrn) {
     break;
     break;
   }
   }
 
 
-  _texture->set_minfilter(ft);
+  get_texture()->set_minfilter(ft);
 
 
   uint aniso_degree;
   uint aniso_degree;
 
 
   aniso_degree = 1;
   aniso_degree = 1;
   if (scrn._d3dcaps.RasterCaps & D3DPRASTERCAPS_ANISOTROPY) {
   if (scrn._d3dcaps.RasterCaps & D3DPRASTERCAPS_ANISOTROPY) {
-    aniso_degree = _texture->get_anisotropic_degree();
+    aniso_degree = get_texture()->get_anisotropic_degree();
     if ((aniso_degree>scrn._d3dcaps.MaxAnisotropy) ||
     if ((aniso_degree>scrn._d3dcaps.MaxAnisotropy) ||
         dx_force_anisotropic_filtering) {
         dx_force_anisotropic_filtering) {
       aniso_degree = scrn._d3dcaps.MaxAnisotropy;
       aniso_degree = scrn._d3dcaps.MaxAnisotropy;
     }
     }
   }
   }
-  _texture->set_anisotropic_degree(aniso_degree);
+  get_texture()->set_anisotropic_degree(aniso_degree);
 
 
 #ifdef _DEBUG
 #ifdef _DEBUG
   dxgsg8_cat.spam()
   dxgsg8_cat.spam()
-    << "create_texture: setting aniso degree for " << _texture->get_name()
+    << "create_texture: setting aniso degree for " << get_texture()->get_name()
     << " to: " << aniso_degree << endl;
     << " to: " << aniso_degree << endl;
 #endif
 #endif
 
 
@@ -624,7 +623,7 @@ create_texture(DXScreenData &scrn) {
 
 
     if (dxgsg8_cat.is_debug()) {
     if (dxgsg8_cat.is_debug()) {
       dxgsg8_cat.debug()
       dxgsg8_cat.debug()
-        << "create_texture: generating mipmaps for " << _texture->get_name()
+        << "create_texture: generating mipmaps for " << get_texture()->get_name()
         << endl;
         << endl;
     }
     }
   } else {
   } else {
@@ -634,7 +633,7 @@ create_texture(DXScreenData &scrn) {
   DWORD usage;
   DWORD usage;
   D3DPOOL pool;
   D3DPOOL pool;
 
 
-  if (_texture->get_render_to_texture ()) {
+  if (get_texture()->get_render_to_texture ()) {
     // REQUIRED
     // REQUIRED
     pool = D3DPOOL_DEFAULT;
     pool = D3DPOOL_DEFAULT;
     usage = D3DUSAGE_RENDERTARGET;
     usage = D3DUSAGE_RENDERTARGET;
@@ -646,7 +645,7 @@ create_texture(DXScreenData &scrn) {
     usage = 0;
     usage = 0;
   }
   }
 
 
-  switch (_texture->get_texture_type()) {
+  switch (get_texture()->get_texture_type()) {
   case Texture::TT_1d_texture:
   case Texture::TT_1d_texture:
   case Texture::TT_2d_texture:
   case Texture::TT_2d_texture:
     hr = scrn._d3d_device->CreateTexture
     hr = scrn._d3d_device->CreateTexture
@@ -678,7 +677,7 @@ create_texture(DXScreenData &scrn) {
 
 
   if (dxgsg8_cat.is_debug()) {
   if (dxgsg8_cat.is_debug()) {
     dxgsg8_cat.debug()
     dxgsg8_cat.debug()
-      << "create_texture: " << _texture->get_name()
+      << "create_texture: " << get_texture()->get_name()
       << " converting panda equivalent of " << D3DFormatStr(_d3d_format)
       << " converting panda equivalent of " << D3DFormatStr(_d3d_format)
       << " => " << D3DFormatStr(target_pixel_format) << endl;
       << " => " << D3DFormatStr(target_pixel_format) << endl;
   }
   }
@@ -984,14 +983,14 @@ d3d_surface_to_texture(RECT &source_rect, IDirect3DSurface8 *d3d_surface,
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 HRESULT DXTextureContext8::
 HRESULT DXTextureContext8::
 fill_d3d_texture_pixels() {
 fill_d3d_texture_pixels() {
-  if (_texture->get_texture_type() == Texture::TT_3d_texture) {
+  if (get_texture()->get_texture_type() == Texture::TT_3d_texture) {
     return fill_d3d_volume_texture_pixels();
     return fill_d3d_volume_texture_pixels();
   }
   }
 
 
   HRESULT hr = E_FAIL;
   HRESULT hr = E_FAIL;
-  nassertr(IS_VALID_PTR(_texture), E_FAIL);
+  nassertr(IS_VALID_PTR(get_texture()), E_FAIL);
 
 
-  CPTA_uchar image = _texture->get_ram_image();
+  CPTA_uchar image = get_texture()->get_ram_image();
   if (image.is_null()) {
   if (image.is_null()) {
     // The texture doesn't have an image to load.  That's ok; it
     // The texture doesn't have an image to load.  That's ok; it
     // might be a texture we've rendered to by frame buffer
     // might be a texture we've rendered to by frame buffer
@@ -1003,13 +1002,13 @@ fill_d3d_texture_pixels() {
 
 
   nassertr(IS_VALID_PTR(_d3d_texture), E_FAIL);
   nassertr(IS_VALID_PTR(_d3d_texture), E_FAIL);
 
 
-  DWORD orig_width  = (DWORD) _texture->get_x_size();
-  DWORD orig_height = (DWORD) _texture->get_y_size();
-  DWORD orig_depth = (DWORD) _texture->get_z_size();
-  DWORD num_color_channels = _texture->get_num_components();
+  DWORD orig_width  = (DWORD) get_texture()->get_x_size();
+  DWORD orig_height = (DWORD) get_texture()->get_y_size();
+  DWORD orig_depth = (DWORD) get_texture()->get_z_size();
+  DWORD num_color_channels = get_texture()->get_num_components();
   D3DFORMAT source_format = _d3d_format;
   D3DFORMAT source_format = _d3d_format;
   BYTE *image_pixels = (BYTE*)image.p();
   BYTE *image_pixels = (BYTE*)image.p();
-  int component_width = _texture->get_component_width();
+  int component_width = get_texture()->get_component_width();
 
 
   nassertr(IS_VALID_PTR(image_pixels), E_FAIL);
   nassertr(IS_VALID_PTR(image_pixels), E_FAIL);
 
 
@@ -1018,10 +1017,10 @@ fill_d3d_texture_pixels() {
   BYTE *pixels = NULL;
   BYTE *pixels = NULL;
 
 
   for (unsigned int di = 0; di < orig_depth; di++) {
   for (unsigned int di = 0; di < orig_depth; di++) {
-    pixels = image_pixels + di * _texture->get_expected_ram_page_size();
+    pixels = image_pixels + di * get_texture()->get_expected_ram_page_size();
     mip_level_0 = NULL;
     mip_level_0 = NULL;
 
 
-    if (_texture->get_texture_type() == Texture::TT_cube_map) {
+    if (get_texture()->get_texture_type() == Texture::TT_cube_map) {
       nassertr(IS_VALID_PTR(_d3d_cube_texture), E_FAIL);
       nassertr(IS_VALID_PTR(_d3d_cube_texture), E_FAIL);
       hr = _d3d_cube_texture->GetCubeMapSurface((D3DCUBEMAP_FACES)di, 0, &mip_level_0);
       hr = _d3d_cube_texture->GetCubeMapSurface((D3DCUBEMAP_FACES)di, 0, &mip_level_0);
     } else {
     } else {
@@ -1031,7 +1030,7 @@ fill_d3d_texture_pixels() {
 
 
     if (FAILED(hr)) {
     if (FAILED(hr)) {
       dxgsg8_cat.error()
       dxgsg8_cat.error()
-        << "FillDDSurfaceTexturePixels failed for " << _texture->get_name()
+        << "FillDDSurfaceTexturePixels failed for " << get_texture()->get_name()
       << ", GetSurfaceLevel failed" << D3DERRORSTRING(hr);
       << ", GetSurfaceLevel failed" << D3DERRORSTRING(hr);
       return E_FAIL;
       return E_FAIL;
     }
     }
@@ -1085,7 +1084,7 @@ fill_d3d_texture_pixels() {
       // original image, but dx8 doesn't support high-precision images
       // original image, but dx8 doesn't support high-precision images
       // anyway.
       // anyway.
 
 
-      int num_components = _texture->get_num_components();
+      int num_components = get_texture()->get_num_components();
       int num_pixels = orig_width * orig_height * num_components;
       int num_pixels = orig_width * orig_height * num_components;
       BYTE *temp_buffer = new BYTE[num_pixels];
       BYTE *temp_buffer = new BYTE[num_pixels];
       if (!IS_VALID_PTR(temp_buffer)) {
       if (!IS_VALID_PTR(temp_buffer)) {
@@ -1113,7 +1112,7 @@ fill_d3d_texture_pixels() {
        &source_size, level_0_filter, (D3DCOLOR)0x0);
        &source_size, level_0_filter, (D3DCOLOR)0x0);
     if (FAILED(hr)) {
     if (FAILED(hr)) {
       dxgsg8_cat.error()
       dxgsg8_cat.error()
-        << "FillDDSurfaceTexturePixels failed for " << _texture->get_name()
+        << "FillDDSurfaceTexturePixels failed for " << get_texture()->get_name()
         << ", D3DXLoadSurfFromMem failed" << D3DERRORSTRING(hr);
         << ", D3DXLoadSurfFromMem failed" << D3DERRORSTRING(hr);
       goto exit_FillDDSurf;
       goto exit_FillDDSurf;
     }
     }
@@ -1131,7 +1130,7 @@ fill_d3d_texture_pixels() {
                              mip_filter_flags);
                              mip_filter_flags);
       if (FAILED(hr)) {
       if (FAILED(hr)) {
         dxgsg8_cat.error()
         dxgsg8_cat.error()
-          << "FillDDSurfaceTexturePixels failed for " << _texture->get_name()
+          << "FillDDSurfaceTexturePixels failed for " << get_texture()->get_name()
           << ", D3DXFilterTex failed" << D3DERRORSTRING(hr);
           << ", D3DXFilterTex failed" << D3DERRORSTRING(hr);
         goto exit_FillDDSurf;
         goto exit_FillDDSurf;
       }
       }
@@ -1159,9 +1158,9 @@ fill_d3d_texture_pixels() {
 HRESULT DXTextureContext8::
 HRESULT DXTextureContext8::
 fill_d3d_volume_texture_pixels() {
 fill_d3d_volume_texture_pixels() {
   HRESULT hr = E_FAIL;
   HRESULT hr = E_FAIL;
-  nassertr(IS_VALID_PTR(_texture), E_FAIL);
+  nassertr(IS_VALID_PTR(get_texture()), E_FAIL);
 
 
-  CPTA_uchar image = _texture->get_ram_image();
+  CPTA_uchar image = get_texture()->get_ram_image();
   if (image.is_null()) {
   if (image.is_null()) {
     // The texture doesn't have an image to load.  That's ok; it
     // The texture doesn't have an image to load.  That's ok; it
     // might be a texture we've rendered to by frame buffer
     // might be a texture we've rendered to by frame buffer
@@ -1172,15 +1171,15 @@ fill_d3d_volume_texture_pixels() {
   PStatTimer timer(GraphicsStateGuardian::_load_texture_pcollector);
   PStatTimer timer(GraphicsStateGuardian::_load_texture_pcollector);
 
 
   nassertr(IS_VALID_PTR(_d3d_texture), E_FAIL);
   nassertr(IS_VALID_PTR(_d3d_texture), E_FAIL);
-  nassertr(_texture->get_texture_type() == Texture::TT_3d_texture, E_FAIL);
+  nassertr(get_texture()->get_texture_type() == Texture::TT_3d_texture, E_FAIL);
 
 
-  DWORD orig_width  = (DWORD) _texture->get_x_size();
-  DWORD orig_height = (DWORD) _texture->get_y_size();
-  DWORD orig_depth = (DWORD) _texture->get_z_size();
-  DWORD num_color_channels = _texture->get_num_components();
+  DWORD orig_width  = (DWORD) get_texture()->get_x_size();
+  DWORD orig_height = (DWORD) get_texture()->get_y_size();
+  DWORD orig_depth = (DWORD) get_texture()->get_z_size();
+  DWORD num_color_channels = get_texture()->get_num_components();
   D3DFORMAT source_format = _d3d_format;
   D3DFORMAT source_format = _d3d_format;
   BYTE *image_pixels = (BYTE*)image.p();
   BYTE *image_pixels = (BYTE*)image.p();
-  int component_width = _texture->get_component_width();
+  int component_width = get_texture()->get_component_width();
 
 
   nassertr(IS_VALID_PTR(image_pixels), E_FAIL);
   nassertr(IS_VALID_PTR(image_pixels), E_FAIL);
 
 
@@ -1193,7 +1192,7 @@ fill_d3d_volume_texture_pixels() {
 
 
   if (FAILED(hr)) {
   if (FAILED(hr)) {
     dxgsg8_cat.error()
     dxgsg8_cat.error()
-      << "FillDDSurfaceTexturePixels failed for " << _texture->get_name()
+      << "FillDDSurfaceTexturePixels failed for " << get_texture()->get_name()
       << ", GetSurfaceLevel failed" << D3DERRORSTRING(hr);
       << ", GetSurfaceLevel failed" << D3DERRORSTRING(hr);
     return E_FAIL;
     return E_FAIL;
   }
   }
@@ -1252,7 +1251,7 @@ fill_d3d_volume_texture_pixels() {
     // original image, but dx8 doesn't support high-precision images
     // original image, but dx8 doesn't support high-precision images
     // anyway.
     // anyway.
 
 
-    int num_components = _texture->get_num_components();
+    int num_components = get_texture()->get_num_components();
     int num_pixels = orig_width * orig_height * orig_depth * num_components;
     int num_pixels = orig_width * orig_height * orig_depth * num_components;
     BYTE *temp_buffer = new BYTE[num_pixels];
     BYTE *temp_buffer = new BYTE[num_pixels];
     if (!IS_VALID_PTR(temp_buffer)) {
     if (!IS_VALID_PTR(temp_buffer)) {
@@ -1281,7 +1280,7 @@ fill_d3d_volume_texture_pixels() {
      &source_size, level_0_filter, (D3DCOLOR)0x0);
      &source_size, level_0_filter, (D3DCOLOR)0x0);
   if (FAILED(hr)) {
   if (FAILED(hr)) {
     dxgsg8_cat.error()
     dxgsg8_cat.error()
-      << "FillDDSurfaceTexturePixels failed for " << _texture->get_name()
+      << "FillDDSurfaceTexturePixels failed for " << get_texture()->get_name()
       << ", D3DXLoadVolumeFromMem failed" << D3DERRORSTRING(hr);
       << ", D3DXLoadVolumeFromMem failed" << D3DERRORSTRING(hr);
     goto exit_FillDDSurf;
     goto exit_FillDDSurf;
   }
   }
@@ -1299,7 +1298,7 @@ fill_d3d_volume_texture_pixels() {
                            mip_filter_flags);
                            mip_filter_flags);
     if (FAILED(hr)) {
     if (FAILED(hr)) {
       dxgsg8_cat.error()
       dxgsg8_cat.error()
-        << "FillDDSurfaceTexturePixels failed for " << _texture->get_name()
+        << "FillDDSurfaceTexturePixels failed for " << get_texture()->get_name()
         << ", D3DXFilterTex failed" << D3DERRORSTRING(hr);
         << ", D3DXFilterTex failed" << D3DERRORSTRING(hr);
       goto exit_FillDDSurf;
       goto exit_FillDDSurf;
     }
     }

+ 1 - 1
panda/src/dxgsg8/dxTextureContext8.h

@@ -29,7 +29,7 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDADX DXTextureContext8 : public TextureContext {
 class EXPCL_PANDADX DXTextureContext8 : public TextureContext {
 public:
 public:
-  DXTextureContext8(Texture *tex);
+  DXTextureContext8(PreparedGraphicsObjects *pgo, Texture *tex);
   virtual ~DXTextureContext8();
   virtual ~DXTextureContext8();
 
 
   bool create_texture(DXScreenData &scrn);
   bool create_texture(DXScreenData &scrn);

+ 2 - 2
panda/src/dxgsg8/dxVertexBufferContext8.cxx

@@ -33,8 +33,8 @@ TypeHandle DXVertexBufferContext8::_type_handle;
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 DXVertexBufferContext8::
 DXVertexBufferContext8::
-DXVertexBufferContext8(GeomVertexArrayData *data) :
-  VertexBufferContext(data),
+DXVertexBufferContext8(PreparedGraphicsObjects *pgo, GeomVertexArrayData *data) :
+  VertexBufferContext(pgo, data),
   _vbuffer(NULL)
   _vbuffer(NULL)
 {
 {
   // Now fill in the FVF code.
   // Now fill in the FVF code.

+ 1 - 1
panda/src/dxgsg8/dxVertexBufferContext8.h

@@ -30,7 +30,7 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDADX DXVertexBufferContext8 : public VertexBufferContext {
 class EXPCL_PANDADX DXVertexBufferContext8 : public VertexBufferContext {
 public:
 public:
-  DXVertexBufferContext8(GeomVertexArrayData *data);
+  DXVertexBufferContext8(PreparedGraphicsObjects *pgo, GeomVertexArrayData *data);
   virtual ~DXVertexBufferContext8();
   virtual ~DXVertexBufferContext8();
 
 
   void create_vbuffer(DXScreenData &scrn);
   void create_vbuffer(DXScreenData &scrn);

+ 19 - 36
panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx

@@ -190,11 +190,11 @@ DXGraphicsStateGuardian9::
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 TextureContext *DXGraphicsStateGuardian9::
 TextureContext *DXGraphicsStateGuardian9::
 prepare_texture(Texture *tex) {
 prepare_texture(Texture *tex) {
-  DXTextureContext9 *dtc = new DXTextureContext9(tex);
+  DXTextureContext9 *dtc = new DXTextureContext9(_prepared_objects, tex);
 
 
   if (!get_supports_compressed_texture_format(tex->get_ram_image_compression())) {
   if (!get_supports_compressed_texture_format(tex->get_ram_image_compression())) {
     dxgsg9_cat.error()
     dxgsg9_cat.error()
-      << *dtc->_texture << " is stored in an unsupported compressed format.\n";
+      << *dtc->get_texture() << " is stored in an unsupported compressed format.\n";
     return NULL;
     return NULL;
   }
   }
   
   
@@ -221,9 +221,7 @@ apply_texture(int i, TextureContext *tc) {
     return;
     return;
   }
   }
 
 
-#ifdef DO_PSTATS
-  add_to_texture_record(tc);
-#endif
+  tc->set_active(true);
 
 
   DXTextureContext9 *dtc = DCAST(DXTextureContext9, tc);
   DXTextureContext9 *dtc = DCAST(DXTextureContext9, tc);
 
 
@@ -232,24 +230,13 @@ apply_texture(int i, TextureContext *tc) {
     _lru -> access_page (dtc -> _lru_page);
     _lru -> access_page (dtc -> _lru_page);
   }
   }
 
 
-  int dirty = dtc->get_dirty_flags();
-
   // If the texture image has changed, or if its use of mipmaps has
   // If the texture image has changed, or if its use of mipmaps has
-  // changed, we need to re-create the image.  Ignore other types of
-  // changes, which aren't significant for DX.
-
-  if ((dirty & (Texture::DF_image | Texture::DF_mipmap)) != 0) {
-    // If this is *only* because of a mipmap change, issue a
-    // warning--it is likely that this change is the result of an
-    // error or oversight.
-    if ((dirty & Texture::DF_image) == 0) {
-      dxgsg9_cat.warning()
-        << *dtc->_texture << " has changed mipmap state.\n";
-    }
+  // changed, we need to re-create the image.
 
 
-    if (!get_supports_compressed_texture_format(tc->_texture->get_ram_image_compression())) {
+  if (dtc->was_modified()) {
+    if (!get_supports_compressed_texture_format(tc->get_texture()->get_ram_image_compression())) {
       dxgsg9_cat.error()
       dxgsg9_cat.error()
-        << *dtc->_texture << " is stored in an unsupported compressed format.\n";
+        << *dtc->get_texture() << " is stored in an unsupported compressed format.\n";
       _d3d_device->SetTextureStageState(i, D3DTSS_COLOROP, D3DTOP_DISABLE);
       _d3d_device->SetTextureStageState(i, D3DTSS_COLOROP, D3DTOP_DISABLE);
       return;
       return;
     }
     }
@@ -257,13 +244,13 @@ apply_texture(int i, TextureContext *tc) {
     if (!dtc->create_texture(*_screen)) {
     if (!dtc->create_texture(*_screen)) {
       // Oops, we can't re-create the texture for some reason.
       // Oops, we can't re-create the texture for some reason.
       dxgsg9_cat.error()
       dxgsg9_cat.error()
-        << "Unable to re-create texture " << *dtc->_texture << endl;
+        << "Unable to re-create texture " << *dtc->get_texture() << endl;
       set_texture_stage_state(i, D3DTSS_COLOROP, D3DTOP_DISABLE);
       set_texture_stage_state(i, D3DTSS_COLOROP, D3DTOP_DISABLE);
       return;
       return;
     }
     }
   }
   }
 
 
-  Texture *tex = tc->_texture;
+  Texture *tex = tc->get_texture();
   Texture::WrapMode wrap_u, wrap_v, wrap_w;
   Texture::WrapMode wrap_u, wrap_v, wrap_w;
 
 
   DWORD address_u;
   DWORD address_u;
@@ -388,7 +375,7 @@ release_shader(ShaderContext *sc) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 VertexBufferContext *DXGraphicsStateGuardian9::
 VertexBufferContext *DXGraphicsStateGuardian9::
 prepare_vertex_buffer(GeomVertexArrayData *data) {
 prepare_vertex_buffer(GeomVertexArrayData *data) {
-  DXVertexBufferContext9 *dvbc = new DXVertexBufferContext9(data, *(this -> _screen));
+  DXVertexBufferContext9 *dvbc = new DXVertexBufferContext9(_prepared_objects, data, *(this -> _screen));
   return dvbc;
   return dvbc;
 }
 }
 
 
@@ -427,7 +414,6 @@ apply_vertex_buffer(VertexBufferContext *vbc, CLP(ShaderContext) *shader_context
     if (dvbc->_vbuffer != NULL) {
     if (dvbc->_vbuffer != NULL) {
       dvbc->upload_data();
       dvbc->upload_data();
 
 
-      add_to_total_buffer_record(dvbc);
       dvbc->mark_loaded();
       dvbc->mark_loaded();
 
 
       set_stream_source = true;
       set_stream_source = true;
@@ -446,7 +432,6 @@ apply_vertex_buffer(VertexBufferContext *vbc, CLP(ShaderContext) *shader_context
 
 
       dvbc->upload_data();
       dvbc->upload_data();
 
 
-      add_to_total_buffer_record(dvbc);
       dvbc->mark_loaded();
       dvbc->mark_loaded();
       _active_vbuffer = NULL;
       _active_vbuffer = NULL;
     }
     }
@@ -467,7 +452,7 @@ apply_vertex_buffer(VertexBufferContext *vbc, CLP(ShaderContext) *shader_context
       }
       }
       _active_vbuffer = dvbc;
       _active_vbuffer = dvbc;
       _active_ibuffer = NULL;
       _active_ibuffer = NULL;
-      add_to_vertex_buffer_record(dvbc);
+      dvbc->set_active(true);
     }
     }
 
 
     if ((dvbc->_fvf != _last_fvf)) {
     if ((dvbc->_fvf != _last_fvf)) {
@@ -558,7 +543,7 @@ apply_vertex_buffer(VertexBufferContext *vbc, CLP(ShaderContext) *shader_context
       }
       }
       _active_vbuffer = dvbc;
       _active_vbuffer = dvbc;
       _active_ibuffer = NULL;
       _active_ibuffer = NULL;
-      add_to_vertex_buffer_record(dvbc);
+      dvbc->set_active(true);
     }
     }
 
 
     if (dvbc -> _direct_3d_vertex_declaration) {
     if (dvbc -> _direct_3d_vertex_declaration) {
@@ -603,7 +588,7 @@ release_vertex_buffer(VertexBufferContext *vbc) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 IndexBufferContext *DXGraphicsStateGuardian9::
 IndexBufferContext *DXGraphicsStateGuardian9::
 prepare_index_buffer(GeomPrimitive *data) {
 prepare_index_buffer(GeomPrimitive *data) {
-  DXIndexBufferContext9 *dibc = new DXIndexBufferContext9(data);
+  DXIndexBufferContext9 *dibc = new DXIndexBufferContext9(_prepared_objects, data);
   return dibc;
   return dibc;
 }
 }
 
 
@@ -627,12 +612,11 @@ apply_index_buffer(IndexBufferContext *ibc) {
 
 
     if (dibc->_ibuffer != NULL) {
     if (dibc->_ibuffer != NULL) {
       dibc->upload_data();
       dibc->upload_data();
-      add_to_total_buffer_record(dibc);
       dibc->mark_loaded();
       dibc->mark_loaded();
 
 
       _d3d_device->SetIndices(dibc->_ibuffer);
       _d3d_device->SetIndices(dibc->_ibuffer);
       _active_ibuffer = dibc;
       _active_ibuffer = dibc;
-      add_to_index_buffer_record(dibc);
+      dibc->set_active(true);
 
 
     } else {
     } else {
       _d3d_device->SetIndices(NULL);
       _d3d_device->SetIndices(NULL);
@@ -649,7 +633,6 @@ apply_index_buffer(IndexBufferContext *ibc) {
 
 
       dibc->upload_data();
       dibc->upload_data();
 
 
-      add_to_total_buffer_record(dibc);
       dibc->mark_loaded();
       dibc->mark_loaded();
       _active_ibuffer = NULL;
       _active_ibuffer = NULL;
     }
     }
@@ -657,7 +640,7 @@ apply_index_buffer(IndexBufferContext *ibc) {
     if (_active_ibuffer != dibc) {
     if (_active_ibuffer != dibc) {
       _d3d_device->SetIndices(dibc->_ibuffer);
       _d3d_device->SetIndices(dibc->_ibuffer);
       _active_ibuffer = dibc;
       _active_ibuffer = dibc;
-      add_to_index_buffer_record(dibc);
+      dibc->set_active(true);
     }
     }
   }
   }
 }
 }
@@ -1902,7 +1885,7 @@ framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
       if (!dtc->create_texture(*_screen)) {
       if (!dtc->create_texture(*_screen)) {
         // Oops, we can't re-create the texture for some reason.
         // Oops, we can't re-create the texture for some reason.
         dxgsg9_cat.error()
         dxgsg9_cat.error()
-          << "Unable to re-create texture " << *dtc->_texture << endl;
+          << "Unable to re-create texture " << *dtc->get_texture() << endl;
         return;
         return;
       }
       }
       hr = dtc->get_d3d_2d_texture()->GetSurfaceLevel(0, &tex_level_0);
       hr = dtc->get_d3d_2d_texture()->GetSurfaceLevel(0, &tex_level_0);
@@ -1921,7 +1904,7 @@ framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
       // If it's still the wrong size, it's because driver can't create size
       // If it's still the wrong size, it's because driver can't create size
       // that we want.  In that case, there's no helping it, we have to give up.
       // that we want.  In that case, there's no helping it, we have to give up.
       dxgsg9_cat.error()
       dxgsg9_cat.error()
-        << "Unable to copy to texture, texture is wrong size: " << *dtc->_texture << endl;
+        << "Unable to copy to texture, texture is wrong size: " << *dtc->get_texture() << endl;
       SAFE_RELEASE(tex_level_0);
       SAFE_RELEASE(tex_level_0);
       return;
       return;
     }
     }
@@ -4460,7 +4443,7 @@ reset_d3d_device(D3DPRESENT_PARAMETERS *presentation_params,
     release_all_index_buffers();
     release_all_index_buffers();
 
 
     // must be called before reset
     // must be called before reset
-    _prepared_objects->update(this);
+    _prepared_objects->begin_frame(this);
 
 
     hr = _d3d_device->Reset(&_presentation_reset);
     hr = _d3d_device->Reset(&_presentation_reset);
     if (FAILED(hr)) {
     if (FAILED(hr)) {
@@ -4518,7 +4501,7 @@ check_cooperative_level() {
     _dx_is_ready = false;
     _dx_is_ready = false;
 
 
     // call this just in case
     // call this just in case
-    _prepared_objects->update (this);
+    _prepared_objects->begin_frame(this);
 
 
     hr = reset_d3d_device(&_screen->_presentation_params);
     hr = reset_d3d_device(&_screen->_presentation_params);
     if (FAILED(hr)) {
     if (FAILED(hr)) {

+ 2 - 2
panda/src/dxgsg9/dxIndexBufferContext9.cxx

@@ -32,8 +32,8 @@ TypeHandle DXIndexBufferContext9::_type_handle;
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 DXIndexBufferContext9::
 DXIndexBufferContext9::
-DXIndexBufferContext9(GeomPrimitive *data) :
-  IndexBufferContext(data),
+DXIndexBufferContext9(PreparedGraphicsObjects *pgo, GeomPrimitive *data) :
+  IndexBufferContext(pgo, data),
   _ibuffer(NULL)
   _ibuffer(NULL)
 {
 {
   _managed = -1;
   _managed = -1;

+ 1 - 1
panda/src/dxgsg9/dxIndexBufferContext9.h

@@ -30,7 +30,7 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDADX DXIndexBufferContext9 : public IndexBufferContext {
 class EXPCL_PANDADX DXIndexBufferContext9 : public IndexBufferContext {
 public:
 public:
-  DXIndexBufferContext9(GeomPrimitive *data);
+  DXIndexBufferContext9(PreparedGraphicsObjects *pgo, GeomPrimitive *data);
   virtual ~DXIndexBufferContext9();
   virtual ~DXIndexBufferContext9();
 
 
   void free_ibuffer(void);
   void free_ibuffer(void);

+ 61 - 62
panda/src/dxgsg9/dxTextureContext9.cxx

@@ -37,8 +37,8 @@ static const DWORD g_LowByteMask = 0x000000FF;
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 DXTextureContext9::
 DXTextureContext9::
-DXTextureContext9(Texture *tex) :
-  TextureContext(tex) {
+DXTextureContext9(PreparedGraphicsObjects *pgo, Texture *tex) :
+  TextureContext(pgo, tex) {
 
 
   if (dxgsg9_cat.is_spam()) {
   if (dxgsg9_cat.is_spam()) {
     dxgsg9_cat.spam()
     dxgsg9_cat.spam()
@@ -63,7 +63,7 @@ DXTextureContext9::
 ~DXTextureContext9() {
 ~DXTextureContext9() {
   if (dxgsg9_cat.is_spam()) {
   if (dxgsg9_cat.is_spam()) {
     dxgsg9_cat.spam()
     dxgsg9_cat.spam()
-      << "Deleting texture context for " << _texture->get_name() << "\n";
+      << "Deleting texture context for " << get_texture()->get_name() << "\n";
   }
   }
 
 
   if (_lru_page)
   if (_lru_page)
@@ -94,32 +94,31 @@ create_texture(DXScreenData &scrn) {
   D3DFORMAT target_pixel_format = D3DFMT_UNKNOWN;
   D3DFORMAT target_pixel_format = D3DFMT_UNKNOWN;
   bool needs_luminance = false;
   bool needs_luminance = false;
 
 
-  nassertr(IS_VALID_PTR(_texture), false);
+  nassertr(IS_VALID_PTR(get_texture()), false);
 
 
   delete_texture();
   delete_texture();
-
-  clear_dirty_flags(Texture::DF_image | Texture::DF_mipmap);
+  mark_loaded();
 
 
   // bpp indicates requested fmt, not texture fmt
   // bpp indicates requested fmt, not texture fmt
-  DWORD target_bpp = get_bits_per_pixel(_texture->get_format(), &num_alpha_bits);
-  DWORD num_color_channels = _texture->get_num_components();
+  DWORD target_bpp = get_bits_per_pixel(get_texture()->get_format(), &num_alpha_bits);
+  DWORD num_color_channels = get_texture()->get_num_components();
 
 
   //PRINT_REFCNT(dxgsg9, scrn._d3d9);
   //PRINT_REFCNT(dxgsg9, scrn._d3d9);
 
 
-  DWORD orig_width = (DWORD)_texture->get_x_size();
-  DWORD orig_height = (DWORD)_texture->get_y_size();
-  DWORD orig_depth = (DWORD)_texture->get_z_size();
+  DWORD orig_width = (DWORD)get_texture()->get_x_size();
+  DWORD orig_height = (DWORD)get_texture()->get_y_size();
+  DWORD orig_depth = (DWORD)get_texture()->get_z_size();
 
 
-  if ((_texture->get_format() == Texture::F_luminance_alpha)||
-      (_texture->get_format() == Texture::F_luminance_alphamask) ||
-      (_texture->get_format() == Texture::F_luminance)) {
+  if ((get_texture()->get_format() == Texture::F_luminance_alpha)||
+      (get_texture()->get_format() == Texture::F_luminance_alphamask) ||
+      (get_texture()->get_format() == Texture::F_luminance)) {
     needs_luminance = true;
     needs_luminance = true;
   }
   }
 
 
   if (num_alpha_bits > 0) {
   if (num_alpha_bits > 0) {
     if (num_color_channels == 3) {
     if (num_color_channels == 3) {
       dxgsg9_cat.error()
       dxgsg9_cat.error()
-        << "texture " << _texture->get_name()
+        << "texture " << get_texture()->get_name()
         << " has no inherent alpha channel, but alpha format is requested!\n";
         << " has no inherent alpha channel, but alpha format is requested!\n";
     }
     }
   }
   }
@@ -157,7 +156,7 @@ create_texture(DXScreenData &scrn) {
 
 
   DWORD filter_caps;
   DWORD filter_caps;
 
 
-  switch (_texture->get_texture_type()) {
+  switch (get_texture()->get_texture_type()) {
   case Texture::TT_1d_texture:
   case Texture::TT_1d_texture:
   case Texture::TT_2d_texture:
   case Texture::TT_2d_texture:
     filter_caps = scrn._d3dcaps.TextureFilterCaps;
     filter_caps = scrn._d3dcaps.TextureFilterCaps;
@@ -251,15 +250,15 @@ create_texture(DXScreenData &scrn) {
 
 
   if (orig_width != target_width || orig_height != target_height ||
   if (orig_width != target_width || orig_height != target_height ||
       orig_depth != target_depth) {
       orig_depth != target_depth) {
-    if (_texture->get_texture_type() == Texture::TT_3d_texture) {
+    if (get_texture()->get_texture_type() == Texture::TT_3d_texture) {
       dxgsg9_cat.info()
       dxgsg9_cat.info()
-        << "Reducing size of " << _texture->get_name()
+        << "Reducing size of " << get_texture()->get_name()
         << " from " << orig_width << "x" << orig_height << "x" << orig_depth
         << " from " << orig_width << "x" << orig_height << "x" << orig_depth
         << " to " << target_width << "x" << target_height
         << " to " << target_width << "x" << target_height
         << "x" << target_depth << "\n";
         << "x" << target_depth << "\n";
     } else {
     } else {
       dxgsg9_cat.info()
       dxgsg9_cat.info()
-        << "Reducing size of " << _texture->get_name()
+        << "Reducing size of " << get_texture()->get_name()
         << " from " << orig_width << "x" << orig_height
         << " from " << orig_width << "x" << orig_height
         << " to " << target_width << "x" << target_height << "\n";
         << " to " << target_width << "x" << target_height << "\n";
     }
     }
@@ -469,7 +468,7 @@ create_texture(DXScreenData &scrn) {
 
 
   // if we've gotten here, haven't found a match
   // if we've gotten here, haven't found a match
   dxgsg9_cat.error()
   dxgsg9_cat.error()
-    << error_message << ": " << _texture->get_name() << endl
+    << error_message << ": " << get_texture()->get_name() << endl
     << "NumColorChannels: " << num_color_channels << "; NumAlphaBits: "
     << "NumColorChannels: " << num_color_channels << "; NumAlphaBits: "
     << num_alpha_bits << "; targetbpp: " <<target_bpp
     << num_alpha_bits << "; targetbpp: " <<target_bpp
     << "; _supported_tex_formats_mask: 0x"
     << "; _supported_tex_formats_mask: 0x"
@@ -482,7 +481,7 @@ create_texture(DXScreenData &scrn) {
  found_matching_format:
  found_matching_format:
   // We found a suitable format that matches the texture's format.
   // We found a suitable format that matches the texture's format.
 
 
-  if (_texture->get_match_framebuffer_format()) {
+  if (get_texture()->get_match_framebuffer_format()) {
     // Instead of creating a texture with the found format, we will
     // Instead of creating a texture with the found format, we will
     // need to make one that exactly matches the framebuffer's
     // need to make one that exactly matches the framebuffer's
     // format.  Look up what that format is.
     // format.  Look up what that format is.
@@ -520,7 +519,7 @@ create_texture(DXScreenData &scrn) {
 
 
   Texture::FilterType ft;
   Texture::FilterType ft;
 
 
-  ft = _texture->get_magfilter();
+  ft = get_texture()->get_magfilter();
   if ((ft != Texture::FT_linear) && ft != Texture::FT_nearest) {
   if ((ft != Texture::FT_linear) && ft != Texture::FT_nearest) {
     // mipmap settings make no sense for magfilter
     // mipmap settings make no sense for magfilter
     if (ft == Texture::FT_nearest_mipmap_nearest) {
     if (ft == Texture::FT_nearest_mipmap_nearest) {
@@ -534,10 +533,10 @@ create_texture(DXScreenData &scrn) {
       (filter_caps & D3DPTFILTERCAPS_MAGFLINEAR) == 0) {
       (filter_caps & D3DPTFILTERCAPS_MAGFLINEAR) == 0) {
     ft = Texture::FT_nearest;
     ft = Texture::FT_nearest;
   }
   }
-  _texture->set_magfilter(ft);
+  get_texture()->set_magfilter(ft);
 
 
   // figure out if we are mipmapping this texture
   // figure out if we are mipmapping this texture
-  ft = _texture->get_minfilter();
+  ft = get_texture()->get_minfilter();
   _has_mipmaps = false;
   _has_mipmaps = false;
 
 
   if (!dx_ignore_mipmaps) {  // set if no HW mipmap capable
   if (!dx_ignore_mipmaps) {  // set if no HW mipmap capable
@@ -555,11 +554,11 @@ create_texture(DXScreenData &scrn) {
         if (ft != Texture::FT_linear_mipmap_linear) {
         if (ft != Texture::FT_linear_mipmap_linear) {
           dxgsg9_cat.spam()
           dxgsg9_cat.spam()
             << "Forcing trilinear mipmapping on DX texture ["
             << "Forcing trilinear mipmapping on DX texture ["
-            << _texture->get_name() << "]\n";
+            << get_texture()->get_name() << "]\n";
         }
         }
       }
       }
       ft = Texture::FT_linear_mipmap_linear;
       ft = Texture::FT_linear_mipmap_linear;
-      _texture->set_minfilter(ft);
+      get_texture()->set_minfilter(ft);
     }
     }
 
 
   } else if ((ft == Texture::FT_nearest_mipmap_nearest) ||   // cvt to no-mipmap filter types
   } else if ((ft == Texture::FT_nearest_mipmap_nearest) ||   // cvt to no-mipmap filter types
@@ -611,23 +610,23 @@ create_texture(DXScreenData &scrn) {
     break;
     break;
   }
   }
 
 
-  _texture->set_minfilter(ft);
+  get_texture()->set_minfilter(ft);
 
 
   uint aniso_degree;
   uint aniso_degree;
 
 
   aniso_degree = 1;
   aniso_degree = 1;
   if (scrn._d3dcaps.RasterCaps & D3DPRASTERCAPS_ANISOTROPY) {
   if (scrn._d3dcaps.RasterCaps & D3DPRASTERCAPS_ANISOTROPY) {
-    aniso_degree = _texture->get_anisotropic_degree();
+    aniso_degree = get_texture()->get_anisotropic_degree();
     if ((aniso_degree>scrn._d3dcaps.MaxAnisotropy) ||
     if ((aniso_degree>scrn._d3dcaps.MaxAnisotropy) ||
         dx_force_anisotropic_filtering) {
         dx_force_anisotropic_filtering) {
       aniso_degree = scrn._d3dcaps.MaxAnisotropy;
       aniso_degree = scrn._d3dcaps.MaxAnisotropy;
     }
     }
   }
   }
-  _texture->set_anisotropic_degree(aniso_degree);
+  get_texture()->set_anisotropic_degree(aniso_degree);
 
 
 #ifdef _DEBUG
 #ifdef _DEBUG
   dxgsg9_cat.spam()
   dxgsg9_cat.spam()
-    << "create_texture: setting aniso degree for " << _texture->get_name()
+    << "create_texture: setting aniso degree for " << get_texture()->get_name()
     << " to: " << aniso_degree << endl;
     << " to: " << aniso_degree << endl;
 #endif
 #endif
 
 
@@ -639,7 +638,7 @@ create_texture(DXScreenData &scrn) {
 
 
     if (dxgsg9_cat.is_debug()) {
     if (dxgsg9_cat.is_debug()) {
       dxgsg9_cat.debug()
       dxgsg9_cat.debug()
-        << "create_texture: generating mipmaps for " << _texture->get_name()
+        << "create_texture: generating mipmaps for " << get_texture()->get_name()
         << endl;
         << endl;
     }
     }
   } else {
   } else {
@@ -649,7 +648,7 @@ create_texture(DXScreenData &scrn) {
   DWORD usage;
   DWORD usage;
   D3DPOOL pool;
   D3DPOOL pool;
 
 
-  if (_texture->get_render_to_texture ( )) {
+  if (get_texture()->get_render_to_texture ( )) {
     // REQUIRED PARAMETERS
     // REQUIRED PARAMETERS
     _managed = false;
     _managed = false;
     pool = D3DPOOL_DEFAULT;
     pool = D3DPOOL_DEFAULT;
@@ -752,7 +751,7 @@ create_texture(DXScreenData &scrn) {
   {
   {
     data_size = (int) ((float) data_size * 1.3f);
     data_size = (int) ((float) data_size * 1.3f);
   }
   }
-  if (_texture->get_texture_type() == Texture::TT_cube_map)
+  if (get_texture()->get_texture_type() == Texture::TT_cube_map)
   {
   {
     data_size *= 6;
     data_size *= 6;
   }
   }
@@ -762,7 +761,7 @@ create_texture(DXScreenData &scrn) {
   attempts = 0;
   attempts = 0;
   do
   do
   {
   {
-    switch (_texture->get_texture_type()) {
+    switch (get_texture()->get_texture_type()) {
     case Texture::TT_1d_texture:
     case Texture::TT_1d_texture:
     case Texture::TT_2d_texture:
     case Texture::TT_2d_texture:
       hr = scrn._d3d_device->CreateTexture
       hr = scrn._d3d_device->CreateTexture
@@ -800,7 +799,7 @@ create_texture(DXScreenData &scrn) {
 
 
   if (DEBUG_TEXTURES && dxgsg9_cat.is_debug()) {
   if (DEBUG_TEXTURES && dxgsg9_cat.is_debug()) {
     dxgsg9_cat.debug()
     dxgsg9_cat.debug()
-      << "create_texture: " << _texture->get_name()
+      << "create_texture: " << get_texture()->get_name()
       << " converting panda equivalent of " << D3DFormatStr(_d3d_format)
       << " converting panda equivalent of " << D3DFormatStr(_d3d_format)
       << " => " << D3DFormatStr(target_pixel_format) << endl;
       << " => " << D3DFormatStr(target_pixel_format) << endl;
   }
   }
@@ -814,7 +813,7 @@ create_texture(DXScreenData &scrn) {
 
 
 
 
   // must not put render to texture into LRU
   // must not put render to texture into LRU
-  if (_lru_page == 0 && _managed == false && _texture->get_render_to_texture ( ) == false)
+  if (_lru_page == 0 && _managed == false && get_texture()->get_render_to_texture ( ) == false)
   {
   {
     Lru *lru;
     Lru *lru;
 
 
@@ -1130,14 +1129,14 @@ d3d_surface_to_texture(RECT &source_rect, IDirect3DSurface9 *d3d_surface,
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 HRESULT DXTextureContext9::
 HRESULT DXTextureContext9::
 fill_d3d_texture_pixels() {
 fill_d3d_texture_pixels() {
-  if (_texture->get_texture_type() == Texture::TT_3d_texture) {
+  if (get_texture()->get_texture_type() == Texture::TT_3d_texture) {
     return fill_d3d_volume_texture_pixels();
     return fill_d3d_volume_texture_pixels();
   }
   }
 
 
   HRESULT hr = E_FAIL;
   HRESULT hr = E_FAIL;
-  nassertr(IS_VALID_PTR(_texture), E_FAIL);
+  nassertr(IS_VALID_PTR(get_texture()), E_FAIL);
 
 
-  CPTA_uchar image = _texture->get_ram_image();
+  CPTA_uchar image = get_texture()->get_ram_image();
   if (image.is_null()) {
   if (image.is_null()) {
     // The texture doesn't have an image to load.  That's ok; it
     // The texture doesn't have an image to load.  That's ok; it
     // might be a texture we've rendered to by frame buffer
     // might be a texture we've rendered to by frame buffer
@@ -1149,13 +1148,13 @@ fill_d3d_texture_pixels() {
 
 
   nassertr(IS_VALID_PTR(_d3d_texture), E_FAIL);
   nassertr(IS_VALID_PTR(_d3d_texture), E_FAIL);
 
 
-  DWORD orig_width  = (DWORD) _texture->get_x_size();
-  DWORD orig_height = (DWORD) _texture->get_y_size();
-  DWORD orig_depth = (DWORD) _texture->get_z_size();
-  DWORD num_color_channels = _texture->get_num_components();
+  DWORD orig_width  = (DWORD) get_texture()->get_x_size();
+  DWORD orig_height = (DWORD) get_texture()->get_y_size();
+  DWORD orig_depth = (DWORD) get_texture()->get_z_size();
+  DWORD num_color_channels = get_texture()->get_num_components();
   D3DFORMAT source_format = _d3d_format;
   D3DFORMAT source_format = _d3d_format;
   BYTE *image_pixels = (BYTE*)image.p();
   BYTE *image_pixels = (BYTE*)image.p();
-  int component_width = _texture->get_component_width();
+  int component_width = get_texture()->get_component_width();
 
 
   nassertr(IS_VALID_PTR(image_pixels), E_FAIL);
   nassertr(IS_VALID_PTR(image_pixels), E_FAIL);
 
 
@@ -1164,10 +1163,10 @@ fill_d3d_texture_pixels() {
   BYTE *pixels = NULL;
   BYTE *pixels = NULL;
 
 
   for (unsigned int di = 0; di < orig_depth; di++) {
   for (unsigned int di = 0; di < orig_depth; di++) {
-    pixels = image_pixels + di * _texture->get_expected_ram_page_size();
+    pixels = image_pixels + di * get_texture()->get_expected_ram_page_size();
     mip_level_0 = NULL;
     mip_level_0 = NULL;
 
 
-    if (_texture->get_texture_type() == Texture::TT_cube_map) {
+    if (get_texture()->get_texture_type() == Texture::TT_cube_map) {
       nassertr(IS_VALID_PTR(_d3d_cube_texture), E_FAIL);
       nassertr(IS_VALID_PTR(_d3d_cube_texture), E_FAIL);
       hr = _d3d_cube_texture->GetCubeMapSurface((D3DCUBEMAP_FACES)di, 0, &mip_level_0);
       hr = _d3d_cube_texture->GetCubeMapSurface((D3DCUBEMAP_FACES)di, 0, &mip_level_0);
     } else {
     } else {
@@ -1177,7 +1176,7 @@ fill_d3d_texture_pixels() {
 
 
     if (FAILED(hr)) {
     if (FAILED(hr)) {
       dxgsg9_cat.error()
       dxgsg9_cat.error()
-        << "FillDDSurfaceTexturePixels failed for " << _texture->get_name()
+        << "FillDDSurfaceTexturePixels failed for " << get_texture()->get_name()
       << ", GetSurfaceLevel failed" << D3DERRORSTRING(hr);
       << ", GetSurfaceLevel failed" << D3DERRORSTRING(hr);
       return E_FAIL;
       return E_FAIL;
     }
     }
@@ -1231,7 +1230,7 @@ fill_d3d_texture_pixels() {
       // original image, but dx8 doesn't support high-precision images
       // original image, but dx8 doesn't support high-precision images
       // anyway.
       // anyway.
 
 
-      int num_components = _texture->get_num_components();
+      int num_components = get_texture()->get_num_components();
       int num_pixels = orig_width * orig_height * num_components;
       int num_pixels = orig_width * orig_height * num_components;
       BYTE *temp_buffer = new BYTE[num_pixels];
       BYTE *temp_buffer = new BYTE[num_pixels];
       if (!IS_VALID_PTR(temp_buffer)) {
       if (!IS_VALID_PTR(temp_buffer)) {
@@ -1259,7 +1258,7 @@ fill_d3d_texture_pixels() {
        &source_size, level_0_filter, (D3DCOLOR)0x0);
        &source_size, level_0_filter, (D3DCOLOR)0x0);
     if (FAILED(hr)) {
     if (FAILED(hr)) {
       dxgsg9_cat.error()
       dxgsg9_cat.error()
-        << "FillDDSurfaceTexturePixels failed for " << _texture->get_name()
+        << "FillDDSurfaceTexturePixels failed for " << get_texture()->get_name()
         << ", D3DXLoadSurfFromMem failed" << D3DERRORSTRING(hr);
         << ", D3DXLoadSurfFromMem failed" << D3DERRORSTRING(hr);
       goto exit_FillDDSurf;
       goto exit_FillDDSurf;
     }
     }
@@ -1277,7 +1276,7 @@ fill_d3d_texture_pixels() {
                              mip_filter_flags);
                              mip_filter_flags);
       if (FAILED(hr)) {
       if (FAILED(hr)) {
         dxgsg9_cat.error()
         dxgsg9_cat.error()
-          << "FillDDSurfaceTexturePixels failed for " << _texture->get_name()
+          << "FillDDSurfaceTexturePixels failed for " << get_texture()->get_name()
           << ", D3DXFilterTex failed" << D3DERRORSTRING(hr);
           << ", D3DXFilterTex failed" << D3DERRORSTRING(hr);
         goto exit_FillDDSurf;
         goto exit_FillDDSurf;
       }
       }
@@ -1308,9 +1307,9 @@ fill_d3d_texture_pixels() {
 HRESULT DXTextureContext9::
 HRESULT DXTextureContext9::
 fill_d3d_volume_texture_pixels() {
 fill_d3d_volume_texture_pixels() {
   HRESULT hr = E_FAIL;
   HRESULT hr = E_FAIL;
-  nassertr(IS_VALID_PTR(_texture), E_FAIL);
+  nassertr(IS_VALID_PTR(get_texture()), E_FAIL);
 
 
-  CPTA_uchar image = _texture->get_ram_image();
+  CPTA_uchar image = get_texture()->get_ram_image();
   if (image.is_null()) {
   if (image.is_null()) {
     // The texture doesn't have an image to load.  That's ok; it
     // The texture doesn't have an image to load.  That's ok; it
     // might be a texture we've rendered to by frame buffer
     // might be a texture we've rendered to by frame buffer
@@ -1321,15 +1320,15 @@ fill_d3d_volume_texture_pixels() {
   PStatTimer timer(GraphicsStateGuardian::_load_texture_pcollector);
   PStatTimer timer(GraphicsStateGuardian::_load_texture_pcollector);
 
 
   nassertr(IS_VALID_PTR(_d3d_texture), E_FAIL);
   nassertr(IS_VALID_PTR(_d3d_texture), E_FAIL);
-  nassertr(_texture->get_texture_type() == Texture::TT_3d_texture, E_FAIL);
+  nassertr(get_texture()->get_texture_type() == Texture::TT_3d_texture, E_FAIL);
 
 
-  DWORD orig_width  = (DWORD) _texture->get_x_size();
-  DWORD orig_height = (DWORD) _texture->get_y_size();
-  DWORD orig_depth = (DWORD) _texture->get_z_size();
-  DWORD num_color_channels = _texture->get_num_components();
+  DWORD orig_width  = (DWORD) get_texture()->get_x_size();
+  DWORD orig_height = (DWORD) get_texture()->get_y_size();
+  DWORD orig_depth = (DWORD) get_texture()->get_z_size();
+  DWORD num_color_channels = get_texture()->get_num_components();
   D3DFORMAT source_format = _d3d_format;
   D3DFORMAT source_format = _d3d_format;
   BYTE *image_pixels = (BYTE*)image.p();
   BYTE *image_pixels = (BYTE*)image.p();
-  int component_width = _texture->get_component_width();
+  int component_width = get_texture()->get_component_width();
 
 
   nassertr(IS_VALID_PTR(image_pixels), E_FAIL);
   nassertr(IS_VALID_PTR(image_pixels), E_FAIL);
 
 
@@ -1342,7 +1341,7 @@ fill_d3d_volume_texture_pixels() {
 
 
   if (FAILED(hr)) {
   if (FAILED(hr)) {
     dxgsg9_cat.error()
     dxgsg9_cat.error()
-      << "FillDDSurfaceTexturePixels failed for " << _texture->get_name()
+      << "FillDDSurfaceTexturePixels failed for " << get_texture()->get_name()
       << ", GetSurfaceLevel failed" << D3DERRORSTRING(hr);
       << ", GetSurfaceLevel failed" << D3DERRORSTRING(hr);
     return E_FAIL;
     return E_FAIL;
   }
   }
@@ -1401,7 +1400,7 @@ fill_d3d_volume_texture_pixels() {
     // original image, but dx8 doesn't support high-precision images
     // original image, but dx8 doesn't support high-precision images
     // anyway.
     // anyway.
 
 
-    int num_components = _texture->get_num_components();
+    int num_components = get_texture()->get_num_components();
     int num_pixels = orig_width * orig_height * orig_depth * num_components;
     int num_pixels = orig_width * orig_height * orig_depth * num_components;
     BYTE *temp_buffer = new BYTE[num_pixels];
     BYTE *temp_buffer = new BYTE[num_pixels];
     if (!IS_VALID_PTR(temp_buffer)) {
     if (!IS_VALID_PTR(temp_buffer)) {
@@ -1430,7 +1429,7 @@ fill_d3d_volume_texture_pixels() {
      &source_size, level_0_filter, (D3DCOLOR)0x0);
      &source_size, level_0_filter, (D3DCOLOR)0x0);
   if (FAILED(hr)) {
   if (FAILED(hr)) {
     dxgsg9_cat.error()
     dxgsg9_cat.error()
-      << "FillDDSurfaceTexturePixels failed for " << _texture->get_name()
+      << "FillDDSurfaceTexturePixels failed for " << get_texture()->get_name()
       << ", D3DXLoadVolumeFromMem failed" << D3DERRORSTRING(hr);
       << ", D3DXLoadVolumeFromMem failed" << D3DERRORSTRING(hr);
     goto exit_FillDDSurf;
     goto exit_FillDDSurf;
   }
   }
@@ -1448,7 +1447,7 @@ fill_d3d_volume_texture_pixels() {
                            mip_filter_flags);
                            mip_filter_flags);
     if (FAILED(hr)) {
     if (FAILED(hr)) {
       dxgsg9_cat.error()
       dxgsg9_cat.error()
-        << "FillDDSurfaceTexturePixels failed for " << _texture->get_name()
+        << "FillDDSurfaceTexturePixels failed for " << get_texture()->get_name()
         << ", D3DXFilterTex failed" << D3DERRORSTRING(hr);
         << ", D3DXFilterTex failed" << D3DERRORSTRING(hr);
       goto exit_FillDDSurf;
       goto exit_FillDDSurf;
     }
     }

+ 1 - 1
panda/src/dxgsg9/dxTextureContext9.h

@@ -31,7 +31,7 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDADX DXTextureContext9 : public TextureContext {
 class EXPCL_PANDADX DXTextureContext9 : public TextureContext {
 public:
 public:
-  DXTextureContext9(Texture *tex);
+  DXTextureContext9(PreparedGraphicsObjects *pgo, Texture *tex);
   virtual ~DXTextureContext9();
   virtual ~DXTextureContext9();
 
 
   bool create_texture(DXScreenData &scrn);
   bool create_texture(DXScreenData &scrn);

+ 2 - 2
panda/src/dxgsg9/dxVertexBufferContext9.cxx

@@ -34,8 +34,8 @@ TypeHandle DXVertexBufferContext9::_type_handle;
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 DXVertexBufferContext9::
 DXVertexBufferContext9::
-DXVertexBufferContext9(GeomVertexArrayData *data, DXScreenData &scrn) :
-  VertexBufferContext(data),
+DXVertexBufferContext9(PreparedGraphicsObjects *pgo, GeomVertexArrayData *data, DXScreenData &scrn) :
+  VertexBufferContext(pgo, data),
   _vbuffer(NULL)
   _vbuffer(NULL)
 {
 {
   // Now fill in the FVF code.
   // Now fill in the FVF code.

+ 1 - 1
panda/src/dxgsg9/dxVertexBufferContext9.h

@@ -30,7 +30,7 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDADX DXVertexBufferContext9 : public VertexBufferContext {
 class EXPCL_PANDADX DXVertexBufferContext9 : public VertexBufferContext {
 public:
 public:
-  DXVertexBufferContext9(GeomVertexArrayData *data, DXScreenData &scrn);
+  DXVertexBufferContext9(PreparedGraphicsObjects *pgo, GeomVertexArrayData *data, DXScreenData &scrn);
   virtual ~DXVertexBufferContext9();
   virtual ~DXVertexBufferContext9();
 
 
   void free_vbuffer(void);
   void free_vbuffer(void);

+ 4 - 4
panda/src/express/pipelineCyclerLinks.I

@@ -20,7 +20,7 @@
 #ifdef THREADED_PIPELINE
 #ifdef THREADED_PIPELINE
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PipelineCyclerLinks::Constructor
 //     Function: PipelineCyclerLinks::Constructor
-//       Access: Public
+//       Access: Protected
 //  Description: 
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE PipelineCyclerLinks::
 INLINE PipelineCyclerLinks::
@@ -35,7 +35,7 @@ PipelineCyclerLinks() {
 #ifdef THREADED_PIPELINE
 #ifdef THREADED_PIPELINE
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PipelineCyclerLinks::Destructor
 //     Function: PipelineCyclerLinks::Destructor
-//       Access: Public
+//       Access: Protected
 //  Description: 
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE PipelineCyclerLinks::
 INLINE PipelineCyclerLinks::
@@ -47,7 +47,7 @@ INLINE PipelineCyclerLinks::
 #ifdef THREADED_PIPELINE
 #ifdef THREADED_PIPELINE
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PipelineCyclerLinks::remove_from_list
 //     Function: PipelineCyclerLinks::remove_from_list
-//       Access: Private
+//       Access: Protected
 //  Description: Removes a PipelineCyclerLinks record from the
 //  Description: Removes a PipelineCyclerLinks record from the
 //               doubly-linked list.
 //               doubly-linked list.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -66,7 +66,7 @@ remove_from_list() {
 #ifdef THREADED_PIPELINE
 #ifdef THREADED_PIPELINE
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PipelineCyclerLinks::insert_before
 //     Function: PipelineCyclerLinks::insert_before
-//       Access: Private
+//       Access: Protected
 //  Description: Adds a PipelineCyclerLinks record before the indicated
 //  Description: Adds a PipelineCyclerLinks record before the indicated
 //               node in the doubly-linked list.
 //               node in the doubly-linked list.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 65 - 24
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -1236,8 +1236,20 @@ end_frame() {
     GLP(Flush)();
     GLP(Flush)();
   }
   }
 
 
+#ifdef DO_PSTATS
+  // Check for textures, etc., that are no longer resident.
+  check_nonresident_texture(_prepared_objects->_texture_residency.get_inactive_resident());
+  check_nonresident_texture(_prepared_objects->_texture_residency.get_active_resident());
+
+  // OpenGL provides no methods for querying whether a buffer object
+  // (vertex buffer) is resident.  In fact, the API appears geared
+  // towards the assumption that such buffers are always resident.
+  // OK.
+#endif
+
   report_my_gl_errors();
   report_my_gl_errors();
 }
 }
+    
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GLGraphicsStateGuardian::begin_draw_primitives
 //     Function: GLGraphicsStateGuardian::begin_draw_primitives
@@ -2117,7 +2129,7 @@ prepare_texture(Texture *tex) {
     break;
     break;
   }
   }
 
 
-  CLP(TextureContext) *gtc = new CLP(TextureContext)(tex);
+  CLP(TextureContext) *gtc = new CLP(TextureContext)(_prepared_objects, tex);
   GLP(GenTextures)(1, &gtc->_index);
   GLP(GenTextures)(1, &gtc->_index);
   report_my_gl_errors();
   report_my_gl_errors();
 
 
@@ -2529,7 +2541,7 @@ record_deleted_display_list(GLuint index) {
 VertexBufferContext *CLP(GraphicsStateGuardian)::
 VertexBufferContext *CLP(GraphicsStateGuardian)::
 prepare_vertex_buffer(GeomVertexArrayData *data) {
 prepare_vertex_buffer(GeomVertexArrayData *data) {
   if (_supports_buffers) {
   if (_supports_buffers) {
-    CLP(VertexBufferContext) *gvbc = new CLP(VertexBufferContext)(data);
+    CLP(VertexBufferContext) *gvbc = new CLP(VertexBufferContext)(_prepared_objects, data);
     _glGenBuffers(1, &gvbc->_index);
     _glGenBuffers(1, &gvbc->_index);
 
 
     if (GLCAT.is_debug()) {
     if (GLCAT.is_debug()) {
@@ -2566,7 +2578,7 @@ apply_vertex_buffer(VertexBufferContext *vbc) {
     }
     }
     _glBindBuffer(GL_ARRAY_BUFFER, gvbc->_index);
     _glBindBuffer(GL_ARRAY_BUFFER, gvbc->_index);
     _current_vbuffer_index = gvbc->_index;
     _current_vbuffer_index = gvbc->_index;
-    add_to_vertex_buffer_record(gvbc);
+    gvbc->set_active(true);
   }
   }
 
 
   if (gvbc->was_modified()) {
   if (gvbc->was_modified()) {
@@ -2589,7 +2601,7 @@ apply_vertex_buffer(VertexBufferContext *vbc) {
       }
       }
       _data_transferred_pcollector.add_level(num_bytes);
       _data_transferred_pcollector.add_level(num_bytes);
     }
     }
-    add_to_total_buffer_record(gvbc);
+
     gvbc->mark_loaded();
     gvbc->mark_loaded();
   }
   }
 
 
@@ -2696,7 +2708,7 @@ setup_array_data(const GeomVertexArrayData *data) {
 IndexBufferContext *CLP(GraphicsStateGuardian)::
 IndexBufferContext *CLP(GraphicsStateGuardian)::
 prepare_index_buffer(GeomPrimitive *data) {
 prepare_index_buffer(GeomPrimitive *data) {
   if (_supports_buffers) {
   if (_supports_buffers) {
-    CLP(IndexBufferContext) *gibc = new CLP(IndexBufferContext)(data);
+    CLP(IndexBufferContext) *gibc = new CLP(IndexBufferContext)(_prepared_objects, data);
     _glGenBuffers(1, &gibc->_index);
     _glGenBuffers(1, &gibc->_index);
 
 
     if (GLCAT.is_debug()) {
     if (GLCAT.is_debug()) {
@@ -2734,7 +2746,7 @@ apply_index_buffer(IndexBufferContext *ibc) {
     }
     }
     _glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gibc->_index);
     _glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gibc->_index);
     _current_ibuffer_index = gibc->_index;
     _current_ibuffer_index = gibc->_index;
-    add_to_index_buffer_record(gibc);
+    gibc->set_active(true);
   }
   }
 
 
   if (gibc->was_modified()) {
   if (gibc->was_modified()) {
@@ -2757,7 +2769,6 @@ apply_index_buffer(IndexBufferContext *ibc) {
       }
       }
       _data_transferred_pcollector.add_level(num_bytes);
       _data_transferred_pcollector.add_level(num_bytes);
     }
     }
-    add_to_total_buffer_record(gibc);
     gibc->mark_loaded();
     gibc->mark_loaded();
   }
   }
 
 
@@ -6239,25 +6250,19 @@ void CLP(GraphicsStateGuardian)::
 apply_texture(TextureContext *tc) {
 apply_texture(TextureContext *tc) {
   CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
   CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
 
 
-  add_to_texture_record(gtc);
-  GLenum target = get_texture_target(gtc->_texture->get_texture_type());
+  gtc->set_active(true);
+  GLenum target = get_texture_target(gtc->get_texture()->get_texture_type());
   if (target == GL_NONE) {
   if (target == GL_NONE) {
     return;
     return;
   }
   }
   GLP(BindTexture)(target, gtc->_index);
   GLP(BindTexture)(target, gtc->_index);
 
 
-  int dirty = gtc->get_dirty_flags();
-  if ((dirty & (Texture::DF_wrap | Texture::DF_filter | Texture::DF_border)) != 0) {
-    // We need to re-specify the texture properties.
-    specify_texture(gtc->_texture);
-  }
-  if ((dirty & (Texture::DF_image | Texture::DF_mipmap)) != 0) {
-    // We need to re-upload the image.
+  if (gtc->was_modified()) {
+    specify_texture(gtc->get_texture());
     upload_texture(gtc);
     upload_texture(gtc);
+    gtc->mark_loaded();
   }
   }
 
 
-  gtc->clear_dirty_flags();
-
   report_my_gl_errors();
   report_my_gl_errors();
 }
 }
 
 
@@ -6272,7 +6277,7 @@ apply_texture(TextureContext *tc) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool CLP(GraphicsStateGuardian)::
 bool CLP(GraphicsStateGuardian)::
 upload_texture(CLP(TextureContext) *gtc) {
 upload_texture(CLP(TextureContext) *gtc) {
-  Texture *tex = gtc->_texture;
+  Texture *tex = gtc->get_texture();
   CPTA_uchar image = tex->get_ram_image();
   CPTA_uchar image = tex->get_ram_image();
   if (image.is_null()) {
   if (image.is_null()) {
     return false;
     return false;
@@ -6451,7 +6456,7 @@ upload_texture(CLP(TextureContext) *gtc) {
     gtc->_depth = depth;
     gtc->_depth = depth;
 
 
 #ifdef DO_PSTATS
 #ifdef DO_PSTATS
-    gtc->_texture_memory_size = get_texture_memory_size(tex);
+    gtc->update_data_size_bytes(get_texture_memory_size(tex));
 #endif
 #endif
 
 
 #ifndef NDEBUG
 #ifndef NDEBUG
@@ -6502,7 +6507,7 @@ upload_texture_image(CLP(TextureContext) *gtc,
 #endif
 #endif
 #ifndef NDEBUG
 #ifndef NDEBUG
     if (CLP(show_mipmaps) && target == GL_TEXTURE_2D) {
     if (CLP(show_mipmaps) && target == GL_TEXTURE_2D) {
-      build_phony_mipmaps(gtc->_texture);
+      build_phony_mipmaps(gtc->get_texture());
       report_my_gl_errors();
       report_my_gl_errors();
       return true;
       return true;
 
 
@@ -6552,10 +6557,10 @@ upload_texture_image(CLP(TextureContext) *gtc,
   if (GLCAT.is_debug()) {
   if (GLCAT.is_debug()) {
     if (image_compression != Texture::CM_off) {
     if (image_compression != Texture::CM_off) {
       GLCAT.debug()
       GLCAT.debug()
-	<< "loading pre-compressed texture " << gtc->_texture->get_name() << "\n";
+	<< "loading pre-compressed texture " << gtc->get_texture()->get_name() << "\n";
     } else if (is_compressed_format(internal_format)) {
     } else if (is_compressed_format(internal_format)) {
       GLCAT.debug()
       GLCAT.debug()
-	<< "compressing texture " << gtc->_texture->get_name() << "\n";
+	<< "compressing texture " << gtc->get_texture()->get_name() << "\n";
     }
     }
   }
   }
 
 
@@ -6640,7 +6645,7 @@ upload_texture_image(CLP(TextureContext) *gtc,
   if (error_code != GL_NO_ERROR) {
   if (error_code != GL_NO_ERROR) {
     const GLubyte *error_string = GLUP(ErrorString)(error_code);
     const GLubyte *error_string = GLUP(ErrorString)(error_code);
     GLCAT.error()
     GLCAT.error()
-      << "GL texture creation failed for " << gtc->_texture->get_name();
+      << "GL texture creation failed for " << gtc->get_texture()->get_name();
     if (error_string != (const GLubyte *)NULL) {
     if (error_string != (const GLubyte *)NULL) {
       GLCAT.error(false)
       GLCAT.error(false)
         << " : " << error_string;
         << " : " << error_string;
@@ -6737,6 +6742,42 @@ get_texture_memory_size(Texture *tex) const {
   return result;
   return result;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GLGraphicsStateGuardian::check_nonresident_texture
+//       Access: Private
+//  Description: Checks the list of resident texture objects to see if
+//               any have recently been evicted.
+////////////////////////////////////////////////////////////////////
+void CLP(GraphicsStateGuardian)::
+check_nonresident_texture(BufferContextChain &chain) {
+  size_t num_textures = chain.get_count();
+  CLP(TextureContext) **gtc_list = (CLP(TextureContext) **)alloca(num_textures * sizeof(CLP(TextureContext) *));
+  GLuint *texture_list = (GLuint *)alloca(num_textures * sizeof(GLuint));
+  size_t ti = 0;
+  BufferContext *node = chain.get_first();
+  while (node != (BufferContext *)NULL) {
+    CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), node);
+    gtc_list[ti] = gtc;
+    texture_list[ti] = gtc->_index;
+    node = node->get_next();
+    ++ti;
+  }
+  nassertv(ti == num_textures);
+  GLboolean *results = (GLboolean *)alloca(num_textures * sizeof(GLboolean));
+  bool all_resident = (glAreTexturesResident(num_textures, texture_list, results) != 0);
+
+  report_my_gl_errors();
+
+  if (!all_resident) {
+    // Some are now nonresident.
+    for (ti = 0; ti < num_textures; ++ti) {
+      if (!results[ti]) {
+        gtc_list[ti]->set_resident(false);
+      }
+    }
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GLGraphicsStateGuardian::do_point_size
 //     Function: GLGraphicsStateGuardian::do_point_size
 //       Access: Protected
 //       Access: Protected

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

@@ -278,6 +278,7 @@ protected:
 			    Texture::CompressionMode image_compression);
 			    Texture::CompressionMode image_compression);
 
 
   size_t get_texture_memory_size(Texture *tex) const;
   size_t get_texture_memory_size(Texture *tex) const;
+  void check_nonresident_texture(BufferContextChain &chain);
 
 
   void do_point_size();
   void do_point_size();
 
 

+ 2 - 2
panda/src/glstuff/glIndexBufferContext_src.I

@@ -23,8 +23,8 @@
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE CLP(IndexBufferContext)::
 INLINE CLP(IndexBufferContext)::
-CLP(IndexBufferContext)(GeomPrimitive *data) :
-  IndexBufferContext(data)
+CLP(IndexBufferContext)(PreparedGraphicsObjects *pgo, GeomPrimitive *data) :
+  IndexBufferContext(pgo, data)
 {
 {
   _index = 0;
   _index = 0;
 }
 }

+ 2 - 1
panda/src/glstuff/glIndexBufferContext_src.h

@@ -26,7 +26,8 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 class EXPCL_GL CLP(IndexBufferContext) : public IndexBufferContext {
 class EXPCL_GL CLP(IndexBufferContext) : public IndexBufferContext {
 public:
 public:
-  INLINE CLP(IndexBufferContext)(GeomPrimitive *data);
+  INLINE CLP(IndexBufferContext)(PreparedGraphicsObjects *pgo, 
+                                 GeomPrimitive *data);
 
 
   // This is the GL "name" of the data object.
   // This is the GL "name" of the data object.
   GLuint _index;
   GLuint _index;

+ 2 - 3
panda/src/glstuff/glTextureContext_src.I

@@ -23,10 +23,9 @@
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE CLP(TextureContext)::
 INLINE CLP(TextureContext)::
-CLP(TextureContext)(Texture *tex) :
-  TextureContext(tex)
+CLP(TextureContext)(PreparedGraphicsObjects *pgo, Texture *tex) :
+  TextureContext(pgo, tex)
 {
 {
   _index = 0;
   _index = 0;
   _already_applied = false;
   _already_applied = false;
-  _texture_memory_size = 0;
 }
 }

+ 0 - 17
panda/src/glstuff/glTextureContext_src.cxx

@@ -19,20 +19,3 @@
 #include "notify.h"
 #include "notify.h"
 
 
 TypeHandle CLP(TextureContext)::_type_handle;
 TypeHandle CLP(TextureContext)::_type_handle;
-
-////////////////////////////////////////////////////////////////////
-//     Function: GLTextureContext::estimate_texture_memory
-//       Access: Public, Virtual
-//  Description: Estimates the amount of texture memory that will be
-//               consumed by loading this texture.  This is mainly
-//               useful for debugging and reporting purposes.
-//
-//               Returns a value in bytes.
-////////////////////////////////////////////////////////////////////
-size_t CLP(TextureContext)::
-estimate_texture_memory() {
-  if (_texture_memory_size == 0) {
-    return TextureContext::estimate_texture_memory();
-  }
-  return _texture_memory_size;
-}

+ 1 - 5
panda/src/glstuff/glTextureContext_src.h

@@ -25,9 +25,7 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 class EXPCL_GL CLP(TextureContext) : public TextureContext {
 class EXPCL_GL CLP(TextureContext) : public TextureContext {
 public:
 public:
-  INLINE CLP(TextureContext)(Texture *tex);
-
-  virtual size_t estimate_texture_memory();
+  INLINE CLP(TextureContext)(PreparedGraphicsObjects *pgo, Texture *tex);
 
 
   // This is the GL "name" of the texture object.
   // This is the GL "name" of the texture object.
   GLuint _index;
   GLuint _index;
@@ -41,8 +39,6 @@ public:
   GLsizei _height;
   GLsizei _height;
   GLsizei _depth;
   GLsizei _depth;
 
 
-  size_t _texture_memory_size;
-
 public:
 public:
   static TypeHandle get_class_type() {
   static TypeHandle get_class_type() {
     return _type_handle;
     return _type_handle;

+ 2 - 2
panda/src/glstuff/glVertexBufferContext_src.I

@@ -23,8 +23,8 @@
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE CLP(VertexBufferContext)::
 INLINE CLP(VertexBufferContext)::
-CLP(VertexBufferContext)(GeomVertexArrayData *data) :
-  VertexBufferContext(data)
+CLP(VertexBufferContext)(PreparedGraphicsObjects *pgo, GeomVertexArrayData *data) :
+  VertexBufferContext(pgo, data)
 {
 {
   _index = 0;
   _index = 0;
 }
 }

+ 2 - 1
panda/src/glstuff/glVertexBufferContext_src.h

@@ -26,7 +26,8 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 class EXPCL_GL CLP(VertexBufferContext) : public VertexBufferContext {
 class EXPCL_GL CLP(VertexBufferContext) : public VertexBufferContext {
 public:
 public:
-  INLINE CLP(VertexBufferContext)(GeomVertexArrayData *data);
+  INLINE CLP(VertexBufferContext)(PreparedGraphicsObjects *pgo, 
+                                  GeomVertexArrayData *data);
 
 
   // This is the GL "name" of the data object.
   // This is the GL "name" of the data object.
   GLuint _index;
   GLuint _index;

+ 9 - 0
panda/src/gobj/Sources.pp

@@ -11,6 +11,9 @@
   #define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx 
   #define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx 
 
 
   #define SOURCES \
   #define SOURCES \
+    bufferContext.I bufferContext.h \
+    bufferContextChain.I bufferContextChain.h \
+    bufferResidencyTracker.I bufferResidencyTracker.h \
     config_gobj.h \
     config_gobj.h \
     geom.h geom.I \
     geom.h geom.I \
     geomContext.I geomContext.h \
     geomContext.I geomContext.h \
@@ -61,6 +64,9 @@
     videoTexture.I videoTexture.h
     videoTexture.I videoTexture.h
     
     
   #define INCLUDED_SOURCES \
   #define INCLUDED_SOURCES \
+    bufferContext.cxx \
+    bufferContextChain.cxx \
+    bufferResidencyTracker.cxx \
     config_gobj.cxx \
     config_gobj.cxx \
     geomContext.cxx \
     geomContext.cxx \
     geom.cxx \
     geom.cxx \
@@ -108,6 +114,9 @@
     videoTexture.cxx
     videoTexture.cxx
 
 
   #define INSTALL_HEADERS \
   #define INSTALL_HEADERS \
+    bufferContext.I bufferContext.h \
+    bufferContextChain.I bufferContextChain.h \
+    bufferResidencyTracker.I bufferResidencyTracker.h \
     config_gobj.h \
     config_gobj.h \
     geom.I geom.h \
     geom.I geom.h \
     textureContext.I textureContext.h \
     textureContext.I textureContext.h \

+ 158 - 0
panda/src/gobj/bufferContext.I

@@ -0,0 +1,158 @@
+// Filename: bufferContext.I
+// Created by:  drose (16Mar06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: BufferContext::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE BufferContext::
+BufferContext(BufferResidencyTracker *residency) :
+  _residency(residency),
+  _residency_state(0),
+  _data_size_bytes(0),
+  _owning_chain(&residency->_chains[0])
+{
+#ifdef DO_PSTATS
+  ++(_owning_chain->_count);
+  insert_before(_owning_chain);
+#endif  // DO_PSTATS
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BufferContext::get_data_size_bytes
+//       Access: Public
+//  Description: Returns the number of bytes previously reported for
+//               the data object.  This is used to track changes in
+//               the data object's allocated size; if it changes from
+//               this, we need to create a new buffer.  This is also
+//               used to track memory utilization in PStats.
+////////////////////////////////////////////////////////////////////
+INLINE size_t BufferContext::
+get_data_size_bytes() const {
+  return _data_size_bytes;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BufferContext::get_modified
+//       Access: Public
+//  Description: Returns the UpdateSeq that was recorded the last time
+//               mark_loaded() was called.
+////////////////////////////////////////////////////////////////////
+INLINE UpdateSeq BufferContext::
+get_modified() const {
+  return _modified;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BufferContext::set_active
+//       Access: Public
+//  Description: Changes the active flag associated with this object.
+//               An object is considered "active" if it was rendered
+//               in the current frame.
+////////////////////////////////////////////////////////////////////
+INLINE void BufferContext::
+set_active(bool flag) {
+#ifdef DO_PSTATS
+  if (flag) {
+    _residency_state |= BufferResidencyTracker::S_active;
+    // Assume that rendering the object automatically makes it
+    // resident.
+    _residency_state |= BufferResidencyTracker::S_resident;
+  } else {
+    _residency_state &= ~BufferResidencyTracker::S_active;
+  }
+  set_owning_chain(&_residency->_chains[_residency_state]);
+#endif  // DO_PSTATS
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BufferContext::set_resident
+//       Access: Public
+//  Description: Changes the resident flag associated with this
+//               object.  An object is considered "resident" if it
+//               appears to be resident in texture memory.
+////////////////////////////////////////////////////////////////////
+INLINE void BufferContext::
+set_resident(bool flag) {
+#ifdef DO_PSTATS
+  if (flag) {
+    _residency_state |= BufferResidencyTracker::S_resident;
+  } else {
+    _residency_state &= ~BufferResidencyTracker::S_resident;
+  }
+  set_owning_chain(&_residency->_chains[_residency_state]);
+#endif  // DO_PSTATS
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BufferContext::get_next
+//       Access: Public
+//  Description: This can be used along with
+//               BufferContextChain::get_first() to walk through the
+//               list of objects stored on a tracker.
+////////////////////////////////////////////////////////////////////
+INLINE BufferContext *BufferContext::
+get_next() const {
+  if ((BufferContextChain *)_next == _owning_chain) {
+    return NULL;
+  }
+  return (BufferContext *)_next;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BufferContext::update_data_size_bytes
+//       Access: Public
+//  Description: Should be called (usually by a derived class) when
+//               the on-card size of this object has changed.
+////////////////////////////////////////////////////////////////////
+INLINE void BufferContext::
+update_data_size_bytes(size_t new_data_size_bytes) {
+  _owning_chain->adjust_bytes((int)new_data_size_bytes - (int)_data_size_bytes);
+  _data_size_bytes = new_data_size_bytes;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BufferContext::update_modified
+//       Access: Public
+//  Description: Should be called (usually by a derived class) when
+//               the modified counter for this object has changed.
+////////////////////////////////////////////////////////////////////
+INLINE void BufferContext::
+update_modified(UpdateSeq new_modified) {
+  _modified = new_modified;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BufferContext::set_owning_chain
+//       Access: Private
+//  Description: Moves this object to a different BufferContextChain.
+////////////////////////////////////////////////////////////////////
+INLINE void BufferContext::
+set_owning_chain(BufferContextChain *chain) {
+  if (chain != _owning_chain) {
+    --(_owning_chain->_count);
+    _owning_chain->adjust_bytes(-(int)_data_size_bytes);
+    remove_from_list();
+    _owning_chain = chain;
+    ++(_owning_chain->_count);
+    _owning_chain->adjust_bytes((int)_data_size_bytes);
+    insert_before(_owning_chain);
+  }
+}

+ 36 - 0
panda/src/gobj/bufferContext.cxx

@@ -0,0 +1,36 @@
+// Filename: bufferContext.cxx
+// Created by:  drose (16Mar06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "bufferContext.h"
+
+TypeHandle BufferContext::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: BufferContext::Destructor
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+BufferContext::
+~BufferContext() {
+#ifdef DO_PSTATS
+  --(_owning_chain->_count);
+  _owning_chain->adjust_bytes(-(int)_data_size_bytes);
+  remove_from_list();
+#endif  // DO_PSTATS
+  _owning_chain = NULL;
+}

+ 97 - 0
panda/src/gobj/bufferContext.h

@@ -0,0 +1,97 @@
+// Filename: bufferContext.h
+// Created by:  drose (16Mar06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef BUFFERCONTEXT_H
+#define BUFFERCONTEXT_H
+
+#include "pandabase.h"
+
+#include "savedContext.h"
+#include "updateSeq.h"
+#include "linkedListNode.h"
+#include "bufferContextChain.h"
+#include "bufferResidencyTracker.h"
+
+class PreparedGraphicsObjects;
+
+////////////////////////////////////////////////////////////////////
+//       Class : BufferContext
+// Description : This is a base class for those kinds of SavedContexts
+//               that occupy an easily-measured (and substantial)
+//               number of bytes in the video card's frame buffer
+//               memory or AGP memory.  At the present, this includes
+//               most of the SavedContext types: VertexBufferContext
+//               and IndexBufferContext, as well as TextureContext.
+//
+//               This class provides methods for tracking the video
+//               memory utilization, as well as residency of each
+//               object, via PStats.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA BufferContext : public SavedContext, private LinkedListNode {
+public:
+  INLINE BufferContext(BufferResidencyTracker *residency);
+  virtual ~BufferContext();
+
+  INLINE size_t get_data_size_bytes() const;
+  INLINE UpdateSeq get_modified() const;
+
+  INLINE void set_active(bool flag);
+  INLINE void set_resident(bool flag);
+
+  INLINE BufferContext *get_next() const;
+
+  INLINE void update_data_size_bytes(size_t new_data_size_bytes);
+  INLINE void update_modified(UpdateSeq new_modified);
+
+private:
+  INLINE void set_owning_chain(BufferContextChain *chain);
+
+private:
+  BufferResidencyTracker *_residency;
+  int _residency_state;
+
+  size_t _data_size_bytes;
+  UpdateSeq _modified;
+  BufferContextChain *_owning_chain;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    SavedContext::init_type();
+    register_type(_type_handle, "BufferContext",
+                  SavedContext::get_class_type());
+  }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+
+private:
+  static TypeHandle _type_handle;
+
+  friend class PreparedGraphicsObjects;
+  friend class BufferResidencyTracker;
+  friend class BufferContextChain;
+};
+
+#include "bufferContext.I"
+
+#endif
+

+ 73 - 0
panda/src/gobj/bufferContextChain.I

@@ -0,0 +1,73 @@
+// Filename: bufferContextChain.I
+// Created by:  drose (16Mar06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: BufferContextChain::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE BufferContextChain::
+BufferContextChain() :
+  LinkedListNode(true),  // This object is the root of a list of BufferContexts.
+  _total_size(0),
+  _count(0)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BufferContextChain::Destructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE BufferContextChain::
+~BufferContextChain() {
+  nassertv(_total_size == 0 && _count == 0);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BufferContextChain::get_total_size
+//       Access: Public
+//  Description: Returns the total number of bytes represented by the
+//               BufferContexts currently assigned to this tracker.
+////////////////////////////////////////////////////////////////////
+INLINE size_t BufferContextChain::
+get_total_size() const {
+  return _total_size;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BufferContextChain::get_count
+//       Access: Public
+//  Description: Returns the total number of BufferContexts currently
+//               assigned to this tracker.
+////////////////////////////////////////////////////////////////////
+INLINE int BufferContextChain::
+get_count() const {
+  return _count;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BufferContextChain::adjust_bytes
+//       Access: Private
+//  Description: Adds or removes some from the total byte count.
+////////////////////////////////////////////////////////////////////
+INLINE void BufferContextChain::
+adjust_bytes(int delta) {
+  _total_size += delta;
+}

+ 62 - 0
panda/src/gobj/bufferContextChain.cxx

@@ -0,0 +1,62 @@
+// Filename: bufferContextChain.cxx
+// Created by:  drose (16Mar06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "bufferContextChain.h"
+#include "bufferContext.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: BufferContextChain::get_first
+//       Access: Public
+//  Description: Returns the first BufferContext object stored in the
+//               tracker.  You can walk through the entire list of
+//               objects stored on the tracker by calling get_next()
+//               on each returned object, until the return value is
+//               NULL.
+////////////////////////////////////////////////////////////////////
+BufferContext *BufferContextChain::
+get_first() {
+  // This method is declared non-inline so we can include
+  // bufferContext.h, which is necessary for proper downcasting of the
+  // _next pointer.
+  if (_next == this) {
+    return NULL;
+  }
+  return (BufferContext *)_next;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BufferContextChain::take_from
+//       Access: Public
+//  Description: Moves all of the BufferContexts from the other
+//               tracker onto this one.
+////////////////////////////////////////////////////////////////////
+void BufferContextChain::
+take_from(BufferContextChain &other) {
+  _total_size += other._total_size;
+  _count += other._count;
+  other._total_size = 0;
+  other._count = 0;
+
+  LinkedListNode *llnode = other._next;
+  while (llnode != &other) {
+    ((BufferContext *)llnode)->_owning_chain = this;
+    llnode = ((BufferContext *)llnode)->_next;
+  }
+
+  take_list_from(&other);
+}

+ 61 - 0
panda/src/gobj/bufferContextChain.h

@@ -0,0 +1,61 @@
+// Filename: bufferContextChain.h
+// Created by:  drose (16Mar06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef BUFFERCONTEXTCHAIN_H
+#define BUFFERCONTEXTCHAIN_H
+
+#include "pandabase.h"
+#include "linkedListNode.h"
+
+class BufferContext;
+
+////////////////////////////////////////////////////////////////////
+//       Class : BufferContextChain
+// Description : This class maintains a linked list of BufferContexts
+//               that might be allocated on the graphics card in some
+//               context.  There is a different BufferContextChain for
+//               resident textures, active textures, evicted textures,
+//               etc.
+//
+//               The primary purpose of this class is to facilitate
+//               PStats reporting of graphics memory usage.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA BufferContextChain : private LinkedListNode {
+public:
+  INLINE BufferContextChain();
+  INLINE ~BufferContextChain();
+
+  INLINE size_t get_total_size() const;
+  INLINE int get_count() const;
+
+  BufferContext *get_first();
+
+  void take_from(BufferContextChain &other);
+
+private:
+  INLINE void adjust_bytes(int delta);
+  size_t _total_size;
+  int _count;
+
+  friend class BufferContext;
+};
+
+#include "bufferContextChain.I"
+
+#endif
+

+ 58 - 0
panda/src/gobj/bufferResidencyTracker.I

@@ -0,0 +1,58 @@
+// Filename: bufferResidencyTracker.I
+// Created by:  drose (16Mar06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: BufferResidencyTracker::get_inactive_nonresident
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE BufferContextChain &BufferResidencyTracker::
+get_inactive_nonresident() {
+  return _chains[S_inactive_nonresident];
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BufferResidencyTracker::get_active_nonresident
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE BufferContextChain &BufferResidencyTracker::
+get_active_nonresident() {
+  return _chains[S_active_nonresident];
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BufferResidencyTracker::get_inactive_resident
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE BufferContextChain &BufferResidencyTracker::
+get_inactive_resident() {
+  return _chains[S_inactive_resident];
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BufferResidencyTracker::get_active_resident
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE BufferContextChain &BufferResidencyTracker::
+get_active_resident() {
+  return _chains[S_active_resident];
+}

+ 92 - 0
panda/src/gobj/bufferResidencyTracker.cxx

@@ -0,0 +1,92 @@
+// Filename: bufferResidencyTracker.cxx
+// Created by:  drose (16Mar06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "bufferResidencyTracker.h"
+#include "clockObject.h"
+
+PStatCollector BufferResidencyTracker::_gmem_collector("Graphics memory");
+
+////////////////////////////////////////////////////////////////////
+//     Function: BufferResidencyTracker::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+BufferResidencyTracker::
+BufferResidencyTracker(const string &pgo_name, const string &type_name) :
+  _pgo_collector(_gmem_collector, pgo_name),
+  _active_resident_collector(PStatCollector(_pgo_collector, "Active"), type_name),
+  _active_nonresident_collector(PStatCollector(_pgo_collector, "Thrashing"), type_name),
+  _inactive_resident_collector(PStatCollector(_pgo_collector, "Inactive"), type_name),
+  _inactive_nonresident_collector(PStatCollector(_pgo_collector, "Nonresident"), type_name),
+  _active_frame(0)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BufferResidencyTracker::begin_frame
+//       Access: Public
+//  Description: To be called at the beginning of a frame, this
+//               initializes the active/inactive status.
+////////////////////////////////////////////////////////////////////
+void BufferResidencyTracker::
+begin_frame() {
+#ifdef DO_PSTATS
+  int this_frame = ClockObject::get_global_clock()->get_frame_count();
+  if (_active_frame != this_frame) {
+    _active_frame = this_frame;
+
+    // Move all of the previously "active" objects into "inactive".
+    // They'll get re-added to "active" as they get rendered.
+    move_inactive(_chains[S_inactive_nonresident],
+                  _chains[S_active_nonresident]);
+    move_inactive(_chains[S_inactive_resident],
+                  _chains[S_active_resident]);
+  }
+#endif  // DO_PSTATS
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BufferResidencyTracker::end_frame
+//       Access: Public
+//  Description: To be called at the end of a frame, this
+//               updates the PStatCollectors appropriately.
+////////////////////////////////////////////////////////////////////
+void BufferResidencyTracker::
+end_frame() {
+  _inactive_nonresident_collector.set_level(_chains[S_inactive_nonresident].get_total_size());
+  _active_nonresident_collector.set_level(_chains[S_active_nonresident].get_total_size());
+  _inactive_resident_collector.set_level(_chains[S_inactive_resident].get_total_size());
+  _active_resident_collector.set_level(_chains[S_active_resident].get_total_size());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BufferResidencyTracker::move_inactive
+//       Access: Private
+//  Description: Moves all of the "active" objects into "inactive".
+////////////////////////////////////////////////////////////////////
+void BufferResidencyTracker::
+move_inactive(BufferContextChain &inactive, BufferContextChain &active) {
+  BufferContext *node = active.get_first();
+  while (node != (BufferContext *)NULL) {
+    nassertv((node->_residency_state & S_active) != 0);
+    node->_residency_state &= ~S_active;
+    node = node->get_next();
+  }
+
+  inactive.take_from(active);
+}

+ 92 - 0
panda/src/gobj/bufferResidencyTracker.h

@@ -0,0 +1,92 @@
+// Filename: bufferResidencyTracker.h
+// Created by:  drose (16Mar06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef BUFFERRESIDENCYTRACKER_H
+#define BUFFERRESIDENCYTRACKER_H
+
+#include "pandabase.h"
+#include "bufferContextChain.h"
+#include "pStatCollector.h"
+
+class BufferContext;
+
+////////////////////////////////////////////////////////////////////
+//       Class : BufferResidencyTracker
+// Description : This class is used to keep track of the current state
+//               of all the BufferContexts for a particular graphics
+//               context: whether each one is active (rendered this
+//               frame) or inactive (not rendered this frame), and
+//               whether it is resident or nonresident in video
+//               memory.
+//
+//               The primary purpose of this class is to facilitate
+//               PStats reporting of video card memory usage.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA BufferResidencyTracker {
+public:
+  BufferResidencyTracker(const string &pgo_name, const string &type_name);
+
+  void begin_frame();
+  void end_frame();
+
+  INLINE BufferContextChain &get_inactive_nonresident();
+  INLINE BufferContextChain &get_active_nonresident();
+  INLINE BufferContextChain &get_inactive_resident();
+  INLINE BufferContextChain &get_active_resident();
+
+private:
+  void move_inactive(BufferContextChain &inactive, BufferContextChain &active);
+
+private:
+  enum State {
+    // Individual bits.
+    S_active   = 0x01,
+    S_resident = 0x02,
+
+    // Aggregate bits: unions of the above.
+    S_inactive_nonresident = 0x00,
+    S_active_nonresident   = 0x01,
+    S_inactive_resident    = 0x02,
+    S_active_resident      = 0x03,
+
+    // The total number of different states.
+    S_num_states = 4,
+  };
+
+  // One chain for each of the possible states, ordered as above.
+  BufferContextChain _chains[S_num_states];
+
+  // A couple of PStatCollectors just to organize names.
+  static PStatCollector _gmem_collector;
+  PStatCollector _pgo_collector;
+
+  // One PStatCollector for each state.  These are ordered in reverse
+  // order that we would like them to appear in the PStats graph.
+  PStatCollector _active_resident_collector;
+  PStatCollector _active_nonresident_collector;
+  PStatCollector _inactive_resident_collector;
+  PStatCollector _inactive_nonresident_collector;
+
+  // The frame number currently considered "active".
+  int _active_frame;
+  friend class BufferContext;
+};
+
+#include "bufferResidencyTracker.I"
+
+#endif

+ 2 - 0
panda/src/gobj/config_gobj.cxx

@@ -16,6 +16,7 @@
 //
 //
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
+#include "bufferContext.h"
 #include "config_util.h"
 #include "config_util.h"
 #include "config_gobj.h"
 #include "config_gobj.h"
 #include "geom.h"
 #include "geom.h"
@@ -238,6 +239,7 @@ ConfigVariableDouble default_keystone
 
 
 
 
 ConfigureFn(config_gobj) {
 ConfigureFn(config_gobj) {
+  BufferContext::init_type();
   Geom::init_type();
   Geom::init_type();
   GeomMunger::init_type();
   GeomMunger::init_type();
   GeomPrimitive::init_type();
   GeomPrimitive::init_type();

+ 3 - 1
panda/src/gobj/gobj_composite1.cxx

@@ -1,4 +1,6 @@
-
+#include "bufferContext.cxx"
+#include "bufferContextChain.cxx"
+#include "bufferResidencyTracker.cxx"
 #include "geom.cxx"
 #include "geom.cxx"
 #include "geomContext.cxx"
 #include "geomContext.cxx"
 #include "geomEnums.cxx"
 #include "geomEnums.cxx"

+ 10 - 33
panda/src/gobj/indexBufferContext.I

@@ -23,11 +23,9 @@
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE IndexBufferContext::
 INLINE IndexBufferContext::
-IndexBufferContext(GeomPrimitive *data) :
-  _data(data),
-  // Initially, the number of bytes is zero, until the data has been
-  // loaded (and mark_loaded() is called).
-  _data_size_bytes(0)
+IndexBufferContext(PreparedGraphicsObjects *pgo, GeomPrimitive *data) :
+  BufferContext(&pgo->_ibuffer_residency),
+  _data(data)
 {
 {
 }
 }
 
 
@@ -42,19 +40,6 @@ get_data() const {
   return _data;
   return _data;
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: IndexBufferContext::get_data_size_bytes
-//       Access: Public
-//  Description: Returns the number of bytes previously reported for
-//               the data object.  This is used to track changes in
-//               the data object's allocated size; if it changes from
-//               this, we need to create a new buffer.
-////////////////////////////////////////////////////////////////////
-INLINE int IndexBufferContext::
-get_data_size_bytes() const {
-  return _data_size_bytes;
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: IndexBufferContext::changed_size
 //     Function: IndexBufferContext::changed_size
 //       Access: Public
 //       Access: Public
@@ -63,7 +48,7 @@ get_data_size_bytes() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool IndexBufferContext::
 INLINE bool IndexBufferContext::
 changed_size() const {
 changed_size() const {
-  return get_data_size_bytes() != _data->get_data_size_bytes();
+  return get_data_size_bytes() != (size_t)_data->get_data_size_bytes();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -85,18 +70,7 @@ changed_usage_hint() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool IndexBufferContext::
 INLINE bool IndexBufferContext::
 was_modified() const {
 was_modified() const {
-  return _modified != _data->get_modified();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: IndexBufferContext::get_modified
-//       Access: Public
-//  Description: Returns the UpdateSeq that was recorded the last time
-//               mark_loaded() was called.
-////////////////////////////////////////////////////////////////////
-INLINE UpdateSeq IndexBufferContext::
-get_modified() const {
-  return _modified;
+  return get_modified() != _data->get_modified();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -108,7 +82,10 @@ get_modified() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void IndexBufferContext::
 INLINE void IndexBufferContext::
 mark_loaded() {
 mark_loaded() {
-  _data_size_bytes = _data->get_data_size_bytes();
+  update_data_size_bytes(_data->get_data_size_bytes());
+  update_modified(_data->get_modified());
   _usage_hint = _data->get_usage_hint();
   _usage_hint = _data->get_usage_hint();
-  _modified = _data->get_modified();
+
+  // Assume the buffer is now resident.
+  set_resident(true);
 }
 }

+ 6 - 10
panda/src/gobj/indexBufferContext.h

@@ -21,9 +21,9 @@
 
 
 #include "pandabase.h"
 #include "pandabase.h"
 
 
-#include "savedContext.h"
-#include "updateSeq.h"
+#include "bufferContext.h"
 #include "geomPrimitive.h"
 #include "geomPrimitive.h"
+#include "preparedGraphicsObjects.h"
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //       Class : IndexBufferContext
 //       Class : IndexBufferContext
@@ -36,17 +36,15 @@
 //               allocate a vertex buffer for the array.  OpenGL can
 //               allocate a vertex buffer for the array.  OpenGL can
 //               create a buffer object.
 //               create a buffer object.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA IndexBufferContext : public SavedContext {
+class EXPCL_PANDA IndexBufferContext : public BufferContext {
 public:
 public:
-  INLINE IndexBufferContext(GeomPrimitive *data);
+  INLINE IndexBufferContext(PreparedGraphicsObjects *pgo, GeomPrimitive *data);
 
 
   INLINE GeomPrimitive *get_data() const;
   INLINE GeomPrimitive *get_data() const;
 
 
-  INLINE int get_data_size_bytes() const;
   INLINE bool changed_size() const;
   INLINE bool changed_size() const;
   INLINE bool changed_usage_hint() const;
   INLINE bool changed_usage_hint() const;
   INLINE bool was_modified() const;
   INLINE bool was_modified() const;
-  INLINE UpdateSeq get_modified() const;
 
 
   INLINE void mark_loaded();
   INLINE void mark_loaded();
 
 
@@ -55,8 +53,6 @@ private:
   // the GSG both own their IndexBufferContexts!  That would create a
   // the GSG both own their IndexBufferContexts!  That would create a
   // circular reference count.
   // circular reference count.
   GeomPrimitive *_data;
   GeomPrimitive *_data;
-  UpdateSeq _modified;
-  int _data_size_bytes;
   GeomEnums::UsageHint _usage_hint;
   GeomEnums::UsageHint _usage_hint;
 
 
 public:
 public:
@@ -64,9 +60,9 @@ public:
     return _type_handle;
     return _type_handle;
   }
   }
   static void init_type() {
   static void init_type() {
-    SavedContext::init_type();
+    BufferContext::init_type();
     register_type(_type_handle, "IndexBufferContext",
     register_type(_type_handle, "IndexBufferContext",
-                  SavedContext::get_class_type());
+                  BufferContext::get_class_type());
   }
   }
   virtual TypeHandle get_type() const {
   virtual TypeHandle get_type() const {
     return get_class_type();
     return get_class_type();

+ 12 - 0
panda/src/gobj/preparedGraphicsObjects.I

@@ -17,6 +17,18 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: PreparedGraphicsObjects::get_name
+//       Access: Public
+//  Description: Returns the name of the PreparedGraphicsObjects
+//               structure.  This is an arbitrary name that serves
+//               mainly to uniquify the context for PStats reporting.
+////////////////////////////////////////////////////////////////////
+INLINE const string &PreparedGraphicsObjects::
+get_name() const {
+  return _name;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PreparedGraphicsObjects::release_all
 //     Function: PreparedGraphicsObjects::release_all
 //       Access: Public
 //       Access: Public

+ 49 - 31
panda/src/gobj/preparedGraphicsObjects.cxx

@@ -27,8 +27,7 @@
 #include "shaderExpansion.h"
 #include "shaderExpansion.h"
 #include "reMutexHolder.h"
 #include "reMutexHolder.h"
 
 
-PStatCollector PreparedGraphicsObjects::_total_texusage_pcollector("Texture usage");
-PStatCollector PreparedGraphicsObjects::_total_buffers_pcollector("Vertex buffer size");
+int PreparedGraphicsObjects::_name_index = 0;
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PreparedGraphicsObjects::Constructor
 //     Function: PreparedGraphicsObjects::Constructor
@@ -36,7 +35,12 @@ PStatCollector PreparedGraphicsObjects::_total_buffers_pcollector("Vertex buffer
 //  Description: 
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 PreparedGraphicsObjects::
 PreparedGraphicsObjects::
-PreparedGraphicsObjects() {
+PreparedGraphicsObjects() : 
+  _name(init_name()),
+  _texture_residency(_name, "texture"),
+  _vbuffer_residency(_name, "vbuffer"),
+  _ibuffer_residency(_name, "ibuffer")
+{
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -58,8 +62,7 @@ PreparedGraphicsObjects::
        tci != _prepared_textures.end();
        tci != _prepared_textures.end();
        ++tci) {
        ++tci) {
     TextureContext *tc = (*tci);
     TextureContext *tc = (*tci);
-    _total_texusage_pcollector.sub_level(tc->estimate_texture_memory());
-    tc->_texture->clear_prepared(this);
+    tc->get_texture()->clear_prepared(this);
   }
   }
 
 
   _prepared_textures.clear();
   _prepared_textures.clear();
@@ -95,7 +98,6 @@ PreparedGraphicsObjects::
        vbci != _prepared_vertex_buffers.end();
        vbci != _prepared_vertex_buffers.end();
        ++vbci) {
        ++vbci) {
     VertexBufferContext *vbc = (*vbci);
     VertexBufferContext *vbc = (*vbci);
-    _total_buffers_pcollector.sub_level(vbc->get_data_size_bytes());
     vbc->_data->clear_prepared(this);
     vbc->_data->clear_prepared(this);
   }
   }
 
 
@@ -108,7 +110,6 @@ PreparedGraphicsObjects::
        ibci != _prepared_index_buffers.end();
        ibci != _prepared_index_buffers.end();
        ++ibci) {
        ++ibci) {
     IndexBufferContext *ibc = (*ibci);
     IndexBufferContext *ibc = (*ibci);
-    _total_buffers_pcollector.sub_level(ibc->get_data_size_bytes());
     ibc->_data->clear_prepared(this);
     ibc->_data->clear_prepared(this);
   }
   }
 
 
@@ -175,8 +176,7 @@ void PreparedGraphicsObjects::
 release_texture(TextureContext *tc) {
 release_texture(TextureContext *tc) {
   ReMutexHolder holder(_lock);
   ReMutexHolder holder(_lock);
 
 
-  tc->_texture->clear_prepared(this);
-  _total_texusage_pcollector.sub_level(tc->estimate_texture_memory());
+  tc->get_texture()->clear_prepared(this);
 
 
   // We have to set the Texture pointer to NULL at this point, since
   // We have to set the Texture pointer to NULL at this point, since
   // the Texture itself might destruct at any time after it has been
   // the Texture itself might destruct at any time after it has been
@@ -208,8 +208,7 @@ release_all_textures() {
        tci != _prepared_textures.end();
        tci != _prepared_textures.end();
        ++tci) {
        ++tci) {
     TextureContext *tc = (*tci);
     TextureContext *tc = (*tci);
-    tc->_texture->clear_prepared(this);
-    _total_texusage_pcollector.sub_level(tc->estimate_texture_memory());
+    tc->get_texture()->clear_prepared(this);
     tc->_texture = (Texture *)NULL;
     tc->_texture = (Texture *)NULL;
 
 
     _released_textures.insert(tc);
     _released_textures.insert(tc);
@@ -255,8 +254,6 @@ prepare_texture_now(Texture *tex, GraphicsStateGuardianBase *gsg) {
   if (tc != (TextureContext *)NULL) {
   if (tc != (TextureContext *)NULL) {
     bool prepared = _prepared_textures.insert(tc).second;
     bool prepared = _prepared_textures.insert(tc).second;
     nassertr(prepared, tc);
     nassertr(prepared, tc);
-
-    _total_texusage_pcollector.add_level(tc->estimate_texture_memory());
   }
   }
 
 
   return tc;
   return tc;
@@ -600,7 +597,6 @@ release_vertex_buffer(VertexBufferContext *vbc) {
   ReMutexHolder holder(_lock);
   ReMutexHolder holder(_lock);
 
 
   vbc->_data->clear_prepared(this);
   vbc->_data->clear_prepared(this);
-  _total_buffers_pcollector.sub_level(vbc->get_data_size_bytes());
 
 
   // We have to set the Data pointer to NULL at this point, since
   // We have to set the Data pointer to NULL at this point, since
   // the Data itself might destruct at any time after it has been
   // the Data itself might destruct at any time after it has been
@@ -633,7 +629,6 @@ release_all_vertex_buffers() {
        ++vbci) {
        ++vbci) {
     VertexBufferContext *vbc = (*vbci);
     VertexBufferContext *vbc = (*vbci);
     vbc->_data->clear_prepared(this);
     vbc->_data->clear_prepared(this);
-    _total_buffers_pcollector.sub_level(vbc->get_data_size_bytes());
     vbc->_data = (GeomVertexArrayData *)NULL;
     vbc->_data = (GeomVertexArrayData *)NULL;
 
 
     _released_vertex_buffers.insert(vbc);
     _released_vertex_buffers.insert(vbc);
@@ -679,11 +674,6 @@ prepare_vertex_buffer_now(GeomVertexArrayData *data, GraphicsStateGuardianBase *
   if (vbc != (VertexBufferContext *)NULL) {
   if (vbc != (VertexBufferContext *)NULL) {
     bool prepared = _prepared_vertex_buffers.insert(vbc).second;
     bool prepared = _prepared_vertex_buffers.insert(vbc).second;
     nassertr(prepared, vbc);
     nassertr(prepared, vbc);
-
-    // The size has already been counted by
-    // GraphicsStateGuardian::add_to_vertex_buffer_record(); we don't need to
-    // count it again here.
-    //_total_buffers_pcollector.add_level(vbc->get_data_size_bytes());
   }
   }
 
 
   return vbc;
   return vbc;
@@ -747,7 +737,6 @@ release_index_buffer(IndexBufferContext *ibc) {
   ReMutexHolder holder(_lock);
   ReMutexHolder holder(_lock);
 
 
   ibc->_data->clear_prepared(this);
   ibc->_data->clear_prepared(this);
-  _total_buffers_pcollector.sub_level(ibc->get_data_size_bytes());
 
 
   // We have to set the Data pointer to NULL at this point, since
   // We have to set the Data pointer to NULL at this point, since
   // the Data itself might destruct at any time after it has been
   // the Data itself might destruct at any time after it has been
@@ -780,7 +769,6 @@ release_all_index_buffers() {
        ++ibci) {
        ++ibci) {
     IndexBufferContext *ibc = (*ibci);
     IndexBufferContext *ibc = (*ibci);
     ibc->_data->clear_prepared(this);
     ibc->_data->clear_prepared(this);
-    _total_buffers_pcollector.sub_level(ibc->get_data_size_bytes());
     ibc->_data = (GeomPrimitive *)NULL;
     ibc->_data = (GeomPrimitive *)NULL;
 
 
     _released_index_buffers.insert(ibc);
     _released_index_buffers.insert(ibc);
@@ -826,22 +814,17 @@ prepare_index_buffer_now(GeomPrimitive *data, GraphicsStateGuardianBase *gsg) {
   if (ibc != (IndexBufferContext *)NULL) {
   if (ibc != (IndexBufferContext *)NULL) {
     bool prepared = _prepared_index_buffers.insert(ibc).second;
     bool prepared = _prepared_index_buffers.insert(ibc).second;
     nassertr(prepared, ibc);
     nassertr(prepared, ibc);
-
-    // The size has already been counted by
-    // GraphicsStateGuardian::add_to_index_buffer_record(); we don't need to
-    // count it again here.
-    //_total_buffers_pcollector.add_level(ibc->get_data_size_bytes());
   }
   }
 
 
   return ibc;
   return ibc;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: PreparedGraphicsObjects::update
+//     Function: PreparedGraphicsObjects::begin_frame
 //       Access: Public
 //       Access: Public
 //  Description: This is called by the GraphicsStateGuardian to
 //  Description: This is called by the GraphicsStateGuardian to
-//               indicate that it is in a state to load or release
-//               textures.
+//               indicate that it is about to begin processing of the
+//               frame.
 //
 //
 //               Any texture contexts that were previously passed to
 //               Any texture contexts that were previously passed to
 //               release_texture() are actually passed to the GSG to
 //               release_texture() are actually passed to the GSG to
@@ -849,7 +832,7 @@ prepare_index_buffer_now(GeomPrimitive *data, GraphicsStateGuardianBase *gsg) {
 //               passed to prepare_texture are actually loaded.
 //               passed to prepare_texture are actually loaded.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void PreparedGraphicsObjects::
 void PreparedGraphicsObjects::
-update(GraphicsStateGuardianBase *gsg) {
+begin_frame(GraphicsStateGuardianBase *gsg) {
   ReMutexHolder holder(_lock);
   ReMutexHolder holder(_lock);
 
 
   // First, release all the textures, geoms, and buffers awaiting
   // First, release all the textures, geoms, and buffers awaiting
@@ -904,6 +887,11 @@ update(GraphicsStateGuardianBase *gsg) {
 
 
   _released_index_buffers.clear();
   _released_index_buffers.clear();
 
 
+  // Reset the residency trackers.
+  _texture_residency.begin_frame();
+  _vbuffer_residency.begin_frame();
+  _ibuffer_residency.begin_frame();
+
   // Now prepare all the textures, geoms, and buffers awaiting
   // Now prepare all the textures, geoms, and buffers awaiting
   // preparation.
   // preparation.
   EnqueuedTextures::iterator qti;
   EnqueuedTextures::iterator qti;
@@ -956,3 +944,33 @@ update(GraphicsStateGuardianBase *gsg) {
 
 
   _enqueued_index_buffers.clear();
   _enqueued_index_buffers.clear();
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: PreparedGraphicsObjects::end_frame
+//       Access: Public
+//  Description: This is called by the GraphicsStateGuardian to
+//               indicate that it has finished processing of the
+//               frame.
+////////////////////////////////////////////////////////////////////
+void PreparedGraphicsObjects::
+end_frame() {
+  ReMutexHolder holder(_lock);
+
+  _texture_residency.end_frame();
+  _vbuffer_residency.end_frame();
+  _ibuffer_residency.end_frame();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PreparedGraphicsObjects::init_name
+//       Access: Private, Static
+//  Description: Returns a new, unique name for a newly-constructed
+//               object.
+////////////////////////////////////////////////////////////////////
+string PreparedGraphicsObjects::
+init_name() {
+  ++_name_index;
+  ostringstream strm;
+  strm << "context" << _name_index;
+  return strm.str();
+}

+ 16 - 3
panda/src/gobj/preparedGraphicsObjects.h

@@ -30,6 +30,7 @@
 #include "pStatCollector.h"
 #include "pStatCollector.h"
 #include "pset.h"
 #include "pset.h"
 #include "reMutex.h"
 #include "reMutex.h"
+#include "bufferResidencyTracker.h"
 
 
 class TextureContext;
 class TextureContext;
 class GeomContext;
 class GeomContext;
@@ -62,6 +63,8 @@ public:
   PreparedGraphicsObjects();
   PreparedGraphicsObjects();
   ~PreparedGraphicsObjects();
   ~PreparedGraphicsObjects();
 
 
+  INLINE const string &get_name() const;
+
   INLINE void release_all();
   INLINE void release_all();
 
 
   void enqueue_texture(Texture *tex);
   void enqueue_texture(Texture *tex);
@@ -103,7 +106,11 @@ public:
   prepare_index_buffer_now(GeomPrimitive *data,
   prepare_index_buffer_now(GeomPrimitive *data,
                            GraphicsStateGuardianBase *gsg);
                            GraphicsStateGuardianBase *gsg);
 
 
-  void update(GraphicsStateGuardianBase *gsg);
+  void begin_frame(GraphicsStateGuardianBase *gsg);
+  void end_frame();
+
+private:
+  static string init_name();
 
 
 private:
 private:
   typedef phash_set<TextureContext *, pointer_hash> Textures;
   typedef phash_set<TextureContext *, pointer_hash> Textures;
@@ -118,6 +125,7 @@ private:
   typedef phash_set< PT(GeomPrimitive) > EnqueuedIndexBuffers;
   typedef phash_set< PT(GeomPrimitive) > EnqueuedIndexBuffers;
 
 
   ReMutex _lock;
   ReMutex _lock;
+  string _name;
   Textures _prepared_textures, _released_textures;  
   Textures _prepared_textures, _released_textures;  
   EnqueuedTextures _enqueued_textures;
   EnqueuedTextures _enqueued_textures;
   Geoms _prepared_geoms, _released_geoms;  
   Geoms _prepared_geoms, _released_geoms;  
@@ -129,8 +137,13 @@ private:
   IndexBuffers _prepared_index_buffers, _released_index_buffers;  
   IndexBuffers _prepared_index_buffers, _released_index_buffers;  
   EnqueuedIndexBuffers _enqueued_index_buffers;
   EnqueuedIndexBuffers _enqueued_index_buffers;
 
 
-  static PStatCollector _total_texusage_pcollector;
-  static PStatCollector _total_buffers_pcollector;
+public:
+  BufferResidencyTracker _texture_residency;
+  BufferResidencyTracker _vbuffer_residency;
+  BufferResidencyTracker _ibuffer_residency;
+
+private:
+  static int _name_index;
 
 
   friend class GraphicsStateGuardian;
   friend class GraphicsStateGuardian;
 };
 };

+ 12 - 0
panda/src/gobj/texture.I

@@ -542,6 +542,18 @@ set_keep_ram_image(bool keep_ram_image) {
   _keep_ram_image = keep_ram_image;
   _keep_ram_image = keep_ram_image;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::get_modified
+//       Access: Published
+//  Description: Returns a sequence number which is guaranteed to
+//               change at least every time the texture data or
+//               properties are modified.
+////////////////////////////////////////////////////////////////////
+INLINE UpdateSeq Texture::
+get_modified() const {
+  return _modified;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: Texture::set_filename
 //     Function: Texture::set_filename
 //       Access: Published
 //       Access: Published

+ 13 - 60
panda/src/gobj/texture.cxx

@@ -61,7 +61,6 @@ Texture(const string &name) :
   _wrap_w = WM_repeat;
   _wrap_w = WM_repeat;
   _anisotropic_degree = 1;
   _anisotropic_degree = 1;
   _keep_ram_image = true;
   _keep_ram_image = true;
-  _all_dirty_flags = 0;
   _border_color.set(0.0f, 0.0f, 0.0f, 1.0f);
   _border_color.set(0.0f, 0.0f, 0.0f, 1.0f);
   _compression = CM_default;
   _compression = CM_default;
   _ram_image_compression = CM_off;
   _ram_image_compression = CM_off;
@@ -115,7 +114,6 @@ Texture(const Texture &copy) :
   _border_color(copy._border_color),
   _border_color(copy._border_color),
   _compression(copy._compression),
   _compression(copy._compression),
   _match_framebuffer_format(copy._match_framebuffer_format),
   _match_framebuffer_format(copy._match_framebuffer_format),
-  _all_dirty_flags(0),
   _ram_image(copy._ram_image),
   _ram_image(copy._ram_image),
   _ram_image_compression(copy._ram_image_compression),
   _ram_image_compression(copy._ram_image_compression),
   _ram_page_size(copy._ram_page_size)
   _ram_page_size(copy._ram_page_size)
@@ -157,10 +155,10 @@ operator = (const Texture &copy) {
   _border_color = copy._border_color;
   _border_color = copy._border_color;
   _compression = copy._compression;
   _compression = copy._compression;
   _match_framebuffer_format = copy._match_framebuffer_format;
   _match_framebuffer_format = copy._match_framebuffer_format;
-  _all_dirty_flags = 0;
   _ram_image = copy._ram_image;
   _ram_image = copy._ram_image;
   _ram_image_compression = copy._ram_image_compression;
   _ram_image_compression = copy._ram_image_compression;
   _ram_page_size = copy._ram_page_size;
   _ram_page_size = copy._ram_page_size;
+  ++_modified;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -915,7 +913,7 @@ load(const PNMImage &pnmimage, int z) {
     nassertr((size_t)idx == get_expected_ram_page_size() * (z + 1), false);
     nassertr((size_t)idx == get_expected_ram_page_size() * (z + 1), false);
   }
   }
 
 
-  mark_dirty(DF_image);
+  ++_modified;
 
 
   return true;
   return true;
 }
 }
@@ -1037,7 +1035,7 @@ load_related(const PT(InternalName) &suffix) const {
 void Texture::
 void Texture::
 set_wrap_u(Texture::WrapMode wrap) {
 set_wrap_u(Texture::WrapMode wrap) {
   if (_wrap_u != wrap) {
   if (_wrap_u != wrap) {
-    mark_dirty(DF_wrap);
+    ++_modified;
     _wrap_u = wrap;
     _wrap_u = wrap;
   }
   }
 }
 }
@@ -1050,7 +1048,7 @@ set_wrap_u(Texture::WrapMode wrap) {
 void Texture::
 void Texture::
 set_wrap_v(Texture::WrapMode wrap) {
 set_wrap_v(Texture::WrapMode wrap) {
   if (_wrap_v != wrap) {
   if (_wrap_v != wrap) {
-    mark_dirty(DF_wrap);
+    ++_modified;
     _wrap_v = wrap;
     _wrap_v = wrap;
   }
   }
 }
 }
@@ -1063,7 +1061,7 @@ set_wrap_v(Texture::WrapMode wrap) {
 void Texture::
 void Texture::
 set_wrap_w(Texture::WrapMode wrap) {
 set_wrap_w(Texture::WrapMode wrap) {
   if (_wrap_w != wrap) {
   if (_wrap_w != wrap) {
-    mark_dirty(DF_wrap);
+    ++_modified;
     _wrap_w = wrap;
     _wrap_w = wrap;
   }
   }
 }
 }
@@ -1076,11 +1074,7 @@ set_wrap_w(Texture::WrapMode wrap) {
 void Texture::
 void Texture::
 set_minfilter(Texture::FilterType filter) {
 set_minfilter(Texture::FilterType filter) {
   if (_minfilter != filter) {
   if (_minfilter != filter) {
-    if (is_mipmap(_minfilter) != is_mipmap(filter)) {
-      mark_dirty(DF_filter | DF_mipmap);
-    } else {
-      mark_dirty(DF_filter);
-    }
+    ++_modified;
     _minfilter = filter;
     _minfilter = filter;
   }
   }
 }
 }
@@ -1093,7 +1087,7 @@ set_minfilter(Texture::FilterType filter) {
 void Texture::
 void Texture::
 set_magfilter(Texture::FilterType filter) {
 set_magfilter(Texture::FilterType filter) {
   if (_magfilter != filter) {
   if (_magfilter != filter) {
-    mark_dirty(DF_filter);
+    ++_modified;
     _magfilter = filter;
     _magfilter = filter;
   }
   }
 }
 }
@@ -1110,7 +1104,7 @@ set_magfilter(Texture::FilterType filter) {
 void Texture::
 void Texture::
 set_anisotropic_degree(int anisotropic_degree) {
 set_anisotropic_degree(int anisotropic_degree) {
   if (_anisotropic_degree != anisotropic_degree) {
   if (_anisotropic_degree != anisotropic_degree) {
-    mark_dirty(DF_filter);
+    ++_modified;
     _anisotropic_degree = anisotropic_degree;
     _anisotropic_degree = anisotropic_degree;
   }
   }
 }
 }
@@ -1126,7 +1120,7 @@ set_anisotropic_degree(int anisotropic_degree) {
 void Texture::
 void Texture::
 set_border_color(const Colorf &color) {
 set_border_color(const Colorf &color) {
   if (_border_color != color) {
   if (_border_color != color) {
-    mark_dirty(DF_border);
+    ++_modified;
     _border_color = color;
     _border_color = color;
   }
   }
 }
 }
@@ -1153,7 +1147,7 @@ set_border_color(const Colorf &color) {
 void Texture::
 void Texture::
 set_compression(Texture::CompressionMode compression) {
 set_compression(Texture::CompressionMode compression) {
   if (_compression != compression) {
   if (_compression != compression) {
-    mark_dirty(DF_image);
+    ++_modified;
     _compression = compression;
     _compression = compression;
   }
   }
 }
 }
@@ -1254,7 +1248,7 @@ modify_ram_image() {
     make_ram_image();
     make_ram_image();
   }
   }
 
 
-  mark_dirty(DF_image);
+  ++_modified;
   _keep_ram_image = true;
   _keep_ram_image = true;
   return _ram_image;
   return _ram_image;
 }
 }
@@ -1272,7 +1266,7 @@ PTA_uchar Texture::
 make_ram_image() {
 make_ram_image() {
   _ram_image = PTA_uchar::empty_array(get_expected_ram_image_size());
   _ram_image = PTA_uchar::empty_array(get_expected_ram_image_size());
   _ram_image_compression = CM_off;
   _ram_image_compression = CM_off;
-  mark_dirty(DF_image);
+  ++_modified;
   _keep_ram_image = true;
   _keep_ram_image = true;
   return _ram_image;
   return _ram_image;
 }
 }
@@ -1299,7 +1293,7 @@ set_ram_image(PTA_uchar image, Texture::CompressionMode compression,
     if (page_size == 0) {
     if (page_size == 0) {
       _ram_page_size = image.size();
       _ram_page_size = image.size();
     }
     }
-    mark_dirty(DF_image);
+    ++_modified;
   }
   }
   _keep_ram_image = true;
   _keep_ram_image = true;
 }
 }
@@ -1685,12 +1679,6 @@ prepare_now(PreparedGraphicsObjects *prepared_objects,
   _contexts[prepared_objects] = tc;
   _contexts[prepared_objects] = tc;
 
 
   if (tc != (TextureContext *)NULL) {
   if (tc != (TextureContext *)NULL) {
-    // Now that we have a new TextureContext with zero dirty flags, our
-    // intersection of all dirty flags must be zero.  This doesn't mean
-    // that some other contexts aren't still dirty, but at least one
-    // context isn't.
-    _all_dirty_flags = 0;
-
     if (!keep_texture_ram && !_keep_ram_image) {
     if (!keep_texture_ram && !_keep_ram_image) {
       // Once we have prepared the texture, we can generally safely
       // Once we have prepared the texture, we can generally safely
       // remove the pixels from main RAM.  The GSG is now responsible
       // remove the pixels from main RAM.  The GSG is now responsible
@@ -1706,41 +1694,6 @@ prepare_now(PreparedGraphicsObjects *prepared_objects,
   return tc;
   return tc;
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: Texture::mark_dirty
-//       Access: Public
-//  Description: Sets the indicated dirty bits on for all texture
-//               contexts that share this Texture.  Does not change
-//               the bits that are not on.  This presumably will
-//               inform the GSG that the texture properties have
-//               changed.  See also TextureContext::mark_dirty().
-//
-//               Normally, this does not need to be called directly;
-//               changing the properties on the texture will
-//               automatically call this.  However, if you fiddle with
-//               the texture image directly, you may need to
-//               explicitly call mark_dirty(Texture::DF_image).
-////////////////////////////////////////////////////////////////////
-void Texture::
-mark_dirty(int flags_to_set) {
-  if ((_all_dirty_flags & flags_to_set) == flags_to_set) {
-    // If all the texture contexts already share these bits, no need
-    // to do anything else.
-    return;
-  }
-
-  // Otherwise, iterate through the contexts and mark them all dirty.
-  Contexts::iterator ci;
-  for (ci = _contexts.begin(); ci != _contexts.end(); ++ci) {
-    TextureContext *tc = (*ci).second;
-    if (tc != (TextureContext *)NULL) {
-      tc->mark_dirty(flags_to_set);
-    }
-  }
-
-  _all_dirty_flags |= flags_to_set;
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: Texture::has_cull_callback
 //     Function: Texture::has_cull_callback
 //       Access: Public, Virtual
 //       Access: Public, Virtual

+ 4 - 18
panda/src/gobj/texture.h

@@ -26,6 +26,7 @@
 #include "namable.h"
 #include "namable.h"
 #include "internalName.h"
 #include "internalName.h"
 #include "graphicsStateGuardianBase.h"
 #include "graphicsStateGuardianBase.h"
+#include "updateSeq.h"
 #include "pmap.h"
 #include "pmap.h"
 
 
 class PNMImage;
 class PNMImage;
@@ -267,6 +268,8 @@ PUBLISHED:
   INLINE void set_keep_ram_image(bool keep_ram_image);
   INLINE void set_keep_ram_image(bool keep_ram_image);
   virtual bool get_keep_ram_image() const;
   virtual bool get_keep_ram_image() const;
 
 
+  INLINE UpdateSeq get_modified() const;
+
   void prepare(PreparedGraphicsObjects *prepared_objects);
   void prepare(PreparedGraphicsObjects *prepared_objects);
   bool release(PreparedGraphicsObjects *prepared_objects);
   bool release(PreparedGraphicsObjects *prepared_objects);
   int release_all();
   int release_all();
@@ -307,19 +310,6 @@ public:
   TextureContext *prepare_now(PreparedGraphicsObjects *prepared_objects,
   TextureContext *prepare_now(PreparedGraphicsObjects *prepared_objects,
                               GraphicsStateGuardianBase *gsg);
                               GraphicsStateGuardianBase *gsg);
 
 
-  // These bits are used as parameters to Texture::mark_dirty() and
-  // also TextureContext::mark_dirty() (and related functions in
-  // TextureContext).
-  enum DirtyFlags {
-    DF_image      = 0x001,  // The image pixels have changed.
-    DF_wrap       = 0x002,  // The wrap properties have changed.
-    DF_filter     = 0x004,  // The minfilter or magfilter have changed.
-    DF_mipmap     = 0x008,  // The use of mipmaps or not has changed.
-    DF_border     = 0x010,  // The border has changed.
-  };
-
-  void mark_dirty(int flags_to_set);
-
   virtual bool has_cull_callback() const;
   virtual bool has_cull_callback() const;
   virtual bool cull_callback(CullTraverser *trav, const CullTraverserData &data) const;
   virtual bool cull_callback(CullTraverser *trav, const CullTraverserData &data) const;
 
 
@@ -415,15 +405,11 @@ protected:
   typedef pmap<PT(InternalName), PT(Texture)> RelatedTextures;
   typedef pmap<PT(InternalName), PT(Texture)> RelatedTextures;
   RelatedTextures _related_textures;
   RelatedTextures _related_textures;
 
 
-  // This value represents the intersection of all the dirty flags of
-  // the various TextureContexts that might be associated with this
-  // texture.
-  int _all_dirty_flags;
-
   PTA_uchar _ram_image;
   PTA_uchar _ram_image;
   CompressionMode _ram_image_compression;
   CompressionMode _ram_image_compression;
   size_t _ram_page_size;
   size_t _ram_page_size;
 
 
+  UpdateSeq _modified;
 
 
   // Datagram stuff
   // Datagram stuff
 public:
 public:

+ 28 - 49
panda/src/gobj/textureContext.I

@@ -23,70 +23,49 @@
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE TextureContext::
 INLINE TextureContext::
-TextureContext(Texture *tex) :
+TextureContext(PreparedGraphicsObjects *pgo, Texture *tex) :
+  BufferContext(&pgo->_texture_residency),
   _texture(tex)
   _texture(tex)
 {
 {
-  _dirty_flags = ~0;
+#ifdef DO_PSTATS
+  update_data_size_bytes(estimate_texture_memory());
+#endif
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: TextureContext::mark_dirty
+//     Function: TextureContext::get_texture
 //       Access: Public
 //       Access: Public
-//  Description: Marks the context "dirty", i.e. its properties are
-//               different from the last time the GSG has seen them.
-//               Presumably, the GSG will respond by updating the
-//               properties and clearing the dirty bits the next time
-//               it renders the texture.
-//
-//               The value is the union of all the bits that are to be
-//               set dirty; bits that are not set in this parameter
-//               are left unchanged.  See Texture::DirtyFlags for a
-//               list of available bits.
-//
-//               Usually this function is not called directly, but
-//               rather is called by Texture::mark_dirty() as a result
-//               of changing properties directly on the texture.
+//  Description: Returns the pointer to the associated Texture
+//               object.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE void TextureContext::
-mark_dirty(int flags_to_set) {
-  _dirty_flags |= flags_to_set;
+INLINE Texture *TextureContext::
+get_texture() const {
+  return _texture;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: TextureContext::clear_dirty_flags
+//     Function: TextureContext::was_modified
 //       Access: Public
 //       Access: Public
-//  Description: Removes the indicated flags from the "dirty" bits.
-//               See mark_dirty().
-//
-//               The value is the union of all the bits that are to be
-//               cleared; if a bit is set in the parameter, it will be
-//               removed from the dirty set.  Bits that are not set in
-//               this parameter are left unchanged.
-//
-//               This function is intended to be called by the GSG
-//               after it has updated the texture parameters.
+//  Description: Returns true if the texture has been modified since the
+//               last time mark_loaded() was called.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE void TextureContext::
-clear_dirty_flags(int flags_to_clear) {
-  _dirty_flags &= ~flags_to_clear;
-  _texture->_all_dirty_flags &= ~flags_to_clear;
+INLINE bool TextureContext::
+was_modified() const {
+  return get_modified() != _texture->get_modified();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: TextureContext::get_dirty_flags
+//     Function: TextureContext::mark_loaded
 //       Access: Public
 //       Access: Public
-//  Description: Returns the current state of the dirty flags.  If
-//               this is non-zero, it represents the union of all
-//               properties that have been changed since the last call
-//               to clear_dirty_flags().
-//
-//               This function is intended to be called by the GSG to
-//               determine what properties need to be updated.  See
-//               Texture::DirtyFlags for a list of possible bits.
+//  Description: Should be called after the TextureContext has been
+//               loaded into graphics memory, this updates the
+//               internal flags for changed_size() and modified().
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE int TextureContext::
-get_dirty_flags() const {
-  _texture->reconsider_dirty();
-  return _dirty_flags;
-}
+INLINE void TextureContext::
+mark_loaded() {
+  //  _data_size_bytes = _data->get_texture_size_bytes();
+  update_modified(_texture->get_modified());
 
 
+  // Assume the texture is now resident.
+  set_resident(true);
+}

+ 15 - 14
panda/src/gobj/textureContext.h

@@ -21,8 +21,9 @@
 
 
 #include "pandabase.h"
 #include "pandabase.h"
 
 
-#include "savedContext.h"
+#include "bufferContext.h"
 #include "texture.h"
 #include "texture.h"
+#include "preparedGraphicsObjects.h"
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //       Class : TextureContext
 //       Class : TextureContext
@@ -37,33 +38,31 @@
 //               texture and store it here.  The texture stores all of
 //               texture and store it here.  The texture stores all of
 //               these handles internally.
 //               these handles internally.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA TextureContext : public SavedContext {
+class EXPCL_PANDA TextureContext : public BufferContext {
 public:
 public:
-  INLINE TextureContext(Texture *tex);
+  INLINE TextureContext(PreparedGraphicsObjects *pgo, Texture *tex);
+
+  INLINE Texture *get_texture() const;
+
+  INLINE bool was_modified() const;
+  INLINE void mark_loaded();
 
 
   virtual size_t estimate_texture_memory();
   virtual size_t estimate_texture_memory();
 
 
+private:
   // This cannot be a PT(Texture), because the texture and the GSG
   // This cannot be a PT(Texture), because the texture and the GSG
   // both own their TextureContexts!  That would create a circular
   // both own their TextureContexts!  That would create a circular
   // reference count.
   // reference count.
   Texture *_texture;
   Texture *_texture;
-
-  INLINE void mark_dirty(int flags_to_set);
-  INLINE void clear_dirty_flags(int flags_to_clear = ~0);
-  INLINE int get_dirty_flags() const;
-
-private:
-  int _dirty_flags;
-
-
+  
 public:
 public:
   static TypeHandle get_class_type() {
   static TypeHandle get_class_type() {
     return _type_handle;
     return _type_handle;
   }
   }
   static void init_type() {
   static void init_type() {
-    SavedContext::init_type();
+    BufferContext::init_type();
     register_type(_type_handle, "TextureContext",
     register_type(_type_handle, "TextureContext",
-                  SavedContext::get_class_type());
+                  BufferContext::get_class_type());
   }
   }
   virtual TypeHandle get_type() const {
   virtual TypeHandle get_type() const {
     return get_class_type();
     return get_class_type();
@@ -72,6 +71,8 @@ public:
 
 
 private:
 private:
   static TypeHandle _type_handle;
   static TypeHandle _type_handle;
+
+  friend class PreparedGraphicsObjects;
 };
 };
 
 
 #include "textureContext.I"
 #include "textureContext.I"

+ 10 - 33
panda/src/gobj/vertexBufferContext.I

@@ -23,11 +23,9 @@
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE VertexBufferContext::
 INLINE VertexBufferContext::
-VertexBufferContext(GeomVertexArrayData *data) :
-  _data(data),
-  // Initially, the number of bytes is zero, until the data has been
-  // loaded (and mark_loaded() is called).
-  _data_size_bytes(0)
+VertexBufferContext(PreparedGraphicsObjects *pgo, GeomVertexArrayData *data) :
+  BufferContext(&pgo->_vbuffer_residency),
+  _data(data)
 {
 {
 }
 }
 
 
@@ -42,19 +40,6 @@ get_data() const {
   return _data;
   return _data;
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: VertexBufferContext::get_data_size_bytes
-//       Access: Public
-//  Description: Returns the number of bytes previously reported for
-//               the data object.  This is used to track changes in
-//               the data object's allocated size; if it changes from
-//               this, we need to create a new buffer.
-////////////////////////////////////////////////////////////////////
-INLINE int VertexBufferContext::
-get_data_size_bytes() const {
-  return _data_size_bytes;
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: VertexBufferContext::changed_size
 //     Function: VertexBufferContext::changed_size
 //       Access: Public
 //       Access: Public
@@ -63,7 +48,7 @@ get_data_size_bytes() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool VertexBufferContext::
 INLINE bool VertexBufferContext::
 changed_size() const {
 changed_size() const {
-  return get_data_size_bytes() != _data->get_data_size_bytes();
+  return get_data_size_bytes() != (size_t)_data->get_data_size_bytes();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -85,18 +70,7 @@ changed_usage_hint() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool VertexBufferContext::
 INLINE bool VertexBufferContext::
 was_modified() const {
 was_modified() const {
-  return _modified != _data->get_modified();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: VertexBufferContext::get_modified
-//       Access: Public
-//  Description: Returns the UpdateSeq that was recorded the last time
-//               mark_loaded() was called.
-////////////////////////////////////////////////////////////////////
-INLINE UpdateSeq VertexBufferContext::
-get_modified() const {
-  return _modified;
+  return get_modified() != _data->get_modified();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -108,7 +82,10 @@ get_modified() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void VertexBufferContext::
 INLINE void VertexBufferContext::
 mark_loaded() {
 mark_loaded() {
-  _data_size_bytes = _data->get_data_size_bytes();
+  update_data_size_bytes(_data->get_data_size_bytes());
+  update_modified(_data->get_modified());
   _usage_hint = _data->get_usage_hint();
   _usage_hint = _data->get_usage_hint();
-  _modified = _data->get_modified();
+
+  // Assume the buffer is now resident.
+  set_resident(true);
 }
 }

+ 7 - 10
panda/src/gobj/vertexBufferContext.h

@@ -21,9 +21,9 @@
 
 
 #include "pandabase.h"
 #include "pandabase.h"
 
 
-#include "savedContext.h"
-#include "updateSeq.h"
+#include "bufferContext.h"
 #include "geomVertexArrayData.h"
 #include "geomVertexArrayData.h"
+#include "preparedGraphicsObjects.h"
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //       Class : VertexBufferContext
 //       Class : VertexBufferContext
@@ -36,17 +36,16 @@
 //               allocate a vertex buffer for the array.  OpenGL can
 //               allocate a vertex buffer for the array.  OpenGL can
 //               create a buffer object.
 //               create a buffer object.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA VertexBufferContext : public SavedContext {
+class EXPCL_PANDA VertexBufferContext : public BufferContext {
 public:
 public:
-  INLINE VertexBufferContext(GeomVertexArrayData *data);
+  INLINE VertexBufferContext(PreparedGraphicsObjects *pgo,
+                             GeomVertexArrayData *data);
 
 
   INLINE GeomVertexArrayData *get_data() const;
   INLINE GeomVertexArrayData *get_data() const;
 
 
-  INLINE int get_data_size_bytes() const;
   INLINE bool changed_size() const;
   INLINE bool changed_size() const;
   INLINE bool changed_usage_hint() const;
   INLINE bool changed_usage_hint() const;
   INLINE bool was_modified() const;
   INLINE bool was_modified() const;
-  INLINE UpdateSeq get_modified() const;
 
 
   INLINE void mark_loaded();
   INLINE void mark_loaded();
 
 
@@ -55,8 +54,6 @@ private:
   // the GSG both own their VertexBufferContexts!  That would create a
   // the GSG both own their VertexBufferContexts!  That would create a
   // circular reference count.
   // circular reference count.
   GeomVertexArrayData *_data;
   GeomVertexArrayData *_data;
-  UpdateSeq _modified;
-  int _data_size_bytes;
   GeomEnums::UsageHint _usage_hint;
   GeomEnums::UsageHint _usage_hint;
 
 
 public:
 public:
@@ -64,9 +61,9 @@ public:
     return _type_handle;
     return _type_handle;
   }
   }
   static void init_type() {
   static void init_type() {
-    SavedContext::init_type();
+    BufferContext::init_type();
     register_type(_type_handle, "VertexBufferContext",
     register_type(_type_handle, "VertexBufferContext",
-                  SavedContext::get_class_type());
+                  BufferContext::get_class_type());
   }
   }
   virtual TypeHandle get_type() const {
   virtual TypeHandle get_type() const {
     return get_class_type();
     return get_class_type();

+ 1 - 15
panda/src/pstatclient/pStatProperties.cxx

@@ -154,21 +154,7 @@ static TimeCollectorProperties time_properties[] = {
 };
 };
 
 
 static LevelCollectorProperties level_properties[] = {
 static LevelCollectorProperties level_properties[] = {
-  { 1, "Texture usage",                    { 1.0, 0.0, 0.5 },  "MB", 12, 1048576 },
-  { 1, "Texture usage:Active",             { 0.5, 1.0, 0.8 } },
-  { 1, "Texture memory",                   { 0.0, 0.0, 1.0 },  "MB", 12, 1048576 },
-  { 1, "Texture memory:In use",            { 0.0, 1.0, 1.0 } },
-  { 1, "Texture manager",                  { 1.0, 0.0, 0.0 },  "MB", 12, 1048576 },
-  { 1, "Texture manager:Resident",         { 1.0, 1.0, 0.0 } },
-  { 1, "Prepared Textures",                { 0.6, 0.8, 0.0 },  "", 500 },
-  { 1, "Prepared Textures:Active",         { 0.0, 0.6, 0.8 } },
-  { 1, "Prepared Geoms",                   { 1.0, 0.0, 0.5 },  "", 500 },
-  { 1, "Prepared Geoms:Active",            { 0.5, 1.0, 0.8 } },
-  { 1, "Prepared GeomNodes",               { 1.0, 0.0, 0.5 },  "", 500 },
-  { 1, "Prepared GeomNodes:Active",        { 0.5, 1.0, 0.8 } },
-  { 1, "Vertex buffer size",               { 0.0, 0.0, 1.0 },  "MB", 12, 1048576 },
-  { 1, "Vertex buffer size:Active vertex", { 1.0, 0.0, 0.5 } },
-  { 1, "Vertex buffer size:Active index" , { 0.5, 0.6, 1.0 } },
+  { 1, "Graphics memory",                  { 0.0, 0.0, 1.0 },  "MB", 64, 1048576 },
   { 1, "Vertex buffer switch",             { 0.0, 0.6, 0.8 },  "", 500 },
   { 1, "Vertex buffer switch",             { 0.0, 0.6, 0.8 },  "", 500 },
   { 1, "Vertex buffer switch:Vertex",      { 0.8, 0.0, 0.6 } },
   { 1, "Vertex buffer switch:Vertex",      { 0.8, 0.0, 0.6 } },
   { 1, "Vertex buffer switch:Index",       { 0.8, 0.6, 0.3 } },
   { 1, "Vertex buffer switch:Index",       { 0.8, 0.6, 0.3 } },

+ 3 - 0
panda/src/putil/Sources.pp

@@ -39,6 +39,7 @@
     ioPtaDatagramFloat.h ioPtaDatagramInt.h \
     ioPtaDatagramFloat.h ioPtaDatagramInt.h \
     ioPtaDatagramShort.h keyboardButton.h lineStream.I \
     ioPtaDatagramShort.h keyboardButton.h lineStream.I \
     lineStream.h lineStreamBuf.I lineStreamBuf.h \
     lineStream.h lineStreamBuf.I lineStreamBuf.h \
+    linkedListNode.I linkedListNode.h \
     load_prc_file.h \
     load_prc_file.h \
     modifierButtons.I modifierButtons.h mouseButton.h \
     modifierButtons.I modifierButtons.h mouseButton.h \
     mouseData.I mouseData.h nameUniquifier.I nameUniquifier.h \
     mouseData.I mouseData.h nameUniquifier.I nameUniquifier.h \
@@ -75,6 +76,7 @@
     ioPtaDatagramFloat.cxx \
     ioPtaDatagramFloat.cxx \
     ioPtaDatagramInt.cxx ioPtaDatagramShort.cxx \
     ioPtaDatagramInt.cxx ioPtaDatagramShort.cxx \
     keyboardButton.cxx lineStream.cxx lineStreamBuf.cxx \
     keyboardButton.cxx lineStream.cxx lineStreamBuf.cxx \
+    linkedListNode.cxx \
     load_prc_file.cxx \
     load_prc_file.cxx \
     modifierButtons.cxx mouseButton.cxx mouseData.cxx \
     modifierButtons.cxx mouseButton.cxx mouseData.cxx \
     nameUniquifier.cxx \
     nameUniquifier.cxx \
@@ -119,6 +121,7 @@
     ioPtaDatagramFloat.h ioPtaDatagramInt.h \
     ioPtaDatagramFloat.h ioPtaDatagramInt.h \
     ioPtaDatagramShort.h iterator_types.h keyboardButton.h lineStream.I \
     ioPtaDatagramShort.h iterator_types.h keyboardButton.h lineStream.I \
     lineStream.h lineStreamBuf.I lineStreamBuf.h \
     lineStream.h lineStreamBuf.I lineStreamBuf.h \
+    linkedListNode.I linkedListNode.h \
     load_prc_file.h \
     load_prc_file.h \
     modifierButtons.I \
     modifierButtons.I \
     modifierButtons.h mouseButton.h mouseData.I mouseData.h \
     modifierButtons.h mouseButton.h mouseData.I mouseData.h \

+ 108 - 0
panda/src/putil/linkedListNode.I

@@ -0,0 +1,108 @@
+// Filename: linkedListNode.I
+// Created by:  drose (16Mar06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: LinkedListNode::Constructor
+//       Access: Protected
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE LinkedListNode::
+LinkedListNode() {
+#ifndef NDEBUG
+  _next = NULL;
+  _prev = NULL;
+#endif
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LinkedListNode::Constructor 2
+//       Access: Protected
+//  Description: This constructor should be invoked for any
+//               LinkedListNodes that will be used to serve as the
+//               root of a list.  It sets up the pointers as an empty
+//               list.
+////////////////////////////////////////////////////////////////////
+INLINE LinkedListNode::
+LinkedListNode(bool) {
+  _next = this;
+  _prev = this;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LinkedListNode::Destructor
+//       Access: Protected
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE LinkedListNode::
+~LinkedListNode() {
+  nassertv((_next == NULL && _prev == NULL) || (_next == this && _prev == this));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LinkedListNode::remove_from_list
+//       Access: Protected
+//  Description: Removes a LinkedListNode record from the
+//               doubly-linked list.
+////////////////////////////////////////////////////////////////////
+INLINE void LinkedListNode::
+remove_from_list() {
+  nassertv(_prev->_next == this && _next->_prev == this);
+  _prev->_next = _next;
+  _next->_prev = _prev;
+#ifndef NDEBUG
+  _next = NULL;
+  _prev = NULL;
+#endif
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LinkedListNode::insert_before
+//       Access: Protected
+//  Description: Adds a LinkedListNode record before the indicated
+//               node in the doubly-linked list.
+////////////////////////////////////////////////////////////////////
+INLINE void LinkedListNode::
+insert_before(LinkedListNode *node) {
+  nassertv(node->_prev != NULL && node->_prev->_next == node && node->_next->_prev == node);
+  nassertv(_prev == (LinkedListNode *)NULL &&
+           _next == (LinkedListNode *)NULL);
+  _prev = node->_prev;
+  _next = node;
+  _prev->_next = this;
+  node->_prev = this;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LinkedListNode::take_list_from
+//       Access: Protected
+//  Description: Given that this LinkedListNode represents the root of
+//               a list, and the other pointer represents the root of
+//               a different list, move all of the nodes (except the
+//               root itself) from other_root onto this list.
+////////////////////////////////////////////////////////////////////
+INLINE void LinkedListNode::
+take_list_from(LinkedListNode *other_root) {
+  other_root->_next->_prev = _prev;
+  _prev->_next = other_root->_next;
+  other_root->_prev->_next = this;
+  _prev = other_root->_prev;
+
+  other_root->_next = other_root;
+  other_root->_prev = other_root;
+}

+ 19 - 0
panda/src/putil/linkedListNode.cxx

@@ -0,0 +1,19 @@
+// Filename: linkedListNode.cxx
+// Created by:  drose (16Mar06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "linkedListNode.h"

+ 50 - 0
panda/src/putil/linkedListNode.h

@@ -0,0 +1,50 @@
+// Filename: linkedListNode.h
+// Created by:  drose (16Mar06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef LINKEDLISTNODE_H
+#define LINKEDLISTNODE_H
+
+#include "pandabase.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : LinkedListNode
+// Description : This just stores the pointers to implement a
+//               doubly-linked list of some kind of object.  There are
+//               occasions when a hand-rolled linked list is more
+//               appropriate than an STL container.
+//
+//               Typically, each node of the linked list, as well as
+//               the root of the list, will inherit from this class.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA LinkedListNode {
+protected:
+  INLINE LinkedListNode();
+  INLINE LinkedListNode(bool);
+  INLINE ~LinkedListNode();
+
+  INLINE void remove_from_list();
+  INLINE void insert_before(LinkedListNode *node);
+
+  INLINE void take_list_from(LinkedListNode *other_root);
+
+  LinkedListNode *_prev, *_next;
+};
+
+#include "linkedListNode.I"
+
+#endif

+ 1 - 0
panda/src/putil/putil_composite1.cxx

@@ -23,4 +23,5 @@
 #include "keyboardButton.cxx"
 #include "keyboardButton.cxx"
 #include "lineStream.cxx"
 #include "lineStream.cxx"
 #include "lineStreamBuf.cxx"
 #include "lineStreamBuf.cxx"
+#include "linkedListNode.cxx"
 #include "load_prc_file.cxx"
 #include "load_prc_file.cxx"