diff options
Diffstat (limited to 'indra/newview/llviewerregion.cpp')
-rwxr-xr-x[-rw-r--r--] | indra/newview/llviewerregion.cpp | 2268 |
1 files changed, 1955 insertions, 313 deletions
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 23b7b921b8..92e07c52a5 100644..100755 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -4,7 +4,7 @@ * * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. + * Copyright (C) 2010-2013, Linden Research, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -30,6 +30,7 @@ // linden libraries #include "indra_constants.h" +#include "llaisapi.h" #include "llavatarnamecache.h" // name lookup cap url #include "llfloaterreg.h" #include "llmath.h" @@ -44,8 +45,10 @@ #include "llagent.h" #include "llagentcamera.h" +#include "llavatarrenderinfoaccountant.h" #include "llcallingcard.h" #include "llcaphttpsender.h" +#include "llcapabilitylistener.h" #include "llcommandhandler.h" #include "lldir.h" #include "lleventpoll.h" @@ -53,6 +56,7 @@ #include "llfloaterreporter.h" #include "llfloaterregioninfo.h" #include "llhttpnode.h" +#include "llregioninfomodel.h" #include "llsdutil.h" #include "llstartup.h" #include "lltrans.h" @@ -62,20 +66,132 @@ #include "llviewerstatsrecorder.h" #include "llvlmanager.h" #include "llvlcomposition.h" +#include "llvoavatarself.h" #include "llvocache.h" -#include "llvoclouds.h" #include "llworld.h" #include "llspatialpartition.h" #include "stringize.h" +#include "llviewercontrol.h" +#include "llsdserialize.h" +#include "llfloaterperms.h" +#include "llvieweroctree.h" +#include "llviewerdisplay.h" +#include "llviewerwindow.h" +#include "llprogressview.h" #ifdef LL_WINDOWS #pragma warning(disable:4355) #endif -extern BOOL gNoRender; +// When we receive a base grant of capabilities that has a different number of +// capabilities than the original base grant received for the region, print +// out the two lists of capabilities for analysis. +//#define DEBUG_CAPS_GRANTS -const F32 WATER_TEXTURE_SCALE = 8.f; // Number of times to repeat the water texture across a region -const S16 MAX_MAP_DIST = 10; +// The server only keeps our pending agent info for 60 seconds. +// We want to allow for seed cap retry, but its not useful after that 60 seconds. +// Give it 3 chances, each at 18 seconds to give ourselves a few seconds to connect anyways if we give up. +const S32 MAX_SEED_CAP_ATTEMPTS_BEFORE_LOGIN = 3; +const F32 CAP_REQUEST_TIMEOUT = 18; +// Even though we gave up on login, keep trying for caps after we are logged in: +const S32 MAX_CAP_REQUEST_ATTEMPTS = 30; +const U32 DEFAULT_MAX_REGION_WIDE_PRIM_COUNT = 15000; + +BOOL LLViewerRegion::sVOCacheCullingEnabled = FALSE; +S32 LLViewerRegion::sLastCameraUpdated = 0; +S32 LLViewerRegion::sNewObjectCreationThrottle = -1; + +typedef std::map<std::string, std::string> CapabilityMap; + +static void log_capabilities(const CapabilityMap &capmap); + +class LLViewerRegionImpl { +public: + LLViewerRegionImpl(LLViewerRegion * region, LLHost const & host) + : mHost(host), + mCompositionp(NULL), + mEventPoll(NULL), + mSeedCapMaxAttempts(MAX_CAP_REQUEST_ATTEMPTS), + mSeedCapMaxAttemptsBeforeLogin(MAX_SEED_CAP_ATTEMPTS_BEFORE_LOGIN), + mSeedCapAttempts(0), + mHttpResponderID(0), + mLastCameraUpdate(0), + mLastCameraOrigin(), + mVOCachePartition(NULL), + mLandp(NULL), + // I'd prefer to set the LLCapabilityListener name to match the region + // name -- it's disappointing that's not available at construction time. + // We could instead store an LLCapabilityListener*, making + // setRegionNameAndZone() replace the instance. Would that pose + // consistency problems? Can we even request a capability before calling + // setRegionNameAndZone()? + // For testability -- the new Michael Feathers paradigm -- + // LLCapabilityListener binds all the globals it expects to need at + // construction time. + mCapabilityListener(host.getString(), gMessageSystem, *region, + gAgent.getID(), gAgent.getSessionID()) + {} + + void buildCapabilityNames(LLSD& capabilityNames); + + // The surfaces and other layers + LLSurface* mLandp; + + // Region geometry data + LLVector3d mOriginGlobal; // Location of southwest corner of region (meters) + LLVector3d mCenterGlobal; // Location of center in world space (meters) + LLHost mHost; + + // The unique ID for this region. + LLUUID mRegionID; + + // region/estate owner - usually null. + LLUUID mOwnerID; + + // Network statistics for the region's circuit... + LLTimer mLastNetUpdate; + + // Misc + LLVLComposition *mCompositionp; // Composition layer for the surface + + LLVOCacheEntry::vocache_entry_map_t mCacheMap; //all cached entries + LLVOCacheEntry::vocache_entry_set_t mActiveSet; //all active entries; + LLVOCacheEntry::vocache_entry_set_t mWaitingSet; //entries waiting for LLDrawable to be generated. + std::set< LLPointer<LLViewerOctreeGroup> > mVisibleGroups; //visible groupa + LLVOCachePartition* mVOCachePartition; + LLVOCacheEntry::vocache_entry_set_t mVisibleEntries; //must-be-created visible entries wait for objects creation. + LLVOCacheEntry::vocache_entry_priority_list_t mWaitingList; //transient list storing sorted visible entries waiting for object creation. + std::set<U32> mNonCacheableCreatedList; //list of local ids of all non-cacheable objects + + // time? + // LRU info? + + // Cache ID is unique per-region, across renames, moving locations, + // etc. + LLUUID mCacheID; + + CapabilityMap mCapabilities; + CapabilityMap mSecondCapabilitiesTracker; + + LLEventPoll* mEventPoll; + + S32 mSeedCapMaxAttempts; + S32 mSeedCapMaxAttemptsBeforeLogin; + S32 mSeedCapAttempts; + + S32 mHttpResponderID; + + /// Post an event to this LLCapabilityListener to invoke a capability message on + /// this LLViewerRegion's server + /// (https://wiki.lindenlab.com/wiki/Viewer:Messaging/Messaging_Notes#Capabilities) + LLCapabilityListener mCapabilityListener; + + //spatial partitions for objects in this region + std::vector<LLViewerOctreePartition*> mObjectPartition; + + LLVector3 mLastCameraOrigin; + U32 mLastCameraUpdate; +}; // support for secondlife:///app/region/{REGION} SLapps // N.B. this is defined to work exactly like the classic secondlife://{REGION} @@ -110,7 +226,7 @@ public: } // Process the SLapp as if it was a secondlife://{PLACE} SLurl - LLURLDispatcher::dispatch(url, web, true); + LLURLDispatcher::dispatch(url, "clicked", web, true); return true; } }; @@ -120,54 +236,65 @@ class BaseCapabilitiesComplete : public LLHTTPClient::Responder { LOG_CLASS(BaseCapabilitiesComplete); public: - BaseCapabilitiesComplete(LLViewerRegion* region) - : mRegion(region) - { } + BaseCapabilitiesComplete(U64 region_handle, S32 id) + : mRegionHandle(region_handle), mID(id) + { } virtual ~BaseCapabilitiesComplete() + { } + + static BaseCapabilitiesComplete* build( U64 region_handle, S32 id ) { - if(mRegion) - { - mRegion->setHttpResponderPtrNULL() ; - } + return new BaseCapabilitiesComplete(region_handle, id); } - void setRegion(LLViewerRegion* region) +private: + /* virtual */void httpFailure() { - mRegion = region ; + LL_WARNS("AppInit", "Capabilities") << dumpResponse() << LL_ENDL; + LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); + if (regionp) + { + regionp->failedSeedCapability(); + } } - void error(U32 statusNum, const std::string& reason) - { - LL_WARNS2("AppInit", "Capabilities") << statusNum << ": " << reason << LL_ENDL; - - if (STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState()) + /* virtual */ void httpSuccess() + { + LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); + if(!regionp) //region was removed { - LLStartUp::setStartupState( STATE_SEED_CAP_GRANTED ); + LL_WARNS("AppInit", "Capabilities") << "Received results for region that no longer exists!" << LL_ENDL; + return ; } - } - - void result(const LLSD& content) - { - if(!mRegion || LLHTTPClient::ResponderPtr(this) != mRegion->getHttpResponderPtr()) //region is removed or responder is not created. + if( mID != regionp->getHttpResponderID() ) // region is no longer referring to this responder { + LL_WARNS("AppInit", "Capabilities") << "Received results for a stale http responder!" << LL_ENDL; + regionp->failedSeedCapability(); return ; } + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } LLSD::map_const_iterator iter; for(iter = content.beginMap(); iter != content.endMap(); ++iter) { - mRegion->setCapability(iter->first, iter->second); - LL_DEBUGS2("AppInit", "Capabilities") << "got capability for " - << iter->first << LL_ENDL; + regionp->setCapability(iter->first, iter->second); + + LL_DEBUGS("AppInit", "Capabilities") + << "Capability '" << iter->first << "' is '" << iter->second << "'" << LL_ENDL; /* HACK we're waiting for the ServerReleaseNotes */ - if (iter->first == "ServerReleaseNotes" && mRegion->getReleaseNotesRequested()) + if (iter->first == "ServerReleaseNotes" && regionp->getReleaseNotesRequested()) { - mRegion->showReleaseNotes(); + regionp->showReleaseNotes(); } } - mRegion->setCapabilitiesReceived(true); + regionp->setCapabilitiesReceived(true); if (STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState()) { @@ -175,15 +302,97 @@ public: } } - static boost::intrusive_ptr<BaseCapabilitiesComplete> build( - LLViewerRegion* region) - { - return boost::intrusive_ptr<BaseCapabilitiesComplete>( - new BaseCapabilitiesComplete(region)); - } +private: + U64 mRegionHandle; + S32 mID; +}; + +class BaseCapabilitiesCompleteTracker : public LLHTTPClient::Responder +{ + LOG_CLASS(BaseCapabilitiesCompleteTracker); +public: + BaseCapabilitiesCompleteTracker( U64 region_handle) + : mRegionHandle(region_handle) + { } + + virtual ~BaseCapabilitiesCompleteTracker() + { } + + static BaseCapabilitiesCompleteTracker* build( U64 region_handle ) + { + return new BaseCapabilitiesCompleteTracker( region_handle ); + } + +private: + /* virtual */ void httpFailure() + { + LL_WARNS() << dumpResponse() << LL_ENDL; + } + + /* virtual */ void httpSuccess() + { + LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); + if( !regionp ) + { + LL_WARNS("AppInit", "Capabilities") << "Received results for region that no longer exists!" << LL_ENDL; + return ; + } + + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } + LLSD::map_const_iterator iter; + for(iter = content.beginMap(); iter != content.endMap(); ++iter) + { + regionp->setCapabilityDebug(iter->first, iter->second); + //LL_INFOS()<<"BaseCapabilitiesCompleteTracker New Caps "<<iter->first<<" "<< iter->second<<LL_ENDL; + } + + if ( regionp->getRegionImpl()->mCapabilities.size() != regionp->getRegionImpl()->mSecondCapabilitiesTracker.size() ) + { + LL_WARNS("AppInit", "Capabilities") + << "Sim sent duplicate base caps that differ in size from what we initially received - most likely content. " + << "mCapabilities == " << regionp->getRegionImpl()->mCapabilities.size() + << " mSecondCapabilitiesTracker == " << regionp->getRegionImpl()->mSecondCapabilitiesTracker.size() + << LL_ENDL; +#ifdef DEBUG_CAPS_GRANTS + LL_WARNS("AppInit", "Capabilities") + << "Initial Base capabilities: " << LL_ENDL; + + log_capabilities(regionp->getRegionImpl()->mCapabilities); + + LL_WARNS("AppInit", "Capabilities") + << "Latest base capabilities: " << LL_ENDL; + + log_capabilities(regionp->getRegionImpl()->mSecondCapabilitiesTracker); + +#endif + + if (regionp->getRegionImpl()->mSecondCapabilitiesTracker.size() > regionp->getRegionImpl()->mCapabilities.size() ) + { + // *HACK Since we were granted more base capabilities in this grant request than the initial, replace + // the old with the new. This shouldn't happen i.e. we should always get the same capabilities from a + // sim. The simulator fix from SH-3895 should prevent it from happening, at least in the case of the + // inventory api capability grants. + + // Need to clear a std::map before copying into it because old keys take precedence. + regionp->getRegionImplNC()->mCapabilities.clear(); + regionp->getRegionImplNC()->mCapabilities = regionp->getRegionImpl()->mSecondCapabilitiesTracker; + } + } + else + { + LL_DEBUGS("CrossingCaps") << "Sim sent multiple base cap grants with matching sizes." << LL_ENDL; + } + regionp->getRegionImplNC()->mSecondCapabilitiesTracker.clear(); + } + private: - LLViewerRegion* mRegion; + U64 mRegionHandle; }; @@ -192,19 +401,18 @@ LLViewerRegion::LLViewerRegion(const U64 &handle, const U32 grids_per_region_edge, const U32 grids_per_patch_edge, const F32 region_width_meters) -: mCenterGlobal(), +: mImpl(new LLViewerRegionImpl(this, host)), mHandle(handle), - mHost( host ), mTimeDilation(1.0f), mName(""), mZoning(""), - mOwnerID(), mIsEstateManager(FALSE), - mCompositionp(NULL), mRegionFlags( REGION_FLAGS_DEFAULT ), + mRegionProtocols( 0 ), mSimAccess( SIM_ACCESS_MIN ), mBillableFactor(1.0), mMaxTasks(DEFAULT_MAX_REGION_WIDE_PRIM_COUNT), + mCentralBakeVersion(1), mClassID(0), mCPURatio(0), mColoName("unknown"), @@ -213,49 +421,37 @@ LLViewerRegion::LLViewerRegion(const U64 &handle, mHttpUrl(""), mCacheLoaded(FALSE), mCacheDirty(FALSE), - mCacheID(), - mEventPoll(NULL), mReleaseNotesRequested(FALSE), - // I'd prefer to set the LLCapabilityListener name to match the region - // name -- it's disappointing that's not available at construction time. - // We could instead store an LLCapabilityListener*, making - // setRegionNameAndZone() replace the instance. Would that pose - // consistency problems? Can we even request a capability before calling - // setRegionNameAndZone()? - // For testability -- the new Michael Feathers paradigm -- - // LLCapabilityListener binds all the globals it expects to need at - // construction time. - mCapabilityListener(host.getString(), gMessageSystem, *this, - gAgent.getID(), gAgent.getSessionID()), - mCapabilitiesReceived(false) + mCapabilitiesReceived(false), + mSimulatorFeaturesReceived(false), + mBitsReceived(0.f), + mPacketsReceived(0.f), + mDead(FALSE), + mLastVisitedEntry(NULL), + mInvisibilityCheckHistory(-1), + mPaused(FALSE) { mWidth = region_width_meters; - mOriginGlobal = from_region_handle(handle); + mImpl->mOriginGlobal = from_region_handle(handle); updateRenderMatrix(); - mLandp = new LLSurface('l', NULL); - if (!gNoRender) - { - // Create the composition layer for the surface - mCompositionp = new LLVLComposition(mLandp, grids_per_region_edge, region_width_meters/grids_per_region_edge); - mCompositionp->setSurface(mLandp); + mImpl->mLandp = new LLSurface('l', NULL); - // Create the surfaces - mLandp->setRegion(this); - mLandp->create(grids_per_region_edge, - grids_per_patch_edge, - mOriginGlobal, - mWidth); - } + // Create the composition layer for the surface + mImpl->mCompositionp = + new LLVLComposition(mImpl->mLandp, + grids_per_region_edge, + region_width_meters / grids_per_region_edge); + mImpl->mCompositionp->setSurface(mImpl->mLandp); - if (!gNoRender) - { - mParcelOverlay = new LLViewerParcelOverlay(this, region_width_meters); - } - else - { - mParcelOverlay = NULL; - } + // Create the surfaces + mImpl->mLandp->setRegion(this); + mImpl->mLandp->create(grids_per_region_edge, + grids_per_patch_edge, + mImpl->mOriginGlobal, + mWidth); + + mParcelOverlay = new LLViewerParcelOverlay(this, region_width_meters); setOriginGlobal(from_region_handle(handle)); calculateCenterGlobal(); @@ -265,67 +461,94 @@ LLViewerRegion::LLViewerRegion(const U64 &handle, //create object partitions //MUST MATCH declaration of eObjectPartitions - mObjectPartition.push_back(new LLHUDPartition()); //PARTITION_HUD - mObjectPartition.push_back(new LLTerrainPartition()); //PARTITION_TERRAIN - mObjectPartition.push_back(new LLVoidWaterPartition()); //PARTITION_VOIDWATER - mObjectPartition.push_back(new LLWaterPartition()); //PARTITION_WATER - mObjectPartition.push_back(new LLTreePartition()); //PARTITION_TREE - mObjectPartition.push_back(new LLParticlePartition()); //PARTITION_PARTICLE - mObjectPartition.push_back(new LLCloudPartition()); //PARTITION_CLOUD - mObjectPartition.push_back(new LLGrassPartition()); //PARTITION_GRASS - mObjectPartition.push_back(new LLVolumePartition()); //PARTITION_VOLUME - mObjectPartition.push_back(new LLBridgePartition()); //PARTITION_BRIDGE - mObjectPartition.push_back(new LLHUDParticlePartition());//PARTITION_HUD_PARTICLE - mObjectPartition.push_back(NULL); //PARTITION_NONE + mImpl->mObjectPartition.push_back(new LLHUDPartition(this)); //PARTITION_HUD + mImpl->mObjectPartition.push_back(new LLTerrainPartition(this)); //PARTITION_TERRAIN + mImpl->mObjectPartition.push_back(new LLVoidWaterPartition(this)); //PARTITION_VOIDWATER + mImpl->mObjectPartition.push_back(new LLWaterPartition(this)); //PARTITION_WATER + mImpl->mObjectPartition.push_back(new LLTreePartition(this)); //PARTITION_TREE + mImpl->mObjectPartition.push_back(new LLParticlePartition(this)); //PARTITION_PARTICLE + mImpl->mObjectPartition.push_back(new LLGrassPartition(this)); //PARTITION_GRASS + mImpl->mObjectPartition.push_back(new LLVolumePartition(this)); //PARTITION_VOLUME + mImpl->mObjectPartition.push_back(new LLBridgePartition(this)); //PARTITION_BRIDGE + mImpl->mObjectPartition.push_back(new LLHUDParticlePartition(this));//PARTITION_HUD_PARTICLE + mImpl->mObjectPartition.push_back(new LLVOCachePartition(this)); //PARTITION_VO_CACHE + mImpl->mObjectPartition.push_back(NULL); //PARTITION_NONE + mImpl->mVOCachePartition = getVOCachePartition(); + + mRenderInfoRequestTimer.resetWithExpiry(0.f); // Set timer to be expired + setCapabilitiesReceivedCallback(boost::bind(&LLAvatarRenderInfoAccountant::expireRenderInfoReportTimer, _1)); } void LLViewerRegion::initStats() { - mLastNetUpdate.reset(); + mImpl->mLastNetUpdate.reset(); mPacketsIn = 0; - mBitsIn = 0; - mLastBitsIn = 0; + mBitsIn = (U32Bits)0; + mLastBitsIn = (U32Bits)0; mLastPacketsIn = 0; mPacketsOut = 0; mLastPacketsOut = 0; mPacketsLost = 0; mLastPacketsLost = 0; - mPingDelay = 0; + mPingDelay = (U32Seconds)0; mAlive = false; // can become false if circuit disconnects } LLViewerRegion::~LLViewerRegion() { - if(mHttpResponderPtr) - { - (static_cast<BaseCapabilitiesComplete*>(mHttpResponderPtr.get()))->setRegion(NULL) ; - } + mDead = TRUE; + mImpl->mActiveSet.clear(); + mImpl->mVisibleEntries.clear(); + mImpl->mVisibleGroups.clear(); + mImpl->mWaitingSet.clear(); gVLManager.cleanupData(this); // Can't do this on destruction, because the neighbor pointers might be invalid. // This should be reference counted... disconnectAllNeighbors(); - mCloudLayer.destroy(); LLViewerPartSim::getInstance()->cleanupRegion(this); gObjectList.killObjects(this); - delete mCompositionp; + delete mImpl->mCompositionp; delete mParcelOverlay; - delete mLandp; - delete mEventPoll; - LLHTTPSender::clearSender(mHost); + delete mImpl->mLandp; + delete mImpl->mEventPoll; + LLHTTPSender::clearSender(mImpl->mHost); + std::for_each(mImpl->mObjectPartition.begin(), mImpl->mObjectPartition.end(), DeletePointer()); + saveObjectCache(); - std::for_each(mObjectPartition.begin(), mObjectPartition.end(), DeletePointer()); + delete mImpl; + mImpl = NULL; +} + +LLEventPump& LLViewerRegion::getCapAPI() const +{ + return mImpl->mCapabilityListener.getCapAPI(); } /*virtual*/ const LLHost& LLViewerRegion::getHost() const { - return mHost; + return mImpl->mHost; +} + +LLSurface & LLViewerRegion::getLand() const +{ + return *mImpl->mLandp; +} + +const LLUUID& LLViewerRegion::getRegionID() const +{ + return mImpl->mRegionID; +} + +void LLViewerRegion::setRegionID(const LLUUID& region_id) +{ + mImpl->mRegionID = region_id; } void LLViewerRegion::loadObjectCache() @@ -338,9 +561,13 @@ void LLViewerRegion::loadObjectCache() // Presume success. If it fails, we don't want to try again. mCacheLoaded = TRUE; - if(LLVOCache::hasInstance()) + if(LLVOCache::instanceExists()) { - LLVOCache::getInstance()->readFromCache(mHandle, mCacheID, mCacheMap) ; + LLVOCache::getInstance()->readFromCache(mHandle, mImpl->mCacheID, mImpl->mCacheMap) ; + if (mImpl->mCacheMap.empty()) + { + mCacheDirty = TRUE; + } } } @@ -352,62 +579,49 @@ void LLViewerRegion::saveObjectCache() return; } - if (mCacheMap.empty()) + if (mImpl->mCacheMap.empty()) { return; } - if(LLVOCache::hasInstance()) + if(LLVOCache::instanceExists()) { - LLVOCache::getInstance()->writeToCache(mHandle, mCacheID, mCacheMap, mCacheDirty) ; + const F32 start_time_threshold = 600.0f; //seconds + bool removal_enabled = sVOCacheCullingEnabled && (mRegionTimer.getElapsedTimeF32() > start_time_threshold); //allow to remove invalid objects from object cache file. + + LLVOCache::getInstance()->writeToCache(mHandle, mImpl->mCacheID, mImpl->mCacheMap, mCacheDirty, removal_enabled) ; mCacheDirty = FALSE; } - for(LLVOCacheEntry::vocache_entry_map_t::iterator iter = mCacheMap.begin(); iter != mCacheMap.end(); ++iter) - { - delete iter->second; - } - mCacheMap.clear(); + mImpl->mCacheMap.clear(); } void LLViewerRegion::sendMessage() { - gMessageSystem->sendMessage(mHost); + gMessageSystem->sendMessage(mImpl->mHost); } void LLViewerRegion::sendReliableMessage() { - gMessageSystem->sendReliable(mHost); -} - -void LLViewerRegion::setFlags(BOOL b, U32 flags) -{ - if (b) - { - mRegionFlags |= flags; - } - else - { - mRegionFlags &= ~flags; - } + gMessageSystem->sendReliable(mImpl->mHost); } void LLViewerRegion::setWaterHeight(F32 water_level) { - mLandp->setWaterHeight(water_level); + mImpl->mLandp->setWaterHeight(water_level); } F32 LLViewerRegion::getWaterHeight() const { - return mLandp->getWaterHeight(); + return mImpl->mLandp->getWaterHeight(); } BOOL LLViewerRegion::isVoiceEnabled() const { - return (getRegionFlags() & REGION_FLAGS_ALLOW_VOICE); + return getRegionFlag(REGION_FLAGS_ALLOW_VOICE); } -void LLViewerRegion::setRegionFlags(U32 flags) +void LLViewerRegion::setRegionFlags(U64 flags) { mRegionFlags = flags; } @@ -415,11 +629,10 @@ void LLViewerRegion::setRegionFlags(U32 flags) void LLViewerRegion::setOriginGlobal(const LLVector3d &origin_global) { - mOriginGlobal = origin_global; + mImpl->mOriginGlobal = origin_global; updateRenderMatrix(); - mLandp->setOriginGlobal(origin_global); + mImpl->mLandp->setOriginGlobal(origin_global); mWind.setOriginGlobal(origin_global); - mCloudLayer.setOriginGlobal(origin_global); calculateCenterGlobal(); } @@ -433,16 +646,34 @@ void LLViewerRegion::setTimeDilation(F32 time_dilation) mTimeDilation = time_dilation; } +const LLVector3d & LLViewerRegion::getOriginGlobal() const +{ + return mImpl->mOriginGlobal; +} LLVector3 LLViewerRegion::getOriginAgent() const { - return gAgent.getPosAgentFromGlobal(mOriginGlobal); + return gAgent.getPosAgentFromGlobal(mImpl->mOriginGlobal); } +const LLVector3d & LLViewerRegion::getCenterGlobal() const +{ + return mImpl->mCenterGlobal; +} LLVector3 LLViewerRegion::getCenterAgent() const { - return gAgent.getPosAgentFromGlobal(mCenterGlobal); + return gAgent.getPosAgentFromGlobal(mImpl->mCenterGlobal); +} + +void LLViewerRegion::setOwner(const LLUUID& owner_id) +{ + mImpl->mOwnerID = owner_id; +} + +const LLUUID& LLViewerRegion::getOwner() const +{ + return mImpl->mOwnerID; } void LLViewerRegion::setRegionNameAndZone (const std::string& name_zone) @@ -476,9 +707,14 @@ const std::string LLViewerRegion::getSimAccessString() const return accessToString(mSimAccess); } +std::string LLViewerRegion::getLocalizedSimProductName() const +{ + std::string localized_spn; + return LLTrans::findString(localized_spn, mProductName) ? localized_spn : mProductName; +} // static -std::string LLViewerRegion::regionFlagsToString(U32 flags) +std::string LLViewerRegion::regionFlagsToString(U64 flags) { std::string result; @@ -559,15 +795,46 @@ std::string LLViewerRegion::accessToShortString(U8 sim_access) } // static +U8 LLViewerRegion::shortStringToAccess(const std::string &sim_access) +{ + U8 accessValue; + + if (LLStringUtil::compareStrings(sim_access, "PG") == 0) + { + accessValue = SIM_ACCESS_PG; + } + else if (LLStringUtil::compareStrings(sim_access, "M") == 0) + { + accessValue = SIM_ACCESS_MATURE; + } + else if (LLStringUtil::compareStrings(sim_access, "A") == 0) + { + accessValue = SIM_ACCESS_ADULT; + } + else + { + accessValue = SIM_ACCESS_MIN; + } + + return accessValue; +} + +// static void LLViewerRegion::processRegionInfo(LLMessageSystem* msg, void**) { // send it to 'observers' + // *TODO: switch the floaters to using LLRegionInfoModel + LL_INFOS() << "Processing region info" << LL_ENDL; + LLRegionInfoModel::instance().update(msg); LLFloaterGodTools::processRegionInfo(msg); LLFloaterRegionInfo::processRegionInfo(msg); LLFloaterReporter::processRegionInfo(msg); } - +void LLViewerRegion::setCacheID(const LLUUID& id) +{ + mImpl->mCacheID = id; +} S32 LLViewerRegion::renderPropertyLines() { @@ -591,11 +858,459 @@ void LLViewerRegion::dirtyHeights() } } -BOOL LLViewerRegion::idleUpdate(F32 max_update_time) +//physically delete the cache entry +void LLViewerRegion::killCacheEntry(LLVOCacheEntry* entry, bool for_rendering) +{ + if(!entry || !entry->isValid()) + { + return; + } + + if(for_rendering && !entry->isState(LLVOCacheEntry::ACTIVE)) + { + addNewObject(entry); //force to add to rendering pipeline + } + + //remove from active list and waiting list + if(entry->isState(LLVOCacheEntry::ACTIVE)) + { + mImpl->mActiveSet.erase(entry); + } + else + { + if(entry->isState(LLVOCacheEntry::WAITING)) + { + mImpl->mWaitingSet.erase(entry); + } + + //remove from mVOCachePartition + removeFromVOCacheTree(entry); + } + + //remove from the forced visible list + mImpl->mVisibleEntries.erase(entry); + + //disconnect from parent if it is a child + if(entry->getParentID() > 0) + { + LLVOCacheEntry* parent = getCacheEntry(entry->getParentID()); + if(parent) + { + parent->removeChild(entry); + } + } + else if(entry->getNumOfChildren() > 0)//remove children from cache if has any + { + LLVOCacheEntry* child = entry->getChild(); + while(child != NULL) + { + killCacheEntry(child, for_rendering); + child = entry->getChild(); + } + } + + //will remove it from the object cache, real deletion + entry->setState(LLVOCacheEntry::INACTIVE); + entry->removeOctreeEntry(); + entry->setValid(FALSE); +} + +//physically delete the cache entry +void LLViewerRegion::killCacheEntry(U32 local_id) { - LLMemType mt_ivr(LLMemType::MTYPE_IDLE_UPDATE_VIEWER_REGION); - // did_update returns TRUE if we did at least one significant update - BOOL did_update = mLandp->idleUpdate(max_update_time); + killCacheEntry(getCacheEntry(local_id)); +} + +U32 LLViewerRegion::getNumOfActiveCachedObjects() const +{ + return mImpl->mActiveSet.size(); +} + +void LLViewerRegion::addActiveCacheEntry(LLVOCacheEntry* entry) +{ + if(!entry || mDead) + { + return; + } + if(entry->isState(LLVOCacheEntry::ACTIVE)) + { + return; //already inserted. + } + + if(entry->isState(LLVOCacheEntry::WAITING)) + { + mImpl->mWaitingSet.erase(entry); + } + + entry->setState(LLVOCacheEntry::ACTIVE); + entry->setVisible(); + + llassert(entry->getEntry()->hasDrawable()); + mImpl->mActiveSet.insert(entry); +} + +void LLViewerRegion::removeActiveCacheEntry(LLVOCacheEntry* entry, LLDrawable* drawablep) +{ + if(mDead || !entry || !entry->isValid()) + { + return; + } + if(!entry->isState(LLVOCacheEntry::ACTIVE)) + { + return; //not an active entry. + } + + //shift to the local regional space from agent space + if(drawablep != NULL && drawablep->getVObj().notNull()) + { + const LLVector3& pos = drawablep->getVObj()->getPositionRegion(); + LLVector4a shift; + shift.load3(pos.mV); + shift.sub(entry->getPositionGroup()); + entry->shift(shift); + } + + if(entry->getParentID() > 0) //is a child + { + LLVOCacheEntry* parent = getCacheEntry(entry->getParentID()); + if(parent) + { + parent->addChild(entry); + } + else //parent not in cache. + { + //this happens only when parent is not cacheable. + mOrphanMap[entry->getParentID()].push_back(entry->getLocalID()); + } + } + else //insert to vo cache tree. + { + entry->updateParentBoundingInfo(); + entry->saveBoundingSphere(); + addToVOCacheTree(entry); + } + + mImpl->mVisibleEntries.erase(entry); + mImpl->mActiveSet.erase(entry); + mImpl->mWaitingSet.erase(entry); + entry->setState(LLVOCacheEntry::INACTIVE); +} + +bool LLViewerRegion::addVisibleGroup(LLViewerOctreeGroup* group) +{ + if(mDead || group->isEmpty()) + { + return false; + } + + mImpl->mVisibleGroups.insert(group); + + return true; +} + +U32 LLViewerRegion::getNumOfVisibleGroups() const +{ + return mImpl ? mImpl->mVisibleGroups.size() : 0; +} + +void LLViewerRegion::addToVOCacheTree(LLVOCacheEntry* entry) +{ + if(!sVOCacheCullingEnabled) + { + return; + } + + if(mDead || !entry || !entry->getEntry() || !entry->isValid()) + { + return; + } + if(entry->getParentID() > 0) + { + return; //no child prim in cache octree. + } + + if(entry->hasState(LLVOCacheEntry::IN_VO_TREE)) + { + return; //already in the tree. + } + + llassert_always(!entry->getGroup()); //not in octree. + llassert(!entry->getEntry()->hasDrawable()); //not have drawables + + if(mImpl->mVOCachePartition->addEntry(entry->getEntry())) + { + entry->setState(LLVOCacheEntry::IN_VO_TREE); + } +} + +void LLViewerRegion::removeFromVOCacheTree(LLVOCacheEntry* entry) +{ + if(mDead || !entry || !entry->getEntry()) + { + return; + } + + if(!entry->hasState(LLVOCacheEntry::IN_VO_TREE)) + { + return; //not in the tree. + } + entry->clearState(LLVOCacheEntry::IN_VO_TREE); + + mImpl->mVOCachePartition->removeEntry(entry->getEntry()); +} + +//add child objects as visible entries +void LLViewerRegion::addVisibleChildCacheEntry(LLVOCacheEntry* parent, LLVOCacheEntry* child) +{ + if(mDead) + { + return; + } + + if(parent && (!parent->isValid() || !parent->isState(LLVOCacheEntry::ACTIVE))) + { + return; //parent must be valid and in rendering pipeline + } + + if(child && (!child->getEntry() || !child->isValid() || !child->isState(LLVOCacheEntry::INACTIVE))) + { + return; //child must be valid and not in the rendering pipeline + } + + if(child) + { + child->setState(LLVOCacheEntry::IN_QUEUE); + mImpl->mVisibleEntries.insert(child); + } + else if(parent && parent->getNumOfChildren() > 0) //add all children + { + child = parent->getChild(); + while(child != NULL) + { + addVisibleChildCacheEntry(NULL, child); + child = parent->getChild(); + } + } +} + +void LLViewerRegion::updateVisibleEntries(F32 max_time) +{ + if(mDead) + { + return; + } + + if(mImpl->mVisibleGroups.empty() && mImpl->mVisibleEntries.empty()) + { + return; + } + + if(!sNewObjectCreationThrottle) + { + return; + } + + const F32 LARGE_SCENE_CONTRIBUTION = 1000.f; //a large number to force to load the object. + const LLVector3 camera_origin = LLViewerCamera::getInstance()->getOrigin(); + const U32 cur_frame = LLViewerOctreeEntryData::getCurrentFrame(); + bool needs_update = ((cur_frame - mImpl->mLastCameraUpdate) > 5) && ((camera_origin - mImpl->mLastCameraOrigin).lengthSquared() > 10.f); + U32 last_update = mImpl->mLastCameraUpdate; + LLVector4a local_origin; + local_origin.load3((camera_origin - getOriginAgent()).mV); + + //process visible entries + for(LLVOCacheEntry::vocache_entry_set_t::iterator iter = mImpl->mVisibleEntries.begin(); iter != mImpl->mVisibleEntries.end();) + { + LLVOCacheEntry* vo_entry = *iter; + + if(vo_entry->isValid() && vo_entry->getState() < LLVOCacheEntry::WAITING) + { + //set a large number to force to load this object. + vo_entry->setSceneContribution(LARGE_SCENE_CONTRIBUTION); + + mImpl->mWaitingList.insert(vo_entry); + ++iter; + } + else + { + LLVOCacheEntry::vocache_entry_set_t::iterator next_iter = iter; + ++next_iter; + mImpl->mVisibleEntries.erase(iter); + iter = next_iter; + } + } + + // + //process visible groups + // + //object projected area threshold + F32 projection_threshold = LLVOCacheEntry::getSquaredPixelThreshold(mImpl->mVOCachePartition->isFrontCull()); + F32 dist_threshold = mImpl->mVOCachePartition->isFrontCull() ? gAgentCamera.mDrawDistance : LLVOCacheEntry::sRearFarRadius; + + std::set< LLPointer<LLViewerOctreeGroup> >::iterator group_iter = mImpl->mVisibleGroups.begin(); + for(; group_iter != mImpl->mVisibleGroups.end(); ++group_iter) + { + LLPointer<LLViewerOctreeGroup> group = *group_iter; + if(group->getNumRefs() < 3 || //group to be deleted + !group->getOctreeNode() || group->isEmpty()) //group empty +{ + continue; + } + + for (LLViewerOctreeGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i) + { + if((*i)->hasVOCacheEntry()) + { + LLVOCacheEntry* vo_entry = (LLVOCacheEntry*)(*i)->getVOCacheEntry(); + + if(vo_entry->getParentID() > 0) //is a child + { + //child visibility depends on its parent. + continue; + } + if(!vo_entry->isValid()) + { + continue; //skip invalid entry. + } + + vo_entry->calcSceneContribution(local_origin, needs_update, last_update, dist_threshold); + if(vo_entry->getSceneContribution() > projection_threshold) + { + mImpl->mWaitingList.insert(vo_entry); + } + } + } + } + + if(needs_update) + { + mImpl->mLastCameraOrigin = camera_origin; + mImpl->mLastCameraUpdate = cur_frame; + } + + return; +} + +void LLViewerRegion::createVisibleObjects(F32 max_time) +{ + if(mDead) + { + return; + } + if(mImpl->mWaitingList.empty()) + { + mImpl->mVOCachePartition->setCullHistory(FALSE); + return; + } + + S32 throttle = sNewObjectCreationThrottle; + BOOL has_new_obj = FALSE; + LLTimer update_timer; + for(LLVOCacheEntry::vocache_entry_priority_list_t::iterator iter = mImpl->mWaitingList.begin(); + iter != mImpl->mWaitingList.end(); ++iter) + { + LLVOCacheEntry* vo_entry = *iter; + + if(vo_entry->getState() < LLVOCacheEntry::WAITING) + { + addNewObject(vo_entry); + has_new_obj = TRUE; + if(throttle > 0 && !(--throttle) && update_timer.getElapsedTimeF32() > max_time) + { + break; + } + } + } + + mImpl->mVOCachePartition->setCullHistory(has_new_obj); + + return; +} + +void LLViewerRegion::clearCachedVisibleObjects() +{ + mImpl->mWaitingList.clear(); + mImpl->mVisibleGroups.clear(); + + //reset all occluders + mImpl->mVOCachePartition->resetOccluders(); + mPaused = TRUE; + + //clean visible entries + for(LLVOCacheEntry::vocache_entry_set_t::iterator iter = mImpl->mVisibleEntries.begin(); iter != mImpl->mVisibleEntries.end();) + { + LLVOCacheEntry* entry = *iter; + LLVOCacheEntry* parent = getCacheEntry(entry->getParentID()); + + if(!entry->getParentID() || parent) //no child or parent is cache-able + { + if(parent) //has a cache-able parent + { + parent->addChild(entry); + } + + LLVOCacheEntry::vocache_entry_set_t::iterator next_iter = iter; + ++next_iter; + mImpl->mVisibleEntries.erase(iter); + iter = next_iter; + } + else //parent is not cache-able, leave it. + { + ++iter; + } + } + + //remove all visible entries. + mLastVisitedEntry = NULL; + std::vector<LLDrawable*> delete_list; + for(LLVOCacheEntry::vocache_entry_set_t::iterator iter = mImpl->mActiveSet.begin(); + iter != mImpl->mActiveSet.end(); ++iter) + { + LLDrawable* drawablep = (LLDrawable*)(*iter)->getEntry()->getDrawable(); + + if(drawablep && !drawablep->getParent()) + { + delete_list.push_back(drawablep); + } + } + + if(!delete_list.empty()) + { + for(S32 i = 0; i < delete_list.size(); i++) + { + gObjectList.killObject(delete_list[i]->getVObj()); + } + delete_list.clear(); + } + + return; +} + +//perform some necessary but very light updates. +//to replace the function idleUpdate(...) in case there is no enough time. +void LLViewerRegion::lightIdleUpdate() +{ + if(!sVOCacheCullingEnabled) + { + return; + } + if(mImpl->mCacheMap.empty()) + { + return; + } + + //reset all occluders + mImpl->mVOCachePartition->resetOccluders(); +} + +void LLViewerRegion::idleUpdate(F32 max_update_time) +{ + LLTimer update_timer; + F32 max_time; + + mLastUpdate = LLViewerOctreeEntryData::getCurrentFrame(); + + mImpl->mLandp->idleUpdate(max_update_time); if (mParcelOverlay) { @@ -603,14 +1318,292 @@ BOOL LLViewerRegion::idleUpdate(F32 max_update_time) mParcelOverlay->idleUpdate(); } - return did_update; + if(!sVOCacheCullingEnabled) + { + return; + } + if(mImpl->mCacheMap.empty()) + { + return; + } + if(mPaused) + { + mPaused = FALSE; //unpause. + } + + LLViewerCamera::eCameraID old_camera_id = LLViewerCamera::sCurCameraID; + LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; + + //reset all occluders + mImpl->mVOCachePartition->resetOccluders(); + + max_time = max_update_time - update_timer.getElapsedTimeF32(); + + //kill invisible objects + killInvisibleObjects(max_time * 0.4f); + max_time = max_update_time - update_timer.getElapsedTimeF32(); + + updateVisibleEntries(max_time); + max_time = max_update_time - update_timer.getElapsedTimeF32(); + + createVisibleObjects(max_time); + + mImpl->mWaitingList.clear(); + mImpl->mVisibleGroups.clear(); + + LLViewerCamera::sCurCameraID = old_camera_id; + return; +} + +//update the throttling number for new object creation +void LLViewerRegion::calcNewObjectCreationThrottle() +{ + static LLCachedControl<S32> new_object_creation_throttle(gSavedSettings,"NewObjectCreationThrottle"); + static LLCachedControl<F32> throttle_delay_time(gSavedSettings,"NewObjectCreationThrottleDelayTime"); + static LLFrameTimer timer; + + // + //sNewObjectCreationThrottle = + //-2: throttle is disabled because either the screen is showing progress view, or immediate after the screen is not black + //-1: throttle is disabled by the debug setting + //0: no new object creation is allowed + //>0: valid throttling number + // + + if(gViewerWindow->getProgressView()->getVisible() && throttle_delay_time > 0.f) + { + sNewObjectCreationThrottle = -2; //cancel the throttling + timer.reset(); + } + else if(sNewObjectCreationThrottle < -1) //just recoved from the login/teleport screen + { + if(timer.getElapsedTimeF32() > throttle_delay_time) //wait for throttle_delay_time to reset the throttle + { + sNewObjectCreationThrottle = new_object_creation_throttle; //reset + if(sNewObjectCreationThrottle < -1) + { + sNewObjectCreationThrottle = -1; + } + } + } + + //update some LLVOCacheEntry debug setting factors. + LLVOCacheEntry::updateDebugSettings(); +} + +BOOL LLViewerRegion::isViewerCameraStatic() +{ + return sLastCameraUpdated < LLViewerOctreeEntryData::getCurrentFrame(); +} + +void LLViewerRegion::killInvisibleObjects(F32 max_time) +{ + if(!sVOCacheCullingEnabled) + { + return; + } + if(mImpl->mActiveSet.empty()) + { + return; + } + if(sNewObjectCreationThrottle < 0) + { + return; + } + + LLTimer update_timer; + LLVector4a camera_origin; + camera_origin.load3(LLViewerCamera::getInstance()->getOrigin().mV); + LLVector4a local_origin; + local_origin.load3((LLViewerCamera::getInstance()->getOrigin() - getOriginAgent()).mV); + F32 back_threshold = LLVOCacheEntry::sRearFarRadius; + + size_t max_update = 64; + if(!mInvisibilityCheckHistory && isViewerCameraStatic()) + { + //history is clean, reduce number of checking + max_update /= 2; + } + + std::vector<LLDrawable*> delete_list; + S32 update_counter = llmin(max_update, mImpl->mActiveSet.size()); + LLVOCacheEntry::vocache_entry_set_t::iterator iter = mImpl->mActiveSet.upper_bound(mLastVisitedEntry); + + for(; update_counter > 0; --update_counter, ++iter) + { + if(iter == mImpl->mActiveSet.end()) + { + iter = mImpl->mActiveSet.begin(); + } + if((*iter)->getParentID() > 0) + { + continue; //skip child objects, they are removed with their parent. + } + + LLVOCacheEntry* vo_entry = *iter; + if(!vo_entry->isAnyVisible(camera_origin, local_origin, back_threshold) && vo_entry->mLastCameraUpdated < sLastCameraUpdated) + { + killObject(vo_entry, delete_list); + } + + if(max_time < update_timer.getElapsedTimeF32()) //time out + { + break; + } + } + + if(iter == mImpl->mActiveSet.end()) + { + mLastVisitedEntry = NULL; + } + else + { + mLastVisitedEntry = *iter; + } + + mInvisibilityCheckHistory <<= 1; + if(!delete_list.empty()) + { + mInvisibilityCheckHistory |= 1; + S32 count = delete_list.size(); + for(S32 i = 0; i < count; i++) + { + gObjectList.killObject(delete_list[i]->getVObj()); + } + delete_list.clear(); + } + + return; +} + +void LLViewerRegion::killObject(LLVOCacheEntry* entry, std::vector<LLDrawable*>& delete_list) +{ + //kill the object. + LLDrawable* drawablep = (LLDrawable*)entry->getEntry()->getDrawable(); + llassert(drawablep); + llassert(drawablep->getRegion() == this); + + if(drawablep && !drawablep->getParent()) + { + LLViewerObject* v_obj = drawablep->getVObj(); + if (v_obj->isSelected() + || (v_obj->flagAnimSource() && isAgentAvatarValid() && gAgentAvatarp->hasMotionFromSource(v_obj->getID()))) + { + // do not remove objects user is interacting with + ((LLViewerOctreeEntryData*)drawablep)->setVisible(); + return; + } + LLViewerObject::const_child_list_t& child_list = v_obj->getChildren(); + for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); + iter != child_list.end(); iter++) + { + LLViewerObject* child = *iter; + if(child->mDrawable) + { + if( !child->mDrawable->getEntry() + || !child->mDrawable->getEntry()->hasVOCacheEntry() + || child->isSelected() + || (child->flagAnimSource() && isAgentAvatarValid() && gAgentAvatarp->hasMotionFromSource(child->getID()))) + { + //do not remove parent if any of its children non-cacheable, animating or selected + //especially for the case that an avatar sits on a cache-able object + ((LLViewerOctreeEntryData*)drawablep)->setVisible(); + return; + } + + LLOcclusionCullingGroup* group = (LLOcclusionCullingGroup*)child->mDrawable->getGroup(); + if(group && group->isAnyRecentlyVisible()) + { + //set the parent visible if any of its children visible. + ((LLViewerOctreeEntryData*)drawablep)->setVisible(); + return; + } + } + } + delete_list.push_back(drawablep); + } +} + +LLViewerObject* LLViewerRegion::addNewObject(LLVOCacheEntry* entry) +{ + if(!entry || !entry->getEntry()) + { + if(entry) + { + mImpl->mVisibleEntries.erase(entry); + entry->setState(LLVOCacheEntry::INACTIVE); + } + return NULL; + } + + LLViewerObject* obj = NULL; + if(!entry->getEntry()->hasDrawable()) //not added to the rendering pipeline yet + { + //add the object + obj = gObjectList.processObjectUpdateFromCache(entry, this); + if(obj) + { + if(!entry->isState(LLVOCacheEntry::ACTIVE)) + { + mImpl->mWaitingSet.insert(entry); + entry->setState(LLVOCacheEntry::WAITING); + } + } + } + else + { + LLViewerRegion* old_regionp = ((LLDrawable*)entry->getEntry()->getDrawable())->getRegion(); + if(old_regionp != this) + { + //this object exists in two regions at the same time; + //this case can be safely ignored here because + //server should soon send update message to remove one region for this object. + + LL_WARNS() << "Entry: " << entry->getLocalID() << " exists in two regions at the same time." << LL_ENDL; + return NULL; + } + + LL_WARNS() << "Entry: " << entry->getLocalID() << " in rendering pipeline but not set to be active." << LL_ENDL; + + //should not hit here any more, but does not hurt either, just put it back to active list + addActiveCacheEntry(entry); + } + return obj; } +//update object cache if the object receives a full-update or terse update +//update_type == EObjectUpdateType::OUT_TERSE_IMPROVED or EObjectUpdateType::OUT_FULL +LLViewerObject* LLViewerRegion::updateCacheEntry(U32 local_id, LLViewerObject* objectp, U32 update_type) +{ + if(objectp && update_type != (U32)OUT_TERSE_IMPROVED) + { + return objectp; //no need to access cache + } + + LLVOCacheEntry* entry = getCacheEntry(local_id); + if (!entry) + { + return objectp; //not in the cache, do nothing. + } + if(!objectp) //object not created + { + //create a new object from cache. + objectp = addNewObject(entry); + } + + //remove from cache if terse update + if(update_type == (U32)OUT_TERSE_IMPROVED) + { + killCacheEntry(entry, true); + } + + return objectp; +} // As above, but forcibly do the update. void LLViewerRegion::forceUpdate() { - mLandp->idleUpdate(0.f); + mImpl->mLandp->idleUpdate(0.f); if (mParcelOverlay) { @@ -620,17 +1613,19 @@ void LLViewerRegion::forceUpdate() void LLViewerRegion::connectNeighbor(LLViewerRegion *neighborp, U32 direction) { - mLandp->connectNeighbor(neighborp->mLandp, direction); - mCloudLayer.connectNeighbor(&(neighborp->mCloudLayer), direction); + mImpl->mLandp->connectNeighbor(neighborp->mImpl->mLandp, direction); } void LLViewerRegion::disconnectAllNeighbors() { - mLandp->disconnectAllNeighbors(); - mCloudLayer.disconnectAllNeighbors(); + mImpl->mLandp->disconnectAllNeighbors(); } +LLVLComposition * LLViewerRegion::getComposition() const +{ + return mImpl->mCompositionp; +} F32 LLViewerRegion::getCompositionXY(const S32 x, const S32 y) const { @@ -724,10 +1719,10 @@ F32 LLViewerRegion::getCompositionXY(const S32 x, const S32 y) const void LLViewerRegion::calculateCenterGlobal() { - mCenterGlobal = mOriginGlobal; - mCenterGlobal.mdV[VX] += 0.5 * mWidth; - mCenterGlobal.mdV[VY] += 0.5 * mWidth; - mCenterGlobal.mdV[VZ] = 0.5*mLandp->getMinZ() + mLandp->getMaxZ(); + mImpl->mCenterGlobal = mImpl->mOriginGlobal; + mImpl->mCenterGlobal.mdV[VX] += 0.5 * mWidth; + mImpl->mCenterGlobal.mdV[VY] += 0.5 * mWidth; + mImpl->mCenterGlobal.mdV[VZ] = 0.5 * mImpl->mLandp->getMinZ() + mImpl->mLandp->getMaxZ(); } void LLViewerRegion::calculateCameraDistance() @@ -738,7 +1733,7 @@ void LLViewerRegion::calculateCameraDistance() std::ostream& operator<<(std::ostream &s, const LLViewerRegion ®ion) { s << "{ "; - s << region.mHost; + s << region.mImpl->mHost; s << " mOriginGlobal = " << region.getOriginGlobal()<< "\n"; std::string name(region.getName()), zone(region.getZoning()); if (! name.empty()) @@ -758,9 +1753,9 @@ std::ostream& operator<<(std::ostream &s, const LLViewerRegion ®ion) void LLViewerRegion::updateNetStats() { - F32 dt = mLastNetUpdate.getElapsedTimeAndResetF32(); + F32 dt = mImpl->mLastNetUpdate.getElapsedTimeAndResetF32(); - LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(mHost); + LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(mImpl->mHost); if (!cdp) { mAlive = false; @@ -781,18 +1776,17 @@ void LLViewerRegion::updateNetStats() mPacketsLost = cdp->getPacketsLost(); mPingDelay = cdp->getPingDelay(); - mBitStat.addValue(mBitsIn - mLastBitsIn); - mPacketsStat.addValue(mPacketsIn - mLastPacketsIn); - mPacketsLostStat.addValue(mPacketsLost); + mBitsReceived += mBitsIn - mLastBitsIn; + mPacketsReceived += mPacketsIn - mLastPacketsIn; } U32 LLViewerRegion::getPacketsLost() const { - LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(mHost); + LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(mImpl->mHost); if (!cdp) { - llinfos << "LLViewerRegion::getPacketsLost couldn't find circuit for " << mHost << llendl; + LL_INFOS() << "LLViewerRegion::getPacketsLost couldn't find circuit for " << mImpl->mHost << LL_ENDL; return 0; } else @@ -801,6 +1795,11 @@ U32 LLViewerRegion::getPacketsLost() const } } +S32 LLViewerRegion::getHttpResponderID() const +{ + return mImpl->mHttpResponderID; +} + BOOL LLViewerRegion::pointInRegionGlobal(const LLVector3d &point_global) const { LLVector3 pos_region = getPosRegionFromGlobal(point_global); @@ -827,7 +1826,7 @@ BOOL LLViewerRegion::pointInRegionGlobal(const LLVector3d &point_global) const LLVector3 LLViewerRegion::getPosRegionFromGlobal(const LLVector3d &point_global) const { LLVector3 pos_region; - pos_region.setVec(point_global - mOriginGlobal); + pos_region.setVec(point_global - mImpl->mOriginGlobal); return pos_region; } @@ -835,7 +1834,7 @@ LLVector3d LLViewerRegion::getPosGlobalFromRegion(const LLVector3 &pos_region) c { LLVector3d pos_region_d; pos_region_d.setVec(pos_region); - return pos_region_d + mOriginGlobal; + return pos_region_d + mImpl->mOriginGlobal; } LLVector3 LLViewerRegion::getPosAgentFromRegion(const LLVector3 &pos_region) const @@ -852,7 +1851,7 @@ LLVector3 LLViewerRegion::getPosRegionFromAgent(const LLVector3 &pos_agent) cons F32 LLViewerRegion::getLandHeightRegion(const LLVector3& region_pos) { - return mLandp->resolveHeightRegion( region_pos ); + return mImpl->mLandp->resolveHeightRegion( region_pos ); } bool LLViewerRegion::isAlive() @@ -900,14 +1899,14 @@ public: S32 target_index = input["body"]["Index"][0]["Prey"].asInteger(); S32 you_index = input["body"]["Index"][0]["You" ].asInteger(); - LLDynamicArray<U32>* avatar_locs = ®ion->mMapAvatars; - LLDynamicArray<LLUUID>* avatar_ids = ®ion->mMapAvatarIDs; - avatar_locs->reset(); - avatar_ids->reset(); + std::vector<U32>* avatar_locs = ®ion->mMapAvatars; + std::vector<LLUUID>* avatar_ids = ®ion->mMapAvatarIDs; + avatar_locs->clear(); + avatar_ids->clear(); - //llinfos << "coarse locations agent[0] " << input["body"]["AgentData"][0]["AgentID"].asUUID() << llendl; - //llinfos << "my agent id = " << gAgent.getID() << llendl; - //llinfos << ll_pretty_print_sd(input) << llendl; + //LL_INFOS() << "coarse locations agent[0] " << input["body"]["AgentData"][0]["AgentID"].asUUID() << LL_ENDL; + //LL_INFOS() << "my agent id = " << gAgent.getID() << LL_ENDL; + //LL_INFOS() << ll_pretty_print_sd(input) << LL_ENDL; LLSD locs = input["body"]["Location"], @@ -936,20 +1935,19 @@ public: } else if( i != you_index) { - U32 loc = x << 16 | y << 8 | z; loc = loc; U32 pos = 0x0; pos |= x; pos <<= 8; pos |= y; pos <<= 8; pos |= z; - avatar_locs->put(pos); - //llinfos << "next pos: " << x << "," << y << "," << z << ": " << pos << llendl; + avatar_locs->push_back(pos); + //LL_INFOS() << "next pos: " << x << "," << y << "," << z << ": " << pos << LL_ENDL; if(has_agent_data) // for backwards compatibility with old message format { LLUUID agent_id(agents_it->get("AgentID").asUUID()); - //llinfos << "next agent: " << agent_id.asString() << llendl; - avatar_ids->put(agent_id); + //LL_INFOS() << "next agent: " << agent_id.asString() << LL_ENDL; + avatar_ids->push_back(agent_id); } } if (has_agent_data) @@ -969,9 +1967,9 @@ LLHTTPRegistration<CoarseLocationUpdate> // the deprecated coarse location handler void LLViewerRegion::updateCoarseLocations(LLMessageSystem* msg) { - //llinfos << "CoarseLocationUpdate" << llendl; - mMapAvatars.reset(); - mMapAvatarIDs.reset(); // only matters in a rare case but it's good to be safe. + //LL_INFOS() << "CoarseLocationUpdate" << LL_ENDL; + mMapAvatars.clear(); + mMapAvatarIDs.clear(); // only matters in a rare case but it's good to be safe. U8 x_pos = 0; U8 y_pos = 0; @@ -997,14 +1995,14 @@ void LLViewerRegion::updateCoarseLocations(LLMessageSystem* msg) msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id, i); } - //llinfos << " object X: " << (S32)x_pos << " Y: " << (S32)y_pos + //LL_INFOS() << " object X: " << (S32)x_pos << " Y: " << (S32)y_pos // << " Z: " << (S32)(z_pos * 4) - // << llendl; + // << LL_ENDL; // treat the target specially for the map if(i == target_index) { - LLVector3d global_pos(mOriginGlobal); + LLVector3d global_pos(mImpl->mOriginGlobal); global_pos.mdV[VX] += (F64)(x_pos); global_pos.mdV[VY] += (F64)(y_pos); global_pos.mdV[VZ] += (F64)(z_pos) * 4.0; @@ -1020,10 +2018,10 @@ void LLViewerRegion::updateCoarseLocations(LLMessageSystem* msg) pos |= y_pos; pos <<= 8; pos |= z_pos; - mMapAvatars.put(pos); + mMapAvatars.push_back(pos); if(has_agent_data) { - mMapAvatarIDs.put(agent_id); + mMapAvatarIDs.push_back(agent_id); } } } @@ -1039,54 +2037,356 @@ void LLViewerRegion::getInfo(LLSD& info) info["Region"]["Handle"]["y"] = (LLSD::Integer)y; } -LLViewerRegion::eCacheUpdateResult LLViewerRegion::cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp) +boost::signals2::connection LLViewerRegion::setSimulatorFeaturesReceivedCallback(const caps_received_signal_t::slot_type& cb) +{ + return mSimulatorFeaturesReceivedSignal.connect(cb); +} + +void LLViewerRegion::setSimulatorFeaturesReceived(bool received) +{ + mSimulatorFeaturesReceived = received; + if (received) + { + mSimulatorFeaturesReceivedSignal(getRegionID()); + mSimulatorFeaturesReceivedSignal.disconnect_all_slots(); + } +} + +bool LLViewerRegion::simulatorFeaturesReceived() const +{ + return mSimulatorFeaturesReceived; +} + +void LLViewerRegion::getSimulatorFeatures(LLSD& sim_features) const +{ + sim_features = mSimulatorFeatures; + +} + +void LLViewerRegion::setSimulatorFeatures(const LLSD& sim_features) { - U32 local_id = objectp->getLocalID(); - U32 crc = objectp->getCRC(); + std::stringstream str; + + LLSDSerialize::toPrettyXML(sim_features, str); + LL_INFOS() << str.str() << LL_ENDL; + mSimulatorFeatures = sim_features; + + setSimulatorFeaturesReceived(true); + +} - LLVOCacheEntry* entry = get_if_there(mCacheMap, local_id, (LLVOCacheEntry*)NULL); +//this is called when the parent is not cacheable. +//move all orphan children out of cache and insert to rendering octree. +void LLViewerRegion::findOrphans(U32 parent_id) +{ + orphan_list_t::iterator iter = mOrphanMap.find(parent_id); + if(iter != mOrphanMap.end()) + { + std::vector<U32>* children = &mOrphanMap[parent_id]; + for(S32 i = 0; i < children->size(); i++) + { + //parent is visible, so is the child. + addVisibleChildCacheEntry(NULL, getCacheEntry((*children)[i])); + } + children->clear(); + mOrphanMap.erase(parent_id); + } +} + +void LLViewerRegion::decodeBoundingInfo(LLVOCacheEntry* entry) +{ + if(!sVOCacheCullingEnabled) + { + gObjectList.processObjectUpdateFromCache(entry, this); + return; + } + if(!entry || !entry->isValid()) + { + return; + } + + if(!entry->getEntry()) + { + entry->setOctreeEntry(NULL); + } + + if(entry->getEntry()->hasDrawable()) //already in the rendering pipeline + { + LLViewerRegion* old_regionp = ((LLDrawable*)entry->getEntry()->getDrawable())->getRegion(); + if(old_regionp != this && old_regionp) +{ + LLViewerObject* obj = ((LLDrawable*)entry->getEntry()->getDrawable())->getVObj(); + if(obj) + { + //remove from old region + old_regionp->killCacheEntry(obj->getLocalID()); + + //change region + obj->setRegion(this); + } + } + + addActiveCacheEntry(entry); + + //set parent id + U32 parent_id = 0; + LLViewerObject::unpackParentID(entry->getDP(), parent_id); + if(parent_id != entry->getParentID()) + { + entry->setParentID(parent_id); + } + + //update the object + gObjectList.processObjectUpdateFromCache(entry, this); + return; //done + } + + //must not be active. + llassert_always(!entry->isState(LLVOCacheEntry::ACTIVE)); + removeFromVOCacheTree(entry); //remove from cache octree if it is in. + + LLVector3 pos; + LLVector3 scale; + LLQuaternion rot; + + //decode spatial info and parent info + U32 parent_id = LLViewerObject::extractSpatialExtents(entry->getDP(), pos, scale, rot); + + U32 old_parent_id = entry->getParentID(); + bool same_old_parent = false; + if(parent_id != old_parent_id) //parent changed. + { + if(old_parent_id > 0) //has an old parent, disconnect it + { + LLVOCacheEntry* old_parent = getCacheEntry(old_parent_id); + if(old_parent) + { + old_parent->removeChild(entry); + if(!old_parent->isState(LLVOCacheEntry::INACTIVE)) + { + mImpl->mVisibleEntries.erase(entry); + entry->setState(LLVOCacheEntry::INACTIVE); + } + } + } + entry->setParentID(parent_id); + } + else + { + same_old_parent = true; + } + + if(parent_id > 0) //has a new parent + { + //1, find the parent in cache + LLVOCacheEntry* parent = getCacheEntry(parent_id); + + //2, parent is not in the cache, put into the orphan list. + if(!parent) + { + if(!same_old_parent) + { + //check if parent is non-cacheable and already created + if(isNonCacheableObjectCreated(parent_id)) + { + //parent is visible, so is the child. + addVisibleChildCacheEntry(NULL, entry); + } + else + { + entry->setBoundingInfo(pos, scale); + mOrphanMap[parent_id].push_back(entry->getLocalID()); + } + } + else + { + entry->setBoundingInfo(pos, scale); + } + } + else //parent in cache. + { + if(!parent->isState(LLVOCacheEntry::INACTIVE)) + { + //parent is visible, so is the child. + addVisibleChildCacheEntry(parent, entry); + } + else + { + entry->setBoundingInfo(pos, scale); + parent->addChild(entry); + + if(parent->getGroup()) //re-insert parent to vo-cache tree because its bounding info changed. + { + removeFromVOCacheTree(parent); + addToVOCacheTree(parent); + } + } + } + + return; + } + + // + //no parent + // + entry->setBoundingInfo(pos, scale); + + if(!parent_id) //a potential parent + { + //find all children and update their bounding info + orphan_list_t::iterator iter = mOrphanMap.find(entry->getLocalID()); + if(iter != mOrphanMap.end()) + { + std::vector<U32>* orphans = &mOrphanMap[entry->getLocalID()]; + S32 size = orphans->size(); + for(S32 i = 0; i < size; i++) + { + LLVOCacheEntry* child = getCacheEntry((*orphans)[i]); + if(child) + { + entry->addChild(child); + } + } + orphans->clear(); + mOrphanMap.erase(entry->getLocalID()); + } + } + + if(!entry->getGroup() && entry->isState(LLVOCacheEntry::INACTIVE)) + { + addToVOCacheTree(entry); + } + return ; +} + +LLViewerRegion::eCacheUpdateResult LLViewerRegion::cacheFullUpdate(LLDataPackerBinaryBuffer &dp, U32 flags) +{ + eCacheUpdateResult result; + U32 crc; + U32 local_id; + + LLViewerObject::unpackU32(&dp, local_id, "LocalID"); + LLViewerObject::unpackU32(&dp, crc, "CRC"); + + LLVOCacheEntry* entry = getCacheEntry(local_id, false); if (entry) { + entry->setValid(); + // we've seen this object before if (entry->getCRC() == crc) { // Record a hit entry->recordDupe(); - return CACHE_UPDATE_DUPE; + result = CACHE_UPDATE_DUPE; } + else //CRC changed + { + // Update the cache entry + entry->updateEntry(crc, dp); + + decodeBoundingInfo(entry); - // Update the cache entry - mCacheMap.erase(local_id); - delete entry; + result = CACHE_UPDATE_CHANGED; + } + } + else + { + // we haven't seen this object before + // Create new entry and add to map + result = CACHE_UPDATE_ADDED; entry = new LLVOCacheEntry(local_id, crc, dp); - mCacheMap[local_id] = entry; - return CACHE_UPDATE_CHANGED; + record(LLStatViewer::OBJECT_CACHE_HIT_RATE, LLUnits::Ratio::fromValue(0)); + + mImpl->mCacheMap[local_id] = entry; + + decodeBoundingInfo(entry); } + entry->setUpdateFlags(flags); + + return result; + } + +LLViewerRegion::eCacheUpdateResult LLViewerRegion::cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp, U32 flags) +{ + eCacheUpdateResult result = cacheFullUpdate(dp, flags); - // we haven't seen this object before + return result; +} - // Create new entry and add to map - eCacheUpdateResult result = CACHE_UPDATE_ADDED; - if (mCacheMap.size() > MAX_OBJECT_CACHE_ENTRIES) +LLVOCacheEntry* LLViewerRegion::getCacheEntryForOctree(U32 local_id) +{ + if(!sVOCacheCullingEnabled) { - mCacheMap.erase(mCacheMap.begin()); - result = CACHE_UPDATE_REPLACED; + return NULL; + } + + LLVOCacheEntry* entry = getCacheEntry(local_id); + removeFromVOCacheTree(entry); + return entry; +} + +LLVOCacheEntry* LLViewerRegion::getCacheEntry(U32 local_id, bool valid) +{ + LLVOCacheEntry::vocache_entry_map_t::iterator iter = mImpl->mCacheMap.find(local_id); + if(iter != mImpl->mCacheMap.end()) + { + if(!valid || iter->second->isValid()) + { + return iter->second; + } + } + return NULL; } - entry = new LLVOCacheEntry(local_id, crc, dp); - mCacheMap[local_id] = entry; - return result; +void LLViewerRegion::addCacheMiss(U32 id, LLViewerRegion::eCacheMissType miss_type) +{ +#if 0 + mCacheMissList.insert(CacheMissItem(id, miss_type)); +#else + mCacheMissList.push_back(CacheMissItem(id, miss_type)); +#endif +} + +//check if a non-cacheable object is already created. +bool LLViewerRegion::isNonCacheableObjectCreated(U32 local_id) +{ + if(mImpl && local_id > 0 && mImpl->mNonCacheableCreatedList.find(local_id) != mImpl->mNonCacheableCreatedList.end()) + { + return true; + } + return false; +} + +void LLViewerRegion::removeFromCreatedList(U32 local_id) +{ + if(mImpl && local_id > 0) + { + std::set<U32>::iterator iter = mImpl->mNonCacheableCreatedList.find(local_id); + if(iter != mImpl->mNonCacheableCreatedList.end()) + { + mImpl->mNonCacheableCreatedList.erase(iter); + } + } + } + +void LLViewerRegion::addToCreatedList(U32 local_id) +{ + if(mImpl && local_id > 0) + { + mImpl->mNonCacheableCreatedList.insert(local_id); + } } // Get data packer for this object, if we have cached data // AND the CRC matches. JC -LLDataPacker *LLViewerRegion::getDP(U32 local_id, U32 crc, U8 &cache_miss_type) +bool LLViewerRegion::probeCache(U32 local_id, U32 crc, U32 flags, U8 &cache_miss_type) { - llassert(mCacheLoaded); + //llassert(mCacheLoaded); This assert failes often, changing to early-out -- davep, 2010/10/18 - LLVOCacheEntry* entry = get_if_there(mCacheMap, local_id, (LLVOCacheEntry*)NULL); + LLVOCacheEntry* entry = getCacheEntry(local_id, false); if (entry) { @@ -1095,44 +2395,58 @@ LLDataPacker *LLViewerRegion::getDP(U32 local_id, U32 crc, U8 &cache_miss_type) { // Record a hit entry->recordHit(); - cache_miss_type = CACHE_MISS_TYPE_NONE; - return entry->getDP(crc); + cache_miss_type = CACHE_MISS_TYPE_NONE; + entry->setUpdateFlags(flags); + + if(entry->isState(LLVOCacheEntry::ACTIVE)) + { + ((LLDrawable*)entry->getEntry()->getDrawable())->getVObj()->loadFlags(flags); + return true; + } + + if(entry->isValid()) + { + return true; //already probed + } + + entry->setValid(); + decodeBoundingInfo(entry); + return true; } else { - // llinfos << "CRC miss for " << local_id << llendl; - cache_miss_type = CACHE_MISS_TYPE_CRC; - mCacheMissCRC.put(local_id); + // LL_INFOS() << "CRC miss for " << local_id << LL_ENDL; + + addCacheMiss(local_id, CACHE_MISS_TYPE_CRC); } } else { - // llinfos << "Cache miss for " << local_id << llendl; - cache_miss_type = CACHE_MISS_TYPE_FULL; - mCacheMissFull.put(local_id); + // LL_INFOS() << "Cache miss for " << local_id << LL_ENDL; + addCacheMiss(local_id, CACHE_MISS_TYPE_FULL); } - return NULL; + + return false; } void LLViewerRegion::addCacheMissFull(const U32 local_id) { - mCacheMissFull.put(local_id); + addCacheMiss(local_id, CACHE_MISS_TYPE_FULL); } void LLViewerRegion::requestCacheMisses() { - S32 full_count = mCacheMissFull.count(); - S32 crc_count = mCacheMissCRC.count(); - if (full_count == 0 && crc_count == 0) return; + if (!mCacheMissList.size()) + { + return; + } LLMessageSystem* msg = gMessageSystem; BOOL start_new_message = TRUE; S32 blocks = 0; - S32 i; - // Send full cache miss updates. For these, we KNOW we don't - // have a viewer object. - for (i = 0; i < full_count; i++) + //send requests for all cache-missed objects + for (CacheMissItem::cache_miss_list_t::iterator iter = mCacheMissList.begin(); iter != mCacheMissList.end(); ++iter) { if (start_new_message) { @@ -1144,34 +2458,8 @@ void LLViewerRegion::requestCacheMisses() } msg->nextBlockFast(_PREHASH_ObjectData); - msg->addU8Fast(_PREHASH_CacheMissType, CACHE_MISS_TYPE_FULL); - msg->addU32Fast(_PREHASH_ID, mCacheMissFull[i]); - blocks++; - - if (blocks >= 255) - { - sendReliableMessage(); - start_new_message = TRUE; - blocks = 0; - } - } - - // Send CRC miss updates. For these, we _might_ have a viewer object, - // but probably not. - for (i = 0; i < crc_count; i++) - { - if (start_new_message) - { - msg->newMessageFast(_PREHASH_RequestMultipleObjects); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - start_new_message = FALSE; - } - - msg->nextBlockFast(_PREHASH_ObjectData); - msg->addU8Fast(_PREHASH_CacheMissType, CACHE_MISS_TYPE_CRC); - msg->addU32Fast(_PREHASH_ID, mCacheMissCRC[i]); + msg->addU8Fast(_PREHASH_CacheMissType, (*iter).mType); + msg->addU32Fast(_PREHASH_ID, (*iter).mID); blocks++; if (blocks >= 255) @@ -1187,16 +2475,13 @@ void LLViewerRegion::requestCacheMisses() { sendReliableMessage(); } - mCacheMissFull.reset(); - mCacheMissCRC.reset(); mCacheDirty = TRUE ; - // llinfos << "KILLDEBUG Sent cache miss full " << full_count << " crc " << crc_count << llendl; - #if LL_RECORD_VIEWER_STATS - LLViewerStatsRecorder::instance()->beginObjectUpdateEvents(this); - LLViewerStatsRecorder::instance()->recordRequestCacheMissesEvent(full_count + crc_count); - LLViewerStatsRecorder::instance()->endObjectUpdateEvents(); - #endif + // LL_INFOS() << "KILLDEBUG Sent cache miss full " << full_count << " crc " << crc_count << LL_ENDL; + LLViewerStatsRecorder::instance().requestCacheMissesEvent(mCacheMissList.size()); + LLViewerStatsRecorder::instance().log(0.2f); + + mCacheMissList.clear(); } void LLViewerRegion::dumpCache() @@ -1213,7 +2498,7 @@ void LLViewerRegion::dumpCache() } LLVOCacheEntry *entry; - for(LLVOCacheEntry::vocache_entry_map_t::iterator iter = mCacheMap.begin(); iter != mCacheMap.end(); ++iter) + for(LLVOCacheEntry::vocache_entry_map_t::iterator iter = mImpl->mCacheMap.begin(); iter != mImpl->mCacheMap.end(); ++iter) { entry = iter->second ; @@ -1227,14 +2512,14 @@ void LLViewerRegion::dumpCache() change_bin[changes]++; } - llinfos << "Count " << mCacheMap.size() << llendl; + LL_INFOS() << "Count " << mImpl->mCacheMap.size() << LL_ENDL; for (i = 0; i < BINS; i++) { - llinfos << "Hits " << i << " " << hit_bin[i] << llendl; + LL_INFOS() << "Hits " << i << " " << hit_bin[i] << LL_ENDL; } for (i = 0; i < BINS; i++) { - llinfos << "Changes " << i << " " << change_bin[i] << llendl; + LL_INFOS() << "Changes " << i << " " << change_bin[i] << LL_ENDL; } } @@ -1242,7 +2527,8 @@ void LLViewerRegion::unpackRegionHandshake() { LLMessageSystem *msg = gMessageSystem; - U32 region_flags; + U64 region_flags = 0; + U64 region_protocols = 0; U8 sim_access; std::string sim_name; LLUUID sim_owner; @@ -1251,7 +2537,6 @@ void LLViewerRegion::unpackRegionHandshake() F32 billable_factor; LLUUID cache_id; - msg->getU32 ("RegionInfo", "RegionFlags", region_flags); msg->getU8 ("RegionInfo", "SimAccess", sim_access); msg->getString ("RegionInfo", "SimName", sim_name); msg->getUUID ("RegionInfo", "SimOwner", sim_owner); @@ -1260,7 +2545,20 @@ void LLViewerRegion::unpackRegionHandshake() msg->getF32 ("RegionInfo", "BillableFactor", billable_factor); msg->getUUID ("RegionInfo", "CacheID", cache_id ); + if (msg->has(_PREHASH_RegionInfo4)) + { + msg->getU64Fast(_PREHASH_RegionInfo4, _PREHASH_RegionFlagsExtended, region_flags); + msg->getU64Fast(_PREHASH_RegionInfo4, _PREHASH_RegionProtocols, region_protocols); + } + else + { + U32 flags = 0; + msg->getU32Fast(_PREHASH_RegionInfo, _PREHASH_RegionFlags, flags); + region_flags = flags; + } + setRegionFlags(region_flags); + setRegionProtocols(region_protocols); setSimAccess(sim_access); setRegionNameAndZone(sim_name); setOwner(sim_owner); @@ -1299,44 +2597,76 @@ void LLViewerRegion::unpackRegionHandshake() mProductName = productName; } + + mCentralBakeVersion = region_protocols & 1; // was (S32)gSavedSettings.getBOOL("UseServerTextureBaking"); LLVLComposition *compp = getComposition(); if (compp) { LLUUID tmp_id; + bool changed = false; + + // Get the 4 textures for land msg->getUUID("RegionInfo", "TerrainDetail0", tmp_id); + changed |= (tmp_id != compp->getDetailTextureID(0)); compp->setDetailTextureID(0, tmp_id); + msg->getUUID("RegionInfo", "TerrainDetail1", tmp_id); + changed |= (tmp_id != compp->getDetailTextureID(1)); compp->setDetailTextureID(1, tmp_id); + msg->getUUID("RegionInfo", "TerrainDetail2", tmp_id); + changed |= (tmp_id != compp->getDetailTextureID(2)); compp->setDetailTextureID(2, tmp_id); + msg->getUUID("RegionInfo", "TerrainDetail3", tmp_id); + changed |= (tmp_id != compp->getDetailTextureID(3)); compp->setDetailTextureID(3, tmp_id); + // Get the start altitude and range values for land textures F32 tmp_f32; msg->getF32("RegionInfo", "TerrainStartHeight00", tmp_f32); + changed |= (tmp_f32 != compp->getStartHeight(0)); compp->setStartHeight(0, tmp_f32); + msg->getF32("RegionInfo", "TerrainStartHeight01", tmp_f32); + changed |= (tmp_f32 != compp->getStartHeight(1)); compp->setStartHeight(1, tmp_f32); + msg->getF32("RegionInfo", "TerrainStartHeight10", tmp_f32); + changed |= (tmp_f32 != compp->getStartHeight(2)); compp->setStartHeight(2, tmp_f32); + msg->getF32("RegionInfo", "TerrainStartHeight11", tmp_f32); + changed |= (tmp_f32 != compp->getStartHeight(3)); compp->setStartHeight(3, tmp_f32); + msg->getF32("RegionInfo", "TerrainHeightRange00", tmp_f32); + changed |= (tmp_f32 != compp->getHeightRange(0)); compp->setHeightRange(0, tmp_f32); + msg->getF32("RegionInfo", "TerrainHeightRange01", tmp_f32); + changed |= (tmp_f32 != compp->getHeightRange(1)); compp->setHeightRange(1, tmp_f32); + msg->getF32("RegionInfo", "TerrainHeightRange10", tmp_f32); + changed |= (tmp_f32 != compp->getHeightRange(2)); compp->setHeightRange(2, tmp_f32); + msg->getF32("RegionInfo", "TerrainHeightRange11", tmp_f32); + changed |= (tmp_f32 != compp->getHeightRange(3)); compp->setHeightRange(3, tmp_f32); // If this is an UPDATE (params already ready, we need to regenerate // all of our terrain stuff, by if (compp->getParamsReady()) { - getLand().dirtyAllPatches(); + // Update if the land changed + if (changed) + { + getLand().dirtyAllPatches(); + } } else { @@ -1358,55 +2688,79 @@ void LLViewerRegion::unpackRegionHandshake() msg->addUUID("AgentID", gAgent.getID()); msg->addUUID("SessionID", gAgent.getSessionID()); msg->nextBlock("RegionInfo"); - msg->addU32("Flags", 0x0 ); + + U32 flags = 0; + flags |= REGION_HANDSHAKE_SUPPORTS_SELF_APPEARANCE; + + if(sVOCacheCullingEnabled) + { + flags |= 0x00000001; //set the bit 0 to be 1 to ask sim to send all cacheable objects. + } + if(mImpl->mCacheMap.empty()) + { + flags |= 0x00000002; //set the bit 1 to be 1 to tell sim the cache file is empty, no need to send cache probes. + } + msg->addU32("Flags", flags ); msg->sendReliable(host); + + mRegionTimer.reset(); //reset region timer. } -void LLViewerRegion::setSeedCapability(const std::string& url) +void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) { - if (getCapability("Seed") == url) - { - // llwarns << "Ignoring duplicate seed capability" << llendl; - return; - } - - delete mEventPoll; - mEventPoll = NULL; - - mCapabilities.clear(); - setCapability("Seed", url); - - LLSD capabilityNames = LLSD::emptyArray(); - + capabilityNames.append("AgentPreferences"); + capabilityNames.append("AgentState"); capabilityNames.append("AttachmentResources"); capabilityNames.append("AvatarPickerSearch"); + capabilityNames.append("AvatarRenderInfo"); + capabilityNames.append("CharacterProperties"); capabilityNames.append("ChatSessionRequest"); capabilityNames.append("CopyInventoryFromNotecard"); + capabilityNames.append("CreateInventoryCategory"); capabilityNames.append("DispatchRegionInfo"); + capabilityNames.append("EnvironmentSettings"); capabilityNames.append("EstateChangeInfo"); capabilityNames.append("EventQueueGet"); - capabilityNames.append("ObjectMedia"); - capabilityNames.append("ObjectMediaNavigate"); + capabilityNames.append("FacebookConnect"); + capabilityNames.append("FlickrConnect"); + capabilityNames.append("TwitterConnect"); + capabilityNames.append("FetchLib2"); capabilityNames.append("FetchLibDescendents2"); capabilityNames.append("FetchInventory2"); capabilityNames.append("FetchInventoryDescendents2"); + capabilityNames.append("IncrementCOFVersion"); + AISCommand::getCapabilityNames(capabilityNames); + capabilityNames.append("GetDisplayNames"); + capabilityNames.append("GetMesh"); + capabilityNames.append("GetMesh2"); + capabilityNames.append("GetObjectCost"); + capabilityNames.append("GetObjectPhysicsData"); capabilityNames.append("GetTexture"); + capabilityNames.append("GroupAPIv1"); + capabilityNames.append("GroupMemberData"); capabilityNames.append("GroupProposalBallot"); capabilityNames.append("HomeLocation"); capabilityNames.append("LandResources"); + capabilityNames.append("LSLSyntax"); capabilityNames.append("MapLayer"); capabilityNames.append("MapLayerGod"); + capabilityNames.append("MeshUploadFlag"); + capabilityNames.append("NavMeshGenerationStatus"); capabilityNames.append("NewFileAgentInventory"); + capabilityNames.append("ObjectMedia"); + capabilityNames.append("ObjectMediaNavigate"); + capabilityNames.append("ObjectNavMeshProperties"); capabilityNames.append("ParcelPropertiesUpdate"); - capabilityNames.append("ParcelMediaURLFilterList"); - capabilityNames.append("ParcelNavigateMedia"); capabilityNames.append("ParcelVoiceInfoRequest"); capabilityNames.append("ProductInfoRequest"); capabilityNames.append("ProvisionVoiceAccountRequest"); capabilityNames.append("RemoteParcelRequest"); + capabilityNames.append("RenderMaterials"); capabilityNames.append("RequestTextureDownload"); + capabilityNames.append("ResourceCostSelected"); + capabilityNames.append("RetrieveNavMeshSrc"); capabilityNames.append("SearchStatRequest"); capabilityNames.append("SearchStatTracking"); capabilityNames.append("SendPostcard"); @@ -1415,50 +2769,195 @@ void LLViewerRegion::setSeedCapability(const std::string& url) capabilityNames.append("ServerReleaseNotes"); capabilityNames.append("SetDisplayName"); capabilityNames.append("SimConsoleAsync"); + capabilityNames.append("SimulatorFeatures"); capabilityNames.append("StartGroupProposal"); + capabilityNames.append("TerrainNavMeshProperties"); capabilityNames.append("TextureStats"); capabilityNames.append("UntrustedSimulatorMessage"); capabilityNames.append("UpdateAgentInformation"); capabilityNames.append("UpdateAgentLanguage"); + capabilityNames.append("UpdateAvatarAppearance"); capabilityNames.append("UpdateGestureAgentInventory"); - capabilityNames.append("UpdateNotecardAgentInventory"); - capabilityNames.append("UpdateScriptAgent"); capabilityNames.append("UpdateGestureTaskInventory"); + capabilityNames.append("UpdateNotecardAgentInventory"); capabilityNames.append("UpdateNotecardTaskInventory"); + capabilityNames.append("UpdateScriptAgent"); capabilityNames.append("UpdateScriptTask"); capabilityNames.append("UploadBakedTexture"); capabilityNames.append("ViewerMetrics"); capabilityNames.append("ViewerStartAuction"); capabilityNames.append("ViewerStats"); + // Please add new capabilities alphabetically to reduce // merge conflicts. +} + +void LLViewerRegion::setSeedCapability(const std::string& url) +{ + if (getCapability("Seed") == url) + { + setCapabilityDebug("Seed", url); + LL_DEBUGS("CrossingCaps") << "Received duplicate seed capability, posting to seed " << + url << LL_ENDL; + + //Instead of just returning we build up a second set of seed caps and compare them + //to the "original" seed cap received and determine why there is problem! + LLSD capabilityNames = LLSD::emptyArray(); + mImpl->buildCapabilityNames( capabilityNames ); + LLHTTPClient::post( url, capabilityNames, BaseCapabilitiesCompleteTracker::build(getHandle() ), + LLSD(), CAP_REQUEST_TIMEOUT ); + return; + } + + delete mImpl->mEventPoll; + mImpl->mEventPoll = NULL; + + mImpl->mCapabilities.clear(); + setCapability("Seed", url); + + LLSD capabilityNames = LLSD::emptyArray(); + mImpl->buildCapabilityNames(capabilityNames); - llinfos << "posting to seed " << url << llendl; + LL_INFOS() << "posting to seed " << url << LL_ENDL; - mHttpResponderPtr = BaseCapabilitiesComplete::build(this) ; - LLHTTPClient::post(url, capabilityNames, mHttpResponderPtr); + S32 id = ++mImpl->mHttpResponderID; + LLHTTPClient::post(url, capabilityNames, + BaseCapabilitiesComplete::build(getHandle(), id), + LLSD(), CAP_REQUEST_TIMEOUT); } +S32 LLViewerRegion::getNumSeedCapRetries() +{ + return mImpl->mSeedCapAttempts; +} + +void LLViewerRegion::failedSeedCapability() +{ + // Should we retry asking for caps? + mImpl->mSeedCapAttempts++; + std::string url = getCapability("Seed"); + if ( url.empty() ) + { + LL_WARNS("AppInit", "Capabilities") << "Failed to get seed capabilities, and can not determine url for retries!" << LL_ENDL; + return; + } + // After a few attempts, continue login. We will keep trying once in-world: + if ( mImpl->mSeedCapAttempts >= mImpl->mSeedCapMaxAttemptsBeforeLogin && + STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState() ) + { + LLStartUp::setStartupState( STATE_SEED_CAP_GRANTED ); + } + + if ( mImpl->mSeedCapAttempts < mImpl->mSeedCapMaxAttempts) + { + LLSD capabilityNames = LLSD::emptyArray(); + mImpl->buildCapabilityNames(capabilityNames); + + LL_INFOS() << "posting to seed " << url << " (retry " + << mImpl->mSeedCapAttempts << ")" << LL_ENDL; + + S32 id = ++mImpl->mHttpResponderID; + LLHTTPClient::post(url, capabilityNames, + BaseCapabilitiesComplete::build(getHandle(), id), + LLSD(), CAP_REQUEST_TIMEOUT); + } + else + { + // *TODO: Give a user pop-up about this error? + LL_WARNS("AppInit", "Capabilities") << "Failed to get seed capabilities from '" << url << "' after " << mImpl->mSeedCapAttempts << " attempts. Giving up!" << LL_ENDL; + } +} + +class SimulatorFeaturesReceived : public LLHTTPClient::Responder +{ + LOG_CLASS(SimulatorFeaturesReceived); +public: + SimulatorFeaturesReceived(const std::string& retry_url, U64 region_handle, + S32 attempt = 0, S32 max_attempts = MAX_CAP_REQUEST_ATTEMPTS) + : mRetryURL(retry_url), mRegionHandle(region_handle), mAttempt(attempt), mMaxAttempts(max_attempts) + { } + + /* virtual */ void httpFailure() + { + LL_WARNS("AppInit", "SimulatorFeatures") << dumpResponse() << LL_ENDL; + retry(); + } + + /* virtual */ void httpSuccess() + { + LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); + if(!regionp) //region is removed or responder is not created. + { + LL_WARNS("AppInit", "SimulatorFeatures") + << "Received results for region that no longer exists!" << LL_ENDL; + return ; + } + + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); + return; + } + regionp->setSimulatorFeatures(content); + } + + void retry() + { + if (mAttempt < mMaxAttempts) + { + mAttempt++; + LL_WARNS("AppInit", "SimulatorFeatures") << "Re-trying '" << mRetryURL << "'. Retry #" << mAttempt << LL_ENDL; + LLHTTPClient::get(mRetryURL, new SimulatorFeaturesReceived(*this), LLSD(), CAP_REQUEST_TIMEOUT); + } + } + + std::string mRetryURL; + U64 mRegionHandle; + S32 mAttempt; + S32 mMaxAttempts; +}; + + void LLViewerRegion::setCapability(const std::string& name, const std::string& url) { if(name == "EventQueueGet") { - delete mEventPoll; - mEventPoll = NULL; - mEventPoll = new LLEventPoll(url, getHost()); + delete mImpl->mEventPoll; + mImpl->mEventPoll = NULL; + mImpl->mEventPoll = new LLEventPoll(url, getHost()); } else if(name == "UntrustedSimulatorMessage") { - LLHTTPSender::setSender(mHost, new LLCapHTTPSender(url)); + LLHTTPSender::setSender(mImpl->mHost, new LLCapHTTPSender(url)); + } + else if (name == "SimulatorFeatures") + { + // kick off a request for simulator features + LLHTTPClient::get(url, new SimulatorFeaturesReceived(url, getHandle()), LLSD(), CAP_REQUEST_TIMEOUT); } else { - mCapabilities[name] = url; + mImpl->mCapabilities[name] = url; + if(name == "GetTexture") + { + mHttpUrl = url ; + } + } +} + +void LLViewerRegion::setCapabilityDebug(const std::string& name, const std::string& url) +{ + // Continue to not add certain caps, as we do in setCapability. This is so they match up when we check them later. + if ( ! ( name == "EventQueueGet" || name == "UntrustedSimulatorMessage" || name == "SimulatorFeatures" ) ) + { + mImpl->mSecondCapabilitiesTracker[name] = url; if(name == "GetTexture") { mHttpUrl = url ; } } + } bool LLViewerRegion::isSpecialCapabilityName(const std::string &name) @@ -1468,14 +2967,36 @@ bool LLViewerRegion::isSpecialCapabilityName(const std::string &name) std::string LLViewerRegion::getCapability(const std::string& name) const { - CapabilityMap::const_iterator iter = mCapabilities.find(name); - if(iter == mCapabilities.end()) + if (!capabilitiesReceived() && (name!=std::string("Seed")) && (name!=std::string("ObjectMedia"))) + { + LL_WARNS() << "getCapability called before caps received for " << name << LL_ENDL; + } + + CapabilityMap::const_iterator iter = mImpl->mCapabilities.find(name); + if(iter == mImpl->mCapabilities.end()) { return ""; } + return iter->second; } +bool LLViewerRegion::isCapabilityAvailable(const std::string& name) const +{ + if (!capabilitiesReceived() && (name!=std::string("Seed")) && (name!=std::string("ObjectMedia"))) + { + LL_WARNS() << "isCapabilityAvailable called before caps received for " << name << LL_ENDL; + } + + CapabilityMap::const_iterator iter = mImpl->mCapabilities.find(name); + if(iter == mImpl->mCapabilities.end()) + { + return false; + } + + return true; +} + bool LLViewerRegion::capabilitiesReceived() const { return mCapabilitiesReceived; @@ -1484,34 +3005,51 @@ bool LLViewerRegion::capabilitiesReceived() const void LLViewerRegion::setCapabilitiesReceived(bool received) { mCapabilitiesReceived = received; + + // Tell interested parties that we've received capabilities, + // so that they can safely use getCapability(). + if (received) + { + mCapabilitiesReceivedSignal(getRegionID()); + + LLFloaterPermsDefault::sendInitialPerms(); + + // This is a single-shot signal. Forget callbacks to save resources. + mCapabilitiesReceivedSignal.disconnect_all_slots(); + } +} + +boost::signals2::connection LLViewerRegion::setCapabilitiesReceivedCallback(const caps_received_signal_t::slot_type& cb) +{ + return mCapabilitiesReceivedSignal.connect(cb); } void LLViewerRegion::logActiveCapabilities() const { - int count = 0; - CapabilityMap::const_iterator iter; - for (iter = mCapabilities.begin(); iter != mCapabilities.end(); iter++, count++) + log_capabilities(mImpl->mCapabilities); +} + +LLSpatialPartition* LLViewerRegion::getSpatialPartition(U32 type) +{ + if (type < mImpl->mObjectPartition.size() && type < PARTITION_VO_CACHE) { - if (!iter->second.empty()) - { - llinfos << iter->first << " URL is " << iter->second << llendl; - } + return (LLSpatialPartition*)mImpl->mObjectPartition[type]; } - llinfos << "Dumped " << count << " entries." << llendl; + return NULL; } -LLSpatialPartition* LLViewerRegion::getSpatialPartition(U32 type) +LLVOCachePartition* LLViewerRegion::getVOCachePartition() { - if (type < mObjectPartition.size()) + if(PARTITION_VO_CACHE < mImpl->mObjectPartition.size()) { - return mObjectPartition[type]; + return (LLVOCachePartition*)mImpl->mObjectPartition[PARTITION_VO_CACHE]; } return NULL; } // the viewer can not yet distinquish between normal- and estate-owned objects // so we collapse these two bits and enable the UI if either are set -const U32 ALLOW_RETURN_ENCROACHING_OBJECT = REGION_FLAGS_ALLOW_RETURN_ENCROACHING_OBJECT +const U64 ALLOW_RETURN_ENCROACHING_OBJECT = REGION_FLAGS_ALLOW_RETURN_ENCROACHING_OBJECT | REGION_FLAGS_ALLOW_RETURN_ENCROACHING_ESTATE_OBJECT; bool LLViewerRegion::objectIsReturnable(const LLVector3& pos, const std::vector<LLBBox>& boxes) const @@ -1519,10 +3057,30 @@ bool LLViewerRegion::objectIsReturnable(const LLVector3& pos, const std::vector< return (mParcelOverlay != NULL) && (mParcelOverlay->isOwnedSelf(pos) || mParcelOverlay->isOwnedGroup(pos) - || ((mRegionFlags & ALLOW_RETURN_ENCROACHING_OBJECT) + || (getRegionFlag(ALLOW_RETURN_ENCROACHING_OBJECT) && mParcelOverlay->encroachesOwned(boxes)) ); } +bool LLViewerRegion::childrenObjectReturnable( const std::vector<LLBBox>& boxes ) const +{ + bool result = false; + result = ( mParcelOverlay && mParcelOverlay->encroachesOnUnowned( boxes ) ) ? 1 : 0; + return result; +} + +bool LLViewerRegion::objectsCrossParcel(const std::vector<LLBBox>& boxes) const +{ + return mParcelOverlay && mParcelOverlay->encroachesOnNearbyParcel(boxes); +} + +void LLViewerRegion::getNeighboringRegions( std::vector<LLViewerRegion*>& uniqueRegions ) +{ + mImpl->mLandp->getNeighboringRegions( uniqueRegions ); +} +void LLViewerRegion::getNeighboringRegionsStatus( std::vector<S32>& regions ) +{ + mImpl->mLandp->getNeighboringRegionsStatus( regions ); +} void LLViewerRegion::showReleaseNotes() { std::string url = this->getCapability("ServerReleaseNotes"); @@ -1542,3 +3100,87 @@ std::string LLViewerRegion::getDescription() const { return stringize(*this); } + +bool LLViewerRegion::meshUploadEnabled() const +{ + return (mSimulatorFeatures.has("MeshUploadEnabled") && + mSimulatorFeatures["MeshUploadEnabled"].asBoolean()); +} + +bool LLViewerRegion::meshRezEnabled() const +{ + return (mSimulatorFeatures.has("MeshRezEnabled") && + mSimulatorFeatures["MeshRezEnabled"].asBoolean()); +} + +bool LLViewerRegion::dynamicPathfindingEnabled() const +{ + return ( mSimulatorFeatures.has("DynamicPathfindingEnabled") && + mSimulatorFeatures["DynamicPathfindingEnabled"].asBoolean()); +} + +bool LLViewerRegion::avatarHoverHeightEnabled() const +{ + return ( mSimulatorFeatures.has("AvatarHoverHeightEnabled") && + mSimulatorFeatures["AvatarHoverHeightEnabled"].asBoolean()); +} +/* Static Functions */ + +void log_capabilities(const CapabilityMap &capmap) +{ + S32 count = 0; + CapabilityMap::const_iterator iter; + for (iter = capmap.begin(); iter != capmap.end(); ++iter, ++count) + { + if (!iter->second.empty()) + { + LL_INFOS() << "log_capabilities: " << iter->first << " URL is " << iter->second << LL_ENDL; + } + } + LL_INFOS() << "log_capabilities: Dumped " << count << " entries." << LL_ENDL; +} +void LLViewerRegion::resetMaterialsCapThrottle() +{ + F32 requests_per_sec = 1.0f; // original default; + if ( mSimulatorFeatures.has("RenderMaterialsCapability") + && mSimulatorFeatures["RenderMaterialsCapability"].isReal() ) + { + requests_per_sec = mSimulatorFeatures["RenderMaterialsCapability"].asReal(); + if ( requests_per_sec == 0.0f ) + { + requests_per_sec = 1.0f; + LL_WARNS("Materials") + << "region '" << getName() + << "' returned zero for RenderMaterialsCapability; using default " + << requests_per_sec << " per second" + << LL_ENDL; + } + LL_DEBUGS("Materials") << "region '" << getName() + << "' RenderMaterialsCapability " << requests_per_sec + << LL_ENDL; + } + else + { + LL_DEBUGS("Materials") + << "region '" << getName() + << "' did not return RenderMaterialsCapability, using default " + << requests_per_sec << " per second" + << LL_ENDL; + } + + mMaterialsCapThrottleTimer.resetWithExpiry( 1.0f / requests_per_sec ); +} + +U32 LLViewerRegion::getMaxMaterialsPerTransaction() const +{ + U32 max_entries = 50; // original hard coded default + if ( mSimulatorFeatures.has( "MaxMaterialsPerTransaction" ) + && mSimulatorFeatures[ "MaxMaterialsPerTransaction" ].isInteger()) + { + max_entries = mSimulatorFeatures[ "MaxMaterialsPerTransaction" ].asInteger(); + } + return max_entries; +} + + + |