summaryrefslogtreecommitdiff
path: root/indra/newview/llviewerobjectlist.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llviewerobjectlist.cpp')
-rwxr-xr-x[-rw-r--r--]indra/newview/llviewerobjectlist.cpp1151
1 files changed, 901 insertions, 250 deletions
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index 970cc2e2a7..7c36b30dd1 100644..100755
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -29,7 +29,6 @@
#include "llviewerobjectlist.h"
#include "message.h"
-#include "timing.h"
#include "llfasttimer.h"
#include "llrender.h"
#include "llwindow.h" // decBusyCount()
@@ -47,16 +46,21 @@
#include "lltooltip.h"
#include "llworld.h"
#include "llstring.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"
@@ -64,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"
@@ -72,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;
@@ -89,13 +93,11 @@ extern LLPipeline gPipeline;
// Statics for object lookup tables.
U32 LLViewerObjectList::sSimulatorMachineIndex = 1; // Not zero deliberately, to speed up index check.
-std::map<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;
@@ -103,7 +105,6 @@ LLViewerObjectList::LLViewerObjectList()
mNumNewObjects = 0;
mWasPaused = FALSE;
mNumDeadObjectUpdates = 0;
- mNumUnknownKills = 0;
mNumUnknownUpdates = 0;
}
@@ -170,7 +171,7 @@ BOOL LLViewerObjectList::removeFromLocalIDTable(const LLViewerObject* objectp)
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;
@@ -187,8 +188,8 @@ BOOL LLViewerObjectList::removeFromLocalIDTable(const LLViewerObject* objectp)
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 ;
@@ -213,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;
@@ -225,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);
@@ -252,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
@@ -261,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();
}
@@ -273,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 = gAgentCamera.getCameraPositionGlobal();
LLViewerObject *objectp;
S32 num_objects;
U32 local_id;
@@ -298,10 +403,11 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
num_objects = mesgsys->getNumberOfBlocksFast(_PREHASH_ObjectData);
// I don't think this case is ever hit. TODO* Test this.
- if (!cached && !compressed && update_type != OUT_FULL)
+ if (!compressed && update_type != OUT_FULL)
{
- //llinfos << "TEST: !cached && !compressed && update_type != OUT_FULL" << llendl;
+ //LL_INFOS() << "TEST: !cached && !compressed && update_type != OUT_FULL" << LL_ENDL;
gTerseObjectUpdates += num_objects;
+ /*
S32 size;
if (mesgsys->getReceiveCompressedSize())
{
@@ -311,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())
{
@@ -325,102 +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;
-
-#if LL_RECORD_VIEWER_STATS
- LLViewerStatsRecorder::instance()->beginObjectUpdateEvents(regionp);
-#endif
+ 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.
- U8 cache_miss_type = LLViewerRegion::CACHE_MISS_TYPE_NONE;
- cached_dpp = regionp->getDP(id, crc, cache_miss_type);
- if (cached_dpp)
- {
- // Cache Hit.
- cached_dpp->reset();
- cached_dpp->unpackUUID(fullid, "ID");
- cached_dpp->unpackU32(local_id, "LocalID");
- cached_dpp->unpackU8(pcode, "PCode");
- }
- else
- {
- // Cache Miss.
- #if LL_RECORD_VIEWER_STATS
- LLViewerStatsRecorder::instance()->recordCacheMissEvent(id, update_type, cache_miss_type);
- #endif
-
- 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;
+ 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);
- }
- // I don't think we ever use this flag from the server. DK 2010/12/09
- if (flags & FLAGS_ZLIB_COMPRESSED)
- {
- //llinfos << "TEST: flags & FLAGS_ZLIB_COMPRESSED" << llendl;
- 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) // OUT_FULL_COMPRESSED only?
- {
+ 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,
@@ -428,7 +497,7 @@ 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++;
}
}
@@ -436,24 +505,34 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
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 // 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
@@ -463,13 +542,13 @@ 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);
setUUIDAndLocal(fullid,
@@ -494,37 +573,30 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
{
if (update_type == OUT_TERSE_IMPROVED)
{
- // llinfos << "terse update for an unknown object (compressed):" << fullid << llendl;
- #if LL_RECORD_VIEWER_STATS
- LLViewerStatsRecorder::instance()->recordObjectUpdateFailure(local_id, update_type);
- #endif
+ // LL_INFOS() << "terse update for an unknown object (compressed):" << fullid << LL_ENDL;
+ recorder.objectUpdateFailure(local_id, update_type, msg_size);
continue;
}
}
- else if (cached) // Cache hit only?
- {
- }
else
{
if (update_type != OUT_FULL)
{
- //llinfos << "terse update for an unknown object:" << fullid << llendl;
- #if LL_RECORD_VIEWER_STATS
- LLViewerStatsRecorder::instance()->recordObjectUpdateFailure(local_id, update_type);
- #endif
+ //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;
- #if LL_RECORD_VIEWER_STATS
- LLViewerStatsRecorder::instance()->recordObjectUpdateFailure(local_id, update_type);
- #endif
+ //LL_INFOS() << "update for a dead object:" << fullid << LL_ENDL;
+ recorder.objectUpdateFailure(local_id, update_type, msg_size);
continue;
}
#endif
@@ -532,23 +604,21 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
objectp = createObject(pcode, regionp, fullid, local_id, gMessageSystem->getSender());
if (!objectp)
{
- llinfos << "createObject failure for object: " << fullid << llendl;
- #if LL_RECORD_VIEWER_STATS
- LLViewerStatsRecorder::instance()->recordObjectUpdateFailure(local_id, update_type);
- #endif
+ 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;
+ //bool bCached = false;
if (compressed)
{
if (update_type != OUT_TERSE_IMPROVED) // OUT_FULL_COMPRESSED only?
@@ -556,21 +626,21 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
objectp->mLocalID = local_id;
}
processUpdateCore(objectp, user_data, i, update_type, &compressed_dp, justCreated);
+
+#if 0
if (update_type != OUT_TERSE_IMPROVED) // OUT_FULL_COMPRESSED only?
{
+ U32 flags = 0;
+ mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, i);
+
+ if(!(flags & FLAGS_TEMPORARY_ON_REZ))
+ {
bCached = true;
- #if LL_RECORD_VIEWER_STATS
- LLViewerRegion::eCacheUpdateResult result = objectp->mRegionp->cacheFullUpdate(objectp, compressed_dp);
- LLViewerStatsRecorder::instance()->recordCacheFullUpdate(local_id, update_type, result, objectp);
- #else
- objectp->mRegionp->cacheFullUpdate(objectp, compressed_dp);
- #endif
+ LLViewerRegion::eCacheUpdateResult result = objectp->mRegionp->cacheFullUpdate(objectp, compressed_dp, flags);
+ recorder.cacheFullUpdate(local_id, update_type, result, objectp, msg_size);
}
}
- else if (cached) // Cache hit only?
- {
- objectp->mLocalID = local_id;
- processUpdateCore(objectp, user_data, i, update_type, cached_dpp, justCreated);
+#endif
}
else
{
@@ -580,16 +650,11 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
}
processUpdateCore(objectp, user_data, i, update_type, NULL, justCreated);
}
- #if LL_RECORD_VIEWER_STATS
- LLViewerStatsRecorder::instance()->recordObjectUpdateEvent(local_id, update_type, objectp);
- #endif
+ recorder.objectUpdateEvent(local_id, update_type, objectp, msg_size);
objectp->setLastUpdateType(update_type);
- objectp->setLastUpdateCached(bCached);
}
-#if LL_RECORD_VIEWER_STATS
- LLViewerStatsRecorder::instance()->endObjectUpdateEvents();
-#endif
+ recorder.log(0.2f);
LLVOAvatar::cullAvatarsByPixelArea();
}
@@ -598,14 +663,52 @@ 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()
@@ -636,19 +739,16 @@ void LLViewerObjectList::updateApparentAngles(LLAgent &agent)
}
- 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();
}
}
@@ -695,11 +795,194 @@ 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();
-void LLViewerObjectList::update(LLAgent &agent, LLWorld &world)
+ 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
{
- LLMemType mt(LLMemType::MTYPE_OBJECT);
+ 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);
+
+ 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)
+{
// Update globals
LLViewerObject::setVelocityInterpolate( gSavedSettings.getBOOL("VelocityInterpolate") );
LLViewerObject::setPingInterpolate( gSavedSettings.getBOOL("PingInterpolate") );
@@ -710,7 +993,7 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world)
phase_out_time < 0.0 ||
phase_out_time > interp_time)
{
- llwarns << "Invalid values for InterpolationTime or InterpolationPhaseOut, resetting to defaults" << llendl;
+ LL_WARNS() << "Invalid values for InterpolationTime or InterpolationPhaseOut, resetting to defaults" << LL_ENDL;
interp_time = 3.0f;
phase_out_time = 1.0f;
}
@@ -721,14 +1004,14 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world)
// 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;
+ F64Seconds time_diff = time - gFrameTime;
gFrameTime = time;
- F64 time_since_start = U64_to_F64(gFrameTime - gStartTime)/(F64)SEC_TO_MICROSEC;
- gFrameTimeSeconds = (F32)time_since_start;
+ F64Seconds time_since_start = gFrameTime - gStartTime;
+ gFrameTimeSeconds = time_since_start;
gFrameIntervalSeconds = gFrameTimeSeconds - last_time;
if (gFrameIntervalSeconds < 0.f)
@@ -741,74 +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;
-
- static LLFastTimer::DeclareTimer idle_copy("Idle Copy");
+ static std::vector<LLViewerObject*> idle_list;
+ U32 idle_count = 0;
+
{
- LLFastTimer t(idle_copy);
- idle_list.reserve( mActiveObjects.size() );
+ LL_RECORD_BLOCK_TIME(FTM_IDLE_COPY);
- for (std::set<LLPointer<LLViewerObject> >::iterator active_iter = mActiveObjects.begin();
+ for (std::vector<LLPointer<LLViewerObject> >::iterator active_iter = mActiveObjects.begin();
active_iter != mActiveObjects.end(); active_iter++)
{
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.
- llwarns << "LLViewerObjectList::update has a NULL objectp" << llendl;
+ 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
@@ -820,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);
@@ -837,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);
@@ -866,12 +1157,127 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world)
}
*/
- LLViewerStats::getInstance()->mNumObjectsStat.addValue((S32) mObjects.size());
- 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 (vobj_list_t::iterator iter = mObjects.begin(); iter != mObjects.end(); ++iter)
@@ -883,14 +1289,14 @@ void LLViewerObjectList::clearDebugText()
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.
@@ -899,18 +1305,18 @@ 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);
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())
@@ -925,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;
@@ -949,7 +1359,8 @@ void LLViewerObjectList::removeDrawable(LLDrawable* drawablep)
BOOL LLViewerObjectList::killObject(LLViewerObject *objectp)
{
// Don't ever kill gAgentAvatarp, just force it to the agent's region
- if (objectp == gAgentAvatarp)
+ // unless region is NULL which is assumed to mean you are logging out.
+ if ((objectp == gAgentAvatarp) && gAgent.getRegion())
{
objectp->setRegion(gAgent.getRegion());
return FALSE;
@@ -960,18 +1371,10 @@ BOOL LLViewerObjectList::killObject(LLViewerObject *objectp)
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;
}
@@ -1011,19 +1414,19 @@ void LLViewerObjectList::killAllObjects()
if(!mObjects.empty())
{
- llwarns << "LLViewerObjectList::killAllObjects still has entries in mObjects: " << mObjects.size() << 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();
}
}
@@ -1038,18 +1441,29 @@ void LLViewerObjectList::cleanDeadObjects(BOOL use_timer)
S32 num_removed = 0;
LLViewerObject *objectp;
- for (vobj_list_t::iterator iter = mObjects.begin(); iter != mObjects.end(); )
+
+ 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.
+ // 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())
{
- iter = mObjects.erase(iter);
+ 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;
}
}
@@ -1059,15 +1473,40 @@ void LLViewerObjectList::cleanDeadObjects(BOOL use_timer)
}
}
+ 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!
@@ -1078,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)
{
@@ -1099,11 +1630,13 @@ 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;
for (vobj_list_t::iterator iter = mObjects.begin(); iter != mObjects.end(); ++iter)
{
@@ -1120,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)
{
@@ -1142,6 +1756,12 @@ void LLViewerObjectList::renderObjectsForMap(LLNetMap &netmap)
for (vobj_list_t::iterator iter = mMapObjects.begin(); iter != mMapObjects.end(); ++iter)
{
LLViewerObject* objectp = *iter;
+
+ if(objectp->isDead())//some dead objects somehow not cleaned.
+ {
+ continue ;
+ }
+
if (!objectp->getRegion() || objectp->isOrphaned() || objectp->isAttachment())
{
continue;
@@ -1245,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)
{
@@ -1365,14 +1988,13 @@ void LLViewerObjectList::resetObjectBeacons()
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;
}
@@ -1385,14 +2007,33 @@ LLViewerObject *LLViewerObjectList::createObjectViewer(const LLPCode pcode, LLVi
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)
@@ -1407,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,
@@ -1429,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());
@@ -1456,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;
@@ -1475,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;
}
}
@@ -1505,16 +2147,17 @@ 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.
@@ -1547,16 +2190,16 @@ void LLViewerObjectList::findOrphans(LLViewerObject* objectp, U32 ip, U32 port)
{
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);
@@ -1567,8 +2210,9 @@ void LLViewerObjectList::findOrphans(LLViewerObject* objectp, U32 ip, U32 port)
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
@@ -1580,7 +2224,7 @@ void LLViewerObjectList::findOrphans(LLViewerObject* objectp, U32 ip, U32 port)
}
else
{
- llinfos << "Missing orphan child, removing from list" << llendl;
+ LL_INFOS() << "Missing orphan child, removing from list" << LL_ENDL;
iter = mOrphanChildren.erase(iter);
}
@@ -1643,3 +2287,10 @@ bool LLViewerObjectList::OrphanInfo::operator!=(const OrphanInfo &rhs) const
}
+LLDebugBeacon::~LLDebugBeacon()
+{
+ if (mHUDObject.notNull())
+ {
+ mHUDObject->markDead();
+ }
+}