238 lines
6.3 KiB
C
238 lines
6.3 KiB
C
|
/**
|
||
|
* PANDA 3D SOFTWARE
|
||
|
* Copyright (c) Carnegie Mellon University. All rights reserved.
|
||
|
*
|
||
|
* All use of this software is subject to the terms of the revised BSD
|
||
|
* license. You should have received a copy of this license along
|
||
|
* with this source code in a file named "LICENSE."
|
||
|
*
|
||
|
* @file vertexDataPage.h
|
||
|
* @author drose
|
||
|
* @date 2007-06-04
|
||
|
*/
|
||
|
|
||
|
#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 "conditionVar.h"
|
||
|
#include "thread.h"
|
||
|
#include "mutexHolder.h"
|
||
|
#include "pdeque.h"
|
||
|
|
||
|
class VertexDataBook;
|
||
|
class VertexDataBlock;
|
||
|
|
||
|
/**
|
||
|
* 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_GOBJ VertexDataPage : public SimpleAllocator, public SimpleLruPage {
|
||
|
private:
|
||
|
VertexDataPage(size_t book_size);
|
||
|
VertexDataPage(VertexDataBook *book, size_t page_size, size_t block_size);
|
||
|
virtual ~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.
|
||
|
enum RamClass {
|
||
|
RC_resident,
|
||
|
RC_compressed,
|
||
|
RC_disk,
|
||
|
|
||
|
RC_end_of_list, // list marker; do not use
|
||
|
};
|
||
|
|
||
|
INLINE RamClass get_ram_class() const;
|
||
|
INLINE RamClass get_pending_ram_class() const;
|
||
|
INLINE void request_resident();
|
||
|
|
||
|
INLINE VertexDataBlock *alloc(size_t size);
|
||
|
INLINE VertexDataBlock *get_first_block() const;
|
||
|
|
||
|
INLINE VertexDataBook *get_book() const;
|
||
|
|
||
|
INLINE static SimpleLru *get_global_lru(RamClass rclass);
|
||
|
INLINE static SimpleLru *get_pending_lru();
|
||
|
INLINE static VertexDataSaveFile *get_save_file();
|
||
|
MAKE_PROPERTY(save_file, get_save_file);
|
||
|
|
||
|
INLINE bool save_to_disk();
|
||
|
|
||
|
INLINE static int get_num_threads();
|
||
|
INLINE static int get_num_pending_reads();
|
||
|
INLINE static int get_num_pending_writes();
|
||
|
static void stop_threads();
|
||
|
static void flush_threads();
|
||
|
|
||
|
virtual void output(std::ostream &out) const;
|
||
|
virtual void write(std::ostream &out, int indent_level) const;
|
||
|
|
||
|
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();
|
||
|
void make_disk();
|
||
|
|
||
|
bool do_save_to_disk();
|
||
|
void do_restore_from_disk();
|
||
|
|
||
|
void adjust_book_size();
|
||
|
|
||
|
void request_ram_class(RamClass ram_class);
|
||
|
INLINE void set_ram_class(RamClass ram_class);
|
||
|
static void make_save_file();
|
||
|
|
||
|
INLINE size_t round_up(size_t page_size) const;
|
||
|
unsigned char *alloc_page_data(size_t page_size) const;
|
||
|
void free_page_data(unsigned char *page_data, size_t page_size) const;
|
||
|
|
||
|
typedef pdeque<VertexDataPage *> PendingPages;
|
||
|
|
||
|
class PageThreadManager;
|
||
|
class EXPCL_PANDA_GOBJ PageThread : public Thread {
|
||
|
public:
|
||
|
PageThread(PageThreadManager *manager, const std::string &name);
|
||
|
|
||
|
protected:
|
||
|
virtual void thread_main();
|
||
|
|
||
|
private:
|
||
|
PageThreadManager *_manager;
|
||
|
VertexDataPage *_working_page;
|
||
|
|
||
|
// Signaled when _working_page is set to NULL after finishing a task.
|
||
|
ConditionVar _working_cvar;
|
||
|
friend class PageThreadManager;
|
||
|
};
|
||
|
typedef pvector<PT(PageThread) > PageThreads;
|
||
|
|
||
|
class EXPCL_PANDA_GOBJ PageThreadManager : public ReferenceCount {
|
||
|
public:
|
||
|
PageThreadManager(int num_threads);
|
||
|
void add_page(VertexDataPage *page, RamClass ram_class);
|
||
|
void remove_page(VertexDataPage *page);
|
||
|
int get_num_threads() const;
|
||
|
int get_num_pending_reads() const;
|
||
|
int get_num_pending_writes() const;
|
||
|
void start_threads(int num_threads);
|
||
|
void stop_threads();
|
||
|
|
||
|
private:
|
||
|
PendingPages _pending_writes;
|
||
|
PendingPages _pending_reads;
|
||
|
bool _shutdown;
|
||
|
|
||
|
// Signaled when anything new is added to either of the above queues, or
|
||
|
// when _shutdown is set true. This wakes up any pending thread.
|
||
|
ConditionVar _pending_cvar;
|
||
|
|
||
|
PageThreads _threads;
|
||
|
friend class PageThread;
|
||
|
};
|
||
|
|
||
|
static PT(PageThreadManager) _thread_mgr;
|
||
|
static Mutex &_tlock; // Protects _thread_mgr and all of its members.
|
||
|
|
||
|
unsigned char *_page_data;
|
||
|
size_t _size, _allocated_size, _uncompressed_size;
|
||
|
RamClass _ram_class;
|
||
|
PT(VertexDataSaveBlock) _saved_block;
|
||
|
size_t _book_size;
|
||
|
size_t _block_size;
|
||
|
|
||
|
// Mutex _lock; Inherited from SimpleAllocator. Protects above members.
|
||
|
RamClass _pending_ram_class; // Protected by _tlock.
|
||
|
|
||
|
VertexDataBook *_book; // never changes.
|
||
|
|
||
|
enum { deflate_page_size = 1024, inflate_page_size = 1024 };
|
||
|
|
||
|
// We build up a temporary linked list of these while deflating
|
||
|
// (compressing) the vertex data in-memory.
|
||
|
class EXPCL_PANDA_GOBJ DeflatePage {
|
||
|
public:
|
||
|
DeflatePage() {
|
||
|
_used_size = 0;
|
||
|
_next = nullptr;
|
||
|
}
|
||
|
ALLOC_DELETED_CHAIN(DeflatePage);
|
||
|
|
||
|
unsigned char _buffer[deflate_page_size];
|
||
|
size_t _used_size;
|
||
|
DeflatePage *_next;
|
||
|
|
||
|
public:
|
||
|
static TypeHandle get_class_type() {
|
||
|
return _type_handle;
|
||
|
}
|
||
|
static void init_type() {
|
||
|
register_type(_type_handle, "VertexDataPage::DeflatePage");
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
static TypeHandle _type_handle;
|
||
|
};
|
||
|
|
||
|
static SimpleLru _resident_lru;
|
||
|
static SimpleLru _compressed_lru;
|
||
|
static SimpleLru _disk_lru;
|
||
|
static SimpleLru _pending_lru;
|
||
|
static SimpleLru *_global_lru[RC_end_of_list];
|
||
|
|
||
|
static VertexDataSaveFile *_save_file;
|
||
|
|
||
|
static Mutex _unused_mutex;
|
||
|
|
||
|
static PStatCollector _vdata_compress_pcollector;
|
||
|
static PStatCollector _vdata_decompress_pcollector;
|
||
|
static PStatCollector _vdata_save_pcollector;
|
||
|
static PStatCollector _vdata_restore_pcollector;
|
||
|
static PStatCollector _thread_wait_pcollector;
|
||
|
static PStatCollector _alloc_pages_pcollector;
|
||
|
|
||
|
public:
|
||
|
static TypeHandle get_class_type() {
|
||
|
return _type_handle;
|
||
|
}
|
||
|
static void init_type() {
|
||
|
register_type(_type_handle, "VertexDataPage");
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
static TypeHandle _type_handle;
|
||
|
|
||
|
friend class PageThread;
|
||
|
friend class VertexDataBook;
|
||
|
};
|
||
|
|
||
|
inline std::ostream &operator << (std::ostream &out, const VertexDataPage &page) {
|
||
|
page.output(out);
|
||
|
return out;
|
||
|
}
|
||
|
|
||
|
#include "vertexDataPage.I"
|
||
|
|
||
|
#endif
|