From 92a93e8af0d228bb0267cf883cd8d22a70600b31 Mon Sep 17 00:00:00 2001 From: David Rose Date: Mon, 21 Mar 2005 01:39:24 +0000 Subject: [PATCH] clean up caching a bit, multitex in gl --- .../glstuff/glGraphicsStateGuardian_src.cxx | 74 +++++++++--- .../src/glstuff/glGraphicsStateGuardian_src.h | 3 +- panda/src/gobj/qpgeom.I | 21 +++- panda/src/gobj/qpgeom.cxx | 36 +----- panda/src/gobj/qpgeom.h | 3 +- panda/src/gobj/qpgeomPrimitive.I | 36 +++--- panda/src/gobj/qpgeomPrimitive.cxx | 4 +- panda/src/gobj/qpgeomPrimitive.h | 6 +- panda/src/gobj/qpgeomVertexCacheManager.I | 110 ++++++++--------- panda/src/gobj/qpgeomVertexCacheManager.cxx | 104 ++++++++-------- panda/src/gobj/qpgeomVertexCacheManager.h | 46 +++---- panda/src/gobj/qpgeomVertexData.I | 16 ++- panda/src/gobj/qpgeomVertexData.cxx | 113 ++---------------- panda/src/gobj/qpgeomVertexData.h | 17 +-- panda/src/pgraph/renderState.I | 80 +++++++++++-- panda/src/pgraph/renderState.cxx | 67 +++++++++-- panda/src/pgraph/renderState.h | 24 +++- panda/src/putil/updateSeq.I | 36 ++++-- panda/src/putil/updateSeq.h | 4 +- 19 files changed, 443 insertions(+), 357 deletions(-) diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index 6b19842ef2..d4558e4472 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -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; } diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.h b/panda/src/glstuff/glGraphicsStateGuardian_src.h index 2a243e05ab..b6d5dd23b6 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.h +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.h @@ -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; diff --git a/panda/src/gobj/qpgeom.I b/panda/src/gobj/qpgeom.I index 1cd32c0a25..0165b692a6 100644 --- a/panda/src/gobj/qpgeom.I +++ b/panda/src/gobj/qpgeom.I @@ -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) { } diff --git a/panda/src/gobj/qpgeom.cxx b/panda/src/gobj/qpgeom.cxx index a9531b1326..6d821c6d26 100644 --- a/panda/src/gobj/qpgeom.cxx +++ b/panda/src/gobj/qpgeom.cxx @@ -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 diff --git a/panda/src/gobj/qpgeom.h b/panda/src/gobj/qpgeom.h index 9120d16b3f..1316887259 100644 --- a/panda/src/gobj/qpgeom.h +++ b/panda/src/gobj/qpgeom.h @@ -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; }; diff --git a/panda/src/gobj/qpgeomPrimitive.I b/panda/src/gobj/qpgeomPrimitive.I index abb14e212f..b5b3ff39da 100644 --- a/panda/src/gobj/qpgeomPrimitive.I +++ b/panda/src/gobj/qpgeomPrimitive.I @@ -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]; } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/gobj/qpgeomPrimitive.cxx b/panda/src/gobj/qpgeomPrimitive.cxx index 3dd19b48af..bb251d3735 100644 --- a/panda/src/gobj/qpgeomPrimitive.cxx +++ b/panda/src/gobj/qpgeomPrimitive.cxx @@ -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; diff --git a/panda/src/gobj/qpgeomPrimitive.h b/panda/src/gobj/qpgeomPrimitive.h index edfd154c70..358c93d8ec 100644 --- a/panda/src/gobj/qpgeomPrimitive.h +++ b/panda/src/gobj/qpgeomPrimitive.h @@ -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 CDReader; typedef CycleDataWriter CDWriter; - void recompute_minmax(); + void recompute_minmax(CDWriter &cdata); public: virtual void write_datagram(BamWriter *manager, Datagram &dg); diff --git a/panda/src/gobj/qpgeomVertexCacheManager.I b/panda/src/gobj/qpgeomVertexCacheManager.I index 08e5d80c6d..5dc5090b3b 100644 --- a/panda/src/gobj/qpgeomVertexCacheManager.I +++ b/panda/src/gobj/qpgeomVertexCacheManager.I @@ -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 & diff --git a/panda/src/gobj/qpgeomVertexCacheManager.cxx b/panda/src/gobj/qpgeomVertexCacheManager.cxx index 158104323c..2c75cb0235 100644 --- a/panda/src/gobj/qpgeomVertexCacheManager.cxx +++ b/panda/src/gobj/qpgeomVertexCacheManager.cxx @@ -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; diff --git a/panda/src/gobj/qpgeomVertexCacheManager.h b/panda/src/gobj/qpgeomVertexCacheManager.h index 4ed64d30d1..5b6ec5cee0 100644 --- a/panda/src/gobj/qpgeomVertexCacheManager.h +++ b/panda/src/gobj/qpgeomVertexCacheManager.h @@ -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 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 > EntriesIndex; + typedef pset > EntriesIndex; EntriesIndex _entries_index; static qpGeomVertexCacheManager *_global_ptr; friend class qpGeomMunger; friend class qpGeomPrimitive; - friend class qpGeomVertexData; friend class qpGeom; }; diff --git a/panda/src/gobj/qpgeomVertexData.I b/panda/src/gobj/qpgeomVertexData.I index edc7ada938..cdb774d546 100644 --- a/panda/src/gobj/qpgeomVertexData.I +++ b/panda/src/gobj/qpgeomVertexData.I @@ -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) { } diff --git a/panda/src/gobj/qpgeomVertexData.cxx b/panda/src/gobj/qpgeomVertexData.cxx index c55d3e70c8..7f77e65f2e 100644 --- a/panda/src/gobj/qpgeomVertexData.cxx +++ b/panda/src/gobj/qpgeomVertexData.cxx @@ -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; diff --git a/panda/src/gobj/qpgeomVertexData.h b/panda/src/gobj/qpgeomVertexData.h index c95fed8ff5..351622df4e 100644 --- a/panda/src/gobj/qpgeomVertexData.h +++ b/panda/src/gobj/qpgeomVertexData.h @@ -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 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 _cycler; @@ -172,8 +161,6 @@ public: private: static TypeHandle _type_handle; - - friend class qpGeomVertexCacheManager; }; INLINE ostream &operator << (ostream &out, const qpGeomVertexData &obj); diff --git a/panda/src/pgraph/renderState.I b/panda/src/pgraph/renderState.I index da2f70de30..fbd8022b86 100644 --- a/panda/src/pgraph/renderState.I +++ b/panda/src/pgraph/renderState.I @@ -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; } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/pgraph/renderState.cxx b/panda/src/pgraph/renderState.cxx index ad3144ea4b..7455e2114f 100644 --- a/panda/src/pgraph/renderState.cxx +++ b/panda/src/pgraph/renderState.cxx @@ -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; } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/pgraph/renderState.h b/panda/src/pgraph/renderState.h index 1dc274fc1f..ac369c85fb 100644 --- a/panda/src/pgraph/renderState.h +++ b/panda/src/pgraph/renderState.h @@ -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; diff --git a/panda/src/putil/updateSeq.I b/panda/src/putil/updateSeq.I index cca8de638c..798711a8cf 100644 --- a/panda/src/putil/updateSeq.I +++ b/panda/src/putil/updateSeq.I @@ -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 diff --git a/panda/src/putil/updateSeq.h b/panda/src/putil/updateSeq.h index 5ee4c4548d..2b5e71a8af 100644 --- a/panda/src/putil/updateSeq.h +++ b/panda/src/putil/updateSeq.h @@ -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;