mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 02:42:49 -04:00
cache new geom munging
This commit is contained in:
parent
0768cdd95c
commit
219f16c5de
@ -285,16 +285,6 @@ get_scene() const {
|
||||
return _scene_setup;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GraphicsStateGuardian::get_geom_munger
|
||||
// Access: Public
|
||||
// Description: Returns the current GeomMunger object.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const qpGeomMunger *GraphicsStateGuardian::
|
||||
get_geom_munger() const {
|
||||
return _geom_munger;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GraphicsStateGuardian::clear
|
||||
// Access: Public
|
||||
@ -383,7 +373,6 @@ modify_state(const RenderState *state) {
|
||||
_state_pcollector.add_level(1);
|
||||
_state = _state->issue_delta_modify(state, this);
|
||||
finish_modify_state();
|
||||
setup_geom_munger(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@ -411,7 +400,6 @@ set_state(const RenderState *state) {
|
||||
_state_pcollector.add_level(1);
|
||||
_state = _state->issue_delta_set(state, this);
|
||||
finish_modify_state();
|
||||
setup_geom_munger(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -267,6 +267,21 @@ void GraphicsStateGuardian::
|
||||
release_geom(GeomContext *) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GraphicsStateGuardian::get_geom_munger
|
||||
// Access: Public, Virtual
|
||||
// Description: Creates a new GeomMunger object to munge vertices
|
||||
// appropriate to this GSG for the indicated state.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CPT(qpGeomMunger) GraphicsStateGuardian::
|
||||
get_geom_munger(const RenderState *) {
|
||||
// The default implementation returns a munger that does nothing,
|
||||
// but presumably, every kind of GSG needs some special munging
|
||||
// action, so real GSG's will override this to return something more
|
||||
// useful.
|
||||
return qpGeomMunger::register_munger(new qpGeomMunger);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GraphicsStateGuardian::set_state_and_transform
|
||||
// Access: Public, Virtual
|
||||
@ -607,7 +622,7 @@ finish_decal() {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool GraphicsStateGuardian::
|
||||
begin_draw_primitives(const qpGeomVertexData *data) {
|
||||
_vertex_data = get_geom_munger()->munge_data(data);
|
||||
_vertex_data = data;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -627,7 +642,10 @@ draw_triangles(qpGeomTriangles *) {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void GraphicsStateGuardian::
|
||||
draw_tristrips(qpGeomTristrips *primitive) {
|
||||
primitive->decompose(_vertex_data)->draw(this);
|
||||
PT(qpGeomPrimitive) new_prim = primitive->decompose();
|
||||
if (!new_prim->is_of_type(qpGeomTristrips::get_class_type())) {
|
||||
new_prim->draw(this);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -637,7 +655,10 @@ draw_tristrips(qpGeomTristrips *primitive) {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void GraphicsStateGuardian::
|
||||
draw_trifans(qpGeomTrifans *primitive) {
|
||||
primitive->decompose(_vertex_data)->draw(this);
|
||||
PT(qpGeomPrimitive) new_prim = primitive->decompose();
|
||||
if (!new_prim->is_of_type(qpGeomTrifans::get_class_type())) {
|
||||
new_prim->draw(this);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -1329,21 +1350,6 @@ finish_modify_state() {
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GraphicsStateGuardian::setup_geom_munger
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called after finish_modify_state has completed, this
|
||||
// method sets up the GeomMunger for rendering with the
|
||||
// current state.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void GraphicsStateGuardian::
|
||||
setup_geom_munger(PT(qpGeomMunger) munger) {
|
||||
if (munger == (qpGeomMunger *)NULL) {
|
||||
munger = new qpGeomMunger;
|
||||
}
|
||||
_geom_munger = qpGeomMunger::register_munger(munger);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GraphicsStateGuardian::free_pointers
|
||||
// Access: Protected, Virtual
|
||||
|
@ -97,7 +97,6 @@ PUBLISHED:
|
||||
public:
|
||||
INLINE bool set_scene(SceneSetup *scene_setup);
|
||||
INLINE SceneSetup *get_scene() const;
|
||||
INLINE const qpGeomMunger *get_geom_munger() const;
|
||||
|
||||
virtual PreparedGraphicsObjects *get_prepared_objects();
|
||||
|
||||
@ -108,6 +107,8 @@ public:
|
||||
virtual GeomContext *prepare_geom(Geom *geom);
|
||||
virtual void release_geom(GeomContext *gc);
|
||||
|
||||
virtual CPT(qpGeomMunger) get_geom_munger(const RenderState *state);
|
||||
|
||||
virtual void set_state_and_transform(const RenderState *state,
|
||||
const TransformState *transform);
|
||||
|
||||
@ -209,7 +210,6 @@ protected:
|
||||
virtual void set_blend_mode();
|
||||
|
||||
virtual void finish_modify_state();
|
||||
virtual void setup_geom_munger(PT(qpGeomMunger) munger);
|
||||
|
||||
virtual void free_pointers();
|
||||
virtual void close_gsg();
|
||||
@ -242,7 +242,6 @@ protected:
|
||||
|
||||
CPT(RenderState) _state;
|
||||
CPT(TransformState) _transform;
|
||||
CPT(qpGeomMunger) _geom_munger;
|
||||
CPT(qpGeomVertexData) _vertex_data;
|
||||
|
||||
int _buffer_mask;
|
||||
|
@ -2893,6 +2893,18 @@ release_texture(TextureContext *tc) {
|
||||
delete gtc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DXGraphicsStateGuardian8::get_geom_munger
|
||||
// Access: Public, Virtual
|
||||
// Description: Creates a new GeomMunger object to munge vertices
|
||||
// appropriate to this GSG for the indicated state.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CPT(qpGeomMunger) DXGraphicsStateGuardian8::
|
||||
get_geom_munger(const RenderState *) {
|
||||
PT(DXGeomMunger8) munger = new DXGeomMunger8;
|
||||
return qpGeomMunger::register_munger(munger);
|
||||
}
|
||||
|
||||
// copies current display region in framebuffer to the texture
|
||||
// usually its more efficient to do SetRenderTgt
|
||||
void DXGraphicsStateGuardian8::
|
||||
@ -4052,19 +4064,6 @@ set_blend_mode() {
|
||||
enable_blend(false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DXGraphicsStateGuardian8::setup_geom_munger
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called after finish_modify_state has completed, this
|
||||
// method sets up the GeomMunger for rendering with the
|
||||
// current state.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void DXGraphicsStateGuardian8::
|
||||
setup_geom_munger(PT(qpGeomMunger) munger) {
|
||||
munger = new DXGeomMunger8;
|
||||
GraphicsStateGuardian::setup_geom_munger(munger);
|
||||
}
|
||||
|
||||
TypeHandle DXGraphicsStateGuardian8::get_type(void) const {
|
||||
return get_class_type();
|
||||
}
|
||||
|
@ -97,6 +97,8 @@ public:
|
||||
virtual void apply_texture(TextureContext *tc);
|
||||
virtual void release_texture(TextureContext *tc);
|
||||
|
||||
virtual CPT(qpGeomMunger) get_geom_munger(const RenderState *state);
|
||||
|
||||
virtual void framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
|
||||
const RenderBuffer &rb);
|
||||
virtual bool framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr,
|
||||
@ -152,7 +154,6 @@ protected:
|
||||
virtual void bind_clip_plane(PlaneNode *plane, int plane_id);
|
||||
|
||||
virtual void set_blend_mode();
|
||||
virtual void setup_geom_munger(PT(qpGeomMunger) munger);
|
||||
|
||||
void free_nondx_resources(); // free local internal buffers
|
||||
void free_d3d_device(void);
|
||||
|
@ -2326,6 +2326,18 @@ static int binary_log_cap(const int x) {
|
||||
}
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CLP(GraphicsStateGuardian)::get_geom_munger
|
||||
// Access: Public, Virtual
|
||||
// Description: Creates a new GeomMunger object to munge vertices
|
||||
// appropriate to this GSG for the indicated state.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CPT(qpGeomMunger) CLP(GraphicsStateGuardian)::
|
||||
get_geom_munger(const RenderState *) {
|
||||
PT(CLP(GeomMunger)) munger = new CLP(GeomMunger);
|
||||
return qpGeomMunger::register_munger(munger);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CLP(GraphicsStateGuardian)::framebuffer_copy_to_texture
|
||||
// Access: Public, Virtual
|
||||
@ -5036,19 +5048,6 @@ finish_modify_state() {
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CLP(GraphicsStateGuardian)::setup_geom_munger
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called after finish_modify_state has completed, this
|
||||
// method sets up the GeomMunger for rendering with the
|
||||
// current state.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CLP(GraphicsStateGuardian)::
|
||||
setup_geom_munger(PT(qpGeomMunger) munger) {
|
||||
munger = new CLP(GeomMunger);
|
||||
GraphicsStateGuardian::setup_geom_munger(munger);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CLP(GraphicsStateGuardian)::free_pointers
|
||||
// Access: Protected, Virtual
|
||||
|
@ -102,6 +102,8 @@ public:
|
||||
virtual GeomContext *prepare_geom(Geom *geom);
|
||||
virtual void release_geom(GeomContext *gc);
|
||||
|
||||
virtual CPT(qpGeomMunger) get_geom_munger(const RenderState *state);
|
||||
|
||||
virtual void framebuffer_copy_to_texture
|
||||
(Texture *tex, int z, const DisplayRegion *dr, const RenderBuffer &rb);
|
||||
virtual bool framebuffer_copy_to_ram
|
||||
@ -180,7 +182,6 @@ protected:
|
||||
virtual void set_blend_mode();
|
||||
|
||||
virtual void finish_modify_state();
|
||||
virtual void setup_geom_munger(PT(qpGeomMunger) munger);
|
||||
|
||||
virtual void free_pointers();
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
qpgeomTristrips.h \
|
||||
qpgeomTrifans.h \
|
||||
qpgeomVertexArrayFormat.h qpgeomVertexArrayFormat.I \
|
||||
qpgeomVertexCacheManager.h qpgeomVertexCacheManager.I \
|
||||
qpgeomVertexData.h qpgeomVertexData.I \
|
||||
qpgeomVertexDataType.h qpgeomVertexDataType.I \
|
||||
qpgeomVertexFormat.h qpgeomVertexFormat.I \
|
||||
@ -55,6 +56,7 @@
|
||||
qpgeomTristrips.cxx \
|
||||
qpgeomTrifans.cxx \
|
||||
qpgeomVertexArrayFormat.cxx \
|
||||
qpgeomVertexCacheManager.cxx \
|
||||
qpgeomVertexData.cxx \
|
||||
qpgeomVertexDataType.cxx \
|
||||
qpgeomVertexFormat.cxx \
|
||||
@ -84,6 +86,7 @@
|
||||
qpgeomTristrips.h \
|
||||
qpgeomTrifans.h \
|
||||
qpgeomVertexArrayFormat.h qpgeomVertexArrayFormat.I \
|
||||
qpgeomVertexCacheManager.h qpgeomVertexCacheManager.I \
|
||||
qpgeomVertexData.h qpgeomVertexData.I \
|
||||
qpgeomVertexDataType.h qpgeomVertexDataType.I \
|
||||
qpgeomVertexFormat.h qpgeomVertexFormat.I \
|
||||
|
@ -116,6 +116,15 @@ ConfigVariableString fake_texture_image
|
||||
"the same texture file, which will presumably only be loaded "
|
||||
"once."));
|
||||
|
||||
ConfigVariableInt vertex_convert_cache
|
||||
("vertex-convert-cache", 4194304, // 4 MB
|
||||
PRC_DESC("This is the amount of memory, in bytes, that should be set "
|
||||
"aside for storing pre-processed data for rendering vertices. "
|
||||
"This is not a limit on the actual vertex data, which is "
|
||||
"determined by the model; it is also not a limit on the "
|
||||
"amount of memory used by the video driver or the system "
|
||||
"graphics interface, which Panda has no control over."));
|
||||
|
||||
ConfigVariableDouble default_near
|
||||
("default-near", 1.0,
|
||||
PRC_DESC("The default near clipping distance for all cameras."));
|
||||
|
@ -59,6 +59,8 @@ extern EXPCL_PANDA ConfigVariableEnum<AutoTextureScale> textures_power_2;
|
||||
extern EXPCL_PANDA ConfigVariableEnum<AutoTextureScale> textures_square;
|
||||
extern EXPCL_PANDA ConfigVariableString fake_texture_image;
|
||||
|
||||
extern EXPCL_PANDA ConfigVariableInt vertex_convert_cache;
|
||||
|
||||
extern ConfigVariableDouble default_near;
|
||||
extern ConfigVariableDouble default_far;
|
||||
extern ConfigVariableDouble default_fov;
|
||||
|
@ -48,7 +48,7 @@ dDrawable::
|
||||
// At this level, this doesn't do very much.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void dDrawable::
|
||||
draw(GraphicsStateGuardianBase *) const {
|
||||
draw(GraphicsStateGuardianBase *, const qpGeomVertexData *) const {
|
||||
if (is_dirty()) {
|
||||
((dDrawable *)this)->config();
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ class Datagram;
|
||||
class DatagramIterator;
|
||||
class BamReader;
|
||||
class BamWriter;
|
||||
class qpGeomVertexData;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : Drawable
|
||||
@ -50,7 +51,8 @@ public:
|
||||
dDrawable();
|
||||
virtual ~dDrawable();
|
||||
|
||||
virtual void draw(GraphicsStateGuardianBase *) const;
|
||||
virtual void draw(GraphicsStateGuardianBase *gsg,
|
||||
const qpGeomVertexData *vertex_data) const;
|
||||
virtual bool is_dynamic() const;
|
||||
|
||||
protected:
|
||||
|
@ -915,7 +915,7 @@ release_all() {
|
||||
// Description: Actually draws the Geom with the indicated GSG.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void Geom::
|
||||
draw(GraphicsStateGuardianBase *gsg) const {
|
||||
draw(GraphicsStateGuardianBase *gsg, const qpGeomVertexData *) const {
|
||||
PreparedGraphicsObjects *prepared_objects = gsg->get_prepared_objects();
|
||||
if (is_dirty()) {
|
||||
((Geom *)this)->config();
|
||||
|
@ -43,6 +43,7 @@ class DatagramIterator;
|
||||
class BamReader;
|
||||
class BamWriter;
|
||||
class GeomContext;
|
||||
class qpGeomVertexData;
|
||||
class PreparedGraphicsObjects;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -239,7 +240,8 @@ public:
|
||||
int release_all();
|
||||
|
||||
// From parent dDrawable
|
||||
virtual void draw(GraphicsStateGuardianBase *gsg) const;
|
||||
virtual void draw(GraphicsStateGuardianBase *gsg,
|
||||
const qpGeomVertexData *vertex_data) const;
|
||||
|
||||
// From parent Configurable
|
||||
virtual void config();
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "qpgeomTristrips.cxx"
|
||||
#include "qpgeomTrifans.cxx"
|
||||
#include "qpgeomVertexArrayFormat.cxx"
|
||||
#include "qpgeomVertexCacheManager.cxx"
|
||||
#include "qpgeomVertexData.cxx"
|
||||
#include "qpgeomVertexDataType.cxx"
|
||||
#include "qpgeomVertexFormat.cxx"
|
||||
|
@ -203,13 +203,15 @@ write(ostream &out, int indent_level) const {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeom::draw
|
||||
// Access: Public
|
||||
// Description: Actually draws the Geom with the indicated GSG.
|
||||
// Description: Actually draws the Geom with the indicated GSG, using
|
||||
// the indicated vertex data (which might have been
|
||||
// pre-munged to support the GSG's needs).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeom::
|
||||
draw(GraphicsStateGuardianBase *gsg) const {
|
||||
draw(GraphicsStateGuardianBase *gsg, const qpGeomVertexData *vertex_data) const {
|
||||
CDReader cdata(_cycler);
|
||||
|
||||
if (gsg->begin_draw_primitives(cdata->_data)) {
|
||||
if (gsg->begin_draw_primitives(vertex_data)) {
|
||||
Primitives::const_iterator pi;
|
||||
for (pi = cdata->_primitives.begin();
|
||||
pi != cdata->_primitives.end();
|
||||
|
@ -76,7 +76,8 @@ PUBLISHED:
|
||||
void write(ostream &out, int indent_level = 0) const;
|
||||
|
||||
public:
|
||||
void draw(GraphicsStateGuardianBase *gsg) const;
|
||||
void draw(GraphicsStateGuardianBase *gsg,
|
||||
const qpGeomVertexData *vertex_data) const;
|
||||
|
||||
protected:
|
||||
virtual BoundingVolume *recompute_bound();
|
||||
|
@ -17,10 +17,15 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "qpgeomMunger.h"
|
||||
#include "qpgeomVertexCacheManager.h"
|
||||
#include "mutexHolder.h"
|
||||
#include "pStatTimer.h"
|
||||
|
||||
qpGeomMunger::Registry *qpGeomMunger::_registry = NULL;
|
||||
TypeHandle qpGeomMunger::_type_handle;
|
||||
|
||||
PStatCollector qpGeomMunger::_munge_pcollector("Cull:Munge");
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomMunger::Constructor
|
||||
// Access: Public
|
||||
@ -92,6 +97,7 @@ remove_data(const qpGeomVertexData *data) {
|
||||
CPT(qpGeomVertexData) qpGeomMunger::
|
||||
do_munge_data(const qpGeomVertexData *data) {
|
||||
nassertr(_is_registered, NULL);
|
||||
PStatTimer timer(_munge_pcollector);
|
||||
|
||||
CPT(qpGeomVertexFormat) orig_format = data->get_format();
|
||||
CPT(qpGeomVertexFormat) new_format = munge_format(orig_format);
|
||||
@ -132,8 +138,12 @@ do_munge_format(const qpGeomVertexFormat *format) {
|
||||
nassertr(inserted, NULL);
|
||||
|
||||
// Tell the source format that we have its pointer.
|
||||
inserted = ((qpGeomVertexFormat *)format)->_mungers.insert(this).second;
|
||||
nassertr(inserted, NULL);
|
||||
{
|
||||
qpGeomVertexFormat *f = (qpGeomVertexFormat *)format;
|
||||
MutexHolder holder(f->_cache_lock);
|
||||
inserted = f->_mungers.insert(this).second;
|
||||
nassertr(inserted, NULL);
|
||||
}
|
||||
|
||||
// We also want to keep a reference count on the derived format, but
|
||||
// only if it is actually a different pointer from the original
|
||||
@ -189,9 +199,20 @@ make_registry() {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeomMunger::
|
||||
do_register() {
|
||||
if (gobj_cat.is_debug()) {
|
||||
gobj_cat.debug()
|
||||
<< "GeomMunger::do_register(): " << (void *)this << "\n";
|
||||
}
|
||||
nassertv(!_is_registered);
|
||||
nassertv(_formats.empty());
|
||||
|
||||
// Tell the cache manager to hang on to this new GeomMunger, so we
|
||||
// don't waste our time re-registering the same GeomMunger over and
|
||||
// over again.
|
||||
qpGeomVertexCacheManager *cache_mgr =
|
||||
qpGeomVertexCacheManager::get_global_ptr();
|
||||
cache_mgr->record_munger(this);
|
||||
|
||||
_is_registered = true;
|
||||
}
|
||||
|
||||
@ -202,17 +223,24 @@ do_register() {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeomMunger::
|
||||
do_unregister() {
|
||||
if (gobj_cat.is_debug()) {
|
||||
gobj_cat.debug()
|
||||
<< "GeomMunger::do_unregister(): " << (void *)this << "\n";
|
||||
}
|
||||
nassertv(_is_registered);
|
||||
_is_registered = false;
|
||||
|
||||
// Unregistering means we should blow away the cache.
|
||||
Formats::iterator fi;
|
||||
for (fi = _formats.begin(); fi != _formats.end(); ++fi) {
|
||||
const qpGeomVertexFormat *format = (*fi).first;
|
||||
qpGeomVertexFormat *format = (qpGeomVertexFormat *)(*fi).first;
|
||||
CPT(qpGeomVertexFormat) derived_format = (*fi).second;
|
||||
|
||||
size_t num_erased = ((qpGeomVertexFormat *)format)->_mungers.erase(this);
|
||||
nassertv(num_erased == 1);
|
||||
{
|
||||
MutexHolder holder(format->_cache_lock);
|
||||
size_t num_erased = format->_mungers.erase(this);
|
||||
nassertv(num_erased == 1);
|
||||
}
|
||||
|
||||
if (derived_format != format) {
|
||||
derived_format->unref();
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "typedReferenceCount.h"
|
||||
#include "qpgeomVertexFormat.h"
|
||||
#include "indirectCompareTo.h"
|
||||
#include "pStatCollector.h"
|
||||
#include "pmap.h"
|
||||
#include "pset.h"
|
||||
|
||||
@ -97,6 +98,8 @@ private:
|
||||
|
||||
static Registry *_registry;
|
||||
|
||||
static PStatCollector _munge_pcollector;
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
return _type_handle;
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "qpgeomVertexData.h"
|
||||
#include "qpgeomVertexArrayFormat.h"
|
||||
#include "qpgeomVertexDataType.h"
|
||||
#include "qpgeomVertexCacheManager.h"
|
||||
#include "internalName.h"
|
||||
#include "bamReader.h"
|
||||
#include "bamWriter.h"
|
||||
@ -55,6 +56,23 @@ qpGeomPrimitive(const qpGeomPrimitive ©) :
|
||||
////////////////////////////////////////////////////////////////////
|
||||
qpGeomPrimitive::
|
||||
~qpGeomPrimitive() {
|
||||
// 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);
|
||||
if (cdata->_decomposed != (qpGeomPrimitive *)NULL) {
|
||||
cache_mgr->remove_decompose(this);
|
||||
cdata->_decomposed = NULL;
|
||||
}
|
||||
_cycler.release_write_stage(i, cdata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -209,6 +227,19 @@ set_lengths(PTA_int lengths) {
|
||||
cdata->_lengths = lengths;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomPrimitive::get_num_bytes
|
||||
// Access: Published
|
||||
// Description: Records the number of bytes consumed by the primitive
|
||||
// and its index table(s).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int qpGeomPrimitive::
|
||||
get_num_bytes() const {
|
||||
CDReader cdata(_cycler);
|
||||
return cdata->_vertices.size() * sizeof(short) +
|
||||
cdata->_lengths.size() * sizeof(int);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomPrimitive::get_num_vertices_per_primitive
|
||||
// Access: Published, Virtual
|
||||
@ -310,7 +341,7 @@ get_primitive_num_vertices(int i) const {
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomPrimitive::decompose
|
||||
// Access: Published, Virtual
|
||||
// Access: Published
|
||||
// Description: Decomposes a complex primitive type into a simpler
|
||||
// primitive type, for instance triangle strips to
|
||||
// triangles, and returns a pointer to the new primitive
|
||||
@ -323,8 +354,48 @@ get_primitive_num_vertices(int i) const {
|
||||
// possible kind of primitive type.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PT(qpGeomPrimitive) qpGeomPrimitive::
|
||||
decompose(const qpGeomVertexData *vertex_data) {
|
||||
return this;
|
||||
decompose() {
|
||||
PT(qpGeomPrimitive) result;
|
||||
{
|
||||
// Use read() and release_read() instead of CDReader, because the
|
||||
// call to record_decompose() might recursively call back into
|
||||
// this object, and require a write.
|
||||
const CData *cdata = _cycler.read();
|
||||
if (cdata->_decomposed != (qpGeomPrimitive *)NULL) {
|
||||
result = cdata->_decomposed;
|
||||
_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_decompose(this, result->get_num_bytes());
|
||||
|
||||
return result;
|
||||
}
|
||||
_cycler.release_read(cdata);
|
||||
}
|
||||
|
||||
result = decompose_impl();
|
||||
if (result == this) {
|
||||
// decomposing this primitive has no effect.
|
||||
return this;
|
||||
}
|
||||
|
||||
if (gobj_cat.is_debug()) {
|
||||
gobj_cat.debug()
|
||||
<< "Decomposing " << get_type() << ": " << (void *)this << "\n";
|
||||
}
|
||||
|
||||
// Record the result for the future.
|
||||
CDWriter cdata(_cycler);
|
||||
cdata->_decomposed = result;
|
||||
|
||||
// And add *this* object to the cache manager.
|
||||
qpGeomVertexCacheManager *cache_mgr =
|
||||
qpGeomVertexCacheManager::get_global_ptr();
|
||||
cache_mgr->record_decompose(this, result->get_num_bytes());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -361,6 +432,26 @@ write(ostream &out, const qpGeomVertexData *vertex_data,
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomPrimitive::clear_cache
|
||||
// Access: Published
|
||||
// Description: Removes all of the previously-cached results of
|
||||
// convert_to().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeomPrimitive::
|
||||
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);
|
||||
if (cdata->_decomposed != (qpGeomPrimitive *)NULL) {
|
||||
cache_mgr->remove_decompose(this);
|
||||
cdata->_decomposed = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomPrimitive::calc_tight_bounds
|
||||
// Access: Public, Virtual
|
||||
@ -417,6 +508,42 @@ calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point,
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomPrimitive::decompose_impl
|
||||
// Access: Protected
|
||||
// Description: Decomposes a complex primitive type into a simpler
|
||||
// primitive type, for instance triangle strips to
|
||||
// triangles, and returns a pointer to the new primitive
|
||||
// definition. If the decomposition cannot be
|
||||
// performed, this might return the original object.
|
||||
//
|
||||
// This method is useful for application code that wants
|
||||
// to iterate through the set of triangles on the
|
||||
// primitive without having to write handlers for each
|
||||
// possible kind of primitive type.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PT(qpGeomPrimitive) qpGeomPrimitive::
|
||||
decompose_impl() {
|
||||
return this;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomPrimitive::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 qpGeomPrimitive::
|
||||
remove_cache_entry() 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 = ((qpGeomPrimitive *)this)->_cycler.write_stage(0);
|
||||
cdata->_decomposed = NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomPrimitive::recompute_minmax
|
||||
// Access: Private
|
||||
|
@ -79,6 +79,8 @@ PUBLISHED:
|
||||
PTA_int modify_lengths();
|
||||
void set_lengths(PTA_int lengths);
|
||||
|
||||
int get_num_bytes() const;
|
||||
|
||||
INLINE int get_min_vertex() const;
|
||||
INLINE int get_max_vertex() const;
|
||||
|
||||
@ -87,12 +89,14 @@ PUBLISHED:
|
||||
int get_primitive_start(int i) const;
|
||||
int get_primitive_num_vertices(int i) const;
|
||||
|
||||
virtual PT(qpGeomPrimitive) decompose(const qpGeomVertexData *vertex_data);
|
||||
PT(qpGeomPrimitive) decompose();
|
||||
|
||||
virtual void output(ostream &out, const qpGeomVertexData *vertex_data) const;
|
||||
virtual void write(ostream &out, const qpGeomVertexData *vertex_data,
|
||||
int indent_level) const;
|
||||
|
||||
void clear_cache();
|
||||
|
||||
public:
|
||||
virtual void draw(GraphicsStateGuardianBase *gsg)=0;
|
||||
|
||||
@ -100,6 +104,12 @@ public:
|
||||
bool &found_any,
|
||||
const qpGeomVertexData *vertex_data) const;
|
||||
|
||||
protected:
|
||||
virtual PT(qpGeomPrimitive) decompose_impl();
|
||||
|
||||
private:
|
||||
void remove_cache_entry() const;
|
||||
|
||||
private:
|
||||
// This is the data that must be cycled between pipeline stages.
|
||||
class EXPCL_PANDA CData : public CycleData {
|
||||
@ -117,6 +127,8 @@ private:
|
||||
bool _got_minmax;
|
||||
unsigned short _min_vertex;
|
||||
unsigned short _max_vertex;
|
||||
|
||||
PT(qpGeomPrimitive) _decomposed;
|
||||
};
|
||||
|
||||
PipelineCycler<CData> _cycler;
|
||||
@ -149,6 +161,7 @@ private:
|
||||
static TypeHandle _type_handle;
|
||||
|
||||
friend class qpGeom;
|
||||
friend class qpGeomVertexCacheManager;
|
||||
};
|
||||
|
||||
#include "qpgeomPrimitive.I"
|
||||
|
@ -53,7 +53,18 @@ qpGeomTrifans::
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomTrifans::decompose
|
||||
// Function: qpGeomTrifans::draw
|
||||
// Access: Public, Virtual
|
||||
// Description: Calls the appropriate method on the GSG to draw the
|
||||
// primitive.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeomTrifans::
|
||||
draw(GraphicsStateGuardianBase *gsg) {
|
||||
gsg->draw_trifans(this);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomTrifans::decompose_impl
|
||||
// Access: Published, Virtual
|
||||
// Description: Decomposes a complex primitive type into a simpler
|
||||
// primitive type, for instance triangle strips to
|
||||
@ -67,7 +78,7 @@ qpGeomTrifans::
|
||||
// possible kind of primitive type.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PT(qpGeomPrimitive) qpGeomTrifans::
|
||||
decompose(const qpGeomVertexData *) {
|
||||
decompose_impl() {
|
||||
PT(qpGeomTriangles) triangles = new qpGeomTriangles;
|
||||
CPTA_ushort vertices = get_vertices();
|
||||
CPTA_int lengths = get_lengths();
|
||||
@ -95,17 +106,6 @@ decompose(const qpGeomVertexData *) {
|
||||
return triangles.p();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomTrifans::draw
|
||||
// Access: Public, Virtual
|
||||
// Description: Calls the appropriate method on the GSG to draw the
|
||||
// primitive.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeomTrifans::
|
||||
draw(GraphicsStateGuardianBase *gsg) {
|
||||
gsg->draw_trifans(this);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomTrifans::register_with_read_factory
|
||||
// Access: Public, Static
|
||||
|
@ -34,11 +34,12 @@ PUBLISHED:
|
||||
qpGeomTrifans(const qpGeomTrifans ©);
|
||||
virtual ~qpGeomTrifans();
|
||||
|
||||
virtual PT(qpGeomPrimitive) decompose(const qpGeomVertexData *vertex_data);
|
||||
|
||||
public:
|
||||
virtual void draw(GraphicsStateGuardianBase *gsg);
|
||||
|
||||
protected:
|
||||
virtual PT(qpGeomPrimitive) decompose_impl();
|
||||
|
||||
public:
|
||||
static void register_with_read_factory();
|
||||
|
||||
|
@ -53,7 +53,18 @@ qpGeomTristrips::
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomTristrips::decompose
|
||||
// Function: qpGeomTristrips::draw
|
||||
// Access: Public, Virtual
|
||||
// Description: Calls the appropriate method on the GSG to draw the
|
||||
// primitive.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeomTristrips::
|
||||
draw(GraphicsStateGuardianBase *gsg) {
|
||||
gsg->draw_tristrips(this);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomTristrips::decompose_impl
|
||||
// Access: Published, Virtual
|
||||
// Description: Decomposes a complex primitive type into a simpler
|
||||
// primitive type, for instance triangle strips to
|
||||
@ -67,7 +78,7 @@ qpGeomTristrips::
|
||||
// possible kind of primitive type.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PT(qpGeomPrimitive) qpGeomTristrips::
|
||||
decompose(const qpGeomVertexData *) {
|
||||
decompose_impl() {
|
||||
PT(qpGeomTriangles) triangles = new qpGeomTriangles;
|
||||
CPTA_ushort vertices = get_vertices();
|
||||
CPTA_int lengths = get_lengths();
|
||||
@ -105,17 +116,6 @@ decompose(const qpGeomVertexData *) {
|
||||
return triangles.p();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomTristrips::draw
|
||||
// Access: Public, Virtual
|
||||
// Description: Calls the appropriate method on the GSG to draw the
|
||||
// primitive.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeomTristrips::
|
||||
draw(GraphicsStateGuardianBase *gsg) {
|
||||
gsg->draw_tristrips(this);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomTristrips::register_with_read_factory
|
||||
// Access: Public, Static
|
||||
|
@ -34,11 +34,12 @@ PUBLISHED:
|
||||
qpGeomTristrips(const qpGeomTristrips ©);
|
||||
virtual ~qpGeomTristrips();
|
||||
|
||||
virtual PT(qpGeomPrimitive) decompose(const qpGeomVertexData *vertex_data);
|
||||
|
||||
public:
|
||||
virtual void draw(GraphicsStateGuardianBase *gsg);
|
||||
|
||||
protected:
|
||||
virtual PT(qpGeomPrimitive) decompose_impl();
|
||||
|
||||
public:
|
||||
static void register_with_read_factory();
|
||||
|
||||
|
179
panda/src/gobj/qpgeomVertexCacheManager.I
Normal file
179
panda/src/gobj/qpgeomVertexCacheManager.I
Normal file
@ -0,0 +1,179 @@
|
||||
// Filename: qpgeomVertexCacheManager.I
|
||||
// Created by: drose (11Mar05)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d-general@lists.sourceforge.net .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::set_max_size
|
||||
// Access: Published
|
||||
// Description: Specifies the amount of memory, in bytes, that should
|
||||
// be set aside for storing pre-processed data for
|
||||
// rendering vertices. This is not a limit on the
|
||||
// actual vertex data, which is what it is; it is also
|
||||
// not a limit on the amount of memory used by the video
|
||||
// driver or the system graphics interface, which Panda
|
||||
// has no control over.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpGeomVertexCacheManager::
|
||||
set_max_size(int max_size) const {
|
||||
// We directly change the config variable.
|
||||
vertex_convert_cache = max_size;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::get_max_size
|
||||
// Access: Published
|
||||
// Description: Returns the amount of memory, in bytes, that should
|
||||
// be set aside for storing pre-processed data for
|
||||
// rendering vertices. See set_max_size().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int qpGeomVertexCacheManager::
|
||||
get_max_size() const {
|
||||
return vertex_convert_cache;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::get_total_size
|
||||
// Access: Published
|
||||
// Description: Returns the amount of memory, in bytes, currently
|
||||
// consumed by the cache of pre-processed vertex data.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int qpGeomVertexCacheManager::
|
||||
get_total_size() const {
|
||||
return _total_size;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::record_munger
|
||||
// Access: Private
|
||||
// Description: Records a new GeomMunger in the cache, or marks a
|
||||
// cache hit for a previously-recorded munger. This
|
||||
// should only be called by GeomMunger.
|
||||
//
|
||||
// The cache manager will hold a reference on the
|
||||
// GeomMunger pointer until it expires from the cache.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpGeomVertexCacheManager::
|
||||
record_munger(const qpGeomMunger *munger) {
|
||||
Entry entry;
|
||||
entry._munger = munger;
|
||||
entry._primitive = NULL;
|
||||
entry._source = NULL;
|
||||
entry._format = NULL;
|
||||
entry._result_size = 100; // Make up a nominal number.
|
||||
|
||||
record_entry(entry);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::record_decompose
|
||||
// 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 GeomPrimitive.
|
||||
//
|
||||
// The cache manager will not hold a reference on the
|
||||
// GeomPrimitive pointer; if it destructs, it should
|
||||
// call remove_decompose() to remove itself from the cache.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpGeomVertexCacheManager::
|
||||
record_decompose(const qpGeomPrimitive *primitive, int result_size) {
|
||||
Entry entry;
|
||||
entry._primitive = primitive;
|
||||
entry._source = NULL;
|
||||
entry._format = NULL;
|
||||
entry._result_size = result_size;
|
||||
|
||||
record_entry(entry);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::remove_decompose
|
||||
// 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 GeomPrimitive.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpGeomVertexCacheManager::
|
||||
remove_decompose(const qpGeomPrimitive *primitive) {
|
||||
Entry entry;
|
||||
entry._primitive = primitive;
|
||||
entry._source = NULL;
|
||||
entry._format = NULL;
|
||||
|
||||
remove_entry(entry);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// 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 *format,
|
||||
int result_size) {
|
||||
Entry entry;
|
||||
entry._primitive = NULL;
|
||||
entry._source = source;
|
||||
entry._format = format;
|
||||
entry._result_size = result_size;
|
||||
|
||||
record_entry(entry);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// 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 *format) {
|
||||
Entry entry;
|
||||
entry._primitive = NULL;
|
||||
entry._source = source;
|
||||
entry._format = format;
|
||||
|
||||
remove_entry(entry);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::Entry::operator <
|
||||
// Access: Public
|
||||
// Description: Provides a unique ordering for EntriesIndex.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool qpGeomVertexCacheManager::Entry::
|
||||
operator < (const qpGeomVertexCacheManager::Entry &other) const {
|
||||
if (_munger != other._munger) {
|
||||
return _munger < other._munger;
|
||||
}
|
||||
if (_primitive != other._primitive) {
|
||||
return _primitive < other._primitive;
|
||||
}
|
||||
if (_source != other._source) {
|
||||
return _source < other._source;
|
||||
}
|
||||
return _format < other._format;
|
||||
}
|
148
panda/src/gobj/qpgeomVertexCacheManager.cxx
Normal file
148
panda/src/gobj/qpgeomVertexCacheManager.cxx
Normal file
@ -0,0 +1,148 @@
|
||||
// Filename: qpgeomVertexCacheManager.cxx
|
||||
// Created by: drose (11Mar05)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d-general@lists.sourceforge.net .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "qpgeomVertexCacheManager.h"
|
||||
#include "mutexHolder.h"
|
||||
|
||||
qpGeomVertexCacheManager *qpGeomVertexCacheManager::_global_ptr = NULL;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::Constructor
|
||||
// Access: Protected
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
qpGeomVertexCacheManager::
|
||||
qpGeomVertexCacheManager() :
|
||||
_total_size(0)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::Destructor
|
||||
// Access: Protected
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
qpGeomVertexCacheManager::
|
||||
~qpGeomVertexCacheManager() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::get_global_ptr
|
||||
// Access: Published, Static
|
||||
// Description: Returns the global cache manager pointer.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
qpGeomVertexCacheManager *qpGeomVertexCacheManager::
|
||||
get_global_ptr() {
|
||||
if (_global_ptr == (qpGeomVertexCacheManager *)NULL) {
|
||||
_global_ptr = new qpGeomVertexCacheManager;
|
||||
}
|
||||
return _global_ptr;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::record_data
|
||||
// Access: Private
|
||||
// Description: Records a new generic entry in the cache, or marks a
|
||||
// cache hit for a previous entry in the cache.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeomVertexCacheManager::
|
||||
record_entry(const qpGeomVertexCacheManager::Entry &entry) {
|
||||
if (gobj_cat.is_debug()) {
|
||||
gobj_cat.debug()
|
||||
<< "record_entry(" << entry._munger << ", "
|
||||
<< entry._primitive << ", " << entry._source << ", "
|
||||
<< entry._format << ", " << entry._result_size << ")\n";
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// 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) {
|
||||
if (gobj_cat.is_debug()) {
|
||||
gobj_cat.debug()
|
||||
<< "total_size = " << _total_size << ", max_size = "
|
||||
<< max_size << ", flushing\n";
|
||||
}
|
||||
nassertv(!_entries.empty());
|
||||
ei = _entries.begin();
|
||||
entry_pointer = &(*ei);
|
||||
|
||||
ii = _entries_index.find(entry_pointer);
|
||||
nassertv(ii != _entries_index.end());
|
||||
|
||||
if (entry_pointer->_source != (qpGeomVertexData *)NULL) {
|
||||
entry_pointer->_source->remove_cache_entry(entry_pointer->_format);
|
||||
}
|
||||
_total_size -= entry_pointer->_result_size;
|
||||
_entries_index.erase(ii);
|
||||
_entries.erase(ei);
|
||||
}
|
||||
if (gobj_cat.is_debug()) {
|
||||
gobj_cat.debug()
|
||||
<< "total_size = " << _total_size << ", max_size = "
|
||||
<< max_size << ", done\n";
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::remove_entry
|
||||
// Access: Private
|
||||
// Description: Removes an entry from the cache, if it is there.
|
||||
// Quietly ignores it if it is not.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeomVertexCacheManager::
|
||||
remove_entry(const qpGeomVertexCacheManager::Entry &entry) {
|
||||
if (gobj_cat.is_debug()) {
|
||||
gobj_cat.debug()
|
||||
<< "remove_entry(" << entry._munger << ", "
|
||||
<< entry._source << ", " << entry._format << ")\n";
|
||||
}
|
||||
MutexHolder holder(_lock);
|
||||
|
||||
EntriesIndex::iterator ii = _entries_index.find(&entry);
|
||||
if (ii != _entries_index.end()) {
|
||||
Entries::iterator ei = (*ii).second;
|
||||
_total_size -= (*ei)._result_size;
|
||||
_entries_index.erase(ii);
|
||||
_entries.erase(ei);
|
||||
}
|
||||
}
|
113
panda/src/gobj/qpgeomVertexCacheManager.h
Normal file
113
panda/src/gobj/qpgeomVertexCacheManager.h
Normal file
@ -0,0 +1,113 @@
|
||||
// Filename: qpgeomVertexCacheManager.h
|
||||
// Created by: drose (11Mar05)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d-general@lists.sourceforge.net .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef qpGEOMVERTEXCACHEMANAGER_H
|
||||
#define qpGEOMVERTEXCACHEMANAGER_H
|
||||
|
||||
#include "pandabase.h"
|
||||
#include "qpgeomMunger.h"
|
||||
#include "config_gobj.h"
|
||||
#include "pointerTo.h"
|
||||
#include "pmutex.h"
|
||||
#include "indirectLess.h"
|
||||
#include "plist.h"
|
||||
#include "pmap.h"
|
||||
|
||||
class qpGeomPrimitive;
|
||||
class qpGeomVertexData;
|
||||
class qpGeomVertexFormat;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : qpGeomVertexCacheManager
|
||||
// Description : This is used to keep track of, and limit the size of,
|
||||
// the cache of munged vertices, which would otherwise
|
||||
// be distributed through all of the GeomVertexData
|
||||
// objects in the system.
|
||||
//
|
||||
// The actual data in the cache is not stored here, but
|
||||
// rather it is distributed among the various
|
||||
// GeomVertexData source objects. This allows the cache
|
||||
// data to propagate through the multiprocess pipeline.
|
||||
//
|
||||
// This is part of the experimental Geom rewrite.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA qpGeomVertexCacheManager {
|
||||
protected:
|
||||
qpGeomVertexCacheManager();
|
||||
~qpGeomVertexCacheManager();
|
||||
|
||||
PUBLISHED:
|
||||
INLINE void set_max_size(int max_size) const;
|
||||
INLINE int get_max_size() const;
|
||||
|
||||
INLINE int get_total_size() const;
|
||||
|
||||
static qpGeomVertexCacheManager *get_global_ptr();
|
||||
|
||||
private:
|
||||
INLINE void record_munger(const qpGeomMunger *munger);
|
||||
INLINE void record_decompose(const qpGeomPrimitive *primitive,
|
||||
int result_size);
|
||||
INLINE void remove_decompose(const qpGeomPrimitive *primitive);
|
||||
INLINE void record_data(const qpGeomVertexData *source,
|
||||
const qpGeomVertexFormat *format,
|
||||
int result_size);
|
||||
INLINE void remove_data(const qpGeomVertexData *source,
|
||||
const qpGeomVertexFormat *format);
|
||||
|
||||
class Entry;
|
||||
|
||||
void record_entry(const Entry &entry);
|
||||
void remove_entry(const Entry &entry);
|
||||
|
||||
private:
|
||||
// This mutex protects all operations on this object.
|
||||
Mutex _lock;
|
||||
|
||||
int _total_size;
|
||||
|
||||
class Entry {
|
||||
public:
|
||||
INLINE bool operator < (const Entry &other) const;
|
||||
|
||||
CPT(qpGeomMunger) _munger;
|
||||
const qpGeomPrimitive *_primitive;
|
||||
const qpGeomVertexData *_source;
|
||||
const qpGeomVertexFormat *_format;
|
||||
int _result_size;
|
||||
};
|
||||
|
||||
// This list keeps the cache entries in least-recently-used order:
|
||||
// the items at the head of the list are ready to be flushed.
|
||||
typedef plist<Entry> Entries;
|
||||
Entries _entries;
|
||||
|
||||
// And this indexes into the above list, for fast lookup.
|
||||
typedef pmap<const Entry *, Entries::iterator, IndirectLess<Entry> > EntriesIndex;
|
||||
EntriesIndex _entries_index;
|
||||
|
||||
static qpGeomVertexCacheManager *_global_ptr;
|
||||
|
||||
friend class qpGeomMunger;
|
||||
friend class qpGeomPrimitive;
|
||||
friend class qpGeomVertexData;
|
||||
};
|
||||
|
||||
#include "qpgeomVertexCacheManager.I"
|
||||
|
||||
#endif
|
@ -17,6 +17,7 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "qpgeomVertexData.h"
|
||||
#include "qpgeomVertexCacheManager.h"
|
||||
#include "bamReader.h"
|
||||
#include "bamWriter.h"
|
||||
#include "pset.h"
|
||||
@ -82,6 +83,25 @@ 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -117,11 +137,14 @@ set_num_vertices(int n) {
|
||||
CDWriter cdata(_cycler);
|
||||
nassertv(_format->get_num_arrays() == (int)cdata->_arrays.size());
|
||||
|
||||
bool any_changed = false;
|
||||
|
||||
for (size_t i = 0; i < cdata->_arrays.size(); i++) {
|
||||
int stride = _format->get_array(i)->get_stride();
|
||||
int delta = n - (cdata->_arrays[i].size() / stride);
|
||||
|
||||
if (delta != 0) {
|
||||
any_changed = true;
|
||||
if (cdata->_arrays[i].get_ref_count() > 1) {
|
||||
// Copy-on-write: the array is already reffed somewhere else,
|
||||
// so we're just going to make a copy.
|
||||
@ -145,6 +168,10 @@ set_num_vertices(int n) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (any_changed) {
|
||||
clear_cache();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -190,6 +217,8 @@ modify_array_data(int array) {
|
||||
cdata->_arrays[array] = PTA_uchar();
|
||||
cdata->_arrays[array].v() = orig_data.v();
|
||||
}
|
||||
|
||||
clear_cache();
|
||||
return cdata->_arrays[array];
|
||||
}
|
||||
|
||||
@ -209,105 +238,23 @@ set_array_data(int array, PTA_uchar array_data) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexData::set_data
|
||||
// Function: qpGeomVertexData::get_num_bytes
|
||||
// Access: Published
|
||||
// Description: Sets the nth vertex to a particular value. Query the
|
||||
// format to get the array index and data_type
|
||||
// parameters for the particular data type you want to
|
||||
// set.
|
||||
//
|
||||
// This flavor of set_data() accepts a generic float
|
||||
// array and a specific number of dimensions. The new
|
||||
// data will be copied from the num_values elements
|
||||
// of data.
|
||||
// Description: Returns the total number of bytes consumed by the
|
||||
// different arrays of the vertex data.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeomVertexData::
|
||||
set_data(int array, const qpGeomVertexDataType *data_type,
|
||||
int vertex, const float *data, int num_values) {
|
||||
int stride = _format->get_array(array)->get_stride();
|
||||
int element = vertex * stride + data_type->get_start();
|
||||
int qpGeomVertexData::
|
||||
get_num_bytes() const {
|
||||
CDReader cdata(_cycler);
|
||||
|
||||
int num_bytes = 0;
|
||||
|
||||
{
|
||||
CDReader cdata(_cycler);
|
||||
int array_size = (int)cdata->_arrays[array].size();
|
||||
if (element + data_type->get_total_bytes() > array_size) {
|
||||
// Whoops, we need more vertices!
|
||||
set_num_vertices(vertex + 1);
|
||||
}
|
||||
Arrays::const_iterator ai;
|
||||
for (ai = cdata->_arrays.begin(); ai != cdata->_arrays.end(); ++ai) {
|
||||
num_bytes += (*ai).size();
|
||||
}
|
||||
|
||||
PTA_uchar array_data = modify_array_data(array);
|
||||
nassertv(element >= 0 && element + data_type->get_total_bytes() <= (int)array_data.size());
|
||||
|
||||
switch (data_type->get_numeric_type()) {
|
||||
case qpGeomVertexDataType::NT_uint8:
|
||||
{
|
||||
nassertv(num_values <= data_type->get_num_values());
|
||||
for (int i = 0; i < num_values; i++) {
|
||||
int value = (int)(data[i] * 255.0f);
|
||||
*(unsigned char *)&array_data[element] = value;
|
||||
element += 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case qpGeomVertexDataType::NT_packed_argb:
|
||||
{
|
||||
nassertv(num_values == 4);
|
||||
*(PN_uint32 *)&array_data[element] = pack_argb(data);
|
||||
}
|
||||
break;
|
||||
|
||||
case qpGeomVertexDataType::NT_float:
|
||||
nassertv(num_values == data_type->get_num_values());
|
||||
memcpy(&array_data[element], data, data_type->get_total_bytes());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexData::get_data
|
||||
// Access: Published
|
||||
// Description: Returns the data associated with the nth vertex for a
|
||||
// particular value. Query the format to get the array
|
||||
// index and data_type parameters for the particular
|
||||
// data type you want to get.
|
||||
//
|
||||
// This flavor of get_data() copies its data into a
|
||||
// generic float array.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeomVertexData::
|
||||
get_data(int array, const qpGeomVertexDataType *data_type,
|
||||
int vertex, float *data, int num_values) const {
|
||||
CPTA_uchar array_data = get_array_data(array);
|
||||
int stride = _format->get_array(array)->get_stride();
|
||||
int element = vertex * stride + data_type->get_start();
|
||||
nassertv(element >= 0 && element + data_type->get_total_bytes() <= (int)array_data.size());
|
||||
|
||||
switch (data_type->get_numeric_type()) {
|
||||
case qpGeomVertexDataType::NT_uint8:
|
||||
{
|
||||
nassertv(num_values <= data_type->get_num_values());
|
||||
for (int i = 0; i < num_values; i++) {
|
||||
int value = *(unsigned char *)&array_data[element];
|
||||
element += 1;
|
||||
data[i] = (float)value / 255.0f;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case qpGeomVertexDataType::NT_packed_argb:
|
||||
{
|
||||
nassertv(num_values == 4);
|
||||
unpack_argb(data, *(PN_uint32 *)&array_data[element]);
|
||||
}
|
||||
break;
|
||||
|
||||
case qpGeomVertexDataType::NT_float:
|
||||
nassertv(num_values <= data_type->get_num_values());
|
||||
memcpy(data, &array_data[element], num_values * sizeof(PN_float32));
|
||||
break;
|
||||
}
|
||||
return num_bytes;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -318,10 +265,43 @@ get_data(int array, const qpGeomVertexDataType *data_type,
|
||||
// the data vertex-by-vertex to a new set of data arrays
|
||||
// in the new format.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PT(qpGeomVertexData) qpGeomVertexData::
|
||||
CPT(qpGeomVertexData) qpGeomVertexData::
|
||||
convert_to(const qpGeomVertexFormat *new_format) const {
|
||||
if (new_format == _format) {
|
||||
// Trivial case: no change is needed.
|
||||
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();
|
||||
|
||||
if (gobj_cat.is_debug()) {
|
||||
gobj_cat.debug()
|
||||
<< "Converting " << num_vertices << " vertices.\n";
|
||||
}
|
||||
|
||||
PT(qpGeomVertexData) new_data = new qpGeomVertexData(new_format);
|
||||
|
||||
pset<int> done_arrays;
|
||||
@ -383,6 +363,19 @@ 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;
|
||||
}
|
||||
|
||||
@ -406,6 +399,130 @@ 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
|
||||
// Description: Sets the nth vertex to a particular value. Query the
|
||||
// format to get the array index and data_type
|
||||
// parameters for the particular data type you want to
|
||||
// set.
|
||||
//
|
||||
// This flavor of set_data() accepts a generic float
|
||||
// array and a specific number of dimensions. The new
|
||||
// data will be copied from the num_values elements
|
||||
// of data.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeomVertexData::
|
||||
set_data(int array, const qpGeomVertexDataType *data_type,
|
||||
int vertex, const float *data, int num_values) {
|
||||
int stride = _format->get_array(array)->get_stride();
|
||||
int element = vertex * stride + data_type->get_start();
|
||||
|
||||
{
|
||||
CDReader cdata(_cycler);
|
||||
int array_size = (int)cdata->_arrays[array].size();
|
||||
if (element + data_type->get_total_bytes() > array_size) {
|
||||
// Whoops, we need more vertices!
|
||||
set_num_vertices(vertex + 1);
|
||||
}
|
||||
}
|
||||
|
||||
PTA_uchar array_data = modify_array_data(array);
|
||||
nassertv(element >= 0 && element + data_type->get_total_bytes() <= (int)array_data.size());
|
||||
|
||||
switch (data_type->get_numeric_type()) {
|
||||
case qpGeomVertexDataType::NT_uint8:
|
||||
{
|
||||
nassertv(num_values <= data_type->get_num_values());
|
||||
for (int i = 0; i < num_values; i++) {
|
||||
int value = (int)(data[i] * 255.0f);
|
||||
*(unsigned char *)&array_data[element] = value;
|
||||
element += 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case qpGeomVertexDataType::NT_packed_argb:
|
||||
{
|
||||
nassertv(num_values == 4);
|
||||
*(PN_uint32 *)&array_data[element] = pack_argb(data);
|
||||
}
|
||||
break;
|
||||
|
||||
case qpGeomVertexDataType::NT_float:
|
||||
nassertv(num_values == data_type->get_num_values());
|
||||
memcpy(&array_data[element], data, data_type->get_total_bytes());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexData::get_data
|
||||
// Access: Public
|
||||
// Description: Returns the data associated with the nth vertex for a
|
||||
// particular value. Query the format to get the array
|
||||
// index and data_type parameters for the particular
|
||||
// data type you want to get.
|
||||
//
|
||||
// This flavor of get_data() copies its data into a
|
||||
// generic float array.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeomVertexData::
|
||||
get_data(int array, const qpGeomVertexDataType *data_type,
|
||||
int vertex, float *data, int num_values) const {
|
||||
CPTA_uchar array_data = get_array_data(array);
|
||||
int stride = _format->get_array(array)->get_stride();
|
||||
int element = vertex * stride + data_type->get_start();
|
||||
nassertv(element >= 0 && element + data_type->get_total_bytes() <= (int)array_data.size());
|
||||
|
||||
switch (data_type->get_numeric_type()) {
|
||||
case qpGeomVertexDataType::NT_uint8:
|
||||
{
|
||||
nassertv(num_values <= data_type->get_num_values());
|
||||
for (int i = 0; i < num_values; i++) {
|
||||
int value = *(unsigned char *)&array_data[element];
|
||||
element += 1;
|
||||
data[i] = (float)value / 255.0f;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case qpGeomVertexDataType::NT_packed_argb:
|
||||
{
|
||||
nassertv(num_values == 4);
|
||||
unpack_argb(data, *(PN_uint32 *)&array_data[element]);
|
||||
}
|
||||
break;
|
||||
|
||||
case qpGeomVertexDataType::NT_float:
|
||||
nassertv(num_values <= data_type->get_num_values());
|
||||
memcpy(data, &array_data[element], num_values * sizeof(PN_float32));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexData::get_array_info
|
||||
// Access: Public
|
||||
@ -546,6 +663,27 @@ 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 *format) 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(format);
|
||||
if (ci != cdata->_converted_cache.end()) {
|
||||
cdata->_converted_cache.erase(ci);
|
||||
}
|
||||
((qpGeomVertexData *)this)->_cycler.release_write_stage(0, cdata);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexData::register_with_read_factory
|
||||
// Access: Public, Static
|
||||
|
@ -77,17 +77,21 @@ PUBLISHED:
|
||||
PTA_uchar modify_array_data(int array);
|
||||
void set_array_data(int array, PTA_uchar array_data);
|
||||
|
||||
int get_num_bytes() 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);
|
||||
void get_data(int array, const qpGeomVertexDataType *data_type,
|
||||
int vertex, float *data, int num_values) const;
|
||||
|
||||
PT(qpGeomVertexData) convert_to(const qpGeomVertexFormat *new_format) const;
|
||||
|
||||
void output(ostream &out) const;
|
||||
void write(ostream &out, int indent_level = 0) const;
|
||||
|
||||
public:
|
||||
bool get_array_info(const InternalName *name, CPTA_uchar &array_data,
|
||||
int &num_components,
|
||||
qpGeomVertexDataType::NumericType &numeric_type,
|
||||
@ -101,9 +105,19 @@ public:
|
||||
static void unpack_argb(float data[4], unsigned int packed_argb);
|
||||
|
||||
private:
|
||||
void remove_cache_entry(const qpGeomVertexFormat *format) const;
|
||||
|
||||
private:
|
||||
CPT(qpGeomVertexFormat) _format;
|
||||
|
||||
typedef pvector<PTA_uchar> Arrays;
|
||||
|
||||
CPT(qpGeomVertexFormat) _format;
|
||||
// We have to use reference-counting pointers here instead of having
|
||||
// explicit cleanup in the GeomVertexFormat destructor, because the
|
||||
// cache needs to be stored in the CycleData, which makes accurate
|
||||
// cleanup more difficult. We use the GeomVertexCacheManager class
|
||||
// to avoid cache bloat.
|
||||
typedef pmap<CPT(qpGeomVertexFormat), CPT(qpGeomVertexData) > ConvertedCache;
|
||||
|
||||
// This is the data that must be cycled between pipeline stages.
|
||||
class EXPCL_PANDA CData : public CycleData {
|
||||
@ -116,6 +130,7 @@ private:
|
||||
virtual void fillin(DatagramIterator &scan, BamReader *manager);
|
||||
|
||||
Arrays _arrays;
|
||||
ConvertedCache _converted_cache;
|
||||
};
|
||||
|
||||
PipelineCycler<CData> _cycler;
|
||||
@ -146,6 +161,8 @@ public:
|
||||
|
||||
private:
|
||||
static TypeHandle _type_handle;
|
||||
|
||||
friend class qpGeomVertexCacheManager;
|
||||
};
|
||||
|
||||
INLINE ostream &operator << (ostream &out, const qpGeomVertexData &obj);
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "qpgeomVertexFormat.h"
|
||||
#include "qpgeomVertexData.h"
|
||||
#include "qpgeomMunger.h"
|
||||
#include "mutexHolder.h"
|
||||
#include "indent.h"
|
||||
#include "bamReader.h"
|
||||
#include "bamWriter.h"
|
||||
@ -435,6 +436,7 @@ do_unregister() {
|
||||
|
||||
_data_types_by_name.clear();
|
||||
|
||||
MutexHolder holder(_cache_lock);
|
||||
Mungers::iterator mi;
|
||||
for (mi = _mungers.begin(); mi != _mungers.end(); ++mi) {
|
||||
(*mi)->remove_format(this);
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "pvector.h"
|
||||
#include "pta_float.h"
|
||||
#include "indirectCompareTo.h"
|
||||
#include "pmutex.h"
|
||||
|
||||
class FactoryParams;
|
||||
class qpGeomVertexData;
|
||||
@ -142,9 +143,13 @@ private:
|
||||
typedef pmap<const InternalName *, DataTypeRecord> DataTypesByName;
|
||||
DataTypesByName _data_types_by_name;
|
||||
|
||||
// This set keeps track of things that need to be told when we
|
||||
// destruct, and it is protected by the mutex.
|
||||
Mutex _cache_lock;
|
||||
typedef pset<qpGeomMunger *> Mungers;
|
||||
Mungers _mungers;
|
||||
|
||||
// This is the global registry of all currently-in-use formats.
|
||||
typedef pset<qpGeomVertexFormat *, IndirectCompareTo<qpGeomVertexFormat> > Formats;
|
||||
class Registry {
|
||||
public:
|
||||
|
@ -47,6 +47,7 @@ class qpGeomVertexData;
|
||||
class qpGeomTriangles;
|
||||
class qpGeomTristrips;
|
||||
class qpGeomTrifans;
|
||||
class qpGeomMunger;
|
||||
|
||||
class PreparedGraphicsObjects;
|
||||
class GraphicsOutput;
|
||||
@ -130,6 +131,8 @@ public:
|
||||
virtual GeomContext *prepare_geom(Geom *geom)=0;
|
||||
virtual void release_geom(GeomContext *gc)=0;
|
||||
|
||||
virtual CPT(qpGeomMunger) get_geom_munger(const RenderState *state)=0;
|
||||
|
||||
virtual void set_state_and_transform(const RenderState *state,
|
||||
const TransformState *transform)=0;
|
||||
|
||||
|
@ -30,6 +30,6 @@ draw(CullableObject *object, GraphicsStateGuardianBase *gsg) {
|
||||
draw_with_decals(object, gsg);
|
||||
} else {
|
||||
gsg->set_state_and_transform(object->_state, object->_transform);
|
||||
object->_geom->draw(gsg);
|
||||
object->draw(gsg);
|
||||
}
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ draw_with_decals(CullableObject *object, GraphicsStateGuardianBase *gsg) {
|
||||
CullableObject *base = object;
|
||||
while (base != (CullableObject *)NULL && base->_geom != (Geom *)NULL) {
|
||||
gsg->set_state_and_transform(base->_state->compose(state), base->_transform);
|
||||
base->_geom->draw(gsg);
|
||||
base->draw(gsg);
|
||||
|
||||
base = base->_next;
|
||||
}
|
||||
@ -78,7 +78,7 @@ draw_with_decals(CullableObject *object, GraphicsStateGuardianBase *gsg) {
|
||||
CullableObject *decal = base->_next;
|
||||
while (decal != (CullableObject *)NULL) {
|
||||
gsg->set_state_and_transform(decal->_state->compose(state), decal->_transform);
|
||||
decal->_geom->draw(gsg);
|
||||
decal->draw(gsg);
|
||||
decal = decal->_next;
|
||||
}
|
||||
}
|
||||
@ -89,7 +89,7 @@ draw_with_decals(CullableObject *object, GraphicsStateGuardianBase *gsg) {
|
||||
base = object;
|
||||
while (base != (CullableObject *)NULL && base->_geom != (Geom *)NULL) {
|
||||
gsg->set_state_and_transform(base->_state->compose(state), base->_transform);
|
||||
base->_geom->draw(gsg);
|
||||
base->draw(gsg);
|
||||
|
||||
base = base->_next;
|
||||
}
|
||||
|
@ -85,6 +85,10 @@ make_next() const {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CullResult::
|
||||
add_object(CullableObject *object) {
|
||||
// Munge vertices as needed for the GSG's requirements, and the
|
||||
// object's current state.
|
||||
object->munge_vertices(_gsg);
|
||||
|
||||
// Check to see if there's a special transparency setting.
|
||||
const RenderState *state = object->_state;
|
||||
nassertv(state != (const RenderState *)NULL);
|
||||
|
@ -103,6 +103,35 @@ has_decals() const {
|
||||
return (_next != (CullableObject *)NULL);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CullableObject::munge_vertices
|
||||
// Access: Public
|
||||
// Description: Gets a GeomMunger from the GSG to transform the
|
||||
// vertices to meet the GSG's vertex requirements for
|
||||
// the current state.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void CullableObject::
|
||||
munge_vertices(GraphicsStateGuardianBase *gsg) {
|
||||
// Temporary test until the experimental Geom rewrite becomes the
|
||||
// actual Geom implementation.
|
||||
if (_geom->is_exact_type(qpGeom::get_class_type())) {
|
||||
CPT(qpGeomMunger) munger = gsg->get_geom_munger(_state);
|
||||
_munged_data = munger->munge_data(((const qpGeom *)_geom.p())->get_vertex_data());
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CullableObject::draw
|
||||
// Access: Public
|
||||
// Description: Draws the cullable object on the GSG immediately, in
|
||||
// the GSG's current state. This should only be called
|
||||
// from the draw thread.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void CullableObject::
|
||||
draw(GraphicsStateGuardianBase *gsg) {
|
||||
_geom->draw(gsg, _munged_data);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CullableObject::operator new
|
||||
// Access: Public
|
||||
|
@ -22,6 +22,9 @@
|
||||
#include "pandabase.h"
|
||||
|
||||
#include "geom.h"
|
||||
#include "qpgeom.h"
|
||||
#include "qpgeomVertexData.h"
|
||||
#include "qpgeomMunger.h"
|
||||
#include "renderState.h"
|
||||
#include "transformState.h"
|
||||
#include "pointerTo.h"
|
||||
@ -51,6 +54,9 @@ public:
|
||||
|
||||
INLINE bool has_decals() const;
|
||||
|
||||
INLINE void munge_vertices(GraphicsStateGuardianBase *gsg);
|
||||
INLINE void draw(GraphicsStateGuardianBase *gsg);
|
||||
|
||||
public:
|
||||
~CullableObject();
|
||||
|
||||
@ -67,6 +73,7 @@ PUBLISHED:
|
||||
|
||||
public:
|
||||
CPT(Geom) _geom;
|
||||
CPT(qpGeomVertexData) _munged_data;
|
||||
CPT(RenderState) _state;
|
||||
CPT(TransformState) _transform;
|
||||
CullableObject *_next;
|
||||
|
@ -33,6 +33,11 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void DrawCullHandler::
|
||||
record_object(CullableObject *object) {
|
||||
// Munge vertices as needed for the GSG's requirements, and the
|
||||
// object's current state.
|
||||
object->munge_vertices(_gsg);
|
||||
|
||||
// And draw the object, then dispense with it.
|
||||
draw(object, _gsg);
|
||||
delete object;
|
||||
}
|
||||
|
@ -125,6 +125,7 @@ static TimeCollectorProperties time_properties[] = {
|
||||
{ 1, "Cull", { 0.0, 1.0, 0.0 }, 1.0 / 30.0 },
|
||||
{ 1, "Cull:Show fps", { 0.5, 0.8, 1.0 } },
|
||||
{ 1, "Cull:Bins", { 0.3, 0.6, 0.3 } },
|
||||
{ 1, "Cull:Munge", { 0.3, 0.3, 0.9 } },
|
||||
{ 1, "Draw", { 1.0, 0.0, 0.0 }, 1.0 / 30.0 },
|
||||
{ 1, "Draw:Make current", { 0.4, 0.2, 0.6 } },
|
||||
{ 1, "Draw:Copy texture", { 0.2, 0.6, 0.4 } },
|
||||
|
Loading…
x
Reference in New Issue
Block a user