diff options
Diffstat (limited to 'indra/newview/llviewerobjectlist.cpp')
-rwxr-xr-x[-rw-r--r--] | indra/newview/llviewerobjectlist.cpp | 1423 |
1 files changed, 1058 insertions, 365 deletions
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 2927ca5292..7c36b30dd1 100644..100755 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -2,31 +2,25 @@ * @file llviewerobjectlist.cpp * @brief Implementation of LLViewerObjectList class. * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,7 +29,6 @@ #include "llviewerobjectlist.h" #include "message.h" -#include "timing.h" #include "llfasttimer.h" #include "llrender.h" #include "llwindow.h" // decBusyCount() @@ -47,20 +40,27 @@ #include "llviewerwindow.h" #include "llnetmap.h" #include "llagent.h" +#include "llagentcamera.h" #include "pipeline.h" #include "llspatialpartition.h" #include "lltooltip.h" #include "llworld.h" #include "llstring.h" -#include "llhudtext.h" +#include "llhudicon.h" +#include "llhudnametag.h" #include "lldrawable.h" +#include "llflexibleobject.h" +#include "llviewertextureanim.h" #include "xform.h" #include "llsky.h" #include "llviewercamera.h" #include "llselectmgr.h" #include "llresmgr.h" +#include "llsdutil.h" #include "llviewerregion.h" #include "llviewerstats.h" +#include "llviewerstatsrecorder.h" +#include "llvovolume.h" #include "llvoavatarself.h" #include "lltoolmgr.h" #include "lltoolpie.h" @@ -68,7 +68,7 @@ #include "u64.h" #include "llviewertexturelist.h" #include "lldatapacker.h" -#ifdef LL_STANDALONE +#ifdef LL_USESYSTEMLIBS #include <zlib.h> #else #include "zlib/zlib.h" @@ -76,15 +76,15 @@ #include "object_flags.h" #include "llappviewer.h" +#include "llfloaterperms.h" +#include "llvocache.h" extern F32 gMinObjectDistance; extern BOOL gAnimateTextures; -void dialog_refresh_all(); +#define MAX_CONCURRENT_PHYSICS_REQUESTS 256 -#define CULL_VIS -//#define ORPHAN_SPAM -//#define IGNORE_DEAD +void dialog_refresh_all(); // Global lists of objects - should go away soon. LLViewerObjectList gObjectList; @@ -93,13 +93,11 @@ extern LLPipeline gPipeline; // Statics for object lookup tables. U32 LLViewerObjectList::sSimulatorMachineIndex = 1; // Not zero deliberately, to speed up index check. -LLMap<U64, U32> LLViewerObjectList::sIPAndPortToIndex; +std::map<U64, U32> LLViewerObjectList::sIPAndPortToIndex; std::map<U64, LLUUID> LLViewerObjectList::sIndexAndLocalIDToUUID; LLViewerObjectList::LLViewerObjectList() { - mNumVisCulled = 0; - mNumSizeCulled = 0; mCurLazyUpdateIndex = 0; mCurBin = 0; mNumDeadObjects = 0; @@ -107,7 +105,6 @@ LLViewerObjectList::LLViewerObjectList() mNumNewObjects = 0; mWasPaused = FALSE; mNumDeadObjectUpdates = 0; - mNumUnknownKills = 0; mNumUnknownUpdates = 0; } @@ -164,18 +161,17 @@ U64 LLViewerObjectList::getIndex(const U32 local_id, return (((U64)index) << 32) | (U64)local_id; } -BOOL LLViewerObjectList::removeFromLocalIDTable(const LLViewerObject &object) +BOOL LLViewerObjectList::removeFromLocalIDTable(const LLViewerObject* objectp) { - if(object.getRegion()) + if(objectp && objectp->getRegion()) { - U32 local_id = object.mLocalID; - LLHost region_host = object.getRegion()->getHost(); - U32 ip = region_host.getAddress(); - U32 port = region_host.getPort(); + U32 local_id = objectp->mLocalID; + U32 ip = objectp->getRegion()->getHost().getAddress(); + U32 port = objectp->getRegion()->getHost().getPort(); U64 ipport = (((U64)ip) << 32) | (U64)port; U32 index = sIPAndPortToIndex[ipport]; - // llinfos << "Removing object from table, local ID " << local_id << ", ip " << ip << ":" << port << llendl; + // LL_INFOS() << "Removing object from table, local ID " << local_id << ", ip " << ip << ":" << port << LL_ENDL; U64 indexid = (((U64)index) << 32) | (U64)local_id; @@ -186,14 +182,14 @@ BOOL LLViewerObjectList::removeFromLocalIDTable(const LLViewerObject &object) } // Found existing entry - if (iter->second == object.getID()) + if (iter->second == objectp->getID()) { // Full UUIDs match, so remove the entry sIndexAndLocalIDToUUID.erase(iter); return TRUE; } // UUIDs did not match - this would zap a valid entry, so don't erase it - //llinfos << "Tried to erase entry where id in table (" - // << iter->second << ") did not match object " << object.getID() << llendl; + //LL_INFOS() << "Tried to erase entry where id in table (" + // << iter->second << ") did not match object " << object.getID() << LL_ENDL; } return FALSE ; @@ -218,8 +214,8 @@ void LLViewerObjectList::setUUIDAndLocal(const LLUUID &id, sIndexAndLocalIDToUUID[indexid] = id; - //llinfos << "Adding object to table, full ID " << id - // << ", local ID " << local_id << ", ip " << ip << ":" << port << llendl; + //LL_INFOS() << "Adding object to table, full ID " << id + // << ", local ID " << local_id << ", ip " << ip << ":" << port << LL_ENDL; } S32 gFullObjectUpdates = 0; @@ -230,10 +226,15 @@ void LLViewerObjectList::processUpdateCore(LLViewerObject* objectp, U32 i, const EObjectUpdateType update_type, LLDataPacker* dpp, - BOOL just_created) + bool just_created, + bool from_cache) { - LLMemType mt(LLMemType::MTYPE_OBJECT_PROCESS_UPDATE_CORE); - LLMessageSystem* msg = gMessageSystem; + LLMessageSystem* msg = NULL; + + if(!from_cache) + { + msg = gMessageSystem; + } // ignore returned flags objectp->processUpdateMessage(msg, user_data, i, update_type, dpp); @@ -257,7 +258,18 @@ void LLViewerObjectList::processUpdateCore(LLViewerObject* objectp, // RN: this must be called after we have a drawable // (from gPipeline.addObject) // so that the drawable parent is set properly + if(msg != NULL) + { findOrphans(objectp, msg->getSenderIP(), msg->getSenderPort()); + } + else + { + LLViewerRegion* regionp = objectp->getRegion(); + if(regionp != NULL) + { + findOrphans(objectp, regionp->getHost().getAddress(), regionp->getHost().getPort()); + } + } // If we're just wandering around, don't create new objects selected. if (just_created @@ -266,8 +278,8 @@ void LLViewerObjectList::processUpdateCore(LLViewerObject* objectp, { if ( LLToolMgr::getInstance()->getCurrentTool() != LLToolPie::getInstance() ) { - // llinfos << "DEBUG selecting " << objectp->mID << " " - // << objectp->mLocalID << llendl; + // LL_INFOS() << "DEBUG selecting " << objectp->mID << " " + // << objectp->mLocalID << LL_ENDL; LLSelectMgr::getInstance()->selectObjectAndFamily(objectp); dialog_refresh_all(); } @@ -278,17 +290,105 @@ void LLViewerObjectList::processUpdateCore(LLViewerObject* objectp, } } -static LLFastTimer::DeclareTimer FTM_PROCESS_OBJECTS("Process Objects"); +static LLTrace::BlockTimerStatHandle FTM_PROCESS_OBJECTS("Process Objects"); + +LLViewerObject* LLViewerObjectList::processObjectUpdateFromCache(LLVOCacheEntry* entry, LLViewerRegion* regionp) +{ + LLDataPacker *cached_dpp = entry->getDP(); + + if (!cached_dpp) + { + return NULL; //nothing cached. + } + + LLViewerObject *objectp; + U32 local_id; + LLPCode pcode = 0; + LLUUID fullid; + LLViewerStatsRecorder& recorder = LLViewerStatsRecorder::instance(); + + // Cache Hit. + record(LLStatViewer::OBJECT_CACHE_HIT_RATE, LLUnits::Ratio::fromValue(1)); + + cached_dpp->reset(); + cached_dpp->unpackUUID(fullid, "ID"); + cached_dpp->unpackU32(local_id, "LocalID"); + cached_dpp->unpackU8(pcode, "PCode"); + + objectp = findObject(fullid); + + if (objectp) + { + if(!objectp->isDead() && (objectp->mLocalID != entry->getLocalID() || + objectp->getRegion() != regionp)) + { + removeFromLocalIDTable(objectp); + setUUIDAndLocal(fullid, entry->getLocalID(), + regionp->getHost().getAddress(), + regionp->getHost().getPort()); + + if (objectp->mLocalID != entry->getLocalID()) + { // Update local ID in object with the one sent from the region + objectp->mLocalID = entry->getLocalID(); + } + + if (objectp->getRegion() != regionp) + { // Object changed region, so update it + objectp->updateRegion(regionp); // for LLVOAvatar + } + } + else + { + //should fall through if already loaded because may need to update the object. + //return objectp; //already loaded. + } + } + + bool justCreated = false; + if (!objectp) + { + objectp = createObjectFromCache(pcode, regionp, fullid, entry->getLocalID()); + + if (!objectp) + { + LL_INFOS() << "createObject failure for object: " << fullid << LL_ENDL; + recorder.objectUpdateFailure(entry->getLocalID(), OUT_FULL_CACHED, 0); + return NULL; + } + justCreated = true; + mNumNewObjects++; + } + + if (objectp->isDead()) + { + LL_WARNS() << "Dead object " << objectp->mID << " in UUID map 1!" << LL_ENDL; + } + + processUpdateCore(objectp, NULL, 0, OUT_FULL_CACHED, cached_dpp, justCreated, true); + objectp->loadFlags(entry->getUpdateFlags()); //just in case, reload update flags from cache. + + if(entry->getHitCount() > 0) + { + objectp->setLastUpdateType(OUT_FULL_CACHED); + } + else + { + objectp->setLastUpdateType(OUT_FULL_COMPRESSED); //newly cached + objectp->setLastUpdateCached(TRUE); + } + recorder.log(0.2f); + LLVOAvatar::cullAvatarsByPixelArea(); + + return objectp; +} void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, void **user_data, const EObjectUpdateType update_type, - bool cached, bool compressed) + bool compressed) { - LLMemType mt(LLMemType::MTYPE_OBJECT_PROCESS_UPDATE); - LLFastTimer t(FTM_PROCESS_OBJECTS); + LL_RECORD_BLOCK_TIME(FTM_PROCESS_OBJECTS); - LLVector3d camera_global = gAgent.getCameraPositionGlobal(); LLViewerObject *objectp; S32 num_objects; U32 local_id; @@ -302,9 +402,12 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, // have to transform to absolute coordinates. num_objects = mesgsys->getNumberOfBlocksFast(_PREHASH_ObjectData); - if (!cached && !compressed && update_type != OUT_FULL) + // I don't think this case is ever hit. TODO* Test this. + if (!compressed && update_type != OUT_FULL) { + //LL_INFOS() << "TEST: !cached && !compressed && update_type != OUT_FULL" << LL_ENDL; gTerseObjectUpdates += num_objects; + /* S32 size; if (mesgsys->getReceiveCompressedSize()) { @@ -314,10 +417,12 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, { size = mesgsys->getReceiveSize(); } - // llinfos << "Received terse " << num_objects << " in " << size << " byte (" << size/num_objects << ")" << llendl; + LL_INFOS() << "Received terse " << num_objects << " in " << size << " byte (" << size/num_objects << ")" << LL_ENDL; + */ } else { + /* S32 size; if (mesgsys->getReceiveCompressedSize()) { @@ -328,88 +433,63 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, size = mesgsys->getReceiveSize(); } - // llinfos << "Received " << num_objects << " in " << size << " byte (" << size/num_objects << ")" << llendl; + LL_INFOS() << "Received " << num_objects << " in " << size << " byte (" << size/num_objects << ")" << LL_ENDL; + */ gFullObjectUpdates += num_objects; } U64 region_handle; mesgsys->getU64Fast(_PREHASH_RegionData, _PREHASH_RegionHandle, region_handle); + LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(region_handle); if (!regionp) { - llwarns << "Object update from unknown region! " << region_handle << llendl; + LL_WARNS() << "Object update from unknown region! " << region_handle << LL_ENDL; return; } U8 compressed_dpbuffer[2048]; LLDataPackerBinaryBuffer compressed_dp(compressed_dpbuffer, 2048); - LLDataPacker *cached_dpp = NULL; - + LLViewerStatsRecorder& recorder = LLViewerStatsRecorder::instance(); + for (i = 0; i < num_objects; i++) { + // timer is unused? LLTimer update_timer; BOOL justCreated = FALSE; + S32 msg_size = 0; + bool update_cache = false; //update object cache if it is a full-update or terse update - if (cached) - { - U32 id; - U32 crc; - mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, id, i); - mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_CRC, crc, i); - - // Lookup data packer and add this id to cache miss lists if necessary. - cached_dpp = regionp->getDP(id, crc); - if (cached_dpp) - { - cached_dpp->reset(); - cached_dpp->unpackUUID(fullid, "ID"); - cached_dpp->unpackU32(local_id, "LocalID"); - cached_dpp->unpackU8(pcode, "PCode"); - } - else - { - continue; // no data packer, skip this object - } - } - else if (compressed) + if (compressed) { - U8 compbuffer[2048]; S32 uncompressed_length = 2048; - S32 compressed_length; compressed_dp.reset(); - U32 flags = 0; - if (update_type != OUT_TERSE_IMPROVED) + uncompressed_length = mesgsys->getSizeFast(_PREHASH_ObjectData, i, _PREHASH_Data); + mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_Data, compressed_dpbuffer, 0, i); + compressed_dp.assignBuffer(compressed_dpbuffer, uncompressed_length); + + if (update_type != OUT_TERSE_IMPROVED) // OUT_FULL_COMPRESSED only? { + U32 flags = 0; mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, i); - } - if (flags & FLAGS_ZLIB_COMPRESSED) - { - compressed_length = mesgsys->getSizeFast(_PREHASH_ObjectData, i, _PREHASH_Data); - mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_Data, compbuffer, 0, i); - uncompressed_length = 2048; - uncompress(compressed_dpbuffer, (unsigned long *)&uncompressed_length, - compbuffer, compressed_length); - compressed_dp.assignBuffer(compressed_dpbuffer, uncompressed_length); - } - else - { - uncompressed_length = mesgsys->getSizeFast(_PREHASH_ObjectData, i, _PREHASH_Data); - mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_Data, compressed_dpbuffer, 0, i); - compressed_dp.assignBuffer(compressed_dpbuffer, uncompressed_length); - } - - - if (update_type != OUT_TERSE_IMPROVED) - { + if(flags & FLAGS_TEMPORARY_ON_REZ) + { compressed_dp.unpackUUID(fullid, "ID"); compressed_dp.unpackU32(local_id, "LocalID"); compressed_dp.unpackU8(pcode, "PCode"); } - else + else //send to object cache + { + regionp->cacheFullUpdate(compressed_dp, flags); + continue; + } + } + else //OUT_TERSE_IMPROVED { + update_cache = true; compressed_dp.unpackU32(local_id, "LocalID"); getUUIDFromLocal(fullid, local_id, @@ -417,32 +497,42 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, gMessageSystem->getSenderPort()); if (fullid.isNull()) { - // llwarns << "update for unknown localid " << local_id << " host " << gMessageSystem->getSender() << ":" << gMessageSystem->getSenderPort() << llendl; + // LL_WARNS() << "update for unknown localid " << local_id << " host " << gMessageSystem->getSender() << ":" << gMessageSystem->getSenderPort() << LL_ENDL; mNumUnknownUpdates++; } } } - else if (update_type != OUT_FULL) + else if (update_type != OUT_FULL) // !compressed, !OUT_FULL ==> OUT_FULL_CACHED only? { mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, local_id, i); + msg_size += sizeof(U32); + getUUIDFromLocal(fullid, local_id, gMessageSystem->getSenderIP(), gMessageSystem->getSenderPort()); if (fullid.isNull()) { - // llwarns << "update for unknown localid " << local_id << " host " << gMessageSystem->getSender() << llendl; + // LL_WARNS() << "update for unknown localid " << local_id << " host " << gMessageSystem->getSender() << LL_ENDL; mNumUnknownUpdates++; } } - else + else // OUT_FULL only? { + update_cache = true; mesgsys->getUUIDFast(_PREHASH_ObjectData, _PREHASH_FullID, fullid, i); mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, local_id, i); - // llinfos << "Full Update, obj " << local_id << ", global ID" << fullid << "from " << mesgsys->getSender() << llendl; + msg_size += sizeof(LLUUID); + msg_size += sizeof(U32); + // LL_INFOS() << "Full Update, obj " << local_id << ", global ID" << fullid << "from " << mesgsys->getSender() << LL_ENDL; } objectp = findObject(fullid); + if(update_cache) + { + objectp = regionp->updateCacheEntry(local_id, objectp, update_type); + } + // This looks like it will break if the local_id of the object doesn't change // upon boundary crossing, but we check for region id matching later... // Reset object local id and region pointer if things have changed @@ -452,28 +542,27 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, { //if (objectp->getRegion()) //{ - // llinfos << "Local ID change: Removing object from table, local ID " << objectp->mLocalID + // LL_INFOS() << "Local ID change: Removing object from table, local ID " << objectp->mLocalID // << ", id from message " << local_id << ", from " // << LLHost(objectp->getRegion()->getHost().getAddress(), objectp->getRegion()->getHost().getPort()) // << ", full id " << fullid // << ", objects id " << objectp->getID() // << ", regionp " << (U32) regionp << ", object region " << (U32) objectp->getRegion() - // << llendl; + // << LL_ENDL; //} - removeFromLocalIDTable(*objectp); + removeFromLocalIDTable(objectp); setUUIDAndLocal(fullid, local_id, gMessageSystem->getSenderIP(), gMessageSystem->getSenderPort()); if (objectp->mLocalID != local_id) - { // Update local ID in object with the one sent from the region + { // Update local ID in object with the one sent from the region objectp->mLocalID = local_id; } if (objectp->getRegion() != regionp) - { // Object changed region, so update it - objectp->setRegion(regionp); + { // Object changed region, so update it objectp->updateRegion(regionp); // for LLVOAvatar } } @@ -484,28 +573,30 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, { if (update_type == OUT_TERSE_IMPROVED) { - // llinfos << "terse update for an unknown object:" << fullid << llendl; + // LL_INFOS() << "terse update for an unknown object (compressed):" << fullid << LL_ENDL; + recorder.objectUpdateFailure(local_id, update_type, msg_size); continue; } } - else if (cached) - { - } else { if (update_type != OUT_FULL) { - // llinfos << "terse update for an unknown object:" << fullid << llendl; + //LL_INFOS() << "terse update for an unknown object:" << fullid << LL_ENDL; + recorder.objectUpdateFailure(local_id, update_type, msg_size); continue; } mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_PCode, pcode, i); + msg_size += sizeof(U8); + } #ifdef IGNORE_DEAD if (mDeadObjects.find(fullid) != mDeadObjects.end()) { mNumDeadObjectUpdates++; - // llinfos << "update for a dead object:" << fullid << llendl; + //LL_INFOS() << "update for a dead object:" << fullid << LL_ENDL; + recorder.objectUpdateFailure(local_id, update_type, msg_size); continue; } #endif @@ -513,34 +604,43 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, objectp = createObject(pcode, regionp, fullid, local_id, gMessageSystem->getSender()); if (!objectp) { + LL_INFOS() << "createObject failure for object: " << fullid << LL_ENDL; + recorder.objectUpdateFailure(local_id, update_type, msg_size); continue; } + justCreated = TRUE; mNumNewObjects++; } - if (objectp->isDead()) { - llwarns << "Dead object " << objectp->mID << " in UUID map 1!" << llendl; + LL_WARNS() << "Dead object " << objectp->mID << " in UUID map 1!" << LL_ENDL; } + //bool bCached = false; if (compressed) { - if (update_type != OUT_TERSE_IMPROVED) + if (update_type != OUT_TERSE_IMPROVED) // OUT_FULL_COMPRESSED only? { objectp->mLocalID = local_id; } processUpdateCore(objectp, user_data, i, update_type, &compressed_dp, justCreated); - if (update_type != OUT_TERSE_IMPROVED) + +#if 0 + if (update_type != OUT_TERSE_IMPROVED) // OUT_FULL_COMPRESSED only? { - objectp->mRegionp->cacheFullUpdate(objectp, compressed_dp); + U32 flags = 0; + mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, i); + + if(!(flags & FLAGS_TEMPORARY_ON_REZ)) + { + bCached = true; + LLViewerRegion::eCacheUpdateResult result = objectp->mRegionp->cacheFullUpdate(objectp, compressed_dp, flags); + recorder.cacheFullUpdate(local_id, update_type, result, objectp, msg_size); } } - else if (cached) - { - objectp->mLocalID = local_id; - processUpdateCore(objectp, user_data, i, update_type, cached_dpp, justCreated); +#endif } else { @@ -550,8 +650,12 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, } processUpdateCore(objectp, user_data, i, update_type, NULL, justCreated); } + recorder.objectUpdateEvent(local_id, update_type, objectp, msg_size); + objectp->setLastUpdateType(update_type); } + recorder.log(0.2f); + LLVOAvatar::cullAvatarsByPixelArea(); } @@ -559,22 +663,59 @@ void LLViewerObjectList::processCompressedObjectUpdate(LLMessageSystem *mesgsys, void **user_data, const EObjectUpdateType update_type) { - processObjectUpdate(mesgsys, user_data, update_type, false, true); + processObjectUpdate(mesgsys, user_data, update_type, true); } void LLViewerObjectList::processCachedObjectUpdate(LLMessageSystem *mesgsys, void **user_data, const EObjectUpdateType update_type) { - processObjectUpdate(mesgsys, user_data, update_type, true, false); + //processObjectUpdate(mesgsys, user_data, update_type, true, false); + + S32 num_objects = mesgsys->getNumberOfBlocksFast(_PREHASH_ObjectData); + gFullObjectUpdates += num_objects; + + U64 region_handle; + mesgsys->getU64Fast(_PREHASH_RegionData, _PREHASH_RegionHandle, region_handle); + LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(region_handle); + if (!regionp) + { + LL_WARNS() << "Object update from unknown region! " << region_handle << LL_ENDL; + return; + } + + LLViewerStatsRecorder& recorder = LLViewerStatsRecorder::instance(); + + for (S32 i = 0; i < num_objects; i++) + { + S32 msg_size = 0; + U32 id; + U32 crc; + U32 flags; + mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, id, i); + mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_CRC, crc, i); + mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, i); + msg_size += sizeof(U32) * 2; + + // Lookup data packer and add this id to cache miss lists if necessary. + U8 cache_miss_type = LLViewerRegion::CACHE_MISS_TYPE_NONE; + if(!regionp->probeCache(id, crc, flags, cache_miss_type)) + { + // Cache Miss. + recorder.cacheMissEvent(id, update_type, cache_miss_type, msg_size); + + continue; // no data packer, skip this object + } + } + + return; } void LLViewerObjectList::dirtyAllObjectInventory() { - S32 count = mObjects.count(); - for(S32 i = 0; i < count; ++i) + for (vobj_list_t::iterator iter = mObjects.begin(); iter != mObjects.end(); ++iter) { - mObjects[i]->dirtyInventory(); + (*iter)->dirtyInventory(); } } @@ -587,35 +728,32 @@ void LLViewerObjectList::updateApparentAngles(LLAgent &agent) S32 num_updates, max_value; if (NUM_BINS - 1 == mCurBin) { - num_updates = mObjects.count() - mCurLazyUpdateIndex; - max_value = mObjects.count(); + num_updates = (S32) mObjects.size() - mCurLazyUpdateIndex; + max_value = (S32) mObjects.size(); gTextureList.setUpdateStats(TRUE); } else { - num_updates = (mObjects.count() / NUM_BINS) + 1; - max_value = llmin(mObjects.count(), mCurLazyUpdateIndex + num_updates); + num_updates = ((S32) mObjects.size() / NUM_BINS) + 1; + max_value = llmin((S32) mObjects.size(), mCurLazyUpdateIndex + num_updates); } - if (!gNoRender) + // Slam priorities for textures that we care about (hovered, selected, and focused) + // Hovered + // Assumes only one level deep of parenting + LLSelectNode* nodep = LLSelectMgr::instance().getHoverNode(); + if (nodep) { - // Slam priorities for textures that we care about (hovered, selected, and focused) - // Hovered - // Assumes only one level deep of parenting - LLSelectNode* nodep = LLSelectMgr::instance().getHoverNode(); - if (nodep) + objectp = nodep->getObject(); + if (objectp) { - objectp = nodep->getObject(); - if (objectp) - { - objectp->boostTexturePriority(); - } + objectp->boostTexturePriority(); } } // Focused - objectp = gAgent.getFocusObject(); + objectp = gAgentCamera.getFocusObject(); if (objectp) { objectp->boostTexturePriority(); @@ -642,12 +780,12 @@ void LLViewerObjectList::updateApparentAngles(LLAgent &agent) // Update distance & gpw objectp->setPixelAreaAndAngle(agent); // Also sets the approx. pixel area - objectp->updateTextures(agent); // Update the image levels of textures for this object. + objectp->updateTextures(); // Update the image levels of textures for this object. } } mCurLazyUpdateIndex = max_value; - if (mCurLazyUpdateIndex == mObjects.count()) + if (mCurLazyUpdateIndex == mObjects.size()) { mCurLazyUpdateIndex = 0; } @@ -657,25 +795,223 @@ void LLViewerObjectList::updateApparentAngles(LLAgent &agent) LLVOAvatar::cullAvatarsByPixelArea(); } +class LLObjectCostResponder : public LLCurl::Responder +{ + LOG_CLASS(LLObjectCostResponder); +public: + LLObjectCostResponder(const LLSD& object_ids) + : mObjectIDs(object_ids) + { + } + + // Clear's the global object list's pending + // request list for all objects requested + void clear_object_list_pending_requests() + { + // TODO*: No more hard coding + for ( + LLSD::array_iterator iter = mObjectIDs.beginArray(); + iter != mObjectIDs.endArray(); + ++iter) + { + gObjectList.onObjectCostFetchFailure(iter->asUUID()); + } + } + +private: + /* virtual */ void httpFailure() + { + LL_WARNS() << dumpResponse() << LL_ENDL; + + // TODO*: Error message to user + // For now just clear the request from the pending list + clear_object_list_pending_requests(); + } + + /* virtual */ void httpSuccess() + { + const LLSD& content = getContent(); + if ( !content.isMap() || content.has("error") ) + { + // Improper response or the request had an error, + // show an error to the user? + LL_WARNS() + << "Application level error when fetching object " + << "cost. Message: " << content["error"]["message"].asString() + << ", identifier: " << content["error"]["identifier"].asString() + << LL_ENDL; + + // TODO*: Adaptively adjust request size if the + // service says we've requested too many and retry + + // TODO*: Error message if not retrying + clear_object_list_pending_requests(); + return; + } + + // Success, grab the resource cost and linked set costs + // for an object if one was returned + for ( + LLSD::array_iterator iter = mObjectIDs.beginArray(); + iter != mObjectIDs.endArray(); + ++iter) + { + LLUUID object_id = iter->asUUID(); + + // Check to see if the request contains data for the object + if ( content.has(iter->asString()) ) + { + F32 link_cost = + content[iter->asString()]["linked_set_resource_cost"].asReal(); + F32 object_cost = + content[iter->asString()]["resource_cost"].asReal(); + + F32 physics_cost = content[iter->asString()]["physics_cost"].asReal(); + F32 link_physics_cost = content[iter->asString()]["linked_set_physics_cost"].asReal(); + + gObjectList.updateObjectCost(object_id, object_cost, link_cost, physics_cost, link_physics_cost); + } + else + { + // TODO*: Give user feedback about the missing data? + gObjectList.onObjectCostFetchFailure(object_id); + } + } + } + +private: + LLSD mObjectIDs; +}; + + +class LLPhysicsFlagsResponder : public LLCurl::Responder +{ + LOG_CLASS(LLPhysicsFlagsResponder); +public: + LLPhysicsFlagsResponder(const LLSD& object_ids) + : mObjectIDs(object_ids) + { + } + + // Clear's the global object list's pending + // request list for all objects requested + void clear_object_list_pending_requests() + { + // TODO*: No more hard coding + for ( + LLSD::array_iterator iter = mObjectIDs.beginArray(); + iter != mObjectIDs.endArray(); + ++iter) + { + gObjectList.onPhysicsFlagsFetchFailure(iter->asUUID()); + } + } + +private: + /* virtual */ void httpFailure() + { + LL_WARNS() << dumpResponse() << LL_ENDL; + + // TODO*: Error message to user + // For now just clear the request from the pending list + clear_object_list_pending_requests(); + } + + /* virtual void */ void httpSuccess() + { + const LLSD& content = getContent(); + if ( !content.isMap() || content.has("error") ) + { + // Improper response or the request had an error, + // show an error to the user? + LL_WARNS() + << "Application level error when fetching object " + << "physics flags. Message: " << content["error"]["message"].asString() + << ", identifier: " << content["error"]["identifier"].asString() + << LL_ENDL; + + // TODO*: Adaptively adjust request size if the + // service says we've requested too many and retry + + // TODO*: Error message if not retrying + clear_object_list_pending_requests(); + return; + } + + // Success, grab the resource cost and linked set costs + // for an object if one was returned + for ( + LLSD::array_iterator iter = mObjectIDs.beginArray(); + iter != mObjectIDs.endArray(); + ++iter) + { + LLUUID object_id = iter->asUUID(); + + // Check to see if the request contains data for the object + if ( content.has(iter->asString()) ) + { + const LLSD& data = content[iter->asString()]; + + S32 shape_type = data["PhysicsShapeType"].asInteger(); + + gObjectList.updatePhysicsShapeType(object_id, shape_type); -void LLViewerObjectList::update(LLAgent &agent, LLWorld &world) + if (data.has("Density")) + { + F32 density = data["Density"].asReal(); + F32 friction = data["Friction"].asReal(); + F32 restitution = data["Restitution"].asReal(); + F32 gravity_multiplier = data["GravityMultiplier"].asReal(); + + gObjectList.updatePhysicsProperties(object_id, + density, friction, restitution, gravity_multiplier); + } + } + else + { + // TODO*: Give user feedback about the missing data? + gObjectList.onPhysicsFlagsFetchFailure(object_id); + } + } + } + +private: + LLSD mObjectIDs; +}; + +static LLTrace::BlockTimerStatHandle FTM_IDLE_COPY("Idle Copy"); + +void LLViewerObjectList::update(LLAgent &agent) { - LLMemType mt(LLMemType::MTYPE_OBJECT); // Update globals - gVelocityInterpolate = gSavedSettings.getBOOL("VelocityInterpolate"); - gPingInterpolate = gSavedSettings.getBOOL("PingInterpolate"); + LLViewerObject::setVelocityInterpolate( gSavedSettings.getBOOL("VelocityInterpolate") ); + LLViewerObject::setPingInterpolate( gSavedSettings.getBOOL("PingInterpolate") ); + + F32 interp_time = gSavedSettings.getF32("InterpolationTime"); + F32 phase_out_time = gSavedSettings.getF32("InterpolationPhaseOut"); + if (interp_time < 0.0 || + phase_out_time < 0.0 || + phase_out_time > interp_time) + { + LL_WARNS() << "Invalid values for InterpolationTime or InterpolationPhaseOut, resetting to defaults" << LL_ENDL; + interp_time = 3.0f; + phase_out_time = 1.0f; + } + LLViewerObject::setPhaseOutUpdateInterpolationTime( interp_time ); + LLViewerObject::setMaxUpdateInterpolationTime( phase_out_time ); + gAnimateTextures = gSavedSettings.getBOOL("AnimateTextures"); // update global timer F32 last_time = gFrameTimeSeconds; - U64 time = totalTime(); // this will become the new gFrameTime when the update is done + U64Microseconds time = totalTime(); // this will become the new gFrameTime when the update is done // Time _can_ go backwards, for example if the user changes the system clock. // It doesn't cause any fatal problems (just some oddness with stats), so we shouldn't assert here. // llassert(time > gFrameTime); - F64 time_diff = U64_to_F64(time - gFrameTime)/(F64)SEC_TO_MICROSEC; - gFrameTime = time; - F64 time_since_start = U64_to_F64(gFrameTime - gStartTime)/(F64)SEC_TO_MICROSEC; - gFrameTimeSeconds = (F32)time_since_start; + F64Seconds time_diff = time - gFrameTime; + gFrameTime = time; + F64Seconds time_since_start = gFrameTime - gStartTime; + gFrameTimeSeconds = time_since_start; gFrameIntervalSeconds = gFrameTimeSeconds - last_time; if (gFrameIntervalSeconds < 0.f) @@ -688,68 +1024,82 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world) const F64 frame_time = LLFrameTimer::getElapsedSeconds(); - std::vector<LLViewerObject*> kill_list; - S32 num_active_objects = 0; LLViewerObject *objectp = NULL; // Make a copy of the list in case something in idleUpdate() messes with it - std::vector<LLViewerObject*> idle_list; - idle_list.reserve( mActiveObjects.size() ); + static std::vector<LLViewerObject*> idle_list; - for (std::set<LLPointer<LLViewerObject> >::iterator active_iter = mActiveObjects.begin(); - active_iter != mActiveObjects.end(); active_iter++) + U32 idle_count = 0; + { - objectp = *active_iter; - if (objectp) + LL_RECORD_BLOCK_TIME(FTM_IDLE_COPY); + + for (std::vector<LLPointer<LLViewerObject> >::iterator active_iter = mActiveObjects.begin(); + active_iter != mActiveObjects.end(); active_iter++) { - idle_list.push_back( objectp ); - } - else - { // There shouldn't be any NULL pointers in the list, but they have caused - // crashes before. This may be idleUpdate() messing with the list. - llwarns << "LLViewerObjectList::update has a NULL objectp" << llendl; + objectp = *active_iter; + if (objectp) + { + if (idle_count >= idle_list.size()) + { + idle_list.push_back( objectp ); + } + else + { + idle_list[idle_count] = objectp; + } + ++idle_count; + } + else + { // There shouldn't be any NULL pointers in the list, but they have caused + // crashes before. This may be idleUpdate() messing with the list. + LL_WARNS() << "LLViewerObjectList::update has a NULL objectp" << LL_ENDL; + } } } + std::vector<LLViewerObject*>::iterator idle_end = idle_list.begin()+idle_count; + if (gSavedSettings.getBOOL("FreezeTime")) { + for (std::vector<LLViewerObject*>::iterator iter = idle_list.begin(); - iter != idle_list.end(); iter++) + iter != idle_end; iter++) { objectp = *iter; - if (objectp->getPCode() == LLViewerObject::LL_VO_CLOUDS || - objectp->isAvatar()) + if (objectp->isAvatar()) { - objectp->idleUpdate(agent, world, frame_time); + objectp->idleUpdate(agent, frame_time); } } } else { for (std::vector<LLViewerObject*>::iterator idle_iter = idle_list.begin(); - idle_iter != idle_list.end(); idle_iter++) + idle_iter != idle_end; idle_iter++) { objectp = *idle_iter; - if (!objectp->idleUpdate(agent, world, frame_time)) - { - // If Idle Update returns false, kill object! - kill_list.push_back(objectp); - } - else - { - num_active_objects++; - } + llassert(objectp->isActive()); + objectp->idleUpdate(agent, frame_time); } - for (std::vector<LLViewerObject*>::iterator kill_iter = kill_list.begin(); - kill_iter != kill_list.end(); kill_iter++) + + //update flexible objects + LLVolumeImplFlexible::updateClass(); + + //update animated textures + if (gAnimateTextures) { - objectp = *kill_iter; - killObject(objectp); + LLViewerTextureAnim::updateClass(); } } - mNumSizeCulled = 0; - mNumVisCulled = 0; + + + fetchObjectCosts(); + fetchPhysicsFlags(); + + // update max computed render cost + LLVOVolume::updateRenderComplexity(); // compute all sorts of time-based stats // don't factor frames that were paused into the stats @@ -761,7 +1111,7 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world) /* // Debugging code for viewing orphans, and orphaned parents LLUUID id; - for (i = 0; i < mOrphanParents.count(); i++) + for (i = 0; i < mOrphanParents.size(); i++) { id = sIndexAndLocalIDToUUID[mOrphanParents[i]]; LLViewerObject *objectp = findObject(id); @@ -769,7 +1119,7 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world) { std::string id_str; objectp->mID.toString(id_str); - std::string tmpstr = std::string("Par: ") + id_str; + std::string tmpstr = std::string("Par: ") + id_str; addDebugBeacon(objectp->getPositionAgent(), tmpstr, LLColor4(1.f,0.f,0.f,1.f), @@ -778,7 +1128,7 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world) } LLColor4 text_color; - for (i = 0; i < mOrphanChildren.count(); i++) + for (i = 0; i < mOrphanChildren.size(); i++) { OrphanInfo oi = mOrphanChildren[i]; LLViewerObject *objectp = findObject(oi.mChildInfo); @@ -789,12 +1139,12 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world) std::string tmpstr; if (objectp->getParent()) { - tmpstr = std::string("ChP: ") + id_str; + tmpstr = std::string("ChP: ") + id_str; text_color = LLColor4(0.f, 1.f, 0.f, 1.f); } else { - tmpstr = std::string("ChNoP: ") + id_str; + tmpstr = std::string("ChNoP: ") + id_str; text_color = LLColor4(1.f, 0.f, 0.f, 1.f); } id = sIndexAndLocalIDToUUID[oi.mParentInfo]; @@ -807,31 +1157,146 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world) } */ - LLViewerStats::getInstance()->mNumObjectsStat.addValue(mObjects.count()); - LLViewerStats::getInstance()->mNumActiveObjectsStat.addValue(num_active_objects); - LLViewerStats::getInstance()->mNumSizeCulledStat.addValue(mNumSizeCulled); - LLViewerStats::getInstance()->mNumVisCulledStat.addValue(mNumVisCulled); + sample(LLStatViewer::NUM_OBJECTS, mObjects.size()); + sample(LLStatViewer::NUM_ACTIVE_OBJECTS, idle_count); } +void LLViewerObjectList::fetchObjectCosts() +{ + // issue http request for stale object physics costs + if (!mStaleObjectCost.empty()) + { + LLViewerRegion* regionp = gAgent.getRegion(); + + if (regionp) + { + std::string url = regionp->getCapability("GetObjectCost"); + + if (!url.empty()) + { + LLSD id_list; + U32 object_index = 0; + + for ( + std::set<LLUUID>::iterator iter = mStaleObjectCost.begin(); + iter != mStaleObjectCost.end(); + ) + { + // Check to see if a request for this object + // has already been made. + if ( mPendingObjectCost.find(*iter) == + mPendingObjectCost.end() ) + { + mPendingObjectCost.insert(*iter); + id_list[object_index++] = *iter; + } + + mStaleObjectCost.erase(iter++); + + if (object_index >= MAX_CONCURRENT_PHYSICS_REQUESTS) + { + break; + } + } + + if ( id_list.size() > 0 ) + { + LLSD post_data = LLSD::emptyMap(); + + post_data["object_ids"] = id_list; + LLHTTPClient::post( + url, + post_data, + new LLObjectCostResponder(id_list)); + } + } + else + { + mStaleObjectCost.clear(); + mPendingObjectCost.clear(); + } + } + } +} + +void LLViewerObjectList::fetchPhysicsFlags() +{ + // issue http request for stale object physics flags + if (!mStalePhysicsFlags.empty()) + { + LLViewerRegion* regionp = gAgent.getRegion(); + + if (regionp) + { + std::string url = regionp->getCapability("GetObjectPhysicsData"); + + if (!url.empty()) + { + LLSD id_list; + U32 object_index = 0; + + for ( + std::set<LLUUID>::iterator iter = mStalePhysicsFlags.begin(); + iter != mStalePhysicsFlags.end(); + ) + { + // Check to see if a request for this object + // has already been made. + if ( mPendingPhysicsFlags.find(*iter) == + mPendingPhysicsFlags.end() ) + { + mPendingPhysicsFlags.insert(*iter); + id_list[object_index++] = *iter; + } + + mStalePhysicsFlags.erase(iter++); + + if (object_index >= MAX_CONCURRENT_PHYSICS_REQUESTS) + { + break; + } + } + + if ( id_list.size() > 0 ) + { + LLSD post_data = LLSD::emptyMap(); + + post_data["object_ids"] = id_list; + LLHTTPClient::post( + url, + post_data, + new LLPhysicsFlagsResponder(id_list)); + } + } + else + { + mStalePhysicsFlags.clear(); + mPendingPhysicsFlags.clear(); + } + } + } +} + + void LLViewerObjectList::clearDebugText() { - for (S32 i = 0; i < mObjects.count(); i++) + for (vobj_list_t::iterator iter = mObjects.begin(); iter != mObjects.end(); ++iter) { - mObjects[i]->setDebugText(""); + (*iter)->setDebugText(""); } } void LLViewerObjectList::cleanupReferences(LLViewerObject *objectp) { - LLMemType mt(LLMemType::MTYPE_OBJECT); - if (mDeadObjects.count(objectp->mID)) + if (mDeadObjects.find(objectp->mID) != mDeadObjects.end()) { - llinfos << "Object " << objectp->mID << " already on dead list, ignoring cleanup!" << llendl; - return; + LL_INFOS() << "Object " << objectp->mID << " already on dead list!" << LL_ENDL; + } + else + { + mDeadObjects.insert(objectp->mID); } - - mDeadObjects.insert(std::pair<LLUUID, LLPointer<LLViewerObject> >(objectp->mID, objectp)); // Cleanup any references we have to this object // Remove from object map so noone can look it up. @@ -840,23 +1305,23 @@ void LLViewerObjectList::cleanupReferences(LLViewerObject *objectp) //if (objectp->getRegion()) //{ - // llinfos << "cleanupReferences removing object from table, local ID " << objectp->mLocalID << ", ip " + // LL_INFOS() << "cleanupReferences removing object from table, local ID " << objectp->mLocalID << ", ip " // << objectp->getRegion()->getHost().getAddress() << ":" - // << objectp->getRegion()->getHost().getPort() << llendl; + // << objectp->getRegion()->getHost().getPort() << LL_ENDL; //} - removeFromLocalIDTable(*objectp); + removeFromLocalIDTable(objectp); if (objectp->onActiveList()) { - //llinfos << "Removing " << objectp->mID << " " << objectp->getPCodeString() << " from active list in cleanupReferences." << llendl; + //LL_INFOS() << "Removing " << objectp->mID << " " << objectp->getPCodeString() << " from active list in cleanupReferences." << LL_ENDL; objectp->setOnActiveList(FALSE); - mActiveObjects.erase(objectp); + removeFromActiveList(objectp); } if (objectp->isOnMap()) { - mMapObjects.removeObj(objectp); + removeFromMap(objectp); } // Don't clean up mObject references, these will be cleaned up more efficiently later! @@ -866,8 +1331,12 @@ void LLViewerObjectList::cleanupReferences(LLViewerObject *objectp) mNumDeadObjects++; } +static LLTrace::BlockTimerStatHandle FTM_REMOVE_DRAWABLE("Remove Drawable"); + void LLViewerObjectList::removeDrawable(LLDrawable* drawablep) { + LL_RECORD_BLOCK_TIME(FTM_REMOVE_DRAWABLE); + if (!drawablep) { return; @@ -889,23 +1358,23 @@ void LLViewerObjectList::removeDrawable(LLDrawable* drawablep) BOOL LLViewerObjectList::killObject(LLViewerObject *objectp) { + // Don't ever kill gAgentAvatarp, just force it to the agent's region + // unless region is NULL which is assumed to mean you are logging out. + if ((objectp == gAgentAvatarp) && gAgent.getRegion()) + { + objectp->setRegion(gAgent.getRegion()); + return FALSE; + } + // When we're killing objects, all we do is mark them as dead. // We clean up the dead objects later. if (objectp) { - if (objectp->isDead()) - { - // This object is already dead. Don't need to do more. - return TRUE; - } - else - { - objectp->markDead(); - } - + objectp->markDead(); // does the right thing if object already dead return TRUE; } + return FALSE; } @@ -913,10 +1382,10 @@ void LLViewerObjectList::killObjects(LLViewerRegion *regionp) { LLViewerObject *objectp; - S32 i; - for (i = 0; i < mObjects.count(); i++) + + for (vobj_list_t::iterator iter = mObjects.begin(); iter != mObjects.end(); ++iter) { - objectp = mObjects[i]; + objectp = *iter; if (objectp->mRegionp == regionp) { @@ -933,31 +1402,31 @@ void LLViewerObjectList::killAllObjects() // Used only on global destruction. LLViewerObject *objectp; - for (S32 i = 0; i < mObjects.count(); i++) + for (vobj_list_t::iterator iter = mObjects.begin(); iter != mObjects.end(); ++iter) { - objectp = mObjects[i]; - + objectp = *iter; killObject(objectp); - llassert(objectp->isDead()); + // Object must be dead, or it's the LLVOAvatarSelf which never dies. + llassert((objectp == gAgentAvatarp) || objectp->isDead()); } cleanDeadObjects(FALSE); if(!mObjects.empty()) { - llwarns << "LLViewerObjectList::killAllObjects still has entries in mObjects: " << mObjects.count() << llendl; + LL_WARNS() << "LLViewerObjectList::killAllObjects still has entries in mObjects: " << mObjects.size() << LL_ENDL; mObjects.clear(); } if (!mActiveObjects.empty()) { - llwarns << "Some objects still on active object list!" << llendl; + LL_WARNS() << "Some objects still on active object list!" << LL_ENDL; mActiveObjects.clear(); } if (!mMapObjects.empty()) { - llwarns << "Some objects still on map object list!" << llendl; + LL_WARNS() << "Some objects still on map object list!" << LL_ENDL; mMapObjects.clear(); } } @@ -970,40 +1439,74 @@ void LLViewerObjectList::cleanDeadObjects(BOOL use_timer) return; } - S32 i = 0; S32 num_removed = 0; LLViewerObject *objectp; - while (i < mObjects.count()) + + vobj_list_t::reverse_iterator target = mObjects.rbegin(); + + vobj_list_t::iterator iter = mObjects.begin(); + for ( ; iter != mObjects.end(); ) { - // Scan for all of the dead objects and remove any "global" references to them. - objectp = mObjects[i]; + // Scan for all of the dead objects and put them all on the end of the list with no ref count ops + objectp = *iter; + if (objectp == NULL) + { //we caught up to the dead tail + break; + } + if (objectp->isDead()) { - mObjects.remove(i); + LLPointer<LLViewerObject>::swap(*iter, *target); + *target = NULL; + ++target; num_removed++; - if (num_removed == mNumDeadObjects) + if (num_removed == mNumDeadObjects || iter->isNull()) { - // We've cleaned up all of the dead objects. + // We've cleaned up all of the dead objects or caught up to the dead tail break; } } else { - // iterate, this isn't a dead object. - i++; + ++iter; } } + llassert(num_removed == mNumDeadObjects); + + //erase as a block + mObjects.erase(mObjects.begin()+(mObjects.size()-mNumDeadObjects), mObjects.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; } +void LLViewerObjectList::removeFromActiveList(LLViewerObject* objectp) +{ + S32 idx = objectp->getListIndex(); + if (idx != -1) + { //remove by moving last element to this object's position + llassert(mActiveObjects[idx] == objectp); + + objectp->setListIndex(-1); + + S32 last_index = mActiveObjects.size()-1; + + if (idx != last_index) + { + mActiveObjects[idx] = mActiveObjects[last_index]; + mActiveObjects[idx]->setListIndex(idx); + } + + mActiveObjects.pop_back(); + } +} + void LLViewerObjectList::updateActive(LLViewerObject *objectp) { - LLMemType mt(LLMemType::MTYPE_OBJECT); if (objectp->isDead()) { return; // We don't update dead objects! @@ -1014,20 +1517,112 @@ void LLViewerObjectList::updateActive(LLViewerObject *objectp) { if (active) { - //llinfos << "Adding " << objectp->mID << " " << objectp->getPCodeString() << " to active list." << llendl; - mActiveObjects.insert(objectp); + //LL_INFOS() << "Adding " << objectp->mID << " " << objectp->getPCodeString() << " to active list." << LL_ENDL; + S32 idx = objectp->getListIndex(); + if (idx <= -1) + { + mActiveObjects.push_back(objectp); + objectp->setListIndex(mActiveObjects.size()-1); objectp->setOnActiveList(TRUE); } else { - //llinfos << "Removing " << objectp->mID << " " << objectp->getPCodeString() << " from active list." << llendl; - mActiveObjects.erase(objectp); + llassert(idx < mActiveObjects.size()); + llassert(mActiveObjects[idx] == objectp); + + if (idx >= mActiveObjects.size() || + mActiveObjects[idx] != objectp) + { + LL_WARNS() << "Invalid object list index detected!" << LL_ENDL; + } + } + } + else + { + //LL_INFOS() << "Removing " << objectp->mID << " " << objectp->getPCodeString() << " from active list." << LL_ENDL; + removeFromActiveList(objectp); objectp->setOnActiveList(FALSE); } } + + //post condition: if object is active, it must be on the active list + llassert(!active || std::find(mActiveObjects.begin(), mActiveObjects.end(), objectp) != mActiveObjects.end()); + + //post condition: if object is not active, it must not be on the active list + llassert(active || std::find(mActiveObjects.begin(), mActiveObjects.end(), objectp) == mActiveObjects.end()); +} + +void LLViewerObjectList::updateObjectCost(LLViewerObject* object) +{ + if (!object->isRoot()) + { //always fetch cost for the parent when fetching cost for children + mStaleObjectCost.insert(((LLViewerObject*)object->getParent())->getID()); + } + mStaleObjectCost.insert(object->getID()); +} + +void LLViewerObjectList::updateObjectCost(const LLUUID& object_id, F32 object_cost, F32 link_cost, F32 physics_cost, F32 link_physics_cost) +{ + mPendingObjectCost.erase(object_id); + + LLViewerObject* object = findObject(object_id); + if (object) + { + object->setObjectCost(object_cost); + object->setLinksetCost(link_cost); + object->setPhysicsCost(physics_cost); + object->setLinksetPhysicsCost(link_physics_cost); + } +} + +void LLViewerObjectList::onObjectCostFetchFailure(const LLUUID& object_id) +{ + //LL_WARNS() << "Failed to fetch object cost for object: " << object_id << LL_ENDL; + mPendingObjectCost.erase(object_id); +} + +void LLViewerObjectList::updatePhysicsFlags(const LLViewerObject* object) +{ + mStalePhysicsFlags.insert(object->getID()); +} + +void LLViewerObjectList::updatePhysicsShapeType(const LLUUID& object_id, S32 type) +{ + mPendingPhysicsFlags.erase(object_id); + LLViewerObject* object = findObject(object_id); + if (object) + { + object->setPhysicsShapeType(type); + } } +void LLViewerObjectList::updatePhysicsProperties(const LLUUID& object_id, + F32 density, + F32 friction, + F32 restitution, + F32 gravity_multiplier) +{ + mPendingPhysicsFlags.erase(object_id); + LLViewerObject* object = findObject(object_id); + if (object) + { + object->setPhysicsDensity(density); + object->setPhysicsFriction(friction); + object->setPhysicsGravity(gravity_multiplier); + object->setPhysicsRestitution(restitution); + } +} + +void LLViewerObjectList::onPhysicsFlagsFetchFailure(const LLUUID& object_id) +{ + //LL_WARNS() << "Failed to fetch physics flags for object: " << object_id << LL_ENDL; + mPendingPhysicsFlags.erase(object_id); +} + +static LLTrace::BlockTimerStatHandle FTM_SHIFT_OBJECTS("Shift Objects"); +static LLTrace::BlockTimerStatHandle FTM_PIPELINE_SHIFT("Pipeline Shift"); +static LLTrace::BlockTimerStatHandle FTM_REGION_SHIFT("Region Shift"); void LLViewerObjectList::shiftObjects(const LLVector3 &offset) { @@ -1035,18 +1630,19 @@ void LLViewerObjectList::shiftObjects(const LLVector3 &offset) // We need to update many object caches, I'll document this more as I dig through the code // cleaning things out... - if (gNoRender || 0 == offset.magVecSquared()) + if (0 == offset.magVecSquared()) { return; } + LL_RECORD_BLOCK_TIME(FTM_SHIFT_OBJECTS); + LLViewerObject *objectp; - S32 i; - for (i = 0; i < mObjects.count(); i++) + for (vobj_list_t::iterator iter = mObjects.begin(); iter != mObjects.end(); ++iter) { - objectp = getObject(i); + objectp = *iter; // There could be dead objects on the object list, so don't update stuff if the object is dead. - if (objectp) + if (!objectp->isDead()) { objectp->updatePositionCaches(); @@ -1057,9 +1653,90 @@ void LLViewerObjectList::shiftObjects(const LLVector3 &offset) } } + { + LL_RECORD_BLOCK_TIME(FTM_PIPELINE_SHIFT); gPipeline.shiftObjects(offset); + } + + { + LL_RECORD_BLOCK_TIME(FTM_REGION_SHIFT); LLWorld::getInstance()->shiftRegions(offset); } +} + +void LLViewerObjectList::repartitionObjects() +{ + for (vobj_list_t::iterator iter = mObjects.begin(); iter != mObjects.end(); ++iter) + { + LLViewerObject* objectp = *iter; + if (!objectp->isDead()) + { + LLDrawable* drawable = objectp->mDrawable; + if (drawable && !drawable->isDead()) + { + drawable->updateBinRadius(); + drawable->updateSpatialExtents(); + drawable->movePartition(); + } + } + } +} + +//debug code +bool LLViewerObjectList::hasMapObjectInRegion(LLViewerRegion* regionp) +{ + for (vobj_list_t::iterator iter = mMapObjects.begin(); iter != mMapObjects.end(); ++iter) + { + LLViewerObject* objectp = *iter; + + if(objectp->isDead() || objectp->getRegion() == regionp) + { + return true ; + } + } + + return false ; +} + +//make sure the region is cleaned up. +void LLViewerObjectList::clearAllMapObjectsInRegion(LLViewerRegion* regionp) +{ + std::set<LLViewerObject*> dead_object_list ; + std::set<LLViewerObject*> region_object_list ; + for (vobj_list_t::iterator iter = mMapObjects.begin(); iter != mMapObjects.end(); ++iter) + { + LLViewerObject* objectp = *iter; + + if(objectp->isDead()) + { + dead_object_list.insert(objectp) ; + } + else if(objectp->getRegion() == regionp) + { + region_object_list.insert(objectp) ; + } + } + + if(dead_object_list.size() > 0) + { + LL_WARNS() << "There are " << dead_object_list.size() << " dead objects on the map!" << LL_ENDL ; + + for(std::set<LLViewerObject*>::iterator iter = dead_object_list.begin(); iter != dead_object_list.end(); ++iter) + { + cleanupReferences(*iter) ; + } + } + if(region_object_list.size() > 0) + { + LL_WARNS() << "There are " << region_object_list.size() << " objects not removed from the deleted region!" << LL_ENDL ; + + for(std::set<LLViewerObject*>::iterator iter = region_object_list.begin(); iter != region_object_list.end(); ++iter) + { + (*iter)->markDead() ; + } + } +} + void LLViewerObjectList::renderObjectsForMap(LLNetMap &netmap) { @@ -1074,10 +1751,17 @@ void LLViewerObjectList::renderObjectsForMap(LLNetMap &netmap) LLColor4 group_own_below_water_color = LLUIColorTable::instance().getColor( "NetMapGroupOwnBelowWater" ); + F32 max_radius = gSavedSettings.getF32("MiniMapPrimMaxRadius"); - for (S32 i = 0; i < mMapObjects.count(); i++) + for (vobj_list_t::iterator iter = mMapObjects.begin(); iter != mMapObjects.end(); ++iter) { - LLViewerObject* objectp = mMapObjects[i]; + LLViewerObject* objectp = *iter; + + if(objectp->isDead())//some dead objects somehow not cleaned. + { + continue ; + } + if (!objectp->getRegion() || objectp->isOrphaned() || objectp->isAttachment()) { continue; @@ -1089,6 +1773,11 @@ void LLViewerObjectList::renderObjectsForMap(LLNetMap &netmap) F32 approx_radius = (scale.mV[VX] + scale.mV[VY]) * 0.5f * 0.5f * 1.3f; // 1.3 is a fudge + // Limit the size of megaprims so they don't blot out everything on the minimap. + // Attempting to draw very large megaprims also causes client lag. + // See DEV-17370 and DEV-29869/SNOW-79 for details. + approx_radius = llmin(approx_radius, max_radius); + LLColor4U color = above_water_color; if( objectp->permYouOwner() ) { @@ -1138,21 +1827,14 @@ void LLViewerObjectList::renderObjectBounds(const LLVector3 ¢er) { } -void LLViewerObjectList::renderObjectsForSelect(LLCamera &camera, const LLRect& screen_rect, BOOL pick_parcel_wall, BOOL render_transparent) -{ - generatePickList(camera); - renderPickList(screen_rect, pick_parcel_wall, render_transparent); -} - void LLViewerObjectList::generatePickList(LLCamera &camera) { LLViewerObject *objectp; S32 i; // Reset all of the GL names to zero. - for (i = 0; i < mObjects.count(); i++) + for (vobj_list_t::iterator iter = mObjects.begin(); iter != mObjects.end(); ++iter) { - objectp = mObjects[i]; - objectp->mGLName = 0; + (*iter)->mGLName = 0; } mSelectPickList.clear(); @@ -1183,7 +1865,10 @@ void LLViewerObjectList::generatePickList(LLCamera &camera) LLViewerObject* last_objectp = NULL; for (S32 face_num = 0; face_num < drawablep->getNumFaces(); face_num++) { - LLViewerObject* objectp = drawablep->getFace(face_num)->getViewerObject(); + LLFace * facep = drawablep->getFace(face_num); + if (!facep) continue; + + LLViewerObject* objectp = facep->getViewerObject(); if (objectp && objectp != last_objectp) { @@ -1193,7 +1878,7 @@ void LLViewerObjectList::generatePickList(LLCamera &camera) } } - LLHUDText::addPickable(mSelectPickList); + LLHUDNameTag::addPickable(mSelectPickList); for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin(); iter != LLCharacter::sInstances.end(); ++iter) @@ -1209,11 +1894,10 @@ void LLViewerObjectList::generatePickList(LLCamera &camera) } // add all hud objects to pick list - LLVOAvatar* avatarp = gAgent.getAvatarObject(); - if (avatarp) + if (isAgentAvatarValid()) { - for (LLVOAvatar::attachment_map_t::iterator iter = avatarp->mAttachmentPoints.begin(); - iter != avatarp->mAttachmentPoints.end(); ) + for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin(); + iter != gAgentAvatarp->mAttachmentPoints.end(); ) { LLVOAvatar::attachment_map_t::iterator curiter = iter++; LLViewerJointAttachment* attachment = curiter->second; @@ -1268,34 +1952,6 @@ void LLViewerObjectList::generatePickList(LLCamera &camera) } } -void LLViewerObjectList::renderPickList(const LLRect& screen_rect, BOOL pick_parcel_wall, BOOL render_transparent) -{ - gRenderForSelect = TRUE; - - gPipeline.renderForSelect(mSelectPickList, render_transparent, screen_rect); - - // - // Render pass for selected objects - // - gGL.color4f(1,1,1,1); - gViewerWindow->renderSelections( TRUE, pick_parcel_wall, FALSE ); - - //fix for DEV-19335. Don't pick hud objects when customizing avatar (camera mode doesn't play nice with nametags). - if (!gAgent.cameraCustomizeAvatar()) - { - // render pickable ui elements, like names, etc. - LLHUDObject::renderAllForSelect(); - } - - gGL.flush(); - LLVertexBuffer::unbind(); - - gRenderForSelect = FALSE; - - //llinfos << "Rendered " << count << " for select" << llendl; - //llinfos << "Took " << pick_timer.getElapsedTimeF32()*1000.f << "ms to pick" << llendl; -} - LLViewerObject *LLViewerObjectList::getSelectedObject(const U32 object_id) { std::set<LLViewerObject*>::iterator pick_it; @@ -1315,49 +1971,69 @@ void LLViewerObjectList::addDebugBeacon(const LLVector3 &pos_agent, const LLColor4 &text_color, S32 line_width) { - LLDebugBeacon *beaconp = mDebugBeacons.reserve_block(1); - beaconp->mPositionAgent = pos_agent; - beaconp->mString = string; - beaconp->mColor = color; - beaconp->mTextColor = text_color; - beaconp->mLineWidth = line_width; + LLDebugBeacon beacon; + beacon.mPositionAgent = pos_agent; + beacon.mString = string; + beacon.mColor = color; + beacon.mTextColor = text_color; + beacon.mLineWidth = line_width; + + mDebugBeacons.push_back(beacon); } void LLViewerObjectList::resetObjectBeacons() { - mDebugBeacons.reset(); + mDebugBeacons.clear(); } LLViewerObject *LLViewerObjectList::createObjectViewer(const LLPCode pcode, LLViewerRegion *regionp) { - LLMemType mt(LLMemType::MTYPE_OBJECT); LLUUID fullid; fullid.generate(); LLViewerObject *objectp = LLViewerObject::createObject(fullid, pcode, regionp); if (!objectp) { -// llwarns << "Couldn't create object of type " << LLPrimitive::pCodeToString(pcode) << llendl; +// LL_WARNS() << "Couldn't create object of type " << LLPrimitive::pCodeToString(pcode) << LL_ENDL; return NULL; } mUUIDObjectMap[fullid] = objectp; - mObjects.put(objectp); + mObjects.push_back(objectp); updateActive(objectp); return objectp; } +LLViewerObject *LLViewerObjectList::createObjectFromCache(const LLPCode pcode, LLViewerRegion *regionp, const LLUUID &uuid, const U32 local_id) +{ + llassert_always(uuid.notNull()); + + LLViewerObject *objectp = LLViewerObject::createObject(uuid, pcode, regionp); + if (!objectp) + { +// LL_WARNS() << "Couldn't create object of type " << LLPrimitive::pCodeToString(pcode) << " id:" << fullid << LL_ENDL; + return NULL; + } + + objectp->mLocalID = local_id; + mUUIDObjectMap[uuid] = objectp; + setUUIDAndLocal(uuid, + local_id, + regionp->getHost().getAddress(), + regionp->getHost().getPort()); + mObjects.push_back(objectp); + + updateActive(objectp); -static LLFastTimer::DeclareTimer FTM_CREATE_OBJECT("Create Object"); + return objectp; +} LLViewerObject *LLViewerObjectList::createObject(const LLPCode pcode, LLViewerRegion *regionp, const LLUUID &uuid, const U32 local_id, const LLHost &sender) { - LLMemType mt(LLMemType::MTYPE_OBJECT); - LLFastTimer t(FTM_CREATE_OBJECT); LLUUID fullid; if (uuid == LLUUID::null) @@ -1372,9 +2048,13 @@ LLViewerObject *LLViewerObjectList::createObject(const LLPCode pcode, LLViewerRe LLViewerObject *objectp = LLViewerObject::createObject(fullid, pcode, regionp); if (!objectp) { -// llwarns << "Couldn't create object of type " << LLPrimitive::pCodeToString(pcode) << " id:" << fullid << llendl; +// LL_WARNS() << "Couldn't create object of type " << LLPrimitive::pCodeToString(pcode) << " id:" << fullid << LL_ENDL; return NULL; } + if(regionp) + { + regionp->addToCreatedList(local_id); + } mUUIDObjectMap[fullid] = objectp; setUUIDAndLocal(fullid, @@ -1382,7 +2062,7 @@ LLViewerObject *LLViewerObjectList::createObject(const LLPCode pcode, LLViewerRe gMessageSystem->getSenderIP(), gMessageSystem->getSenderPort()); - mObjects.put(objectp); + mObjects.push_back(objectp); updateActive(objectp); @@ -1394,7 +2074,7 @@ LLViewerObject *LLViewerObjectList::replaceObject(const LLUUID &id, const LLPCod LLViewerObject *old_instance = findObject(id); if (old_instance) { - cleanupReferences(old_instance); + //cleanupReferences(old_instance); old_instance->markDead(); return createObject(pcode, regionp, id, old_instance->getLocalID(), LLHost()); @@ -1405,11 +2085,11 @@ LLViewerObject *LLViewerObjectList::replaceObject(const LLUUID &id, const LLPCod S32 LLViewerObjectList::findReferences(LLDrawable *drawablep) const { LLViewerObject *objectp; - S32 i; S32 num_refs = 0; - for (i = 0; i < mObjects.count(); i++) + + for (vobj_list_t::const_iterator iter = mObjects.begin(); iter != mObjects.end(); ++iter) { - objectp = mObjects[i]; + objectp = *iter; if (objectp->mDrawable.notNull()) { num_refs += objectp->mDrawable->findReferences(drawablep); @@ -1421,10 +2101,7 @@ S32 LLViewerObjectList::findReferences(LLDrawable *drawablep) const void LLViewerObjectList::orphanize(LLViewerObject *childp, U32 parent_id, U32 ip, U32 port) { - LLMemType mt(LLMemType::MTYPE_OBJECT); -#ifdef ORPHAN_SPAM - llinfos << "Orphaning object " << childp->getID() << " with parent " << parent_id << llendl; -#endif + LL_DEBUGS("ORPHANS") << "Orphaning object " << childp->getID() << " with parent " << parent_id << LL_ENDL; // We're an orphan, flag things appropriately. childp->mOrphaned = TRUE; @@ -1440,7 +2117,7 @@ void LLViewerObjectList::orphanize(LLViewerObject *childp, U32 parent_id, U32 ip // object probably ISN'T being reparented, but just got an object // update out of order (child update before parent). make_invisible = false; - //llinfos << "Don't make object handoffs invisible!" << llendl; + //LL_INFOS() << "Don't make object handoffs invisible!" << LL_ENDL; } } @@ -1454,15 +2131,15 @@ void LLViewerObjectList::orphanize(LLViewerObject *childp, U32 parent_id, U32 ip // Unknown parent, add to orpaned child list U64 parent_info = getIndex(parent_id, ip, port); - if (-1 == mOrphanParents.find(parent_info)) + if (std::find(mOrphanParents.begin(), mOrphanParents.end(), parent_info) == mOrphanParents.end()) { - mOrphanParents.put(parent_info); + mOrphanParents.push_back(parent_info); } LLViewerObjectList::OrphanInfo oi(parent_info, childp->mID); - if (-1 == mOrphanChildren.find(oi)) + if (std::find(mOrphanChildren.begin(), mOrphanChildren.end(), oi) == mOrphanChildren.end()) { - mOrphanChildren.put(oi); + mOrphanChildren.push_back(oi); mNumOrphans++; } } @@ -1470,69 +2147,72 @@ void LLViewerObjectList::orphanize(LLViewerObject *childp, U32 parent_id, U32 ip void LLViewerObjectList::findOrphans(LLViewerObject* objectp, U32 ip, U32 port) { - if (gNoRender) + if (objectp->isDead()) { + LL_WARNS() << "Trying to find orphans for dead obj " << objectp->mID + << ":" << objectp->getPCodeString() << LL_ENDL; return; } - if (objectp->isDead()) + //search object cache to get orphans + if(objectp->getRegion()) { - llwarns << "Trying to find orphans for dead obj " << objectp->mID - << ":" << objectp->getPCodeString() << llendl; - return; + objectp->getRegion()->findOrphans(objectp->getLocalID()); } // See if we are a parent of an orphan. // Note: This code is fairly inefficient but it should happen very rarely. // It can be sped up if this is somehow a performance issue... - if (0 == mOrphanParents.count()) + if (mOrphanParents.empty()) { // no known orphan parents return; } - if (-1 == mOrphanParents.find(getIndex(objectp->mLocalID, ip, port))) + if (std::find(mOrphanParents.begin(), mOrphanParents.end(), getIndex(objectp->mLocalID, ip, port)) == mOrphanParents.end()) { // did not find objectp in OrphanParent list return; } - S32 i; U64 parent_info = getIndex(objectp->mLocalID, ip, port); BOOL orphans_found = FALSE; // Iterate through the orphan list, and set parents of matching children. - for (i = 0; i < mOrphanChildren.count(); i++) - { - if (mOrphanChildren[i].mParentInfo != parent_info) + + for (std::vector<OrphanInfo>::iterator iter = mOrphanChildren.begin(); iter != mOrphanChildren.end(); ) + { + if (iter->mParentInfo != parent_info) { + ++iter; continue; } - LLViewerObject *childp = findObject(mOrphanChildren[i].mChildInfo); + LLViewerObject *childp = findObject(iter->mChildInfo); if (childp) { if (childp == objectp) { - llwarns << objectp->mID << " has self as parent, skipping!" - << llendl; + LL_WARNS() << objectp->mID << " has self as parent, skipping!" + << LL_ENDL; continue; } + LL_DEBUGS("ORPHANS") << "Reunited parent " << objectp->mID + << " with child " << childp->mID << LL_ENDL; + LL_DEBUGS("ORPHANS") << "Glob: " << objectp->getPositionGlobal() << LL_ENDL; + LL_DEBUGS("ORPHANS") << "Agent: " << objectp->getPositionAgent() << LL_ENDL; #ifdef ORPHAN_SPAM - llinfos << "Reunited parent " << objectp->mID - << " with child " << childp->mID << llendl; - llinfos << "Glob: " << objectp->getPositionGlobal() << llendl; - llinfos << "Agent: " << objectp->getPositionAgent() << llendl; addDebugBeacon(objectp->getPositionAgent(),""); #endif - gPipeline.markMoved(objectp->mDrawable); - objectp->setChanged(LLXform::MOVED | LLXform::SILHOUETTE); + gPipeline.markMoved(objectp->mDrawable); + objectp->setChanged(LLXform::MOVED | LLXform::SILHOUETTE); // Flag the object as no longer orphaned childp->mOrphaned = FALSE; if (childp->mDrawable.notNull()) { // Make the drawable visible again and set the drawable parent - childp->mDrawable->setState(LLDrawable::CLEAR_INVISIBLE); + childp->mDrawable->clearState(LLDrawable::FORCE_INVISIBLE); childp->setDrawableParent(objectp->mDrawable); // LLViewerObjectList::findOrphans() + gPipeline.markRebuild( childp->mDrawable, LLDrawable::REBUILD_ALL, TRUE ); } // Make certain particles, icon and HUD aren't hidden @@ -1540,29 +2220,35 @@ void LLViewerObjectList::findOrphans(LLViewerObject* objectp, U32 ip, U32 port) objectp->addChild(childp); orphans_found = TRUE; + ++iter; } else { - llinfos << "Missing orphan child, removing from list" << llendl; - mOrphanChildren.remove(i); - i--; + LL_INFOS() << "Missing orphan child, removing from list" << LL_ENDL; + + iter = mOrphanChildren.erase(iter); } } // Remove orphan parent and children from lists now that they've been found - mOrphanParents.remove(mOrphanParents.find(parent_info)); - - i = 0; - while (i < mOrphanChildren.count()) { - if (mOrphanChildren[i].mParentInfo == parent_info) + std::vector<U64>::iterator iter = std::find(mOrphanParents.begin(), mOrphanParents.end(), parent_info); + if (iter != mOrphanParents.end()) + { + mOrphanParents.erase(iter); + } + } + + for (std::vector<OrphanInfo>::iterator iter = mOrphanChildren.begin(); iter != mOrphanChildren.end(); ) + { + if (iter->mParentInfo == parent_info) { - mOrphanChildren.remove(i); + iter = mOrphanChildren.erase(iter); mNumOrphans--; } else { - i++; + ++iter; } } @@ -1601,3 +2287,10 @@ bool LLViewerObjectList::OrphanInfo::operator!=(const OrphanInfo &rhs) const } +LLDebugBeacon::~LLDebugBeacon() +{ + if (mHUDObject.notNull()) + { + mHUDObject->markDead(); + } +} |