diff --git a/indra/newview/floaterlocalassetbrowse.cpp b/indra/newview/floaterlocalassetbrowse.cpp index c643c636d..700fb8dca 100644 --- a/indra/newview/floaterlocalassetbrowse.cpp +++ b/indra/newview/floaterlocalassetbrowse.cpp @@ -376,6 +376,12 @@ std::vector LocalBitmap::getUsingObjects(bool seek_by_type, boo iter != gObjectList.mObjects.end(); iter++ ) { LLViewerObject* obj = *iter; + + if (obj->isDead()) + { + continue; + } + affected_object shell; shell.object = obj; shell.local_sculptmap = false; diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 332c090fc..6fe2e4b18 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -103,6 +103,7 @@ LLViewerObjectList::LLViewerObjectList() mCurLazyUpdateIndex = 0; mCurBin = 0; mNumDeadObjects = 0; + mMinNumDeadObjects = 20; mNumOrphans = 0; mNumNewObjects = 0; mWasPaused = FALSE; @@ -586,23 +587,27 @@ void LLViewerObjectList::dirtyAllObjectInventory() void LLViewerObjectList::updateApparentAngles(LLAgent &agent) { S32 i; - S32 num_objects = 0; + S32 const objects_size = mObjects.size(); LLViewerObject *objectp; S32 num_updates, max_value; + // The list can have shrinked since mCurLazyUpdateIndex was last updated. + if (mCurLazyUpdateIndex >= objects_size) + { + mCurLazyUpdateIndex = 0; + } if (NUM_BINS - 1 == mCurBin) { - num_updates = (S32) mObjects.size() - mCurLazyUpdateIndex; - max_value = (S32) mObjects.size(); + num_updates = objects_size - mCurLazyUpdateIndex; + max_value = objects_size; gTextureList.setUpdateStats(TRUE); } else { - num_updates = ((S32) mObjects.size() / NUM_BINS) + 1; - max_value = llmin((S32) mObjects.size(), mCurLazyUpdateIndex + num_updates); + num_updates = (objects_size / NUM_BINS) + 1; + max_value = llmin(objects_size, mCurLazyUpdateIndex + num_updates); } - if (!gNoRender) { // Slam priorities for textures that we care about (hovered, selected, and focused) @@ -639,8 +644,6 @@ void LLViewerObjectList::updateApparentAngles(LLAgent &agent) objectp = mObjects[i]; if (!objectp->isDead()) { - num_objects++; - // Update distance & gpw objectp->setPixelAreaAndAngle(agent); // Also sets the approx. pixel area objectp->updateTextures(); // Update the image levels of textures for this object. @@ -648,7 +651,7 @@ void LLViewerObjectList::updateApparentAngles(LLAgent &agent) } mCurLazyUpdateIndex = max_value; - if (mCurLazyUpdateIndex == mObjects.size()) + if (mCurLazyUpdateIndex == objects_size) { mCurLazyUpdateIndex = 0; } @@ -809,7 +812,7 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world) } */ - mNumObjectsStat.addValue((S32) mObjects.size()); + mNumObjectsStat.addValue((S32) mObjects.size() - mNumDeadObjects); mNumActiveObjectsStat.addValue(num_active_objects); mNumSizeCulledStat.addValue(mNumSizeCulled); mNumVisCulledStat.addValue(mNumVisCulled); @@ -819,7 +822,12 @@ void LLViewerObjectList::clearDebugText() { for (vobj_list_t::iterator iter = mObjects.begin(); iter != mObjects.end(); ++iter) { - (*iter)->setDebugText(""); + LLViewerObject *objectp = *iter; + if (objectp->isDead()) + { + continue; + } + objectp->setDebugText(""); } } @@ -975,41 +983,65 @@ void LLViewerObjectList::killAllObjects() void LLViewerObjectList::cleanDeadObjects(BOOL use_timer) { - if (!mNumDeadObjects) + if (use_timer && mNumDeadObjects < mMinNumDeadObjects) { - // No dead objects, don't need to scan object list. + // Not enough dead objects, don't scan the whole object list until there are a few. + // However, the longer it takes to reach this quota, the less demanding we are, + // so decrease the lower limit but never demand less than 20. + mMinNumDeadObjects = llmax(20, mMinNumDeadObjects - 1); return; } - llwarns << "ENTERING LLViewerObjectList::cleanDeadObjects" << llendl; + // If we got this many now, we might as well demand it for the next calls too (they + // tend to come in batches). However, never demand more than 100. + mMinNumDeadObjects = llmin(100, mNumDeadObjects); + // Scan for all of the dead objects and remove any "global" references to them. + + // We first move all dead objects to the end of the std::vector (the swap + // is VERY cheap) and only then call erase once: calling erase on a vector + // is very expensive! + + vobj_list_t::iterator iter = mObjects.begin(); // Runs over all objects. + vobj_list_t::iterator const end = mObjects.end(); + vobj_list_t::iterator last = end; // Points to the last object that is not dead. S32 num_removed = 0; - LLViewerObject *objectp; - for (vobj_list_t::iterator iter = mObjects.begin(); iter != mObjects.end(); ) - { - // Scan for all of the dead objects and remove any "global" references to them. - objectp = *iter; - if (objectp->isDead()) - { - iter = mObjects.erase(iter); - num_removed++; - if (num_removed == mNumDeadObjects) - { - // We've cleaned up all of the dead objects. - break; - } - } - else + // Find the first Dead object. + while (iter != last && !(*iter)->isDead()) + ++iter; + + // While iter did not bumb into last, continue the search. + while (iter != last) + { + // Find the next not Dead object from the end. + do { + --last; + ++num_removed; + } while (last != iter && (*last)->isDead()); + if (iter == last) { - ++iter; + // There no more Dead objects left before last. + break; } + // Swap both object Pointers. + vobj_list_t::value_type::swap(*iter, *last); + if (num_removed == mNumDeadObjects) + { + // There aren't any more dead objects. + break; + } + // Find the next Dead object at the beginning. + do { + ++iter; + } while (iter != last && !(*iter)->isDead()); } + llassert(end - last == num_removed); + mObjects.erase(last, end); // We've cleaned the global object list, now let's do some paranoia testing on objects // before blowing away the dead list. mDeadObjects.clear(); mNumDeadObjects = 0; - llwarns << "LEAVING LLViewerObjectList::cleanDeadObjects" << llendl; } void LLViewerObjectList::updateActive(LLViewerObject *objectp) diff --git a/indra/newview/llviewerobjectlist.h b/indra/newview/llviewerobjectlist.h index 43d25229e..f2255d22e 100644 --- a/indra/newview/llviewerobjectlist.h +++ b/indra/newview/llviewerobjectlist.h @@ -190,6 +190,7 @@ public: S32 mNumDeadObjectUpdates; S32 mNumUnknownKills; S32 mNumDeadObjects; + S32 mMinNumDeadObjects; protected: std::vector mOrphanParents; // LocalID/ip,port of orphaned objects std::vector mOrphanChildren; // UUID's of orphaned objects