add ReferenceCount::local_object(), clarify GeomVertexCache

This commit is contained in:
David Rose 2005-04-17 17:38:51 +00:00
parent c83feafc70
commit 05ba41b4d6
30 changed files with 324 additions and 187 deletions

View File

@ -62,6 +62,28 @@ release_all_geoms() {
return _prepared_objects->release_all_geoms();
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsStateGuardian::release_all_vertex_buffers
// Access: Public
// Description: Frees the resources for all vertex buffers associated
// with this GSG.
////////////////////////////////////////////////////////////////////
INLINE int GraphicsStateGuardian::
release_all_vertex_buffers() {
return _prepared_objects->release_all_vertex_buffers();
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsStateGuardian::release_all_index_buffers
// Access: Public
// Description: Frees the resources for all index buffers associated
// with this GSG.
////////////////////////////////////////////////////////////////////
INLINE int GraphicsStateGuardian::
release_all_index_buffers() {
return _prepared_objects->release_all_index_buffers();
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsStateGuardian::set_active
// Access: Published

View File

@ -1511,6 +1511,8 @@ close_gsg() {
if (_prepared_objects->get_ref_count() == 1) {
release_all_textures();
release_all_geoms();
release_all_vertex_buffers();
release_all_index_buffers();
}
}

View File

@ -74,6 +74,8 @@ public:
PUBLISHED:
INLINE int release_all_textures();
INLINE int release_all_geoms();
INLINE int release_all_vertex_buffers();
INLINE int release_all_index_buffers();
INLINE void set_active(bool active);
INLINE bool is_active() const;

View File

@ -59,7 +59,7 @@ GraphicsThreadingModel(const string &model) {
size_t slash = model.find('/', start);
if (slash == string::npos) {
_cull_name = model;
_cull_name = model.substr(start);
} else {
_cull_name = model.substr(start, slash - start);
_draw_name = model.substr(slash + 1);

View File

@ -3197,44 +3197,51 @@ release_texture(TextureContext *tc) {
VertexBufferContext *DXGraphicsStateGuardian8::
prepare_vertex_buffer(qpGeomVertexArrayData *data) {
DXVertexBufferContext8 *dvbc = new DXVertexBufferContext8(data);
if (vertex_buffers && data->get_usage_hint() != qpGeom::UH_client) {
dvbc->create_vbuffer(*_pScrn);
if (dxgsg8_cat.is_debug()) {
dxgsg8_cat.debug()
<< "creating vertex buffer " << dvbc->_vbuffer << ": "
<< data->get_num_rows() << " vertices "
<< *data->get_array_format() << "\n";
}
}
return dvbc;
}
////////////////////////////////////////////////////////////////////
// Function: DXGraphicsStateGuardian8::apply_vertex_buffer
// Access: Public
// Description: Makes the data the currently available data for
// rendering.
// Description: Updates the vertex buffer with the current data, and
// makes it the current vertex buffer for rendering.
////////////////////////////////////////////////////////////////////
void DXGraphicsStateGuardian8::
apply_vertex_buffer(VertexBufferContext *vbc) {
DXVertexBufferContext8 *dvbc = DCAST(DXVertexBufferContext8, vbc);
if (dvbc->_vbuffer != NULL) {
if (dvbc->_vbuffer == NULL) {
// Attempt to create a new vertex buffer.
if (vertex_buffers &&
dvbc->get_data()->get_usage_hint() != qpGeom::UH_client) {
dvbc->create_vbuffer(*_pScrn);
}
if (dvbc->_vbuffer != NULL) {
dvbc->upload_data();
add_to_vertex_buffer_record(dvbc);
add_to_total_buffer_record(dvbc);
dvbc->mark_loaded();
_pD3DDevice->SetStreamSource
(0, dvbc->_vbuffer, dvbc->get_data()->get_array_format()->get_stride());
_vbuffer_active = true;
} else {
_vbuffer_active = false;
}
} else {
add_to_vertex_buffer_record(dvbc);
if (dvbc->was_modified()) {
if (dvbc->changed_size()) {
// Here we have to destroy the old vertex buffer and create a
// new one.
// We have to destroy the old vertex buffer and create a new
// one.
dvbc->create_vbuffer(*_pScrn);
} else {
// Here we just copy the new data to the vertex buffer.
dvbc->upload_data();
}
dvbc->upload_data();
add_to_total_buffer_record(dvbc);
dvbc->mark_loaded();
@ -3243,9 +3250,6 @@ apply_vertex_buffer(VertexBufferContext *vbc) {
_pD3DDevice->SetStreamSource
(0, dvbc->_vbuffer, dvbc->get_data()->get_array_format()->get_stride());
_vbuffer_active = true;
} else {
_vbuffer_active = false;
}
set_vertex_format(dvbc->_fvf);
@ -3281,43 +3285,48 @@ release_vertex_buffer(VertexBufferContext *vbc) {
IndexBufferContext *DXGraphicsStateGuardian8::
prepare_index_buffer(qpGeomPrimitive *data) {
DXIndexBufferContext8 *dibc = new DXIndexBufferContext8(data);
dibc->create_ibuffer(*_pScrn);
if (dxgsg8_cat.is_debug()) {
dxgsg8_cat.debug()
<< "creating index buffer " << dibc->_ibuffer << ": "
<< data->get_num_vertices() << " indices ("
<< data->get_vertices()->get_array_format()->get_column(0)->get_numeric_type()
<< ")\n";
}
return dibc;
}
////////////////////////////////////////////////////////////////////
// Function: DXGraphicsStateGuardian8::apply_index_buffer
// Access: Public
// Description: Makes the data the currently available data for
// rendering.
// Description: Updates the index buffer with the current data, and
// makes it the current index buffer for rendering.
////////////////////////////////////////////////////////////////////
void DXGraphicsStateGuardian8::
apply_index_buffer(IndexBufferContext *ibc) {
DXIndexBufferContext8 *dibc = DCAST(DXIndexBufferContext8, ibc);
if (dibc->_ibuffer != NULL) {
if (dibc->_ibuffer == NULL) {
// Attempt to create a new index buffer.
dibc->create_ibuffer(*_pScrn);
if (dibc->_ibuffer != NULL) {
dibc->upload_data();
add_to_index_buffer_record(dibc);
add_to_total_buffer_record(dibc);
dibc->mark_loaded();
_pD3DDevice->SetIndices(dibc->_ibuffer, 0);
_ibuffer_active = true;
} else {
_pD3DDevice->SetIndices(NULL, 0);
_ibuffer_active = false;
}
} else {
add_to_index_buffer_record(dibc);
if (dibc->was_modified()) {
if (dibc->changed_size()) {
// Here we have to destroy the old index buffer and create a
// new one.
// We have to destroy the old index buffer and create a new
// one.
dibc->create_ibuffer(*_pScrn);
} else {
// Here we just copy the new data to the index buffer.
dibc->upload_data();
}
dibc->upload_data();
add_to_total_buffer_record(dibc);
dibc->mark_loaded();
@ -3325,10 +3334,6 @@ apply_index_buffer(IndexBufferContext *ibc) {
_pD3DDevice->SetIndices(dibc->_ibuffer, 0);
_ibuffer_active = true;
} else {
_pD3DDevice->SetIndices(NULL, 0);
_ibuffer_active = false;
}
}

View File

@ -58,7 +58,8 @@ DXIndexBufferContext8::
////////////////////////////////////////////////////////////////////
// Function: DXIndexBufferContext8::create_ibuffer
// Access: Public
// Description: Creates a new index buffer and uploads data to it.
// Description: Creates a new index buffer (but does not upload data
// to it).
////////////////////////////////////////////////////////////////////
void DXIndexBufferContext8::
create_ibuffer(DXScreenData &scrn) {
@ -77,9 +78,14 @@ create_ibuffer(DXScreenData &scrn) {
dxgsg8_cat.warning()
<< "CreateIndexBuffer failed" << D3DERRORSTRING(hr);
_ibuffer = NULL;
} else {
upload_data();
if (dxgsg8_cat.is_debug()) {
dxgsg8_cat.debug()
<< "creating index buffer " << _ibuffer << ": "
<< get_data()->get_num_vertices() << " indices ("
<< get_data()->get_vertices()->get_array_format()->get_column(0)->get_numeric_type()
<< ")\n";
}
}
}

View File

@ -153,7 +153,8 @@ DXVertexBufferContext8::
////////////////////////////////////////////////////////////////////
// Function: DXVertexBufferContext8::create_vbuffer
// Access: Public
// Description: Creates a new vertex buffer and uploads data to it.
// Description: Creates a new vertex buffer (but does not upload data
// to it).
////////////////////////////////////////////////////////////////////
void DXVertexBufferContext8::
create_vbuffer(DXScreenData &scrn) {
@ -169,9 +170,13 @@ create_vbuffer(DXScreenData &scrn) {
dxgsg8_cat.warning()
<< "CreateVertexBuffer failed" << D3DERRORSTRING(hr);
_vbuffer = NULL;
} else {
upload_data();
if (dxgsg8_cat.is_debug()) {
dxgsg8_cat.debug()
<< "created vertex buffer " << _vbuffer << ": "
<< get_data()->get_num_rows() << " vertices "
<< *get_data()->get_array_format() << "\n";
}
}
}

View File

@ -87,7 +87,7 @@ operator = (const ReferenceCount &) {
// instance of a class that derives from ReferenceCount. Or maybe
// your headers are out of sync, and you need to make clean in
// direct or some higher tree.
nassertv(_ref_count != -100);
nassertv(_ref_count != deleted_ref_count);
}
////////////////////////////////////////////////////////////////////
@ -112,7 +112,13 @@ INLINE ReferenceCount::
// automatic (local variable) instance of a class that derives from
// ReferenceCount. Or maybe your headers are out of sync, and you
// need to make clean in direct or some higher tree.
nassertv(_ref_count != -100);
nassertv(_ref_count != deleted_ref_count);
// If this assertion fails, we're trying to delete a static object
// that still has an outstanding reference count. You should make
// sure that all references to your static objects are gone by the
// time the object itself destructs.
nassertv(_ref_count <= local_ref_count);
// If this assertion fails, the reference counts are all screwed
// up altogether. Maybe some errant code stomped all over memory
@ -129,7 +135,7 @@ INLINE ReferenceCount::
// constructor for a ReferenceCount object, and then bitwise
// copied a dynamically allocated value--reference count and
// all--onto a locally allocated one.
nassertv(_ref_count == 0);
nassertv(_ref_count == 0 || _ref_count == local_ref_count);
// Tell our weak reference holders that we're going away now.
if (_weak_list != (WeakReferenceList *)NULL) {
@ -138,10 +144,10 @@ INLINE ReferenceCount::
}
#ifndef NDEBUG
// Ok, all clear to delete. Now set the reference count to -100,
// so we'll have a better chance of noticing if we happen to have
// a stray pointer to it still out there.
_ref_count = -100;
// Ok, all clear to delete. Now set the reference count to
// deleted_ref_count, so we'll have a better chance of noticing if
// we happen to have a stray pointer to it still out there.
_ref_count = deleted_ref_count;
#endif
#ifdef DO_MEMORY_USAGE
@ -151,7 +157,7 @@ INLINE ReferenceCount::
////////////////////////////////////////////////////////////////////
// Function: ReferenceCount::get_ref_count
// Access: Public
// Access: Published
// Description: Returns the current reference count.
////////////////////////////////////////////////////////////////////
INLINE int ReferenceCount::
@ -164,7 +170,7 @@ get_ref_count() const {
////////////////////////////////////////////////////////////////////
// Function: ReferenceCount::ref
// Access: Public
// Access: Published
// Description: Explicitly increments the reference count. User code
// should avoid using ref() and unref() directly, which
// can result in missed reference counts. Instead, let
@ -191,7 +197,7 @@ ref() const {
// automatic (local variable) instance of a class that derives from
// ReferenceCount. Or maybe your headers are out of sync, and you
// need to make clean in direct or some higher tree.
nassertr(_ref_count != -100, 0);
nassertr(_ref_count != deleted_ref_count, 0);
// If this assertion fails, the reference counts are all screwed
// up altogether. Maybe some errant code stomped all over memory
@ -203,7 +209,7 @@ ref() const {
////////////////////////////////////////////////////////////////////
// Function: ReferenceCount::unref
// Access: Public
// Access: Published
// Description: Explicitly decrements the reference count. Note that
// the object will not be implicitly deleted by unref()
// simply because the reference count drops to zero.
@ -237,7 +243,7 @@ unref() const {
// automatic (local variable) instance of a class that derives from
// ReferenceCount. Or maybe your headers are out of sync, and you
// need to make clean in direct or some higher tree.
nassertr(_ref_count != -100, false);
nassertr(_ref_count != deleted_ref_count, false);
// If this assertion fails, the reference counts are all screwed
// up altogether. Maybe some errant code stomped all over memory
@ -254,7 +260,7 @@ unref() const {
////////////////////////////////////////////////////////////////////
// Function: ReferenceCount::test_ref_count_integrity
// Access: Public
// Access: Published
// Description: Does some easy checks to make sure that the reference
// count isn't completely bogus.
////////////////////////////////////////////////////////////////////
@ -270,7 +276,7 @@ test_ref_count_integrity() const {
// automatic (local variable) instance of a class that derives from
// ReferenceCount. Or maybe your headers are out of sync, and you
// need to make clean in direct or some higher tree.
nassertv(_ref_count != -100);
nassertv(_ref_count != deleted_ref_count);
// If this assertion fails, the reference counts are all screwed
// up altogether. Maybe some errant code stomped all over memory
@ -279,6 +285,30 @@ test_ref_count_integrity() const {
#endif
}
////////////////////////////////////////////////////////////////////
// Function: ReferenceCount::local_object
// Access: Public
// Description: This function should be called, once, immediately
// after creating a new instance of some
// ReferenceCount-derived object on the stack.
//
// This allows the object to be passed to functions that
// will increment and decrement the object's reference
// count temporarily, and it will prevent the object
// from being deleted (inappropriately), when the
// reference count returns to zero. It actually
// achieves this by setting a large positive value in
// the reference count field.
////////////////////////////////////////////////////////////////////
INLINE void ReferenceCount::
local_object() {
// If this assertion fails, you didn't call this immediately after
// creating a local object.
nassertv(_ref_count == 0);
_ref_count = local_ref_count;
}
////////////////////////////////////////////////////////////////////
// Function: ReferenceCount::has_weak_list
// Access: Public

View File

@ -54,6 +54,7 @@ PUBLISHED:
INLINE void test_ref_count_integrity() const;
public:
INLINE void local_object();
INLINE bool has_weak_list() const;
INLINE WeakReferenceList *get_weak_list() const;
@ -61,6 +62,22 @@ public:
INLINE void weak_unref(WeakPointerToVoid *ptv);
private:
enum {
// We use this value as a flag to indicate an object has been
// indicated as a local object, and should not be deleted except
// by its own destructor. Really, any nonzero value would do, but
// having a large specific number makes the sanity checks easier.
local_ref_count = 10000000,
// This value is used as a flag to indicate that an object has
// just been deleted, and you're looking at deallocated memory.
// It's not guaranteed to stick around, of course (since the
// deleted memory might be repurposed for anything else, including
// a new object), but if you ever do encounter this value in a
// reference count field, you screwed up.
deleted_ref_count = -100,
};
int _ref_count;
WeakReferenceList *_weak_list;
@ -137,8 +154,6 @@ private:
static TypeHandle _type_handle;
};
#include "referenceCount.I"
#endif

View File

@ -206,14 +206,19 @@ ConfigVariableString fake_texture_image
"the same texture file, which will presumably only be loaded "
"once."));
ConfigVariableInt vertex_convert_cache
("vertex-convert-cache", 4194304, // 4 MB
PRC_DESC("This is the amount of memory, in bytes, that should be set "
"aside for storing pre-processed data for rendering vertices. "
"This is not a limit on the actual vertex data, which is "
"determined by the model; it is also not a limit on the "
"amount of memory used by the video driver or the system "
"graphics interface, which Panda has no control over."));
ConfigVariableInt geom_cache_size
("geom-cache-size", 5000,
PRC_DESC("Specifies the maximum number of entries in the cache "
"for storing pre-processed data for rendering "
"vertices. This limit is flexible, and may be "
"temporarily exceeded if many different Geoms are "
"pre-processed during the space of a single frame."));
ConfigVariableInt geom_cache_min_frames
("geom-cache-min-frames", 1,
PRC_DESC("Specifies the minimum number of frames any one particular "
"object will remain in the geom cache, even if geom-cache-size "
"is exceeded."));
ConfigVariableDouble default_near
("default-near", 1.0,

View File

@ -66,7 +66,8 @@ extern EXPCL_PANDA ConfigVariableEnum<AutoTextureScale> textures_power_2;
extern EXPCL_PANDA ConfigVariableEnum<AutoTextureScale> textures_square;
extern EXPCL_PANDA ConfigVariableString fake_texture_image;
extern EXPCL_PANDA ConfigVariableInt vertex_convert_cache;
extern EXPCL_PANDA ConfigVariableInt geom_cache_size;
extern EXPCL_PANDA ConfigVariableInt geom_cache_min_frames;
extern ConfigVariableDouble default_near;
extern ConfigVariableDouble default_far;

View File

@ -187,11 +187,34 @@ get_modified() const {
////////////////////////////////////////////////////////////////////
INLINE qpGeom::CacheEntry::
CacheEntry(const qpGeomVertexData *source_data, const qpGeomMunger *modifier) :
_source(NULL),
_source_data(source_data),
_modifier(modifier)
_modifier(modifier),
_geom_result(NULL),
_data_result(NULL)
{
}
////////////////////////////////////////////////////////////////////
// Function: qpGeom::CacheEntry::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE qpGeom::CacheEntry::
CacheEntry(qpGeom *source, const qpGeomVertexData *source_data,
const qpGeomMunger *modifier, const qpGeom *geom_result,
const qpGeomVertexData *data_result) :
_source(source),
_source_data(source_data),
_modifier(modifier),
_geom_result(geom_result),
_data_result(data_result)
{
if (_geom_result != _source) {
_geom_result->ref();
}
}
////////////////////////////////////////////////////////////////////
// Function: qpGeom::CacheEntry::operator <
// Access: Public

View File

@ -469,7 +469,7 @@ munge_geom(const qpGeomMunger *munger,
{
CDReader cdata(_cycler);
CacheEntry temp_entry(source_data, munger);
temp_entry.ref(); // big ugly hack to allow a stack-allocated ReferenceCount object.
temp_entry.local_object();
Cache::const_iterator ci = cdata->_cache.find(&temp_entry);
if (ci != cdata->_cache.end()) {
CacheEntry *entry = (*ci);
@ -483,7 +483,6 @@ munge_geom(const qpGeomMunger *munger,
entry->refresh();
result = entry->_geom_result;
data = entry->_data_result;
temp_entry.unref();
return;
}
@ -496,7 +495,6 @@ munge_geom(const qpGeomMunger *munger,
CDWriter cdataw(((qpGeom *)this)->_cycler, cdata);
cdataw->_cache.erase(entry);
}
temp_entry.unref();
}
// Ok, invoke the munger.
@ -513,10 +511,8 @@ munge_geom(const qpGeomMunger *munger,
CacheEntry *entry;
{
CDWriter cdata(((qpGeom *)this)->_cycler);
entry = new CacheEntry(source_data, munger);
entry->_source = (qpGeom *)this;
entry->_geom_result = result;
entry->_data_result = data;
entry = new CacheEntry((qpGeom *)this, source_data, munger,
result, data);
bool inserted = cdata->_cache.insert(entry).second;
nassertv(inserted);
}
@ -880,6 +876,18 @@ fillin(DatagramIterator &scan, BamReader *manager) {
manager->read_cdata(scan, _cycler);
}
////////////////////////////////////////////////////////////////////
// Function: qpGeom::CacheEntry::Destructor
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
qpGeom::CacheEntry::
~CacheEntry() {
if (_geom_result != _source) {
unref_delete(_geom_result);
}
}
////////////////////////////////////////////////////////////////////
// Function: qpGeom::CacheEntry::evict_callback
// Access: Public, Virtual
@ -900,17 +908,6 @@ evict_callback() {
_source->_cycler.release_write_stage(0, cdata);
}
////////////////////////////////////////////////////////////////////
// Function: qpGeom::CacheEntry::get_result_size
// Access: Public, Virtual
// Description: Returns the approximate number of bytes represented
// by the computed result.
////////////////////////////////////////////////////////////////////
int qpGeom::CacheEntry::
get_result_size() const {
return _geom_result->get_num_bytes() + _data_result->get_num_bytes();
}
////////////////////////////////////////////////////////////////////
// Function: qpGeom::CacheEntry::output
// Access: Public, Virtual

View File

@ -134,22 +134,27 @@ private:
// We have to use reference-counting pointers here instead of having
// explicit cleanup in the GeomVertexFormat destructor, because the
// cache needs to be stored in the CycleData, which makes accurate
// cleanup more difficult. We use the GeomVertexCacheManager class
// to avoid cache bloat.
// cleanup more difficult. We use the GeomCacheManager class to
// avoid cache bloat.
class CacheEntry : public qpGeomCacheEntry {
public:
INLINE CacheEntry(const qpGeomVertexData *source_data,
const qpGeomMunger *modifier);
INLINE CacheEntry(qpGeom *source,
const qpGeomVertexData *source_data,
const qpGeomMunger *modifier,
const qpGeom *geom_result,
const qpGeomVertexData *data_result);
virtual ~CacheEntry();
INLINE bool operator < (const CacheEntry &other) const;
virtual void evict_callback();
virtual int get_result_size() const;
virtual void output(ostream &out) const;
qpGeom *_source;
CPT(qpGeomVertexData) _source_data;
CPT(qpGeomMunger) _modifier;
CPT(qpGeom) _geom_result;
const qpGeom *_geom_result; // ref-counted if not same as _source
CPT(qpGeomVertexData) _data_result;
};
typedef pset<PT(CacheEntry), IndirectLess<CacheEntry> > Cache;

View File

@ -30,27 +30,6 @@ qpGeomCacheEntry() {
#endif
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomCacheEntry::refresh
// Access: Public
// Description: Marks the cache entry recently used, so it will not
// be evicted for a while.
////////////////////////////////////////////////////////////////////
INLINE void qpGeomCacheEntry::
refresh() {
nassertv(_next != (qpGeomCacheEntry *)NULL && _prev != (qpGeomCacheEntry *)NULL);
qpGeomCacheManager *cache_mgr = qpGeomCacheManager::get_global_ptr();
MutexHolder holder(cache_mgr->_lock);
remove_from_list();
insert_before(cache_mgr->_list);
int new_size = get_result_size();
cache_mgr->_total_size += (new_size - _result_size);
_result_size = new_size;
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomCacheEntry::remove_from_list
// Access: Private

View File

@ -20,6 +20,7 @@
#include "qpgeomCacheManager.h"
#include "mutexHolder.h"
#include "config_gobj.h"
#include "clockObject.h"
////////////////////////////////////////////////////////////////////
// Function: qpGeomCacheEntry::Destructor
@ -41,21 +42,20 @@ record() {
nassertr(_next == (qpGeomCacheEntry *)NULL && _prev == (qpGeomCacheEntry *)NULL, NULL);
PT(qpGeomCacheEntry) keepme = this;
_result_size = get_result_size();
qpGeomCacheManager *cache_mgr = qpGeomCacheManager::get_global_ptr();
MutexHolder holder(cache_mgr->_lock);
if (gobj_cat.is_debug()) {
gobj_cat.debug()
<< "recording cache entry: " << *this << ", total_size = "
<< cache_mgr->_total_size + _result_size << "\n";
<< cache_mgr->_total_size + 1 << "\n";
}
insert_before(cache_mgr->_list);
cache_mgr->_total_size += _result_size;
++cache_mgr->_total_size;
cache_mgr->_geom_cache_size_pcollector.set_level(cache_mgr->_total_size);
cache_mgr->_geom_cache_record_pcollector.add_level(1);
_last_frame_used = ClockObject::get_global_clock()->get_frame_count();
// Increment our own reference count while we're in the queue, just
// so we don't have to play games with it later--this is inner-loop
@ -70,6 +70,25 @@ record() {
return this;
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomCacheEntry::refresh
// Access: Public
// Description: Marks the cache entry recently used, so it will not
// be evicted for a while.
////////////////////////////////////////////////////////////////////
void qpGeomCacheEntry::
refresh() {
nassertv(_next != (qpGeomCacheEntry *)NULL && _prev != (qpGeomCacheEntry *)NULL);
qpGeomCacheManager *cache_mgr = qpGeomCacheManager::get_global_ptr();
MutexHolder holder(cache_mgr->_lock);
remove_from_list();
insert_before(cache_mgr->_list);
_last_frame_used = ClockObject::get_global_clock()->get_frame_count();
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomCacheEntry::erase
// Access: Public
@ -92,7 +111,7 @@ erase() {
MutexHolder holder(cache_mgr->_lock);
remove_from_list();
cache_mgr->_total_size -= _result_size;
--cache_mgr->_total_size;
cache_mgr->_geom_cache_size_pcollector.set_level(cache_mgr->_total_size);
cache_mgr->_geom_cache_erase_pcollector.add_level(1);
@ -109,17 +128,6 @@ void qpGeomCacheEntry::
evict_callback() {
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomCacheEntry::get_result_size
// Access: Public, Virtual
// Description: Returns the approximate number of bytes represented
// by the computed result.
////////////////////////////////////////////////////////////////////
int qpGeomCacheEntry::
get_result_size() const {
return 0;
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomCacheEntry::output
// Access: Public, Virtual

View File

@ -43,15 +43,14 @@ public:
virtual ~qpGeomCacheEntry();
PT(qpGeomCacheEntry) record();
INLINE void refresh();
void refresh();
PT(qpGeomCacheEntry) erase();
virtual void evict_callback();
virtual int get_result_size() const;
virtual void output(ostream &out) const;
private:
int _result_size;
int _last_frame_used;
INLINE void remove_from_list();
INLINE void insert_before(qpGeomCacheEntry *node);

View File

@ -20,37 +20,39 @@
////////////////////////////////////////////////////////////////////
// Function: qpGeomCacheManager::set_max_size
// Access: Published
// Description: Specifies the amount of memory, in bytes, that should
// be set aside for storing pre-processed data for
// rendering vertices. This is not a limit on the
// actual vertex data, which is what it is; it is also
// not a limit on the amount of memory used by the video
// driver or the system graphics interface, which Panda
// has no control over.
// Description: Specifies the maximum number of entries in the cache
// for storing pre-processed data for rendering
// vertices. This limit is flexible, and may be
// temporarily exceeded if many different Geoms are
// pre-processed during the space of a single frame.
//
// This is not a limit on the actual vertex data, which
// is what it is; it is also not a limit on the amount
// of memory used by the video driver or the system
// graphics interface, which Panda has no control over.
////////////////////////////////////////////////////////////////////
INLINE void qpGeomCacheManager::
set_max_size(int max_size) const {
// We directly change the config variable.
vertex_convert_cache = max_size;
geom_cache_size = max_size;
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomCacheManager::get_max_size
// Access: Published
// Description: Returns the amount of memory, in bytes, that should
// be set aside for storing pre-processed data for
// rendering vertices. See set_max_size().
// Description: Returns the maximum number of entries in the cache
// for storing pre-processed data for rendering
// vertices. See set_max_size().
////////////////////////////////////////////////////////////////////
INLINE int qpGeomCacheManager::
get_max_size() const {
return vertex_convert_cache;
return geom_cache_size;
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomCacheManager::get_total_size
// Access: Published
// Description: Returns the amount of memory, in bytes, currently
// consumed by the cache of pre-processed vertex data.
// Description: Returns the number of entries currently in the cache.
////////////////////////////////////////////////////////////////////
INLINE int qpGeomCacheManager::
get_total_size() const {

View File

@ -77,21 +77,36 @@ void qpGeomCacheManager::
evict_old_entries() {
MutexHolder holder(_lock);
int current_frame = ClockObject::get_global_clock()->get_frame_count();
int min_frames = geom_cache_min_frames;
int max_size = get_max_size();
while (_total_size > max_size) {
PT(qpGeomCacheEntry) entry = _list->_next;
nassertv(entry != _list);
if (current_frame - entry->_last_frame_used < min_frames) {
// Never mind, this one is too new.
if (gobj_cat.is_debug()) {
gobj_cat.debug()
<< "Oldest element in cache is "
<< current_frame - entry->_last_frame_used
<< " frames; keeping cache at " << _total_size << " entries.\n";
}
break;
}
entry->unref();
if (gobj_cat.is_debug()) {
gobj_cat.debug()
<< "cache total_size = " << _total_size << ", max_size = "
<< "cache total_size = " << _total_size << " entries, max_size = "
<< max_size << ", removing " << *entry << "\n";
}
entry->evict_callback();
_total_size -= entry->_result_size;
--_total_size;
entry->remove_from_list();
_geom_cache_evict_pcollector.add_level(1);
}

View File

@ -252,17 +252,6 @@ do_unregister() {
_formats_by_animation.clear();
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomMunger::CacheEntry::get_result_size
// Access: Public, Virtual
// Description: Returns the approximate number of bytes represented
// by the computed result.
////////////////////////////////////////////////////////////////////
int qpGeomMunger::CacheEntry::
get_result_size() const {
return sizeof(qpGeomMunger);
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomMunger::CacheEntry::output
// Access: Public, Virtual

View File

@ -118,7 +118,6 @@ private:
private:
class CacheEntry : public qpGeomCacheEntry {
public:
virtual int get_result_size() const;
virtual void output(ostream &out) const;
PT(qpGeomMunger) _munger;

View File

@ -300,12 +300,7 @@ clear_vertices() {
////////////////////////////////////////////////////////////////////
void qpGeomPrimitive::
offset_vertices(int offset) {
CDWriter cdata(_cycler);
cdata->_got_minmax = false;
qpGeomVertexRewriter index(cdata->_vertices, 0);
qpGeomVertexRewriter index(modify_vertices(), 0);
while (!index.is_at_end()) {
index.set_data1i(index.get_data1i() + offset);
}

View File

@ -136,3 +136,9 @@ CData(const qpGeomVertexArrayData::CData &copy) :
_modified(copy._modified)
{
}
INLINE ostream &
operator << (ostream &out, const qpGeomVertexArrayData &obj) {
obj.output(out);
return out;
}

View File

@ -159,6 +159,26 @@ set_usage_hint(qpGeomVertexArrayData::UsageHint usage_hint) {
cdata->_modified = qpGeom::get_next_modified();
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexArrayData::output
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
void qpGeomVertexArrayData::
output(ostream &out) const {
out << get_num_rows() << " rows: " << *get_array_format();
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexArrayData::write
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
void qpGeomVertexArrayData::
write(ostream &out, int indent_level) const {
_array_format->write_with_data(out, indent_level, this);
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexArrayData::modify_data
// Access: Public

View File

@ -81,6 +81,9 @@ PUBLISHED:
INLINE int get_data_size_bytes() const;
INLINE UpdateSeq get_modified() const;
void output(ostream &out) const;
void write(ostream &out, int indent_level = 0) const;
public:
INLINE CPTA_uchar get_data() const;
PTA_uchar modify_data();
@ -158,6 +161,8 @@ private:
friend class PreparedGraphicsObjects;
};
INLINE ostream &operator << (ostream &out, const qpGeomVertexArrayData &obj);
#include "qpgeomVertexArrayData.I"
#endif

View File

@ -435,13 +435,13 @@ write(ostream &out, int indent_level) const {
////////////////////////////////////////////////////////////////////
void qpGeomVertexArrayFormat::
write_with_data(ostream &out, int indent_level,
const qpGeomVertexData *data, int array_index) const {
const qpGeomVertexArrayData *array_data) const {
consider_sort_columns();
int num_vertices = data->get_num_rows();
int num_rows = array_data->get_num_rows();
qpGeomVertexReader reader(data);
qpGeomVertexReader reader(array_data);
for (int i = 0; i < num_vertices; i++) {
for (int i = 0; i < num_rows; i++) {
indent(out, indent_level)
<< "row " << i << ":\n";
reader.set_row(i);
@ -449,7 +449,7 @@ write_with_data(ostream &out, int indent_level,
for (ci = _columns.begin(); ci != _columns.end(); ++ci) {
const qpGeomVertexColumn *column = (*ci);
int num_values = min(column->get_num_values(), 4);
reader.set_column(array_index, column);
reader.set_column(0, column);
const LVecBase4f &d = reader.get_data4f();
indent(out, indent_level + 2)

View File

@ -29,6 +29,7 @@
class qpGeomVertexFormat;
class qpGeomVertexData;
class qpGeomVertexArrayData;
class InternalName;
class FactoryParams;
class BamWriter;
@ -109,7 +110,7 @@ PUBLISHED:
void output(ostream &out) const;
void write(ostream &out, int indent_level = 0) const;
void write_with_data(ostream &out, int indent_level,
const qpGeomVertexData *data, int array_index) const;
const qpGeomVertexArrayData *array_data) const;
public:
int compare_to(const qpGeomVertexArrayFormat &other) const;

View File

@ -553,7 +553,8 @@ convert_to(const qpGeomVertexFormat *new_format) const {
// Okay, convert the data to the new format.
if (gobj_cat.is_debug()) {
gobj_cat.debug()
<< "Converting " << get_num_rows() << " rows.\n";
<< "Converting " << get_num_rows() << " rows from " << *_format
<< " to " << *new_format << "\n";
}
PStatTimer timer(_convert_pcollector);

View File

@ -418,7 +418,7 @@ write_with_data(ostream &out, int indent_level,
CPTA_uchar array_data = data->get_array(i)->get_data();
indent(out, indent_level)
<< "Array " << i << " (" << (void *)array_data.p() << "):\n";
_arrays[i]->write_with_data(out, indent_level + 2, data, i);
_arrays[i]->write_with_data(out, indent_level + 2, data->get_array(i));
}
}

View File

@ -169,8 +169,8 @@ static LevelCollectorProperties level_properties[] = {
{ 1, "Vertex buffer switch", { 0.0, 0.6, 0.8 }, "", 500 },
{ 1, "Vertex buffer switch:Vertex", { 0.8, 0.0, 0.6 } },
{ 1, "Vertex buffer switch:Index", { 0.8, 0.6, 0.3 } },
{ 1, "Geom cache size", { 1.0, 0.8, 0.6 }, "MB", 12, 1048576 },
{ 1, "Geom cache operations", { 1.0, 0.8, 0.6 }, "", 500 },
{ 1, "Geom cache size", { 0.6, 0.8, 0.6 }, "", 500 },
{ 1, "Geom cache operations", { 1.0, 0.6, 0.6 }, "", 500 },
{ 1, "Geom cache operations:record", { 0.2, 0.4, 0.8 } },
{ 1, "Geom cache operations:erase", { 0.4, 0.8, 0.2 } },
{ 1, "Geom cache operations:evict", { 0.8, 0.2, 0.4 } },