mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 10:22:45 -04:00
better algorithm for finding available pages
This commit is contained in:
parent
68c9ef5207
commit
67771fb75c
@ -723,9 +723,11 @@ copy_data_from(const GeomVertexArrayDataHandle *other) {
|
||||
other->mark_used();
|
||||
|
||||
_cdata->_buffer.unclean_realloc(other->_cdata->_buffer.get_size());
|
||||
memcpy(_cdata->_buffer.get_write_pointer(),
|
||||
other->_cdata->_buffer.get_read_pointer(true),
|
||||
other->_cdata->_buffer.get_size());
|
||||
|
||||
unsigned char *dest = _cdata->_buffer.get_write_pointer();
|
||||
const unsigned char *source = other->_cdata->_buffer.get_read_pointer(true);
|
||||
size_t size = other->_cdata->_buffer.get_size();
|
||||
memcpy(dest, source, size);
|
||||
|
||||
_cdata->_modified = Geom::get_next_modified();
|
||||
|
||||
|
@ -23,14 +23,30 @@
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE SimpleAllocator::
|
||||
SimpleAllocator(size_t max_size) :
|
||||
SimpleAllocator(size_t max_size, Mutex &lock) :
|
||||
LinkedListNode(true),
|
||||
_total_size(0),
|
||||
_max_size(max_size),
|
||||
_contiguous(max_size)
|
||||
_contiguous(max_size),
|
||||
_lock(lock)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SimpleAllocator::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.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
SimpleAllocatorBlock *SimpleAllocator::
|
||||
alloc(size_t size) {
|
||||
MutexHolder holder(_lock);
|
||||
return do_alloc(size);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SimpleAllocator::is_empty
|
||||
// Access: Published
|
||||
@ -39,7 +55,8 @@ SimpleAllocator(size_t max_size) :
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool SimpleAllocator::
|
||||
is_empty() const {
|
||||
return (_next == this);
|
||||
MutexHolder holder(_lock);
|
||||
return do_is_empty();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -49,6 +66,7 @@ is_empty() const {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE size_t SimpleAllocator::
|
||||
get_total_size() const {
|
||||
MutexHolder holder(_lock);
|
||||
return _total_size;
|
||||
}
|
||||
|
||||
@ -59,6 +77,7 @@ get_total_size() const {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE size_t SimpleAllocator::
|
||||
get_max_size() const {
|
||||
MutexHolder holder(_lock);
|
||||
return _max_size;
|
||||
}
|
||||
|
||||
@ -71,6 +90,7 @@ get_max_size() const {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void SimpleAllocator::
|
||||
set_max_size(size_t max_size) {
|
||||
MutexHolder holder(_lock);
|
||||
_max_size = max_size;
|
||||
}
|
||||
|
||||
@ -86,6 +106,7 @@ set_max_size(size_t max_size) {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE size_t SimpleAllocator::
|
||||
get_contiguous() const {
|
||||
MutexHolder holder(_lock);
|
||||
return _contiguous;
|
||||
}
|
||||
|
||||
@ -97,15 +118,31 @@ get_contiguous() const {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE SimpleAllocatorBlock *SimpleAllocator::
|
||||
get_first_block() const {
|
||||
MutexHolder holder(_lock);
|
||||
return (_next == this) ? (SimpleAllocatorBlock *)NULL : (SimpleAllocatorBlock *)_next;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SimpleAllocator::increase_contiguous
|
||||
// Function: SimpleAllocator::do_is_empty
|
||||
// Access: Protected
|
||||
// Description: Returns true if there are no blocks allocated on this
|
||||
// page, or false if there is at least one.
|
||||
//
|
||||
// Assumes the lock is already held.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool SimpleAllocator::
|
||||
do_is_empty() const {
|
||||
return (_next == this);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SimpleAllocator::mark_contiguous
|
||||
// Access: Protected
|
||||
// Description: Some space has been made available following the
|
||||
// indicated block. Increase the contiguous space
|
||||
// accordingly.
|
||||
//
|
||||
// Assumes the lock is already held.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void SimpleAllocator::
|
||||
mark_contiguous(const LinkedListNode *block) {
|
||||
@ -119,10 +156,11 @@ mark_contiguous(const LinkedListNode *block) {
|
||||
space = ((SimpleAllocatorBlock *)_next)->get_start();
|
||||
}
|
||||
} else {
|
||||
space = ((SimpleAllocatorBlock *)block)->get_max_size() - ((SimpleAllocatorBlock *)block)->get_size();
|
||||
space = ((SimpleAllocatorBlock *)block)->do_get_max_size() - ((SimpleAllocatorBlock *)block)->get_size();
|
||||
}
|
||||
if (space > _contiguous) {
|
||||
_contiguous = space;
|
||||
changed_contiguous();
|
||||
}
|
||||
}
|
||||
|
||||
@ -160,11 +198,8 @@ INLINE SimpleAllocatorBlock::
|
||||
INLINE void SimpleAllocatorBlock::
|
||||
free() {
|
||||
if (_allocator != (SimpleAllocator *)NULL) {
|
||||
_allocator->_total_size -= _size;
|
||||
LinkedListNode *prev = _prev;
|
||||
remove_from_list();
|
||||
_allocator->mark_contiguous(prev);
|
||||
_allocator = NULL;
|
||||
MutexHolder holder(_allocator->_lock);
|
||||
do_free();
|
||||
}
|
||||
}
|
||||
|
||||
@ -223,14 +258,8 @@ is_free() const {
|
||||
INLINE size_t SimpleAllocatorBlock::
|
||||
get_max_size() const {
|
||||
nassertr(_allocator != (SimpleAllocator *)NULL, 0);
|
||||
|
||||
size_t end;
|
||||
if (_next == _allocator) {
|
||||
end = _allocator->get_max_size();
|
||||
} else {
|
||||
end = ((SimpleAllocatorBlock *)_next)->_start;
|
||||
}
|
||||
return end - _start;
|
||||
MutexHolder holder(_allocator->_lock);
|
||||
return do_get_max_size();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -242,7 +271,73 @@ get_max_size() const {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool SimpleAllocatorBlock::
|
||||
realloc(size_t size) {
|
||||
if (size > get_max_size()) {
|
||||
nassertr(_allocator != (SimpleAllocator *)NULL, false);
|
||||
MutexHolder holder(_allocator->_lock);
|
||||
return do_realloc(size);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SimpleAllocatorBlock::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 SimpleAllocatorBlock *SimpleAllocatorBlock::
|
||||
get_next_block() const {
|
||||
nassertr(_allocator != (SimpleAllocator *)NULL, NULL);
|
||||
MutexHolder holder(_allocator->_lock);
|
||||
return (_next == _allocator) ? (SimpleAllocatorBlock *)NULL : (SimpleAllocatorBlock *)_next;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SimpleAllocatorBlock::do_free
|
||||
// Access: Protected
|
||||
// Description: Releases the allocated space.
|
||||
//
|
||||
// Assumes the lock is already held.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void SimpleAllocatorBlock::
|
||||
do_free() {
|
||||
nassertv(_allocator != (SimpleAllocator *)NULL);
|
||||
|
||||
_allocator->_total_size -= _size;
|
||||
LinkedListNode *prev = _prev;
|
||||
remove_from_list();
|
||||
_allocator->mark_contiguous(prev);
|
||||
_allocator = NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SimpleAllocatorBlock::do_get_max_size
|
||||
// Access: Protected
|
||||
// Description: Returns the maximum size this block can be
|
||||
// reallocated to, as limited by the following block.
|
||||
//
|
||||
// Assumes the lock is already held.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE size_t SimpleAllocatorBlock::
|
||||
do_get_max_size() const {
|
||||
size_t end;
|
||||
if (_next == _allocator) {
|
||||
end = _allocator->_max_size;
|
||||
} else {
|
||||
end = ((SimpleAllocatorBlock *)_next)->_start;
|
||||
}
|
||||
return end - _start;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SimpleAllocatorBlock::do_realloc
|
||||
// Access: Protected
|
||||
// Description: Changes the size of this block to the specified size.
|
||||
// Returns true if the change is accepted, false if
|
||||
// there was not enough room.
|
||||
//
|
||||
// Assumes the lock is already held.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool SimpleAllocatorBlock::
|
||||
do_realloc(size_t size) {
|
||||
if (size > do_get_max_size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -259,14 +354,3 @@ realloc(size_t size) {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SimpleAllocatorBlock::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 SimpleAllocatorBlock *SimpleAllocatorBlock::
|
||||
get_next_block() const {
|
||||
return (_next == _allocator) ? (SimpleAllocatorBlock *)NULL : (SimpleAllocatorBlock *)_next;
|
||||
}
|
||||
|
@ -26,24 +26,60 @@
|
||||
SimpleAllocator::
|
||||
~SimpleAllocator() {
|
||||
// We're shutting down. Force-free everything remaining.
|
||||
while (_next != (LinkedListNode *)this) {
|
||||
nassertv(_next != (LinkedListNode *)NULL);
|
||||
cerr << "force-deleting " << _next << "\n";
|
||||
((SimpleAllocatorBlock *)_next)->free();
|
||||
if (_next != (LinkedListNode *)this) {
|
||||
MutexHolder holder(_lock);
|
||||
while (_next != (LinkedListNode *)this) {
|
||||
nassertv(_next != (LinkedListNode *)NULL);
|
||||
((SimpleAllocatorBlock *)_next)->do_free();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SimpleAllocator::alloc
|
||||
// Function: SimpleAllocator::output
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void SimpleAllocator::
|
||||
output(ostream &out) const {
|
||||
MutexHolder holder(_lock);
|
||||
out << "SimpleAllocator, " << _total_size << " of " << _max_size
|
||||
<< " allocated";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SimpleAllocator::write
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void SimpleAllocator::
|
||||
write(ostream &out) const {
|
||||
MutexHolder holder(_lock);
|
||||
out << "SimpleAllocator, " << _total_size << " of " << _max_size
|
||||
<< " allocated";
|
||||
|
||||
SimpleAllocatorBlock *block = (SimpleAllocatorBlock *)_next;
|
||||
while (block->_next != this) {
|
||||
SimpleAllocatorBlock *next = (SimpleAllocatorBlock *)block->_next;
|
||||
|
||||
out << " " << *block << "\n";
|
||||
block = next;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SimpleAllocator::do_alloc
|
||||
// Access: Protected
|
||||
// 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.
|
||||
//
|
||||
// Assumes the lock is already held.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
SimpleAllocatorBlock *SimpleAllocator::
|
||||
alloc(size_t size) {
|
||||
do_alloc(size_t size) {
|
||||
if (size > _contiguous) {
|
||||
// Don't even bother.
|
||||
return NULL;
|
||||
@ -70,6 +106,14 @@ alloc(size_t size) {
|
||||
|
||||
new_block->insert_before(next);
|
||||
_total_size += size;
|
||||
|
||||
if (_max_size - _total_size < _contiguous) {
|
||||
// Since we only have (_max_size - _total_size) bytes
|
||||
// remaining, it follows that our largest contiguous block
|
||||
// must be no larger than this.
|
||||
_contiguous = _max_size - _total_size;
|
||||
changed_contiguous();
|
||||
}
|
||||
return new_block;
|
||||
}
|
||||
if (free_size > best) {
|
||||
@ -89,6 +133,14 @@ alloc(size_t size) {
|
||||
|
||||
new_block->insert_before(this);
|
||||
_total_size += size;
|
||||
|
||||
if (_max_size - _total_size < _contiguous) {
|
||||
// Since we only have (_max_size - _total_size) bytes
|
||||
// remaining, it follows that our largest contiguous block
|
||||
// must be no larger than this.
|
||||
_contiguous = _max_size - _total_size;
|
||||
changed_contiguous();
|
||||
}
|
||||
return new_block;
|
||||
}
|
||||
|
||||
@ -98,56 +150,15 @@ alloc(size_t size) {
|
||||
|
||||
// Now that we've walked through the entire list of blocks, we
|
||||
// really do know accurately what the largest contiguous block is.
|
||||
_contiguous = best;
|
||||
if (_contiguous != best) {
|
||||
_contiguous = best;
|
||||
changed_contiguous();
|
||||
}
|
||||
|
||||
// No room for this block.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SimpleAllocator::output
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void SimpleAllocator::
|
||||
output(ostream &out) const {
|
||||
out << "SimpleAllocator, " << _total_size << " of " << _max_size
|
||||
<< " allocated";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SimpleAllocatorBlock::output
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void SimpleAllocatorBlock::
|
||||
output(ostream &out) const {
|
||||
if (_allocator == (SimpleAllocator *)NULL) {
|
||||
out << "free block\n";
|
||||
} else {
|
||||
out << "block of size " << _size << " at " << _start;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SimpleAllocator::write
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void SimpleAllocator::
|
||||
write(ostream &out) const {
|
||||
out << *this << ":\n";
|
||||
|
||||
SimpleAllocatorBlock *block = (SimpleAllocatorBlock *)_next;
|
||||
while (block->_next != this) {
|
||||
SimpleAllocatorBlock *next = (SimpleAllocatorBlock *)block->_next;
|
||||
|
||||
out << " " << *block << "\n";
|
||||
block = next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SimpleAllocator::make_block
|
||||
// Access: Protected, Virtual
|
||||
@ -159,3 +170,28 @@ make_block(size_t start, size_t size) {
|
||||
return new SimpleAllocatorBlock(this, start, size);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SimpleAllocator::changed_contiguous
|
||||
// Access: Protected, Virtual
|
||||
// Description: This callback function is made whenever the estimate
|
||||
// of contiguous available space changes, either through
|
||||
// an alloc or free. The lock will be held.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void SimpleAllocator::
|
||||
changed_contiguous() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SimpleAllocatorBlock::output
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void SimpleAllocatorBlock::
|
||||
output(ostream &out) const {
|
||||
if (_allocator == (SimpleAllocator *)NULL) {
|
||||
out << "free block\n";
|
||||
} else {
|
||||
MutexHolder holder(_allocator->_lock);
|
||||
out << "block of size " << _size << " at " << _start;
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,8 @@
|
||||
|
||||
#include "pandabase.h"
|
||||
#include "linkedListNode.h"
|
||||
#include "pmutex.h"
|
||||
#include "mutexHolder.h"
|
||||
|
||||
class SimpleAllocatorBlock;
|
||||
|
||||
@ -31,17 +33,13 @@ class SimpleAllocatorBlock;
|
||||
// integers within a specified upper limit; it uses a
|
||||
// simple first-fit algorithm to find the next available
|
||||
// space.
|
||||
//
|
||||
// Note that this class is not inherently thread-safe;
|
||||
// derived classes are responsible for protecting any
|
||||
// calls into it within mutexes, if necessary.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA SimpleAllocator : public LinkedListNode {
|
||||
PUBLISHED:
|
||||
INLINE SimpleAllocator(size_t max_size);
|
||||
INLINE SimpleAllocator(size_t max_size, Mutex &lock);
|
||||
virtual ~SimpleAllocator();
|
||||
|
||||
SimpleAllocatorBlock *alloc(size_t size);
|
||||
INLINE SimpleAllocatorBlock *alloc(size_t size);
|
||||
|
||||
INLINE bool is_empty() const;
|
||||
INLINE size_t get_total_size() const;
|
||||
@ -55,10 +53,14 @@ PUBLISHED:
|
||||
void write(ostream &out) const;
|
||||
|
||||
protected:
|
||||
SimpleAllocatorBlock *do_alloc(size_t size);
|
||||
INLINE bool do_is_empty() const;
|
||||
|
||||
virtual SimpleAllocatorBlock *make_block(size_t start, size_t size);
|
||||
INLINE void mark_contiguous(const LinkedListNode *block);
|
||||
virtual void changed_contiguous();
|
||||
|
||||
private:
|
||||
protected:
|
||||
// This is implemented as a linked-list chain of allocated blocks.
|
||||
// Free blocks are implicit. Blocks are kept in sorted order from
|
||||
// beginning to end. Allocating a block means creating a new entry
|
||||
@ -76,6 +78,16 @@ private:
|
||||
// it will not be smaller.
|
||||
size_t _contiguous;
|
||||
|
||||
// This mutex protects all operations within this class. The caller
|
||||
// must pass the reference to a mutex in to the constructor, and the
|
||||
// caller remains responsible for owning the mutex. This allows the
|
||||
// mutex to be shared where appropriate.
|
||||
|
||||
// A derived class may also use it to protect itself as well, but
|
||||
// take care to call do_alloc() instead of alloc() etc. as
|
||||
// necessary.
|
||||
Mutex &_lock;
|
||||
|
||||
friend class SimpleAllocatorBlock;
|
||||
};
|
||||
|
||||
@ -106,6 +118,11 @@ PUBLISHED:
|
||||
|
||||
void output(ostream &out) const;
|
||||
|
||||
protected:
|
||||
INLINE void do_free();
|
||||
INLINE size_t do_get_max_size() const;
|
||||
INLINE bool do_realloc(size_t size);
|
||||
|
||||
private:
|
||||
SimpleAllocator *_allocator;
|
||||
size_t _start;
|
||||
|
@ -17,6 +17,18 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexDataBook::alloc
|
||||
// Access: Published
|
||||
// Description: Allocates and returns a new VertexDataBuffer of the
|
||||
// requested size.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE VertexDataBlock *VertexDataBook::
|
||||
alloc(size_t size) {
|
||||
MutexHolder holder(_lock);
|
||||
return do_alloc(size);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexDataBook::get_num_pages
|
||||
// Access: Published
|
||||
@ -27,17 +39,6 @@ get_num_pages() const {
|
||||
return _pages.size();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexDataBook::get_page
|
||||
// Access: Published
|
||||
// Description: Returns the nth page created for the book.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE VertexDataPage *VertexDataBook::
|
||||
get_page(int n) const {
|
||||
nassertr(n >= 0 && n < (int)_pages.size(), NULL);
|
||||
return _pages[n];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexDataBook::create_new_page
|
||||
// Access: Private
|
||||
|
@ -17,7 +17,7 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "vertexDataBook.h"
|
||||
#include "mutexHolder.h"
|
||||
#include "reMutexHolder.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexDataBook::Constructor
|
||||
@ -26,7 +26,6 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
VertexDataBook::
|
||||
VertexDataBook(size_t block_size) : _block_size(block_size) {
|
||||
_next_pi = 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -38,71 +37,6 @@ VertexDataBook::
|
||||
~VertexDataBook() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexDataBook::alloc
|
||||
// Access: Published
|
||||
// Description: Allocates and returns a new VertexDataBuffer of the
|
||||
// requested size.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
VertexDataBlock *VertexDataBook::
|
||||
alloc(size_t size) {
|
||||
MutexHolder holder(_lock);
|
||||
|
||||
// First, try to allocate from the last page that worked; then
|
||||
// continue to the end of the list. We consider only pages that are
|
||||
// currently resident (or that are empty), to minimize unnecessary
|
||||
// swapping.
|
||||
size_t pi = _next_pi;
|
||||
while (pi < _pages.size()) {
|
||||
if (_pages[pi]->get_ram_class() == VertexDataPage::RC_resident ||
|
||||
_pages[pi]->is_empty()) {
|
||||
VertexDataBlock *block = _pages[pi]->alloc(size);
|
||||
if (block != (VertexDataBlock *)NULL) {
|
||||
_next_pi = pi;
|
||||
return block;
|
||||
}
|
||||
if (_pages[pi]->is_empty()) {
|
||||
// This page is empty, but must have been too small. Create a
|
||||
// new page in its place.
|
||||
delete _pages[pi];
|
||||
_pages[pi] = create_new_page(size);
|
||||
VertexDataBlock *block = _pages[pi]->alloc(size);
|
||||
return block;
|
||||
}
|
||||
}
|
||||
++pi;
|
||||
}
|
||||
|
||||
// Then, go back to the beginning and try those pages.
|
||||
pi = 0;
|
||||
_next_pi = min(_next_pi, _pages.size());
|
||||
while (pi < _next_pi) {
|
||||
if (_pages[pi]->get_ram_class() == VertexDataPage::RC_resident ||
|
||||
_pages[pi]->is_empty()) {
|
||||
VertexDataBlock *block = _pages[pi]->alloc(size);
|
||||
if (block != (VertexDataBlock *)NULL) {
|
||||
_next_pi = pi;
|
||||
return block;
|
||||
}
|
||||
if (_pages[pi]->is_empty()) {
|
||||
// This page is empty, but must have been too small. Create a
|
||||
// new page in its place.
|
||||
delete _pages[pi];
|
||||
_pages[pi] = create_new_page(size);
|
||||
return _pages[pi]->alloc(size);
|
||||
}
|
||||
}
|
||||
++pi;
|
||||
}
|
||||
|
||||
// No page was good enough. Create a new page. Make it at least
|
||||
// large enough to hold this requested block.
|
||||
VertexDataPage *page = create_new_page(size);
|
||||
_pages.push_back(page);
|
||||
VertexDataBlock *block = page->alloc(size);
|
||||
return block;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexDataBook::count_total_page_size
|
||||
// Access: Published
|
||||
@ -111,6 +45,8 @@ alloc(size_t size) {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
size_t VertexDataBook::
|
||||
count_total_page_size() const {
|
||||
MutexHolder holder(_lock);
|
||||
|
||||
size_t total = 0;
|
||||
Pages::const_iterator pi;
|
||||
for (pi = _pages.begin(); pi != _pages.end(); ++pi) {
|
||||
@ -128,6 +64,8 @@ count_total_page_size() const {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
size_t VertexDataBook::
|
||||
count_total_page_size(VertexDataPage::RamClass ram_class) const {
|
||||
MutexHolder holder(_lock);
|
||||
|
||||
size_t total = 0;
|
||||
Pages::const_iterator pi;
|
||||
for (pi = _pages.begin(); pi != _pages.end(); ++pi) {
|
||||
@ -146,6 +84,8 @@ count_total_page_size(VertexDataPage::RamClass ram_class) const {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
size_t VertexDataBook::
|
||||
count_allocated_size() const {
|
||||
MutexHolder holder(_lock);
|
||||
|
||||
size_t total = 0;
|
||||
Pages::const_iterator pi;
|
||||
for (pi = _pages.begin(); pi != _pages.end(); ++pi) {
|
||||
@ -163,6 +103,8 @@ count_allocated_size() const {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
size_t VertexDataBook::
|
||||
count_allocated_size(VertexDataPage::RamClass ram_class) const {
|
||||
MutexHolder holder(_lock);
|
||||
|
||||
size_t total = 0;
|
||||
Pages::const_iterator pi;
|
||||
for (pi = _pages.begin(); pi != _pages.end(); ++pi) {
|
||||
@ -183,9 +125,61 @@ count_allocated_size(VertexDataPage::RamClass ram_class) const {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void VertexDataBook::
|
||||
save_to_disk() {
|
||||
MutexHolder holder(_lock);
|
||||
|
||||
Pages::iterator pi;
|
||||
for (pi = _pages.begin(); pi != _pages.end(); ++pi) {
|
||||
(*pi)->save_to_disk();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexDataBook::do_alloc
|
||||
// Access: Private
|
||||
// Description: Allocates and returns a new VertexDataBuffer of the
|
||||
// requested size.
|
||||
//
|
||||
// Assumes the lock is already held.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
VertexDataBlock *VertexDataBook::
|
||||
do_alloc(size_t size) {
|
||||
// Look for an empty page of the appropriate size. The _pages set
|
||||
// is sorted so that the pages with the smallest available blocks
|
||||
// are at the front.
|
||||
|
||||
// Create a dummy page to use to search the set.
|
||||
VertexDataPage size_page(size);
|
||||
Pages::iterator pi = _pages.lower_bound(&size_page);
|
||||
|
||||
// Now we can start from the first element of the set that is
|
||||
// possibly large enough to contain this block, and work up from
|
||||
// there.
|
||||
while (pi != _pages.end()) {
|
||||
Pages::iterator pnext = pi;
|
||||
++pnext;
|
||||
|
||||
VertexDataPage *page = (*pi);
|
||||
|
||||
// Allocating a block may change the page's available contiguous
|
||||
// size, and thereby change its position in the set, invalidating
|
||||
// the iterator pi. This is why we've already computed pnext.
|
||||
VertexDataBlock *block = page->do_alloc(size);
|
||||
|
||||
if (block != (VertexDataBlock *)NULL) {
|
||||
// This page worked.
|
||||
return block;
|
||||
}
|
||||
|
||||
// Try the next page.
|
||||
pi = pnext;
|
||||
}
|
||||
|
||||
// No page was good enough. Create a new page. Make it at least
|
||||
// large enough to hold this requested block.
|
||||
VertexDataPage *page = create_new_page(size);
|
||||
_pages.insert(page);
|
||||
|
||||
VertexDataBlock *block = page->do_alloc(size);
|
||||
return block;
|
||||
}
|
||||
|
@ -23,6 +23,8 @@
|
||||
#include "pmutex.h"
|
||||
#include "mutexHolder.h"
|
||||
#include "vertexDataPage.h"
|
||||
#include "indirectLess.h"
|
||||
#include "plist.h"
|
||||
|
||||
class VertexDataBlock;
|
||||
|
||||
@ -36,10 +38,9 @@ PUBLISHED:
|
||||
VertexDataBook(size_t block_size);
|
||||
~VertexDataBook();
|
||||
|
||||
VertexDataBlock *alloc(size_t size);
|
||||
INLINE VertexDataBlock *alloc(size_t size);
|
||||
|
||||
INLINE int get_num_pages() const;
|
||||
INLINE VertexDataPage *get_page(int n) const;
|
||||
|
||||
size_t count_total_page_size() const;
|
||||
size_t count_total_page_size(VertexDataPage::RamClass ram_class) const;
|
||||
@ -48,15 +49,21 @@ PUBLISHED:
|
||||
|
||||
void save_to_disk();
|
||||
|
||||
public:
|
||||
void reorder_page(VertexDataPage *page);
|
||||
|
||||
private:
|
||||
INLINE VertexDataPage *create_new_page(size_t size);
|
||||
VertexDataBlock *do_alloc(size_t size);
|
||||
|
||||
private:
|
||||
size_t _block_size;
|
||||
typedef pvector<VertexDataPage *> Pages;
|
||||
|
||||
typedef pset<VertexDataPage *, IndirectLess<VertexDataPage> > Pages;
|
||||
Pages _pages;
|
||||
size_t _next_pi;
|
||||
|
||||
Mutex _lock;
|
||||
friend class VertexDataPage;
|
||||
};
|
||||
|
||||
#include "vertexDataBook.I"
|
||||
|
@ -141,7 +141,7 @@ clean_realloc(size_t size) {
|
||||
INLINE void VertexDataBuffer::
|
||||
unclean_realloc(size_t size) {
|
||||
MutexHolder holder(_lock);
|
||||
do_clean_realloc(size);
|
||||
do_unclean_realloc(size);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
@ -59,6 +59,21 @@ request_resident() {
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexDataPage::alloc
|
||||
// Access: Published
|
||||
// Description: Allocates a new block. Returns NULL if a block of the
|
||||
// requested size cannot be allocated.
|
||||
//
|
||||
// To free the allocated block, call block->free(), or
|
||||
// simply delete the block pointer.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE VertexDataBlock *VertexDataPage::
|
||||
alloc(size_t size) {
|
||||
MutexHolder holder(_lock);
|
||||
return do_alloc(size);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexDataPage::get_first_block
|
||||
// Access: Published
|
||||
@ -164,7 +179,7 @@ has_thread() {
|
||||
INLINE unsigned char *VertexDataPage::
|
||||
get_page_data(bool force) {
|
||||
MutexHolder holder(_lock);
|
||||
if (_ram_class != RC_resident) {
|
||||
if (_ram_class != RC_resident || _pending_ram_class != RC_resident) {
|
||||
if (force) {
|
||||
make_resident_now();
|
||||
} else {
|
||||
@ -180,6 +195,26 @@ get_page_data(bool force) {
|
||||
return _page_data;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexDataPage::operator
|
||||
// Access: Public
|
||||
// Description: This comparison method is used to order pages within
|
||||
// a book.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool VertexDataPage::
|
||||
operator < (const VertexDataPage &other) const {
|
||||
// We sort pages so that the pages with the smallest number of
|
||||
// available contiguous bytes come up first. We store our best
|
||||
// estimate of continguous bytes here.
|
||||
if (_book_size != other._book_size) {
|
||||
return _book_size < other._book_size;
|
||||
}
|
||||
|
||||
// For pages of equal size, we sort based on pointers, to make it
|
||||
// easy to quickly find a specific page.
|
||||
return this < &other;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexDataPage::set_ram_class
|
||||
// Access: Private
|
||||
@ -190,6 +225,10 @@ INLINE void VertexDataPage::
|
||||
set_ram_class(RamClass rclass) {
|
||||
_ram_class = rclass;
|
||||
mark_used_lru(_global_lru[rclass]);
|
||||
|
||||
// Changing the ram class might make our effective available space 0
|
||||
// and thereby change the placement within the book.
|
||||
adjust_book_size();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
@ -71,6 +71,10 @@ SimpleLru *VertexDataPage::_global_lru[RC_end_of_list] = {
|
||||
|
||||
VertexDataSaveFile *VertexDataPage::_save_file;
|
||||
|
||||
// This mutex is (mostly) unused. We just need a Mutex to pass to the
|
||||
// Book Constructor, below.
|
||||
Mutex VertexDataPage::_unused_mutex;
|
||||
|
||||
PStatCollector VertexDataPage::_vdata_compress_pcollector("*:Vertex Data:Compress");
|
||||
PStatCollector VertexDataPage::_vdata_decompress_pcollector("*:Vertex Data:Decompress");
|
||||
PStatCollector VertexDataPage::_vdata_save_pcollector("*:Vertex Data:Save");
|
||||
@ -79,19 +83,39 @@ PStatCollector VertexDataPage::_thread_wait_pcollector("*:Wait:Idle");
|
||||
|
||||
TypeHandle VertexDataPage::_type_handle;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexDataPage::Book Constructor
|
||||
// Access: Public
|
||||
// Description: This constructor is used only by VertexDataBook, to
|
||||
// create a mostly-empty object that can be used to
|
||||
// search for a particular page size in the set.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
VertexDataPage::
|
||||
VertexDataPage(size_t book_size) :
|
||||
SimpleAllocator(book_size, _unused_mutex),
|
||||
SimpleLruPage(book_size),
|
||||
_book_size(book_size),
|
||||
_book(NULL)
|
||||
{
|
||||
_page_data = NULL;
|
||||
_size = 0;
|
||||
_uncompressed_size = 0;
|
||||
_ram_class = RC_resident;
|
||||
_pending_ram_class = RC_resident;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexDataPage::Constructor
|
||||
// Access: Published
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
VertexDataPage::
|
||||
VertexDataPage(VertexDataBook *book, size_t page_size) :
|
||||
SimpleAllocator(page_size),
|
||||
SimpleAllocator(page_size, book->_lock),
|
||||
SimpleLruPage(page_size),
|
||||
_book_size(page_size),
|
||||
_book(book)
|
||||
{
|
||||
nassertv(page_size == get_max_size());
|
||||
|
||||
get_class_type().inc_memory_usage(TypeHandle::MC_array, (int)page_size);
|
||||
_page_data = new unsigned char[page_size];
|
||||
_size = page_size;
|
||||
@ -103,12 +127,15 @@ VertexDataPage(VertexDataBook *book, size_t page_size) :
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexDataPage::Destructor
|
||||
// Access: Published
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
VertexDataPage::
|
||||
~VertexDataPage() {
|
||||
MutexHolder holder(_lock);
|
||||
|
||||
// Since the only way to delete a page is via the
|
||||
// changed_contiguous() method, the lock will already be held.
|
||||
// MutexHolder holder(_lock);
|
||||
|
||||
{
|
||||
MutexHolder holder2(_tlock);
|
||||
@ -125,29 +152,6 @@ VertexDataPage::
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// 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);
|
||||
VertexDataBlock *block = (VertexDataBlock *)SimpleAllocator::alloc(size);
|
||||
|
||||
if (block != (VertexDataBlock *)NULL && _ram_class != RC_disk) {
|
||||
// When we allocate a new block within a resident page, we have to
|
||||
// clear the disk cache (since we have just invalidated it).
|
||||
_saved_block.clear();
|
||||
}
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexDataPage::stop_thread
|
||||
// Access: Published, Static
|
||||
@ -182,6 +186,27 @@ make_block(size_t start, size_t size) {
|
||||
return new VertexDataBlock(this, start, size);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexDataPage::changed_contiguous
|
||||
// Access: Protected, Virtual
|
||||
// Description: This callback function is made whenever the estimate
|
||||
// of contiguous available space changes, either through
|
||||
// an alloc or free. The lock will be held.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void VertexDataPage::
|
||||
changed_contiguous() {
|
||||
if (do_is_empty()) {
|
||||
// If the page is now empty, delete it.
|
||||
VertexDataBook::Pages::iterator pi = _book->_pages.find(this);
|
||||
nassertv(pi != _book->_pages.end());
|
||||
_book->_pages.erase(pi);
|
||||
delete this;
|
||||
return;
|
||||
}
|
||||
|
||||
adjust_book_size();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexDataPage::evict_lru
|
||||
// Access: Public, Virtual
|
||||
@ -223,6 +248,30 @@ evict_lru() {
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexDataPage::do_alloc
|
||||
// Access: Private
|
||||
// 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.
|
||||
//
|
||||
// Assumes the lock is already held.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
VertexDataBlock *VertexDataPage::
|
||||
do_alloc(size_t size) {
|
||||
VertexDataBlock *block = (VertexDataBlock *)SimpleAllocator::do_alloc(size);
|
||||
|
||||
if (block != (VertexDataBlock *)NULL && _ram_class != RC_disk) {
|
||||
// When we allocate a new block within a resident page, we have to
|
||||
// clear the disk cache (since we have just invalidated it).
|
||||
_saved_block.clear();
|
||||
}
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexDataPage::make_resident_now
|
||||
// Access: Private
|
||||
@ -287,9 +336,8 @@ make_resident() {
|
||||
delete[] _page_data;
|
||||
_page_data = new_data;
|
||||
_size = _uncompressed_size;
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
set_lru_size(_size);
|
||||
set_ram_class(RC_resident);
|
||||
}
|
||||
@ -471,6 +519,33 @@ do_restore_from_disk() {
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexDataPage::adjust_book_size
|
||||
// Access: Private
|
||||
// Description: Called when the "book size"--the size of the page as
|
||||
// recorded in its book's table--has changed for some
|
||||
// reason. Assumes the lock is held.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void VertexDataPage::
|
||||
adjust_book_size() {
|
||||
size_t new_size = _contiguous;
|
||||
if (_ram_class != RC_resident) {
|
||||
// Let's not attempt to allocate new buffers from non-resident
|
||||
// pages.
|
||||
new_size = 0;
|
||||
}
|
||||
|
||||
if (new_size != _book_size) {
|
||||
VertexDataBook::Pages::iterator pi = _book->_pages.find(this);
|
||||
nassertv(pi != _book->_pages.end());
|
||||
_book->_pages.erase(pi);
|
||||
|
||||
_book_size = new_size;
|
||||
bool inserted = _book->_pages.insert(this).second;
|
||||
nassertv(inserted);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexDataPage::request_ram_class
|
||||
// Access: Private
|
||||
@ -483,12 +558,6 @@ do_restore_from_disk() {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void VertexDataPage::
|
||||
request_ram_class(RamClass ram_class) {
|
||||
if (ram_class == _ram_class) {
|
||||
gobj_cat.warning()
|
||||
<< "Page " << this << " already has ram class " << ram_class << "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!vertex_data_threaded_paging || !Thread::is_threading_supported()) {
|
||||
// No threads. Do it immediately.
|
||||
switch (ram_class) {
|
||||
@ -613,6 +682,9 @@ remove_page(VertexDataPage *page) {
|
||||
}
|
||||
|
||||
page->_pending_ram_class = page->_ram_class;
|
||||
|
||||
// Put the page back on its proper LRU.
|
||||
page->mark_used_lru(_global_lru[page->_ram_class]);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
@ -42,10 +42,11 @@ class VertexDataBlock;
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA VertexDataPage : public SimpleAllocator, public SimpleLruPage {
|
||||
public:
|
||||
VertexDataPage(size_t book_size);
|
||||
VertexDataPage(VertexDataBook *book, size_t page_size);
|
||||
PUBLISHED:
|
||||
~VertexDataPage();
|
||||
|
||||
PUBLISHED:
|
||||
// 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.
|
||||
@ -61,7 +62,7 @@ PUBLISHED:
|
||||
INLINE RamClass get_pending_ram_class() const;
|
||||
INLINE void request_resident();
|
||||
|
||||
VertexDataBlock *alloc(size_t size);
|
||||
INLINE VertexDataBlock *alloc(size_t size);
|
||||
INLINE VertexDataBlock *get_first_block() const;
|
||||
|
||||
INLINE VertexDataBook *get_book() const;
|
||||
@ -77,14 +78,18 @@ PUBLISHED:
|
||||
|
||||
public:
|
||||
INLINE unsigned char *get_page_data(bool force);
|
||||
INLINE bool operator < (const VertexDataPage &other) const;
|
||||
|
||||
protected:
|
||||
virtual SimpleAllocatorBlock *make_block(size_t start, size_t size);
|
||||
virtual void changed_contiguous();
|
||||
virtual void evict_lru();
|
||||
|
||||
private:
|
||||
class PageThread;
|
||||
|
||||
VertexDataBlock *do_alloc(size_t size);
|
||||
|
||||
void make_resident_now();
|
||||
void make_resident();
|
||||
void make_compressed();
|
||||
@ -93,7 +98,8 @@ private:
|
||||
bool do_save_to_disk();
|
||||
void do_restore_from_disk();
|
||||
|
||||
PageThread *get_thread();
|
||||
void adjust_book_size();
|
||||
|
||||
void request_ram_class(RamClass ram_class);
|
||||
INLINE void set_ram_class(RamClass ram_class);
|
||||
static void make_save_file();
|
||||
@ -126,8 +132,9 @@ private:
|
||||
size_t _size, _uncompressed_size;
|
||||
RamClass _ram_class;
|
||||
PT(VertexDataSaveBlock) _saved_block;
|
||||
size_t _book_size;
|
||||
|
||||
Mutex _lock; // Protects above members
|
||||
//Mutex _lock; // Inherited from SimpleAllocator. Protects above members.
|
||||
|
||||
RamClass _pending_ram_class; // Protected by _tlock.
|
||||
|
||||
@ -141,6 +148,8 @@ private:
|
||||
|
||||
static VertexDataSaveFile *_save_file;
|
||||
|
||||
static Mutex _unused_mutex;
|
||||
|
||||
static PStatCollector _vdata_compress_pcollector;
|
||||
static PStatCollector _vdata_decompress_pcollector;
|
||||
static PStatCollector _vdata_save_pcollector;
|
||||
@ -159,6 +168,7 @@ private:
|
||||
static TypeHandle _type_handle;
|
||||
|
||||
friend class PageThread;
|
||||
friend class VertexDataBook;
|
||||
};
|
||||
|
||||
#include "vertexDataPage.I"
|
||||
|
@ -33,7 +33,7 @@
|
||||
VertexDataSaveFile::
|
||||
VertexDataSaveFile(const Filename &directory, const string &prefix,
|
||||
size_t max_size) :
|
||||
SimpleAllocator(max_size)
|
||||
SimpleAllocator(max_size, _lock)
|
||||
{
|
||||
Filename dir;
|
||||
if (directory.empty()) {
|
||||
@ -183,7 +183,7 @@ write_data(const unsigned char *data, size_t size, bool compressed) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PT(VertexDataSaveBlock) block = (VertexDataSaveBlock *)SimpleAllocator::alloc(size);
|
||||
PT(VertexDataSaveBlock) block = (VertexDataSaveBlock *)SimpleAllocator::do_alloc(size);
|
||||
if (block != (VertexDataSaveBlock *)NULL) {
|
||||
block->set_compressed(compressed);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user