add retained mode rendering infrastructure

This commit is contained in:
David Rose 2001-06-12 23:54:03 +00:00
parent 123223a153
commit e14e69dce0
17 changed files with 175 additions and 26 deletions

View File

@ -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;

View File

@ -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);
}
}
}

View File

@ -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:

View File

@ -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,

View File

@ -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

View File

@ -53,6 +53,7 @@ public:
virtual ~dDrawable();
virtual void draw(GraphicsStateGuardianBase *);
virtual bool is_dynamic() const;
protected:
virtual void propagate_stale_bound();

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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"

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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
};

View File

@ -40,6 +40,7 @@
#include <bamFile.h>
#include <materialPool.h>
#include <pt_NodeRelation.h>
#include <config_gobj.h>
#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<NodeTransitionWrapper, NullLevelState> {
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(),

View File

@ -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();

View File

@ -15,12 +15,15 @@
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "geomNode.h"
#include "geomTransformer.h"
#include "config_sgraph.h"
#include <geom.h>
#include <allTransitionsWrapper.h>
#include <indent.h>
#include <config_gobj.h>
////////////////////////////////////////////////////////////////////
// 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;
}