split out vertexdata classes
This commit is contained in:
parent
e1d4257bed
commit
5042239458
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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"
|
||||
|
|
@ -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
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,63 +17,8 @@
|
|||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "vertexDataBook.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: 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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include "pandabase.h"
|
||||
#include "vertexDataBook.h"
|
||||
#include "vertexDataBlock.h"
|
||||
#include "pointerTo.h"
|
||||
#include "virtualFile.h"
|
||||
#include "pStatCollector.h"
|
||||
|
|
|
|||
|
|
@ -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]);
|
||||
}
|
||||
|
|
@ -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 <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);
|
||||
}
|
||||
|
|
@ -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
|
||||
Loading…
Reference in New Issue