mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 10:54:24 -04:00
simply geom caching system
This commit is contained in:
parent
398186266d
commit
5ad57abaf5
@ -97,5 +97,27 @@ compare_to_impl(const qpGeomMunger *other) const {
|
||||
if (_color_scale != om->_color_scale) {
|
||||
return _color_scale < om->_color_scale ? -1 : 1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
return qpGeomMunger::compare_to_impl(other);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ColorMunger::geom_compare_to_impl
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called to compare two GeomMungers who are known to be
|
||||
// of the same type, for an apples-to-apples comparison.
|
||||
// This will never be called on two pointers of a
|
||||
// different type.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int ColorMunger::
|
||||
geom_compare_to_impl(const qpGeomMunger *other) const {
|
||||
const ColorMunger *om = DCAST(ColorMunger, other);
|
||||
if (_color != om->_color) {
|
||||
return _color < om->_color ? -1 : 1;
|
||||
}
|
||||
if (_color_scale != om->_color_scale) {
|
||||
return _color_scale < om->_color_scale ? -1 : 1;
|
||||
}
|
||||
|
||||
return qpGeomMunger::geom_compare_to_impl(other);
|
||||
}
|
||||
|
@ -42,6 +42,7 @@ public:
|
||||
protected:
|
||||
virtual CPT(qpGeomVertexData) munge_data_impl(const qpGeomVertexData *data);
|
||||
virtual int compare_to_impl(const qpGeomMunger *other) const;
|
||||
virtual int geom_compare_to_impl(const qpGeomMunger *other) const;
|
||||
|
||||
private:
|
||||
int _num_components;
|
||||
|
@ -84,6 +84,7 @@ compare_to_impl(const qpGeomMunger *other) const {
|
||||
if (_tex_gen != om->_tex_gen) {
|
||||
return _tex_gen < om->_tex_gen ? -1 : 1;
|
||||
}
|
||||
|
||||
return ColorMunger::compare_to_impl(other);
|
||||
}
|
||||
|
||||
@ -97,8 +98,8 @@ compare_to_impl(const qpGeomMunger *other) const {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int CLP(GeomMunger)::
|
||||
geom_compare_to_impl(const qpGeomMunger *other) const {
|
||||
// We don't consider _texture and _tex_gen for these purposes; they
|
||||
// We don't consider _texture and _tex_gen for this purpose; they
|
||||
// affect only whether the GL display list should be regenerated or
|
||||
// not.
|
||||
return ColorMunger::compare_to_impl(other);
|
||||
// not, and don't require reconverting the vertices.
|
||||
return ColorMunger::geom_compare_to_impl(other);
|
||||
}
|
||||
|
@ -2057,6 +2057,11 @@ begin_draw_primitives(const qpGeom *geom, const qpGeomMunger *munger,
|
||||
UpdateSeq modified = max(geom->get_modified(), _vertex_data->get_modified());
|
||||
if (ggc->_modified == modified) {
|
||||
// If it hasn't been modified, just play the display list again.
|
||||
if (GLCAT.is_spam()) {
|
||||
GLCAT.spam()
|
||||
<< "calling display list " << ggc->_index << "\n";
|
||||
}
|
||||
|
||||
GLP(CallList)(ggc->_index);
|
||||
#ifdef DO_PSTATS
|
||||
_vertices_display_list_pcollector.add_level(ggc->_num_verts);
|
||||
@ -2066,6 +2071,15 @@ begin_draw_primitives(const qpGeom *geom, const qpGeomMunger *munger,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (GLCAT.is_debug()) {
|
||||
GLCAT.debug()
|
||||
<< "compiling display list " << ggc->_index << "\n";
|
||||
cerr << "ggc = " << ggc << "," << ggc->_modified
|
||||
<< " geom = " << geom << "," << geom->get_modified()
|
||||
<< " vertex_data = " << _vertex_data << ","
|
||||
<< _vertex_data->get_modified() << "\n";
|
||||
}
|
||||
|
||||
// If it has been modified, or this is the first time, then we
|
||||
// need to build the display list up.
|
||||
if (CLP(compile_and_execute)) {
|
||||
@ -2149,15 +2163,18 @@ begin_draw_primitives(const qpGeom *geom, const qpGeomMunger *munger,
|
||||
GLP(TexCoordPointer)(num_components, get_numeric_type(numeric_type),
|
||||
stride, client_pointer + start);
|
||||
GLP(EnableClientState)(GL_TEXTURE_COORD_ARRAY);
|
||||
cerr << "sending " << *name << "\n";
|
||||
|
||||
} else {
|
||||
// The vertex data doesn't have texcoords for this stage (even
|
||||
// though they're needed).
|
||||
GLP(DisableClientState)(GL_TEXTURE_COORD_ARRAY);
|
||||
cerr << "not defined " << *name << "\n";
|
||||
}
|
||||
} else {
|
||||
// No texcoords are needed for this stage.
|
||||
GLP(DisableClientState)(GL_TEXTURE_COORD_ARRAY);
|
||||
cerr << "not sending " << *stage->get_texcoord_name() << "\n";
|
||||
}
|
||||
|
||||
++stage_index;
|
||||
|
@ -27,7 +27,8 @@
|
||||
qpgeomUsageHint.h \
|
||||
qpgeomVertexArrayData.h qpgeomVertexArrayData.I \
|
||||
qpgeomVertexArrayFormat.h qpgeomVertexArrayFormat.I \
|
||||
qpgeomVertexCacheManager.h qpgeomVertexCacheManager.I \
|
||||
qpgeomCacheEntry.h qpgeomCacheEntry.I \
|
||||
qpgeomCacheManager.h qpgeomCacheManager.I \
|
||||
qpgeomVertexData.h qpgeomVertexData.I \
|
||||
qpgeomVertexDataType.h qpgeomVertexDataType.I \
|
||||
qpgeomVertexFormat.h qpgeomVertexFormat.I \
|
||||
@ -63,7 +64,8 @@
|
||||
qpgeomTrifans.cxx \
|
||||
qpgeomVertexArrayData.cxx \
|
||||
qpgeomVertexArrayFormat.cxx \
|
||||
qpgeomVertexCacheManager.cxx \
|
||||
qpgeomCacheEntry.cxx \
|
||||
qpgeomCacheManager.cxx \
|
||||
qpgeomVertexData.cxx \
|
||||
qpgeomVertexDataType.cxx \
|
||||
qpgeomVertexFormat.cxx \
|
||||
@ -97,7 +99,8 @@
|
||||
qpgeomUsageHint.h \
|
||||
qpgeomVertexArrayData.h qpgeomVertexArrayData.I \
|
||||
qpgeomVertexArrayFormat.h qpgeomVertexArrayFormat.I \
|
||||
qpgeomVertexCacheManager.h qpgeomVertexCacheManager.I \
|
||||
qpgeomCacheEntry.h qpgeomCacheEntry.I \
|
||||
qpgeomCacheManager.h qpgeomCacheManager.I \
|
||||
qpgeomVertexData.h qpgeomVertexData.I \
|
||||
qpgeomVertexDataType.h qpgeomVertexDataType.I \
|
||||
qpgeomVertexFormat.h qpgeomVertexFormat.I \
|
||||
|
@ -19,7 +19,8 @@
|
||||
#include "qpgeomTrifans.cxx"
|
||||
#include "qpgeomVertexArrayData.cxx"
|
||||
#include "qpgeomVertexArrayFormat.cxx"
|
||||
#include "qpgeomVertexCacheManager.cxx"
|
||||
#include "qpgeomCacheEntry.cxx"
|
||||
#include "qpgeomCacheManager.cxx"
|
||||
#include "qpgeomVertexData.cxx"
|
||||
#include "qpgeomVertexDataType.cxx"
|
||||
#include "qpgeomVertexFormat.cxx"
|
||||
|
@ -137,6 +137,28 @@ get_modified() const {
|
||||
return cdata->_modified;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeom::CacheEntry::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE qpGeom::CacheEntry::
|
||||
CacheEntry(const qpGeomMunger *modifier) :
|
||||
_modifier(modifier)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeom::CacheEntry::operator <
|
||||
// Access: Public
|
||||
// Description: Provides a unique ordering within the set.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool qpGeom::CacheEntry::
|
||||
operator < (const CacheEntry &other) const {
|
||||
return (_modifier < other._modifier);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeom::CData::Constructor
|
||||
// Access: Public
|
||||
|
@ -17,7 +17,6 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "qpgeom.h"
|
||||
#include "qpgeomVertexCacheManager.h"
|
||||
#include "pStatTimer.h"
|
||||
#include "bamReader.h"
|
||||
#include "bamWriter.h"
|
||||
@ -77,19 +76,17 @@ qpGeom::
|
||||
// When we destruct, we should ensure that all of our cached
|
||||
// entries, across all pipeline stages, are properly removed from
|
||||
// the cache manager.
|
||||
qpGeomVertexCacheManager *cache_mgr =
|
||||
qpGeomVertexCacheManager::get_global_ptr();
|
||||
|
||||
int num_stages = _cycler.get_num_stages();
|
||||
for (int i = 0; i < num_stages; i++) {
|
||||
if (_cycler.is_stage_unique(i)) {
|
||||
CData *cdata = _cycler.write_stage(i);
|
||||
for (MungedCache::iterator ci = cdata->_munged_cache.begin();
|
||||
ci != cdata->_munged_cache.end();
|
||||
for (Cache::iterator ci = cdata->_cache.begin();
|
||||
ci != cdata->_cache.end();
|
||||
++ci) {
|
||||
cache_mgr->remove_geom(this, (*ci).first);
|
||||
CacheEntry *entry = (*ci);
|
||||
entry->erase();
|
||||
}
|
||||
cdata->_munged_cache.clear();
|
||||
cdata->_cache.clear();
|
||||
_cycler.release_write_stage(i, cdata);
|
||||
}
|
||||
}
|
||||
@ -236,21 +233,22 @@ munge_geom(const qpGeomMunger *munger,
|
||||
// call to record_geom() might recursively call back into this
|
||||
// object, and require a write.
|
||||
const CData *cdata = _cycler.read();
|
||||
MungedCache::const_iterator ci = cdata->_munged_cache.find(munger);
|
||||
if (ci != cdata->_munged_cache.end()) {
|
||||
CacheEntry temp_entry(munger);
|
||||
temp_entry.ref(); // big ugly hack to allow a static ReferenceCount object.
|
||||
Cache::const_iterator ci = cdata->_cache.find(&temp_entry);
|
||||
if (ci != cdata->_cache.end()) {
|
||||
_cycler.release_read(cdata);
|
||||
CacheEntry *entry = (*ci);
|
||||
|
||||
// Record a cache hit, so this element will stay in the cache a
|
||||
// while longer.
|
||||
qpGeomVertexCacheManager *cache_mgr =
|
||||
qpGeomVertexCacheManager::get_global_ptr();
|
||||
cache_mgr->record_geom(this, munger,
|
||||
(*ci).second._geom->get_num_bytes() +
|
||||
(*ci).second._data->get_num_bytes());
|
||||
|
||||
result = (*ci).second._geom;
|
||||
data = (*ci).second._data;
|
||||
entry->refresh();
|
||||
result = entry->_geom_result;
|
||||
data = entry->_data_result;
|
||||
temp_entry.unref();
|
||||
return;
|
||||
}
|
||||
temp_entry.unref();
|
||||
_cycler.release_read(cdata);
|
||||
}
|
||||
|
||||
@ -263,20 +261,21 @@ munge_geom(const qpGeomMunger *munger,
|
||||
|
||||
{
|
||||
// Record the new result in the cache.
|
||||
CacheEntry *entry;
|
||||
{
|
||||
CDWriter cdata(((qpGeom *)this)->_cycler);
|
||||
MungeResult &mr = cdata->_munged_cache[munger];
|
||||
mr._geom = result;
|
||||
mr._data = data;
|
||||
entry = new CacheEntry(munger);
|
||||
entry->_source = (qpGeom *)this;
|
||||
entry->_geom_result = result;
|
||||
entry->_data_result = data;
|
||||
bool inserted = cdata->_cache.insert(entry).second;
|
||||
nassertv(inserted);
|
||||
}
|
||||
|
||||
// And tell the cache manager about the new entry. (It might
|
||||
// immediately request a delete from the cache of the thing we just
|
||||
// added.)
|
||||
qpGeomVertexCacheManager *cache_mgr =
|
||||
qpGeomVertexCacheManager::get_global_ptr();
|
||||
cache_mgr->record_geom(this, munger,
|
||||
result->get_num_bytes() + data->get_num_bytes());
|
||||
// immediately request a delete from the cache of the thing we
|
||||
// just added.)
|
||||
entry->record();
|
||||
}
|
||||
}
|
||||
|
||||
@ -334,16 +333,14 @@ void qpGeom::
|
||||
clear_cache() {
|
||||
// Probably we shouldn't do anything at all here unless we are
|
||||
// running in pipeline stage 0.
|
||||
qpGeomVertexCacheManager *cache_mgr =
|
||||
qpGeomVertexCacheManager::get_global_ptr();
|
||||
|
||||
CData *cdata = CDWriter(_cycler);
|
||||
for (MungedCache::iterator ci = cdata->_munged_cache.begin();
|
||||
ci != cdata->_munged_cache.end();
|
||||
for (Cache::iterator ci = cdata->_cache.begin();
|
||||
ci != cdata->_cache.end();
|
||||
++ci) {
|
||||
cache_mgr->remove_geom(this, (*ci).first);
|
||||
CacheEntry *entry = (*ci);
|
||||
entry->erase();
|
||||
}
|
||||
cdata->_munged_cache.clear();
|
||||
cdata->_cache.clear();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -473,27 +470,6 @@ recompute_bound() {
|
||||
return bound;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeom::remove_cache_entry
|
||||
// Access: Private
|
||||
// Description: Removes a particular entry from the local cache; it
|
||||
// has already been removed from the cache manager.
|
||||
// This is only called from GeomVertexCacheManager.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeom::
|
||||
remove_cache_entry(const qpGeomMunger *modifier) const {
|
||||
// We have to operate on stage 0 of the pipeline, since that's where
|
||||
// the cache really counts. Because of the multistage pipeline, we
|
||||
// might not actually have a cache entry there (it might have been
|
||||
// added to stage 1 instead). No big deal if we don't.
|
||||
CData *cdata = ((qpGeom *)this)->_cycler.write_stage(0);
|
||||
MungedCache::iterator ci = cdata->_munged_cache.find(modifier);
|
||||
if (ci != cdata->_munged_cache.end()) {
|
||||
cdata->_munged_cache.erase(ci);
|
||||
}
|
||||
((qpGeom *)this)->_cycler.release_write_stage(0, cdata);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeom::reset_usage_hint
|
||||
// Access: Private
|
||||
@ -569,6 +545,49 @@ fillin(DatagramIterator &scan, BamReader *manager) {
|
||||
manager->read_cdata(scan, _cycler);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeom::CacheEntry::evict_callback
|
||||
// Access: Public, Virtual
|
||||
// Description: Called when the entry is evicted from the cache, this
|
||||
// should clean up the owning object appropriately.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeom::CacheEntry::
|
||||
evict_callback() {
|
||||
// We have to operate on stage 0 of the pipeline, since that's where
|
||||
// the cache really counts. Because of the multistage pipeline, we
|
||||
// might not actually have a cache entry there (it might have been
|
||||
// added to stage 1 instead). No big deal if we don't.
|
||||
CData *cdata = _source->_cycler.write_stage(0);
|
||||
Cache::iterator ci = cdata->_cache.find(this);
|
||||
if (ci != cdata->_cache.end()) {
|
||||
cdata->_cache.erase(ci);
|
||||
}
|
||||
_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
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeom::CacheEntry::
|
||||
output(ostream &out) const {
|
||||
out << "geom " << (void *)_source << ", "
|
||||
<< (const void *)_modifier;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeom::CData::make_copy
|
||||
// Access: Public, Virtual
|
||||
|
@ -30,9 +30,12 @@
|
||||
#include "qpgeomPrimitive.h"
|
||||
#include "qpgeomMunger.h"
|
||||
#include "qpgeomUsageHint.h"
|
||||
#include "qpgeomCacheEntry.h"
|
||||
#include "updateSeq.h"
|
||||
#include "pointerTo.h"
|
||||
#include "geom.h"
|
||||
#include "indirectLess.h"
|
||||
#include "pset.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : qpGeom
|
||||
@ -98,9 +101,6 @@ public:
|
||||
protected:
|
||||
virtual BoundingVolume *recompute_bound();
|
||||
|
||||
private:
|
||||
void remove_cache_entry(const qpGeomMunger *modifier) const;
|
||||
|
||||
private:
|
||||
typedef pvector<PT(qpGeomPrimitive) > Primitives;
|
||||
|
||||
@ -109,12 +109,21 @@ private:
|
||||
// cache needs to be stored in the CycleData, which makes accurate
|
||||
// cleanup more difficult. We use the GeomVertexCacheManager class
|
||||
// to avoid cache bloat.
|
||||
class MungeResult {
|
||||
class CacheEntry : public qpGeomCacheEntry {
|
||||
public:
|
||||
CPT(qpGeom) _geom;
|
||||
CPT(qpGeomVertexData) _data;
|
||||
INLINE CacheEntry(const qpGeomMunger *modifier);
|
||||
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(qpGeomMunger) _modifier;
|
||||
CPT(qpGeom) _geom_result;
|
||||
CPT(qpGeomVertexData) _data_result;
|
||||
};
|
||||
typedef pmap<CPT(qpGeomMunger), MungeResult> MungedCache;
|
||||
typedef pset<PT(CacheEntry), IndirectLess<CacheEntry> > Cache;
|
||||
|
||||
// This is the data that must be cycled between pipeline stages.
|
||||
class EXPCL_PANDA CData : public CycleData {
|
||||
@ -131,7 +140,7 @@ private:
|
||||
qpGeomUsageHint::UsageHint _usage_hint;
|
||||
bool _got_usage_hint;
|
||||
UpdateSeq _modified;
|
||||
MungedCache _munged_cache;
|
||||
Cache _cache;
|
||||
};
|
||||
|
||||
PipelineCycler<CData> _cycler;
|
||||
@ -171,7 +180,7 @@ public:
|
||||
private:
|
||||
static TypeHandle _type_handle;
|
||||
|
||||
friend class qpGeomVertexCacheManager;
|
||||
friend class CacheEntry;
|
||||
};
|
||||
|
||||
INLINE ostream &operator << (ostream &out, const qpGeom &obj);
|
||||
|
93
panda/src/gobj/qpgeomCacheEntry.I
Normal file
93
panda/src/gobj/qpgeomCacheEntry.I
Normal file
@ -0,0 +1,93 @@
|
||||
// Filename: qpgeomCacheEntry.I
|
||||
// Created by: drose (21Mar05)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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: qpGeomCacheEntry::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE qpGeomCacheEntry::
|
||||
qpGeomCacheEntry() {
|
||||
#ifndef NDEBUG
|
||||
_next = NULL;
|
||||
_prev = NULL;
|
||||
#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
|
||||
// Description: Removes a GeomCacheEntry record from the
|
||||
// doubly-linked list.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpGeomCacheEntry::
|
||||
remove_from_list() {
|
||||
nassertv(_prev->_next == this && _next->_prev == this);
|
||||
_prev->_next = _next;
|
||||
_next->_prev = _prev;
|
||||
#ifndef NDEBUG
|
||||
_next = NULL;
|
||||
_prev = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomCacheEntry::insert_before
|
||||
// Access: Private
|
||||
// Description: Adds a GeomCacheEntry record before the indicated
|
||||
// node in the doubly-linked list.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpGeomCacheEntry::
|
||||
insert_before(qpGeomCacheEntry *node) {
|
||||
nassertv(node->_prev->_next == node && node->_next->_prev == node);
|
||||
nassertv(_prev == (qpGeomCacheEntry *)NULL &&
|
||||
_next == (qpGeomCacheEntry *)NULL);
|
||||
_prev = node->_prev;
|
||||
_next = node;
|
||||
_prev->_next = this;
|
||||
node->_prev = this;
|
||||
}
|
||||
|
||||
INLINE ostream &
|
||||
operator << (ostream &out, const qpGeomCacheEntry &entry) {
|
||||
entry.output(out);
|
||||
return out;
|
||||
}
|
||||
|
127
panda/src/gobj/qpgeomCacheEntry.cxx
Normal file
127
panda/src/gobj/qpgeomCacheEntry.cxx
Normal file
@ -0,0 +1,127 @@
|
||||
// Filename: qpgeomCacheEntry.cxx
|
||||
// Created by: drose (21Mar05)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "qpgeomCacheEntry.h"
|
||||
#include "qpgeomCacheManager.h"
|
||||
#include "mutexHolder.h"
|
||||
#include "config_gobj.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomCacheEntry::Destructor
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
qpGeomCacheEntry::
|
||||
~qpGeomCacheEntry() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomCacheEntry::record
|
||||
// Access: Public
|
||||
// Description: Records the entry in the global cache for the first
|
||||
// time.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PT(qpGeomCacheEntry) qpGeomCacheEntry::
|
||||
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";
|
||||
}
|
||||
|
||||
insert_before(cache_mgr->_list);
|
||||
cache_mgr->_total_size += _result_size;
|
||||
|
||||
// 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
|
||||
// stuff.
|
||||
ref();
|
||||
|
||||
// Now remove any old entries if our cache is over the limit. This may
|
||||
// also remove the entry we just added, especially if our cache size
|
||||
// is set to 0. This may actually remove this very object.
|
||||
cache_mgr->evict_old_entries();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomCacheEntry::erase
|
||||
// Access: Public
|
||||
// Description: Removes the entry from the queue, returning a pointer
|
||||
// to the entry. Does not call evict_callback().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PT(qpGeomCacheEntry) qpGeomCacheEntry::
|
||||
erase() {
|
||||
nassertr(_next != (qpGeomCacheEntry *)NULL && _prev != (qpGeomCacheEntry *)NULL, NULL);
|
||||
|
||||
PT(qpGeomCacheEntry) keepme = this;
|
||||
unref();
|
||||
|
||||
if (gobj_cat.is_debug()) {
|
||||
gobj_cat.debug()
|
||||
<< "remove_entry(" << *this << ")\n";
|
||||
}
|
||||
|
||||
qpGeomCacheManager *cache_mgr = qpGeomCacheManager::get_global_ptr();
|
||||
MutexHolder holder(cache_mgr->_lock);
|
||||
|
||||
remove_from_list();
|
||||
cache_mgr->_total_size -= _result_size;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomCacheEntry::evict_callback
|
||||
// Access: Public, Virtual
|
||||
// Description: Called when the entry is evicted from the cache, this
|
||||
// should clean up the owning object appropriately.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
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
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeomCacheEntry::
|
||||
output(ostream &out) const {
|
||||
out << "[ unknown ]";
|
||||
}
|
69
panda/src/gobj/qpgeomCacheEntry.h
Normal file
69
panda/src/gobj/qpgeomCacheEntry.h
Normal file
@ -0,0 +1,69 @@
|
||||
// Filename: qpgeomCacheEntry.h
|
||||
// Created by: drose (21Mar05)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 qpGEOMCACHEENTRY_H
|
||||
#define qpGEOMCACHEENTRY_H
|
||||
|
||||
#include "pandabase.h"
|
||||
#include "qpgeomCacheManager.h"
|
||||
#include "referenceCount.h"
|
||||
#include "config_gobj.h"
|
||||
#include "pointerTo.h"
|
||||
#include "mutexHolder.h"
|
||||
|
||||
class qpGeom;
|
||||
class qpGeomPrimitive;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : qpGeomCacheEntry
|
||||
// Description : This object contains a single cache entry in the
|
||||
// GeomCacheManager. This is actually the base class of
|
||||
// any number of individual cache types.
|
||||
//
|
||||
// This is part of the experimental Geom rewrite.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA qpGeomCacheEntry : public ReferenceCount {
|
||||
public:
|
||||
INLINE qpGeomCacheEntry();
|
||||
virtual ~qpGeomCacheEntry();
|
||||
|
||||
PT(qpGeomCacheEntry) record();
|
||||
INLINE 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;
|
||||
|
||||
INLINE void remove_from_list();
|
||||
INLINE void insert_before(qpGeomCacheEntry *node);
|
||||
|
||||
private:
|
||||
qpGeomCacheEntry *_prev, *_next;
|
||||
|
||||
friend class qpGeomCacheManager;
|
||||
};
|
||||
|
||||
INLINE ostream &operator << (ostream &out, const qpGeomCacheEntry &entry);
|
||||
|
||||
#include "qpgeomCacheEntry.I"
|
||||
|
||||
#endif
|
58
panda/src/gobj/qpgeomCacheManager.I
Normal file
58
panda/src/gobj/qpgeomCacheManager.I
Normal file
@ -0,0 +1,58 @@
|
||||
// Filename: qpgeomCacheManager.I
|
||||
// Created by: drose (11Mar05)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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: 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.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpGeomCacheManager::
|
||||
set_max_size(int max_size) const {
|
||||
// We directly change the config variable.
|
||||
vertex_convert_cache = 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().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int qpGeomCacheManager::
|
||||
get_max_size() const {
|
||||
return vertex_convert_cache;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// 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.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int qpGeomCacheManager::
|
||||
get_total_size() const {
|
||||
return _total_size;
|
||||
}
|
92
panda/src/gobj/qpgeomCacheManager.cxx
Normal file
92
panda/src/gobj/qpgeomCacheManager.cxx
Normal file
@ -0,0 +1,92 @@
|
||||
// Filename: qpgeomCacheManager.cxx
|
||||
// Created by: drose (11Mar05)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "qpgeomCacheManager.h"
|
||||
#include "qpgeomCacheEntry.h"
|
||||
#include "mutexHolder.h"
|
||||
|
||||
qpGeomCacheManager *qpGeomCacheManager::_global_ptr = NULL;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomCacheManager::Constructor
|
||||
// Access: Protected
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
qpGeomCacheManager::
|
||||
qpGeomCacheManager() :
|
||||
_total_size(0)
|
||||
{
|
||||
// We deliberately hang on to this pointer forever.
|
||||
_list = new qpGeomCacheEntry;
|
||||
_list->ref();
|
||||
_list->_next = _list;
|
||||
_list->_prev = _list;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomCacheManager::Destructor
|
||||
// Access: Protected
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
qpGeomCacheManager::
|
||||
~qpGeomCacheManager() {
|
||||
// Shouldn't be deleting this global object.
|
||||
nassertv(false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomCacheManager::get_global_ptr
|
||||
// Access: Published, Static
|
||||
// Description: Returns the global cache manager pointer.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
qpGeomCacheManager *qpGeomCacheManager::
|
||||
get_global_ptr() {
|
||||
if (_global_ptr == (qpGeomCacheManager *)NULL) {
|
||||
_global_ptr = new qpGeomCacheManager;
|
||||
}
|
||||
return _global_ptr;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomCacheManager::evict_old_entries
|
||||
// Access: Private
|
||||
// Description: Trims the cache size down to get_max_size() by
|
||||
// evicting old cache entries as needed.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeomCacheManager::
|
||||
evict_old_entries() {
|
||||
MutexHolder holder(_lock);
|
||||
|
||||
int max_size = get_max_size();
|
||||
while (_total_size > max_size) {
|
||||
PT(qpGeomCacheEntry) entry = _list->_next;
|
||||
nassertv(entry != _list);
|
||||
entry->unref();
|
||||
|
||||
if (gobj_cat.is_debug()) {
|
||||
gobj_cat.debug()
|
||||
<< "cache total_size = " << _total_size << ", max_size = "
|
||||
<< max_size << ", removing " << *entry << "\n";
|
||||
}
|
||||
|
||||
entry->evict_callback();
|
||||
|
||||
_total_size -= entry->_result_size;
|
||||
entry->remove_from_list();
|
||||
}
|
||||
}
|
91
panda/src/gobj/qpgeomCacheManager.h
Normal file
91
panda/src/gobj/qpgeomCacheManager.h
Normal file
@ -0,0 +1,91 @@
|
||||
// Filename: qpgeomCacheManager.h
|
||||
// Created by: drose (11Mar05)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 qpGEOMCACHEMANAGER_H
|
||||
#define qpGEOMCACHEMANAGER_H
|
||||
|
||||
#include "pandabase.h"
|
||||
#include "config_gobj.h"
|
||||
#include "pmutex.h"
|
||||
|
||||
class qpGeomCacheEntry;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : qpGeomCacheManager
|
||||
// Description : This is used to keep track of, and limit the size of,
|
||||
// the cache of munged vertices, which would otherwise
|
||||
// be distributed through all of the GeomVertexData
|
||||
// objects in the system.
|
||||
//
|
||||
// The actual data in the cache is not stored here, but
|
||||
// rather it is distributed among the various
|
||||
// GeomVertexData source objects. This allows the cache
|
||||
// data to propagate through the multiprocess pipeline.
|
||||
//
|
||||
// This structure actually caches any of a number of
|
||||
// different types of pointers, and mixes them all up in
|
||||
// the same LRU cache list. Some of them (such as
|
||||
// GeomMunger) are reference-counted here in the cache;
|
||||
// most are not.
|
||||
//
|
||||
// This is part of the experimental Geom rewrite.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA qpGeomCacheManager {
|
||||
protected:
|
||||
qpGeomCacheManager();
|
||||
~qpGeomCacheManager();
|
||||
|
||||
PUBLISHED:
|
||||
INLINE void set_max_size(int max_size) const;
|
||||
INLINE int get_max_size() const;
|
||||
|
||||
INLINE int get_total_size() const;
|
||||
|
||||
static qpGeomCacheManager *get_global_ptr();
|
||||
|
||||
public:
|
||||
void evict_old_entries();
|
||||
|
||||
private:
|
||||
// This mutex protects all operations on this object, especially the
|
||||
// linked-list operations.
|
||||
Mutex _lock;
|
||||
|
||||
int _total_size;
|
||||
|
||||
// We maintain a doubly-linked list to keep the cache entries in
|
||||
// least-recently-used order: the items at the head of the list are
|
||||
// ready to be flushed. We use our own doubly-linked list instead
|
||||
// of an STL list, just so we can avoid a tiny bit of overhead,
|
||||
// especially in keeping the pointer directly into the list from the
|
||||
// calling objects.
|
||||
|
||||
// The tail and the head of the list are both kept by the _prev and
|
||||
// _next pointers, respectively, within the following object, which
|
||||
// always exists solely to keep a handle to the list. Keeping a
|
||||
// token of the list this way avoids special cases for an empty
|
||||
// list.
|
||||
qpGeomCacheEntry *_list;
|
||||
|
||||
static qpGeomCacheManager *_global_ptr;
|
||||
friend class qpGeomCacheEntry;
|
||||
};
|
||||
|
||||
#include "qpgeomCacheManager.I"
|
||||
|
||||
#endif
|
@ -17,7 +17,7 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "qpgeomMunger.h"
|
||||
#include "qpgeomVertexCacheManager.h"
|
||||
#include "qpgeomCacheManager.h"
|
||||
#include "mutexHolder.h"
|
||||
#include "pStatTimer.h"
|
||||
|
||||
@ -35,6 +35,29 @@ qpGeomMunger::
|
||||
qpGeomMunger(const GraphicsStateGuardianBase *, const RenderState *) :
|
||||
_is_registered(false)
|
||||
{
|
||||
_registered_key = get_registry()->_mungers.end();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomMunger::Copy Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
qpGeomMunger::
|
||||
qpGeomMunger(const qpGeomMunger ©) :
|
||||
_is_registered(false)
|
||||
{
|
||||
_registered_key = get_registry()->_mungers.end();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomMunger::Copy Assignment Operator
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeomMunger::
|
||||
operator = (const qpGeomMunger ©) {
|
||||
nassertv(!_is_registered);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -205,7 +228,7 @@ compare_to_impl(const qpGeomMunger *other) const {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int qpGeomMunger::
|
||||
geom_compare_to_impl(const qpGeomMunger *other) const {
|
||||
return compare_to_impl(other);
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -237,9 +260,9 @@ do_register() {
|
||||
// Tell the cache manager to hang on to this new GeomMunger, so we
|
||||
// don't waste our time re-registering the same GeomMunger over and
|
||||
// over again.
|
||||
qpGeomVertexCacheManager *cache_mgr =
|
||||
qpGeomVertexCacheManager::get_global_ptr();
|
||||
cache_mgr->record_munger(this);
|
||||
CacheEntry *entry = new CacheEntry;
|
||||
entry->_munger = this;
|
||||
entry->record();
|
||||
|
||||
_is_registered = true;
|
||||
}
|
||||
@ -277,6 +300,27 @@ do_unregister() {
|
||||
_formats.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
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeomMunger::CacheEntry::
|
||||
output(ostream &out) const {
|
||||
out << "munger " << _munger;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomMunger::Registry::Constructor
|
||||
// Access: Public
|
||||
@ -315,6 +359,7 @@ register_munger(qpGeomMunger *munger) {
|
||||
Mungers::iterator mi = _mungers.insert(munger).first;
|
||||
qpGeomMunger *new_munger = (*mi);
|
||||
if (!new_munger->is_registered()) {
|
||||
new_munger->_registered_key = mi;
|
||||
new_munger->do_register();
|
||||
}
|
||||
|
||||
@ -331,8 +376,8 @@ register_munger(qpGeomMunger *munger) {
|
||||
void qpGeomMunger::Registry::
|
||||
unregister_munger(qpGeomMunger *munger) {
|
||||
nassertv(munger->is_registered());
|
||||
Mungers::iterator mi = _mungers.find(munger);
|
||||
nassertv(mi != _mungers.end());
|
||||
_mungers.erase(mi);
|
||||
nassertv(munger->_registered_key != _mungers.end());
|
||||
_mungers.erase(munger->_registered_key);
|
||||
munger->_registered_key = _mungers.end();
|
||||
munger->do_unregister();
|
||||
}
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "typedReferenceCount.h"
|
||||
#include "qpgeomVertexFormat.h"
|
||||
#include "qpgeomVertexData.h"
|
||||
#include "qpgeomCacheEntry.h"
|
||||
#include "indirectCompareTo.h"
|
||||
#include "pStatCollector.h"
|
||||
#include "pointerTo.h"
|
||||
@ -59,6 +60,8 @@ class qpGeom;
|
||||
class EXPCL_PANDA qpGeomMunger : public TypedReferenceCount {
|
||||
public:
|
||||
qpGeomMunger(const GraphicsStateGuardianBase *gsg, const RenderState *state);
|
||||
qpGeomMunger(const qpGeomMunger ©);
|
||||
void operator = (const qpGeomMunger ©);
|
||||
virtual ~qpGeomMunger();
|
||||
|
||||
INLINE bool is_registered() const;
|
||||
@ -94,6 +97,14 @@ private:
|
||||
void do_unregister();
|
||||
|
||||
private:
|
||||
class CacheEntry : public qpGeomCacheEntry {
|
||||
public:
|
||||
virtual int get_result_size() const;
|
||||
virtual void output(ostream &out) const;
|
||||
|
||||
PT(qpGeomMunger) _munger;
|
||||
};
|
||||
|
||||
typedef pmap<const qpGeomVertexFormat *, const qpGeomVertexFormat *> Formats;
|
||||
Formats _formats;
|
||||
|
||||
@ -108,6 +119,15 @@ private:
|
||||
Mungers _mungers;
|
||||
};
|
||||
|
||||
// We store the iterator into the above registry, while we are
|
||||
// registered. This makes it easier to remove our own entry,
|
||||
// especially when the destructor is called. Since it's a virtual
|
||||
// destructor, we can't reliably look up our pointer in the map once
|
||||
// we have reached the base class destructor (since the object has
|
||||
// changed types by then, and the sorting in the map depends partly
|
||||
// on type).
|
||||
Mungers::iterator _registered_key;
|
||||
|
||||
static Registry *_registry;
|
||||
|
||||
static PStatCollector _munge_pcollector;
|
||||
|
@ -21,7 +21,6 @@
|
||||
#include "qpgeomVertexData.h"
|
||||
#include "qpgeomVertexArrayFormat.h"
|
||||
#include "qpgeomVertexDataType.h"
|
||||
#include "qpgeomVertexCacheManager.h"
|
||||
#include "preparedGraphicsObjects.h"
|
||||
#include "internalName.h"
|
||||
#include "bamReader.h"
|
||||
@ -66,16 +65,13 @@ qpGeomPrimitive::
|
||||
// When we destruct, we should ensure that all of our cached
|
||||
// entries, across all pipeline stages, are properly removed from
|
||||
// the cache manager.
|
||||
qpGeomVertexCacheManager *cache_mgr =
|
||||
qpGeomVertexCacheManager::get_global_ptr();
|
||||
|
||||
int num_stages = _cycler.get_num_stages();
|
||||
for (int i = 0; i < num_stages; i++) {
|
||||
if (_cycler.is_stage_unique(i)) {
|
||||
CData *cdata = _cycler.write_stage(i);
|
||||
if (cdata->_decomposed != (qpGeomPrimitive *)NULL) {
|
||||
cache_mgr->remove_primitive(this);
|
||||
cdata->_decomposed = NULL;
|
||||
if (cdata->_cache != (CacheEntry *)NULL) {
|
||||
cdata->_cache->erase();
|
||||
cdata->_cache = NULL;
|
||||
}
|
||||
_cycler.release_write_stage(i, cdata);
|
||||
}
|
||||
@ -446,14 +442,12 @@ decompose() const {
|
||||
// call to record_primitive() might recursively call back into
|
||||
// this object, and require a write.
|
||||
const CData *cdata = _cycler.read();
|
||||
if (cdata->_decomposed != (qpGeomPrimitive *)NULL) {
|
||||
result = cdata->_decomposed;
|
||||
if (cdata->_cache != (CacheEntry *)NULL) {
|
||||
result = cdata->_cache->_decomposed;
|
||||
_cycler.release_read(cdata);
|
||||
// Record a cache hit, so this element will stay in the cache a
|
||||
// while longer.
|
||||
qpGeomVertexCacheManager *cache_mgr =
|
||||
qpGeomVertexCacheManager::get_global_ptr();
|
||||
cache_mgr->record_primitive(this, result->get_num_bytes());
|
||||
cdata->_cache->refresh();
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -472,13 +466,17 @@ decompose() const {
|
||||
}
|
||||
|
||||
// Record the result for the future.
|
||||
CDWriter cdata(((qpGeomPrimitive *)this)->_cycler);
|
||||
cdata->_decomposed = result;
|
||||
CacheEntry *entry;
|
||||
{
|
||||
CDWriter cdata(((qpGeomPrimitive *)this)->_cycler);
|
||||
entry = new CacheEntry;
|
||||
entry->_source = (qpGeomPrimitive *)this;
|
||||
entry->_decomposed = result;
|
||||
cdata->_cache = entry;
|
||||
}
|
||||
|
||||
// And add *this* object to the cache manager.
|
||||
qpGeomVertexCacheManager *cache_mgr =
|
||||
qpGeomVertexCacheManager::get_global_ptr();
|
||||
cache_mgr->record_primitive(this, result->get_num_bytes());
|
||||
entry->record();
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -526,13 +524,10 @@ void qpGeomPrimitive::
|
||||
clear_cache() {
|
||||
// Probably we shouldn't do anything at all here unless we are
|
||||
// running in pipeline stage 0.
|
||||
qpGeomVertexCacheManager *cache_mgr =
|
||||
qpGeomVertexCacheManager::get_global_ptr();
|
||||
|
||||
CData *cdata = CDWriter(_cycler);
|
||||
if (cdata->_decomposed != (qpGeomPrimitive *)NULL) {
|
||||
cache_mgr->remove_primitive(this);
|
||||
cdata->_decomposed = NULL;
|
||||
if (cdata->_cache != (CacheEntry *)NULL) {
|
||||
cdata->_cache->erase();
|
||||
cdata->_cache = NULL;
|
||||
}
|
||||
|
||||
// This, on the other hand, should be applied to the current
|
||||
@ -779,24 +774,6 @@ do_rotate() {
|
||||
cdataw->_rotated_vertices = rotated_vertices;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomPrimitive::remove_cache_entry
|
||||
// Access: Private
|
||||
// Description: Removes a particular entry from the local cache; it
|
||||
// has already been removed from the cache manager.
|
||||
// This is only called from GeomVertexCacheManager.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeomPrimitive::
|
||||
remove_cache_entry() const {
|
||||
// We have to operate on stage 0 of the pipeline, since that's where
|
||||
// the cache really counts. Because of the multistage pipeline, we
|
||||
// might not actually have a cache entry there (it might have been
|
||||
// added to stage 1 instead). No big deal if we don't.
|
||||
CData *cdata = ((qpGeomPrimitive *)this)->_cycler.write_stage(0);
|
||||
cdata->_decomposed = NULL;
|
||||
((qpGeomPrimitive *)this)->_cycler.release_write_stage(0, cdata);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomPrimitive::recompute_minmax
|
||||
// Access: Private
|
||||
@ -896,6 +873,46 @@ fillin(DatagramIterator &scan, BamReader *manager) {
|
||||
manager->read_cdata(scan, _cycler);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomPrimitive::CacheEntry::evict_callback
|
||||
// Access: Public, Virtual
|
||||
// Description: Called when the entry is evicted from the cache, this
|
||||
// should clean up the owning object appropriately.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeomPrimitive::CacheEntry::
|
||||
evict_callback() {
|
||||
// We have to operate on stage 0 of the pipeline, since that's where
|
||||
// the cache really counts. Because of the multistage pipeline, we
|
||||
// might not actually have a cache entry there (it might have been
|
||||
// added to stage 1 instead). No big deal if we don't.
|
||||
CData *cdata = _source->_cycler.write_stage(0);
|
||||
if (cdata->_cache == this) {
|
||||
cdata->_cache = NULL;
|
||||
}
|
||||
_source->_cycler.release_write_stage(0, cdata);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomPrimitive::CacheEntry::get_result_size
|
||||
// Access: Public, Virtual
|
||||
// Description: Returns the approximate number of bytes represented
|
||||
// by the computed result.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int qpGeomPrimitive::CacheEntry::
|
||||
get_result_size() const {
|
||||
return _decomposed->get_num_bytes();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomPrimitive::CacheEntry::output
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeomPrimitive::CacheEntry::
|
||||
output(ostream &out) const {
|
||||
out << "primitive " << (void *)_source;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomPrimitive::CData::make_copy
|
||||
// Access: Public, Virtual
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
#include "pandabase.h"
|
||||
#include "qpgeomUsageHint.h"
|
||||
#include "qpgeomCacheEntry.h"
|
||||
#include "typedWritableReferenceCount.h"
|
||||
#include "luse.h"
|
||||
#include "updateSeq.h"
|
||||
@ -163,7 +164,6 @@ protected:
|
||||
|
||||
private:
|
||||
void do_rotate();
|
||||
void remove_cache_entry() const;
|
||||
|
||||
protected:
|
||||
static PStatCollector _rotate_pcollector;
|
||||
@ -179,6 +179,17 @@ private:
|
||||
typedef pmap<PreparedGraphicsObjects *, IndexBufferContext *> Contexts;
|
||||
Contexts _contexts;
|
||||
|
||||
class CacheEntry : public qpGeomCacheEntry {
|
||||
public:
|
||||
virtual void evict_callback();
|
||||
virtual int get_result_size() const;
|
||||
virtual void output(ostream &out) const;
|
||||
|
||||
qpGeomPrimitive *_source;
|
||||
CPT(qpGeomPrimitive) _decomposed;
|
||||
};
|
||||
|
||||
|
||||
// This is the data that must be cycled between pipeline stages.
|
||||
class EXPCL_PANDA CData : public CycleData {
|
||||
public:
|
||||
@ -201,7 +212,7 @@ private:
|
||||
unsigned short _min_vertex;
|
||||
unsigned short _max_vertex;
|
||||
|
||||
CPT(qpGeomPrimitive) _decomposed;
|
||||
PT(CacheEntry) _cache;
|
||||
};
|
||||
|
||||
PipelineCycler<CData> _cycler;
|
||||
@ -234,7 +245,6 @@ private:
|
||||
static TypeHandle _type_handle;
|
||||
|
||||
friend class qpGeom;
|
||||
friend class qpGeomVertexCacheManager;
|
||||
friend class PreparedGraphicsObjects;
|
||||
};
|
||||
|
||||
|
@ -141,7 +141,7 @@ public:
|
||||
private:
|
||||
static TypeHandle _type_handle;
|
||||
|
||||
friend class qpGeomVertexCacheManager;
|
||||
friend class qpGeomCacheManager;
|
||||
friend class PreparedGraphicsObjects;
|
||||
};
|
||||
|
||||
|
@ -1,303 +0,0 @@
|
||||
// Filename: qpgeomVertexCacheManager.I
|
||||
// Created by: drose (11Mar05)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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: qpGeomVertexCacheManager::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.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpGeomVertexCacheManager::
|
||||
set_max_size(int max_size) const {
|
||||
// We directly change the config variable.
|
||||
vertex_convert_cache = max_size;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::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().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int qpGeomVertexCacheManager::
|
||||
get_max_size() const {
|
||||
return vertex_convert_cache;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::get_total_size
|
||||
// Access: Published
|
||||
// Description: Returns the amount of memory, in bytes, currently
|
||||
// consumed by the cache of pre-processed vertex data.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int qpGeomVertexCacheManager::
|
||||
get_total_size() const {
|
||||
return _total_size;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::record_munger
|
||||
// Access: Private
|
||||
// Description: Records a new GeomMunger in the cache, or marks a
|
||||
// cache hit for a previously-recorded munger. This
|
||||
// should only be called by GeomMunger.
|
||||
//
|
||||
// The cache manager will hold a reference on the
|
||||
// GeomMunger pointer until it expires from the cache.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpGeomVertexCacheManager::
|
||||
record_munger(const qpGeomMunger *munger) {
|
||||
// Make up a nominal result_size for a munger.
|
||||
record_entry(Entry(munger, 100));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::record_primitive
|
||||
// Access: Private
|
||||
// Description: Records a new entry in the cache, or marks a cache
|
||||
// hit for a previous entry in the cache. This should
|
||||
// only be called by GeomPrimitive.
|
||||
//
|
||||
// The cache manager will not hold a reference on the
|
||||
// GeomPrimitive pointer; if it destructs, it should
|
||||
// call remove_primitive() to remove itself from the cache.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpGeomVertexCacheManager::
|
||||
record_primitive(const qpGeomPrimitive *primitive, int result_size) {
|
||||
record_entry(Entry(primitive, result_size));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::remove_primitive
|
||||
// Access: Private
|
||||
// Description: Removes an entry from the cache, if it is there.
|
||||
// Quietly ignores it if it is not. This should only be
|
||||
// called by GeomPrimitive.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpGeomVertexCacheManager::
|
||||
remove_primitive(const qpGeomPrimitive *primitive) {
|
||||
remove_entry(Entry(primitive, 0));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::record_geom
|
||||
// Access: Private
|
||||
// Description: Records a new entry in the cache, or marks a cache
|
||||
// hit for a previous entry in the cache. This should
|
||||
// only be called by Geom.
|
||||
//
|
||||
// The cache manager will not hold a reference on the
|
||||
// Geom pointer; if it destructs, it should call
|
||||
// remove_geom() to remove itself from the cache.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpGeomVertexCacheManager::
|
||||
record_geom(const qpGeom *source, const qpGeomMunger *modifier,
|
||||
int result_size) {
|
||||
record_entry(Entry(source, modifier, result_size));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::remove_geom
|
||||
// Access: Private
|
||||
// Description: Removes an entry from the cache, if it is there.
|
||||
// Quietly ignores it if it is not. This should only be
|
||||
// called by GeomVertexData.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpGeomVertexCacheManager::
|
||||
remove_geom(const qpGeom *source, const qpGeomMunger *modifier) {
|
||||
remove_entry(Entry(source, modifier, 0));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::dequeue_entry
|
||||
// Access: Private
|
||||
// Description: Removes an Entry record from the doubly-linked list.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpGeomVertexCacheManager::
|
||||
dequeue_entry(qpGeomVertexCacheManager::Entry *entry) {
|
||||
nassertv(entry->_prev->_next == entry &&
|
||||
entry->_next->_prev == entry);
|
||||
entry->_prev->_next = entry->_next;
|
||||
entry->_next->_prev = entry->_prev;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::enqueue_entry
|
||||
// Access: Private
|
||||
// Description: Adds an Entry record to the tail of the doubly-linked
|
||||
// list.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpGeomVertexCacheManager::
|
||||
enqueue_entry(qpGeomVertexCacheManager::Entry *entry) {
|
||||
nassertv(_list->_prev->_next == _list &&
|
||||
_list->_next->_prev == _list);
|
||||
entry->_prev = _list->_prev;
|
||||
entry->_next = _list;
|
||||
entry->_prev->_next = entry;
|
||||
_list->_prev = entry;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::Entry::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE qpGeomVertexCacheManager::Entry::
|
||||
Entry() :
|
||||
_cache_type(CT_none),
|
||||
_result_size(0)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::Entry::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE qpGeomVertexCacheManager::Entry::
|
||||
Entry(const qpGeomMunger *munger, int result_size) :
|
||||
_cache_type(CT_munger),
|
||||
_result_size(result_size)
|
||||
{
|
||||
_u._munger = munger;
|
||||
_u._munger->ref();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::Entry::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE qpGeomVertexCacheManager::Entry::
|
||||
Entry(const qpGeomPrimitive *primitive, int result_size) :
|
||||
_cache_type(CT_primitive),
|
||||
_result_size(result_size)
|
||||
{
|
||||
_u._primitive = primitive;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::Entry::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE qpGeomVertexCacheManager::Entry::
|
||||
Entry(const qpGeom *source, const qpGeomMunger *modifier,
|
||||
int result_size) :
|
||||
_cache_type(CT_geom),
|
||||
_result_size(result_size)
|
||||
{
|
||||
_u._geom._source = source;
|
||||
_u._geom._modifier = modifier;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::Entry::Copy Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE qpGeomVertexCacheManager::Entry::
|
||||
Entry(const qpGeomVertexCacheManager::Entry ©) :
|
||||
_cache_type(copy._cache_type),
|
||||
_result_size(copy._result_size)
|
||||
{
|
||||
_u = copy._u;
|
||||
if (_cache_type == CT_munger) {
|
||||
_u._munger->ref();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::Entry::Copy Assignment Operator
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpGeomVertexCacheManager::Entry::
|
||||
operator = (const qpGeomVertexCacheManager::Entry ©) {
|
||||
if (_cache_type == CT_munger) {
|
||||
unref_delete(_u._munger);
|
||||
}
|
||||
_cache_type = copy._cache_type;
|
||||
_result_size = copy._result_size;
|
||||
_u = copy._u;
|
||||
if (_cache_type == CT_munger) {
|
||||
_u._munger->ref();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::Entry::Destructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE qpGeomVertexCacheManager::Entry::
|
||||
~Entry() {
|
||||
if (_cache_type == CT_munger) {
|
||||
unref_delete(_u._munger);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::Entry::operator <
|
||||
// Access: Public
|
||||
// Description: Provides a unique ordering for EntriesIndex.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool qpGeomVertexCacheManager::Entry::
|
||||
operator < (const qpGeomVertexCacheManager::Entry &other) const {
|
||||
if (_cache_type != other._cache_type) {
|
||||
return (int)_cache_type < (int)other._cache_type;
|
||||
}
|
||||
|
||||
switch (_cache_type) {
|
||||
case CT_none:
|
||||
// We shouldn't be adding the end-of-list token to the index.
|
||||
nassertr(false, false);
|
||||
return false;
|
||||
|
||||
case CT_munger:
|
||||
return _u._munger < other._u._munger;
|
||||
|
||||
case CT_primitive:
|
||||
return _u._primitive < other._u._primitive;
|
||||
|
||||
case CT_geom:
|
||||
if (_u._geom._source != other._u._geom._source) {
|
||||
return _u._geom._source < other._u._geom._source;
|
||||
}
|
||||
if (_u._geom._modifier != other._u._geom._modifier) {
|
||||
return _u._geom._modifier->geom_compare_to(*other._u._geom._modifier) < 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
INLINE ostream &
|
||||
operator << (ostream &out, const qpGeomVertexCacheManager::Entry &entry) {
|
||||
entry.output(out);
|
||||
return out;
|
||||
}
|
||||
|
@ -1,196 +0,0 @@
|
||||
// Filename: qpgeomVertexCacheManager.cxx
|
||||
// Created by: drose (11Mar05)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "qpgeomVertexCacheManager.h"
|
||||
#include "mutexHolder.h"
|
||||
|
||||
qpGeomVertexCacheManager *qpGeomVertexCacheManager::_global_ptr = NULL;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::Constructor
|
||||
// Access: Protected
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
qpGeomVertexCacheManager::
|
||||
qpGeomVertexCacheManager() :
|
||||
_total_size(0)
|
||||
{
|
||||
_list = new Entry;
|
||||
_list->_next = _list;
|
||||
_list->_prev = _list;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::Destructor
|
||||
// Access: Protected
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
qpGeomVertexCacheManager::
|
||||
~qpGeomVertexCacheManager() {
|
||||
// Shouldn't be deleting this global object.
|
||||
nassertv(false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::get_global_ptr
|
||||
// Access: Published, Static
|
||||
// Description: Returns the global cache manager pointer.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
qpGeomVertexCacheManager *qpGeomVertexCacheManager::
|
||||
get_global_ptr() {
|
||||
if (_global_ptr == (qpGeomVertexCacheManager *)NULL) {
|
||||
_global_ptr = new qpGeomVertexCacheManager;
|
||||
}
|
||||
return _global_ptr;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::record_data
|
||||
// Access: Private
|
||||
// Description: Records a new generic entry in the cache, or marks a
|
||||
// cache hit for a previous entry in the cache.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeomVertexCacheManager::
|
||||
record_entry(const qpGeomVertexCacheManager::Entry &const_entry) {
|
||||
MutexHolder holder(_lock);
|
||||
|
||||
EntriesIndex::iterator ii = _entries_index.find((Entry *)&const_entry);
|
||||
if (ii != _entries_index.end()) {
|
||||
// We already had this entry in the cache. Refresh it.
|
||||
if (gobj_cat.is_spam()) {
|
||||
gobj_cat.spam()
|
||||
<< "refreshing cache entry: " << const_entry << "\n";
|
||||
}
|
||||
|
||||
// Move the previous cache entry to the tail of the list.
|
||||
Entry *entry = (*ii);
|
||||
dequeue_entry(entry);
|
||||
enqueue_entry(entry);
|
||||
|
||||
_total_size += (const_entry._result_size - entry->_result_size);
|
||||
entry->_result_size = const_entry._result_size;
|
||||
|
||||
} else {
|
||||
// There was no such entry already in the cache. Add it.
|
||||
if (gobj_cat.is_debug()) {
|
||||
gobj_cat.debug()
|
||||
<< "recording cache entry: " << const_entry << ", total_size = "
|
||||
<< _total_size + const_entry._result_size << "\n";
|
||||
}
|
||||
|
||||
Entry *entry = new Entry(const_entry);
|
||||
enqueue_entry(entry);
|
||||
_total_size += entry->_result_size;
|
||||
|
||||
// Also record an index entry.
|
||||
bool inserted = _entries_index.insert(entry).second;
|
||||
nassertv(inserted);
|
||||
}
|
||||
|
||||
// Now remove any old entries if our cache is over the limit. This may
|
||||
// also remove the entry we just added, especially if our cache size
|
||||
// is set to 0.
|
||||
int max_size = get_max_size();
|
||||
while (_total_size > max_size) {
|
||||
Entry *entry = _list->_next;
|
||||
nassertv(entry != _list);
|
||||
|
||||
if (gobj_cat.is_debug()) {
|
||||
gobj_cat.debug()
|
||||
<< "cache total_size = " << _total_size << ", max_size = "
|
||||
<< max_size << ", removing " << *entry << "\n";
|
||||
}
|
||||
|
||||
ii = _entries_index.find(entry);
|
||||
nassertv(ii != _entries_index.end());
|
||||
|
||||
switch (entry->_cache_type) {
|
||||
case CT_primitive:
|
||||
entry->_u._primitive->remove_cache_entry();
|
||||
break;
|
||||
|
||||
case CT_geom:
|
||||
entry->_u._geom._source->remove_cache_entry
|
||||
(entry->_u._geom._modifier);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
_total_size -= entry->_result_size;
|
||||
_entries_index.erase(ii);
|
||||
|
||||
dequeue_entry(entry);
|
||||
delete entry;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::remove_entry
|
||||
// Access: Private
|
||||
// Description: Removes an entry from the cache, if it is there.
|
||||
// Quietly ignores it if it is not.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeomVertexCacheManager::
|
||||
remove_entry(const qpGeomVertexCacheManager::Entry &const_entry) {
|
||||
if (gobj_cat.is_debug()) {
|
||||
gobj_cat.debug()
|
||||
<< "remove_entry(" << const_entry << ")\n";
|
||||
}
|
||||
MutexHolder holder(_lock);
|
||||
|
||||
EntriesIndex::iterator ii = _entries_index.find((Entry *)&const_entry);
|
||||
if (ii != _entries_index.end()) {
|
||||
Entry *entry = (*ii);
|
||||
_total_size -= entry->_result_size;
|
||||
_entries_index.erase(ii);
|
||||
dequeue_entry(entry);
|
||||
delete entry;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::Entry::output
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeomVertexCacheManager::Entry::
|
||||
output(ostream &out) const {
|
||||
out << "[ ";
|
||||
switch (_cache_type) {
|
||||
case CT_none:
|
||||
out << "end-of-list token";
|
||||
break;
|
||||
|
||||
case CT_munger:
|
||||
out << "munger " << (void *)_u._munger << ":"
|
||||
<< _u._munger->get_ref_count();
|
||||
break;
|
||||
|
||||
case CT_primitive:
|
||||
out << "primitive " << (void *)_u._primitive;
|
||||
break;
|
||||
|
||||
case CT_geom:
|
||||
out << "geom " << (void *)_u._geom._source << ", "
|
||||
<< (void *)_u._geom._modifier;
|
||||
break;
|
||||
}
|
||||
|
||||
out << ", result_size = " << _result_size << " ]";
|
||||
}
|
@ -1,167 +0,0 @@
|
||||
// Filename: qpgeomVertexCacheManager.h
|
||||
// Created by: drose (11Mar05)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 qpGEOMVERTEXCACHEMANAGER_H
|
||||
#define qpGEOMVERTEXCACHEMANAGER_H
|
||||
|
||||
#include "pandabase.h"
|
||||
#include "qpgeomMunger.h"
|
||||
#include "config_gobj.h"
|
||||
#include "pointerTo.h"
|
||||
#include "pmutex.h"
|
||||
#include "indirectLess.h"
|
||||
#include "plist.h"
|
||||
#include "pmap.h"
|
||||
|
||||
class qpGeom;
|
||||
class qpGeomPrimitive;
|
||||
class qpGeomVertexData;
|
||||
class qpGeomVertexFormat;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : qpGeomVertexCacheManager
|
||||
// Description : This is used to keep track of, and limit the size of,
|
||||
// the cache of munged vertices, which would otherwise
|
||||
// be distributed through all of the GeomVertexData
|
||||
// objects in the system.
|
||||
//
|
||||
// The actual data in the cache is not stored here, but
|
||||
// rather it is distributed among the various
|
||||
// GeomVertexData source objects. This allows the cache
|
||||
// data to propagate through the multiprocess pipeline.
|
||||
//
|
||||
// This structure actually caches any of a number of
|
||||
// different types of pointers, and mixes them all up in
|
||||
// the same LRU cache list. Some of them (such as
|
||||
// GeomMunger) are reference-counted here in the cache;
|
||||
// most are not.
|
||||
//
|
||||
// This is part of the experimental Geom rewrite.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA qpGeomVertexCacheManager {
|
||||
protected:
|
||||
qpGeomVertexCacheManager();
|
||||
~qpGeomVertexCacheManager();
|
||||
|
||||
public:
|
||||
class Entry;
|
||||
|
||||
PUBLISHED:
|
||||
INLINE void set_max_size(int max_size) const;
|
||||
INLINE int get_max_size() const;
|
||||
|
||||
INLINE int get_total_size() const;
|
||||
|
||||
static qpGeomVertexCacheManager *get_global_ptr();
|
||||
|
||||
private:
|
||||
INLINE void record_munger(const qpGeomMunger *munger);
|
||||
INLINE void record_primitive(const qpGeomPrimitive *primitive,
|
||||
int result_size);
|
||||
INLINE void remove_primitive(const qpGeomPrimitive *primitive);
|
||||
INLINE void record_geom(const qpGeom *source,
|
||||
const qpGeomMunger *modifier,
|
||||
int result_size);
|
||||
INLINE void remove_geom(const qpGeom *source,
|
||||
const qpGeomMunger *modifier);
|
||||
|
||||
void record_entry(const Entry &const_entry);
|
||||
void remove_entry(const Entry &const_entry);
|
||||
|
||||
INLINE void dequeue_entry(Entry *entry);
|
||||
INLINE void enqueue_entry(Entry *entry);
|
||||
|
||||
private:
|
||||
// This mutex protects all operations on this object.
|
||||
Mutex _lock;
|
||||
|
||||
int _total_size;
|
||||
|
||||
enum CacheType {
|
||||
CT_none,
|
||||
CT_munger,
|
||||
CT_primitive,
|
||||
CT_geom,
|
||||
};
|
||||
|
||||
public:
|
||||
// This class is public only so we can declare the global ostream
|
||||
// output operator. It doesn't need to be visible outside this
|
||||
// class. It contains a single cache entry, which might actually be
|
||||
// any of a handful of different pointer types. The enumerated type
|
||||
// declared above, and the union declared below, serve to implement
|
||||
// this C-style polymorphism.
|
||||
class Entry {
|
||||
public:
|
||||
INLINE Entry();
|
||||
INLINE Entry(const qpGeomMunger *munger, int result_size);
|
||||
INLINE Entry(const qpGeomPrimitive *primitive, int result_size);
|
||||
INLINE Entry(const qpGeom *source, const qpGeomMunger *modifier,
|
||||
int result_size);
|
||||
INLINE Entry(const Entry ©);
|
||||
INLINE void operator = (const Entry ©);
|
||||
INLINE ~Entry();
|
||||
INLINE bool operator < (const Entry &other) const;
|
||||
|
||||
void output(ostream &out) const;
|
||||
|
||||
CacheType _cache_type;
|
||||
int _result_size;
|
||||
union {
|
||||
const qpGeomMunger *_munger;
|
||||
const qpGeomPrimitive *_primitive;
|
||||
struct {
|
||||
const qpGeom *_source;
|
||||
const qpGeomMunger *_modifier;
|
||||
} _geom;
|
||||
} _u;
|
||||
|
||||
Entry *_prev, *_next;
|
||||
};
|
||||
|
||||
private:
|
||||
// We maintain a doubly-linked list to keep the cache entries in
|
||||
// least-recently-used order: the items at the head of the list are
|
||||
// ready to be flushed. We use our own doubly-linked list instead
|
||||
// of an STL list, just so we can avoid a tiny bit of overhead,
|
||||
// especially with managing the pointer to the entry in
|
||||
// _entries_index.
|
||||
|
||||
// The tail and the head of the list are both kept by the _prev and
|
||||
// _next pointers, respectively, within the following object, which
|
||||
// always exists solely to keep a handle to the list. Keeping a
|
||||
// token of the list this way avoids special cases for an empty
|
||||
// list.
|
||||
Entry *_list;
|
||||
|
||||
// And this indexes into the above list, for fast lookup.
|
||||
typedef pset<Entry *, IndirectLess<Entry> > EntriesIndex;
|
||||
EntriesIndex _entries_index;
|
||||
|
||||
static qpGeomVertexCacheManager *_global_ptr;
|
||||
|
||||
friend class qpGeomMunger;
|
||||
friend class qpGeomPrimitive;
|
||||
friend class qpGeom;
|
||||
};
|
||||
|
||||
INLINE ostream &operator << (ostream &out, const qpGeomVertexCacheManager::Entry &entry);
|
||||
|
||||
#include "qpgeomVertexCacheManager.I"
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user