Pārlūkot izejas kodu

add VertexArrayBook::save_to_disk()

David Rose 18 gadi atpakaļ
vecāks
revīzija
fd13c10bbd

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

@@ -31,7 +31,6 @@
 #include "cycleDataStageReader.h"
 #include "cycleDataStageWriter.h"
 #include "pipelineCycler.h"
-#include "pStatCollector.h"
 #include "pmap.h"
 #include "reMutex.h"
 #include "simpleLru.h"

+ 11 - 0
panda/src/gobj/simpleAllocator.I

@@ -31,6 +31,17 @@ SimpleAllocator(size_t max_size) :
 {
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: SimpleAllocator::is_empty
+//       Access: Published
+//  Description: Returns true if there are no blocks allocated on this
+//               page, or false if there is at least one.
+////////////////////////////////////////////////////////////////////
+INLINE bool SimpleAllocator::
+is_empty() const {
+  return (_next == this);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: SimpleAllocator::get_total_size
 //       Access: Published

+ 5 - 0
panda/src/gobj/simpleAllocator.cxx

@@ -28,6 +28,7 @@ SimpleAllocator::
   // We're shutting down.  Force-free everything remaining.
   while (_next != (LinkedListNode *)this) {
     nassertv(_next != (LinkedListNode *)NULL);
+    cerr << "force-deleting " << _next << "\n";
     ((SimpleAllocatorBlock *)_next)->free();
   }
 }
@@ -65,6 +66,8 @@ alloc(size_t size) {
       size_t free_size = next->_start - end;
       if (size <= free_size) {
         SimpleAllocatorBlock *new_block = make_block(end, size);
+        nassertr(new_block->get_allocator() == this, NULL);
+
         new_block->insert_before(next);
         _total_size += size;
         return new_block;
@@ -82,6 +85,8 @@ alloc(size_t size) {
   size_t free_size = _max_size - end;
   if (size <= free_size) {
     SimpleAllocatorBlock *new_block = make_block(end, size);
+    nassertr(new_block->get_allocator() == this, NULL);
+
     new_block->insert_before(this);
     _total_size += size;
     return new_block;

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

@@ -39,6 +39,7 @@ PUBLISHED:
 
   SimpleAllocatorBlock *alloc(size_t size);
 
+  INLINE bool is_empty() const;
   INLINE size_t get_total_size() const;
   INLINE size_t get_max_size() const;
   INLINE void set_max_size(size_t max_size);

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

@@ -38,9 +38,11 @@
 #include "zStream.h"
 #include "indent.h"
 #include "cmath.h"
+#include "pStatTimer.h"
 
 #include <stddef.h>
 
+PStatCollector Texture::_texture_read_pcollector("*:Texture:Read");
 TypeHandle Texture::_type_handle;
 
 ////////////////////////////////////////////////////////////////////
@@ -1760,6 +1762,8 @@ do_read(const Filename &fullpath, const Filename &alpha_fullpath,
         int primary_file_num_channels, int alpha_file_channel,
         int z, int n, bool read_pages, bool read_mipmaps,
         bool header_only, BamCacheRecord *record) {
+  PStatTimer timer(_texture_read_pcollector);
+
   if (record != (BamCacheRecord *)NULL) {
     header_only = false;
   }

+ 3 - 0
panda/src/gobj/texture.h

@@ -29,6 +29,7 @@
 #include "updateSeq.h"
 #include "pmap.h"
 #include "config_gobj.h"
+#include "pStatCollector.h"
 
 class PNMImage;
 class TextureContext;
@@ -535,6 +536,8 @@ private:
   typedef pmap<string, PT(TypedReferenceCount) > AuxData;
   AuxData _aux_data;
 
+  static PStatCollector _texture_read_pcollector;
+
   // Datagram stuff
 public:
   static void register_with_read_factory();

+ 1 - 15
panda/src/gobj/vertexDataBook.I

@@ -79,21 +79,6 @@ check_resident() const {
   nassertv(_size == _uncompressed_size);
 }
 
-////////////////////////////////////////////////////////////////////
-//     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.
-////////////////////////////////////////////////////////////////////
-INLINE VertexDataBlock *VertexDataPage::
-alloc(size_t size) {
-  check_resident();
-  return (VertexDataBlock *)SimpleAllocator::alloc(size);
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: VertexDataPage::get_first_block
 //       Access: Published
@@ -197,6 +182,7 @@ get_page() const {
 ////////////////////////////////////////////////////////////////////
 INLINE unsigned char *VertexDataBlock::
 get_pointer() const {
+  nassertr(get_page() != (VertexDataPage *)NULL, NULL);
   return get_page()->get_page_data() + get_start();
 }
 

+ 92 - 35
panda/src/gobj/vertexDataBook.cxx

@@ -61,7 +61,6 @@ SimpleLru *VertexDataPage::_global_lru[RC_end_of_list] = {
   &VertexDataPage::_resident_lru,
   &VertexDataPage::_compressed_lru,
   &VertexDataPage::_disk_lru,
-  &VertexDataPage::_disk_lru,
 };
 
 size_t VertexDataPage::_total_page_size = 0;
@@ -110,12 +109,13 @@ alloc(size_t size) {
       _next_pi = pi;
       return block;
     }
-    if (_pages[pi]->get_total_size() == 0) {
+    if (_pages[pi]->is_empty()) {
       // This page is empty, but must have been too small.  Create a
       // new page in its place.
       delete _pages[pi];
       _pages[pi] = create_new_page(size);
-      return _pages[pi]->alloc(size);
+      VertexDataBlock *block = _pages[pi]->alloc(size);
+      return block;
     }
     ++pi;
   }
@@ -129,7 +129,7 @@ alloc(size_t size) {
       _next_pi = pi;
       return block;
     }
-    if (_pages[pi]->get_total_size() == 0) {
+    if (_pages[pi]->is_empty()) {
       // This page is empty, but must have been too small.  Create a
       // new page in its place.
       delete _pages[pi];
@@ -143,7 +143,24 @@ alloc(size_t size) {
   // large enough to hold this requested block.
   VertexDataPage *page = create_new_page(size);
   _pages.push_back(page);
-  return page->alloc(size);
+  VertexDataBlock *block = page->alloc(size);
+  return block;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VertexDataBook::save_to_disk
+//       Access: Published
+//  Description: Writes all pages to disk immediately, just in case
+//               they get evicted later.  It makes sense to make this
+//               call just before taking down a loading screen, to
+//               minimize chugs from saving pages inadvertently later.
+////////////////////////////////////////////////////////////////////
+void VertexDataBook::
+save_to_disk() {
+  Pages::iterator pi;
+  for (pi = _pages.begin(); pi != _pages.end(); ++pi) {
+    (*pi)->save_to_disk();
+  }
 }
 
 
@@ -157,7 +174,6 @@ VertexDataPage(size_t page_size) : SimpleAllocator(page_size), SimpleLruPage(pag
   _page_data = new unsigned char[get_max_size()];
   _size = page_size;
   _uncompressed_size = _size;
-  _saved_block = NULL;
   _total_page_size += _size;
   get_class_type().inc_memory_usage(TypeHandle::MC_array, _size);
   set_ram_class(RC_resident);
@@ -176,10 +192,6 @@ VertexDataPage::
   if (_page_data != NULL) {
     delete[] _page_data;
   }
-
-  if (_saved_block != (SimpleAllocatorBlock *)NULL) {
-    delete _saved_block;
-  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -196,7 +208,7 @@ make_resident() {
     return;
   }
 
-  if (_ram_class == RC_disk || _ram_class == RC_compressed_disk) {
+  if (_ram_class == RC_disk) {
     restore_from_disk();
   }
 
@@ -249,7 +261,7 @@ make_compressed() {
     return;
   }
 
-  if (_ram_class == RC_disk || _ram_class == RC_compressed_disk) {
+  if (_ram_class == RC_disk) {
     restore_from_disk();
   }
 
@@ -306,24 +318,15 @@ make_compressed() {
 ////////////////////////////////////////////////////////////////////
 void VertexDataPage::
 make_disk() {
-  if (_ram_class == RC_disk || _ram_class == RC_compressed_disk) {
-    // If we're already compressed, just mark the page recently used.
+  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) {
-    nassertv(_saved_block == (SimpleAllocatorBlock *)NULL);
-    PStatTimer timer(_vdata_save_pcollector);
-
-    if (gobj_cat.is_debug()) {
-      gobj_cat.debug()
-        << "Storing page, " << _size << " bytes, to disk\n";
-    }
-
-    _saved_block = get_save_file()->write_data(_page_data, _size);
-    if (_saved_block == NULL) {
-      // Can't write it to disk.  Too bad.
+    if (!save_to_disk()) {
+      // Can't save it to disk for some reason.
       mark_used_lru();
       return;
     }
@@ -335,12 +338,47 @@ make_disk() {
     _page_data = NULL;
     _size = 0;
 
-    if (_ram_class == RC_resident) {
-      set_ram_class(RC_disk);
+    set_ram_class(RC_disk);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     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.
+//
+//               Returns true on success, false on failure.
+////////////////////////////////////////////////////////////////////
+bool VertexDataPage::
+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 {
-      set_ram_class(RC_compressed_disk);
+      if (gobj_cat.is_debug()) {
+        gobj_cat.debug()
+          << "Page already stored: " << _size << " bytes\n";
+      }
     }
   }
+ 
+  return true;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -352,8 +390,8 @@ make_disk() {
 ////////////////////////////////////////////////////////////////////
 void VertexDataPage::
 restore_from_disk() {
-  if (_ram_class == RC_disk || _ram_class == RC_compressed_disk) {
-    nassertv(_saved_block != (VertexDataBlock *)NULL);
+  if (_ram_class == RC_disk) {
+    nassertv(_saved_block != (VertexDataSaveBlock *)NULL);
     nassertv(_page_data == (unsigned char *)NULL && _size == 0);
 
     PStatTimer timer(_vdata_restore_pcollector);
@@ -375,11 +413,8 @@ restore_from_disk() {
     get_class_type().inc_memory_usage(TypeHandle::MC_array, _size);
     _total_page_size += _size;
 
-    delete _saved_block;
-    _saved_block = NULL;
-
     set_lru_size(_size);
-    if (_ram_class == RC_compressed_disk) {
+    if (_saved_block->get_compressed()) {
       set_ram_class(RC_compressed);
     } else {
       set_ram_class(RC_resident);
@@ -387,6 +422,29 @@ restore_from_disk() {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     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) {
+  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
@@ -429,7 +487,6 @@ evict_lru() {
     break;
 
   case RC_disk:
-  case RC_compressed_disk:
     gobj_cat.warning()
       << "Cannot evict array data from disk.\n";
     break;

+ 6 - 4
panda/src/gobj/vertexDataBook.h

@@ -24,10 +24,10 @@
 #include "simpleAllocator.h"
 #include "referenceCount.h"
 #include "pStatCollector.h"
+#include "vertexDataSaveFile.h"
 
 class VertexDataPage;
 class VertexDataBlock;
-class VertexDataSaveFile;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : VertexDataBook
@@ -44,6 +44,8 @@ PUBLISHED:
   INLINE int get_num_pages() const;
   INLINE VertexDataPage *get_page(int n) const;
 
+  void save_to_disk();
+
 private:
   INLINE VertexDataPage *create_new_page(size_t size);
 
@@ -73,7 +75,6 @@ PUBLISHED:
     RC_resident,
     RC_compressed,
     RC_disk,
-    RC_compressed_disk,
 
     RC_end_of_list,  // list marker; do not use
   };
@@ -84,9 +85,10 @@ PUBLISHED:
   void make_resident();
   void make_compressed();
   void make_disk();
+  bool save_to_disk();
   void restore_from_disk();
 
-  INLINE VertexDataBlock *alloc(size_t size);
+  VertexDataBlock *alloc(size_t size);
   INLINE VertexDataBlock *get_first_block() const;
 
   INLINE static size_t get_total_page_size();
@@ -107,7 +109,7 @@ private:
   unsigned char *_page_data;
   size_t _size, _uncompressed_size;
   RamClass _ram_class;
-  SimpleAllocatorBlock *_saved_block;
+  PT(VertexDataSaveBlock) _saved_block;
 
   static SimpleLru _resident_lru;
   static SimpleLru _compressed_lru;

+ 4 - 1
panda/src/gobj/vertexDataBuffer.cxx

@@ -91,7 +91,10 @@ page_out(VertexDataBook &book) {
     // We only need to allocate a block if we don't have a source
     // file.
     _block = book.alloc(_size);
-    memcpy(_block->get_pointer(), _resident_data, _size);
+    nassertv(_block != (VertexDataBlock *)NULL);
+    unsigned char *pointer = _block->get_pointer();
+    nassertv(pointer != (unsigned char *)NULL);
+    memcpy(pointer, _resident_data, _size);
   }
 
   free(_resident_data);

+ 38 - 1
panda/src/gobj/vertexDataSaveFile.I

@@ -48,6 +48,43 @@ get_total_file_size() const {
 ////////////////////////////////////////////////////////////////////
 INLINE size_t VertexDataSaveFile::
 get_used_file_size() const {
-  return _allocator.get_total_size();
+  return SimpleAllocator::get_total_size();
 }
 
+
+////////////////////////////////////////////////////////////////////
+//     Function: VertexDataSaveBlock::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE VertexDataSaveBlock::
+VertexDataSaveBlock(VertexDataSaveFile *file, size_t start, size_t size) :
+  SimpleAllocatorBlock(file, start, size)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VertexDataSaveBlock::set_compressed
+//       Access: Public
+//  Description: Sets the compressed flag.  This is true to indicate
+//               the data is written in zlib-compressed form to the
+//               save file; false to indicate the data is
+//               uncompressed.
+////////////////////////////////////////////////////////////////////
+INLINE void VertexDataSaveBlock::
+set_compressed(bool compressed) {
+  _compressed = compressed;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VertexDataSaveBlock::get_compressed
+//       Access: Public
+//  Description: Returns the compressed flag.  This is true to
+//               indicate the data is written in zlib-compressed form
+//               to the save file; false to indicate the data is
+//               uncompressed.
+////////////////////////////////////////////////////////////////////
+INLINE bool VertexDataSaveBlock::
+get_compressed() const {
+  return _compressed;
+}

+ 20 - 9
panda/src/gobj/vertexDataSaveFile.cxx

@@ -26,7 +26,7 @@
 VertexDataSaveFile::
 VertexDataSaveFile(const Filename &directory, const string &prefix,
                    size_t max_size) :
-  _allocator(max_size)
+  SimpleAllocator(max_size)
 {
   Filename dir;
   if (directory.empty()) {
@@ -168,14 +168,15 @@ VertexDataSaveFile::
 //               cannot be written (e.g. no remaining space on the
 //               file).
 ////////////////////////////////////////////////////////////////////
-SimpleAllocatorBlock *VertexDataSaveFile::
-write_data(const unsigned char *data, size_t size) {
+PT(VertexDataSaveBlock) VertexDataSaveFile::
+write_data(const unsigned char *data, size_t size, bool compressed) {
   if (!_is_valid) {
     return NULL;
   }
 
-  SimpleAllocatorBlock *block = _allocator.alloc(size);
-  if (block != (SimpleAllocatorBlock *)NULL) {
+  PT(VertexDataSaveBlock) block = (VertexDataSaveBlock *)SimpleAllocator::alloc(size);
+  if (block != (VertexDataSaveBlock *)NULL) {
+    block->set_compressed(compressed);
 
 #ifdef _WIN32
     if (SetFilePointer(_handle, block->get_start(), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
@@ -189,7 +190,6 @@ write_data(const unsigned char *data, size_t size) {
         bytes_written != size) {
       gobj_cat.error()
         << "Error writing " << size << " bytes to save file.  Disk full?\n";
-      delete block;
       return NULL;
     }
 
@@ -201,11 +201,10 @@ write_data(const unsigned char *data, size_t size) {
       return false;
     }
 
-    ssize_t result = write(_fd, data, size);
+    ssize_t result = ::write(_fd, data, size);
     if (result != (ssize_t)size) {
       gobj_cat.error()
         << "Error writing " << size << " bytes to save file.  Disk full?\n";
-      delete block;
       return NULL;
     }
 #endif  // _WIN32
@@ -223,7 +222,7 @@ write_data(const unsigned char *data, size_t size) {
 //               on success, false on failure.
 ////////////////////////////////////////////////////////////////////
 bool VertexDataSaveFile::
-read_data(unsigned char *data, size_t size, SimpleAllocatorBlock *block) {
+read_data(unsigned char *data, size_t size, VertexDataSaveBlock *block) {
   if (!_is_valid) {
     return false;
   }
@@ -263,3 +262,15 @@ read_data(unsigned char *data, size_t size, SimpleAllocatorBlock *block) {
 
   return true;
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: VertexDataSaveFile::make_block
+//       Access: Protected, Virtual
+//  Description: Creates a new SimpleAllocatorBlock object.  Override
+//               this function to specialize the block type returned.
+////////////////////////////////////////////////////////////////////
+SimpleAllocatorBlock *VertexDataSaveFile::
+make_block(size_t start, size_t size) {
+  return new VertexDataSaveBlock(this, start, size);
+}
+

+ 31 - 4
panda/src/gobj/vertexDataSaveFile.h

@@ -28,6 +28,8 @@
 #include <windows.h>
 #endif
 
+class VertexDataSaveBlock;
+
 ////////////////////////////////////////////////////////////////////
 //       Class : VertexDataSaveFile
 // Description : A temporary file to hold the vertex data that has
@@ -35,7 +37,7 @@
 //               vertex data arrays are written into one large flat
 //               file.
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA VertexDataSaveFile {
+class EXPCL_PANDA VertexDataSaveFile : public SimpleAllocator {
 public:
   VertexDataSaveFile(const Filename &directory, const string &prefix,
                      size_t max_size);
@@ -46,12 +48,15 @@ public:
   INLINE size_t get_total_file_size() const;
   INLINE size_t get_used_file_size() const;
   
-  SimpleAllocatorBlock *write_data(const unsigned char *data, size_t size);
+  PT(VertexDataSaveBlock) write_data(const unsigned char *data, size_t size,
+                                     bool compressed);
   bool read_data(unsigned char *data, size_t size,
-                 SimpleAllocatorBlock *block);
+                 VertexDataSaveBlock *block);
+
+protected:
+  virtual SimpleAllocatorBlock *make_block(size_t start, size_t size);
 
 private:
-  SimpleAllocator _allocator;
   Filename _filename;
   bool _is_valid;
   size_t _total_file_size;
@@ -63,6 +68,28 @@ private:
 #endif  // _WIN32
 };
 
+////////////////////////////////////////////////////////////////////
+//       Class : VertexDataSaveBlock
+// Description : A block of bytes on the save file.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA VertexDataSaveBlock : public SimpleAllocatorBlock, public ReferenceCount {
+protected:
+  INLINE VertexDataSaveBlock(VertexDataSaveFile *file,
+                             size_t start, size_t size);
+
+public:
+  INLINE void set_compressed(bool compressed);
+  INLINE bool get_compressed() const;
+
+private:
+  bool _compressed;
+
+public:
+  INLINE unsigned char *get_pointer() const;
+
+  friend class VertexDataSaveFile;
+};
+
 #include "vertexDataSaveFile.I"
 
 #endif