add retained mode rendering infrastructure
This commit is contained in:
parent
123223a153
commit
e14e69dce0
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ public:
|
|||
virtual ~dDrawable();
|
||||
|
||||
virtual void draw(GraphicsStateGuardianBase *);
|
||||
virtual bool is_dynamic() const;
|
||||
|
||||
protected:
|
||||
virtual void propagate_stale_bound();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue