ソースを参照

First pass at memory-managed vertices. Might break threaded code.

David Rose 18 年 前
コミット
b943c36fae
48 ファイル変更1240 行追加586 行削除
  1. 14 2
      panda/src/display/graphicsEngine.cxx
  2. 5 1
      panda/src/display/graphicsEngine.h
  3. 18 18
      panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx
  4. 1 1
      panda/src/dxgsg8/dxGraphicsStateGuardian8.h
  5. 1 1
      panda/src/dxgsg8/dxIndexBufferContext8.cxx
  6. 3 3
      panda/src/dxgsg8/dxVertexBufferContext8.cxx
  7. 2 2
      panda/src/dxgsg8/dxVertexBufferContext8.h
  8. 21 21
      panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx
  9. 1 1
      panda/src/dxgsg9/dxGraphicsStateGuardian9.h
  10. 1 1
      panda/src/dxgsg9/dxIndexBufferContext9.cxx
  11. 1 1
      panda/src/dxgsg9/dxShaderContext9.cxx
  12. 4 4
      panda/src/dxgsg9/dxVertexBufferContext9.cxx
  13. 3 3
      panda/src/dxgsg9/dxVertexBufferContext9.h
  14. 14 13
      panda/src/glstuff/glGraphicsStateGuardian_src.cxx
  15. 2 2
      panda/src/glstuff/glGraphicsStateGuardian_src.h
  16. 1 1
      panda/src/glstuff/glShaderContext_src.cxx
  17. 3 0
      panda/src/gobj/Sources.pp
  18. 1 2
      panda/src/gobj/config_gobj.cxx
  19. 4 0
      panda/src/gobj/geom.cxx
  20. 11 0
      panda/src/gobj/geomEnums.h
  21. 6 22
      panda/src/gobj/geomPrimitive.I
  22. 2 1
      panda/src/gobj/geomPrimitive.cxx
  23. 3 4
      panda/src/gobj/geomPrimitive.h
  24. 188 176
      panda/src/gobj/geomVertexArrayData.I
  25. 297 58
      panda/src/gobj/geomVertexArrayData.cxx
  26. 95 73
      panda/src/gobj/geomVertexArrayData.h
  27. 2 2
      panda/src/gobj/geomVertexData.I
  28. 33 37
      panda/src/gobj/geomVertexData.cxx
  29. 8 8
      panda/src/gobj/geomVertexData.h
  30. 3 2
      panda/src/gobj/geomVertexFormat.cxx
  31. 18 31
      panda/src/gobj/geomVertexReader.I
  32. 8 10
      panda/src/gobj/geomVertexReader.cxx
  33. 3 5
      panda/src/gobj/geomVertexReader.h
  34. 29 35
      panda/src/gobj/geomVertexWriter.I
  35. 8 10
      panda/src/gobj/geomVertexWriter.cxx
  36. 3 5
      panda/src/gobj/geomVertexWriter.h
  37. 11 8
      panda/src/gobj/gobj_composite1.cxx
  38. 3 5
      panda/src/gobj/gobj_composite2.cxx
  39. 203 0
      panda/src/gobj/simpleLru.I
  40. 96 0
      panda/src/gobj/simpleLru.cxx
  41. 88 0
      panda/src/gobj/simpleLru.h
  42. 4 4
      panda/src/gobj/vertexBufferContext.I
  43. 4 4
      panda/src/gobj/vertexBufferContext.h
  44. 5 4
      panda/src/pgraph/geomTransformer.cxx
  45. 2 2
      panda/src/pgraph/sceneGraphReducer.cxx
  46. 2 2
      panda/src/pstatclient/pStatClient.cxx
  47. 4 0
      panda/src/pstatclient/pStatProperties.cxx
  48. 1 1
      panda/src/putil/copyOnWritePointer.I

+ 14 - 2
panda/src/display/graphicsEngine.cxx

@@ -43,6 +43,7 @@
 #include "objectDeletor.h"
 #include "objectDeletor.h"
 #include "bamCache.h"
 #include "bamCache.h"
 #include "cullableObject.h"
 #include "cullableObject.h"
+#include "geomVertexArrayData.h"
 
 
 #if defined(WIN32)
 #if defined(WIN32)
   #define WINDOWS_LEAN_AND_MEAN
   #define WINDOWS_LEAN_AND_MEAN
@@ -75,6 +76,12 @@ PStatCollector GraphicsEngine::_cyclers_pcollector("PipelineCyclers");
 PStatCollector GraphicsEngine::_dirty_cyclers_pcollector("Dirty PipelineCyclers");
 PStatCollector GraphicsEngine::_dirty_cyclers_pcollector("Dirty PipelineCyclers");
 PStatCollector GraphicsEngine::_delete_pcollector("App:Delete");
 PStatCollector GraphicsEngine::_delete_pcollector("App:Delete");
 
 
+
+PStatCollector GraphicsEngine::_sw_sprites_pcollector("SW Sprites");
+PStatCollector GraphicsEngine::_vertex_data_resident_pcollector("Vertex Data:Resident");
+PStatCollector GraphicsEngine::_vertex_data_compressed_pcollector("Vertex Data:Compressed");
+PStatCollector GraphicsEngine::_vertex_data_disk_pcollector("Vertex Data:Disk");
+
 // These are counted independently by the collision system; we
 // These are counted independently by the collision system; we
 // redefine them here so we can reset them at each frame.
 // redefine them here so we can reset them at each frame.
 PStatCollector GraphicsEngine::_cnode_volume_pcollector("Collision Volumes:CollisionNode");
 PStatCollector GraphicsEngine::_cnode_volume_pcollector("Collision Volumes:CollisionNode");
@@ -95,7 +102,6 @@ PStatCollector GraphicsEngine::_volume_inv_sphere_pcollector("Collision Volumes:
 PStatCollector GraphicsEngine::_test_inv_sphere_pcollector("Collision Tests:CollisionInvSphere");
 PStatCollector GraphicsEngine::_test_inv_sphere_pcollector("Collision Tests:CollisionInvSphere");
 PStatCollector GraphicsEngine::_volume_geom_pcollector("Collision Volumes:CollisionGeom");
 PStatCollector GraphicsEngine::_volume_geom_pcollector("Collision Volumes:CollisionGeom");
 PStatCollector GraphicsEngine::_test_geom_pcollector("Collision Tests:CollisionGeom");
 PStatCollector GraphicsEngine::_test_geom_pcollector("Collision Tests:CollisionGeom");
-PStatCollector GraphicsEngine::_sw_sprites_pcollector("SW Sprites");
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsEngine::Constructor
 //     Function: GraphicsEngine::Constructor
@@ -672,6 +678,8 @@ render_frame() {
     PStatTimer timer(_delete_pcollector, current_thread);
     PStatTimer timer(_delete_pcollector, current_thread);
     deletor->flush();
     deletor->flush();
   }
   }
+
+  GeomVertexArrayData::lru_epoch();
   
   
   GeomCacheManager::flush_level();
   GeomCacheManager::flush_level();
   CullTraverser::flush_level();
   CullTraverser::flush_level();
@@ -714,6 +722,11 @@ render_frame() {
     _render_states_unused_pcollector.set_level(RenderState::get_num_unused_states());
     _render_states_unused_pcollector.set_level(RenderState::get_num_unused_states());
   }
   }
 
 
+  _sw_sprites_pcollector.clear_level();
+  _vertex_data_resident_pcollector.set_level(GeomVertexArrayData::get_global_lru(GeomVertexArrayData::RC_resident)->get_total_size());
+  _vertex_data_compressed_pcollector.set_level(GeomVertexArrayData::get_global_lru(GeomVertexArrayData::RC_compressed)->get_total_size());
+  _vertex_data_disk_pcollector.set_level(GeomVertexArrayData::get_global_lru(GeomVertexArrayData::RC_disk)->get_total_size());
+
   _cnode_volume_pcollector.clear_level();
   _cnode_volume_pcollector.clear_level();
   _gnode_volume_pcollector.clear_level();
   _gnode_volume_pcollector.clear_level();
   _geom_volume_pcollector.clear_level();
   _geom_volume_pcollector.clear_level();
@@ -732,7 +745,6 @@ render_frame() {
   _test_inv_sphere_pcollector.clear_level();
   _test_inv_sphere_pcollector.clear_level();
   _volume_geom_pcollector.clear_level();
   _volume_geom_pcollector.clear_level();
   _test_geom_pcollector.clear_level();
   _test_geom_pcollector.clear_level();
-  _sw_sprites_pcollector.clear_level();
 
 
 #endif  // DO_PSTATS
 #endif  // DO_PSTATS
 
 

+ 5 - 1
panda/src/display/graphicsEngine.h

@@ -359,6 +359,11 @@ private:
   static PStatCollector _dirty_cyclers_pcollector;
   static PStatCollector _dirty_cyclers_pcollector;
   static PStatCollector _delete_pcollector;
   static PStatCollector _delete_pcollector;
 
 
+  static PStatCollector _sw_sprites_pcollector;
+  static PStatCollector _vertex_data_resident_pcollector;
+  static PStatCollector _vertex_data_compressed_pcollector;
+  static PStatCollector _vertex_data_disk_pcollector;
+
   static PStatCollector _cnode_volume_pcollector;
   static PStatCollector _cnode_volume_pcollector;
   static PStatCollector _gnode_volume_pcollector;
   static PStatCollector _gnode_volume_pcollector;
   static PStatCollector _geom_volume_pcollector;
   static PStatCollector _geom_volume_pcollector;
@@ -377,7 +382,6 @@ private:
   static PStatCollector _test_inv_sphere_pcollector;
   static PStatCollector _test_inv_sphere_pcollector;
   static PStatCollector _volume_geom_pcollector;
   static PStatCollector _volume_geom_pcollector;
   static PStatCollector _test_geom_pcollector;
   static PStatCollector _test_geom_pcollector;
-  static PStatCollector _sw_sprites_pcollector;
 
 
   friend class WindowRenderer;
   friend class WindowRenderer;
   friend class GraphicsOutput;
   friend class GraphicsOutput;

+ 18 - 18
panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx

@@ -305,7 +305,7 @@ prepare_vertex_buffer(GeomVertexArrayData *data) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void DXGraphicsStateGuardian8::
 void DXGraphicsStateGuardian8::
 apply_vertex_buffer(VertexBufferContext *vbc,
 apply_vertex_buffer(VertexBufferContext *vbc,
-                    const GeomVertexArrayDataPipelineReader *reader) {
+                    const GeomVertexArrayDataHandle *reader) {
   DXVertexBufferContext8 *dvbc = DCAST(DXVertexBufferContext8, vbc);
   DXVertexBufferContext8 *dvbc = DCAST(DXVertexBufferContext8, vbc);
 
 
   if (dvbc->_vbuffer == NULL) {
   if (dvbc->_vbuffer == NULL) {
@@ -807,7 +807,7 @@ begin_draw_primitives(const GeomPipelineReader *geom_reader,
   const GeomVertexFormat *format = _data_reader->get_format();
   const GeomVertexFormat *format = _data_reader->get_format();
 
 
   // The munger should have put the FVF data in the first array.
   // The munger should have put the FVF data in the first array.
-  const GeomVertexArrayDataPipelineReader *data = _data_reader->get_array_reader(0);
+  const GeomVertexArrayDataHandle *data = _data_reader->get_array_reader(0);
 
 
   VertexBufferContext *vbc = ((GeomVertexArrayData *)(data->get_object()))->prepare_now(get_prepared_objects(), this);
   VertexBufferContext *vbc = ((GeomVertexArrayData *)(data->get_object()))->prepare_now(get_prepared_objects(), this);
   nassertr(vbc != (VertexBufferContext *)NULL, false);
   nassertr(vbc != (VertexBufferContext *)NULL, false);
@@ -930,9 +930,9 @@ draw_triangles(const GeomPrimitivePipelineReader *reader) {
         (D3DPT_TRIANGLELIST,
         (D3DPT_TRIANGLELIST,
          min_vertex, max_vertex,
          min_vertex, max_vertex,
          reader->get_num_primitives(),
          reader->get_num_primitives(),
-         reader->get_data(),
+         reader->get_pointer(),
          index_type,
          index_type,
-         _data_reader->get_array_reader(0)->get_data(),
+         _data_reader->get_array_reader(0)->get_pointer(),
          _data_reader->get_format()->get_array(0)->get_stride());
          _data_reader->get_format()->get_array(0)->get_stride());
     }
     }
   } else {
   } else {
@@ -949,7 +949,7 @@ draw_triangles(const GeomPrimitivePipelineReader *reader) {
       draw_primitive_up(D3DPT_TRIANGLELIST, reader->get_num_primitives(),
       draw_primitive_up(D3DPT_TRIANGLELIST, reader->get_num_primitives(),
                         reader->get_first_vertex(),
                         reader->get_first_vertex(),
                         reader->get_num_vertices(),
                         reader->get_num_vertices(),
-                        _data_reader->get_array_reader(0)->get_data(),
+                        _data_reader->get_array_reader(0)->get_pointer(),
                         _data_reader->get_format()->get_array(0)->get_stride());
                         _data_reader->get_format()->get_array(0)->get_stride());
     }
     }
   }
   }
@@ -990,8 +990,8 @@ draw_tristrips(const GeomPrimitivePipelineReader *reader) {
           (D3DPT_TRIANGLESTRIP,
           (D3DPT_TRIANGLESTRIP,
            min_vertex, max_vertex,
            min_vertex, max_vertex,
            reader->get_num_vertices() - 2,
            reader->get_num_vertices() - 2,
-           reader->get_data(), index_type,
-           _data_reader->get_array_reader(0)->get_data(),
+           reader->get_pointer(), index_type,
+           _data_reader->get_array_reader(0)->get_pointer(),
            _data_reader->get_format()->get_array(0)->get_stride());
            _data_reader->get_format()->get_array(0)->get_stride());
       }
       }
     } else {
     } else {
@@ -1008,7 +1008,7 @@ draw_tristrips(const GeomPrimitivePipelineReader *reader) {
                           reader->get_num_vertices() - 2,
                           reader->get_num_vertices() - 2,
                           reader->get_first_vertex(),
                           reader->get_first_vertex(),
                           reader->get_num_vertices(),
                           reader->get_num_vertices(),
-                          _data_reader->get_array_reader(0)->get_data(),
+                          _data_reader->get_array_reader(0)->get_pointer(),
                           _data_reader->get_format()->get_array(0)->get_stride());
                           _data_reader->get_format()->get_array(0)->get_stride());
       }
       }
     }
     }
@@ -1050,9 +1050,9 @@ draw_tristrips(const GeomPrimitivePipelineReader *reader) {
 
 
       } else {
       } else {
         // Indexed, client arrays, individual triangle strips.
         // Indexed, client arrays, individual triangle strips.
-        CPTA_uchar array_data = _data_reader->get_array_reader(0)->get_data();
+        const unsigned char *array_data = _data_reader->get_array_reader(0)->get_pointer();
         int stride = _data_reader->get_format()->get_array(0)->get_stride();
         int stride = _data_reader->get_format()->get_array(0)->get_stride();
-        CPTA_uchar vertices = reader->get_data();
+        const unsigned char *vertices = reader->get_pointer();
         D3DFORMAT index_type = get_index_type(reader->get_index_type());
         D3DFORMAT index_type = get_index_type(reader->get_index_type());
 
 
         unsigned int start = 0;
         unsigned int start = 0;
@@ -1087,7 +1087,7 @@ draw_tristrips(const GeomPrimitivePipelineReader *reader) {
 
 
       } else {
       } else {
         // Nonindexed, client arrays, individual triangle strips.
         // Nonindexed, client arrays, individual triangle strips.
-        CPTA_uchar array_data = _data_reader->get_array_reader(0)->get_data();
+        const unsigned char *array_data = _data_reader->get_array_reader(0)->get_pointer();
         int stride = _data_reader->get_format()->get_array(0)->get_stride();
         int stride = _data_reader->get_format()->get_array(0)->get_stride();
 
 
         unsigned int start = 0;
         unsigned int start = 0;
@@ -1150,9 +1150,9 @@ draw_trifans(const GeomPrimitivePipelineReader *reader) {
 
 
     } else {
     } else {
       // Indexed, client arrays.
       // Indexed, client arrays.
-      CPTA_uchar array_data = _data_reader->get_array_reader(0)->get_data();
+      const unsigned char *array_data = _data_reader->get_array_reader(0)->get_pointer();
       int stride = _data_reader->get_format()->get_array(0)->get_stride();
       int stride = _data_reader->get_format()->get_array(0)->get_stride();
-      CPTA_uchar vertices = reader->get_data();
+      const unsigned char *vertices = reader->get_pointer();
       D3DFORMAT index_type = get_index_type(reader->get_index_type());
       D3DFORMAT index_type = get_index_type(reader->get_index_type());
 
 
       unsigned int start = 0;
       unsigned int start = 0;
@@ -1187,7 +1187,7 @@ draw_trifans(const GeomPrimitivePipelineReader *reader) {
 
 
     } else {
     } else {
       // Nonindexed, client arrays.
       // Nonindexed, client arrays.
-      CPTA_uchar array_data = _data_reader->get_array_reader(0)->get_data();
+      const unsigned char *array_data = _data_reader->get_array_reader(0)->get_pointer();
       int stride = _data_reader->get_format()->get_array(0)->get_stride();
       int stride = _data_reader->get_format()->get_array(0)->get_stride();
 
 
       unsigned int start = 0;
       unsigned int start = 0;
@@ -1238,9 +1238,9 @@ draw_lines(const GeomPrimitivePipelineReader *reader) {
         (D3DPT_LINELIST,
         (D3DPT_LINELIST,
          min_vertex, max_vertex,
          min_vertex, max_vertex,
          reader->get_num_primitives(),
          reader->get_num_primitives(),
-         reader->get_data(),
+         reader->get_pointer(),
          index_type,
          index_type,
-         _data_reader->get_array_reader(0)->get_data(),
+         _data_reader->get_array_reader(0)->get_pointer(),
          _data_reader->get_format()->get_array(0)->get_stride());
          _data_reader->get_format()->get_array(0)->get_stride());
     }
     }
   } else {
   } else {
@@ -1256,7 +1256,7 @@ draw_lines(const GeomPrimitivePipelineReader *reader) {
       draw_primitive_up(D3DPT_LINELIST, reader->get_num_primitives(),
       draw_primitive_up(D3DPT_LINELIST, reader->get_num_primitives(),
                         reader->get_first_vertex(),
                         reader->get_first_vertex(),
                         reader->get_num_vertices(),
                         reader->get_num_vertices(),
-                        _data_reader->get_array_reader(0)->get_data(),
+                        _data_reader->get_array_reader(0)->get_pointer(),
                         _data_reader->get_format()->get_array(0)->get_stride());
                         _data_reader->get_format()->get_array(0)->get_stride());
     }
     }
   }
   }
@@ -1299,7 +1299,7 @@ draw_points(const GeomPrimitivePipelineReader *reader) {
     draw_primitive_up(D3DPT_POINTLIST, reader->get_num_primitives(),
     draw_primitive_up(D3DPT_POINTLIST, reader->get_num_primitives(),
                       reader->get_first_vertex(),
                       reader->get_first_vertex(),
                       reader->get_num_vertices(),
                       reader->get_num_vertices(),
-                      _data_reader->get_array_reader(0)->get_data(),
+                      _data_reader->get_array_reader(0)->get_pointer(),
                       _data_reader->get_format()->get_array(0)->get_stride());
                       _data_reader->get_format()->get_array(0)->get_stride());
   }
   }
 }
 }

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

@@ -57,7 +57,7 @@ public:
 
 
   virtual VertexBufferContext *prepare_vertex_buffer(GeomVertexArrayData *data);
   virtual VertexBufferContext *prepare_vertex_buffer(GeomVertexArrayData *data);
   void apply_vertex_buffer(VertexBufferContext *vbc,
   void apply_vertex_buffer(VertexBufferContext *vbc,
-                           const GeomVertexArrayDataPipelineReader *reader);
+                           const GeomVertexArrayDataHandle *reader);
   virtual void release_vertex_buffer(VertexBufferContext *vbc);
   virtual void release_vertex_buffer(VertexBufferContext *vbc);
 
 
   virtual IndexBufferContext *prepare_index_buffer(GeomPrimitive *data);
   virtual IndexBufferContext *prepare_index_buffer(GeomPrimitive *data);

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

@@ -131,7 +131,7 @@ upload_data(const GeomPrimitivePipelineReader *reader) {
   }
   }
 
 
   GraphicsStateGuardian::_data_transferred_pcollector.add_level(data_size);
   GraphicsStateGuardian::_data_transferred_pcollector.add_level(data_size);
-  memcpy(local_pointer, reader->get_data(), data_size);
+  memcpy(local_pointer, reader->get_pointer(), data_size);
 
 
   _ibuffer->Unlock();
   _ibuffer->Unlock();
 }
 }

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

@@ -189,7 +189,7 @@ DXVertexBufferContext8::
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void DXVertexBufferContext8::
 void DXVertexBufferContext8::
 create_vbuffer(DXScreenData &scrn,
 create_vbuffer(DXScreenData &scrn,
-               const GeomVertexArrayDataPipelineReader *reader) {
+               const GeomVertexArrayDataHandle *reader) {
   nassertv(reader->get_object() == get_data());
   nassertv(reader->get_object() == get_data());
   Thread *current_thread = reader->get_current_thread();
   Thread *current_thread = reader->get_current_thread();
 
 
@@ -232,7 +232,7 @@ create_vbuffer(DXScreenData &scrn,
 //               DirectX.
 //               DirectX.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void DXVertexBufferContext8::
 void DXVertexBufferContext8::
-upload_data(const GeomVertexArrayDataPipelineReader *reader) {
+upload_data(const GeomVertexArrayDataHandle *reader) {
   nassertv(reader->get_object() == get_data());
   nassertv(reader->get_object() == get_data());
   nassertv(_vbuffer != NULL);
   nassertv(_vbuffer != NULL);
   Thread *current_thread = reader->get_current_thread();
   Thread *current_thread = reader->get_current_thread();
@@ -257,7 +257,7 @@ upload_data(const GeomVertexArrayDataPipelineReader *reader) {
   }
   }
 
 
   GraphicsStateGuardian::_data_transferred_pcollector.add_level(data_size);
   GraphicsStateGuardian::_data_transferred_pcollector.add_level(data_size);
-  memcpy(local_pointer, reader->get_data(), data_size);
+  memcpy(local_pointer, reader->get_pointer(), data_size);
 
 
   _vbuffer->Unlock();
   _vbuffer->Unlock();
 }
 }

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

@@ -34,8 +34,8 @@ public:
   virtual ~DXVertexBufferContext8();
   virtual ~DXVertexBufferContext8();
 
 
   void create_vbuffer(DXScreenData &scrn,
   void create_vbuffer(DXScreenData &scrn,
-                      const GeomVertexArrayDataPipelineReader *reader);
-  void upload_data(const GeomVertexArrayDataPipelineReader *reader);
+                      const GeomVertexArrayDataHandle *reader);
+  void upload_data(const GeomVertexArrayDataHandle *reader);
 
 
   IDirect3DVertexBuffer8 *_vbuffer;
   IDirect3DVertexBuffer8 *_vbuffer;
   int _fvf;
   int _fvf;

+ 21 - 21
panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx

@@ -393,7 +393,7 @@ prepare_vertex_buffer(GeomVertexArrayData *data) {
 void DXGraphicsStateGuardian9::
 void DXGraphicsStateGuardian9::
 apply_vertex_buffer(VertexBufferContext *vbc,
 apply_vertex_buffer(VertexBufferContext *vbc,
                     CLP(ShaderContext) *shader_context,
                     CLP(ShaderContext) *shader_context,
-                    const GeomVertexArrayDataPipelineReader *reader) {
+                    const GeomVertexArrayDataHandle *reader) {
   DXVertexBufferContext9 *dvbc = DCAST(DXVertexBufferContext9, vbc);
   DXVertexBufferContext9 *dvbc = DCAST(DXVertexBufferContext9, vbc);
 
 
   DBG_SH3 dxgsg9_cat.debug ( ) << "apply_vertex_buffer\n"; DBG_E
   DBG_SH3 dxgsg9_cat.debug ( ) << "apply_vertex_buffer\n"; DBG_E
@@ -1186,7 +1186,7 @@ begin_draw_primitives(const GeomPipelineReader *geom_reader,
   _vertex_array_shader_context = _current_shader_context;
   _vertex_array_shader_context = _current_shader_context;
 
 
   const GeomVertexFormat *format = _data_reader->get_format ( );
   const GeomVertexFormat *format = _data_reader->get_format ( );
-  const GeomVertexArrayDataPipelineReader *data;
+  const GeomVertexArrayDataHandle *data;
   int number_of_arrays = _data_reader -> get_num_arrays ( );
   int number_of_arrays = _data_reader -> get_num_arrays ( );
 
 
   if (_current_shader_context && number_of_arrays > 1) {
   if (_current_shader_context && number_of_arrays > 1) {
@@ -1422,9 +1422,9 @@ draw_triangles(const GeomPrimitivePipelineReader *reader) {
         (D3DPT_TRIANGLELIST,
         (D3DPT_TRIANGLELIST,
          min_vertex, max_vertex,
          min_vertex, max_vertex,
          reader->get_num_primitives(),
          reader->get_num_primitives(),
-         reader->get_data(),
+         reader->get_pointer(),
          index_type,
          index_type,
-         _data_reader->get_array_reader(0)->get_data(),
+         _data_reader->get_array_reader(0)->get_pointer(),
          _data_reader->get_format()->get_array(0)->get_stride());
          _data_reader->get_format()->get_array(0)->get_stride());
     }
     }
   } else {
   } else {
@@ -1446,7 +1446,7 @@ draw_triangles(const GeomPrimitivePipelineReader *reader) {
       draw_primitive_up(D3DPT_TRIANGLELIST, reader->get_num_primitives(),
       draw_primitive_up(D3DPT_TRIANGLELIST, reader->get_num_primitives(),
       reader->get_first_vertex(),
       reader->get_first_vertex(),
       reader->get_num_vertices(),
       reader->get_num_vertices(),
-      _data_reader->get_array_reader(0)->get_data(),
+      _data_reader->get_array_reader(0)->get_pointer(),
       _data_reader->get_format()->get_array(0)->get_stride());
       _data_reader->get_format()->get_array(0)->get_stride());
     }
     }
   }
   }
@@ -1497,8 +1497,8 @@ draw_tristrips(const GeomPrimitivePipelineReader *reader) {
           (D3DPT_TRIANGLESTRIP,
           (D3DPT_TRIANGLESTRIP,
            min_vertex, max_vertex,
            min_vertex, max_vertex,
            reader->get_num_vertices() - 2,
            reader->get_num_vertices() - 2,
-           reader->get_data(), index_type,
-           _data_reader->get_array_reader(0)->get_data(),
+           reader->get_pointer(), index_type,
+           _data_reader->get_array_reader(0)->get_pointer(),
            _data_reader->get_format()->get_array(0)->get_stride());
            _data_reader->get_format()->get_array(0)->get_stride());
       }
       }
     } else {
     } else {
@@ -1518,7 +1518,7 @@ draw_tristrips(const GeomPrimitivePipelineReader *reader) {
         reader->get_num_vertices() - 2,
         reader->get_num_vertices() - 2,
         reader->get_first_vertex(),
         reader->get_first_vertex(),
         reader->get_num_vertices(),
         reader->get_num_vertices(),
-        _data_reader->get_array_reader(0)->get_data(),
+        _data_reader->get_array_reader(0)->get_pointer(),
         _data_reader->get_format()->get_array(0)->get_stride());
         _data_reader->get_format()->get_array(0)->get_stride());
       }
       }
     }
     }
@@ -1561,9 +1561,9 @@ draw_tristrips(const GeomPrimitivePipelineReader *reader) {
 
 
       } else {
       } else {
         // Indexed, client arrays, individual triangle strips.
         // Indexed, client arrays, individual triangle strips.
-        CPTA_uchar array_data = _data_reader->get_array_reader(0)->get_data();
+        const unsigned char *array_data = _data_reader->get_array_reader(0)->get_pointer();
         int stride = _data_reader->get_format()->get_array(0)->get_stride();
         int stride = _data_reader->get_format()->get_array(0)->get_stride();
-        CPTA_uchar vertices = reader->get_data();
+        const unsigned char *vertices = reader->get_pointer();
         D3DFORMAT index_type = get_index_type(reader->get_index_type());
         D3DFORMAT index_type = get_index_type(reader->get_index_type());
 
 
         unsigned int start = 0;
         unsigned int start = 0;
@@ -1598,7 +1598,7 @@ draw_tristrips(const GeomPrimitivePipelineReader *reader) {
 
 
       } else {
       } else {
         // Nonindexed, client arrays, individual triangle strips.
         // Nonindexed, client arrays, individual triangle strips.
-        CPTA_uchar array_data = _data_reader->get_array_reader(0)->get_data();
+        const unsigned char *array_data = _data_reader->get_array_reader(0)->get_pointer();
         int stride = _data_reader->get_format()->get_array(0)->get_stride();
         int stride = _data_reader->get_format()->get_array(0)->get_stride();
 
 
         unsigned int start = 0;
         unsigned int start = 0;
@@ -1664,9 +1664,9 @@ draw_trifans(const GeomPrimitivePipelineReader *reader) {
 
 
     } else {
     } else {
       // Indexed, client arrays.
       // Indexed, client arrays.
-      CPTA_uchar array_data = _data_reader->get_array_reader(0)->get_data();
+      const unsigned char *array_data = _data_reader->get_array_reader(0)->get_pointer();
       int stride = _data_reader->get_format()->get_array(0)->get_stride();
       int stride = _data_reader->get_format()->get_array(0)->get_stride();
-      CPTA_uchar vertices = reader->get_data();
+      const unsigned char *vertices = reader->get_pointer();
       D3DFORMAT index_type = get_index_type(reader->get_index_type());
       D3DFORMAT index_type = get_index_type(reader->get_index_type());
 
 
       unsigned int start = 0;
       unsigned int start = 0;
@@ -1701,7 +1701,7 @@ draw_trifans(const GeomPrimitivePipelineReader *reader) {
 
 
     } else {
     } else {
       // Nonindexed, client arrays.
       // Nonindexed, client arrays.
-      CPTA_uchar array_data = _data_reader->get_array_reader(0)->get_data();
+      const unsigned char *array_data = _data_reader->get_array_reader(0)->get_pointer();
       int stride = _data_reader->get_format()->get_array(0)->get_stride();
       int stride = _data_reader->get_format()->get_array(0)->get_stride();
 
 
       unsigned int start = 0;
       unsigned int start = 0;
@@ -1753,9 +1753,9 @@ draw_lines(const GeomPrimitivePipelineReader *reader) {
         (D3DPT_LINELIST,
         (D3DPT_LINELIST,
          min_vertex, max_vertex,
          min_vertex, max_vertex,
          reader->get_num_primitives(),
          reader->get_num_primitives(),
-         reader->get_data(),
+         reader->get_pointer(),
          index_type,
          index_type,
-         _data_reader->get_array_reader(0)->get_data(),
+         _data_reader->get_array_reader(0)->get_pointer(),
          _data_reader->get_format()->get_array(0)->get_stride());
          _data_reader->get_format()->get_array(0)->get_stride());
     }
     }
   } else {
   } else {
@@ -1771,7 +1771,7 @@ draw_lines(const GeomPrimitivePipelineReader *reader) {
       draw_primitive_up(D3DPT_LINELIST, reader->get_num_primitives(),
       draw_primitive_up(D3DPT_LINELIST, reader->get_num_primitives(),
       reader->get_first_vertex(),
       reader->get_first_vertex(),
       reader->get_num_vertices(),
       reader->get_num_vertices(),
-      _data_reader->get_array_reader(0)->get_data(),
+      _data_reader->get_array_reader(0)->get_pointer(),
       _data_reader->get_format()->get_array(0)->get_stride());
       _data_reader->get_format()->get_array(0)->get_stride());
     }
     }
   }
   }
@@ -1814,7 +1814,7 @@ draw_points(const GeomPrimitivePipelineReader *reader) {
     draw_primitive_up(D3DPT_POINTLIST, reader->get_num_primitives(),
     draw_primitive_up(D3DPT_POINTLIST, reader->get_num_primitives(),
                       reader->get_first_vertex(),
                       reader->get_first_vertex(),
                       reader->get_num_vertices(),
                       reader->get_num_vertices(),
-                      _data_reader->get_array_reader(0)->get_data(),
+                      _data_reader->get_array_reader(0)->get_pointer(),
                       _data_reader->get_format()->get_array(0)->get_stride());
                       _data_reader->get_format()->get_array(0)->get_stride());
   }
   }
 }
 }
@@ -2220,11 +2220,11 @@ bool vertex_buffer_page_in_function (LruPage *lru_page)
 
 
   // allocate vertex buffer
   // allocate vertex buffer
   Thread *current_thread = Thread::get_current_thread();
   Thread *current_thread = Thread::get_current_thread();
-  GeomVertexArrayDataPipelineReader reader(vertex_buffer->get_data(), current_thread);
-  vertex_buffer -> allocate_vbuffer (*(gsg->_screen), &reader);
+  CPT(GeomVertexArrayDataHandle) reader = vertex_buffer->get_data()->get_handle(current_thread);
+  vertex_buffer -> allocate_vbuffer (*(gsg->_screen), reader);
 
 
   // update vertex buffer
   // update vertex buffer
-  vertex_buffer -> upload_data(&reader);
+  vertex_buffer -> upload_data(reader);
   vertex_buffer -> set_resident(true);
   vertex_buffer -> set_resident(true);
 
 
   if (DEBUG_LRU && dxgsg9_cat.is_debug())
   if (DEBUG_LRU && dxgsg9_cat.is_debug())

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

@@ -94,7 +94,7 @@ public:
 
 
   virtual VertexBufferContext *prepare_vertex_buffer(GeomVertexArrayData *data);
   virtual VertexBufferContext *prepare_vertex_buffer(GeomVertexArrayData *data);
   void apply_vertex_buffer(VertexBufferContext *vbc, CLP(ShaderContext) *shader_context,
   void apply_vertex_buffer(VertexBufferContext *vbc, CLP(ShaderContext) *shader_context,
-                           const GeomVertexArrayDataPipelineReader *reader);
+                           const GeomVertexArrayDataHandle *reader);
   virtual void release_vertex_buffer(VertexBufferContext *vbc);
   virtual void release_vertex_buffer(VertexBufferContext *vbc);
 
 
   virtual IndexBufferContext *prepare_index_buffer(GeomPrimitive *data);
   virtual IndexBufferContext *prepare_index_buffer(GeomPrimitive *data);

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

@@ -237,7 +237,7 @@ upload_data(const GeomPrimitivePipelineReader *reader) {
   }
   }
 
 
   GraphicsStateGuardian::_data_transferred_pcollector.add_level(data_size);
   GraphicsStateGuardian::_data_transferred_pcollector.add_level(data_size);
-  memcpy(local_pointer, reader->get_data(), data_size);
+  memcpy(local_pointer, reader->get_pointer(), data_size);
 
 
   _ibuffer->Unlock();
   _ibuffer->Unlock();
 }
 }

+ 1 - 1
panda/src/dxgsg9/dxShaderContext9.cxx

@@ -459,7 +459,7 @@ update_shader_vertex_arrays(CLP(ShaderContext) *prev, GSG *gsg)
     {
     {
       if (_vertex_element_array == 0) {
       if (_vertex_element_array == 0) {
         bool error;
         bool error;
-        const GeomVertexArrayDataPipelineReader *array_reader;
+        const GeomVertexArrayDataHandle *array_reader;
         Geom::NumericType numeric_type;
         Geom::NumericType numeric_type;
         int start, stride, num_values;
         int start, stride, num_values;
         int nvarying = _expansion->_var_spec.size();
         int nvarying = _expansion->_var_spec.size();

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

@@ -341,7 +341,7 @@ free_vbuffer(void) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void DXVertexBufferContext9::
 void DXVertexBufferContext9::
 allocate_vbuffer(DXScreenData &scrn,
 allocate_vbuffer(DXScreenData &scrn,
-                 const GeomVertexArrayDataPipelineReader *reader) {
+                 const GeomVertexArrayDataHandle *reader) {
 
 
   int data_size;
   int data_size;
   HRESULT hr;
   HRESULT hr;
@@ -393,7 +393,7 @@ allocate_vbuffer(DXScreenData &scrn,
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void DXVertexBufferContext9::
 void DXVertexBufferContext9::
 create_vbuffer(DXScreenData &scrn,
 create_vbuffer(DXScreenData &scrn,
-               const GeomVertexArrayDataPipelineReader *reader) {
+               const GeomVertexArrayDataHandle *reader) {
   nassertv(reader->get_object() == get_data());
   nassertv(reader->get_object() == get_data());
   Thread *current_thread = reader->get_current_thread();
   Thread *current_thread = reader->get_current_thread();
 
 
@@ -442,7 +442,7 @@ create_vbuffer(DXScreenData &scrn,
 //               DirectX.
 //               DirectX.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void DXVertexBufferContext9::
 void DXVertexBufferContext9::
-upload_data(const GeomVertexArrayDataPipelineReader *reader) {
+upload_data(const GeomVertexArrayDataHandle *reader) {
   nassertv(reader->get_object() == get_data());
   nassertv(reader->get_object() == get_data());
   nassertv(_vbuffer != NULL);
   nassertv(_vbuffer != NULL);
   Thread *current_thread = reader->get_current_thread();
   Thread *current_thread = reader->get_current_thread();
@@ -473,7 +473,7 @@ upload_data(const GeomVertexArrayDataPipelineReader *reader) {
   }
   }
 
 
   GraphicsStateGuardian::_data_transferred_pcollector.add_level(data_size);
   GraphicsStateGuardian::_data_transferred_pcollector.add_level(data_size);
-  memcpy(local_pointer, reader->get_data(), data_size);
+  memcpy(local_pointer, reader->get_pointer(), data_size);
 
 
   _vbuffer->Unlock();
   _vbuffer->Unlock();
 }
 }

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

@@ -34,9 +34,9 @@ public:
   virtual ~DXVertexBufferContext9();
   virtual ~DXVertexBufferContext9();
 
 
   void free_vbuffer();
   void free_vbuffer();
-  void allocate_vbuffer(DXScreenData &scrn, const GeomVertexArrayDataPipelineReader *reader);
-  void create_vbuffer(DXScreenData &scrn, const GeomVertexArrayDataPipelineReader *reader);
-  void upload_data(const GeomVertexArrayDataPipelineReader *reader);
+  void allocate_vbuffer(DXScreenData &scrn, const GeomVertexArrayDataHandle *reader);
+  void create_vbuffer(DXScreenData &scrn, const GeomVertexArrayDataHandle *reader);
+  void upload_data(const GeomVertexArrayDataHandle *reader);
 
 
   IDirect3DVertexBuffer9 *_vbuffer;
   IDirect3DVertexBuffer9 *_vbuffer;
   int _fvf;
   int _fvf;

+ 14 - 13
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -1782,7 +1782,7 @@ update_standard_vertex_arrays() {
 #endif  // SUPPORT_IMMEDIATE_MODE
 #endif  // SUPPORT_IMMEDIATE_MODE
   {
   {
     // We may use vertex arrays or buffers to render primitives.
     // We may use vertex arrays or buffers to render primitives.
-    const GeomVertexArrayDataPipelineReader *array_reader;
+    const GeomVertexArrayDataHandle *array_reader;
     int num_values;
     int num_values;
     Geom::NumericType numeric_type;
     Geom::NumericType numeric_type;
     int start;
     int start;
@@ -2697,7 +2697,7 @@ prepare_vertex_buffer(GeomVertexArrayData *data) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsStateGuardian)::
 void CLP(GraphicsStateGuardian)::
 apply_vertex_buffer(VertexBufferContext *vbc,
 apply_vertex_buffer(VertexBufferContext *vbc,
-                    const GeomVertexArrayDataPipelineReader *reader) {
+                    const GeomVertexArrayDataHandle *reader) {
   nassertv(_supports_buffers);
   nassertv(_supports_buffers);
   nassertv(reader->get_modified() != UpdateSeq::initial());
   nassertv(reader->get_modified() != UpdateSeq::initial());
 
 
@@ -2724,12 +2724,12 @@ apply_vertex_buffer(VertexBufferContext *vbc,
     if (num_bytes != 0) {
     if (num_bytes != 0) {
       if (gvbc->changed_size(reader) || gvbc->changed_usage_hint(reader)) {
       if (gvbc->changed_size(reader) || gvbc->changed_usage_hint(reader)) {
         _glBufferData(GL_ARRAY_BUFFER, num_bytes,
         _glBufferData(GL_ARRAY_BUFFER, num_bytes,
-                      reader->get_data(),
+                      reader->get_pointer(),
                       get_usage(reader->get_usage_hint()));
                       get_usage(reader->get_usage_hint()));
 
 
       } else {
       } else {
         _glBufferSubData(GL_ARRAY_BUFFER, 0, num_bytes,
         _glBufferSubData(GL_ARRAY_BUFFER, 0, num_bytes,
-                         reader->get_data());
+                         reader->get_pointer());
       }
       }
       _data_transferred_pcollector.add_level(num_bytes);
       _data_transferred_pcollector.add_level(num_bytes);
     }
     }
@@ -2795,10 +2795,10 @@ release_vertex_buffer(VertexBufferContext *vbc) {
 //               in client memory, that is, the data array passed in.
 //               in client memory, that is, the data array passed in.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 const unsigned char *CLP(GraphicsStateGuardian)::
 const unsigned char *CLP(GraphicsStateGuardian)::
-setup_array_data(const GeomVertexArrayDataPipelineReader *array_reader) {
+setup_array_data(const GeomVertexArrayDataHandle *array_reader) {
   if (!_supports_buffers) {
   if (!_supports_buffers) {
     // No support for buffer objects; always render from client.
     // No support for buffer objects; always render from client.
-    return array_reader->get_data();
+    return array_reader->get_pointer();
   }
   }
   if (!vertex_buffers || _geom_display_list != 0 ||
   if (!vertex_buffers || _geom_display_list != 0 ||
       array_reader->get_usage_hint() == Geom::UH_client) {
       array_reader->get_usage_hint() == Geom::UH_client) {
@@ -2812,12 +2812,12 @@ setup_array_data(const GeomVertexArrayDataPipelineReader *array_reader) {
       _glBindBuffer(GL_ARRAY_BUFFER, 0);
       _glBindBuffer(GL_ARRAY_BUFFER, 0);
       _current_vbuffer_index = 0;
       _current_vbuffer_index = 0;
     }
     }
-    return array_reader->get_data();
+    return array_reader->get_pointer();
   }
   }
 
 
   // Prepare the buffer object and bind it.
   // Prepare the buffer object and bind it.
   VertexBufferContext *vbc = ((GeomVertexArrayData *)array_reader->get_object())->prepare_now(get_prepared_objects(), this);
   VertexBufferContext *vbc = ((GeomVertexArrayData *)array_reader->get_object())->prepare_now(get_prepared_objects(), this);
-  nassertr(vbc != (VertexBufferContext *)NULL, array_reader->get_data());
+  nassertr(vbc != (VertexBufferContext *)NULL, array_reader->get_pointer());
   apply_vertex_buffer(vbc, array_reader);
   apply_vertex_buffer(vbc, array_reader);
 
 
   // NULL is the OpenGL convention for the first byte of the buffer object.
   // NULL is the OpenGL convention for the first byte of the buffer object.
@@ -2884,6 +2884,7 @@ apply_index_buffer(IndexBufferContext *ibc,
 
 
   if (gibc->was_modified(reader)) {
   if (gibc->was_modified(reader)) {
     PStatTimer timer(_load_index_buffer_pcollector, reader->get_current_thread());
     PStatTimer timer(_load_index_buffer_pcollector, reader->get_current_thread());
+    
     int num_bytes = reader->get_data_size_bytes();
     int num_bytes = reader->get_data_size_bytes();
     if (GLCAT.is_spam()) {
     if (GLCAT.is_spam()) {
       GLCAT.spam()
       GLCAT.spam()
@@ -2893,12 +2894,12 @@ apply_index_buffer(IndexBufferContext *ibc,
     if (num_bytes != 0) {
     if (num_bytes != 0) {
       if (gibc->changed_size(reader) || gibc->changed_usage_hint(reader)) {
       if (gibc->changed_size(reader) || gibc->changed_usage_hint(reader)) {
         _glBufferData(GL_ELEMENT_ARRAY_BUFFER, num_bytes,
         _glBufferData(GL_ELEMENT_ARRAY_BUFFER, num_bytes,
-                      reader->get_data(),
+                      reader->get_pointer(),
                       get_usage(reader->get_usage_hint()));
                       get_usage(reader->get_usage_hint()));
 
 
       } else {
       } else {
         _glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, num_bytes,
         _glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, num_bytes,
-                         reader->get_data());
+                         reader->get_pointer());
       }
       }
       _data_transferred_pcollector.add_level(num_bytes);
       _data_transferred_pcollector.add_level(num_bytes);
     }
     }
@@ -2966,7 +2967,7 @@ const unsigned char *CLP(GraphicsStateGuardian)::
 setup_primitive(const GeomPrimitivePipelineReader *reader) {
 setup_primitive(const GeomPrimitivePipelineReader *reader) {
   if (!_supports_buffers) {
   if (!_supports_buffers) {
     // No support for buffer objects; always render from client.
     // No support for buffer objects; always render from client.
-    return reader->get_data();
+    return reader->get_pointer();
   }
   }
   if (!vertex_buffers || _geom_display_list != 0 ||
   if (!vertex_buffers || _geom_display_list != 0 ||
       reader->get_usage_hint() == Geom::UH_client) {
       reader->get_usage_hint() == Geom::UH_client) {
@@ -2980,12 +2981,12 @@ setup_primitive(const GeomPrimitivePipelineReader *reader) {
       _glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
       _glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
       _current_ibuffer_index = 0;
       _current_ibuffer_index = 0;
     }
     }
-    return reader->get_data();
+    return reader->get_pointer();
   }
   }
 
 
   // Prepare the buffer object and bind it.
   // Prepare the buffer object and bind it.
   IndexBufferContext *ibc = ((GeomPrimitive *)reader->get_object())->prepare_now(get_prepared_objects(), this);
   IndexBufferContext *ibc = ((GeomPrimitive *)reader->get_object())->prepare_now(get_prepared_objects(), this);
-  nassertr(ibc != (IndexBufferContext *)NULL, reader->get_data());
+  nassertr(ibc != (IndexBufferContext *)NULL, reader->get_pointer());
   apply_index_buffer(ibc, reader);
   apply_index_buffer(ibc, reader);
 
 
   // NULL is the OpenGL convention for the first byte of the buffer object.
   // NULL is the OpenGL convention for the first byte of the buffer object.

+ 2 - 2
panda/src/glstuff/glGraphicsStateGuardian_src.h

@@ -131,9 +131,9 @@ public:
 
 
   virtual VertexBufferContext *prepare_vertex_buffer(GeomVertexArrayData *data);
   virtual VertexBufferContext *prepare_vertex_buffer(GeomVertexArrayData *data);
   void apply_vertex_buffer(VertexBufferContext *vbc,
   void apply_vertex_buffer(VertexBufferContext *vbc,
-                           const GeomVertexArrayDataPipelineReader *reader);
+                           const GeomVertexArrayDataHandle *reader);
   virtual void release_vertex_buffer(VertexBufferContext *vbc);
   virtual void release_vertex_buffer(VertexBufferContext *vbc);
-  const unsigned char *setup_array_data(const GeomVertexArrayDataPipelineReader *data);
+  const unsigned char *setup_array_data(const GeomVertexArrayDataHandle *data);
 
 
   virtual IndexBufferContext *prepare_index_buffer(GeomPrimitive *data);
   virtual IndexBufferContext *prepare_index_buffer(GeomPrimitive *data);
   void apply_index_buffer(IndexBufferContext *ibc,
   void apply_index_buffer(IndexBufferContext *ibc,

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

@@ -218,7 +218,7 @@ update_shader_vertex_arrays(CLP(ShaderContext) *prev, GSG *gsg) {
   } else
   } else
 #endif // SUPPORT_IMMEDIATE_MODE
 #endif // SUPPORT_IMMEDIATE_MODE
   {
   {
-    const GeomVertexArrayDataPipelineReader *array_reader;
+    const GeomVertexArrayDataHandle *array_reader;
     Geom::NumericType numeric_type;
     Geom::NumericType numeric_type;
     int start, stride, num_values;
     int start, stride, num_values;
     int nvarying = _expansion->_var_spec.size();
     int nvarying = _expansion->_var_spec.size();

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

@@ -50,6 +50,7 @@
     savedContext.I savedContext.h \
     savedContext.I savedContext.h \
     shaderContext.h shaderContext.I \
     shaderContext.h shaderContext.I \
     shaderExpansion.h shaderExpansion.I \
     shaderExpansion.h shaderExpansion.I \
+    simpleLru.h simpleLru.I \
     sliderTable.I sliderTable.h \
     sliderTable.I sliderTable.h \
     texture.I texture.h \
     texture.I texture.h \
     textureContext.I textureContext.h \
     textureContext.I textureContext.h \
@@ -106,6 +107,7 @@
     savedContext.cxx \
     savedContext.cxx \
     shaderContext.cxx \
     shaderContext.cxx \
     shaderExpansion.cxx \
     shaderExpansion.cxx \
+    simpleLru.cxx \
     sliderTable.cxx \
     sliderTable.cxx \
     texture.cxx textureContext.cxx texturePool.cxx \
     texture.cxx textureContext.cxx texturePool.cxx \
     texturePoolFilter.cxx \
     texturePoolFilter.cxx \
@@ -162,6 +164,7 @@
     savedContext.I savedContext.h \
     savedContext.I savedContext.h \
     shaderContext.h shaderContext.I \
     shaderContext.h shaderContext.I \
     shaderExpansion.h shaderExpansion.I \
     shaderExpansion.h shaderExpansion.I \
+    simpleLru.h simpleLru.I \
     sliderTable.I sliderTable.h \
     sliderTable.I sliderTable.h \
     texture.I texture.h \
     texture.I texture.h \
     textureContext.I textureContext.h \
     textureContext.I textureContext.h \

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

@@ -287,8 +287,7 @@ ConfigureFn(config_gobj) {
   GeomTrifans::init_type();
   GeomTrifans::init_type();
   GeomTristrips::init_type();
   GeomTristrips::init_type();
   GeomVertexArrayData::init_type();
   GeomVertexArrayData::init_type();
-  GeomVertexArrayDataPipelineReader::init_type();
-  GeomVertexArrayDataPipelineWriter::init_type();
+  GeomVertexArrayDataHandle::init_type();
   GeomVertexArrayFormat::init_type();
   GeomVertexArrayFormat::init_type();
   GeomVertexData::init_type();
   GeomVertexData::init_type();
   GeomVertexDataPipelineReader::init_type();
   GeomVertexDataPipelineReader::init_type();

+ 4 - 0
panda/src/gobj/geom.cxx

@@ -223,6 +223,10 @@ offset_vertices(const GeomVertexData *data, int offset) {
 
 
 #ifndef NDEBUG
 #ifndef NDEBUG
     if (!prim->check_valid(data)) {
     if (!prim->check_valid(data)) {
+      gobj_cat.warning()
+        << *prim << " is invalid for " << *data << ":\n";
+      prim->write(gobj_cat.warning(false), 4);
+      
       all_is_valid = false;
       all_is_valid = false;
     }
     }
 #endif
 #endif

+ 11 - 0
panda/src/gobj/geomEnums.h

@@ -210,6 +210,17 @@ PUBLISHED:
     AT_hardware, // Hardware-accelerated animation on the graphics card.
     AT_hardware, // Hardware-accelerated animation on the graphics card.
   };
   };
 
 
+  // These are used to indicate the current residency state of vertex
+  // data, which may or may not have been temporarily evicted to
+  // satisfy memory requirements.
+  enum RamClass {
+    RC_resident,
+    RC_compressed,
+    RC_disk,
+
+    RC_end_of_list,  // list marker; do not use
+  };
+
 };
 };
 
 
 EXPCL_PANDA ostream &operator << (ostream &out, GeomEnums::NumericType numeric_type);
 EXPCL_PANDA ostream &operator << (ostream &out, GeomEnums::NumericType numeric_type);

+ 6 - 22
panda/src/gobj/geomPrimitive.I

@@ -303,18 +303,6 @@ get_index_stride() const {
   return reader.get_index_stride();
   return reader.get_index_stride();
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: GeomPrimitive::get_data
-//       Access: Public
-//  Description: A convenience function to return the actual data of
-//               the index array.
-////////////////////////////////////////////////////////////////////
-INLINE CPTA_uchar GeomPrimitive::
-get_data() const {
-  nassertr(is_indexed(), CPTA_uchar());
-  return get_vertices()->get_data();
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomPrimitive::get_ends
 //     Function: GeomPrimitive::get_ends
 //       Access: Public
 //       Access: Public
@@ -486,8 +474,7 @@ GeomPrimitivePipelineReader(const GeomPrimitive *object,
   _cdata->ref();
   _cdata->ref();
 #endif  // DO_PIPELINING
 #endif  // DO_PIPELINING
   if (!_cdata->_vertices.is_null()) {
   if (!_cdata->_vertices.is_null()) {
-    _vertices_reader =
-      new GeomVertexArrayDataPipelineReader(_cdata->_vertices.get_read_pointer(), _current_thread);
+    _vertices_reader = _cdata->_vertices.get_read_pointer()->get_handle();
   }
   }
 }
 }
 
 
@@ -518,9 +505,6 @@ operator = (const GeomPrimitivePipelineReader &) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE GeomPrimitivePipelineReader::
 INLINE GeomPrimitivePipelineReader::
 ~GeomPrimitivePipelineReader() {
 ~GeomPrimitivePipelineReader() {
-  if (_vertices_reader != (GeomVertexArrayDataPipelineReader *)NULL) {
-    delete _vertices_reader;
-  }
 #ifdef _DEBUG
 #ifdef _DEBUG
   nassertv(_object->test_ref_count_nonzero());
   nassertv(_object->test_ref_count_nonzero());
 #endif // _DEBUG
 #endif // _DEBUG
@@ -671,19 +655,19 @@ get_index_stride() const {
 //       Access: Public
 //       Access: Public
 //  Description: 
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE const GeomVertexArrayDataPipelineReader *GeomPrimitivePipelineReader::
+INLINE const GeomVertexArrayDataHandle *GeomPrimitivePipelineReader::
 get_vertices_reader() const {
 get_vertices_reader() const {
   return _vertices_reader;
   return _vertices_reader;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GeomPrimitivePipelineReader::get_data
+//     Function: GeomPrimitivePipelineReader::get_pointer
 //       Access: Public
 //       Access: Public
 //  Description: 
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE CPTA_uchar GeomPrimitivePipelineReader::
-get_data() const {
-  return _vertices_reader->get_data();
+INLINE const unsigned char *GeomPrimitivePipelineReader::
+get_pointer() const {
+  return _vertices_reader->get_pointer();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 2 - 1
panda/src/gobj/geomPrimitive.cxx

@@ -1314,7 +1314,8 @@ calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point,
       }
       }
     } else {
     } else {
       for (int i = 0; i < num_vertices; ++i) {
       for (int i = 0; i < num_vertices; ++i) {
-        reader.set_row(index.get_data1i());
+        int ii = index.get_data1i();
+        reader.set_row(ii);
         const LVecBase3f &vertex = reader.get_data3f();
         const LVecBase3f &vertex = reader.get_data3f();
         
         
         if (found_any) {
         if (found_any) {

+ 3 - 4
panda/src/gobj/geomPrimitive.h

@@ -158,7 +158,6 @@ public:
   void set_nonindexed_vertices(int first_vertex, int num_vertices);
   void set_nonindexed_vertices(int first_vertex, int num_vertices);
 
 
   INLINE int get_index_stride() const;
   INLINE int get_index_stride() const;
-  INLINE CPTA_uchar get_data() const;
 
 
   INLINE CPTA_int get_ends() const;
   INLINE CPTA_int get_ends() const;
   PTA_int modify_ends();
   PTA_int modify_ends();
@@ -346,8 +345,8 @@ public:
   INLINE UpdateSeq get_modified() const;
   INLINE UpdateSeq get_modified() const;
   bool check_valid(const GeomVertexDataPipelineReader *data_reader) const;
   bool check_valid(const GeomVertexDataPipelineReader *data_reader) const;
   INLINE int get_index_stride() const;
   INLINE int get_index_stride() const;
-  INLINE const GeomVertexArrayDataPipelineReader *get_vertices_reader() const;
-  INLINE CPTA_uchar get_data() const;
+  INLINE const GeomVertexArrayDataHandle *get_vertices_reader() const;
+  INLINE const unsigned char *get_pointer() const;
   INLINE CPTA_int get_ends() const;
   INLINE CPTA_int get_ends() const;
   INLINE CPT(GeomVertexArrayData) get_mins() const;
   INLINE CPT(GeomVertexArrayData) get_mins() const;
   INLINE CPT(GeomVertexArrayData) get_maxs() const;
   INLINE CPT(GeomVertexArrayData) get_maxs() const;
@@ -357,7 +356,7 @@ private:
   Thread *_current_thread;
   Thread *_current_thread;
   const GeomPrimitive::CData *_cdata;
   const GeomPrimitive::CData *_cdata;
 
 
-  GeomVertexArrayDataPipelineReader *_vertices_reader;
+  CPT(GeomVertexArrayDataHandle) _vertices_reader;
 
 
 public:
 public:
   static TypeHandle get_class_type() {
   static TypeHandle get_class_type() {

+ 188 - 176
panda/src/gobj/geomVertexArrayData.I

@@ -62,8 +62,7 @@ has_column(const InternalName *name) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE int GeomVertexArrayData::
 INLINE int GeomVertexArrayData::
 get_num_rows() const {
 get_num_rows() const {
-  GeomVertexArrayDataPipelineReader reader(this, Thread::get_current_thread());
-  return reader.get_num_rows();
+  return get_handle()->get_num_rows();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -90,8 +89,7 @@ get_num_rows() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool GeomVertexArrayData::
 INLINE bool GeomVertexArrayData::
 set_num_rows(int n) {
 set_num_rows(int n) {
-  GeomVertexArrayDataPipelineWriter writer(this, true, Thread::get_current_thread());
-  return writer.set_num_rows(n);
+  return modify_handle()->set_num_rows(n);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -109,8 +107,7 @@ set_num_rows(int n) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool GeomVertexArrayData::
 INLINE bool GeomVertexArrayData::
 unclean_set_num_rows(int n) {
 unclean_set_num_rows(int n) {
-  GeomVertexArrayDataPipelineWriter writer(this, true, Thread::get_current_thread());
-  return writer.unclean_set_num_rows(n);
+  return modify_handle()->unclean_set_num_rows(n);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -121,7 +118,7 @@ unclean_set_num_rows(int n) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void GeomVertexArrayData::
 INLINE void GeomVertexArrayData::
 clear_rows() {
 clear_rows() {
-  set_data(PTA_uchar(GeomVertexArrayData::get_class_type()));
+  return modify_handle()->clear_rows();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -132,7 +129,7 @@ clear_rows() {
 INLINE int GeomVertexArrayData::
 INLINE int GeomVertexArrayData::
 get_data_size_bytes() const {
 get_data_size_bytes() const {
   CDReader cdata(_cycler);
   CDReader cdata(_cycler);
-  return cdata->_data.size();
+  return cdata->_data_full_size;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -149,49 +146,71 @@ get_modified() const {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GeomVertexArrayData::get_data
+//     Function: GeomVertexArrayData::get_handle
 //       Access: Published
 //       Access: Published
-//  Description: Returns a const pointer to the actual vertex data,
-//               for application code to directly examine (but not
-//               modify).
+//  Description: Returns an object that can be used to read the actual
+//               data bytes stored in the array.  Calling this method
+//               locks the data, and will block any other threads
+//               attempting to read or write the data, until the
+//               returned object destructs.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE CPTA_uchar GeomVertexArrayData::
-get_data() const {
-  CDReader cdata(_cycler);
-  return cdata->_data;
+INLINE CPT(GeomVertexArrayDataHandle) GeomVertexArrayData::
+get_handle(Thread *current_thread) const {
+  return new GeomVertexArrayDataHandle(this, current_thread, 
+                                       _cycler.read_unlocked(current_thread),
+                                       false);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GeomVertexArrayData::modify_data
+//     Function: GeomVertexArrayData::modify_handle
 //       Access: Published
 //       Access: Published
-//  Description: Returns a modifiable pointer to the actual vertex
-//               array, so that application code may directly
-//               manipulate it.  Use with caution.
-//
-//               Don't call this in a downstream thread unless you
-//               don't mind it blowing away other changes you might
-//               have recently made in an upstream thread.
+//  Description: Returns an object that can be used to read or write
+//               the actual data bytes stored in the array.  Calling
+//               this method locks the data, and will block any other
+//               threads attempting to read or write the data, until
+//               the returned object destructs.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE PTA_uchar GeomVertexArrayData::
-modify_data() {
-  GeomVertexArrayDataPipelineWriter writer(this, true, Thread::get_current_thread());
-  return writer.modify_data();
+INLINE PT(GeomVertexArrayDataHandle) GeomVertexArrayData::
+modify_handle(Thread *current_thread) {
+  return new GeomVertexArrayDataHandle(this, current_thread, 
+                                       _cycler.write_upstream(true, current_thread),
+                                       true);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GeomVertexArrayData::set_data
+//     Function: GeomVertexArrayData::get_ram_class
 //       Access: Published
 //       Access: Published
-//  Description: Replaces the vertex data array with a completely new
-//               array.
-//
-//               Don't call this in a downstream thread unless you
-//               don't mind it blowing away other changes you might
-//               have recently made in an upstream thread.
+//  Description: Returns the current ram class of the array.  If this
+//               is other than RC_resident, the array data is not
+//               resident in memory.
+////////////////////////////////////////////////////////////////////
+INLINE GeomVertexArrayData::RamClass GeomVertexArrayData::
+get_ram_class() const {
+  return _ram_class;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomVertexArrayData::get_global_lru
+//       Access: Published, Static
+//  Description: Returns a pointer to the global LRU object that
+//               manages the GeomVertexArrayData's with the indicated
+//               RamClass.
+////////////////////////////////////////////////////////////////////
+INLINE SimpleLru *GeomVertexArrayData::
+get_global_lru(RamClass rclass) {
+  nassertr(rclass >= 0 && rclass < RC_end_of_list, NULL);
+  return &_global_lru[rclass];
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomVertexArrayData::set_ram_class
+//       Access: Private
+//  Description: Puts the data in a new ram class.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void GeomVertexArrayData::
 INLINE void GeomVertexArrayData::
-set_data(CPTA_uchar array) {
-  GeomVertexArrayDataPipelineWriter writer(this, true, Thread::get_current_thread());
-  writer.set_data(array);
+set_ram_class(RamClass rclass) {
+  _ram_class = rclass;
+  mark_used_lru(&_global_lru[rclass]);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -202,9 +221,9 @@ set_data(CPTA_uchar array) {
 INLINE GeomVertexArrayData::CData::
 INLINE GeomVertexArrayData::CData::
 CData() :
 CData() :
   _usage_hint(UH_unspecified),
   _usage_hint(UH_unspecified),
-  _data(GeomVertexArrayData::get_class_type())
+  _data(GeomVertexArrayData::get_class_type()),
+  _data_full_size(0)
 {
 {
-  _data.node_ref();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -215,24 +234,41 @@ CData() :
 INLINE GeomVertexArrayData::CData::
 INLINE GeomVertexArrayData::CData::
 CData(const GeomVertexArrayData::CData &copy) :
 CData(const GeomVertexArrayData::CData &copy) :
   _usage_hint(copy._usage_hint),
   _usage_hint(copy._usage_hint),
-  _data(copy._data),
+  _data(GeomVertexArrayData::get_class_type()),
+  _data_full_size(copy._data_full_size),
   _modified(copy._modified)
   _modified(copy._modified)
 {
 {
-  _data.node_ref();
+  _data.v() = copy._data.v();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GeomVertexArrayDataPipelineBase::Constructor
+//     Function: GeomVertexArrayData::CData::Copy Assignment
 //       Access: Public
 //       Access: Public
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE GeomVertexArrayDataPipelineBase::
-GeomVertexArrayDataPipelineBase(GeomVertexArrayData *object, 
-                                Thread *current_thread,
-                                GeomVertexArrayData::CData *cdata) :
-  _object(object),
+INLINE void GeomVertexArrayData::CData::
+operator = (const GeomVertexArrayData::CData &copy) {
+  _usage_hint = copy._usage_hint;
+  _modified = copy._modified;
+  _data.v() = copy._data.v();
+  _data_full_size = copy._data_full_size;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomVertexArrayDataHandle::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE GeomVertexArrayDataHandle::
+GeomVertexArrayDataHandle(const GeomVertexArrayData *object, 
+                          Thread *current_thread,
+                          const GeomVertexArrayData::CData *cdata,
+                          bool writable) :
+  _holder(((GeomVertexArrayData::CData *)cdata)->_rw_lock),
+  _object((GeomVertexArrayData *)object),
   _current_thread(current_thread),
   _current_thread(current_thread),
-  _cdata(cdata)
+  _cdata((GeomVertexArrayData::CData *)cdata),
+  _writable(writable)
 {
 {
 #ifdef _DEBUG
 #ifdef _DEBUG
   nassertv(_object->test_ref_count_nonzero());
   nassertv(_object->test_ref_count_nonzero());
@@ -243,16 +279,42 @@ GeomVertexArrayDataPipelineBase(GeomVertexArrayData *object,
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GeomVertexArrayDataPipelineBase::Destructor
+//     Function: GeomVertexArrayDataHandle::Copy Constructor
+//       Access: Private
+//  Description: Don't attempt to copy these objects.
+////////////////////////////////////////////////////////////////////
+INLINE GeomVertexArrayDataHandle::
+GeomVertexArrayDataHandle(const GeomVertexArrayDataHandle &copy) :
+  _holder(copy._cdata->_rw_lock)
+{
+  nassertv(false);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomVertexArrayDataHandle::Copy Assignment Operator
+//       Access: Private
+//  Description: Don't attempt to copy these objects.
+////////////////////////////////////////////////////////////////////
+INLINE void GeomVertexArrayDataHandle::
+operator = (const GeomVertexArrayDataHandle &) {
+  nassertv(false);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomVertexArrayDataHandle::Destructor
 //       Access: Public
 //       Access: Public
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE GeomVertexArrayDataPipelineBase::
-~GeomVertexArrayDataPipelineBase() {
+INLINE GeomVertexArrayDataHandle::
+~GeomVertexArrayDataHandle() {
 #ifdef _DEBUG
 #ifdef _DEBUG
   nassertv(_object->test_ref_count_nonzero());
   nassertv(_object->test_ref_count_nonzero());
 #endif // _DEBUG
 #endif // _DEBUG
 
 
+  if (_writable) {
+    _object->_cycler.release_write(_cdata);
+  }
+
 #ifdef DO_PIPELINING
 #ifdef DO_PIPELINING
   unref_delete((CycleData *)_cdata);
   unref_delete((CycleData *)_cdata);
 #endif  // DO_PIPELINING
 #endif  // DO_PIPELINING
@@ -264,184 +326,134 @@ INLINE GeomVertexArrayDataPipelineBase::
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GeomVertexArrayDataPipelineBase::get_current_thread
+//     Function: GeomVertexArrayDataHandle::get_current_thread
 //       Access: Public
 //       Access: Public
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE Thread *GeomVertexArrayDataPipelineBase::
+INLINE Thread *GeomVertexArrayDataHandle::
 get_current_thread() const {
 get_current_thread() const {
   return _current_thread;
   return _current_thread;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GeomVertexArrayDataPipelineBase::get_array_format
+//     Function: GeomVertexArrayDataHandle::get_object
 //       Access: Public
 //       Access: Public
-//  Description: 
-////////////////////////////////////////////////////////////////////
-INLINE const GeomVertexArrayFormat *GeomVertexArrayDataPipelineBase::
-get_array_format() const {
-  return _object->_array_format;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GeomVertexArrayDataPipelineBase::get_usage_hint
-//       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE GeomVertexArrayDataPipelineBase::UsageHint GeomVertexArrayDataPipelineBase::
-get_usage_hint() const {
-  return _cdata->_usage_hint;
+INLINE const GeomVertexArrayData *GeomVertexArrayDataHandle::
+get_object() const {
+  return _object;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GeomVertexArrayDataPipelineBase::get_data
+//     Function: GeomVertexArrayDataHandle::get_object
 //       Access: Public
 //       Access: Public
-//  Description: 
-////////////////////////////////////////////////////////////////////
-INLINE CPTA_uchar GeomVertexArrayDataPipelineBase::
-get_data() const {
-  return _cdata->_data;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GeomVertexArrayDataPipelineBase::get_num_rows
-//       Access: Published
-//  Description: 
-////////////////////////////////////////////////////////////////////
-INLINE int GeomVertexArrayDataPipelineBase::
-get_num_rows() const {
-  return get_data_size_bytes() / _object->_array_format->get_stride();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GeomVertexArrayDataPipelineBase::get_data_size_bytes
-//       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE int GeomVertexArrayDataPipelineBase::
-get_data_size_bytes() const {
-  return _cdata->_data.size();
+INLINE GeomVertexArrayData *GeomVertexArrayDataHandle::
+get_object() {
+  return _object;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GeomVertexArrayDataPipelineBase::get_modified
+//     Function: GeomVertexArrayDataHandle::get_pointer
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description: Returns a pointer to the beginning of the actual data
+//               stream.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE UpdateSeq GeomVertexArrayDataPipelineBase::
-get_modified() const {
-  return _cdata->_modified;
+INLINE const unsigned char *GeomVertexArrayDataHandle::
+get_pointer() const {
+  check_resident();
+  return _cdata->_data.p();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GeomVertexArrayDataPipelineReader::Constructor
+//     Function: GeomVertexArrayDataHandle::get_pointer
 //       Access: Public
 //       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE GeomVertexArrayDataPipelineReader::
-GeomVertexArrayDataPipelineReader(const GeomVertexArrayData *object, 
-                                  Thread *current_thread) :
-  GeomVertexArrayDataPipelineBase((GeomVertexArrayData *)object,
-                                  current_thread,
-                                  (GeomVertexArrayData::CData *)object->_cycler.read_unlocked(current_thread))
-{
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GeomVertexArrayDataPipelineReader::Copy Constructor
-//       Access: Private
-//  Description: Don't attempt to copy these objects.
-////////////////////////////////////////////////////////////////////
-INLINE GeomVertexArrayDataPipelineReader::
-GeomVertexArrayDataPipelineReader(const GeomVertexArrayDataPipelineReader &copy) :
-  GeomVertexArrayDataPipelineBase(copy)
-{
-  nassertv(false);
-}
-
+//  Description: Returns a pointer to the beginning of the actual data
+//               stream.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GeomVertexArrayDataPipelineReader::Copy Assignment Operator
-//       Access: Private
-//  Description: Don't attempt to copy these objects.
-////////////////////////////////////////////////////////////////////
-INLINE void GeomVertexArrayDataPipelineReader::
-operator = (const GeomVertexArrayDataPipelineReader &) {
-  nassertv(false);
+INLINE unsigned char *GeomVertexArrayDataHandle::
+get_pointer() {
+  nassertr(_writable, NULL);
+  check_resident();
+  return _cdata->_data.p();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GeomVertexArrayDataPipelineReader::Destructor
+//     Function: GeomVertexArrayDataHandle::get_array_format
 //       Access: Public
 //       Access: Public
-//  Description:
+//  Description: 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE GeomVertexArrayDataPipelineReader::
-~GeomVertexArrayDataPipelineReader() {
-  //  _object->_cycler.release_read(_cdata);
+INLINE const GeomVertexArrayFormat *GeomVertexArrayDataHandle::
+get_array_format() const {
+  return _object->_array_format;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GeomVertexArrayDataPipelineReader::get_object
+//     Function: GeomVertexArrayDataHandle::get_usage_hint
 //       Access: Public
 //       Access: Public
-//  Description:
+//  Description: 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE const GeomVertexArrayData *GeomVertexArrayDataPipelineReader::
-get_object() const {
-  return _object;
+INLINE GeomVertexArrayDataHandle::UsageHint GeomVertexArrayDataHandle::
+get_usage_hint() const {
+  return _cdata->_usage_hint;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GeomVertexArrayDataPipelineWriter::Constructor
-//       Access: Public
-//  Description:
+//     Function: GeomVertexArrayDataHandle::get_num_rows
+//       Access: Published
+//  Description: 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE GeomVertexArrayDataPipelineWriter::
-GeomVertexArrayDataPipelineWriter(GeomVertexArrayData *object, bool force_to_0,
-                                  Thread *current_thread) :
-  GeomVertexArrayDataPipelineBase(object, current_thread,
-                                  object->_cycler.write_upstream(force_to_0, current_thread))
-{
+INLINE int GeomVertexArrayDataHandle::
+get_num_rows() const {
+  return get_data_size_bytes() / _object->_array_format->get_stride();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GeomVertexArrayDataPipelineWriter::Copy Constructor
-//       Access: Private
-//  Description: Don't attempt to copy these objects.
+//     Function: GeomVertexArrayDataHandle::clear_rows
+//       Access: Published
+//  Description: 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE GeomVertexArrayDataPipelineWriter::
-GeomVertexArrayDataPipelineWriter(const GeomVertexArrayDataPipelineWriter &copy) :
-  GeomVertexArrayDataPipelineBase(copy) 
-{
-  nassertv(false);
+INLINE void GeomVertexArrayDataHandle::
+clear_rows() {
+  set_num_rows(0);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GeomVertexArrayDataPipelineWriter::Copy Assignment Operator
-//       Access: Private
-//  Description: Don't attempt to copy these objects.
+//     Function: GeomVertexArrayDataHandle::get_data_size_bytes
+//       Access: Published
+//  Description: 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE void GeomVertexArrayDataPipelineWriter::
-operator = (const GeomVertexArrayDataPipelineWriter &) {
-  nassertv(false);
+INLINE int GeomVertexArrayDataHandle::
+get_data_size_bytes() const {
+  return _cdata->_data_full_size;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GeomVertexArrayDataPipelineWriter::Destructor
-//       Access: Public
-//  Description:
+//     Function: GeomVertexArrayDataHandle::get_modified
+//       Access: Published
+//  Description: 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE GeomVertexArrayDataPipelineWriter::
-~GeomVertexArrayDataPipelineWriter() {
-  _object->_cycler.release_write(_cdata);
+INLINE UpdateSeq GeomVertexArrayDataHandle::
+get_modified() const {
+  return _cdata->_modified;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GeomVertexArrayDataPipelineWriter::get_object
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE GeomVertexArrayData *GeomVertexArrayDataPipelineWriter::
-get_object() const {
-  return _object;
+//     Function: GeomVertexArrayDataHandle::check_resident
+//       Access: Published
+//  Description: Forces the vertex data into system RAM, if it is not
+//               already there; also, marks it recently-used.
+////////////////////////////////////////////////////////////////////
+void GeomVertexArrayDataHandle::
+check_resident() const {
+  if (_object->get_ram_class() != RC_resident) {
+    _object->make_resident();
+  } else {
+    _object->mark_used_lru();
+  }
+  nassertv(_cdata->_data.size() == _cdata->_data_full_size);
 }
 }
 
 
 INLINE ostream &
 INLINE ostream &

+ 297 - 58
panda/src/gobj/geomVertexArrayData.cxx

@@ -23,11 +23,55 @@
 #include "bamReader.h"
 #include "bamReader.h"
 #include "bamWriter.h"
 #include "bamWriter.h"
 #include "pset.h"
 #include "pset.h"
+#include "config_gobj.h"
+#include "pStatTimer.h"
+
+#ifdef HAVE_ZLIB
+#include <zlib.h>
+#endif
+
+ConfigVariableInt max_ram_vertex_data
+("max-ram-vertex-data", 0,
+ PRC_DESC("Specifies the maximum number of bytes of all vertex data "
+          "that is allowed to remain resident in system RAM at one time. "
+          "If more than this number of bytes of vertices are created, "
+          "the least-recently-used ones will be temporarily compressed in "
+          "system RAM until they are needed.  Set it to 0 for no limit."));
+
+ConfigVariableInt max_compressed_vertex_data
+("max-compressed-vertex-data", 0,
+ PRC_DESC("Specifies the maximum number of bytes of all vertex data "
+          "that is allowed to remain compressed in system RAM at one time. "
+          "If more than this number of bytes of vertices are created, "
+          "the least-recently-used ones will be temporarily flushed to "
+          "disk until they are needed.  Set it to 0 for no limit."));
+
+// We make this a static constant rather than a dynamic variable,
+// since we can't tolerate this value changing at runtime.
+static const size_t min_vertex_data_compress_size = 
+  ConfigVariableInt
+  ("min-vertex-data-compress-size", 64,
+   PRC_DESC("This is the minimum number of bytes that we deem worthy of "
+            "passing through zlib to compress, when a vertex buffer is "
+            "evicted from resident state and compressed for long-term "
+            "storage.  Buffers smaller than this are assumed to be likely to "
+            "have minimal compression gains (or even end up larger)."));
+
+
+
+SimpleLru GeomVertexArrayData::_global_lru[RC_end_of_list] = {
+  SimpleLru(max_ram_vertex_data),
+  SimpleLru(max_compressed_vertex_data),
+  SimpleLru(0)
+};
+
+PStatCollector GeomVertexArrayData::_vdata_compress_pcollector("*:Vertex Data:Compress");
+PStatCollector GeomVertexArrayData::_vdata_decompress_pcollector("*:Vertex Data:Decompress");
+
 
 
 TypeHandle GeomVertexArrayData::_type_handle;
 TypeHandle GeomVertexArrayData::_type_handle;
 TypeHandle GeomVertexArrayData::CData::_type_handle;
 TypeHandle GeomVertexArrayData::CData::_type_handle;
-TypeHandle GeomVertexArrayDataPipelineReader::_type_handle;
-TypeHandle GeomVertexArrayDataPipelineWriter::_type_handle;
+TypeHandle GeomVertexArrayDataHandle::_type_handle;
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexArrayData::Default Constructor
 //     Function: GeomVertexArrayData::Default Constructor
@@ -36,8 +80,11 @@ TypeHandle GeomVertexArrayDataPipelineWriter::_type_handle;
 //               reading from the bam file.
 //               reading from the bam file.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 GeomVertexArrayData::
 GeomVertexArrayData::
-GeomVertexArrayData() {
+GeomVertexArrayData() : SimpleLruPage(0) {
   _endian_reversed = false;
   _endian_reversed = false;
+  _ram_class = RC_resident;
+
+  // Can't put it in the LRU until it has been read in and made valid.
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -47,6 +94,7 @@ GeomVertexArrayData() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 PT(CopyOnWriteObject) GeomVertexArrayData::
 PT(CopyOnWriteObject) GeomVertexArrayData::
 make_cow_copy() {
 make_cow_copy() {
+  make_resident();
   return new GeomVertexArrayData(*this);
   return new GeomVertexArrayData(*this);
 }
 }
 
 
@@ -58,6 +106,7 @@ make_cow_copy() {
 GeomVertexArrayData::
 GeomVertexArrayData::
 GeomVertexArrayData(const GeomVertexArrayFormat *array_format,
 GeomVertexArrayData(const GeomVertexArrayFormat *array_format,
                     GeomVertexArrayData::UsageHint usage_hint) :
                     GeomVertexArrayData::UsageHint usage_hint) :
+  SimpleLruPage(0),
   _array_format(array_format)
   _array_format(array_format)
 {
 {
   OPEN_ITERATE_ALL_STAGES(_cycler) {
   OPEN_ITERATE_ALL_STAGES(_cycler) {
@@ -67,6 +116,10 @@ GeomVertexArrayData(const GeomVertexArrayFormat *array_format,
   CLOSE_ITERATE_ALL_STAGES(_cycler);
   CLOSE_ITERATE_ALL_STAGES(_cycler);
 
 
   _endian_reversed = false;
   _endian_reversed = false;
+
+  _ram_class = RC_resident;
+  mark_used_lru(&_global_lru[RC_resident]);
+
   nassertv(_array_format->is_registered());
   nassertv(_array_format->is_registered());
 }
 }
   
   
@@ -78,10 +131,15 @@ GeomVertexArrayData(const GeomVertexArrayFormat *array_format,
 GeomVertexArrayData::
 GeomVertexArrayData::
 GeomVertexArrayData(const GeomVertexArrayData &copy) :
 GeomVertexArrayData(const GeomVertexArrayData &copy) :
   CopyOnWriteObject(copy),
   CopyOnWriteObject(copy),
+  SimpleLruPage(copy),
   _array_format(copy._array_format),
   _array_format(copy._array_format),
   _cycler(copy._cycler)
   _cycler(copy._cycler)
 {
 {
   _endian_reversed = false;
   _endian_reversed = false;
+
+  _ram_class = copy._ram_class;
+  mark_used_lru(&_global_lru[_ram_class]);
+
   nassertv(_array_format->is_registered());
   nassertv(_array_format->is_registered());
 }
 }
 
 
@@ -96,6 +154,7 @@ GeomVertexArrayData(const GeomVertexArrayData &copy) :
 void GeomVertexArrayData::
 void GeomVertexArrayData::
 operator = (const GeomVertexArrayData &copy) {
 operator = (const GeomVertexArrayData &copy) {
   CopyOnWriteObject::operator = (copy);
   CopyOnWriteObject::operator = (copy);
+  SimpleLruPage::operator = (copy);
   _array_format = copy._array_format;
   _array_format = copy._array_format;
   _cycler = copy._cycler;
   _cycler = copy._cycler;
 
 
@@ -272,6 +331,155 @@ release_all() {
   return num_freed;
   return num_freed;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GeomVertexArrayData::lru_epoch
+//       Access: Published, Static
+//  Description: Marks that an epoch has passed in each LRU.  Asks the
+//               LRU's to consider whether they should perform
+//               evictions.
+////////////////////////////////////////////////////////////////////
+void GeomVertexArrayData::
+lru_epoch() {
+  for (int i = 0; i < (int)RC_end_of_list; ++i) {
+    get_global_lru((RamClass)i)->consider_evict();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomVertexArrayData::make_resident
+//       Access: Published
+//  Description: Moves the vertex data to fully resident status by
+//               expanding it or reading it from disk as necessary.
+////////////////////////////////////////////////////////////////////
+void GeomVertexArrayData::
+make_resident() {
+  // TODO: make this work with pipelining properly.
+  if (_ram_class == RC_compressed) {
+    CDWriter cdata(_cycler, true);
+#ifdef HAVE_ZLIB
+    if (cdata->_data_full_size > min_vertex_data_compress_size) {
+      PStatTimer timer(_vdata_decompress_pcollector);
+
+      if (gobj_cat.is_debug()) {
+        gobj_cat.debug()
+          << "Expanding " << *this << " from " << cdata->_data.size()
+          << " to " << cdata->_data_full_size << "\n";
+      }
+      PTA_uchar new_data = PTA_uchar::empty_array(cdata->_data_full_size, get_class_type());
+      uLongf dest_len = cdata->_data_full_size;
+      int result = uncompress(new_data.p(), &dest_len,
+                              cdata->_data.p(), cdata->_data.size());
+      if (result != Z_OK) {
+        gobj_cat.error()
+          << "Couldn't expand: zlib error " << result << "\n";
+      }
+      nassertv(dest_len == new_data.size());
+      cdata->_data = new_data;
+    }
+#endif
+    set_lru_size(cdata->_data.size());
+  }
+  
+  set_ram_class(RC_resident);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomVertexArrayData::make_compressed
+//       Access: Published
+//  Description: Moves the vertex data to compressed status by
+//               compressing it or reading it from disk as necessary.
+////////////////////////////////////////////////////////////////////
+void GeomVertexArrayData::
+make_compressed() {
+  // TODO: make this work with pipelining properly.
+  if (_ram_class == RC_resident) {
+
+    CDWriter cdata(_cycler, true);
+#ifdef HAVE_ZLIB
+    if (cdata->_data_full_size > min_vertex_data_compress_size) {
+      PStatTimer timer(_vdata_compress_pcollector);
+
+      // According to the zlib manual, we need to provide this much
+      // buffer to the compress algorithm: 0.1% bigger plus twelve
+      // bytes.
+      uLongf buffer_size = cdata->_data_full_size + ((cdata->_data_full_size + 999) / 1000) + 12;
+      Bytef *buffer = new Bytef[buffer_size];
+
+      int result = compress(buffer, &buffer_size,
+                            cdata->_data.p(), cdata->_data_full_size);
+      if (result != Z_OK) {
+        gobj_cat.error()
+          << "Couldn't compress: zlib error " << result << "\n";
+      }
+    
+      PTA_uchar new_data = PTA_uchar::empty_array(buffer_size, get_class_type());
+      memcpy(new_data.p(), buffer, buffer_size);
+      delete[] buffer;
+
+      cdata->_data = new_data;
+      if (gobj_cat.is_debug()) {
+        gobj_cat.debug()
+          << "Compressed " << *this << " from " << cdata->_data_full_size
+          << " to " << cdata->_data.size() << "\n";
+      }
+    }
+#endif
+    set_ram_class(RC_compressed);
+    set_lru_size(cdata->_data.size());
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomVertexArrayData::make_disk
+//       Access: Published
+//  Description: Moves the vertex data to disk status by
+//               writing it to disk as necessary.
+////////////////////////////////////////////////////////////////////
+void GeomVertexArrayData::
+make_disk() {
+  // TODO: make this work with pipelining properly.
+  if (_ram_class == RC_compressed) {
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomVertexArrayData::evict_lru
+//       Access: Public, Virtual
+//  Description: Evicts the page from the LRU.  Called internally when
+//               the LRU determines that it is full.  May also be
+//               called externally when necessary to explicitly evict
+//               the page.
+//
+//               It is legal for this method to either evict the page
+//               as requested, do nothing (in which case the eviction
+//               will be requested again at the next epoch), or
+//               requeue itself on the tail of the queue (in which
+//               case the eviction will be requested again much
+//               later).
+////////////////////////////////////////////////////////////////////
+void GeomVertexArrayData::
+evict_lru() {
+  nassertv(get_lru() == get_global_lru(_ram_class));
+
+  switch (_ram_class) {
+  case RC_resident:
+    make_compressed();
+    break;
+
+  case RC_compressed:
+    make_disk();
+    break;
+
+  case RC_disk:
+    gobj_cat.warning()
+      << "Cannot evict array data from disk.\n";
+    break;
+
+  case RC_end_of_list:
+    break;
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexArrayData::clear_prepared
 //     Function: GeomVertexArrayData::clear_prepared
 //       Access: Private
 //       Access: Private
@@ -359,6 +567,7 @@ register_with_read_factory() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GeomVertexArrayData::
 void GeomVertexArrayData::
 write_datagram(BamWriter *manager, Datagram &dg) {
 write_datagram(BamWriter *manager, Datagram &dg) {
+  make_resident();
   CopyOnWriteObject::write_datagram(manager, dg);
   CopyOnWriteObject::write_datagram(manager, dg);
 
 
   manager->write_pointer(dg, _array_format);
   manager->write_pointer(dg, _array_format);
@@ -465,6 +674,8 @@ finalize(BamReader *manager) {
 
 
   // Now is also the time to node_ref the data.
   // Now is also the time to node_ref the data.
   cdata->_data.node_ref();
   cdata->_data.node_ref();
+
+  set_ram_class(RC_resident);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -510,7 +721,6 @@ fillin(DatagramIterator &scan, BamReader *manager) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 GeomVertexArrayData::CData::
 GeomVertexArrayData::CData::
 ~CData() {
 ~CData() {
-  _data.node_unref();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -548,47 +758,41 @@ fillin(DatagramIterator &scan, BamReader *manager, void *extra_data) {
   GeomVertexArrayData *array_data = (GeomVertexArrayData *)extra_data;
   GeomVertexArrayData *array_data = (GeomVertexArrayData *)extra_data;
   _usage_hint = (UsageHint)scan.get_uint8();
   _usage_hint = (UsageHint)scan.get_uint8();
   READ_PTA(manager, scan, array_data->read_raw_data, _data);
   READ_PTA(manager, scan, array_data->read_raw_data, _data);
+  _data_full_size = _data.size();
+  array_data->set_lru_size(_data_full_size);
 
 
   _modified = Geom::get_next_modified();
   _modified = Geom::get_next_modified();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GeomVertexArrayDataPipelineWriter::set_num_rows
+//     Function: GeomVertexArrayDataHandle::set_num_rows
 //       Access: Public
 //       Access: Public
 //  Description: 
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-bool GeomVertexArrayDataPipelineWriter::
+bool GeomVertexArrayDataHandle::
 set_num_rows(int n) {
 set_num_rows(int n) {
+  nassertr(_writable, false);
+  check_resident();
+
   int stride = _object->_array_format->get_stride();
   int stride = _object->_array_format->get_stride();
   int delta = n - (_cdata->_data.size() / stride);
   int delta = n - (_cdata->_data.size() / stride);
   
   
   if (delta != 0) {
   if (delta != 0) {
-    if (_cdata->_data.get_node_ref_count() > 1) {
-      // Copy-on-write: the data is already reffed somewhere else,
-      // so we're just going to make a copy.
-      PTA_uchar new_data(GeomVertexArrayData::get_class_type());
-      new_data.reserve(n * stride);
-      new_data.insert(new_data.end(), n * stride, 0);
-      memcpy(new_data, _cdata->_data, 
-             min((size_t)(n * stride), _cdata->_data.size()));
-      _cdata->_data.node_unref();
-      _cdata->_data = new_data;
-      _cdata->_data.node_ref();
+    if (delta > 0) {
+      _cdata->_data.insert(_cdata->_data.end(), delta * stride, 0);
       
       
     } else {
     } else {
-      // We've got the only reference to the data, so we can change
-      // it directly.
-      if (delta > 0) {
-        _cdata->_data.insert(_cdata->_data.end(), delta * stride, 0);
-        
-      } else {
-        _cdata->_data.erase(_cdata->_data.begin() + n * stride, 
-                           _cdata->_data.end());
-      }
+      _cdata->_data.erase(_cdata->_data.begin() + n * stride, 
+                          _cdata->_data.end());
     }
     }
 
 
     _cdata->_modified = Geom::get_next_modified();
     _cdata->_modified = Geom::get_next_modified();
+    _cdata->_data_full_size = _cdata->_data.size();
 
 
+    if (get_current_thread()->get_pipeline_stage() == 0) {
+      _object->set_ram_class(RC_resident);
+      _object->set_lru_size(_cdata->_data_full_size);
+    }
     return true;
     return true;
   }
   }
   
   
@@ -596,24 +800,30 @@ set_num_rows(int n) {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GeomVertexArrayDataPipelineWriter::unclean_set_num_rows
+//     Function: GeomVertexArrayDataHandle::unclean_set_num_rows
 //       Access: Public
 //       Access: Public
 //  Description: 
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-bool GeomVertexArrayDataPipelineWriter::
+bool GeomVertexArrayDataHandle::
 unclean_set_num_rows(int n) {
 unclean_set_num_rows(int n) {
+  nassertr(_writable, false);
+  check_resident();
+
   int stride = _object->_array_format->get_stride();
   int stride = _object->_array_format->get_stride();
   int delta = n - (_cdata->_data.size() / stride);
   int delta = n - (_cdata->_data.size() / stride);
   
   
   if (delta != 0) {
   if (delta != 0) {
     // Just make a new array.  No reason to keep the old one around.
     // Just make a new array.  No reason to keep the old one around.
-    PTA_uchar new_data = PTA_uchar::empty_array(n * stride, GeomVertexArrayData::get_class_type());
+    //_cdata->_data = GeomVertexArrayData::Data('\0', n * stride, GeomVertexArrayData::get_class_type());
+    _cdata->_data = PTA_uchar::empty_array(n * stride, GeomVertexArrayData::get_class_type());
 
 
-    _cdata->_data.node_unref();
-    _cdata->_data = new_data;
-    _cdata->_data.node_ref();
     _cdata->_modified = Geom::get_next_modified();
     _cdata->_modified = Geom::get_next_modified();
+    _cdata->_data_full_size = _cdata->_data.size();
 
 
+    if (get_current_thread()->get_pipeline_stage() == 0) {
+      _object->set_ram_class(RC_resident);
+      _object->set_lru_size(_cdata->_data_full_size);
+    }
     return true;
     return true;
   }
   }
   
   
@@ -621,37 +831,66 @@ unclean_set_num_rows(int n) {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GeomVertexArrayDataPipelineWriter::modify_data
-//       Access: Published
-//  Description: 
+//     Function: GeomVertexArrayDataHandle::copy_data_from
+//       Access: Public
+//  Description: Copies the entire data array from the other object.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-PTA_uchar GeomVertexArrayDataPipelineWriter::
-modify_data() {
-  // Perform copy-on-write: if the *node* reference count on the
-  // vertex data is greater than 1, assume some other
-  // GeomVertexArrayData has the same pointer, so make a copy of it
-  // first.
-  if (_cdata->_data.get_node_ref_count() > 1) {
-    PTA_uchar orig_data = _cdata->_data;
-    _cdata->_data.node_unref();
-    _cdata->_data = PTA_uchar(GeomVertexArrayData::get_class_type());
-    _cdata->_data.v() = orig_data.v();
-    _cdata->_data.node_ref();
-  }
+void GeomVertexArrayDataHandle::
+copy_data_from(const GeomVertexArrayDataHandle *other) {
+  nassertv(_writable);
+  check_resident();
+  other->check_resident();
+
+  _cdata->_data.v() = other->_cdata->_data.v();
   _cdata->_modified = Geom::get_next_modified();
   _cdata->_modified = Geom::get_next_modified();
+  _cdata->_data_full_size = _cdata->_data.size();
 
 
-  return _cdata->_data;
+  if (get_current_thread()->get_pipeline_stage() == 0) {
+    _object->set_ram_class(RC_resident);
+    _object->set_lru_size(_cdata->_data_full_size);
+  }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GeomVertexArrayDataPipelineWriter::set_data
-//       Access: Published
-//  Description: 
-////////////////////////////////////////////////////////////////////
-void GeomVertexArrayDataPipelineWriter::
-set_data(CPTA_uchar array) {
-  _cdata->_data.node_unref();
-  _cdata->_data = (PTA_uchar &)array;
-  _cdata->_data.node_ref();
+//     Function: GeomVertexArrayDataHandle::copy_subdata_from
+//       Access: Public
+//  Description: Copies a portion of the data array from the other
+//               object into a portion of the data array of this
+//               object.  If to_size != from_size, the size of this
+//               data array is adjusted accordingly.
+////////////////////////////////////////////////////////////////////
+void GeomVertexArrayDataHandle::
+copy_subdata_from(size_t to_start, size_t to_size,
+                  const GeomVertexArrayDataHandle *other,
+                  size_t from_start, size_t from_size) {
+  nassertv(_writable);
+  check_resident();
+  other->check_resident();
+
+  pvector<unsigned char> &to_v = _cdata->_data.v();
+  to_start = min(to_start, to_v.size());
+  to_size = min(to_size, to_v.size() - to_start);
+
+  from_start = min(from_start, other->_cdata->_data.size());
+  from_size = min(from_size, other->_cdata->_data.size() - from_start);
+
+  if (from_size < to_size) {
+    // Reduce the array.
+    to_v.erase(to_v.begin() + to_start + from_size, to_v.begin() + to_start + to_size);
+
+  } else if (to_size < from_size) {
+    // Expand the array.
+    to_v.insert(to_v.begin() + to_start + to_size, from_size - to_size, char());
+  }
+
+  // Now copy the data.
+  memcpy(&to_v[0] + to_start, other->get_pointer() + from_start, from_size);
   _cdata->_modified = Geom::get_next_modified();
   _cdata->_modified = Geom::get_next_modified();
+  _cdata->_data_full_size = _cdata->_data.size();
+
+  if (get_current_thread()->get_pipeline_stage() == 0) {
+    _object->set_ram_class(RC_resident);
+    _object->set_lru_size(_cdata->_data_full_size);
+  }
 }
 }
+

+ 95 - 73
panda/src/gobj/geomVertexArrayData.h

@@ -33,11 +33,15 @@
 #include "pipelineCycler.h"
 #include "pipelineCycler.h"
 #include "pStatCollector.h"
 #include "pStatCollector.h"
 #include "pmap.h"
 #include "pmap.h"
+#include "reMutex.h"
+#include "simpleLru.h"
 
 
 class PreparedGraphicsObjects;
 class PreparedGraphicsObjects;
 class VertexBufferContext;
 class VertexBufferContext;
 class GraphicsStateGuardianBase;
 class GraphicsStateGuardianBase;
 
 
+class GeomVertexArrayDataHandle;
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //       Class : GeomVertexArrayData
 //       Class : GeomVertexArrayData
 // Description : This is the data for one array of a GeomVertexData
 // Description : This is the data for one array of a GeomVertexData
@@ -57,7 +61,7 @@ class GraphicsStateGuardianBase;
 //               GeomVertexReader/Writer/Rewriter for high-level tools
 //               GeomVertexReader/Writer/Rewriter for high-level tools
 //               to manipulate the actual vertex data.
 //               to manipulate the actual vertex data.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA GeomVertexArrayData : public CopyOnWriteObject, public GeomEnums {
+class EXPCL_PANDA GeomVertexArrayData : public CopyOnWriteObject, public SimpleLruPage, public GeomEnums {
 private:
 private:
   GeomVertexArrayData();
   GeomVertexArrayData();
 
 
@@ -90,9 +94,8 @@ PUBLISHED:
   void output(ostream &out) const;
   void output(ostream &out) const;
   void write(ostream &out, int indent_level = 0) const;
   void write(ostream &out, int indent_level = 0) const;
 
 
-  INLINE CPTA_uchar get_data() const;
-  INLINE PTA_uchar modify_data();
-  INLINE void set_data(CPTA_uchar data);
+  INLINE CPT(GeomVertexArrayDataHandle) get_handle(Thread *current_thread = Thread::get_current_thread()) const;
+  INLINE PT(GeomVertexArrayDataHandle) modify_handle(Thread *current_thread = Thread::get_current_thread());
 
 
   void prepare(PreparedGraphicsObjects *prepared_objects);
   void prepare(PreparedGraphicsObjects *prepared_objects);
   bool is_prepared(PreparedGraphicsObjects *prepared_objects) const;
   bool is_prepared(PreparedGraphicsObjects *prepared_objects) const;
@@ -102,10 +105,25 @@ PUBLISHED:
   bool release(PreparedGraphicsObjects *prepared_objects);
   bool release(PreparedGraphicsObjects *prepared_objects);
   int release_all();
   int release_all();
 
 
+  INLINE RamClass get_ram_class() const;
+
+  INLINE static SimpleLru *get_global_lru(RamClass rclass);
+  static void lru_epoch();
+
+  void make_resident();
+  void make_compressed();
+  void make_disk();
+
+public:
+  virtual void evict_lru();
+
 private:
 private:
   void clear_prepared(PreparedGraphicsObjects *prepared_objects);
   void clear_prepared(PreparedGraphicsObjects *prepared_objects);
   PTA_uchar reverse_data_endianness(const PTA_uchar &data);
   PTA_uchar reverse_data_endianness(const PTA_uchar &data);
 
 
+  INLINE void set_ram_class(RamClass rclass);
+
+
   CPT(GeomVertexArrayFormat) _array_format;
   CPT(GeomVertexArrayFormat) _array_format;
 
 
   // A GeomVertexArrayData keeps a list (actually, a map) of all the
   // A GeomVertexArrayData keeps a list (actually, a map) of all the
@@ -120,11 +138,17 @@ private:
   // to indicate the data must be endian-reversed in finalize().
   // to indicate the data must be endian-reversed in finalize().
   bool _endian_reversed;
   bool _endian_reversed;
 
 
+  RamClass _ram_class;
+
+  typedef pvector<unsigned char> Data;
+
   // This is the data that must be cycled between pipeline stages.
   // This is the data that must be cycled between pipeline stages.
   class EXPCL_PANDA CData : public CycleData {
   class EXPCL_PANDA CData : public CycleData {
   public:
   public:
     INLINE CData();
     INLINE CData();
     INLINE CData(const CData &copy);
     INLINE CData(const CData &copy);
+    INLINE void operator = (const CData &copy);
+
     virtual ~CData();
     virtual ~CData();
     ALLOC_DELETED_CHAIN(CData);
     ALLOC_DELETED_CHAIN(CData);
     virtual CycleData *make_copy() const;
     virtual CycleData *make_copy() const;
@@ -138,7 +162,12 @@ private:
 
 
     UsageHint _usage_hint;
     UsageHint _usage_hint;
     PTA_uchar _data;
     PTA_uchar _data;
+    size_t _data_full_size;
     UpdateSeq _modified;
     UpdateSeq _modified;
+
+    // This implements read-write locking.  Anyone who gets the data for
+    // reading or writing will hold this mutex during the lock.
+    ReMutex _rw_lock;
     
     
   public:
   public:
     static TypeHandle get_class_type() {
     static TypeHandle get_class_type() {
@@ -160,6 +189,11 @@ private:
   typedef CycleDataStageReader<CData> CDStageReader;
   typedef CycleDataStageReader<CData> CDStageReader;
   typedef CycleDataStageWriter<CData> CDStageWriter;
   typedef CycleDataStageWriter<CData> CDStageWriter;
 
 
+  static SimpleLru _global_lru[RC_end_of_list];
+
+  static PStatCollector _vdata_compress_pcollector;
+  static PStatCollector _vdata_decompress_pcollector;
+
 public:
 public:
   static void register_with_read_factory();
   static void register_with_read_factory();
   virtual void write_datagram(BamWriter *manager, Datagram &dg);
   virtual void write_datagram(BamWriter *manager, Datagram &dg);
@@ -194,104 +228,92 @@ private:
   friend class GeomCacheManager;
   friend class GeomCacheManager;
   friend class GeomVertexData;
   friend class GeomVertexData;
   friend class PreparedGraphicsObjects;
   friend class PreparedGraphicsObjects;
-  friend class GeomVertexArrayDataPipelineBase;
-  friend class GeomVertexArrayDataPipelineReader;
-  friend class GeomVertexArrayDataPipelineWriter;
+  friend class GeomVertexArrayDataHandle;
 };
 };
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//       Class : GeomVertexArrayDataPipelineBase
-// Description : The common code from
+//       Class : GeomVertexArrayDataHandle
+// Description : This data object is returned by
+//               GeomVertexArrayData::get_handle() or modify_handle().
+//               As long as it exists, the data is locked; when the
+//               last of these destructs, the data is unlocked.
+//
+//               Only one thread at a time may lock the data; other
+//               threads attempting to lock the data will block.  A
+//               given thread may simultaneously lock the data
+//               multiple times.
+//
+//               This class serves in lieu of a pair of
 //               GeomVertexArrayDataPipelineReader and
 //               GeomVertexArrayDataPipelineReader and
-//               GeomVertexArrayDataPipelineWriter.
+//               GeomVertexArrayDataPipelineWriter classes
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA GeomVertexArrayDataPipelineBase : public GeomEnums {
-protected:
-  INLINE GeomVertexArrayDataPipelineBase(GeomVertexArrayData *object, 
-                                         Thread *current_thread,
-                                         GeomVertexArrayData::CData *cdata);
+class EXPCL_PANDA GeomVertexArrayDataHandle : public ReferenceCount, public GeomEnums {
+private:
+  INLINE GeomVertexArrayDataHandle(const GeomVertexArrayData *object, 
+                                   Thread *current_thread,
+                                   const GeomVertexArrayData::CData *_cdata, 
+                                   bool writable);
+  INLINE GeomVertexArrayDataHandle(const GeomVertexArrayDataHandle &);
+  INLINE void operator = (const GeomVertexArrayDataHandle &);
+  
+PUBLISHED:
+  INLINE ~GeomVertexArrayDataHandle();
+
 public:
 public:
-  INLINE ~GeomVertexArrayDataPipelineBase();
+  ALLOC_DELETED_CHAIN(GeomVertexArrayDataHandle);
 
 
   INLINE Thread *get_current_thread() const;
   INLINE Thread *get_current_thread() const;
+  INLINE const GeomVertexArrayData *get_object() const;
+  INLINE GeomVertexArrayData *get_object();
 
 
-  INLINE const GeomVertexArrayFormat *get_array_format() const;
+  INLINE const unsigned char *get_pointer() const;
+  INLINE unsigned char *get_pointer();
 
 
+PUBLISHED:
+  INLINE const GeomVertexArrayFormat *get_array_format() const;
   INLINE UsageHint get_usage_hint() const;
   INLINE UsageHint get_usage_hint() const;
-  INLINE CPTA_uchar get_data() const;
+
   INLINE int get_num_rows() const;
   INLINE int get_num_rows() const;
+  bool set_num_rows(int n);
+  bool unclean_set_num_rows(int n);
+  INLINE void clear_rows();
+
   INLINE int get_data_size_bytes() const;
   INLINE int get_data_size_bytes() const;
   INLINE UpdateSeq get_modified() const;
   INLINE UpdateSeq get_modified() const;
 
 
-protected:
+  void copy_data_from(const GeomVertexArrayDataHandle *other);
+  void copy_subdata_from(size_t to_start, size_t to_size,
+                         const GeomVertexArrayDataHandle *other,
+                         size_t from_start, size_t from_size);
+
+  /*
+  INLINE string get_data() const;
+  void set_data(const string &data);
+  INLINE string get_subdata(size_t start, size_t size) const;
+  void set_subdata(size_t start, size_t size, const string &data);
+  */
+
+  INLINE void check_resident() const;
+  
+private:
+  ReMutexHolder _holder;
   PT(GeomVertexArrayData) _object;
   PT(GeomVertexArrayData) _object;
   Thread *_current_thread;
   Thread *_current_thread;
   GeomVertexArrayData::CData *_cdata;
   GeomVertexArrayData::CData *_cdata;
-};
-
-////////////////////////////////////////////////////////////////////
-//       Class : GeomVertexArrayDataPipelineReader
-// Description : Encapsulates the data from a GeomVertexArrayData,
-//               pre-fetched for one stage of the pipeline.
-////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA GeomVertexArrayDataPipelineReader : public GeomVertexArrayDataPipelineBase {
-public:
-  INLINE GeomVertexArrayDataPipelineReader(const GeomVertexArrayData *object, Thread *current_thread);
-private:
-  INLINE GeomVertexArrayDataPipelineReader(const GeomVertexArrayDataPipelineReader &copy);
-  INLINE void operator = (const GeomVertexArrayDataPipelineReader &copy);
-
-public:
-  INLINE ~GeomVertexArrayDataPipelineReader();
-  ALLOC_DELETED_CHAIN(GeomVertexArrayDataPipelineReader);
-
-  INLINE const GeomVertexArrayData *get_object() const;
+  bool _writable;
 
 
 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() {
-    register_type(_type_handle, "GeomVertexArrayDataPipelineReader");
+    register_type(_type_handle, "GeomVertexArrayDataHandle");
   }
   }
 
 
 private:
 private:
   static TypeHandle _type_handle;
   static TypeHandle _type_handle;
-};
-
-////////////////////////////////////////////////////////////////////
-//       Class : GeomVertexArrayDataPipelineWriter
-// Description : Encapsulates the data from a GeomVertexArrayData,
-//               pre-fetched for one stage of the pipeline.
-////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA GeomVertexArrayDataPipelineWriter : public GeomVertexArrayDataPipelineBase {
-public:
-  INLINE GeomVertexArrayDataPipelineWriter(GeomVertexArrayData *object, bool force_to_0, Thread *current_thread);
-private:
-  INLINE GeomVertexArrayDataPipelineWriter(const GeomVertexArrayDataPipelineWriter &copy);
-  INLINE void operator = (const GeomVertexArrayDataPipelineWriter &copy);
-
-public:
-  INLINE ~GeomVertexArrayDataPipelineWriter();
-  ALLOC_DELETED_CHAIN(GeomVertexArrayDataPipelineWriter);
-
-  bool set_num_rows(int n);
-  bool unclean_set_num_rows(int n);
-
-  INLINE GeomVertexArrayData *get_object() const;
-  PTA_uchar modify_data();
-  void set_data(CPTA_uchar data);
-
-public:
-  static TypeHandle get_class_type() {
-    return _type_handle;
-  }
-  static void init_type() {
-    register_type(_type_handle, "GeomVertexArrayDataPipelineWriter");
-  }
 
 
-private:
-  static TypeHandle _type_handle;
+  friend class GeomVertexArrayData;
 };
 };
 
 
 INLINE ostream &operator << (ostream &out, const GeomVertexArrayData &obj);
 INLINE ostream &operator << (ostream &out, const GeomVertexArrayData &obj);

+ 2 - 2
panda/src/gobj/geomVertexData.I

@@ -711,7 +711,7 @@ check_array_readers() const {
 //       Access: Public
 //       Access: Public
 //  Description: 
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE const GeomVertexArrayDataPipelineReader *GeomVertexDataPipelineReader::
+INLINE const GeomVertexArrayDataHandle *GeomVertexDataPipelineReader::
 get_array_reader(int i) const {
 get_array_reader(int i) const {
   nassertr(_got_array_readers, NULL);
   nassertr(_got_array_readers, NULL);
   nassertr(i >= 0 && i < (int)_array_readers.size(), NULL);
   nassertr(i >= 0 && i < (int)_array_readers.size(), NULL);
@@ -846,7 +846,7 @@ check_array_writers() const {
 //       Access: Public
 //       Access: Public
 //  Description: 
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE GeomVertexArrayDataPipelineWriter *GeomVertexDataPipelineWriter::
+INLINE GeomVertexArrayDataHandle *GeomVertexDataPipelineWriter::
 get_array_writer(int i) const {
 get_array_writer(int i) const {
   nassertr(_got_array_writers, NULL);
   nassertr(_got_array_writers, NULL);
   nassertr(i >= 0 && i < (int)_array_writers.size(), NULL);
   nassertr(i >= 0 && i < (int)_array_writers.size(), NULL);

+ 33 - 37
panda/src/gobj/geomVertexData.cxx

@@ -426,10 +426,10 @@ set_slider_table(const SliderTable *table) {
 //               more of the arrays can be copied without the need to
 //               more of the arrays can be copied without the need to
 //               apply any conversion operation.  If it is true, the
 //               apply any conversion operation.  If it is true, the
 //               original GeomVertexArrayData objects in this object
 //               original GeomVertexArrayData objects in this object
-//               are retained, but their data arrays are copied
-//               pointerwise from the source; if it is false, then the
-//               GeomVertexArrayData objects themselves are copied
-//               pointerwise from the source.
+//               are retained, and their data arrays are copied
+//               byte-by-byte from the source; if it is false, then the
+//               GeomVertexArrayData objects are copied pointerwise
+//               from the source.
 //
 //
 //               Don't call this in a downstream thread unless you
 //               Don't call this in a downstream thread unless you
 //               don't mind it blowing away other changes you might
 //               don't mind it blowing away other changes you might
@@ -465,13 +465,10 @@ copy_from(const GeomVertexData *source, bool keep_data_objects,
         // Great!  Just use the same data for this one.
         // Great!  Just use the same data for this one.
         if (keep_data_objects) {
         if (keep_data_objects) {
           // Copy the data, but keep the same GeomVertexArrayData object.  
           // Copy the data, but keep the same GeomVertexArrayData object.  
-
-          // Maybe it even has the same data pointer already.  If so,
-          // avoid flipping the modified flag.
-          CPTA_uchar source_data = source->get_array(source_i)->get_data();
-          if (get_array(dest_i)->get_data() != source_data) {
-            modify_array(dest_i)->set_data(source_data);
-          }
+          
+          PT(GeomVertexArrayData) dest_data = modify_array(dest_i);
+          CPT(GeomVertexArrayData) source_data = source->get_array(source_i);
+          dest_data->modify_handle()->copy_data_from(source_data->get_handle());
         } else {
         } else {
           // Copy the GeomVertexArrayData object.
           // Copy the GeomVertexArrayData object.
           if (get_array(dest_i) != source->get_array(source_i)) {
           if (get_array(dest_i) != source->get_array(source_i)) {
@@ -491,7 +488,8 @@ copy_from(const GeomVertexData *source, bool keep_data_objects,
   // Now go back through and copy any data that's left over.
   // Now go back through and copy any data that's left over.
   for (source_i = 0; source_i < num_arrays; ++source_i) {
   for (source_i = 0; source_i < num_arrays; ++source_i) {
     CPT(GeomVertexArrayData) array_obj = source->get_array(source_i);
     CPT(GeomVertexArrayData) array_obj = source->get_array(source_i);
-    CPTA_uchar array_data = array_obj->get_data();
+    CPT(GeomVertexArrayDataHandle) array_handle = array_obj->get_handle();
+    const unsigned char *array_data = array_handle->get_pointer();
     const GeomVertexArrayFormat *source_array_format = source_format->get_array(source_i);
     const GeomVertexArrayFormat *source_array_format = source_format->get_array(source_i);
     int num_columns = source_array_format->get_num_columns();
     int num_columns = source_array_format->get_num_columns();
     for (int di = 0; di < num_columns; ++di) {
     for (int di = 0; di < num_columns; ++di) {
@@ -509,7 +507,8 @@ copy_from(const GeomVertexData *source, bool keep_data_objects,
         if (dest_column->is_bytewise_equivalent(*source_column)) {
         if (dest_column->is_bytewise_equivalent(*source_column)) {
           // We can do a quick bytewise copy.
           // We can do a quick bytewise copy.
           PT(GeomVertexArrayData) dest_array_obj = modify_array(dest_i);
           PT(GeomVertexArrayData) dest_array_obj = modify_array(dest_i);
-          PTA_uchar dest_array_data = dest_array_obj->modify_data();
+          PT(GeomVertexArrayDataHandle) dest_handle = dest_array_obj->modify_handle();
+          unsigned char *dest_array_data = dest_handle->get_pointer();
 
 
           bytewise_copy(dest_array_data + dest_column->get_start(), 
           bytewise_copy(dest_array_data + dest_column->get_start(), 
                         dest_array_format->get_stride(),
                         dest_array_format->get_stride(),
@@ -520,7 +519,8 @@ copy_from(const GeomVertexData *source, bool keep_data_objects,
                    source_column->is_uint8_rgba()) {
                    source_column->is_uint8_rgba()) {
           // A common special case: OpenGL color to DirectX color.
           // A common special case: OpenGL color to DirectX color.
           PT(GeomVertexArrayData) dest_array_obj = modify_array(dest_i);
           PT(GeomVertexArrayData) dest_array_obj = modify_array(dest_i);
-          PTA_uchar dest_array_data = dest_array_obj->modify_data();
+          PT(GeomVertexArrayDataHandle) dest_handle = dest_array_obj->modify_handle();
+          unsigned char *dest_array_data = dest_handle->get_pointer();
 
 
           uint8_rgba_to_packed_argb
           uint8_rgba_to_packed_argb
             (dest_array_data + dest_column->get_start(), 
             (dest_array_data + dest_column->get_start(), 
@@ -533,7 +533,8 @@ copy_from(const GeomVertexData *source, bool keep_data_objects,
           // Another common special case: DirectX color to OpenGL
           // Another common special case: DirectX color to OpenGL
           // color.
           // color.
           PT(GeomVertexArrayData) dest_array_obj = modify_array(dest_i);
           PT(GeomVertexArrayData) dest_array_obj = modify_array(dest_i);
-          PTA_uchar dest_array_data = dest_array_obj->modify_data();
+          PT(GeomVertexArrayDataHandle) dest_handle = dest_array_obj->modify_handle();
+          unsigned char *dest_array_data = dest_handle->get_pointer();
 
 
           packed_argb_to_uint8_rgba
           packed_argb_to_uint8_rgba
             (dest_array_data + dest_column->get_start(), 
             (dest_array_data + dest_column->get_start(), 
@@ -654,10 +655,12 @@ copy_row_from(int dest_row, const GeomVertexData *source,
 
 
   for (int i = 0; i < num_arrays; ++i) {
   for (int i = 0; i < num_arrays; ++i) {
     PT(GeomVertexArrayData) dest_array_obj = modify_array(i);
     PT(GeomVertexArrayData) dest_array_obj = modify_array(i);
-    PTA_uchar dest_array_data = dest_array_obj->modify_data();
+    PT(GeomVertexArrayDataHandle) dest_handle = dest_array_obj->modify_handle();
+    unsigned char *dest_array_data = dest_handle->get_pointer();
 
 
     CPT(GeomVertexArrayData) source_array_obj = source->get_array(i);
     CPT(GeomVertexArrayData) source_array_obj = source->get_array(i);
-    CPTA_uchar source_array_data = source_array_obj->get_data();
+    CPT(GeomVertexArrayDataHandle) source_array_handle = source_array_obj->get_handle();
+    const unsigned char *source_array_data = source_array_handle->get_pointer();
 
 
     const GeomVertexArrayFormat *array_format = source_format->get_array(i);
     const GeomVertexArrayFormat *array_format = source_format->get_array(i);
     int stride = array_format->get_stride();
     int stride = array_format->get_stride();
@@ -948,6 +951,7 @@ animate_vertices(Thread *current_thread) const {
   CDWriter cdataw(((GeomVertexData *)this)->_cycler, cdata, false);
   CDWriter cdataw(((GeomVertexData *)this)->_cycler, cdata, false);
   cdataw->_animated_vertices_modified = modified;
   cdataw->_animated_vertices_modified = modified;
   ((GeomVertexData *)this)->update_animated_vertices(cdataw, current_thread);
   ((GeomVertexData *)this)->update_animated_vertices(cdataw, current_thread);
+
   return cdataw->_animated_vertices;
   return cdataw->_animated_vertices;
 }
 }
 
 
@@ -1270,7 +1274,7 @@ update_animated_vertices(GeomVertexData::CData *cdata, Thread *current_thread) {
             if (slider_value != 0.0f) {
             if (slider_value != 0.0f) {
               CPT(InternalName) base_name = orig_format->get_morph_base(mi);
               CPT(InternalName) base_name = orig_format->get_morph_base(mi);
               CPT(InternalName) delta_name = orig_format->get_morph_delta(mi);
               CPT(InternalName) delta_name = orig_format->get_morph_delta(mi);
-              
+
               GeomVertexRewriter data(new_data, base_name);
               GeomVertexRewriter data(new_data, base_name);
               GeomVertexReader delta(this, delta_name);
               GeomVertexReader delta(this, delta_name);
               int num_subranges = rows.get_num_subranges();
               int num_subranges = rows.get_num_subranges();
@@ -1714,7 +1718,7 @@ get_num_rows() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool GeomVertexDataPipelineReader::
 bool GeomVertexDataPipelineReader::
 get_array_info(const InternalName *name, 
 get_array_info(const InternalName *name, 
-               const GeomVertexArrayDataPipelineReader *&array_reader,
+               const GeomVertexArrayDataHandle *&array_reader,
                int &num_values, 
                int &num_values, 
                GeomVertexDataPipelineReader::NumericType &numeric_type, 
                GeomVertexDataPipelineReader::NumericType &numeric_type, 
                int &start, int &stride) const {
                int &start, int &stride) const {
@@ -1738,7 +1742,7 @@ get_array_info(const InternalName *name,
 //  Description: 
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool GeomVertexDataPipelineReader::
 bool GeomVertexDataPipelineReader::
-get_vertex_info(const GeomVertexArrayDataPipelineReader *&array_reader,
+get_vertex_info(const GeomVertexArrayDataHandle *&array_reader,
                 int &num_values, 
                 int &num_values, 
                 GeomVertexDataPipelineReader::NumericType &numeric_type, 
                 GeomVertexDataPipelineReader::NumericType &numeric_type, 
                 int &start, int &stride) const {
                 int &start, int &stride) const {
@@ -1763,7 +1767,7 @@ get_vertex_info(const GeomVertexArrayDataPipelineReader *&array_reader,
 //  Description: 
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool GeomVertexDataPipelineReader::
 bool GeomVertexDataPipelineReader::
-get_normal_info(const GeomVertexArrayDataPipelineReader *&array_reader,
+get_normal_info(const GeomVertexArrayDataHandle *&array_reader,
                 GeomVertexDataPipelineReader::NumericType &numeric_type, 
                 GeomVertexDataPipelineReader::NumericType &numeric_type, 
                 int &start, int &stride) const {
                 int &start, int &stride) const {
   nassertr(_got_array_readers, false);
   nassertr(_got_array_readers, false);
@@ -1787,7 +1791,7 @@ get_normal_info(const GeomVertexArrayDataPipelineReader *&array_reader,
 //  Description: 
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool GeomVertexDataPipelineReader::
 bool GeomVertexDataPipelineReader::
-get_color_info(const GeomVertexArrayDataPipelineReader *&array_reader,
+get_color_info(const GeomVertexArrayDataHandle *&array_reader,
                int &num_values, 
                int &num_values, 
                GeomVertexDataPipelineReader::NumericType &numeric_type, 
                GeomVertexDataPipelineReader::NumericType &numeric_type, 
                int &start, int &stride) const {
                int &start, int &stride) const {
@@ -1818,7 +1822,8 @@ make_array_readers() {
   _array_readers.reserve(_cdata->_arrays.size());
   _array_readers.reserve(_cdata->_arrays.size());
   GeomVertexData::Arrays::const_iterator ai;
   GeomVertexData::Arrays::const_iterator ai;
   for (ai = _cdata->_arrays.begin(); ai != _cdata->_arrays.end(); ++ai) {
   for (ai = _cdata->_arrays.begin(); ai != _cdata->_arrays.end(); ++ai) {
-    _array_readers.push_back(new GeomVertexArrayDataPipelineReader((*ai).get_read_pointer(), _current_thread));
+    CPT(GeomVertexArrayData) array_obj = (*ai).get_read_pointer();
+    _array_readers.push_back(array_obj->get_handle(_current_thread));
   }
   }
 
 
   _got_array_readers = true;
   _got_array_readers = true;
@@ -1833,10 +1838,6 @@ void GeomVertexDataPipelineReader::
 delete_array_readers() {
 delete_array_readers() {
   nassertv(_got_array_readers);
   nassertv(_got_array_readers);
 
 
-  ArrayReaders::iterator ri;
-  for (ri = _array_readers.begin(); ri != _array_readers.end(); ++ri) {
-    delete (*ri);
-  }
   _array_readers.clear();
   _array_readers.clear();
   _got_array_readers = false;
   _got_array_readers = false;
 }
 }
@@ -1888,15 +1889,15 @@ set_num_rows(int n) {
   }
   }
 
 
   if (color_array >= 0 && orig_color_rows < n) {
   if (color_array >= 0 && orig_color_rows < n) {
-    // We have just added some rows, fill the "color" column with
+    // We have just added some rows; fill the "color" column with
     // (1, 1, 1, 1), for the programmer's convenience.
     // (1, 1, 1, 1), for the programmer's convenience.
-    GeomVertexArrayDataPipelineWriter *array_writer = _array_writers[color_array];
+    GeomVertexArrayDataHandle *array_writer = _array_writers[color_array];
     const GeomVertexArrayFormat *array_format = array_writer->get_array_format();
     const GeomVertexArrayFormat *array_format = array_writer->get_array_format();
     const GeomVertexColumn *column = 
     const GeomVertexColumn *column = 
       array_format->get_column(InternalName::get_color());
       array_format->get_column(InternalName::get_color());
     int stride = array_format->get_stride();
     int stride = array_format->get_stride();
     unsigned char *start = 
     unsigned char *start = 
-      array_writer->modify_data() + column->get_start();
+      array_writer->get_pointer() + column->get_start();
     unsigned char *stop = start + array_writer->get_data_size_bytes();
     unsigned char *stop = start + array_writer->get_data_size_bytes();
     unsigned char *pointer = start + stride * orig_color_rows;
     unsigned char *pointer = start + stride * orig_color_rows;
     int num_values = column->get_num_values();
     int num_values = column->get_num_values();
@@ -1999,8 +2000,7 @@ set_array(int i, const GeomVertexArrayData *array) {
   _cdata->_animated_vertices_modified = UpdateSeq();
   _cdata->_animated_vertices_modified = UpdateSeq();
 
 
   if (_got_array_writers) {
   if (_got_array_writers) {
-    delete _array_writers[i];
-    _array_writers[i] = new GeomVertexArrayDataPipelineWriter(_cdata->_arrays[i].get_write_pointer(), _force_to_0, _current_thread);
+    _array_writers[i] = _cdata->_arrays[i].get_write_pointer()->modify_handle(_current_thread);
   }
   }
 }
 }
 
 
@@ -2017,7 +2017,7 @@ make_array_writers() {
   GeomVertexData::Arrays::iterator ai;
   GeomVertexData::Arrays::iterator ai;
   for (ai = _cdata->_arrays.begin(); ai != _cdata->_arrays.end(); ++ai) {
   for (ai = _cdata->_arrays.begin(); ai != _cdata->_arrays.end(); ++ai) {
     PT(GeomVertexArrayData) array_obj = (*ai).get_write_pointer();
     PT(GeomVertexArrayData) array_obj = (*ai).get_write_pointer();
-    _array_writers.push_back(new GeomVertexArrayDataPipelineWriter(array_obj, _force_to_0, _current_thread));
+    _array_writers.push_back(array_obj->modify_handle(_current_thread));
   }
   }
 
 
   _object->clear_cache_stage();
   _object->clear_cache_stage();
@@ -2036,10 +2036,6 @@ void GeomVertexDataPipelineWriter::
 delete_array_writers() {
 delete_array_writers() {
   nassertv(_got_array_writers);
   nassertv(_got_array_writers);
 
 
-  ArrayWriters::iterator ri;
-  for (ri = _array_writers.begin(); ri != _array_writers.end(); ++ri) {
-    delete (*ri);
-  }
   _array_writers.clear();
   _array_writers.clear();
   _got_array_writers = false;
   _got_array_writers = false;
 }
 }

+ 8 - 8
panda/src/gobj/geomVertexData.h

@@ -409,27 +409,27 @@ public:
   INLINE const GeomVertexData *get_object() const;
   INLINE const GeomVertexData *get_object() const;
 
 
   INLINE void check_array_readers() const;
   INLINE void check_array_readers() const;
-  INLINE const GeomVertexArrayDataPipelineReader *get_array_reader(int i) const;
+  INLINE const GeomVertexArrayDataHandle *get_array_reader(int i) const;
   int get_num_rows() const;
   int get_num_rows() const;
 
 
   bool get_array_info(const InternalName *name, 
   bool get_array_info(const InternalName *name, 
-                      const GeomVertexArrayDataPipelineReader *&array_reader,
+                      const GeomVertexArrayDataHandle *&array_reader,
                       int &num_values, NumericType &numeric_type, 
                       int &num_values, NumericType &numeric_type, 
                       int &start, int &stride) const;
                       int &start, int &stride) const;
 
 
   INLINE bool has_vertex() const;
   INLINE bool has_vertex() const;
   INLINE bool is_vertex_transformed() const;
   INLINE bool is_vertex_transformed() const;
-  bool get_vertex_info(const GeomVertexArrayDataPipelineReader *&array_reader,
+  bool get_vertex_info(const GeomVertexArrayDataHandle *&array_reader,
                        int &num_values, NumericType &numeric_type, 
                        int &num_values, NumericType &numeric_type, 
                        int &start, int &stride) const;
                        int &start, int &stride) const;
 
 
   INLINE bool has_normal() const;
   INLINE bool has_normal() const;
-  bool get_normal_info(const GeomVertexArrayDataPipelineReader *&array_reader,
+  bool get_normal_info(const GeomVertexArrayDataHandle *&array_reader,
                        NumericType &numeric_type,
                        NumericType &numeric_type,
                        int &start, int &stride) const;
                        int &start, int &stride) const;
 
 
   INLINE bool has_color() const;
   INLINE bool has_color() const;
-  bool get_color_info(const GeomVertexArrayDataPipelineReader *&array_reader,
+  bool get_color_info(const GeomVertexArrayDataHandle *&array_reader,
                       int &num_values, NumericType &numeric_type, 
                       int &num_values, NumericType &numeric_type, 
                       int &start, int &stride) const;
                       int &start, int &stride) const;
 
 
@@ -438,7 +438,7 @@ private:
   void delete_array_readers();
   void delete_array_readers();
 
 
   bool _got_array_readers;
   bool _got_array_readers;
-  typedef pvector<GeomVertexArrayDataPipelineReader *> ArrayReaders;
+  typedef pvector<CPT(GeomVertexArrayDataHandle) > ArrayReaders;
   ArrayReaders _array_readers;
   ArrayReaders _array_readers;
 
 
 public:
 public:
@@ -473,7 +473,7 @@ public:
   INLINE GeomVertexData *get_object() const;
   INLINE GeomVertexData *get_object() const;
 
 
   INLINE void check_array_writers() const;
   INLINE void check_array_writers() const;
-  INLINE GeomVertexArrayDataPipelineWriter *get_array_writer(int i) const;
+  INLINE GeomVertexArrayDataHandle *get_array_writer(int i) const;
 
 
   PT(GeomVertexArrayData) modify_array(int i);
   PT(GeomVertexArrayData) modify_array(int i);
   void set_array(int i, const GeomVertexArrayData *array);
   void set_array(int i, const GeomVertexArrayData *array);
@@ -488,7 +488,7 @@ private:
 
 
   bool _force_to_0;
   bool _force_to_0;
   bool _got_array_writers;
   bool _got_array_writers;
-  typedef pvector<GeomVertexArrayDataPipelineWriter *> ArrayWriters;
+  typedef pvector<PT(GeomVertexArrayDataHandle) > ArrayWriters;
   ArrayWriters _array_writers;
   ArrayWriters _array_writers;
 
 
 public:
 public:

+ 3 - 2
panda/src/gobj/geomVertexFormat.cxx

@@ -575,9 +575,10 @@ write_with_data(ostream &out, int indent_level,
   indent(out, indent_level)
   indent(out, indent_level)
     << data->get_num_rows() << " rows.\n";
     << data->get_num_rows() << " rows.\n";
   for (size_t i = 0; i < _arrays.size(); i++) {
   for (size_t i = 0; i < _arrays.size(); i++) {
-    CPTA_uchar array_data = data->get_array(i)->get_data();
+    CPT(GeomVertexArrayDataHandle) handle = data->get_array(i)->get_handle();
+    const unsigned char *array_data = handle->get_pointer();
     indent(out, indent_level)
     indent(out, indent_level)
-      << "Array " << i << " (" << (void *)array_data.p() << ", "
+      << "Array " << i << " (" << (void *)array_data << ", "
       << *_arrays[i] << "):\n";
       << *_arrays[i] << "):\n";
     _arrays[i]->write_with_data(out, indent_level + 2, data->get_array(i));
     _arrays[i]->write_with_data(out, indent_level + 2, data->get_array(i));
   }
   }

+ 18 - 31
panda/src/gobj/geomVertexReader.I

@@ -147,7 +147,7 @@ GeomVertexReader(const GeomVertexReader &copy) :
   _current_thread(copy._current_thread),
   _current_thread(copy._current_thread),
   _packer(copy._packer),
   _packer(copy._packer),
   _stride(copy._stride),
   _stride(copy._stride),
-  _data(copy._data),
+  _handle(copy._handle),
   _pointer_begin(copy._pointer_begin),
   _pointer_begin(copy._pointer_begin),
   _pointer_end(copy._pointer_end),
   _pointer_end(copy._pointer_end),
   _pointer(copy._pointer),
   _pointer(copy._pointer),
@@ -168,7 +168,7 @@ operator = (const GeomVertexReader &copy) {
   _current_thread = copy._current_thread;
   _current_thread = copy._current_thread;
   _packer = copy._packer;
   _packer = copy._packer;
   _stride = copy._stride;
   _stride = copy._stride;
-  _data = copy._data;
+  _handle = copy._handle;
   _pointer_begin = copy._pointer_begin;
   _pointer_begin = copy._pointer_begin;
   _pointer_end = copy._pointer_end;
   _pointer_end = copy._pointer_end;
   _pointer = copy._pointer;
   _pointer = copy._pointer;
@@ -242,9 +242,7 @@ set_column(int column) {
                              &reader);
                              &reader);
   }
   }
   if (_array_data != (const GeomVertexArrayData *)NULL) {
   if (_array_data != (const GeomVertexArrayData *)NULL) {
-    GeomVertexArrayDataPipelineReader reader(_array_data, _current_thread);
-    return set_array_column(reader.get_array_format()->get_column(column),
-                            &reader);
+    return set_array_column(_array_data->get_array_format()->get_column(column));
   }
   }
   return false;
   return false;
 }
 }
@@ -291,9 +289,7 @@ set_column(const InternalName *name) {
                              &reader);
                              &reader);
   }
   }
   if (_array_data != (const GeomVertexArrayData *)NULL) {
   if (_array_data != (const GeomVertexArrayData *)NULL) {
-    GeomVertexArrayDataPipelineReader reader(_array_data, _current_thread);
-    return set_array_column(reader.get_array_format()->get_column(name),
-                            &reader);
+    return set_array_column(_array_data->get_array_format()->get_column(name));
   }
   }
 
 
   return false;
   return false;
@@ -511,10 +507,9 @@ get_packer() const {
 //               and sets the internal pointer to the indicated row.
 //               and sets the internal pointer to the indicated row.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void GeomVertexReader::
 INLINE void GeomVertexReader::
-set_pointer(int row, const GeomVertexArrayDataPipelineReader *array_reader) {
-  _data = array_reader->get_data();
-  _pointer_begin = _data;
-  _pointer_end = _pointer_begin + array_reader->get_data_size_bytes();
+set_pointer(int row) {
+  _pointer_begin = _handle->get_pointer();
+  _pointer_end = _pointer_begin + _handle->get_data_size_bytes();
   quick_set_pointer(row);
   quick_set_pointer(row);
 }
 }
 
 
@@ -529,21 +524,16 @@ INLINE void GeomVertexReader::
 quick_set_pointer(int row) {
 quick_set_pointer(int row) {
   nassertv(has_column());
   nassertv(has_column());
 
 
-#if defined(_DEBUG) && !defined(HAVE_THREADS)
-  // Make sure we still have the same pointer as stored the array.  We
-  // only perform this test in debug mode, because it is expensive,
-  // and only in single-threaded mode, because in threaded mode
-  // another thread might have reallocated the other pointer outside
-  // of our control anyway.
-  if (_vertex_data != (const GeomVertexData *)NULL) {
-    const GeomVertexArrayData *array_data = _vertex_data->get_array(_array);
-    nassertv(_pointer_begin == array_data->get_data());
-  } else {
-    nassertv(_pointer_begin == _array_data->get_data());
-  }
+#if defined(_DEBUG)
+  // Make sure we still have the same pointer as stored in the array.
+  nassertv(_pointer_begin == _handle->get_pointer());
 #endif
 #endif
 
 
   _pointer = _pointer_begin + _packer->_column->get_start() + _stride * row;
   _pointer = _pointer_begin + _packer->_column->get_start() + _stride * row;
+
+#if defined(_DEBUG)
+  nassertv(_pointer_begin == _pointer_end || _pointer < _pointer_end);
+#endif
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -554,14 +544,11 @@ quick_set_pointer(int row) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE const unsigned char *GeomVertexReader::
 INLINE const unsigned char *GeomVertexReader::
 inc_pointer() {
 inc_pointer() {
-#ifdef _DEBUG
+#if defined(_DEBUG)
   nassertr(_pointer < _pointer_end, empty_buffer);
   nassertr(_pointer < _pointer_end, empty_buffer);
-  if (_vertex_data != (const GeomVertexData *)NULL){ 
-    const GeomVertexArrayData *array_data = _vertex_data->get_array(_array);
-    nassertr(_pointer >= array_data->get_data().p() && _pointer < array_data->get_data().p() + array_data->get_data_size_bytes(), empty_buffer);
-  } else {
-    nassertr(_pointer >= _array_data->get_data().p() && _pointer < _array_data->get_data().p() + _array_data->get_data_size_bytes(), empty_buffer);
-  }
+  // Make sure we still have the same pointer as stored in the array.
+  nassertr(_pointer_begin == _handle->get_pointer(), empty_buffer);
+  nassertr(_pointer < _pointer_begin + _handle->get_data_size_bytes(), empty_buffer);
 #endif
 #endif
 
 
   const unsigned char *orig_pointer = _pointer;
   const unsigned char *orig_pointer = _pointer;

+ 8 - 10
panda/src/gobj/geomVertexReader.cxx

@@ -57,8 +57,7 @@ set_column(int array, const GeomVertexColumn *column) {
     return set_vertex_column(array, column, &reader);
     return set_vertex_column(array, column, &reader);
   }
   }
   if (_array_data != (const GeomVertexArrayData *)NULL) {
   if (_array_data != (const GeomVertexArrayData *)NULL) {
-    GeomVertexArrayDataPipelineReader reader(_array_data, _current_thread);
-    return set_array_column(column, &reader);
+    return set_array_column(column);
   }
   }
 
 
   // No data is associated with the Reader.
   // No data is associated with the Reader.
@@ -121,12 +120,11 @@ set_vertex_column(int array, const GeomVertexColumn *column,
 #endif
 #endif
 
 
   _array = array;
   _array = array;
-  const GeomVertexArrayDataPipelineReader *array_reader = 
-    data_reader->get_array_reader(_array);
-  _stride = array_reader->get_array_format()->get_stride();
+  _handle = data_reader->get_array_reader(_array);
+  _stride = _handle->get_array_format()->get_stride();
 
 
   _packer = column->_packer;
   _packer = column->_packer;
-  set_pointer(_start_row, array_reader);
+  set_pointer(_start_row);
   
   
   return true;
   return true;
 }
 }
@@ -139,18 +137,18 @@ set_vertex_column(int array, const GeomVertexColumn *column,
 //               GeomVertexArrayData.
 //               GeomVertexArrayData.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool GeomVertexReader::
 bool GeomVertexReader::
-set_array_column(const GeomVertexColumn *column,
-                 const GeomVertexArrayDataPipelineReader *array_reader) {
+set_array_column(const GeomVertexColumn *column) {
   if (column == (const GeomVertexColumn *)NULL) {
   if (column == (const GeomVertexColumn *)NULL) {
     return set_column(0, NULL);
     return set_column(0, NULL);
   }
   }
 
 
   nassertr(_array_data != (const GeomVertexArrayData *)NULL, false);
   nassertr(_array_data != (const GeomVertexArrayData *)NULL, false);
 
 
-  _stride = array_reader->get_array_format()->get_stride();
+  _handle = _array_data->get_handle();
+  _stride = _handle->get_array_format()->get_stride();
 
 
   _packer = column->_packer;
   _packer = column->_packer;
-  set_pointer(_start_row, array_reader);
+  set_pointer(_start_row);
   
   
   return true;
   return true;
 }
 }

+ 3 - 5
panda/src/gobj/geomVertexReader.h

@@ -120,15 +120,13 @@ protected:
 private:
 private:
   void initialize();
   void initialize();
 
 
-  INLINE void set_pointer(int row, 
-                          const GeomVertexArrayDataPipelineReader *array_reader);
+  INLINE void set_pointer(int row);
   INLINE void quick_set_pointer(int row);
   INLINE void quick_set_pointer(int row);
   INLINE const unsigned char *inc_pointer();
   INLINE const unsigned char *inc_pointer();
 
 
   bool set_vertex_column(int array, const GeomVertexColumn *column,
   bool set_vertex_column(int array, const GeomVertexColumn *column,
                          const GeomVertexDataPipelineReader *data_reader);
                          const GeomVertexDataPipelineReader *data_reader);
-  bool set_array_column(const GeomVertexColumn *column,
-                        const GeomVertexArrayDataPipelineReader *array_reader);
+  bool set_array_column(const GeomVertexColumn *column);
 
 
   // It is important that we only store *one* of the following two
   // It is important that we only store *one* of the following two
   // pointers.  If we are storing a GeomVertexData/array index, we
   // pointers.  If we are storing a GeomVertexData/array index, we
@@ -143,7 +141,7 @@ private:
   GeomVertexColumn::Packer *_packer;
   GeomVertexColumn::Packer *_packer;
   int _stride;
   int _stride;
 
 
-  CPTA_uchar _data;
+  CPT(GeomVertexArrayDataHandle) _handle;
   const unsigned char *_pointer_begin;
   const unsigned char *_pointer_begin;
   const unsigned char *_pointer_end;
   const unsigned char *_pointer_end;
   const unsigned char *_pointer;
   const unsigned char *_pointer;

+ 29 - 35
panda/src/gobj/geomVertexWriter.I

@@ -145,7 +145,7 @@ GeomVertexWriter(const GeomVertexWriter &copy) :
   _current_thread(copy._current_thread),
   _current_thread(copy._current_thread),
   _packer(copy._packer),
   _packer(copy._packer),
   _stride(copy._stride),
   _stride(copy._stride),
-  _data(copy._data),
+  _handle(copy._handle),
   _pointer_begin(copy._pointer_begin),
   _pointer_begin(copy._pointer_begin),
   _pointer_end(copy._pointer_end),
   _pointer_end(copy._pointer_end),
   _pointer(copy._pointer),
   _pointer(copy._pointer),
@@ -166,7 +166,7 @@ operator = (const GeomVertexWriter &copy) {
   _current_thread = copy._current_thread;
   _current_thread = copy._current_thread;
   _packer = copy._packer;
   _packer = copy._packer;
   _stride = copy._stride;
   _stride = copy._stride;
-  _data = copy._data;
+  _handle = copy._handle;
   _pointer_begin = copy._pointer_begin;
   _pointer_begin = copy._pointer_begin;
   _pointer_end = copy._pointer_end;
   _pointer_end = copy._pointer_end;
   _pointer = copy._pointer;
   _pointer = copy._pointer;
@@ -240,9 +240,7 @@ set_column(int column) {
                              &writer);
                              &writer);
   }
   }
   if (_array_data != (GeomVertexArrayData *)NULL) {
   if (_array_data != (GeomVertexArrayData *)NULL) {
-    GeomVertexArrayDataPipelineWriter writer(_array_data, true, _current_thread);
-    return set_array_column(writer.get_array_format()->get_column(column),
-                            &writer);
+    return set_array_column(_array_data->get_array_format()->get_column(column));
   }
   }
   return false;
   return false;
 }
 }
@@ -289,9 +287,7 @@ set_column(const InternalName *name) {
                              &writer);
                              &writer);
   }
   }
   if (_array_data != (GeomVertexArrayData *)NULL) {
   if (_array_data != (GeomVertexArrayData *)NULL) {
-    GeomVertexArrayDataPipelineWriter writer(_array_data, true, _current_thread);
-    return set_array_column(writer.get_array_format()->get_column(name),
-                            &writer);
+    return set_array_column(_array_data->get_array_format()->get_column(name));
   }
   }
   return false;
   return false;
 }
 }
@@ -814,10 +810,9 @@ get_packer() const {
 //               and sets the internal pointer to the indicated row.
 //               and sets the internal pointer to the indicated row.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void GeomVertexWriter::
 INLINE void GeomVertexWriter::
-set_pointer(int row, GeomVertexArrayDataPipelineWriter *array_writer) {
-  _data = array_writer->modify_data();
-  _pointer_begin = _data;
-  _pointer_end = _pointer_begin + array_writer->get_data_size_bytes();
+set_pointer(int row) {
+  _pointer_begin = _handle->get_pointer();
+  _pointer_end = _pointer_begin + _handle->get_data_size_bytes();
   quick_set_pointer(row);
   quick_set_pointer(row);
 }
 }
 
 
@@ -832,21 +827,16 @@ INLINE void GeomVertexWriter::
 quick_set_pointer(int row) {
 quick_set_pointer(int row) {
   nassertv(has_column());
   nassertv(has_column());
 
 
-#if defined(_DEBUG) && !defined(HAVE_THREADS)
-  // Make sure we still have the same pointer as stored the array.  We
-  // only perform this test in debug mode, because it is expensive,
-  // and only in single-threaded mode, because in threaded mode
-  // another thread might have reallocated the other pointer outside
-  // of our control anyway.
-  if (_vertex_data != (const GeomVertexData *)NULL) {
-    const GeomVertexArrayData *array_data = _vertex_data->get_array(_array);
-    nassertv(_pointer_begin == array_data->get_data());
-  } else {
-    nassertv(_pointer_begin == _array_data->get_data());
-  }
+#if defined(_DEBUG)
+  // Make sure we still have the same pointer as stored in the array.
+  nassertv(_pointer_begin == _handle->get_pointer());
 #endif
 #endif
 
 
   _pointer = _pointer_begin + _packer->_column->get_start() + _stride * row;
   _pointer = _pointer_begin + _packer->_column->get_start() + _stride * row;
+
+#if defined(_DEBUG)
+  nassertv(_pointer_begin == _pointer_end || _pointer <= _pointer_end);
+#endif
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -857,14 +847,11 @@ quick_set_pointer(int row) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE unsigned char *GeomVertexWriter::
 INLINE unsigned char *GeomVertexWriter::
 inc_pointer() {
 inc_pointer() {
-#ifdef _DEBUG
+#if defined(_DEBUG)
   nassertr(_pointer < _pointer_end, empty_buffer);
   nassertr(_pointer < _pointer_end, empty_buffer);
-  if (_vertex_data != (GeomVertexData *)NULL){ 
-    const GeomVertexArrayData *array_data = _vertex_data->get_array(_array);
-    nassertr(_pointer >= array_data->get_data().p() && _pointer < array_data->get_data().p() + array_data->get_data_size_bytes(), empty_buffer);
-  } else {
-    nassertr(_pointer >= _array_data->get_data().p() && _pointer < _array_data->get_data().p() + _array_data->get_data_size_bytes(), empty_buffer);
-  }
+  // Make sure we still have the same pointer as stored in the array.
+  nassertr(_pointer_begin == _handle->get_pointer(), empty_buffer);
+  nassertr(_pointer < _pointer_begin + _handle->get_data_size_bytes(), empty_buffer);
 #endif
 #endif
 
 
   unsigned char *orig_pointer = _pointer;
   unsigned char *orig_pointer = _pointer;
@@ -885,16 +872,23 @@ inc_add_pointer() {
   if (_pointer >= _pointer_end) {
   if (_pointer >= _pointer_end) {
     // Reset the data pointer.
     // Reset the data pointer.
     int write_row = get_write_row();
     int write_row = get_write_row();
+
     if (_vertex_data != (GeomVertexData *)NULL) {
     if (_vertex_data != (GeomVertexData *)NULL) {
+      // If we have a whole GeomVertexData, we must set the length of
+      // all its arrays at once.
       GeomVertexDataPipelineWriter writer(_vertex_data, true, _current_thread);
       GeomVertexDataPipelineWriter writer(_vertex_data, true, _current_thread);
       writer.check_array_writers();
       writer.check_array_writers();
       writer.set_num_rows(max(write_row + 1, writer.get_num_rows()));
       writer.set_num_rows(max(write_row + 1, writer.get_num_rows()));
-      set_pointer(write_row, writer.get_array_writer(_array));
+      _handle = writer.get_array_writer(_array);
+
     } else {
     } else {
-      GeomVertexArrayDataPipelineWriter writer(_array_data, true, _current_thread);
-      writer.set_num_rows(max(write_row + 1, writer.get_num_rows()));
-      set_pointer(write_row, &writer);
+      // Otherwise, we can get away with modifying only the one array
+      // we're using.
+      _handle->set_num_rows(max(write_row + 1, _handle->get_num_rows()));
     }
     }
+
+    set_pointer(write_row);
   }
   }
   return inc_pointer();
   return inc_pointer();
 }
 }
+

+ 8 - 10
panda/src/gobj/geomVertexWriter.cxx

@@ -62,8 +62,7 @@ set_column(int array, const GeomVertexColumn *column) {
     return set_vertex_column(array, column, &writer);
     return set_vertex_column(array, column, &writer);
   }
   }
   if (_array_data != (GeomVertexArrayData *)NULL) {
   if (_array_data != (GeomVertexArrayData *)NULL) {
-    GeomVertexArrayDataPipelineWriter writer(_array_data, true, _current_thread);
-    return set_array_column(column, &writer);
+    return set_array_column(column);
   }
   }
 
 
   // No data is associated with the Writer.
   // No data is associated with the Writer.
@@ -126,12 +125,11 @@ set_vertex_column(int array, const GeomVertexColumn *column,
 #endif
 #endif
 
 
   _array = array;
   _array = array;
-  GeomVertexArrayDataPipelineWriter *array_writer = 
-    data_writer->get_array_writer(_array);
-  _stride = array_writer->get_array_format()->get_stride();
+  _handle = data_writer->get_array_writer(_array);
+  _stride = _handle->get_array_format()->get_stride();
 
 
   _packer = column->_packer;
   _packer = column->_packer;
-  set_pointer(_start_row, array_writer);
+  set_pointer(_start_row);
   
   
   return true;
   return true;
 }
 }
@@ -144,18 +142,18 @@ set_vertex_column(int array, const GeomVertexColumn *column,
 //               GeomVertexArrayData.
 //               GeomVertexArrayData.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool GeomVertexWriter::
 bool GeomVertexWriter::
-set_array_column(const GeomVertexColumn *column,
-                 GeomVertexArrayDataPipelineWriter *array_writer) {
+set_array_column(const GeomVertexColumn *column) {
   if (column == (const GeomVertexColumn *)NULL) {
   if (column == (const GeomVertexColumn *)NULL) {
     return set_column(0, NULL);
     return set_column(0, NULL);
   }
   }
 
 
   nassertr(_array_data != (GeomVertexArrayData *)NULL, false);
   nassertr(_array_data != (GeomVertexArrayData *)NULL, false);
 
 
-  _stride = array_writer->get_array_format()->get_stride();
+  _handle = _array_data->modify_handle();
+  _stride = _handle->get_array_format()->get_stride();
 
 
   _packer = column->_packer;
   _packer = column->_packer;
-  set_pointer(_start_row, array_writer);
+  set_pointer(_start_row);
   
   
   return true;
   return true;
 }
 }

+ 3 - 5
panda/src/gobj/geomVertexWriter.h

@@ -157,16 +157,14 @@ private:
 
 
   void initialize();
   void initialize();
 
 
-  INLINE void set_pointer(int row, 
-                          GeomVertexArrayDataPipelineWriter *array_writer);
+  INLINE void set_pointer(int row);
   INLINE void quick_set_pointer(int row);
   INLINE void quick_set_pointer(int row);
   INLINE unsigned char *inc_pointer();
   INLINE unsigned char *inc_pointer();
   INLINE unsigned char *inc_add_pointer();
   INLINE unsigned char *inc_add_pointer();
 
 
   bool set_vertex_column(int array, const GeomVertexColumn *column,
   bool set_vertex_column(int array, const GeomVertexColumn *column,
                          GeomVertexDataPipelineWriter *data_writer);
                          GeomVertexDataPipelineWriter *data_writer);
-  bool set_array_column(const GeomVertexColumn *column,
-                        GeomVertexArrayDataPipelineWriter *array_writer);
+  bool set_array_column(const GeomVertexColumn *column);
 
 
   // It is important that we only store *one* of the following two
   // It is important that we only store *one* of the following two
   // pointers.  If we are storing a GeomVertexData/array index, we
   // pointers.  If we are storing a GeomVertexData/array index, we
@@ -181,7 +179,7 @@ private:
   GeomVertexColumn::Packer *_packer;
   GeomVertexColumn::Packer *_packer;
   int _stride;
   int _stride;
 
 
-  PTA_uchar _data;
+  PT(GeomVertexArrayDataHandle) _handle;
   unsigned char *_pointer_begin;
   unsigned char *_pointer_begin;
   unsigned char *_pointer_end;
   unsigned char *_pointer_end;
   unsigned char *_pointer;
   unsigned char *_pointer;

+ 11 - 8
panda/src/gobj/gobj_composite1.cxx

@@ -1,25 +1,28 @@
 #include "bufferContext.cxx"
 #include "bufferContext.cxx"
 #include "bufferContextChain.cxx"
 #include "bufferContextChain.cxx"
 #include "bufferResidencyTracker.cxx"
 #include "bufferResidencyTracker.cxx"
+#include "config_gobj.cxx"
 #include "geom.cxx"
 #include "geom.cxx"
+#include "geomCacheEntry.cxx"
+#include "geomCacheManager.cxx"
 #include "geomContext.cxx"
 #include "geomContext.cxx"
 #include "geomEnums.cxx"
 #include "geomEnums.cxx"
+#include "geomLines.cxx"
+#include "geomLinestrips.cxx"
 #include "geomMunger.cxx"
 #include "geomMunger.cxx"
+#include "geomPoints.cxx"
 #include "geomPrimitive.cxx"
 #include "geomPrimitive.cxx"
 #include "geomTriangles.cxx"
 #include "geomTriangles.cxx"
-#include "geomTristrips.cxx"
 #include "geomTrifans.cxx"
 #include "geomTrifans.cxx"
-#include "geomLines.cxx"
-#include "geomLinestrips.cxx"
-#include "geomPoints.cxx"
+#include "geomTristrips.cxx"
+#include "geomVertexAnimationSpec.cxx"
 #include "geomVertexArrayData.cxx"
 #include "geomVertexArrayData.cxx"
 #include "geomVertexArrayFormat.cxx"
 #include "geomVertexArrayFormat.cxx"
-#include "geomCacheEntry.cxx"
-#include "geomCacheManager.cxx"
-#include "geomVertexAnimationSpec.cxx"
-#include "geomVertexData.cxx"
 #include "geomVertexColumn.cxx"
 #include "geomVertexColumn.cxx"
+#include "geomVertexData.cxx"
 #include "geomVertexFormat.cxx"
 #include "geomVertexFormat.cxx"
 #include "geomVertexReader.cxx"
 #include "geomVertexReader.cxx"
 #include "geomVertexRewriter.cxx"
 #include "geomVertexRewriter.cxx"
 #include "geomVertexWriter.cxx"
 #include "geomVertexWriter.cxx"
+#include "indexBufferContext.cxx"
+#include "internalName.cxx"

+ 3 - 5
panda/src/gobj/gobj_composite2.cxx

@@ -1,6 +1,3 @@
-#include "config_gobj.cxx"
-#include "indexBufferContext.cxx"
-#include "internalName.cxx"
 #include "lens.cxx"
 #include "lens.cxx"
 #include "material.cxx"
 #include "material.cxx"
 #include "materialPool.cxx"
 #include "materialPool.cxx"
@@ -11,14 +8,15 @@
 #include "preparedGraphicsObjects.cxx"
 #include "preparedGraphicsObjects.cxx"
 #include "queryContext.cxx"
 #include "queryContext.cxx"
 #include "savedContext.cxx"
 #include "savedContext.cxx"
+#include "shaderContext.cxx"
+#include "shaderExpansion.cxx"
+#include "simpleLru.cxx"
 #include "sliderTable.cxx"
 #include "sliderTable.cxx"
 #include "texture.cxx"
 #include "texture.cxx"
 #include "textureContext.cxx"
 #include "textureContext.cxx"
 #include "texturePool.cxx"
 #include "texturePool.cxx"
 #include "texturePoolFilter.cxx"
 #include "texturePoolFilter.cxx"
 #include "textureStage.cxx"
 #include "textureStage.cxx"
-#include "shaderExpansion.cxx"
-#include "shaderContext.cxx"
 #include "transformBlend.cxx"
 #include "transformBlend.cxx"
 #include "transformBlendTable.cxx"
 #include "transformBlendTable.cxx"
 #include "transformTable.cxx"
 #include "transformTable.cxx"

+ 203 - 0
panda/src/gobj/simpleLru.I

@@ -0,0 +1,203 @@
+// Filename: simpleLru.I
+// Created by:  drose (11May07)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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: SimpleLru::Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+SimpleLru::
+SimpleLru(size_t max_size) : LinkedListNode(true) {
+  _total_size = 0;
+  _max_size = max_size;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SimpleLru::get_total_size
+//       Access: Published
+//  Description: Returns the total size of all objects currently
+//               active on the LRU.
+////////////////////////////////////////////////////////////////////
+INLINE size_t SimpleLru::
+get_total_size() const {
+  return _total_size;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SimpleLru::get_max_size
+//       Access: Published
+//  Description: Returns the max size of all objects that are allowed
+//               to be active on the LRU.
+////////////////////////////////////////////////////////////////////
+INLINE size_t SimpleLru::
+get_max_size() const {
+  return _max_size;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SimpleLru::set_max_size
+//       Access: Published
+//  Description: Changes the max size of all objects that are allowed
+//               to be active on the LRU.
+////////////////////////////////////////////////////////////////////
+INLINE void SimpleLru::
+set_max_size(size_t max_size) {
+  _max_size = max_size;
+  consider_evict();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SimpleLru::consider_evict
+//       Access: Published
+//  Description: Evicts a sequence of objects if the queue is full.
+////////////////////////////////////////////////////////////////////
+INLINE void SimpleLru::
+consider_evict() {
+  if (_max_size != 0 && _total_size > _max_size) {
+    do_evict();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SimpleLruPage::Constructor
+//       Access: Protected
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE SimpleLruPage::
+SimpleLruPage(size_t lru_size) :
+  _lru(NULL),
+  _lru_size(lru_size)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SimpleLruPage::Copy Constructor
+//       Access: Protected
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE SimpleLruPage::
+SimpleLruPage(const SimpleLruPage &copy) :
+  _lru(NULL),
+  _lru_size(copy._lru_size)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SimpleLruPage::Copy Assignment Operator
+//       Access: Protected
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE void SimpleLruPage::
+operator = (const SimpleLruPage &copy) {
+  set_lru_size(copy.get_lru_size());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SimpleLruPage::enqueue_lru
+//       Access: Published
+//  Description: Returns the LRU that manages this page, or NULL if it
+//               is not currently managed by any LRU.
+////////////////////////////////////////////////////////////////////
+INLINE SimpleLru *SimpleLruPage::
+get_lru() const {
+  return _lru;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SimpleLruPage::enqueue_lru
+//       Access: Published
+//  Description: Adds the page to the tail of the SimpleLru.  When it
+//               reaches the head, it will be the next to be evicted.
+////////////////////////////////////////////////////////////////////
+INLINE void SimpleLruPage::
+enqueue_lru(SimpleLru *lru) {
+  dequeue_lru();
+  _lru = lru;
+  _lru->_total_size += _lru_size;
+  insert_before(_lru);
+
+  // Let's not automatically evict pages; instead, we'll evict only on
+  // an explicit epoch test.
+  //  _lru->consider_evict();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SimpleLruPage::dequeue_lru
+//       Access: Published
+//  Description: Removes the page from its SimpleLru.
+////////////////////////////////////////////////////////////////////
+INLINE void SimpleLruPage::
+dequeue_lru() {
+  if (_lru != (SimpleLru *)NULL) {
+    remove_from_list();
+    _lru->_total_size -= _lru_size;
+    _lru = NULL;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SimpleLruPage::mark_used_lru
+//       Access: Published
+//  Description: To be called when the page is used; this will move it
+//               to the tail of the SimpleLru queue it is already on.
+////////////////////////////////////////////////////////////////////
+INLINE void SimpleLruPage::
+mark_used_lru() {
+  if (_lru != (SimpleLru *)NULL) {
+    mark_used_lru(_lru);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SimpleLruPage::mark_used_lru
+//       Access: Published
+//  Description: To be called when the page is used; this will move it
+//               to the tail of the specified SimpleLru queue.
+////////////////////////////////////////////////////////////////////
+INLINE void SimpleLruPage::
+mark_used_lru(SimpleLru *lru) {
+  dequeue_lru();
+  enqueue_lru(lru);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SimpleLruPage::get_lru_size
+//       Access: Published
+//  Description: Returns the size of this page as reported to the LRU,
+//               presumably in bytes.
+////////////////////////////////////////////////////////////////////
+INLINE size_t SimpleLruPage::
+get_lru_size() const {
+  return _lru_size;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SimpleLruPage::set_lru_size
+//       Access: Published
+//  Description: Specifies the size of this page, presumably in bytes,
+//               although any units is possible.
+////////////////////////////////////////////////////////////////////
+INLINE void SimpleLruPage::
+set_lru_size(size_t lru_size) {
+  if (_lru != (SimpleLru *)NULL) {
+    _lru->_total_size -= _lru_size;
+    _lru->_total_size += lru_size;
+  }
+  _lru_size = lru_size;
+}

+ 96 - 0
panda/src/gobj/simpleLru.cxx

@@ -0,0 +1,96 @@
+// Filename: simpleLru.cxx
+// Created by:  drose (11May07)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "simpleLru.h"
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: SimpleLru::Destructor
+//       Access: Protected, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+SimpleLru::
+~SimpleLru() {
+#ifndef NDEBUG
+  // We're shutting down.  Force-remove everything remaining, but
+  // don't explicitly evict it (that would force vertex buffers to
+  // write themselves to disk unnecessarily).
+  while (_next != (LinkedListNode *)NULL) {
+    ((SimpleLruPage *)_next)->_lru = NULL;
+    ((SimpleLruPage *)_next)->remove_from_list();
+  }
+#endif
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SimpleLru::do_evict
+//       Access: Private
+//  Description: Evicts pages until the LRU is within tolerance.
+////////////////////////////////////////////////////////////////////
+void SimpleLru::
+do_evict() {
+  // Store the current end of the list.  If pages re-enqueue
+  // themselves during this traversal, we don't want to visit them
+  // twice.
+  SimpleLruPage *end = (SimpleLruPage *)_prev;
+
+  // Now walk through the list.
+  SimpleLruPage *node = (SimpleLruPage *)_next;
+  while (_total_size > _max_size) {
+    SimpleLruPage *next = (SimpleLruPage *)node->_next;
+    
+    node->evict_lru();
+    if (node == end) {
+      // If we reach the original tail of the list, stop.
+      return;
+    }
+    node = next;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SimpleLruPage::Destructor
+//       Access: Published, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+SimpleLruPage::
+~SimpleLruPage() {
+  if (_lru != NULL) {
+    dequeue_lru();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SimpleLruPage::evict_lru
+//       Access: Published, Virtual
+//  Description: Evicts the page from the LRU.  Called internally when
+//               the LRU determines that it is full.  May also be
+//               called externally when necessary to explicitly evict
+//               the page.
+//
+//               It is legal for this method to either evict the page
+//               as requested, do nothing (in which case the eviction
+//               will be requested again at the next epoch), or
+//               requeue itself on the tail of the queue (in which
+//               case the eviction will be requested again much
+//               later).
+////////////////////////////////////////////////////////////////////
+void SimpleLruPage::
+evict_lru() {
+  dequeue_lru();
+}

+ 88 - 0
panda/src/gobj/simpleLru.h

@@ -0,0 +1,88 @@
+// Filename: simpleLru.h
+// Created by:  drose (11May07)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 SIMPLELRU_H
+#define SIMPLELRU_H
+
+#include "pandabase.h"
+#include "linkedListNode.h"
+
+class SimpleLruPage;
+
+////////////////////////////////////////////////////////////////////
+//       Class : SimpleLru
+// Description : An implementation of a very simple LRU algorithm.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA SimpleLru : public LinkedListNode {
+PUBLISHED:
+  INLINE SimpleLru(size_t max_size);
+  ~SimpleLru();
+
+  INLINE size_t get_total_size() const;
+  INLINE size_t get_max_size() const;
+  INLINE void set_max_size(size_t max_size);
+
+  INLINE void consider_evict();
+
+private:
+  void do_evict();
+
+  size_t _total_size;
+  size_t _max_size;
+
+  friend class SimpleLruPage;
+};
+
+////////////////////////////////////////////////////////////////////
+//       Class : SimpleLruPage
+// Description : One atomic piece that may be managed by a SimpleLru
+//               chain.  To use this class, inherit from it and
+//               override evict_lru().
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA SimpleLruPage : public LinkedListNode {
+PUBLISHED:
+  INLINE SimpleLruPage(size_t lru_size);
+  INLINE SimpleLruPage(const SimpleLruPage &copy);
+  INLINE void operator = (const SimpleLruPage &copy);
+
+  virtual ~SimpleLruPage();
+
+  INLINE SimpleLru *get_lru() const;
+
+  INLINE void enqueue_lru(SimpleLru *lru);
+  INLINE void dequeue_lru();
+
+  INLINE void mark_used_lru();
+  INLINE void mark_used_lru(SimpleLru *lru);
+
+  INLINE size_t get_lru_size() const;
+  INLINE void set_lru_size(size_t lru_size);
+
+  virtual void evict_lru();
+
+private:
+  SimpleLru *_lru;
+
+  size_t _lru_size;
+
+  friend class SimpleLru;
+};
+
+#include "simpleLru.I"
+
+#endif

+ 4 - 4
panda/src/gobj/vertexBufferContext.I

@@ -47,7 +47,7 @@ get_data() const {
 //               last time mark_loaded() was called.
 //               last time mark_loaded() was called.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool VertexBufferContext::
 INLINE bool VertexBufferContext::
-changed_size(const GeomVertexArrayDataPipelineReader *reader) const {
+changed_size(const GeomVertexArrayDataHandle *reader) const {
   nassertr(reader->get_object() == _data, false);
   nassertr(reader->get_object() == _data, false);
   return get_data_size_bytes() != (size_t)reader->get_data_size_bytes();
   return get_data_size_bytes() != (size_t)reader->get_data_size_bytes();
 }
 }
@@ -59,7 +59,7 @@ changed_size(const GeomVertexArrayDataPipelineReader *reader) const {
 //               since the last time mark_loaded() was called.
 //               since the last time mark_loaded() was called.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool VertexBufferContext::
 INLINE bool VertexBufferContext::
-changed_usage_hint(const GeomVertexArrayDataPipelineReader *reader) const {
+changed_usage_hint(const GeomVertexArrayDataHandle *reader) const {
   nassertr(reader->get_object() == _data, false);
   nassertr(reader->get_object() == _data, false);
   return _usage_hint != reader->get_usage_hint();
   return _usage_hint != reader->get_usage_hint();
 }
 }
@@ -71,7 +71,7 @@ changed_usage_hint(const GeomVertexArrayDataPipelineReader *reader) const {
 //               last time mark_loaded() was called.
 //               last time mark_loaded() was called.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool VertexBufferContext::
 INLINE bool VertexBufferContext::
-was_modified(const GeomVertexArrayDataPipelineReader *reader) const {
+was_modified(const GeomVertexArrayDataHandle *reader) const {
   nassertr(reader->get_object() == _data, false);
   nassertr(reader->get_object() == _data, false);
   return get_modified() != reader->get_modified();
   return get_modified() != reader->get_modified();
 }
 }
@@ -84,7 +84,7 @@ was_modified(const GeomVertexArrayDataPipelineReader *reader) const {
 //               internal flags for changed_size() and modified().
 //               internal flags for changed_size() and modified().
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void VertexBufferContext::
 INLINE void VertexBufferContext::
-mark_loaded(const GeomVertexArrayDataPipelineReader *reader) {
+mark_loaded(const GeomVertexArrayDataHandle *reader) {
   nassertv(reader->get_object() == _data);
   nassertv(reader->get_object() == _data);
   update_data_size_bytes(reader->get_data_size_bytes());
   update_data_size_bytes(reader->get_data_size_bytes());
   update_modified(reader->get_modified());
   update_modified(reader->get_modified());

+ 4 - 4
panda/src/gobj/vertexBufferContext.h

@@ -44,12 +44,12 @@ public:
 PUBLISHED:
 PUBLISHED:
   INLINE GeomVertexArrayData *get_data() const;
   INLINE GeomVertexArrayData *get_data() const;
 
 
-  INLINE bool changed_size(const GeomVertexArrayDataPipelineReader *reader) const;
-  INLINE bool changed_usage_hint(const GeomVertexArrayDataPipelineReader *reader) const;
-  INLINE bool was_modified(const GeomVertexArrayDataPipelineReader *reader) const;
+  INLINE bool changed_size(const GeomVertexArrayDataHandle *reader) const;
+  INLINE bool changed_usage_hint(const GeomVertexArrayDataHandle *reader) const;
+  INLINE bool was_modified(const GeomVertexArrayDataHandle *reader) const;
 
 
 public:
 public:
-  INLINE void mark_loaded(const GeomVertexArrayDataPipelineReader *reader);
+  INLINE void mark_loaded(const GeomVertexArrayDataHandle *reader);
 
 
 private:
 private:
   // This cannot be a PT(GeomVertexArrayData), because the data and
   // This cannot be a PT(GeomVertexArrayData), because the data and

+ 5 - 4
panda/src/pgraph/geomTransformer.cxx

@@ -484,15 +484,16 @@ collect_vertex_data(Geom *geom, int collect_bits) {
   new_data->set_num_rows(new_num_vertices);
   new_data->set_num_rows(new_num_vertices);
 
 
   for (int i = 0; i < vdata->get_num_arrays(); ++i) {
   for (int i = 0; i < vdata->get_num_arrays(); ++i) {
-    GeomVertexArrayData *new_array = new_data->modify_array(i);
-    const GeomVertexArrayData *old_array = vdata->get_array(i);
+    PT(GeomVertexArrayData) new_array = new_data->modify_array(i);
+    CPT(GeomVertexArrayData) old_array = vdata->get_array(i);
     int stride = format->get_array(i)->get_stride();
     int stride = format->get_array(i)->get_stride();
     int start_byte = offset * stride;
     int start_byte = offset * stride;
     int copy_bytes = old_array->get_data_size_bytes();
     int copy_bytes = old_array->get_data_size_bytes();
     nassertr(start_byte + copy_bytes == new_array->get_data_size_bytes(), 0);
     nassertr(start_byte + copy_bytes == new_array->get_data_size_bytes(), 0);
 
 
-    memcpy(new_array->modify_data() + start_byte,
-           old_array->get_data(), copy_bytes);
+    new_array->modify_handle()->copy_subdata_from
+      (start_byte, copy_bytes, 
+       old_array->get_handle(), 0, copy_bytes);
   }
   }
 
 
   // Also, copy the animation data (if any).  This means combining
   // Also, copy the animation data (if any).  This means combining

+ 2 - 2
panda/src/pgraph/sceneGraphReducer.cxx

@@ -67,7 +67,7 @@ flatten(PandaNode *root, int combine_siblings_bits) {
     // Now visit each of the children in turn.
     // Now visit each of the children in turn.
     int num_children = cr.get_num_children();
     int num_children = cr.get_num_children();
     for (int i = 0; i < num_children; i++) {
     for (int i = 0; i < num_children; i++) {
-      PandaNode *child_node = cr.get_child(i);
+      PT(PandaNode) child_node = cr.get_child(i);
       num_pass_nodes += r_flatten(root, child_node, combine_siblings_bits);
       num_pass_nodes += r_flatten(root, child_node, combine_siblings_bits);
     }
     }
 
 
@@ -271,7 +271,7 @@ r_flatten(PandaNode *grandparent_node, PandaNode *parent_node,
       PandaNode::Children cr = parent_node->get_children();
       PandaNode::Children cr = parent_node->get_children();
       int num_children = cr.get_num_children();
       int num_children = cr.get_num_children();
       for (int i = 0; i < num_children; i++) {
       for (int i = 0; i < num_children; i++) {
-        PandaNode *child_node = cr.get_child(i);
+        PT(PandaNode) child_node = cr.get_child(i);
         num_nodes += r_flatten(parent_node, child_node, combine_siblings_bits);
         num_nodes += r_flatten(parent_node, child_node, combine_siblings_bits);
       }
       }
     }
     }

+ 2 - 2
panda/src/pstatclient/pStatClient.cxx

@@ -231,7 +231,7 @@ main_tick() {
 
 
     size_t total_usage = 0;
     size_t total_usage = 0;
     int i;
     int i;
-    for (int i = 0; i < num_typehandles; ++i) {
+    for (i = 0; i < num_typehandles; ++i) {
       TypeHandle type = type_reg->get_typehandle(i);
       TypeHandle type = type_reg->get_typehandle(i);
       for (int mi = 0; mi < (int)TypeHandle::MC_limit; ++mi) {
       for (int mi = 0; mi < (int)TypeHandle::MC_limit; ++mi) {
         TypeHandle::MemoryClass mc = (TypeHandle::MemoryClass)mi;
         TypeHandle::MemoryClass mc = (TypeHandle::MemoryClass)mi;
@@ -245,7 +245,7 @@ main_tick() {
     }
     }
     size_t other_usage = total_usage;
     size_t other_usage = total_usage;
 
 
-    for (int i = 0; i < num_typehandles; ++i) {
+    for (i = 0; i < num_typehandles; ++i) {
       TypeHandle type = type_reg->get_typehandle(i);
       TypeHandle type = type_reg->get_typehandle(i);
       for (int mi = 0; mi < (int)TypeHandle::MC_limit; ++mi) {
       for (int mi = 0; mi < (int)TypeHandle::MC_limit; ++mi) {
         TypeHandle::MemoryClass mc = (TypeHandle::MemoryClass)mi;
         TypeHandle::MemoryClass mc = (TypeHandle::MemoryClass)mi;

+ 4 - 0
panda/src/pstatclient/pStatProperties.cxx

@@ -199,6 +199,10 @@ static LevelCollectorProperties level_properties[] = {
   { 1, "Main memory",                      { 0.5, 1.0, 0.5 },  "MB", 64, 1048576 },
   { 1, "Main memory",                      { 0.5, 1.0, 0.5 },  "MB", 64, 1048576 },
   { 1, "Main memory:C++",                  { 0.2, 0.2, 1.0 } },
   { 1, "Main memory:C++",                  { 0.2, 0.2, 1.0 } },
   { 1, "Main memory:Interpreter",          { 0.8, 0.2, 0.5 } },
   { 1, "Main memory:Interpreter",          { 0.8, 0.2, 0.5 } },
+  { 1, "Vertex Data",                      { 1.0, 0.4, 0.0 },  "MB", 64, 1048576 },
+  { 1, "Vertex Data:Disk",                 { 0.6, 0.9, 0.1 } },
+  { 1, "Vertex Data:Compressed",           { 0.5, 0.1, 0.4 } },
+  { 1, "Vertex Data:Resident",             { 0.9, 0.1, 0.7 } },
   { 1, "TransformStates",                  { 1.0, 0.5, 0.5 },  "", 5000 },
   { 1, "TransformStates",                  { 1.0, 0.5, 0.5 },  "", 5000 },
   { 1, "TransformStates:On nodes",         { 0.2, 0.8, 1.0 } },
   { 1, "TransformStates:On nodes",         { 0.2, 0.8, 1.0 } },
   { 1, "TransformStates:Cached",           { 1.0, 0.0, 0.2 } },
   { 1, "TransformStates:Cached",           { 1.0, 0.0, 0.2 } },

+ 1 - 1
panda/src/putil/copyOnWritePointer.I

@@ -121,7 +121,7 @@ get_write_pointer() {
   if (_object == (CopyOnWriteObject *)NULL) {
   if (_object == (CopyOnWriteObject *)NULL) {
     return NULL;
     return NULL;
   }
   }
-  if (_object->get_ref_count() > 1) {
+  if (_object->get_cache_ref_count() > 1) {
     PT(CopyOnWriteObject) new_object = _object->make_cow_copy();
     PT(CopyOnWriteObject) new_object = _object->make_cow_copy();
     cache_unref_delete(_object);
     cache_unref_delete(_object);
     _object = new_object;
     _object = new_object;