From e14e69dce0c0e986d1075cf66f012022fb99180e Mon Sep 17 00:00:00 2001 From: David Rose Date: Tue, 12 Jun 2001 23:54:03 +0000 Subject: [PATCH] add retained mode rendering infrastructure --- panda/src/display/config_display.cxx | 4 ++ panda/src/display/graphicsStateGuardian.cxx | 44 ++++++++++++++++----- panda/src/gobj/config_gobj.cxx | 12 ++++++ panda/src/gobj/config_gobj.h | 2 + panda/src/gobj/drawable.cxx | 13 ++++++ panda/src/gobj/drawable.h | 1 + panda/src/gobj/geom.cxx | 14 +++++++ panda/src/gobj/geom.h | 2 + panda/src/graph/dftraverser.h | 4 +- panda/src/graph/traverserVisitor.h | 12 +++--- panda/src/pstatclient/pStatClient.cxx | 22 ++++++++--- panda/src/pstatclient/pStatClient.h | 1 + panda/src/pstatclient/pStatCollector.I | 20 ++++++++++ panda/src/pstatclient/pStatCollector.h | 4 ++ panda/src/sgmanip/nodePath.cxx | 22 ++++++++++- panda/src/sgmanip/nodePath.h | 2 +- panda/src/sgraph/geomNode.cxx | 22 +++++++++++ 17 files changed, 175 insertions(+), 26 deletions(-) diff --git a/panda/src/display/config_display.cxx b/panda/src/display/config_display.cxx index 27c25ad6f0..15045bb997 100644 --- a/panda/src/display/config_display.cxx +++ b/panda/src/display/config_display.cxx @@ -27,6 +27,8 @@ #include "graphicsChannel.h" #include "hardwareChannel.h" #include "textureContext.h" +#include "geomNodeContext.h" +#include "geomContext.h" Configure(config_display); NotifyCategoryDef(display, ""); @@ -130,6 +132,8 @@ init_libdisplay() { GraphicsChannel::init_type(); HardwareChannel::init_type(); TextureContext::init_type(); + GeomNodeContext::init_type(); + GeomContext::init_type(); disp = new Config::ConfigTable::Symbol; guard = new Config::ConfigTable::Symbol; diff --git a/panda/src/display/graphicsStateGuardian.cxx b/panda/src/display/graphicsStateGuardian.cxx index 8ae28143db..c3c31bf155 100644 --- a/panda/src/display/graphicsStateGuardian.cxx +++ b/panda/src/display/graphicsStateGuardian.cxx @@ -414,6 +414,24 @@ release_all_textures() { //////////////////////////////////////////////////////////////////// void GraphicsStateGuardian:: release_all_geoms() { + // As above, for both Geoms and GeomNodes. + + Geoms temp_geoms = _prepared_geoms; + for (Geoms::const_iterator gi = temp_geoms.begin(); + gi != temp_geoms.end(); + ++gi) { + release_geom(*gi); + } + + GeomNodes temp_geom_nodes = _prepared_geom_nodes; + for (GeomNodes::const_iterator gni = temp_geom_nodes.begin(); + gni != temp_geom_nodes.end(); + ++gni) { + release_geom_node(*gni); + } + + nassertv(_prepared_geoms.empty()); + nassertv(_prepared_geom_nodes.empty()); } //////////////////////////////////////////////////////////////////// @@ -723,9 +741,11 @@ unmark_prepared_geom_node(GeomNodeContext *gnc) { void GraphicsStateGuardian:: init_frame_pstats() { _current_textures.clear(); + _current_geoms.clear(); + _current_geom_nodes.clear(); _active_texusage_pcollector.clear_level(); - _total_geom_pcollector.clear_level(); - _total_geom_node_pcollector.clear_level(); + _active_geom_pcollector.clear_level(); + _active_geom_node_pcollector.clear_level(); // Also clear out our other counters while we're here. _vertices_tristrip_pcollector.clear_level(); @@ -752,8 +772,10 @@ init_frame_pstats() { //////////////////////////////////////////////////////////////////// void GraphicsStateGuardian:: add_to_texture_record(TextureContext *tc) { - if (_current_textures.insert(tc).second) { - _active_texusage_pcollector.add_level(tc->estimate_texture_memory()); + if (PStatClient::is_connected()) { + if (_current_textures.insert(tc).second) { + _active_texusage_pcollector.add_level(tc->estimate_texture_memory()); + } } } @@ -767,8 +789,10 @@ add_to_texture_record(TextureContext *tc) { //////////////////////////////////////////////////////////////////// void GraphicsStateGuardian:: add_to_geom_record(GeomContext *gc) { - if (gc != (GeomContext *)NULL && _current_geoms.insert(gc).second) { - _active_geom_pcollector.add_level(1); + if (PStatClient::is_connected()) { + if (gc != (GeomContext *)NULL && _current_geoms.insert(gc).second) { + _active_geom_pcollector.add_level(1); + } } } @@ -782,9 +806,11 @@ add_to_geom_record(GeomContext *gc) { //////////////////////////////////////////////////////////////////// void GraphicsStateGuardian:: add_to_geom_node_record(GeomNodeContext *gnc) { - if (gnc != (GeomNodeContext *)NULL && - _current_geom_nodes.insert(gnc).second) { - _active_geom_node_pcollector.add_level(1); + if (PStatClient::is_connected()) { + if (gnc != (GeomNodeContext *)NULL && + _current_geom_nodes.insert(gnc).second) { + _active_geom_node_pcollector.add_level(1); + } } } diff --git a/panda/src/gobj/config_gobj.cxx b/panda/src/gobj/config_gobj.cxx index 9e64673ab0..747a45bba5 100644 --- a/panda/src/gobj/config_gobj.cxx +++ b/panda/src/gobj/config_gobj.cxx @@ -75,6 +75,18 @@ bool textures_down_square = false; // wastefully. bool keep_texture_ram = config_gobj.GetBool("keep-texture-ram", false); +// Ditto for Geom's. This is a little more dangerous, because if +// anyone calls release_all_geoms() on the GSG, we won't be able to +// restore them automatically. +bool keep_geom_ram = config_gobj.GetBool("keep-geom-ram", false); + +// Set this true to allow the use of retained mode rendering, which +// creates specific cache information (like display lists or vertex +// buffers) with the GSG for static geometry, when supported by the +// GSG. Set it false to use only immediate mode, which sends the +// vertices to the GSG every frame. +bool retained_mode = config_gobj.GetBool("retained-mode", true); + // Set this to specify how textures should be written into Bam files. // Currently, the options are: diff --git a/panda/src/gobj/config_gobj.h b/panda/src/gobj/config_gobj.h index 1e5c679b35..b1a942666f 100644 --- a/panda/src/gobj/config_gobj.h +++ b/panda/src/gobj/config_gobj.h @@ -31,6 +31,8 @@ extern EXPCL_PANDA bool textures_down_power_2; extern EXPCL_PANDA bool textures_up_square; extern EXPCL_PANDA bool textures_down_square; extern EXPCL_PANDA bool keep_texture_ram; +extern EXPCL_PANDA bool keep_geom_ram; +extern EXPCL_PANDA bool retained_mode; enum BamTextureMode { BTM_fullpath, diff --git a/panda/src/gobj/drawable.cxx b/panda/src/gobj/drawable.cxx index 56c7ba487c..f979e1e10d 100644 --- a/panda/src/gobj/drawable.cxx +++ b/panda/src/gobj/drawable.cxx @@ -52,6 +52,19 @@ draw(GraphicsStateGuardianBase *) { } } +//////////////////////////////////////////////////////////////////// +// Function: Drawable::draw +// Access: Public, Virtual +// Description: Returns true if the Drawable has any dynamic +// properties that are expected to change from one frame +// to the next, or false if the Drawable is largely +// static. +//////////////////////////////////////////////////////////////////// +bool dDrawable:: +is_dynamic() const { + return false; +} + //////////////////////////////////////////////////////////////////// // Function: Drawable::propagate_stale_bound // Access: Protected, Virtual diff --git a/panda/src/gobj/drawable.h b/panda/src/gobj/drawable.h index cc83d877dd..0eec0cc175 100644 --- a/panda/src/gobj/drawable.h +++ b/panda/src/gobj/drawable.h @@ -53,6 +53,7 @@ public: virtual ~dDrawable(); virtual void draw(GraphicsStateGuardianBase *); + virtual bool is_dynamic() const; protected: virtual void propagate_stale_bound(); diff --git a/panda/src/gobj/geom.cxx b/panda/src/gobj/geom.cxx index 8045d64001..e1a5cb35db 100644 --- a/panda/src/gobj/geom.cxx +++ b/panda/src/gobj/geom.cxx @@ -324,6 +324,20 @@ get_texcoords(PTA_TexCoordf &texcoords, GeomBindType &bind, tindex = _tindex; } +//////////////////////////////////////////////////////////////////// +// Function: Geom::is_dynamic +// Access: Public, Virtual +// Description: Returns true if the Geom has any dynamic properties +// that are expected to change from one frame to the +// next, or false if the Geom is largely static. For +// now, this is the same thing as asking whether its +// vertices are indexed. +//////////////////////////////////////////////////////////////////// +bool Geom:: +is_dynamic() const { + return (_vindex != (ushort*)0L); +} + //////////////////////////////////////////////////////////////////// // Function: Geom::get_num_vertices // Access: Public diff --git a/panda/src/gobj/geom.h b/panda/src/gobj/geom.h index 934ac4a6b0..f4f90a4956 100644 --- a/panda/src/gobj/geom.h +++ b/panda/src/gobj/geom.h @@ -171,6 +171,8 @@ public: GeomBindType &bind, PTA_ushort &tindex) const; + virtual bool is_dynamic() const; + PUBLISHED: INLINE GeomBindType get_binding(int attr) const; INLINE const PTA_Vertexf &get_coords_array() const; diff --git a/panda/src/graph/dftraverser.h b/panda/src/graph/dftraverser.h index e60b2caeb3..418a0ec68f 100644 --- a/panda/src/graph/dftraverser.h +++ b/panda/src/graph/dftraverser.h @@ -42,8 +42,8 @@ public: typedef TYPENAME Visitor::AttributeWrapper AttributeWrapper; INLINE_GRAPH DFTraverser(Visitor &visitor, - const AttributeWrapper &initial_render_state, - TypeHandle graph_type); + const AttributeWrapper &initial_render_state, + TypeHandle graph_type); INLINE_GRAPH void start(NodeRelation *arc, const LevelState &initial_level_state); INLINE_GRAPH void start(Node *root, const LevelState &initial_level_state); diff --git a/panda/src/graph/traverserVisitor.h b/panda/src/graph/traverserVisitor.h index 11abdb7fb1..48129a762c 100644 --- a/panda/src/graph/traverserVisitor.h +++ b/panda/src/graph/traverserVisitor.h @@ -31,19 +31,19 @@ public: typedef TYPENAME TransitionWrapper::AttributeWrapper AttributeWrapper; INLINE_GRAPH bool reached_node(Node *node, - AttributeWrapper &render_state, - LevelState &level_state); + AttributeWrapper &render_state, + LevelState &level_state); // Some traversers (notably DFTraverser) will also call the // following two functions to mark the crossing of arcs. This will // allow the Visitor to maintain its own internal state as needed. INLINE_GRAPH bool forward_arc(NodeRelation *arc, TransitionWrapper &trans, - AttributeWrapper &pre, AttributeWrapper &post, - LevelState &level_state); + AttributeWrapper &pre, AttributeWrapper &post, + LevelState &level_state); INLINE_GRAPH void backward_arc(NodeRelation *arc, TransitionWrapper &trans, - AttributeWrapper &pre, AttributeWrapper &post, - const LevelState &level_state); + AttributeWrapper &pre, AttributeWrapper &post, + const LevelState &level_state); }; #include "traverserVisitor.T" diff --git a/panda/src/pstatclient/pStatClient.cxx b/panda/src/pstatclient/pStatClient.cxx index bbfe656d68..ccd8a1ef27 100644 --- a/panda/src/pstatclient/pStatClient.cxx +++ b/panda/src/pstatclient/pStatClient.cxx @@ -581,8 +581,7 @@ stop(int collector_index, int thread_index, float as_of) { //////////////////////////////////////////////////////////////////// void PStatClient:: clear_level(int collector_index, int thread_index) { - if (_collectors[collector_index]._def->_is_active && - _threads[thread_index]._is_active) { + if (_collectors[collector_index]._def->_is_active) { _collectors[collector_index]._per_thread[thread_index]._has_level = false; _collectors[collector_index]._per_thread[thread_index]._level = 0.0; } @@ -599,8 +598,7 @@ clear_level(int collector_index, int thread_index) { //////////////////////////////////////////////////////////////////// void PStatClient:: set_level(int collector_index, int thread_index, float level) { - if (_collectors[collector_index]._def->_is_active && - _threads[thread_index]._is_active) { + if (_collectors[collector_index]._def->_is_active) { level *= _collectors[collector_index]._def->_factor; _collectors[collector_index]._per_thread[thread_index]._has_level = true; _collectors[collector_index]._per_thread[thread_index]._level = level; @@ -620,14 +618,26 @@ set_level(int collector_index, int thread_index, float level) { //////////////////////////////////////////////////////////////////// void PStatClient:: add_level(int collector_index, int thread_index, float increment) { - if (_collectors[collector_index]._def->_is_active && - _threads[thread_index]._is_active) { + if (_collectors[collector_index]._def->_is_active) { increment *= _collectors[collector_index]._def->_factor; _collectors[collector_index]._per_thread[thread_index]._has_level = true; _collectors[collector_index]._per_thread[thread_index]._level += increment; } } +//////////////////////////////////////////////////////////////////// +// Function: PStatClient::get_level +// Access: Private +// Description: Returns the current level value of the given collector. +// +// Normally you would not use this interface directly; +// instead, call PStatCollector::get_level(). +//////////////////////////////////////////////////////////////////// +float PStatClient:: +get_level(int collector_index, int thread_index) const { + return _collectors[collector_index]._per_thread[thread_index]._level; +} + //////////////////////////////////////////////////////////////////// // Function: PStatClient::new_frame // Access: Private diff --git a/panda/src/pstatclient/pStatClient.h b/panda/src/pstatclient/pStatClient.h index 314c7d38e8..3bd0991485 100644 --- a/panda/src/pstatclient/pStatClient.h +++ b/panda/src/pstatclient/pStatClient.h @@ -106,6 +106,7 @@ private: void clear_level(int collector_index, int thread_index); void set_level(int collector_index, int thread_index, float level); void add_level(int collector_index, int thread_index, float increment); + float get_level(int collector_index, int thread_index) const; void new_frame(int thread_index); void transmit_frame_data(int thread_index); diff --git a/panda/src/pstatclient/pStatCollector.I b/panda/src/pstatclient/pStatCollector.I index 57e49c91d7..cca3485f8d 100644 --- a/panda/src/pstatclient/pStatCollector.I +++ b/panda/src/pstatclient/pStatCollector.I @@ -212,6 +212,16 @@ sub_level(float decrement) { _client->add_level(_index, 0, -decrement); } +//////////////////////////////////////////////////////////////////// +// Function: PStatCollector::get_level +// Access: Published +// Description: Returns the current level value of the given collector. +//////////////////////////////////////////////////////////////////// +INLINE float PStatCollector:: +get_level() { + return _client->get_level(_index, 0); +} + //////////////////////////////////////////////////////////////////// // Function: PStatCollector::is_active // Access: Public @@ -325,4 +335,14 @@ sub_level(const PStatThread &thread, float decrement) { _client->add_level(_index, thread._index, -decrement); } +//////////////////////////////////////////////////////////////////// +// Function: PStatCollector::get_level +// Access: Public +// Description: Returns the current level value of the given collector. +//////////////////////////////////////////////////////////////////// +INLINE float PStatCollector:: +get_level(const PStatThread &thread) { + return _client->get_level(_index, thread._index); +} + #endif // DO_PSTATS diff --git a/panda/src/pstatclient/pStatCollector.h b/panda/src/pstatclient/pStatCollector.h index aace9ddf65..6034e2ec90 100644 --- a/panda/src/pstatclient/pStatCollector.h +++ b/panda/src/pstatclient/pStatCollector.h @@ -74,6 +74,7 @@ PUBLISHED: INLINE void set_level(float level); INLINE void add_level(float increment); INLINE void sub_level(float decrement); + INLINE float get_level(); public: INLINE bool is_active(const PStatThread &thread); @@ -86,6 +87,7 @@ public: INLINE void set_level(const PStatThread &thread, float level); INLINE void add_level(const PStatThread &thread, float increment); INLINE void sub_level(const PStatThread &thread, float decrement); + INLINE float get_level(const PStatThread &thread); private: PStatClient *_client; @@ -108,6 +110,7 @@ PUBLISHED: INLINE void set_level(float) { } INLINE void add_level(float) { } INLINE void sub_level(float) { } + INLINE float get_level() { return 0.0; } public: INLINE bool is_active(const PStatThread &) { return false; } @@ -120,6 +123,7 @@ public: INLINE void set_level(const PStatThread &, float) { } INLINE void add_level(const PStatThread &, float) { } INLINE void sub_level(const PStatThread &, float) { } + INLINE float get_level(const PStatThread &) { return 0.0; } #endif // DO_PSTATS }; diff --git a/panda/src/sgmanip/nodePath.cxx b/panda/src/sgmanip/nodePath.cxx index ce41110985..250c1a6162 100644 --- a/panda/src/sgmanip/nodePath.cxx +++ b/panda/src/sgmanip/nodePath.cxx @@ -40,6 +40,7 @@ #include #include #include +#include #include "plist.h" @@ -47,7 +48,7 @@ TypeHandle NodePath::_type_handle; // This class is used in prepare_scene() to traverse the scene graph -// and register textures with the gsg. +// and register textures and geoms with the gsg. class ScenePrepareVisitor : public TraverserVisitor { public: bool forward_arc(NodeRelation *, NodeTransitionWrapper &trans, @@ -62,7 +63,17 @@ public: return true; } + bool reached_node(Node *node, NodeAttributeWrapper &, + NullLevelState &) { + if (_retained_mode && node->is_of_type(GeomNode::get_class_type())) { + GeomNode *gnode = DCAST(GeomNode, node); + gnode->prepare(_gsg); + } + return true; + } + GraphicsStateGuardianBase *_gsg; + bool _retained_mode; }; //////////////////////////////////////////////////////////////////// @@ -2760,9 +2771,15 @@ get_stashed_ancestor() const { // will initialize itself when the scene is rendered, // but this may take some of the overhead away from that // process. +// +// If force_retained_mode is true, retained mode is set +// on the geometry encountered, regardless of the +// setting of the retained-mode Config variable. +// Otherwise, retained mode is set only if the +// retained-mode Config variable is true. //////////////////////////////////////////////////////////////////// void NodePath:: -prepare_scene(GraphicsStateGuardianBase *gsg) { +prepare_scene(GraphicsStateGuardianBase *gsg, bool force_retained_mode) { nassertv_always(!is_empty()); // Use the ScenePrepareVisitor and fire off a traversal of the scene @@ -2771,6 +2788,7 @@ prepare_scene(GraphicsStateGuardianBase *gsg) { // graph at this point and below. ScenePrepareVisitor visitor; visitor._gsg = gsg; + visitor._retained_mode = retained_mode || force_retained_mode; NodeAttributeWrapper initial(TextureTransition::get_class_type()); df_traverse(node(), visitor, initial, NullLevelState(), diff --git a/panda/src/sgmanip/nodePath.h b/panda/src/sgmanip/nodePath.h index 5bdc503629..2f77970feb 100644 --- a/panda/src/sgmanip/nodePath.h +++ b/panda/src/sgmanip/nodePath.h @@ -509,7 +509,7 @@ PUBLISHED: INLINE bool is_stashed() const; NodePath get_stashed_ancestor() const; - void prepare_scene(GraphicsStateGuardianBase *gsg); + void prepare_scene(GraphicsStateGuardianBase *gsg, bool force_retained_mode = false); INLINE void clear_wrt_cache(); void show_bounds(); diff --git a/panda/src/sgraph/geomNode.cxx b/panda/src/sgraph/geomNode.cxx index 10a30d9592..dbf0039722 100644 --- a/panda/src/sgraph/geomNode.cxx +++ b/panda/src/sgraph/geomNode.cxx @@ -15,12 +15,15 @@ // panda3d@yahoogroups.com . // //////////////////////////////////////////////////////////////////// + #include "geomNode.h" #include "geomTransformer.h" +#include "config_sgraph.h" #include #include #include +#include //////////////////////////////////////////////////////////////////// // Static variables @@ -182,6 +185,25 @@ prepare(GraphicsStateGuardianBase *gsg) { unprepare(); _prepared_context = gc; _prepared_gsg = gsg; + + if (!keep_geom_ram) { + // Once we have prepared the GeomNode, we can generally safely + // remove the vertices from main RAM. The GSG is now + // responsible for remembering what it looks like. + + if (sgraph_cat.is_debug()) { + sgraph_cat.debug() + << "Dumping RAM for " << *this << "\n"; + } + + // First, change our bounding volume to a static volume, so it + // won't try to recompute itself once we clear out the Geoms. + set_bound(get_bound()); + + // Now remove the set of Geoms, since we don't need them any + // more. + _geoms.clear(); + } } return gc; }