소스 검색

split out vertexdata classes

David Rose 18 년 전
부모
커밋
5042239458

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

@@ -64,8 +64,10 @@
     userVertexSlider.I userVertexSlider.h \
     userVertexSlider.I userVertexSlider.h \
     userVertexTransform.I userVertexTransform.h \
     userVertexTransform.I userVertexTransform.h \
     vertexBufferContext.I vertexBufferContext.h \
     vertexBufferContext.I vertexBufferContext.h \
+    vertexDataBlock.I vertexDataBlock.h \
     vertexDataBook.I vertexDataBook.h \
     vertexDataBook.I vertexDataBook.h \
     vertexDataBuffer.I vertexDataBuffer.h \
     vertexDataBuffer.I vertexDataBuffer.h \
+    vertexDataPage.I vertexDataPage.h \
     vertexDataSaveFile.I vertexDataSaveFile.h \
     vertexDataSaveFile.I vertexDataSaveFile.h \
     vertexSlider.I vertexSlider.h \
     vertexSlider.I vertexSlider.h \
     vertexTransform.I vertexTransform.h \
     vertexTransform.I vertexTransform.h \
@@ -123,8 +125,10 @@
     userVertexSlider.cxx \
     userVertexSlider.cxx \
     userVertexTransform.cxx \
     userVertexTransform.cxx \
     vertexBufferContext.cxx \
     vertexBufferContext.cxx \
+    vertexDataBlock.cxx \
     vertexDataBook.cxx \
     vertexDataBook.cxx \
     vertexDataBuffer.cxx \
     vertexDataBuffer.cxx \
+    vertexDataPage.cxx \
     vertexDataSaveFile.cxx \
     vertexDataSaveFile.cxx \
     vertexSlider.cxx \
     vertexSlider.cxx \
     vertexTransform.cxx \
     vertexTransform.cxx \
@@ -186,8 +190,10 @@
     userVertexSlider.I userVertexSlider.h \
     userVertexSlider.I userVertexSlider.h \
     userVertexTransform.I userVertexTransform.h \
     userVertexTransform.I userVertexTransform.h \
     vertexBufferContext.I vertexBufferContext.h \
     vertexBufferContext.I vertexBufferContext.h \
+    vertexDataBlock.I vertexDataBlock.h \
     vertexDataBook.I vertexDataBook.h \
     vertexDataBook.I vertexDataBook.h \
     vertexDataBuffer.I vertexDataBuffer.h \
     vertexDataBuffer.I vertexDataBuffer.h \
+    vertexDataPage.I vertexDataPage.h \
     vertexDataSaveFile.I vertexDataSaveFile.h \
     vertexDataSaveFile.I vertexDataSaveFile.h \
     vertexSlider.I vertexSlider.h \
     vertexSlider.I vertexSlider.h \
     vertexTransform.I vertexTransform.h \
     vertexTransform.I vertexTransform.h \

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

@@ -51,7 +51,6 @@
 #include "transformTable.h"
 #include "transformTable.h"
 #include "userVertexSlider.h"
 #include "userVertexSlider.h"
 #include "userVertexTransform.h"
 #include "userVertexTransform.h"
-#include "vertexDataBook.h"
 #include "vertexDataBuffer.h"
 #include "vertexDataBuffer.h"
 #include "vertexTransform.h"
 #include "vertexTransform.h"
 #include "vertexSlider.h"
 #include "vertexSlider.h"

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

@@ -23,7 +23,9 @@
 #include "userVertexSlider.cxx"
 #include "userVertexSlider.cxx"
 #include "userVertexTransform.cxx"
 #include "userVertexTransform.cxx"
 #include "vertexBufferContext.cxx"
 #include "vertexBufferContext.cxx"
+#include "vertexDataBlock.cxx"
 #include "vertexDataBook.cxx"
 #include "vertexDataBook.cxx"
+#include "vertexDataPage.cxx"
 #include "vertexDataBuffer.cxx"
 #include "vertexDataBuffer.cxx"
 #include "vertexDataSaveFile.cxx"
 #include "vertexDataSaveFile.cxx"
 #include "vertexSlider.cxx"
 #include "vertexSlider.cxx"

+ 63 - 0
panda/src/gobj/vertexDataBlock.I

@@ -0,0 +1,63 @@
+// Filename: vertexDataBlock.I
+// Created by:  drose (04Jun07)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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: VertexDataBlock::Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE VertexDataBlock::
+VertexDataBlock(VertexDataPage *page, size_t start, size_t size) :
+  SimpleAllocatorBlock(page, start, size)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VertexDataBlock::get_page
+//       Access: Published
+//  Description: Returns the page from which this buffer was
+//               allocated.
+////////////////////////////////////////////////////////////////////
+INLINE VertexDataPage *VertexDataBlock::
+get_page() const {
+  return (VertexDataPage *)get_allocator();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VertexDataBlock::get_pointer
+//       Access: Public
+//  Description: Returns a pointer to the start of the allocated
+//               memory for this buffer.
+////////////////////////////////////////////////////////////////////
+INLINE unsigned char *VertexDataBlock::
+get_pointer() const {
+  nassertr(get_page() != (VertexDataPage *)NULL, NULL);
+  return get_page()->get_page_data() + get_start();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VertexDataBlock::get_next_block
+//       Access: Published
+//  Description: Returns a pointer to the next allocated block in the
+//               chain, or NULL if there are no more allocated blocks.
+////////////////////////////////////////////////////////////////////
+INLINE VertexDataBlock *VertexDataBlock::
+get_next_block() const {
+  return (VertexDataBlock *)SimpleAllocatorBlock::get_next_block();
+}

+ 19 - 0
panda/src/gobj/vertexDataBlock.cxx

@@ -0,0 +1,19 @@
+// Filename: vertexDataBlock.cxx
+// Created by:  drose (04Jun07)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "vertexDataBlock.h"

+ 51 - 0
panda/src/gobj/vertexDataBlock.h

@@ -0,0 +1,51 @@
+// Filename: vertexDataBlock.h
+// Created by:  drose (04Jun07)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 VERTEXDATABLOCK_H
+#define VERTEXDATABLOCK_H
+
+#include "pandabase.h"
+#include "simpleAllocator.h"
+#include "referenceCount.h"
+
+class VertexDataPage;
+class VertexDataBlock;
+
+////////////////////////////////////////////////////////////////////
+//       Class : VertexDataBlock
+// Description : A block of bytes that stores the actual raw vertex
+//               data referenced by a GeomVertexArrayData object.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA VertexDataBlock : public SimpleAllocatorBlock, public ReferenceCount {
+protected:
+  INLINE VertexDataBlock(VertexDataPage *page,
+                         size_t start, size_t size);
+
+PUBLISHED:
+  INLINE VertexDataPage *get_page() const;
+  INLINE VertexDataBlock *get_next_block() const;
+
+public:
+  INLINE unsigned char *get_pointer() const;
+
+  friend class VertexDataPage;
+};
+
+#include "vertexDataBlock.I"
+
+#endif

+ 0 - 177
panda/src/gobj/vertexDataBook.I

@@ -50,180 +50,3 @@ create_new_page(size_t size) {
   size_t page_size = ((size + _block_size - 1) / _block_size) * _block_size;
   size_t page_size = ((size + _block_size - 1) / _block_size) * _block_size;
   return new VertexDataPage(page_size);
   return new VertexDataPage(page_size);
 }
 }
-
-////////////////////////////////////////////////////////////////////
-//     Function: VertexDataPage::get_ram_class
-//       Access: Published
-//  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 VertexDataPage::RamClass VertexDataPage::
-get_ram_class() const {
-  return _ram_class;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: VertexDataPage::get_first_block
-//       Access: Published
-//  Description: Returns a pointer to the first allocated block, or
-//               NULL if there are no allocated blocks.
-////////////////////////////////////////////////////////////////////
-INLINE VertexDataBlock *VertexDataPage::
-get_first_block() const {
-  MutexHolder holder(_lock);
-  check_resident();
-  return (VertexDataBlock *)SimpleAllocator::get_first_block();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: VertexDataPage::get_total_page_size
-//       Access: Published, Static
-//  Description: Returns the byte count allocated to all
-//               VertexDataPages currently in existance.
-////////////////////////////////////////////////////////////////////
-INLINE size_t VertexDataPage::
-get_total_page_size() {
-  return _total_page_size;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: VertexDataPage::get_global_lru
-//       Access: Published, Static
-//  Description: Returns a pointer to the global LRU object that
-//               manages the VertexDataPage's with the indicated
-//               RamClass.
-////////////////////////////////////////////////////////////////////
-INLINE SimpleLru *VertexDataPage::
-get_global_lru(RamClass rclass) {
-  nassertr(rclass >= 0 && rclass < RC_end_of_list, NULL);
-  return _global_lru[rclass];
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: VertexDataPage::get_save_file
-//       Access: Published, Static
-//  Description: Returns the global VertexDataSaveFile that will be
-//               used to save vertex data buffers to disk when
-//               necessary.
-////////////////////////////////////////////////////////////////////
-INLINE VertexDataSaveFile *VertexDataPage::
-get_save_file() {
-  if (_save_file == (VertexDataSaveFile *)NULL) {
-    make_save_file();
-  }
-  return _save_file;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: VertexDataPage::save_to_disk
-//       Access: Published
-//  Description: Writes the page to disk, but does not evict it from
-//               memory or affect its LRU status.  If it gets evicted
-//               later without having been modified, it will not need
-//               to write itself to disk again.
-////////////////////////////////////////////////////////////////////
-INLINE bool VertexDataPage::
-save_to_disk() {
-  MutexHolder holder(_lock);
-  return do_save_to_disk();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: VertexDataPage::restore_from_disk
-//       Access: Published
-//  Description: Restores the page from disk and makes it
-//               either compressed or resident (according to whether
-//               it was stored compressed on disk).
-////////////////////////////////////////////////////////////////////
-INLINE void VertexDataPage::
-restore_from_disk() {
-  MutexHolder holder(_lock);
-  do_restore_from_disk();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: VertexDataPage::get_page_data
-//       Access: Public
-//  Description: Returns a pointer to the page's data area.
-////////////////////////////////////////////////////////////////////
-INLINE unsigned char *VertexDataPage::
-get_page_data() const {
-  MutexHolder holder(_lock);
-  check_resident();
-  return _page_data;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: VertexDataPage::check_resident
-//       Access: Private
-//  Description: Forces the vertex data into system RAM, if it is not
-//               already there; also, marks it recently-used.
-//
-//               Assumes the lock is already held.
-////////////////////////////////////////////////////////////////////
-INLINE void VertexDataPage::
-check_resident() const {
-  if (_ram_class != RC_resident) {
-    ((VertexDataPage *)this)->make_resident();
-  } else {
-    ((VertexDataPage *)this)->mark_used_lru();
-  }
-  nassertv(_size == _uncompressed_size);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: VertexDataPage::set_ram_class
-//       Access: Private
-//  Description: Puts the data in a new ram class.
-////////////////////////////////////////////////////////////////////
-INLINE void VertexDataPage::
-set_ram_class(RamClass rclass) {
-  _ram_class = rclass;
-  mark_used_lru(_global_lru[rclass]);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: VertexDataBlock::Constructor
-//       Access: Published
-//  Description: 
-////////////////////////////////////////////////////////////////////
-INLINE VertexDataBlock::
-VertexDataBlock(VertexDataPage *page, size_t start, size_t size) :
-  SimpleAllocatorBlock(page, start, size)
-{
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: VertexDataBlock::get_page
-//       Access: Published
-//  Description: Returns the page from which this buffer was
-//               allocated.
-////////////////////////////////////////////////////////////////////
-INLINE VertexDataPage *VertexDataBlock::
-get_page() const {
-  return (VertexDataPage *)get_allocator();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: VertexDataBlock::get_pointer
-//       Access: Public
-//  Description: Returns a pointer to the start of the allocated
-//               memory for this buffer.
-////////////////////////////////////////////////////////////////////
-INLINE unsigned char *VertexDataBlock::
-get_pointer() const {
-  nassertr(get_page() != (VertexDataPage *)NULL, NULL);
-  return get_page()->get_page_data() + get_start();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: VertexDataBlock::get_next_block
-//       Access: Published
-//  Description: Returns a pointer to the next allocated block in the
-//               chain, or NULL if there are no more allocated blocks.
-////////////////////////////////////////////////////////////////////
-INLINE VertexDataBlock *VertexDataBlock::
-get_next_block() const {
-  return (VertexDataBlock *)SimpleAllocatorBlock::get_next_block();
-}

+ 0 - 415
panda/src/gobj/vertexDataBook.cxx

@@ -17,63 +17,8 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
 #include "vertexDataBook.h"
 #include "vertexDataBook.h"
-#include "configVariableInt.h"
-#include "vertexDataSaveFile.h"
-#include "pStatTimer.h"
 #include "mutexHolder.h"
 #include "mutexHolder.h"
 
 
-#ifdef HAVE_ZLIB
-#include <zlib.h>
-#endif
-
-ConfigVariableInt max_resident_vertex_data
-("max-resident-vertex-data", -1,
- 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 -1 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 -1 for no limit."));
-
-ConfigVariableInt vertex_data_compression_level
-("vertex-data-compression-level", 1,
- PRC_DESC("Specifies the zlib compression level to use when compressing "
-          "vertex data.  The number should be in the range 1 to 9, where "
-          "larger values are slower but give better compression."));
-
-ConfigVariableInt max_disk_vertex_data
-("max-disk-vertex-data", -1,
- PRC_DESC("Specifies the maximum number of bytes of vertex data "
-          "that is allowed to be written to disk.  Set it to -1 for no "
-          "limit."));
-
-SimpleLru VertexDataPage::_resident_lru(max_resident_vertex_data);
-SimpleLru VertexDataPage::_compressed_lru(max_compressed_vertex_data);
-SimpleLru VertexDataPage::_disk_lru(0);
-
-SimpleLru *VertexDataPage::_global_lru[RC_end_of_list] = {
-  &VertexDataPage::_resident_lru,
-  &VertexDataPage::_compressed_lru,
-  &VertexDataPage::_disk_lru,
-};
-
-size_t VertexDataPage::_total_page_size = 0;
-VertexDataSaveFile *VertexDataPage::_save_file;
-
-PStatCollector VertexDataPage::_vdata_compress_pcollector("*:Vertex Data:Compress");
-PStatCollector VertexDataPage::_vdata_decompress_pcollector("*:Vertex Data:Decompress");
-PStatCollector VertexDataPage::_vdata_save_pcollector("*:Vertex Data:Save");
-PStatCollector VertexDataPage::_vdata_restore_pcollector("*:Vertex Data:Restore");
-
-TypeHandle VertexDataPage::_type_handle;
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: VertexDataBook::Constructor
 //     Function: VertexDataBook::Constructor
 //       Access: Published
 //       Access: Published
@@ -166,363 +111,3 @@ save_to_disk() {
   }
   }
 }
 }
 
 
-
-////////////////////////////////////////////////////////////////////
-//     Function: VertexDataPage::Constructor
-//       Access: Published
-//  Description: 
-////////////////////////////////////////////////////////////////////
-VertexDataPage::
-VertexDataPage(size_t page_size) : SimpleAllocator(page_size), SimpleLruPage(page_size) {
-  _page_data = new unsigned char[get_max_size()];
-  _size = page_size;
-  _uncompressed_size = _size;
-  _total_page_size += _size;
-  get_class_type().inc_memory_usage(TypeHandle::MC_array, (int)_size);
-  set_ram_class(RC_resident);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: VertexDataPage::Destructor
-//       Access: Published
-//  Description: 
-////////////////////////////////////////////////////////////////////
-VertexDataPage::
-~VertexDataPage() {
-  _total_page_size -= _size;
-  get_class_type().dec_memory_usage(TypeHandle::MC_array, (int)_size);
-
-  if (_page_data != NULL) {
-    delete[] _page_data;
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: VertexDataPage::alloc
-//       Access: Published
-//  Description: Allocates a new block.  Returns NULL if a block of the
-//               requested size cannot be allocated.
-//
-//               To free the allocated block, call block->free(), or
-//               simply delete the block pointer.
-////////////////////////////////////////////////////////////////////
-VertexDataBlock *VertexDataPage::
-alloc(size_t size) {
-  MutexHolder holder(_lock);
-  check_resident();
-  
-  VertexDataBlock *block = (VertexDataBlock *)SimpleAllocator::alloc(size);
-
-  if (block != (VertexDataBlock *)NULL) {
-    // When we allocate a new block within the page, we have to clear
-    // the disk cache (since we have just invalidated it).
-    _saved_block.clear();
-  }
-
-  return block;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: VertexDataPage::make_block
-//       Access: Protected, Virtual
-//  Description: Creates a new SimpleAllocatorBlock object.  Override
-//               this function to specialize the block type returned.
-////////////////////////////////////////////////////////////////////
-SimpleAllocatorBlock *VertexDataPage::
-make_block(size_t start, size_t size) {
-  return new VertexDataBlock(this, start, size);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: VertexDataPage::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 VertexDataPage::
-evict_lru() {
-  MutexHolder holder(_lock);
-
-  switch (_ram_class) {
-  case RC_resident:
-    if (_compressed_lru.get_max_size() == 0) {
-      make_disk();
-    } else {
-      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: VertexDataPage::make_resident
-//       Access: Private
-//  Description: Moves the page to fully resident status by
-//               expanding it or reading it from disk as necessary.
-//
-//               Assumes the lock is already held.
-////////////////////////////////////////////////////////////////////
-void VertexDataPage::
-make_resident() {
-  if (_ram_class == RC_resident) {
-    // If we're already resident, just mark the page recently used.
-    mark_used_lru();
-    return;
-  }
-
-  if (_ram_class == RC_disk) {
-    do_restore_from_disk();
-  }
-
-  if (_ram_class == RC_compressed) {
-#ifdef HAVE_ZLIB
-    PStatTimer timer(_vdata_decompress_pcollector);
-
-    if (gobj_cat.is_debug()) {
-      gobj_cat.debug()
-        << "Expanding page from " << _size
-        << " to " << _uncompressed_size << "\n";
-    }
-    unsigned char *new_data = new unsigned char[_uncompressed_size];
-    uLongf dest_len = _uncompressed_size;
-    int result = uncompress(new_data, &dest_len, _page_data, _size);
-    if (result != Z_OK) {
-      gobj_cat.error()
-        << "Couldn't expand: zlib error " << result << "\n";
-      nassert_raise("zlib error");
-    }
-    nassertv(dest_len == _uncompressed_size);
-
-    get_class_type().dec_memory_usage(TypeHandle::MC_array, (int)_size);
-    _total_page_size -= _size;
-
-    delete[] _page_data;
-    _page_data = new_data;
-    _size = _uncompressed_size;
-
-    get_class_type().inc_memory_usage(TypeHandle::MC_array, (int)_size);
-    _total_page_size += _size;
-  
-#endif
-    set_lru_size(_size);
-    set_ram_class(RC_resident);
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: VertexDataPage::make_compressed
-//       Access: Private
-//  Description: Moves the page to compressed status by
-//               compressing it or reading it from disk as necessary.
-//
-//               Assumes the lock is already held.
-////////////////////////////////////////////////////////////////////
-void VertexDataPage::
-make_compressed() {
-  if (_ram_class == RC_compressed) {
-    // If we're already compressed, just mark the page recently used.
-    mark_used_lru();
-    return;
-  }
-
-  if (_ram_class == RC_disk) {
-    do_restore_from_disk();
-  }
-
-  if (_ram_class == RC_resident) {
-    nassertv(_size == _uncompressed_size);
-
-#ifdef HAVE_ZLIB
-    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 = _uncompressed_size + ((_uncompressed_size + 999) / 1000) + 12;
-    Bytef *buffer = (Bytef *)alloca(buffer_size);
-
-    int result = compress2(buffer, &buffer_size,
-                           _page_data, _uncompressed_size,
-                           vertex_data_compression_level);
-    if (result != Z_OK) {
-      gobj_cat.error()
-        << "Couldn't compress: zlib error " << result << "\n";
-      nassert_raise("zlib error");
-    }
-    
-    unsigned char *new_data = new unsigned char[buffer_size];
-    memcpy(new_data, buffer, buffer_size);
-
-    get_class_type().dec_memory_usage(TypeHandle::MC_array, (int)_size);
-    _total_page_size -= _size;
-
-    delete[] _page_data;
-    _page_data = new_data;
-    _size = buffer_size;
-
-    get_class_type().inc_memory_usage(TypeHandle::MC_array, (int)_size);
-    _total_page_size += _size;
-
-    if (gobj_cat.is_debug()) {
-      gobj_cat.debug()
-        << "Compressed " << *this << " from " << _uncompressed_size
-        << " to " << _size << "\n";
-    }
-#endif
-    set_lru_size(_size);
-    set_ram_class(RC_compressed);
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: VertexDataPage::make_disk
-//       Access: Private
-//  Description: Moves the page to disk status by writing it to disk
-//               as necessary.
-//
-//               Assumes the lock is already held.
-////////////////////////////////////////////////////////////////////
-void VertexDataPage::
-make_disk() {
-  if (_ram_class == RC_disk) {
-    // If we're already on disk, just mark the page recently used.
-    mark_used_lru();
-    return;
-  }
-
-  if (_ram_class == RC_resident || _ram_class == RC_compressed) {
-    if (!do_save_to_disk()) {
-      // Can't save it to disk for some reason.
-      mark_used_lru();
-      return;
-    }
-
-    get_class_type().dec_memory_usage(TypeHandle::MC_array, (int)_size);
-    _total_page_size -= _size;
-
-    delete[] _page_data;
-    _page_data = NULL;
-    _size = 0;
-
-    set_ram_class(RC_disk);
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: VertexDataPage::do_save_to_disk
-//       Access: Private
-//  Description: Writes the page to disk, but does not evict it from
-//               memory or affect its LRU status.  If it gets evicted
-//               later without having been modified, it will not need
-//               to write itself to disk again.
-//
-//               Returns true on success, false on failure.  Assumes
-//               the lock is already held.
-////////////////////////////////////////////////////////////////////
-bool VertexDataPage::
-do_save_to_disk() {
-  if (_ram_class == RC_resident || _ram_class == RC_compressed) {
-    PStatTimer timer(_vdata_save_pcollector);
-
-    if (_saved_block == (VertexDataSaveBlock *)NULL) {
-      if (gobj_cat.is_debug()) {
-        gobj_cat.debug()
-          << "Storing page, " << _size << " bytes, to disk\n";
-      }
-
-      bool compressed = (_ram_class == RC_compressed);
-      
-      _saved_block = get_save_file()->write_data(_page_data, _size, compressed);
-      if (_saved_block == (VertexDataSaveBlock *)NULL) {
-        // Can't write it to disk.  Too bad.
-        return false;
-      }
-    } else {
-      if (gobj_cat.is_debug()) {
-        gobj_cat.debug()
-          << "Page already stored: " << _size << " bytes\n";
-      }
-    }
-  }
- 
-  return true;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: VertexDataPage::do_restore_from_disk
-//       Access: Private
-//  Description: Restores the page from disk and makes it
-//               either compressed or resident (according to whether
-//               it was stored compressed on disk).
-//
-//               Assumes the lock is already held.
-////////////////////////////////////////////////////////////////////
-void VertexDataPage::
-do_restore_from_disk() {
-  if (_ram_class == RC_disk) {
-    nassertv(_saved_block != (VertexDataSaveBlock *)NULL);
-    nassertv(_page_data == (unsigned char *)NULL && _size == 0);
-
-    PStatTimer timer(_vdata_restore_pcollector);
-
-    size_t buffer_size = _saved_block->get_size();
-    if (gobj_cat.is_debug()) {
-      gobj_cat.debug()
-        << "Restoring page, " << buffer_size << " bytes, from disk\n";
-    }
-
-    unsigned char *new_data = new unsigned char[buffer_size];
-    if (!get_save_file()->read_data(new_data, buffer_size, _saved_block)) {
-      nassert_raise("read error");
-    }
-
-    _page_data = new_data;
-    _size = buffer_size;
-
-    get_class_type().inc_memory_usage(TypeHandle::MC_array, (int)_size);
-    _total_page_size += _size;
-
-    set_lru_size(_size);
-    if (_saved_block->get_compressed()) {
-      set_ram_class(RC_compressed);
-    } else {
-      set_ram_class(RC_resident);
-    }
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: VertexDataPage::make_save_file
-//       Access: Private, Static
-//  Description: Creates the global VertexDataSaveFile that will be
-//               used to save vertex data buffers to disk when
-//               necessary.
-////////////////////////////////////////////////////////////////////
-void VertexDataPage::
-make_save_file() {
-  size_t max_size = (size_t)max_disk_vertex_data;
-
-  _save_file = new VertexDataSaveFile(vertex_save_file_directory,
-                                      vertex_save_file_prefix, max_size);
-}

+ 3 - 115
panda/src/gobj/vertexDataBook.h

@@ -16,19 +16,14 @@
 //
 //
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
-#ifndef VERTEXDATAPAGE_H
-#define VERTEXDATAPAGE_H
+#ifndef VERTEXDATABOOK_H
+#define VERTEXDATABOOK_H
 
 
 #include "pandabase.h"
 #include "pandabase.h"
-#include "simpleLru.h"
-#include "simpleAllocator.h"
-#include "referenceCount.h"
-#include "pStatCollector.h"
-#include "vertexDataSaveFile.h"
 #include "pmutex.h"
 #include "pmutex.h"
 #include "mutexHolder.h"
 #include "mutexHolder.h"
+#include "vertexDataPage.h"
 
 
-class VertexDataPage;
 class VertexDataBlock;
 class VertexDataBlock;
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -59,113 +54,6 @@ private:
   Mutex _lock;
   Mutex _lock;
 };
 };
 
 
-////////////////////////////////////////////////////////////////////
-//       Class : VertexDataPage
-// Description : A block of bytes that holds one or more
-//               VertexDataBlocks.  The entire page may be paged out,
-//               in the form of in-memory compression or to an on-disk
-//               cache file, if necessary.
-////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA VertexDataPage : public SimpleAllocator, public SimpleLruPage {
-PUBLISHED:
-  VertexDataPage(size_t page_size);
-  ~VertexDataPage();
-
-  // These are used to indicate the current residency state of the
-  // page, 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
-  };
-
-  INLINE RamClass get_ram_class() const;
-
-  VertexDataBlock *alloc(size_t size);
-  INLINE VertexDataBlock *get_first_block() const;
-
-  INLINE static size_t get_total_page_size();
-  INLINE static SimpleLru *get_global_lru(RamClass rclass);
-  INLINE static VertexDataSaveFile *get_save_file();
-
-  INLINE bool save_to_disk();
-  INLINE void restore_from_disk();
-
-public:
-  INLINE unsigned char *get_page_data() const;
-
-protected:
-  virtual SimpleAllocatorBlock *make_block(size_t start, size_t size);
-  virtual void evict_lru();
-
-private:
-  INLINE void check_resident() const;
-
-  void make_resident();
-  void make_compressed();
-  void make_disk();
-
-  bool do_save_to_disk();
-  void do_restore_from_disk();
-
-  INLINE void set_ram_class(RamClass ram_class);
-  static void make_save_file();
-
-  unsigned char *_page_data;
-  size_t _size, _uncompressed_size;
-  RamClass _ram_class;
-  PT(VertexDataSaveBlock) _saved_block;
-
-  Mutex _lock;
-
-  static SimpleLru _resident_lru;
-  static SimpleLru _compressed_lru;
-  static SimpleLru _disk_lru;
-  static SimpleLru *_global_lru[RC_end_of_list];
-
-  static size_t _total_page_size;
-  static VertexDataSaveFile *_save_file;
-
-  static PStatCollector _vdata_compress_pcollector;
-  static PStatCollector _vdata_decompress_pcollector;
-  static PStatCollector _vdata_save_pcollector;
-  static PStatCollector _vdata_restore_pcollector;
-
-public:
-  static TypeHandle get_class_type() {
-    return _type_handle;
-  }
-  static void init_type() {
-    register_type(_type_handle, "VertexDataPage");
-  }
-
-private:
-  static TypeHandle _type_handle;
-};
-
-////////////////////////////////////////////////////////////////////
-//       Class : VertexDataBlock
-// Description : A block of bytes that stores the actual raw vertex
-//               data referenced by a GeomVertexArrayData object.
-////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA VertexDataBlock : public SimpleAllocatorBlock, public ReferenceCount {
-protected:
-  INLINE VertexDataBlock(VertexDataPage *page,
-                         size_t start, size_t size);
-
-PUBLISHED:
-  INLINE VertexDataPage *get_page() const;
-  INLINE VertexDataBlock *get_next_block() const;
-
-public:
-  INLINE unsigned char *get_pointer() const;
-
-  friend class VertexDataPage;
-};
-
 #include "vertexDataBook.I"
 #include "vertexDataBook.I"
 
 
 #endif
 #endif

+ 1 - 0
panda/src/gobj/vertexDataBuffer.h

@@ -21,6 +21,7 @@
 
 
 #include "pandabase.h"
 #include "pandabase.h"
 #include "vertexDataBook.h"
 #include "vertexDataBook.h"
+#include "vertexDataBlock.h"
 #include "pointerTo.h"
 #include "pointerTo.h"
 #include "virtualFile.h"
 #include "virtualFile.h"
 #include "pStatCollector.h"
 #include "pStatCollector.h"

+ 150 - 0
panda/src/gobj/vertexDataPage.I

@@ -0,0 +1,150 @@
+// Filename: vertexDataPage.I
+// Created by:  drose (04Jun07)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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: VertexDataPage::get_ram_class
+//       Access: Published
+//  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 VertexDataPage::RamClass VertexDataPage::
+get_ram_class() const {
+  return _ram_class;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VertexDataPage::get_first_block
+//       Access: Published
+//  Description: Returns a pointer to the first allocated block, or
+//               NULL if there are no allocated blocks.
+////////////////////////////////////////////////////////////////////
+INLINE VertexDataBlock *VertexDataPage::
+get_first_block() const {
+  MutexHolder holder(_lock);
+  check_resident();
+  return (VertexDataBlock *)SimpleAllocator::get_first_block();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VertexDataPage::get_total_page_size
+//       Access: Published, Static
+//  Description: Returns the byte count allocated to all
+//               VertexDataPages currently in existance.
+////////////////////////////////////////////////////////////////////
+INLINE size_t VertexDataPage::
+get_total_page_size() {
+  return _total_page_size;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VertexDataPage::get_global_lru
+//       Access: Published, Static
+//  Description: Returns a pointer to the global LRU object that
+//               manages the VertexDataPage's with the indicated
+//               RamClass.
+////////////////////////////////////////////////////////////////////
+INLINE SimpleLru *VertexDataPage::
+get_global_lru(RamClass rclass) {
+  nassertr(rclass >= 0 && rclass < RC_end_of_list, NULL);
+  return _global_lru[rclass];
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VertexDataPage::get_save_file
+//       Access: Published, Static
+//  Description: Returns the global VertexDataSaveFile that will be
+//               used to save vertex data buffers to disk when
+//               necessary.
+////////////////////////////////////////////////////////////////////
+INLINE VertexDataSaveFile *VertexDataPage::
+get_save_file() {
+  if (_save_file == (VertexDataSaveFile *)NULL) {
+    make_save_file();
+  }
+  return _save_file;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VertexDataPage::save_to_disk
+//       Access: Published
+//  Description: Writes the page to disk, but does not evict it from
+//               memory or affect its LRU status.  If it gets evicted
+//               later without having been modified, it will not need
+//               to write itself to disk again.
+////////////////////////////////////////////////////////////////////
+INLINE bool VertexDataPage::
+save_to_disk() {
+  MutexHolder holder(_lock);
+  return do_save_to_disk();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VertexDataPage::restore_from_disk
+//       Access: Published
+//  Description: Restores the page from disk and makes it
+//               either compressed or resident (according to whether
+//               it was stored compressed on disk).
+////////////////////////////////////////////////////////////////////
+INLINE void VertexDataPage::
+restore_from_disk() {
+  MutexHolder holder(_lock);
+  do_restore_from_disk();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VertexDataPage::get_page_data
+//       Access: Public
+//  Description: Returns a pointer to the page's data area.
+////////////////////////////////////////////////////////////////////
+INLINE unsigned char *VertexDataPage::
+get_page_data() const {
+  MutexHolder holder(_lock);
+  check_resident();
+  return _page_data;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VertexDataPage::check_resident
+//       Access: Private
+//  Description: Forces the vertex data into system RAM, if it is not
+//               already there; also, marks it recently-used.
+//
+//               Assumes the lock is already held.
+////////////////////////////////////////////////////////////////////
+INLINE void VertexDataPage::
+check_resident() const {
+  if (_ram_class != RC_resident) {
+    ((VertexDataPage *)this)->make_resident();
+  } else {
+    ((VertexDataPage *)this)->mark_used_lru();
+  }
+  nassertv(_size == _uncompressed_size);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VertexDataPage::set_ram_class
+//       Access: Private
+//  Description: Puts the data in a new ram class.
+////////////////////////////////////////////////////////////////////
+INLINE void VertexDataPage::
+set_ram_class(RamClass rclass) {
+  _ram_class = rclass;
+  mark_used_lru(_global_lru[rclass]);
+}

+ 435 - 0
panda/src/gobj/vertexDataPage.cxx

@@ -0,0 +1,435 @@
+// Filename: vertexDataPage.cxx
+// Created by:  drose (04Jun07)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "vertexDataPage.h"
+#include "configVariableInt.h"
+#include "vertexDataSaveFile.h"
+#include "pStatTimer.h"
+#include "mutexHolder.h"
+
+#ifdef HAVE_ZLIB
+#include <zlib.h>
+#endif
+
+ConfigVariableInt max_resident_vertex_data
+("max-resident-vertex-data", -1,
+ 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 -1 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 -1 for no limit."));
+
+ConfigVariableInt vertex_data_compression_level
+("vertex-data-compression-level", 1,
+ PRC_DESC("Specifies the zlib compression level to use when compressing "
+          "vertex data.  The number should be in the range 1 to 9, where "
+          "larger values are slower but give better compression."));
+
+ConfigVariableInt max_disk_vertex_data
+("max-disk-vertex-data", -1,
+ PRC_DESC("Specifies the maximum number of bytes of vertex data "
+          "that is allowed to be written to disk.  Set it to -1 for no "
+          "limit."));
+
+SimpleLru VertexDataPage::_resident_lru(max_resident_vertex_data);
+SimpleLru VertexDataPage::_compressed_lru(max_compressed_vertex_data);
+SimpleLru VertexDataPage::_disk_lru(0);
+
+SimpleLru *VertexDataPage::_global_lru[RC_end_of_list] = {
+  &VertexDataPage::_resident_lru,
+  &VertexDataPage::_compressed_lru,
+  &VertexDataPage::_disk_lru,
+};
+
+size_t VertexDataPage::_total_page_size = 0;
+VertexDataSaveFile *VertexDataPage::_save_file;
+
+PStatCollector VertexDataPage::_vdata_compress_pcollector("*:Vertex Data:Compress");
+PStatCollector VertexDataPage::_vdata_decompress_pcollector("*:Vertex Data:Decompress");
+PStatCollector VertexDataPage::_vdata_save_pcollector("*:Vertex Data:Save");
+PStatCollector VertexDataPage::_vdata_restore_pcollector("*:Vertex Data:Restore");
+
+TypeHandle VertexDataPage::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: VertexDataPage::Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+VertexDataPage::
+VertexDataPage(size_t page_size) : SimpleAllocator(page_size), SimpleLruPage(page_size) {
+  _page_data = new unsigned char[get_max_size()];
+  _size = page_size;
+  _uncompressed_size = _size;
+  _total_page_size += _size;
+  get_class_type().inc_memory_usage(TypeHandle::MC_array, (int)_size);
+  set_ram_class(RC_resident);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VertexDataPage::Destructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+VertexDataPage::
+~VertexDataPage() {
+  _total_page_size -= _size;
+  get_class_type().dec_memory_usage(TypeHandle::MC_array, (int)_size);
+
+  if (_page_data != NULL) {
+    delete[] _page_data;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VertexDataPage::alloc
+//       Access: Published
+//  Description: Allocates a new block.  Returns NULL if a block of the
+//               requested size cannot be allocated.
+//
+//               To free the allocated block, call block->free(), or
+//               simply delete the block pointer.
+////////////////////////////////////////////////////////////////////
+VertexDataBlock *VertexDataPage::
+alloc(size_t size) {
+  MutexHolder holder(_lock);
+  check_resident();
+  
+  VertexDataBlock *block = (VertexDataBlock *)SimpleAllocator::alloc(size);
+
+  if (block != (VertexDataBlock *)NULL) {
+    // When we allocate a new block within the page, we have to clear
+    // the disk cache (since we have just invalidated it).
+    _saved_block.clear();
+  }
+
+  return block;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VertexDataPage::make_block
+//       Access: Protected, Virtual
+//  Description: Creates a new SimpleAllocatorBlock object.  Override
+//               this function to specialize the block type returned.
+////////////////////////////////////////////////////////////////////
+SimpleAllocatorBlock *VertexDataPage::
+make_block(size_t start, size_t size) {
+  return new VertexDataBlock(this, start, size);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VertexDataPage::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 VertexDataPage::
+evict_lru() {
+  MutexHolder holder(_lock);
+
+  switch (_ram_class) {
+  case RC_resident:
+    if (_compressed_lru.get_max_size() == 0) {
+      make_disk();
+    } else {
+      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: VertexDataPage::make_resident
+//       Access: Private
+//  Description: Moves the page to fully resident status by
+//               expanding it or reading it from disk as necessary.
+//
+//               Assumes the lock is already held.
+////////////////////////////////////////////////////////////////////
+void VertexDataPage::
+make_resident() {
+  if (_ram_class == RC_resident) {
+    // If we're already resident, just mark the page recently used.
+    mark_used_lru();
+    return;
+  }
+
+  if (_ram_class == RC_disk) {
+    do_restore_from_disk();
+  }
+
+  if (_ram_class == RC_compressed) {
+#ifdef HAVE_ZLIB
+    PStatTimer timer(_vdata_decompress_pcollector);
+
+    if (gobj_cat.is_debug()) {
+      gobj_cat.debug()
+        << "Expanding page from " << _size
+        << " to " << _uncompressed_size << "\n";
+    }
+    unsigned char *new_data = new unsigned char[_uncompressed_size];
+    uLongf dest_len = _uncompressed_size;
+    int result = uncompress(new_data, &dest_len, _page_data, _size);
+    if (result != Z_OK) {
+      gobj_cat.error()
+        << "Couldn't expand: zlib error " << result << "\n";
+      nassert_raise("zlib error");
+    }
+    nassertv(dest_len == _uncompressed_size);
+
+    get_class_type().dec_memory_usage(TypeHandle::MC_array, (int)_size);
+    _total_page_size -= _size;
+
+    delete[] _page_data;
+    _page_data = new_data;
+    _size = _uncompressed_size;
+
+    get_class_type().inc_memory_usage(TypeHandle::MC_array, (int)_size);
+    _total_page_size += _size;
+  
+#endif
+    set_lru_size(_size);
+    set_ram_class(RC_resident);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VertexDataPage::make_compressed
+//       Access: Private
+//  Description: Moves the page to compressed status by
+//               compressing it or reading it from disk as necessary.
+//
+//               Assumes the lock is already held.
+////////////////////////////////////////////////////////////////////
+void VertexDataPage::
+make_compressed() {
+  if (_ram_class == RC_compressed) {
+    // If we're already compressed, just mark the page recently used.
+    mark_used_lru();
+    return;
+  }
+
+  if (_ram_class == RC_disk) {
+    do_restore_from_disk();
+  }
+
+  if (_ram_class == RC_resident) {
+    nassertv(_size == _uncompressed_size);
+
+#ifdef HAVE_ZLIB
+    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 = _uncompressed_size + ((_uncompressed_size + 999) / 1000) + 12;
+    Bytef *buffer = (Bytef *)alloca(buffer_size);
+
+    int result = compress2(buffer, &buffer_size,
+                           _page_data, _uncompressed_size,
+                           vertex_data_compression_level);
+    if (result != Z_OK) {
+      gobj_cat.error()
+        << "Couldn't compress: zlib error " << result << "\n";
+      nassert_raise("zlib error");
+    }
+    
+    unsigned char *new_data = new unsigned char[buffer_size];
+    memcpy(new_data, buffer, buffer_size);
+
+    get_class_type().dec_memory_usage(TypeHandle::MC_array, (int)_size);
+    _total_page_size -= _size;
+
+    delete[] _page_data;
+    _page_data = new_data;
+    _size = buffer_size;
+
+    get_class_type().inc_memory_usage(TypeHandle::MC_array, (int)_size);
+    _total_page_size += _size;
+
+    if (gobj_cat.is_debug()) {
+      gobj_cat.debug()
+        << "Compressed " << *this << " from " << _uncompressed_size
+        << " to " << _size << "\n";
+    }
+#endif
+    set_lru_size(_size);
+    set_ram_class(RC_compressed);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VertexDataPage::make_disk
+//       Access: Private
+//  Description: Moves the page to disk status by writing it to disk
+//               as necessary.
+//
+//               Assumes the lock is already held.
+////////////////////////////////////////////////////////////////////
+void VertexDataPage::
+make_disk() {
+  if (_ram_class == RC_disk) {
+    // If we're already on disk, just mark the page recently used.
+    mark_used_lru();
+    return;
+  }
+
+  if (_ram_class == RC_resident || _ram_class == RC_compressed) {
+    if (!do_save_to_disk()) {
+      // Can't save it to disk for some reason.
+      mark_used_lru();
+      return;
+    }
+
+    get_class_type().dec_memory_usage(TypeHandle::MC_array, (int)_size);
+    _total_page_size -= _size;
+
+    delete[] _page_data;
+    _page_data = NULL;
+    _size = 0;
+
+    set_ram_class(RC_disk);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VertexDataPage::do_save_to_disk
+//       Access: Private
+//  Description: Writes the page to disk, but does not evict it from
+//               memory or affect its LRU status.  If it gets evicted
+//               later without having been modified, it will not need
+//               to write itself to disk again.
+//
+//               Returns true on success, false on failure.  Assumes
+//               the lock is already held.
+////////////////////////////////////////////////////////////////////
+bool VertexDataPage::
+do_save_to_disk() {
+  if (_ram_class == RC_resident || _ram_class == RC_compressed) {
+    PStatTimer timer(_vdata_save_pcollector);
+
+    if (_saved_block == (VertexDataSaveBlock *)NULL) {
+      if (gobj_cat.is_debug()) {
+        gobj_cat.debug()
+          << "Storing page, " << _size << " bytes, to disk\n";
+      }
+
+      bool compressed = (_ram_class == RC_compressed);
+      
+      _saved_block = get_save_file()->write_data(_page_data, _size, compressed);
+      if (_saved_block == (VertexDataSaveBlock *)NULL) {
+        // Can't write it to disk.  Too bad.
+        return false;
+      }
+    } else {
+      if (gobj_cat.is_debug()) {
+        gobj_cat.debug()
+          << "Page already stored: " << _size << " bytes\n";
+      }
+    }
+  }
+ 
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VertexDataPage::do_restore_from_disk
+//       Access: Private
+//  Description: Restores the page from disk and makes it
+//               either compressed or resident (according to whether
+//               it was stored compressed on disk).
+//
+//               Assumes the lock is already held.
+////////////////////////////////////////////////////////////////////
+void VertexDataPage::
+do_restore_from_disk() {
+  if (_ram_class == RC_disk) {
+    nassertv(_saved_block != (VertexDataSaveBlock *)NULL);
+    nassertv(_page_data == (unsigned char *)NULL && _size == 0);
+
+    PStatTimer timer(_vdata_restore_pcollector);
+
+    size_t buffer_size = _saved_block->get_size();
+    if (gobj_cat.is_debug()) {
+      gobj_cat.debug()
+        << "Restoring page, " << buffer_size << " bytes, from disk\n";
+    }
+
+    unsigned char *new_data = new unsigned char[buffer_size];
+    if (!get_save_file()->read_data(new_data, buffer_size, _saved_block)) {
+      nassert_raise("read error");
+    }
+
+    _page_data = new_data;
+    _size = buffer_size;
+
+    get_class_type().inc_memory_usage(TypeHandle::MC_array, (int)_size);
+    _total_page_size += _size;
+
+    set_lru_size(_size);
+    if (_saved_block->get_compressed()) {
+      set_ram_class(RC_compressed);
+    } else {
+      set_ram_class(RC_resident);
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VertexDataPage::make_save_file
+//       Access: Private, Static
+//  Description: Creates the global VertexDataSaveFile that will be
+//               used to save vertex data buffers to disk when
+//               necessary.
+////////////////////////////////////////////////////////////////////
+void VertexDataPage::
+make_save_file() {
+  size_t max_size = (size_t)max_disk_vertex_data;
+
+  _save_file = new VertexDataSaveFile(vertex_save_file_directory,
+                                      vertex_save_file_prefix, max_size);
+}

+ 121 - 0
panda/src/gobj/vertexDataPage.h

@@ -0,0 +1,121 @@
+// Filename: vertexDataPage.h
+// Created by:  drose (04Jun07)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 VERTEXDATAPAGE_H
+#define VERTEXDATAPAGE_H
+
+#include "pandabase.h"
+#include "simpleLru.h"
+#include "simpleAllocator.h"
+#include "pStatCollector.h"
+#include "vertexDataSaveFile.h"
+#include "pmutex.h"
+#include "mutexHolder.h"
+
+class VertexDataBlock;
+
+////////////////////////////////////////////////////////////////////
+//       Class : VertexDataPage
+// Description : A block of bytes that holds one or more
+//               VertexDataBlocks.  The entire page may be paged out,
+//               in the form of in-memory compression or to an on-disk
+//               cache file, if necessary.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA VertexDataPage : public SimpleAllocator, public SimpleLruPage {
+PUBLISHED:
+  VertexDataPage(size_t page_size);
+  ~VertexDataPage();
+
+  // These are used to indicate the current residency state of the
+  // page, 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
+  };
+
+  INLINE RamClass get_ram_class() const;
+
+  VertexDataBlock *alloc(size_t size);
+  INLINE VertexDataBlock *get_first_block() const;
+
+  INLINE static size_t get_total_page_size();
+  INLINE static SimpleLru *get_global_lru(RamClass rclass);
+  INLINE static VertexDataSaveFile *get_save_file();
+
+  INLINE bool save_to_disk();
+  INLINE void restore_from_disk();
+
+public:
+  INLINE unsigned char *get_page_data() const;
+
+protected:
+  virtual SimpleAllocatorBlock *make_block(size_t start, size_t size);
+  virtual void evict_lru();
+
+private:
+  INLINE void check_resident() const;
+
+  void make_resident();
+  void make_compressed();
+  void make_disk();
+
+  bool do_save_to_disk();
+  void do_restore_from_disk();
+
+  INLINE void set_ram_class(RamClass ram_class);
+  static void make_save_file();
+
+  unsigned char *_page_data;
+  size_t _size, _uncompressed_size;
+  RamClass _ram_class;
+  PT(VertexDataSaveBlock) _saved_block;
+
+  Mutex _lock;
+
+  static SimpleLru _resident_lru;
+  static SimpleLru _compressed_lru;
+  static SimpleLru _disk_lru;
+  static SimpleLru *_global_lru[RC_end_of_list];
+
+  static size_t _total_page_size;
+  static VertexDataSaveFile *_save_file;
+
+  static PStatCollector _vdata_compress_pcollector;
+  static PStatCollector _vdata_decompress_pcollector;
+  static PStatCollector _vdata_save_pcollector;
+  static PStatCollector _vdata_restore_pcollector;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    register_type(_type_handle, "VertexDataPage");
+  }
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "vertexDataPage.I"
+
+#endif