clean up caching a bit, multitex in gl
This commit is contained in:
parent
720fddb73b
commit
92a93e8af0
|
|
@ -433,6 +433,8 @@ reset() {
|
|||
|
||||
_glActiveTexture = (PFNGLACTIVETEXTUREPROC)
|
||||
get_extension_func(GLPREFIX_QUOTED, "ActiveTexture");
|
||||
_glClientActiveTexture = (PFNGLACTIVETEXTUREPROC)
|
||||
get_extension_func(GLPREFIX_QUOTED, "ClientActiveTexture");
|
||||
_glMultiTexCoord2fv = (PFNGLMULTITEXCOORD2FVPROC)
|
||||
get_extension_func(GLPREFIX_QUOTED, "MultiTexCoord2fv");
|
||||
|
||||
|
|
@ -441,12 +443,15 @@ reset() {
|
|||
|
||||
_glActiveTexture = (PFNGLACTIVETEXTUREPROC)
|
||||
get_extension_func(GLPREFIX_QUOTED, "ActiveTextureARB");
|
||||
_glClientActiveTexture = (PFNGLACTIVETEXTUREPROC)
|
||||
get_extension_func(GLPREFIX_QUOTED, "ClientActiveTextureARB");
|
||||
_glMultiTexCoord2fv = (PFNGLMULTITEXCOORD2FVPROC)
|
||||
get_extension_func(GLPREFIX_QUOTED, "MultiTexCoord2fvARB");
|
||||
}
|
||||
|
||||
if (_supports_multitexture) {
|
||||
if (_glActiveTexture == NULL || _glMultiTexCoord2fv == NULL) {
|
||||
if (_glActiveTexture == NULL || _glClientActiveTexture == NULL ||
|
||||
_glMultiTexCoord2fv == NULL) {
|
||||
GLCAT.warning()
|
||||
<< "Multitexture advertised as supported by OpenGL runtime, but could not get pointers to extension functions.\n";
|
||||
_supports_multitexture = false;
|
||||
|
|
@ -454,6 +459,7 @@ reset() {
|
|||
}
|
||||
if (!_supports_multitexture) {
|
||||
_glActiveTexture = null_glActiveTexture;
|
||||
_glClientActiveTexture = null_glActiveTexture;
|
||||
}
|
||||
|
||||
_supports_buffers = false;
|
||||
|
|
@ -707,6 +713,7 @@ reset() {
|
|||
_current_tex_gen = DCAST(TexGenAttrib, TexGenAttrib::make());
|
||||
_needs_tex_gen = false;
|
||||
_tex_gen_modifies_mat = false;
|
||||
_last_max_stage_index = 0;
|
||||
_auto_antialias_mode = false;
|
||||
_render_mode = RenderModeAttrib::M_filled;
|
||||
|
||||
|
|
@ -2041,12 +2048,13 @@ begin_draw_primitives(const qpGeom *geom, const qpGeomVertexData *vertex_data) {
|
|||
if (geom->get_usage_hint() == qpGeomUsageHint::UH_static &&
|
||||
_vertex_data->get_usage_hint() == qpGeomUsageHint::UH_static &&
|
||||
display_lists) {
|
||||
// If the geom appears to be totally static, try to build it into
|
||||
// If the geom claims to be totally static, try to build it into
|
||||
// a display list.
|
||||
GeomContext *gc = ((qpGeom *)geom)->prepare_now(get_prepared_objects(), this);
|
||||
nassertr(gc != (GeomContext *)NULL, false);
|
||||
CLP(GeomContext) *ggc = DCAST(CLP(GeomContext), gc);
|
||||
if (ggc->_modified == geom->get_modified()) {
|
||||
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.
|
||||
GLP(CallList)(ggc->_index);
|
||||
#ifdef DO_PSTATS
|
||||
|
|
@ -2064,7 +2072,7 @@ begin_draw_primitives(const qpGeom *geom, const qpGeomVertexData *vertex_data) {
|
|||
} else {
|
||||
GLP(NewList)(ggc->_index, GL_COMPILE);
|
||||
}
|
||||
ggc->_modified = geom->get_modified();
|
||||
ggc->_modified = modified;
|
||||
|
||||
#ifdef DO_PSTATS
|
||||
// Count up the number of vertices used by primitives in the Geom,
|
||||
|
|
@ -2115,17 +2123,53 @@ begin_draw_primitives(const qpGeom *geom, const qpGeomVertexData *vertex_data) {
|
|||
GLP(DisableClientState)(GL_COLOR_ARRAY);
|
||||
}
|
||||
|
||||
if (_vertex_data->get_array_info(InternalName::get_texcoord(),
|
||||
array_data, num_components, numeric_type,
|
||||
start, stride)) {
|
||||
const unsigned char *client_pointer = setup_array_data(array_data);
|
||||
GLP(TexCoordPointer)(num_components, get_numeric_type(numeric_type),
|
||||
stride, client_pointer + start);
|
||||
GLP(EnableClientState)(GL_TEXTURE_COORD_ARRAY);
|
||||
} else {
|
||||
GLP(DisableClientState)(GL_TEXTURE_COORD_ARRAY);
|
||||
// Now set up each of the active texture coordinate stages--or at
|
||||
// least those for which we're not generating texture coordinates
|
||||
// automatically.
|
||||
const Geom::ActiveTextureStages &active_stages =
|
||||
_current_texture->get_on_stages();
|
||||
const Geom::NoTexCoordStages &no_texcoords =
|
||||
_current_tex_gen->get_no_texcoords();
|
||||
|
||||
int max_stage_index = (int)active_stages.size();
|
||||
int stage_index = 0;
|
||||
while (stage_index < max_stage_index) {
|
||||
_glClientActiveTexture(GL_TEXTURE0 + stage_index);
|
||||
TextureStage *stage = active_stages[stage_index];
|
||||
if (no_texcoords.find(stage) == no_texcoords.end()) {
|
||||
// This stage is not one of the stages that doesn't need
|
||||
// texcoords issued for it.
|
||||
const InternalName *name = stage->get_texcoord_name();
|
||||
|
||||
if (_vertex_data->get_array_info(name, array_data, num_components,
|
||||
numeric_type, start, stride)) {
|
||||
// The vertex data does have texcoords for this stage.
|
||||
const unsigned char *client_pointer = setup_array_data(array_data);
|
||||
GLP(TexCoordPointer)(num_components, get_numeric_type(numeric_type),
|
||||
stride, client_pointer + start);
|
||||
GLP(EnableClientState)(GL_TEXTURE_COORD_ARRAY);
|
||||
|
||||
} else {
|
||||
// The vertex data doesn't have texcoords for this stage (even
|
||||
// though they're needed).
|
||||
GLP(DisableClientState)(GL_TEXTURE_COORD_ARRAY);
|
||||
}
|
||||
} else {
|
||||
// No texcoords are needed for this stage.
|
||||
GLP(DisableClientState)(GL_TEXTURE_COORD_ARRAY);
|
||||
}
|
||||
|
||||
++stage_index;
|
||||
}
|
||||
|
||||
// Be sure also to disable any texture stages we had enabled before.
|
||||
while (stage_index < _last_max_stage_index) {
|
||||
_glClientActiveTexture(GL_TEXTURE0 + stage_index);
|
||||
GLP(DisableClientState)(GL_TEXTURE_COORD_ARRAY);
|
||||
++stage_index;
|
||||
}
|
||||
_last_max_stage_index = max_stage_index;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -2528,7 +2572,7 @@ setup_array_data(const qpGeomVertexArrayData *data) {
|
|||
nassertr(vbc != (VertexBufferContext *)NULL, data->get_data());
|
||||
apply_vertex_buffer(vbc);
|
||||
|
||||
// NULL is the OpenGL convention for the first byte of the buffer.
|
||||
// NULL is the OpenGL convention for the first byte of the buffer object.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -2659,7 +2703,7 @@ setup_primitive(const qpGeomPrimitive *data) {
|
|||
nassertr(ibc != (IndexBufferContext *)NULL, data->get_flat_last_vertices());
|
||||
apply_index_buffer(ibc);
|
||||
|
||||
// NULL is the OpenGL convention for the first byte of the buffer.
|
||||
// NULL is the OpenGL convention for the first byte of the buffer object.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -318,7 +318,7 @@ protected:
|
|||
int _pass_number;
|
||||
bool _auto_rescale_normal;
|
||||
CLP(GeomContext) *_geom_display_list;
|
||||
float _num_display_list_verts_before;
|
||||
int _last_max_stage_index;
|
||||
|
||||
int _error_count;
|
||||
|
||||
|
|
@ -340,6 +340,7 @@ public:
|
|||
|
||||
bool _supports_multitexture;
|
||||
PFNGLACTIVETEXTUREPROC _glActiveTexture;
|
||||
PFNGLCLIENTACTIVETEXTUREPROC _glClientActiveTexture;
|
||||
PFNGLMULTITEXCOORD2FVPROC _glMultiTexCoord2fv;
|
||||
|
||||
bool _supports_buffers;
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@ modify_primitive(int i) {
|
|||
CDWriter cdata(_cycler);
|
||||
nassertr(i >= 0 && i < (int)cdata->_primitives.size(), NULL);
|
||||
cdata->_got_usage_hint = false;
|
||||
cdata->_modified = qpGeom::get_next_modified();
|
||||
return cdata->_primitives[i];
|
||||
}
|
||||
|
||||
|
|
@ -117,6 +118,23 @@ set_primitive(int i, const qpGeomPrimitive *primitive) {
|
|||
}
|
||||
}
|
||||
cdata->_primitives[i] = (qpGeomPrimitive *)primitive;
|
||||
cdata->_modified = qpGeom::get_next_modified();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeom::get_modified
|
||||
// Access: Published
|
||||
// Description: Returns a sequence number which is guaranteed to
|
||||
// change at least every time any of the primitives in
|
||||
// the Geom is modified, or the set of primitives is
|
||||
// modified. However, this does not include
|
||||
// modifications to the vertex data, which should be
|
||||
// tested separately.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE UpdateSeq qpGeom::
|
||||
get_modified() const {
|
||||
CDReader cdata(_cycler);
|
||||
return cdata->_modified;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -141,7 +159,8 @@ CData(const qpGeom::CData ©) :
|
|||
_data(copy._data),
|
||||
_primitives(copy._primitives),
|
||||
_usage_hint(copy._usage_hint),
|
||||
_got_usage_hint(copy._got_usage_hint)
|
||||
_got_usage_hint(copy._got_usage_hint),
|
||||
_modified(copy._modified)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -157,6 +157,7 @@ add_primitive(const qpGeomPrimitive *primitive) {
|
|||
if (cdata->_got_usage_hint) {
|
||||
cdata->_usage_hint = min(cdata->_usage_hint, primitive->get_usage_hint());
|
||||
}
|
||||
cdata->_modified = qpGeom::get_next_modified();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -176,6 +177,7 @@ remove_primitive(int i) {
|
|||
cdata->_got_usage_hint = false;
|
||||
}
|
||||
cdata->_primitives.erase(cdata->_primitives.begin() + i);
|
||||
cdata->_modified = qpGeom::get_next_modified();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -214,40 +216,6 @@ get_num_bytes() const {
|
|||
return num_bytes;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeom::get_modified
|
||||
// Access: Published
|
||||
// Description: Returns the maximum UpdateSeq of all the Geom's
|
||||
// individual primitives and vertex arrays. This,
|
||||
// therefore, will change only when any part of the Geom
|
||||
// changes.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
UpdateSeq qpGeom::
|
||||
get_modified() const {
|
||||
CDReader cdata(_cycler);
|
||||
UpdateSeq seq;
|
||||
|
||||
Primitives::const_iterator pi;
|
||||
for (pi = cdata->_primitives.begin();
|
||||
pi != cdata->_primitives.end();
|
||||
++pi) {
|
||||
UpdateSeq pseq = (*pi)->get_modified();
|
||||
if (seq < pseq) {
|
||||
seq = pseq;
|
||||
}
|
||||
}
|
||||
|
||||
int num_arrays = cdata->_data->get_num_arrays();
|
||||
for (int i = 0; i < num_arrays; ++i) {
|
||||
UpdateSeq aseq = cdata->_data->get_array(i)->get_modified();
|
||||
if (seq < aseq) {
|
||||
seq = aseq;
|
||||
}
|
||||
}
|
||||
|
||||
return seq;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeom::munge_geom
|
||||
// Access: Published
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ PUBLISHED:
|
|||
void clear_primitives();
|
||||
|
||||
int get_num_bytes() const;
|
||||
UpdateSeq get_modified() const;
|
||||
INLINE UpdateSeq get_modified() const;
|
||||
|
||||
void munge_geom(const qpGeomMunger *munger,
|
||||
CPT(qpGeom) &result, CPT(qpGeomVertexData) &data) const;
|
||||
|
|
@ -129,6 +129,7 @@ private:
|
|||
Primitives _primitives;
|
||||
qpGeomUsageHint::UsageHint _usage_hint;
|
||||
bool _got_usage_hint;
|
||||
UpdateSeq _modified;
|
||||
MungedCache _munged_cache;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -197,6 +197,11 @@ get_ends() const {
|
|||
INLINE CPTA_ushort qpGeomPrimitive::
|
||||
get_mins() const {
|
||||
CDReader cdata(_cycler);
|
||||
if (!cdata->_got_minmax) {
|
||||
CDWriter cdataw(((qpGeomPrimitive *)this)->_cycler, cdata);
|
||||
((qpGeomPrimitive *)this)->recompute_minmax(cdataw);
|
||||
return cdataw->_mins;
|
||||
}
|
||||
return cdata->_mins;
|
||||
}
|
||||
|
||||
|
|
@ -214,6 +219,11 @@ get_mins() const {
|
|||
INLINE CPTA_ushort qpGeomPrimitive::
|
||||
get_maxs() const {
|
||||
CDReader cdata(_cycler);
|
||||
if (!cdata->_got_minmax) {
|
||||
CDWriter cdataw(((qpGeomPrimitive *)this)->_cycler, cdata);
|
||||
((qpGeomPrimitive *)this)->recompute_minmax(cdataw);
|
||||
return cdataw->_maxs;
|
||||
}
|
||||
return cdata->_maxs;
|
||||
}
|
||||
|
||||
|
|
@ -252,7 +262,9 @@ INLINE int qpGeomPrimitive::
|
|||
get_min_vertex() const {
|
||||
CDReader cdata(_cycler);
|
||||
if (!cdata->_got_minmax) {
|
||||
((qpGeomPrimitive *)this)->recompute_minmax();
|
||||
CDWriter cdataw(((qpGeomPrimitive *)this)->_cycler, cdata);
|
||||
((qpGeomPrimitive *)this)->recompute_minmax(cdataw);
|
||||
return cdataw->_min_vertex;
|
||||
}
|
||||
return cdata->_min_vertex;
|
||||
}
|
||||
|
|
@ -265,12 +277,9 @@ get_min_vertex() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int qpGeomPrimitive::
|
||||
get_min_vertex(int i) const {
|
||||
CDReader cdata(_cycler);
|
||||
if (!cdata->_got_minmax) {
|
||||
((qpGeomPrimitive *)this)->recompute_minmax();
|
||||
}
|
||||
nassertr(i >= 0 && i < (int)cdata->_mins.size(), -1);
|
||||
return cdata->_mins[i];
|
||||
CPTA_ushort mins = get_mins();
|
||||
nassertr(i >= 0 && i < (int)mins.size(), -1);
|
||||
return mins[i];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -283,7 +292,9 @@ INLINE int qpGeomPrimitive::
|
|||
get_max_vertex() const {
|
||||
CDReader cdata(_cycler);
|
||||
if (!cdata->_got_minmax) {
|
||||
((qpGeomPrimitive *)this)->recompute_minmax();
|
||||
CDWriter cdataw(((qpGeomPrimitive *)this)->_cycler, cdata);
|
||||
((qpGeomPrimitive *)this)->recompute_minmax(cdataw);
|
||||
return cdataw->_max_vertex;
|
||||
}
|
||||
return cdata->_max_vertex;
|
||||
}
|
||||
|
|
@ -296,12 +307,9 @@ get_max_vertex() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int qpGeomPrimitive::
|
||||
get_max_vertex(int i) const {
|
||||
CDReader cdata(_cycler);
|
||||
if (!cdata->_got_minmax) {
|
||||
((qpGeomPrimitive *)this)->recompute_minmax();
|
||||
}
|
||||
nassertr(i >= 0 && i < (int)cdata->_maxs.size(), -1);
|
||||
return cdata->_maxs[i];
|
||||
CPTA_ushort maxs = get_maxs();
|
||||
nassertr(i >= 0 && i < (int)maxs.size(), -1);
|
||||
return maxs[i];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -804,9 +804,7 @@ remove_cache_entry() const {
|
|||
// necessary.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeomPrimitive::
|
||||
recompute_minmax() {
|
||||
CDWriter cdata(_cycler);
|
||||
|
||||
recompute_minmax(qpGeomPrimitive::CDWriter &cdata) {
|
||||
if (cdata->_vertices.empty()) {
|
||||
cdata->_min_vertex = 0;
|
||||
cdata->_max_vertex = 0;
|
||||
|
|
|
|||
|
|
@ -77,8 +77,8 @@ PUBLISHED:
|
|||
SM_smooth,
|
||||
|
||||
// SM_uniform: all vertices across all faces have the same colors
|
||||
// and normals. It doesn't matter which ShadeModelAttrib mode is
|
||||
// used to render this primitive.
|
||||
// and normals. It doesn't really matter which ShadeModelAttrib
|
||||
// mode is used to render this primitive.
|
||||
SM_uniform,
|
||||
|
||||
// SM_flat_(first,last)_vertex: each face within the primitive
|
||||
|
|
@ -208,7 +208,7 @@ private:
|
|||
typedef CycleDataReader<CData> CDReader;
|
||||
typedef CycleDataWriter<CData> CDWriter;
|
||||
|
||||
void recompute_minmax();
|
||||
void recompute_minmax(CDWriter &cdata);
|
||||
|
||||
public:
|
||||
virtual void write_datagram(BamWriter *manager, Datagram &dg);
|
||||
|
|
|
|||
|
|
@ -101,36 +101,6 @@ remove_primitive(const qpGeomPrimitive *primitive) {
|
|||
remove_entry(Entry(primitive, 0));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::record_data
|
||||
// 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 GeomVertexData.
|
||||
//
|
||||
// The cache manager will not hold a reference on the
|
||||
// GeomVertexData pointer; if it destructs, it should
|
||||
// call remove_data() to remove itself from the cache.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpGeomVertexCacheManager::
|
||||
record_data(const qpGeomVertexData *source, const qpGeomVertexFormat *modifier,
|
||||
int result_size) {
|
||||
record_entry(Entry(source, modifier, result_size));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::remove_data
|
||||
// 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_data(const qpGeomVertexData *source,
|
||||
const qpGeomVertexFormat *modifier) {
|
||||
remove_entry(Entry(source, modifier, 0));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::record_geom
|
||||
// Access: Private
|
||||
|
|
@ -139,8 +109,8 @@ remove_data(const qpGeomVertexData *source,
|
|||
// 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.
|
||||
// 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,
|
||||
|
|
@ -153,13 +123,54 @@ record_geom(const qpGeom *source, const qpGeomMunger *modifier,
|
|||
// 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 Geom.
|
||||
// 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
|
||||
|
|
@ -193,22 +204,8 @@ Entry(const qpGeomPrimitive *primitive, int result_size) :
|
|||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE qpGeomVertexCacheManager::Entry::
|
||||
Entry(const qpGeomVertexData *source, const qpGeomVertexFormat *modifier,
|
||||
Entry(const qpGeom *source, const qpGeomMunger *modifier,
|
||||
int result_size) :
|
||||
_cache_type(CT_data),
|
||||
_result_size(result_size)
|
||||
{
|
||||
_u._data._source = source;
|
||||
_u._data._modifier = modifier;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// 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)
|
||||
{
|
||||
|
|
@ -269,19 +266,22 @@ INLINE qpGeomVertexCacheManager::Entry::
|
|||
////////////////////////////////////////////////////////////////////
|
||||
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_data:
|
||||
if (_u._data._source != other._u._data._source) {
|
||||
return _u._data._source < other._u._data._source;
|
||||
}
|
||||
return _u._data._modifier < other._u._data._modifier;
|
||||
|
||||
case CT_geom:
|
||||
if (_u._geom._source != other._u._geom._source) {
|
||||
return _u._geom._source < other._u._geom._source;
|
||||
|
|
@ -289,7 +289,7 @@ operator < (const qpGeomVertexCacheManager::Entry &other) const {
|
|||
return _u._geom._modifier < other._u._geom._modifier;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
INLINE ostream &
|
||||
|
|
|
|||
|
|
@ -30,6 +30,9 @@ qpGeomVertexCacheManager::
|
|||
qpGeomVertexCacheManager() :
|
||||
_total_size(0)
|
||||
{
|
||||
_list = new Entry;
|
||||
_list->_next = _list;
|
||||
_list->_prev = _list;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -39,6 +42,8 @@ qpGeomVertexCacheManager() :
|
|||
////////////////////////////////////////////////////////////////////
|
||||
qpGeomVertexCacheManager::
|
||||
~qpGeomVertexCacheManager() {
|
||||
// Shouldn't be deleting this global object.
|
||||
nassertv(false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -61,80 +66,77 @@ get_global_ptr() {
|
|||
// cache hit for a previous entry in the cache.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeomVertexCacheManager::
|
||||
record_entry(const qpGeomVertexCacheManager::Entry &entry) {
|
||||
record_entry(const qpGeomVertexCacheManager::Entry &const_entry) {
|
||||
MutexHolder holder(_lock);
|
||||
EntriesIndex::iterator ii = _entries_index.find(&entry);
|
||||
if (ii != _entries_index.end()) {
|
||||
// Remove the previous cache entry.
|
||||
Entries::iterator ei = (*ii).second;
|
||||
_total_size -= (*ei)._result_size;
|
||||
_entries_index.erase(ii);
|
||||
_entries.erase(ei);
|
||||
|
||||
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: " << entry << "\n";
|
||||
<< "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: " << entry << ", total_size = "
|
||||
<< _total_size + entry._result_size << "\n";
|
||||
<< "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);
|
||||
}
|
||||
|
||||
// Add the new entry at the end of the list, so it will be the last
|
||||
// to be removed.
|
||||
Entries::iterator ei =
|
||||
_entries.insert(_entries.end(), entry);
|
||||
Entry *entry_pointer = &(*ei);
|
||||
|
||||
// Also record an index entry.
|
||||
bool inserted = _entries_index.insert
|
||||
(EntriesIndex::value_type(entry_pointer, ei)).second;
|
||||
nassertv(inserted);
|
||||
|
||||
_total_size += entry_pointer->_result_size;
|
||||
|
||||
// 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) {
|
||||
nassertv(!_entries.empty());
|
||||
ei = _entries.begin();
|
||||
entry_pointer = &(*ei);
|
||||
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_pointer << "\n";
|
||||
<< max_size << ", removing " << *entry << "\n";
|
||||
}
|
||||
|
||||
ii = _entries_index.find(entry_pointer);
|
||||
ii = _entries_index.find(entry);
|
||||
nassertv(ii != _entries_index.end());
|
||||
|
||||
switch (entry_pointer->_cache_type) {
|
||||
case CT_data:
|
||||
entry_pointer->_u._data._source->remove_cache_entry
|
||||
(entry_pointer->_u._data._modifier);
|
||||
break;
|
||||
|
||||
switch (entry->_cache_type) {
|
||||
case CT_primitive:
|
||||
entry_pointer->_u._primitive->remove_cache_entry();
|
||||
entry->_u._primitive->remove_cache_entry();
|
||||
break;
|
||||
|
||||
case CT_geom:
|
||||
entry_pointer->_u._geom._source->remove_cache_entry
|
||||
(entry_pointer->_u._geom._modifier);
|
||||
entry->_u._geom._source->remove_cache_entry
|
||||
(entry->_u._geom._modifier);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
_total_size -= entry_pointer->_result_size;
|
||||
_total_size -= entry->_result_size;
|
||||
_entries_index.erase(ii);
|
||||
_entries.erase(ei);
|
||||
|
||||
dequeue_entry(entry);
|
||||
delete entry;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -145,19 +147,20 @@ record_entry(const qpGeomVertexCacheManager::Entry &entry) {
|
|||
// Quietly ignores it if it is not.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeomVertexCacheManager::
|
||||
remove_entry(const qpGeomVertexCacheManager::Entry &entry) {
|
||||
remove_entry(const qpGeomVertexCacheManager::Entry &const_entry) {
|
||||
if (gobj_cat.is_debug()) {
|
||||
gobj_cat.debug()
|
||||
<< "remove_entry(" << entry << ")\n";
|
||||
<< "remove_entry(" << const_entry << ")\n";
|
||||
}
|
||||
MutexHolder holder(_lock);
|
||||
|
||||
EntriesIndex::iterator ii = _entries_index.find(&entry);
|
||||
EntriesIndex::iterator ii = _entries_index.find((Entry *)&const_entry);
|
||||
if (ii != _entries_index.end()) {
|
||||
Entries::iterator ei = (*ii).second;
|
||||
_total_size -= (*ei)._result_size;
|
||||
Entry *entry = (*ii);
|
||||
_total_size -= entry->_result_size;
|
||||
_entries_index.erase(ii);
|
||||
_entries.erase(ei);
|
||||
dequeue_entry(entry);
|
||||
delete entry;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -170,6 +173,10 @@ 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();
|
||||
|
|
@ -179,11 +186,6 @@ output(ostream &out) const {
|
|||
out << "primitive " << (void *)_u._primitive;
|
||||
break;
|
||||
|
||||
case CT_data:
|
||||
out << "data " << (void *)_u._data._source << ", "
|
||||
<< (void *)_u._data._modifier;
|
||||
break;
|
||||
|
||||
case CT_geom:
|
||||
out << "geom " << (void *)_u._geom._source << ", "
|
||||
<< (void *)_u._geom._modifier;
|
||||
|
|
|
|||
|
|
@ -74,18 +74,17 @@ private:
|
|||
INLINE void record_primitive(const qpGeomPrimitive *primitive,
|
||||
int result_size);
|
||||
INLINE void remove_primitive(const qpGeomPrimitive *primitive);
|
||||
INLINE void record_data(const qpGeomVertexData *source,
|
||||
const qpGeomVertexFormat *modifier,
|
||||
int result_size);
|
||||
INLINE void remove_data(const qpGeomVertexData *source,
|
||||
const qpGeomVertexFormat *modifier);
|
||||
INLINE void record_geom(const qpGeom *source,
|
||||
const qpGeomMunger *modifier,
|
||||
int result_size);
|
||||
INLINE void remove_geom(const qpGeom *geom, const qpGeomMunger *modifier);
|
||||
INLINE void remove_geom(const qpGeom *source,
|
||||
const qpGeomMunger *modifier);
|
||||
|
||||
void record_entry(const Entry &entry);
|
||||
void remove_entry(const Entry &entry);
|
||||
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.
|
||||
|
|
@ -94,9 +93,9 @@ private:
|
|||
int _total_size;
|
||||
|
||||
enum CacheType {
|
||||
CT_none,
|
||||
CT_munger,
|
||||
CT_primitive,
|
||||
CT_data,
|
||||
CT_geom,
|
||||
};
|
||||
|
||||
|
|
@ -109,10 +108,9 @@ public:
|
|||
// 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 qpGeomVertexData *source,
|
||||
const qpGeomVertexFormat *modifier, int result_size);
|
||||
INLINE Entry(const qpGeom *source, const qpGeomMunger *modifier,
|
||||
int result_size);
|
||||
INLINE Entry(const Entry ©);
|
||||
|
|
@ -127,32 +125,38 @@ public:
|
|||
union {
|
||||
const qpGeomMunger *_munger;
|
||||
const qpGeomPrimitive *_primitive;
|
||||
struct {
|
||||
const qpGeomVertexData *_source;
|
||||
const qpGeomVertexFormat *_modifier;
|
||||
} _data;
|
||||
struct {
|
||||
const qpGeom *_source;
|
||||
const qpGeomMunger *_modifier;
|
||||
} _geom;
|
||||
} _u;
|
||||
|
||||
Entry *_prev, *_next;
|
||||
};
|
||||
|
||||
private:
|
||||
// This list keeps the cache entries in least-recently-used order:
|
||||
// the items at the head of the list are ready to be flushed.
|
||||
typedef plist<Entry> Entries;
|
||||
Entries _entries;
|
||||
// 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 pmap<const Entry *, Entries::iterator, IndirectLess<Entry> > EntriesIndex;
|
||||
typedef pset<Entry *, IndirectLess<Entry> > EntriesIndex;
|
||||
EntriesIndex _entries_index;
|
||||
|
||||
static qpGeomVertexCacheManager *_global_ptr;
|
||||
|
||||
friend class qpGeomMunger;
|
||||
friend class qpGeomPrimitive;
|
||||
friend class qpGeomVertexData;
|
||||
friend class qpGeom;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -91,6 +91,19 @@ get_array(int i) const {
|
|||
return cdata->_arrays[i];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexData::get_modified
|
||||
// Access: Published
|
||||
// Description: Returns a sequence number which is guaranteed to
|
||||
// change at least every time the vertex data is
|
||||
// modified.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE UpdateSeq qpGeomVertexData::
|
||||
get_modified() const {
|
||||
CDReader cdata(_cycler);
|
||||
return cdata->_modified;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexData::CData::Constructor
|
||||
// Access: Public
|
||||
|
|
@ -107,7 +120,8 @@ CData() {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE qpGeomVertexData::CData::
|
||||
CData(const qpGeomVertexData::CData ©) :
|
||||
_arrays(copy._arrays)
|
||||
_arrays(copy._arrays),
|
||||
_modified(copy._modified)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@
|
|||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "qpgeomVertexData.h"
|
||||
#include "qpgeomVertexCacheManager.h"
|
||||
#include "pStatTimer.h"
|
||||
#include "bamReader.h"
|
||||
#include "bamWriter.h"
|
||||
|
|
@ -93,25 +92,6 @@ operator = (const qpGeomVertexData ©) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
qpGeomVertexData::
|
||||
~qpGeomVertexData() {
|
||||
// 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 (ConvertedCache::iterator ci = cdata->_converted_cache.begin();
|
||||
ci != cdata->_converted_cache.end();
|
||||
++ci) {
|
||||
cache_mgr->remove_data(this, (*ci).first);
|
||||
}
|
||||
cdata->_converted_cache.clear();
|
||||
_cycler.release_write_stage(i, cdata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -144,7 +124,6 @@ get_num_vertices() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeomVertexData::
|
||||
clear_vertices() {
|
||||
clear_cache();
|
||||
CDWriter cdata(_cycler);
|
||||
nassertv(_format->get_num_arrays() == (int)cdata->_arrays.size());
|
||||
|
||||
|
|
@ -154,6 +133,7 @@ clear_vertices() {
|
|||
++ai) {
|
||||
(*ai)->clear_vertices();
|
||||
}
|
||||
cdata->_modified = qpGeom::get_next_modified();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -170,13 +150,13 @@ modify_array(int i) {
|
|||
// Perform copy-on-write: if the reference count on the vertex data
|
||||
// is greater than 1, assume some other GeomVertexData has the same
|
||||
// pointer, so make a copy of it first.
|
||||
clear_cache();
|
||||
CDWriter cdata(_cycler);
|
||||
nassertr(i >= 0 && i < (int)cdata->_arrays.size(), NULL);
|
||||
|
||||
if (cdata->_arrays[i]->get_ref_count() > 1) {
|
||||
cdata->_arrays[i] = new qpGeomVertexArrayData(*cdata->_arrays[i]);
|
||||
}
|
||||
cdata->_modified = qpGeom::get_next_modified();
|
||||
|
||||
return cdata->_arrays[i];
|
||||
}
|
||||
|
|
@ -191,10 +171,10 @@ modify_array(int i) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeomVertexData::
|
||||
set_array(int i, const qpGeomVertexArrayData *array) {
|
||||
clear_cache();
|
||||
CDWriter cdata(_cycler);
|
||||
nassertv(i >= 0 && i < (int)cdata->_arrays.size());
|
||||
cdata->_arrays[i] = (qpGeomVertexArrayData *)array;
|
||||
cdata->_modified = qpGeom::get_next_modified();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -232,28 +212,6 @@ convert_to(const qpGeomVertexFormat *new_format) const {
|
|||
return this;
|
||||
}
|
||||
|
||||
// Look up the format in our cache--maybe we've recently converted
|
||||
// to the requested format.
|
||||
{
|
||||
// Use read() and release_read() instead of CDReader, because the
|
||||
// call to record_data() might recursively call back into this
|
||||
// object, and require a write.
|
||||
const CData *cdata = _cycler.read();
|
||||
ConvertedCache::const_iterator ci =
|
||||
cdata->_converted_cache.find(new_format);
|
||||
if (ci != cdata->_converted_cache.end()) {
|
||||
_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_data(this, new_format, (*ci).second->get_num_bytes());
|
||||
|
||||
return (*ci).second;
|
||||
}
|
||||
_cycler.release_read(cdata);
|
||||
}
|
||||
|
||||
// Okay, convert the data to the new format.
|
||||
int num_vertices = get_num_vertices();
|
||||
|
||||
|
|
@ -326,19 +284,6 @@ convert_to(const qpGeomVertexFormat *new_format) const {
|
|||
}
|
||||
}
|
||||
|
||||
// Record the new result in the cache.
|
||||
{
|
||||
CDWriter cdata(((qpGeomVertexData *)this)->_cycler);
|
||||
cdata->_converted_cache[new_format] = new_data;
|
||||
}
|
||||
|
||||
// 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_data(this, new_format, new_data->get_num_bytes());
|
||||
|
||||
return new_data;
|
||||
}
|
||||
|
||||
|
|
@ -362,28 +307,6 @@ write(ostream &out, int indent_level) const {
|
|||
_format->write_with_data(out, indent_level, this);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexData::clear_cache
|
||||
// Access: Published
|
||||
// Description: Removes all of the previously-cached results of
|
||||
// convert_to().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeomVertexData::
|
||||
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 (ConvertedCache::iterator ci = cdata->_converted_cache.begin();
|
||||
ci != cdata->_converted_cache.end();
|
||||
++ci) {
|
||||
cache_mgr->remove_data(this, (*ci).first);
|
||||
}
|
||||
cdata->_converted_cache.clear();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexData::set_data
|
||||
// Access: Public
|
||||
|
|
@ -695,27 +618,6 @@ unpack_argb(float data[4], unsigned int packed_argb) {
|
|||
data[3] = (float)((packed_argb >> 24) & 0xff) / 255.0f;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexData::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 qpGeomVertexData::
|
||||
remove_cache_entry(const qpGeomVertexFormat *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 = ((qpGeomVertexData *)this)->_cycler.write_stage(0);
|
||||
ConvertedCache::iterator ci = cdata->_converted_cache.find(modifier);
|
||||
if (ci != cdata->_converted_cache.end()) {
|
||||
cdata->_converted_cache.erase(ci);
|
||||
}
|
||||
((qpGeomVertexData *)this)->_cycler.release_write_stage(0, cdata);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexData::do_set_num_vertices
|
||||
// Access: Private
|
||||
|
|
@ -728,13 +630,18 @@ do_set_num_vertices(int n, qpGeomVertexData::CDWriter &cdata) {
|
|||
bool any_changed = false;
|
||||
|
||||
for (size_t i = 0; i < cdata->_arrays.size(); i++) {
|
||||
if (cdata->_arrays[i]->set_num_vertices(n)) {
|
||||
if (cdata->_arrays[i]->get_num_vertices() != n) {
|
||||
// Copy-on-write.
|
||||
if (cdata->_arrays[i]->get_ref_count() > 1) {
|
||||
cdata->_arrays[i] = new qpGeomVertexArrayData(*cdata->_arrays[i]);
|
||||
}
|
||||
cdata->_arrays[i]->set_num_vertices(n);
|
||||
any_changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (any_changed) {
|
||||
clear_cache();
|
||||
cdata->_modified = qpGeom::get_next_modified();
|
||||
}
|
||||
|
||||
return any_changed;
|
||||
|
|
|
|||
|
|
@ -82,14 +82,13 @@ PUBLISHED:
|
|||
void set_array(int i, const qpGeomVertexArrayData *array);
|
||||
|
||||
int get_num_bytes() const;
|
||||
INLINE UpdateSeq get_modified() const;
|
||||
|
||||
CPT(qpGeomVertexData) convert_to(const qpGeomVertexFormat *new_format) const;
|
||||
|
||||
void output(ostream &out) const;
|
||||
void write(ostream &out, int indent_level = 0) const;
|
||||
|
||||
void clear_cache();
|
||||
|
||||
public:
|
||||
void set_data(int array, const qpGeomVertexDataType *data_type,
|
||||
int vertex, const float *data, int num_values);
|
||||
|
|
@ -109,22 +108,12 @@ public:
|
|||
static unsigned int pack_argb(const float data[4]);
|
||||
static void unpack_argb(float data[4], unsigned int packed_argb);
|
||||
|
||||
private:
|
||||
void remove_cache_entry(const qpGeomVertexFormat *modifier) const;
|
||||
|
||||
private:
|
||||
CPT(qpGeomVertexFormat) _format;
|
||||
qpGeomUsageHint::UsageHint _usage_hint;
|
||||
|
||||
typedef pvector< PT(qpGeomVertexArrayData) > Arrays;
|
||||
|
||||
// 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.
|
||||
typedef pmap<CPT(qpGeomVertexFormat), CPT(qpGeomVertexData) > ConvertedCache;
|
||||
|
||||
// This is the data that must be cycled between pipeline stages.
|
||||
class EXPCL_PANDA CData : public CycleData {
|
||||
public:
|
||||
|
|
@ -136,7 +125,7 @@ private:
|
|||
virtual void fillin(DatagramIterator &scan, BamReader *manager);
|
||||
|
||||
Arrays _arrays;
|
||||
ConvertedCache _converted_cache;
|
||||
UpdateSeq _modified;
|
||||
};
|
||||
|
||||
PipelineCycler<CData> _cycler;
|
||||
|
|
@ -172,8 +161,6 @@ public:
|
|||
|
||||
private:
|
||||
static TypeHandle _type_handle;
|
||||
|
||||
friend class qpGeomVertexCacheManager;
|
||||
};
|
||||
|
||||
INLINE ostream &operator << (ostream &out, const qpGeomVertexData &obj);
|
||||
|
|
|
|||
|
|
@ -155,21 +155,79 @@ get_bin_index() const {
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RenderState::is_flat_shaded
|
||||
// Function: RenderState::get_color
|
||||
// Access: Published
|
||||
// Description: Returns true if this RenderState specifies a flat
|
||||
// shading model (that is, per-vertex color applies to
|
||||
// entire triangles), or false if it specifies a smooth
|
||||
// shading model or does not specify.
|
||||
// Description: This function is provided as an optimization, to
|
||||
// speed up the render-time checking for the existance
|
||||
// of a ColorAttrib on this state. It returns a
|
||||
// pointer to the ColorAttrib, if there is one, or
|
||||
// NULL if there is not.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool RenderState::
|
||||
is_flat_shaded() const {
|
||||
if ((_flags & F_checked_flat_shaded) == 0) {
|
||||
INLINE const ColorAttrib *RenderState::
|
||||
get_color() const {
|
||||
if ((_flags & F_checked_color) == 0) {
|
||||
// We pretend this function is const, even though it transparently
|
||||
// modifies the internal flat_shaded cache.
|
||||
((RenderState *)this)->determine_flat_shaded();
|
||||
// modifies the internal color cache.
|
||||
((RenderState *)this)->determine_color();
|
||||
}
|
||||
return ((_flags & F_flat_shaded) != 0);
|
||||
return _color;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RenderState::get_color_scale
|
||||
// Access: Published
|
||||
// Description: This function is provided as an optimization, to
|
||||
// speed up the render-time checking for the existance
|
||||
// of a ColorScaleAttrib on this state. It returns a
|
||||
// pointer to the ColorScaleAttrib, if there is one, or
|
||||
// NULL if there is not.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const ColorScaleAttrib *RenderState::
|
||||
get_color_scale() const {
|
||||
if ((_flags & F_checked_color_scale) == 0) {
|
||||
// We pretend this function is const, even though it transparently
|
||||
// modifies the internal color_scale cache.
|
||||
((RenderState *)this)->determine_color_scale();
|
||||
}
|
||||
return _color_scale;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RenderState::get_texture
|
||||
// Access: Published
|
||||
// Description: This function is provided as an optimization, to
|
||||
// speed up the render-time checking for the existance
|
||||
// of a TextureAttrib on this state. It returns a
|
||||
// pointer to the TextureAttrib, if there is one, or
|
||||
// NULL if there is not.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const TextureAttrib *RenderState::
|
||||
get_texture() const {
|
||||
if ((_flags & F_checked_texture) == 0) {
|
||||
// We pretend this function is const, even though it transparently
|
||||
// modifies the internal texture cache.
|
||||
((RenderState *)this)->determine_texture();
|
||||
}
|
||||
return _texture;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RenderState::get_tex_gen
|
||||
// Access: Published
|
||||
// Description: This function is provided as an optimization, to
|
||||
// speed up the render-time checking for the existance
|
||||
// of a TexGenAttrib on this state. It returns a
|
||||
// pointer to the TexGenAttrib, if there is one, or
|
||||
// NULL if there is not.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const TexGenAttrib *RenderState::
|
||||
get_tex_gen() const {
|
||||
if ((_flags & F_checked_tex_gen) == 0) {
|
||||
// We pretend this function is const, even though it transparently
|
||||
// modifies the internal tex_gen cache.
|
||||
((RenderState *)this)->determine_tex_gen();
|
||||
}
|
||||
return _tex_gen;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -22,7 +22,10 @@
|
|||
#include "cullBinManager.h"
|
||||
#include "fogAttrib.h"
|
||||
#include "transparencyAttrib.h"
|
||||
#include "shadeModelAttrib.h"
|
||||
#include "colorAttrib.h"
|
||||
#include "colorScaleAttrib.h"
|
||||
#include "textureAttrib.h"
|
||||
#include "texGenAttrib.h"
|
||||
#include "pStatTimer.h"
|
||||
#include "config_pgraph.h"
|
||||
#include "bamReader.h"
|
||||
|
|
@ -1513,23 +1516,63 @@ determine_transparency() {
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RenderState::determine_flat_shaded
|
||||
// Function: RenderState::determine_color
|
||||
// Access: Private
|
||||
// Description: This is the private implementation of
|
||||
// is_flat_shaded().
|
||||
// Description: This is the private implementation of get_color().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void RenderState::
|
||||
determine_flat_shaded() {
|
||||
const RenderAttrib *attrib =
|
||||
get_attrib(ShadeModelAttrib::get_class_type());
|
||||
determine_color() {
|
||||
const RenderAttrib *attrib = get_attrib(ColorAttrib::get_class_type());
|
||||
_color = (const ColorAttrib *)NULL;
|
||||
if (attrib != (const RenderAttrib *)NULL) {
|
||||
const ShadeModelAttrib *sma = DCAST(ShadeModelAttrib, attrib);
|
||||
if (sma->get_mode() == ShadeModelAttrib::M_flat) {
|
||||
_flags |= F_flat_shaded;
|
||||
}
|
||||
_color = DCAST(ColorAttrib, attrib);
|
||||
}
|
||||
_flags |= F_checked_color;
|
||||
}
|
||||
|
||||
_flags |= F_checked_flat_shaded;
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RenderState::determine_color_scale
|
||||
// Access: Private
|
||||
// Description: This is the private implementation of get_color_scale().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void RenderState::
|
||||
determine_color_scale() {
|
||||
const RenderAttrib *attrib = get_attrib(ColorScaleAttrib::get_class_type());
|
||||
_color_scale = (const ColorScaleAttrib *)NULL;
|
||||
if (attrib != (const RenderAttrib *)NULL) {
|
||||
_color_scale = DCAST(ColorScaleAttrib, attrib);
|
||||
}
|
||||
_flags |= F_checked_color_scale;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RenderState::determine_texture
|
||||
// Access: Private
|
||||
// Description: This is the private implementation of get_texture().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void RenderState::
|
||||
determine_texture() {
|
||||
const RenderAttrib *attrib = get_attrib(TextureAttrib::get_class_type());
|
||||
_texture = (const TextureAttrib *)NULL;
|
||||
if (attrib != (const RenderAttrib *)NULL) {
|
||||
_texture = DCAST(TextureAttrib, attrib);
|
||||
}
|
||||
_flags |= F_checked_texture;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RenderState::determine_tex_gen
|
||||
// Access: Private
|
||||
// Description: This is the private implementation of get_tex_gen().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void RenderState::
|
||||
determine_tex_gen() {
|
||||
const RenderAttrib *attrib = get_attrib(TexGenAttrib::get_class_type());
|
||||
_tex_gen = (const TexGenAttrib *)NULL;
|
||||
if (attrib != (const RenderAttrib *)NULL) {
|
||||
_tex_gen = DCAST(TexGenAttrib, attrib);
|
||||
}
|
||||
_flags |= F_checked_tex_gen;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -32,6 +32,10 @@ class GraphicsStateGuardianBase;
|
|||
class FogAttrib;
|
||||
class CullBinAttrib;
|
||||
class TransparencyAttrib;
|
||||
class ColorAttrib;
|
||||
class ColorScaleAttrib;
|
||||
class TextureAttrib;
|
||||
class TexGenAttrib;
|
||||
class FactoryParams;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -114,7 +118,10 @@ PUBLISHED:
|
|||
INLINE const CullBinAttrib *get_bin() const;
|
||||
INLINE const TransparencyAttrib *get_transparency() const;
|
||||
INLINE int get_bin_index() const;
|
||||
INLINE bool is_flat_shaded() const;
|
||||
INLINE const ColorAttrib *get_color() const;
|
||||
INLINE const ColorScaleAttrib *get_color_scale() const;
|
||||
INLINE const TextureAttrib *get_texture() const;
|
||||
INLINE const TexGenAttrib *get_tex_gen() const;
|
||||
|
||||
public:
|
||||
CPT(RenderState) issue_delta_modify(const RenderState *other,
|
||||
|
|
@ -151,7 +158,10 @@ private:
|
|||
void determine_fog();
|
||||
void determine_bin();
|
||||
void determine_transparency();
|
||||
void determine_flat_shaded();
|
||||
void determine_color();
|
||||
void determine_color_scale();
|
||||
void determine_texture();
|
||||
void determine_tex_gen();
|
||||
|
||||
INLINE void set_destructing();
|
||||
INLINE bool is_destructing() const;
|
||||
|
|
@ -225,14 +235,20 @@ private:
|
|||
const FogAttrib *_fog;
|
||||
const CullBinAttrib *_bin;
|
||||
const TransparencyAttrib *_transparency;
|
||||
const ColorAttrib *_color;
|
||||
const ColorScaleAttrib *_color_scale;
|
||||
const TextureAttrib *_texture;
|
||||
const TexGenAttrib *_tex_gen;
|
||||
|
||||
enum Flags {
|
||||
F_checked_bin_index = 0x0001,
|
||||
F_checked_fog = 0x0002,
|
||||
F_checked_bin = 0x0004,
|
||||
F_checked_transparency = 0x0008,
|
||||
F_checked_flat_shaded = 0x0010,
|
||||
F_flat_shaded = 0x0020,
|
||||
F_checked_color = 0x0010,
|
||||
F_checked_color_scale = 0x0020,
|
||||
F_checked_texture = 0x0040,
|
||||
F_checked_tex_gen = 0x0080,
|
||||
F_is_destructing = 0x8000,
|
||||
};
|
||||
unsigned short _flags;
|
||||
|
|
|
|||
|
|
@ -67,8 +67,9 @@ fresh() {
|
|||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE UpdateSeq::
|
||||
UpdateSeq(const UpdateSeq ©) {
|
||||
_seq = copy._seq;
|
||||
UpdateSeq(const UpdateSeq ©) :
|
||||
_seq(copy._seq)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -132,15 +133,8 @@ is_fresh() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool UpdateSeq::
|
||||
is_special() const {
|
||||
switch (_seq) {
|
||||
case (unsigned int)SC_initial:
|
||||
case (unsigned int)SC_old:
|
||||
case (unsigned int)SC_fresh:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
// This relies on the assumption that (~0 + 1) == 0.
|
||||
return ((_seq + 1) <= 2);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -190,6 +184,26 @@ operator <= (const UpdateSeq &other) const {
|
|||
return (*this) == other || (*this) < other;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: UpdateSeq::Comparison operator
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool UpdateSeq::
|
||||
operator > (const UpdateSeq &other) const {
|
||||
return (other < (*this));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: UpdateSeq::Comparison operator
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool UpdateSeq::
|
||||
operator >= (const UpdateSeq &other) const {
|
||||
return (other <= (*this));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: UpdateSeq::Preincrement operator
|
||||
// Access: Published
|
||||
|
|
|
|||
|
|
@ -61,6 +61,8 @@ PUBLISHED:
|
|||
INLINE bool operator != (const UpdateSeq &other) const;
|
||||
INLINE bool operator < (const UpdateSeq &other) const;
|
||||
INLINE bool operator <= (const UpdateSeq &other) const;
|
||||
INLINE bool operator > (const UpdateSeq &other) const;
|
||||
INLINE bool operator >= (const UpdateSeq &other) const;
|
||||
|
||||
INLINE UpdateSeq operator ++ ();
|
||||
INLINE UpdateSeq operator ++ (int);
|
||||
|
|
@ -71,7 +73,7 @@ private:
|
|||
enum SpecialCases {
|
||||
SC_initial = 0,
|
||||
SC_old = 1,
|
||||
SC_fresh = ~0,
|
||||
SC_fresh = ~(unsigned int)0,
|
||||
};
|
||||
|
||||
unsigned int _seq;
|
||||
|
|
|
|||
Loading…
Reference in New Issue