From 0ebafd6c752923f4f3c5d1e8dcf8b012ba4bfad6 Mon Sep 17 00:00:00 2001 From: David Rose Date: Mon, 9 Jul 2007 17:03:27 +0000 Subject: [PATCH] further fixes to bam loader ordering --- panda/src/gobj/geomVertexArrayData.cxx | 1 - panda/src/gobj/geomVertexData.cxx | 18 ++++- panda/src/gobj/geomVertexData.h | 1 + panda/src/putil/bamReader.cxx | 92 +++++++++++++++----------- panda/src/putil/bamReader.h | 19 ++++-- 5 files changed, 83 insertions(+), 48 deletions(-) diff --git a/panda/src/gobj/geomVertexArrayData.cxx b/panda/src/gobj/geomVertexArrayData.cxx index a628806ca6..95c6c9fe52 100644 --- a/panda/src/gobj/geomVertexArrayData.cxx +++ b/panda/src/gobj/geomVertexArrayData.cxx @@ -623,7 +623,6 @@ fillin(DatagramIterator &scan, BamReader *manager, void *extra_data) { } else { // Now, the array data is just stored directly. size_t size = scan.get_uint32(); - _buffer.unclean_realloc(size); const unsigned char *source_data = diff --git a/panda/src/gobj/geomVertexData.cxx b/panda/src/gobj/geomVertexData.cxx index 22233ddaae..3bd0a6fffa 100644 --- a/panda/src/gobj/geomVertexData.cxx +++ b/panda/src/gobj/geomVertexData.cxx @@ -1536,6 +1536,21 @@ complete_pointers(TypedWritable **p_list, BamReader *manager) { return pi; } +//////////////////////////////////////////////////////////////////// +// Function: GeomVertexData::require_fully_complete +// Access: Public, Virtual +// Description: Some objects require all of their nested pointers to +// have been completed before the objects themselves can +// be completed. If this is the case, override this +// method to return true, and be careful with circular +// references (which would make the object unreadable +// from a bam file). +//////////////////////////////////////////////////////////////////// +bool GeomVertexData:: +require_fully_complete() const { + return true; +} + //////////////////////////////////////////////////////////////////// // Function: GeomVertexData::finalize // Access: Public, Virtual @@ -1703,7 +1718,8 @@ complete_pointers(TypedWritable **p_list, BamReader *manager) { // a SparseArray for each of them that reflects the complete // number of rows in the data. SparseArray all_rows; - all_rows.set_range(0, _arrays[0].get_read_pointer()->get_num_rows()); + CPT(GeomVertexArrayData) adata = _arrays[0].get_read_pointer(); + all_rows.set_range(0, adata->get_num_rows()); if (_slider_table != (SliderTable *)NULL) { int num_sliders = _slider_table->get_num_sliders(); diff --git a/panda/src/gobj/geomVertexData.h b/panda/src/gobj/geomVertexData.h index 8b78ba37f6..23a7bca783 100644 --- a/panda/src/gobj/geomVertexData.h +++ b/panda/src/gobj/geomVertexData.h @@ -325,6 +325,7 @@ public: static void register_with_read_factory(); virtual void write_datagram(BamWriter *manager, Datagram &dg); virtual int complete_pointers(TypedWritable **plist, BamReader *manager); + virtual bool require_fully_complete() const; virtual void finalize(BamReader *manager); diff --git a/panda/src/putil/bamReader.cxx b/panda/src/putil/bamReader.cxx index c2e62d7949..11f040b532 100644 --- a/panda/src/putil/bamReader.cxx +++ b/panda/src/putil/bamReader.cxx @@ -301,35 +301,11 @@ resolve() { all_completed = true; any_completed_this_pass = false; - // First do the PipelineCycler objects. - CyclerPointers::iterator ci; - ci = _cycler_pointers.begin(); - while (ci != _cycler_pointers.end()) { - PipelineCyclerBase *cycler = (*ci).first; - const vector_int &pointer_ids = (*ci).second; - - if (resolve_cycler_pointers(cycler, pointer_ids)) { - // Now remove this cycler from the list of things that need - // completion. We have to be a bit careful when deleting things - // from the STL container while we are traversing it. - CyclerPointers::iterator old = ci; - ++ci; - _cycler_pointers.erase(old); - any_completed_this_pass = true; - - } else { - // Couldn't complete this cycler yet; it'll wait for next time. - ++ci; - all_completed = false; - } - } - - // Now do the main objects. ObjectPointers::iterator oi; oi = _object_pointers.begin(); while (oi != _object_pointers.end()) { int object_id = (*oi).first; - const vector_int &pointer_ids = (*oi).second; + PointerReference &pref = (*oi).second; CreatedObjs::iterator ci = _created_objs.find(object_id); nassertr(ci != _created_objs.end(), false); @@ -338,7 +314,7 @@ resolve() { TypedWritable *object_ptr = created_obj._ptr; - if (resolve_object_pointers(object_ptr, pointer_ids)) { + if (resolve_object_pointers(object_ptr, pref)) { // Now remove this object from the list of things that need // completion. We have to be a bit careful when deleting things // from the STL container while we are traversing it. @@ -574,12 +550,13 @@ read_pointer(DatagramIterator &scan) { // Read the object ID, and associate it with the requesting object. int object_id = read_object_id(scan); + PointerReference &pref = _object_pointers[requestor_id]; if (_reading_cycler == (PipelineCyclerBase *)NULL) { // This is not being read within a read_cdata() call. - _object_pointers[requestor_id].push_back(object_id); + pref._objects.push_back(object_id); } else { // This *is* being read within a read_cdata() call. - _cycler_pointers[_reading_cycler].push_back(object_id); + pref._cycler_pointers[_reading_cycler].push_back(object_id); } // If the object ID is zero (which indicates a NULL pointer), we @@ -1054,7 +1031,39 @@ p_read_object() { // and returns true; otherwise, returns false. //////////////////////////////////////////////////////////////////// bool BamReader:: -resolve_object_pointers(TypedWritable *object, const vector_int &pointer_ids) { +resolve_object_pointers(TypedWritable *object, + BamReader::PointerReference &pref) { + // Some objects further require all of their nested objects to have + // been completed (i.e. complete_pointers has been called on each + // nested object) before they can themselves be completed. + bool require_fully_complete = object->require_fully_complete(); + + // First do the PipelineCycler objects. + CyclerPointers::iterator ci; + ci = pref._cycler_pointers.begin(); + while (ci != pref._cycler_pointers.end()) { + PipelineCyclerBase *cycler = (*ci).first; + const vector_int &pointer_ids = (*ci).second; + + if (resolve_cycler_pointers(cycler, pointer_ids, require_fully_complete)) { + // Now remove this cycler from the list of things that need + // completion. We have to be a bit careful when deleting things + // from the STL container while we are traversing it. + CyclerPointers::iterator old = ci; + ++ci; + pref._cycler_pointers.erase(old); + + } else { + // Couldn't complete this cycler yet; it'll wait for next time. + ++ci; + } + } + + if (!pref._cycler_pointers.empty()) { + // If we didn't get all the cyclers, we have to wait. + return false; + } + // Now make sure we have all of the pointers this object is // waiting for. If any of the pointers has not yet been read // in, we can't resolve this object--we can't do anything for a @@ -1062,15 +1071,12 @@ resolve_object_pointers(TypedWritable *object, const vector_int &pointer_ids) { // that object. bool is_complete = true; - // Some objects further require all of their nested objects to have - // been completed (i.e. complete_pointers has been called on each - // nested object) before they can themselves be completed. - bool require_fully_complete = object->require_fully_complete(); - vector_typedWritable references; vector_int::const_iterator pi; - for (pi = pointer_ids.begin(); pi != pointer_ids.end() && is_complete; ++pi) { + for (pi = pref._objects.begin(); + pi != pref._objects.end() && is_complete; + ++pi) { int child_id = (*pi); if (child_id == 0) { // A NULL pointer is a NULL pointer. @@ -1106,7 +1112,7 @@ resolve_object_pointers(TypedWritable *object, const vector_int &pointer_ids) { if (is_complete) { // Okay, here's the complete list of pointers for you! - nassertr(references.size() == pointer_ids.size(), false); + nassertr(references.size() == pref._objects.size(), false); if (bam_cat.is_spam()) { bam_cat.spam() @@ -1143,7 +1149,8 @@ resolve_object_pointers(TypedWritable *object, const vector_int &pointer_ids) { //////////////////////////////////////////////////////////////////// bool BamReader:: resolve_cycler_pointers(PipelineCyclerBase *cycler, - const vector_int &pointer_ids) { + const vector_int &pointer_ids, + bool require_fully_complete) { // Now make sure we have all of the pointers this cycler is // waiting for. If any of the pointers has not yet been read // in, we can't resolve this cycler--we can't do anything for a @@ -1175,8 +1182,15 @@ resolve_cycler_pointers(PipelineCyclerBase *cycler, is_complete = false; } else { - // Yes, it's ready. - references.push_back(child_obj._ptr); + if (require_fully_complete && + _object_pointers.find(child_id) != _object_pointers.end()) { + // It's not yet complete itself. + is_complete = false; + + } else { + // Yes, it's ready. + references.push_back(child_obj._ptr); + } } } } diff --git a/panda/src/putil/bamReader.h b/panda/src/putil/bamReader.h index bd617b2c68..44bb0fb8fd 100644 --- a/panda/src/putil/bamReader.h +++ b/panda/src/putil/bamReader.h @@ -149,12 +149,15 @@ private: INLINE static void create_factory(); private: + class PointerReference; + void free_object_ids(DatagramIterator &scan); int read_object_id(DatagramIterator &scan); int read_pta_id(DatagramIterator &scan); int p_read_object(); - bool resolve_object_pointers(TypedWritable *object, const vector_int &pointer_ids); - bool resolve_cycler_pointers(PipelineCyclerBase *cycler, const vector_int &pointer_ids); + bool resolve_object_pointers(TypedWritable *object, PointerReference &pref); + bool resolve_cycler_pointers(PipelineCyclerBase *cycler, const vector_int &pointer_ids, + bool require_fully_complete); void finalize(); INLINE bool get_datagram(Datagram &datagram); @@ -215,12 +218,14 @@ private: // completed, along with the object ID's of the pointers they need, // in the order in which read_pointer() was called, so that we may // call the appropriate complete_pointers() later. - typedef phash_map ObjectPointers; - ObjectPointers _object_pointers; - - // Ditto, for the PiplineCycler objects. typedef phash_map CyclerPointers; - CyclerPointers _cycler_pointers; + class PointerReference { + public: + vector_int _objects; + CyclerPointers _cycler_pointers; + }; + typedef phash_map ObjectPointers; + ObjectPointers _object_pointers; // This is the number of extra objects that must still be read (and // saved in the _created_objs map) before returning from