diff --git a/panda/src/gobj/Sources.pp b/panda/src/gobj/Sources.pp index 7625490378..2bf6dbf423 100644 --- a/panda/src/gobj/Sources.pp +++ b/panda/src/gobj/Sources.pp @@ -64,8 +64,10 @@ userVertexSlider.I userVertexSlider.h \ userVertexTransform.I userVertexTransform.h \ vertexBufferContext.I vertexBufferContext.h \ + vertexDataBlock.I vertexDataBlock.h \ vertexDataBook.I vertexDataBook.h \ vertexDataBuffer.I vertexDataBuffer.h \ + vertexDataPage.I vertexDataPage.h \ vertexDataSaveFile.I vertexDataSaveFile.h \ vertexSlider.I vertexSlider.h \ vertexTransform.I vertexTransform.h \ @@ -123,8 +125,10 @@ userVertexSlider.cxx \ userVertexTransform.cxx \ vertexBufferContext.cxx \ + vertexDataBlock.cxx \ vertexDataBook.cxx \ vertexDataBuffer.cxx \ + vertexDataPage.cxx \ vertexDataSaveFile.cxx \ vertexSlider.cxx \ vertexTransform.cxx \ @@ -186,8 +190,10 @@ userVertexSlider.I userVertexSlider.h \ userVertexTransform.I userVertexTransform.h \ vertexBufferContext.I vertexBufferContext.h \ + vertexDataBlock.I vertexDataBlock.h \ vertexDataBook.I vertexDataBook.h \ vertexDataBuffer.I vertexDataBuffer.h \ + vertexDataPage.I vertexDataPage.h \ vertexDataSaveFile.I vertexDataSaveFile.h \ vertexSlider.I vertexSlider.h \ vertexTransform.I vertexTransform.h \ diff --git a/panda/src/gobj/config_gobj.cxx b/panda/src/gobj/config_gobj.cxx index 467495a984..ab338eb56f 100644 --- a/panda/src/gobj/config_gobj.cxx +++ b/panda/src/gobj/config_gobj.cxx @@ -51,7 +51,6 @@ #include "transformTable.h" #include "userVertexSlider.h" #include "userVertexTransform.h" -#include "vertexDataBook.h" #include "vertexDataBuffer.h" #include "vertexTransform.h" #include "vertexSlider.h" diff --git a/panda/src/gobj/gobj_composite2.cxx b/panda/src/gobj/gobj_composite2.cxx index 11d3bb212d..a063ee4a9d 100644 --- a/panda/src/gobj/gobj_composite2.cxx +++ b/panda/src/gobj/gobj_composite2.cxx @@ -23,7 +23,9 @@ #include "userVertexSlider.cxx" #include "userVertexTransform.cxx" #include "vertexBufferContext.cxx" +#include "vertexDataBlock.cxx" #include "vertexDataBook.cxx" +#include "vertexDataPage.cxx" #include "vertexDataBuffer.cxx" #include "vertexDataSaveFile.cxx" #include "vertexSlider.cxx" diff --git a/panda/src/gobj/vertexDataBlock.I b/panda/src/gobj/vertexDataBlock.I new file mode 100644 index 0000000000..a0c7a37e4a --- /dev/null +++ b/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 +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// 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(); +} diff --git a/panda/src/gobj/vertexDataBlock.cxx b/panda/src/gobj/vertexDataBlock.cxx new file mode 100644 index 0000000000..606869b0c3 --- /dev/null +++ b/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 +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#include "vertexDataBlock.h" diff --git a/panda/src/gobj/vertexDataBlock.h b/panda/src/gobj/vertexDataBlock.h new file mode 100644 index 0000000000..3046b54586 --- /dev/null +++ b/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 +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#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 diff --git a/panda/src/gobj/vertexDataBook.I b/panda/src/gobj/vertexDataBook.I index 4f16b4327d..29c60f7e71 100644 --- a/panda/src/gobj/vertexDataBook.I +++ b/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; 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(); -} diff --git a/panda/src/gobj/vertexDataBook.cxx b/panda/src/gobj/vertexDataBook.cxx index 8fa1764f81..2a4c1a728d 100644 --- a/panda/src/gobj/vertexDataBook.cxx +++ b/panda/src/gobj/vertexDataBook.cxx @@ -17,63 +17,8 @@ //////////////////////////////////////////////////////////////////// #include "vertexDataBook.h" -#include "configVariableInt.h" -#include "vertexDataSaveFile.h" -#include "pStatTimer.h" #include "mutexHolder.h" -#ifdef HAVE_ZLIB -#include -#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 // 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); -} diff --git a/panda/src/gobj/vertexDataBook.h b/panda/src/gobj/vertexDataBook.h index b4a1bc1747..cbdcea2e39 100644 --- a/panda/src/gobj/vertexDataBook.h +++ b/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 "simpleLru.h" -#include "simpleAllocator.h" -#include "referenceCount.h" -#include "pStatCollector.h" -#include "vertexDataSaveFile.h" #include "pmutex.h" #include "mutexHolder.h" +#include "vertexDataPage.h" -class VertexDataPage; class VertexDataBlock; //////////////////////////////////////////////////////////////////// @@ -59,113 +54,6 @@ private: 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" #endif diff --git a/panda/src/gobj/vertexDataBuffer.h b/panda/src/gobj/vertexDataBuffer.h index 99ff47cf96..9b3dbd6e52 100644 --- a/panda/src/gobj/vertexDataBuffer.h +++ b/panda/src/gobj/vertexDataBuffer.h @@ -21,6 +21,7 @@ #include "pandabase.h" #include "vertexDataBook.h" +#include "vertexDataBlock.h" #include "pointerTo.h" #include "virtualFile.h" #include "pStatCollector.h" diff --git a/panda/src/gobj/vertexDataPage.I b/panda/src/gobj/vertexDataPage.I new file mode 100644 index 0000000000..7d2560bb6d --- /dev/null +++ b/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 +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// 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]); +} diff --git a/panda/src/gobj/vertexDataPage.cxx b/panda/src/gobj/vertexDataPage.cxx new file mode 100644 index 0000000000..5650c668f0 --- /dev/null +++ b/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 +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#include "vertexDataPage.h" +#include "configVariableInt.h" +#include "vertexDataSaveFile.h" +#include "pStatTimer.h" +#include "mutexHolder.h" + +#ifdef HAVE_ZLIB +#include +#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); +} diff --git a/panda/src/gobj/vertexDataPage.h b/panda/src/gobj/vertexDataPage.h new file mode 100644 index 0000000000..8479534374 --- /dev/null +++ b/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 +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#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