diff options
-rwxr-xr-x | indra/newview/CMakeLists.txt | 2 | ||||
-rw-r--r-- | indra/newview/llappviewer.cpp | 4 | ||||
-rw-r--r-- | indra/newview/llavatarrenderinfoaccountant.cpp | 360 | ||||
-rw-r--r-- | indra/newview/llavatarrenderinfoaccountant.h | 54 | ||||
-rw-r--r-- | indra/newview/llspatialpartition.cpp | 2 | ||||
-rw-r--r-- | indra/newview/llviewerregion.cpp | 5 | ||||
-rw-r--r-- | indra/newview/llviewerregion.h | 4 | ||||
-rwxr-xr-x | indra/newview/llvoavatar.cpp | 3 | ||||
-rw-r--r-- | indra/newview/llvoavatar.h | 23 | ||||
-rw-r--r-- | indra/newview/llvovolume.cpp | 2 |
10 files changed, 455 insertions, 4 deletions
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index bd0169fb2f..cb96dfeb48 100755 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -113,6 +113,7 @@ set(viewer_SOURCE_FILES llavatariconctrl.cpp llavatarlist.cpp llavatarlistitem.cpp + llavatarrenderinfoaccountant.cpp llavatarpropertiesprocessor.cpp llblockedlistitem.cpp llblocklist.cpp @@ -702,6 +703,7 @@ set(viewer_HEADER_FILES llavatarlist.h llavatarlistitem.h llavatarpropertiesprocessor.h + llavatarrenderinfoaccountant.h llblockedlistitem.h llblocklist.h llbox.h diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 4745157c8b..7404d2d228 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -97,6 +97,7 @@ #include "llupdaterservice.h" #include "llfloatertexturefetchdebugger.h" #include "llspellcheck.h" +#include "llavatarrenderinfoaccountant.h" // Linden library includes #include "llavatarnamecache.h" @@ -4587,6 +4588,9 @@ void LLAppViewer::idle() gObjectList.updateApparentAngles(gAgent); } + // Update AV render info + LLAvatarRenderInfoAccountant::idle(); + { LLFastTimer t(FTM_AUDIO_UPDATE); diff --git a/indra/newview/llavatarrenderinfoaccountant.cpp b/indra/newview/llavatarrenderinfoaccountant.cpp new file mode 100644 index 0000000000..04a79f7d4c --- /dev/null +++ b/indra/newview/llavatarrenderinfoaccountant.cpp @@ -0,0 +1,360 @@ +/** + * @file llavatarrenderinfoaccountant.cpp + * @author Dave Simmons + * @date 2013-02-28 + * @brief + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 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 + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +// Precompiled header +#include "llviewerprecompiledheaders.h" +// associated header +#include "llavatarrenderinfoaccountant.h" +// STL headers +// std headers +// external library headers +// other Linden headers +#include "llcharacter.h" +#include "llhttpclient.h" +#include "lltimer.h" +#include "llviewerobjectlist.h" +#include "llviewerregion.h" +#include "llvoavatar.h" +#include "llworld.h" + + +// Use this for debugging +//#define LL_AVATAR_RENDER_INFO_LOG_SPAM + +static const std::string KEY_AGENTS = "agents"; // map +static const std::string KEY_WEIGHT = "weight"; // integer +static const std::string KEY_GEOMETRY = "geometry"; // integer +static const std::string KEY_SURFACE = "surface"; // float + +static const std::string KEY_IDENTIFIER = "identifier"; +static const std::string KEY_MESSAGE = "message"; +static const std::string KEY_ERROR = "error"; + + +// Send data updates about once per minute, only need per-frame resolution +LLFrameTimer LLAvatarRenderInfoAccountant::sRenderInfoReportTimer; + + +// HTTP responder class for GET request for avatar render weight information +class LLAvatarRenderInfoGetResponder : public LLHTTPClient::Responder +{ +public: + LLAvatarRenderInfoGetResponder(U64 region_handle) : mRegionHandle(region_handle) + { + } + + virtual void error(U32 statusNum, const std::string& reason) + { + LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); + if (regionp) + { + llwarns << "HTTP error result for avatar weight GET: " << statusNum + << ", " << reason + << " returned by region " << regionp->getName() + << llendl; + } + else + { + llwarns << "Avatar render weight GET error recieved but region not found for " + << mRegionHandle + << ", error " << statusNum + << ", " << reason + << llendl; + } + + } + + virtual void result(const LLSD& content) + { + LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); + if (regionp) + { + #ifdef LL_AVATAR_RENDER_INFO_LOG_SPAM + llinfos << "Result for avatar weights request for region " << regionp->getName() << ":" << llendl; + #endif // LL_AVATAR_RENDER_INFO_LOG_SPAM + + if (content.isMap()) + { + if (content.has(KEY_AGENTS)) + { + const LLSD & agents = content[KEY_AGENTS]; + if (agents.isMap()) + { + LLSD::map_const_iterator report_iter = agents.beginMap(); + while (report_iter != agents.endMap()) + { + LLUUID target_agent_id = LLUUID(report_iter->first); + const LLSD & agent_info_map = report_iter->second; + LLViewerObject* avatarp = gObjectList.findObject(target_agent_id); + if (avatarp && + avatarp->isAvatar() && + agent_info_map.isMap()) + { // Extract the data for this avatar + + #ifdef LL_AVATAR_RENDER_INFO_LOG_SPAM + llinfos << " Agent " << target_agent_id + << ": " << agent_info_map << llendl; + #endif // LL_AVATAR_RENDER_INFO_LOG_SPAM + + if (agent_info_map.has(KEY_WEIGHT)) + { + ((LLVOAvatar *) avatarp)->setReportedVisualComplexity(agent_info_map[KEY_WEIGHT].asInteger()); + } + if (agent_info_map.has(KEY_GEOMETRY)) + { + ((LLVOAvatar *) avatarp)->setReportedAttachmentGeometryBytes(agent_info_map[KEY_GEOMETRY].asInteger()); + } + if (agent_info_map.has(KEY_SURFACE)) + { + ((LLVOAvatar *) avatarp)->setReportedAttachmentSurfaceArea((F32) agent_info_map[KEY_SURFACE].asReal()); + } + } + report_iter++; + } + } + } // has "agents" + else if (content.has(KEY_ERROR)) + { + const LLSD & error = content[KEY_ERROR]; + llwarns << "Avatar render info GET error: " + << error[KEY_IDENTIFIER] + << ": " << error[KEY_MESSAGE] + << " from region " << regionp->getName() + << llendl; + } + } + } + else + { + llinfos << "Avatar render weight info recieved but region not found for " + << mRegionHandle << llendl; + } + } + +private: + U64 mRegionHandle; +}; + + +// HTTP responder class for POST request for avatar render weight information +class LLAvatarRenderInfoPostResponder : public LLHTTPClient::Responder +{ +public: + LLAvatarRenderInfoPostResponder(U64 region_handle) : mRegionHandle(region_handle) + { + } + + virtual void error(U32 statusNum, const std::string& reason) + { + LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); + if (regionp) + { + llwarns << "HTTP error result for avatar weight POST: " << statusNum + << ", " << reason + << " returned by region " << regionp->getName() + << llendl; + } + else + { + llwarns << "Avatar render weight POST error recieved but region not found for " + << mRegionHandle + << ", error " << statusNum + << ", " << reason + << llendl; + } + } + + virtual void result(const LLSD& content) + { + LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); + if (regionp) + { + #ifdef LL_AVATAR_RENDER_INFO_LOG_SPAM + llinfos << "Result for avatar weights POST for region " << regionp->getName() + << ": " << content << llendl; + #endif // LL_AVATAR_RENDER_INFO_LOG_SPAM + + if (content.isMap()) + { + if (content.has(KEY_ERROR)) + { + const LLSD & error = content[KEY_ERROR]; + llwarns << "Avatar render info POST error: " + << error[KEY_IDENTIFIER] + << ": " << error[KEY_MESSAGE] + << " from region " << regionp->getName() + << llendl; + } + } + } + else + { + llinfos << "Avatar render weight POST result recieved but region not found for " + << mRegionHandle << llendl; + } + } + +private: + U64 mRegionHandle; +}; + + +// static +// Send request for one region, no timer checks +void LLAvatarRenderInfoAccountant::sendRenderInfoToRegion(LLViewerRegion * regionp) +{ + std::string url = regionp->getCapability("AvatarRenderInfo"); + if (!url.empty()) + { + #ifdef LL_AVATAR_RENDER_INFO_LOG_SPAM + llinfos << "Sending avatar render info to region " + << regionp->getName() + << " from " << url + << llendl; + #endif // LL_AVATAR_RENDER_INFO_LOG_SPAM + + // Build the render info to POST to the region + LLSD report = LLSD::emptyMap(); + LLSD agents = LLSD::emptyMap(); + + std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin(); + while( iter != LLCharacter::sInstances.end() ) + { + LLVOAvatar* avatar = dynamic_cast<LLVOAvatar*>(*iter); + if (avatar && + avatar->getRezzedStatus() == 2 && // Fully rezzed + !avatar->isDead() && // Not dead yet + avatar->getObjectHost() == regionp->getHost()) // Ensure it's on the same region + { + avatar->calculateUpdateRenderCost(); // Make sure the numbers are up-to-date + + LLSD info = LLSD::emptyMap(); + if (avatar->getVisualComplexity() > 0) + { + info[KEY_WEIGHT] = avatar->getVisualComplexity(); + } + if (avatar->getAttachmentGeometryBytes() > 0) + { + info[KEY_GEOMETRY] = (S32) avatar->getAttachmentGeometryBytes(); + } + if (avatar->getAttachmentSurfaceArea() > 0.f) + { + info[KEY_SURFACE] = avatar->getAttachmentSurfaceArea(); + } + if (info.size() > 0) + { + agents[avatar->getID().asString()] = info; + } + + #ifdef LL_AVATAR_RENDER_INFO_LOG_SPAM + llinfos << "Sending avatar render info for " << avatar->getID() + << ": " << info << llendl; + #endif // LL_AVATAR_RENDER_INFO_LOG_SPAM + } + iter++; + } + + report[KEY_AGENTS] = agents; + if (agents.size() > 0) + { + LLHTTPClient::post(url, report, new LLAvatarRenderInfoPostResponder(regionp->getHandle())); + } + } +} + + + + +// static +// Send request for one region, no timer checks +void LLAvatarRenderInfoAccountant::getRenderInfoFromRegion(LLViewerRegion * regionp) +{ + std::string url = regionp->getCapability("AvatarRenderInfo"); + if (!url.empty()) + { + #ifdef LL_AVATAR_RENDER_INFO_LOG_SPAM + llinfos << "Requesting avatar render info for region " + << regionp->getName() + << " from " << url + << llendl; + #endif // LL_AVATAR_RENDER_INFO_LOG_SPAM + + // First send a request to get the latest data + LLHTTPClient::get(url, new LLAvatarRenderInfoGetResponder(regionp->getHandle())); + } +} + + +// static +// Called every frame - send render weight requests to every region +void LLAvatarRenderInfoAccountant::idle() +{ + if (sRenderInfoReportTimer.hasExpired()) + { + const F32 SECS_BETWEEN_REGION_SCANS = 5.f; // Scan the region list every 5 seconds + const F32 SECS_BETWEEN_REGION_REQUEST = 60.0; // Update each region every 60 seconds + + S32 num_avs = LLCharacter::sInstances.size(); + + // Check all regions and see if it's time to fetch/send data + for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); + iter != LLWorld::getInstance()->getRegionList().end(); ++iter) + { + LLViewerRegion* regionp = *iter; + if (regionp && + regionp->isAlive() && + regionp->capabilitiesReceived() && // Region has capability URLs available + regionp->getRenderInfoRequestTimer().hasExpired()) // Time to make request + { + sendRenderInfoToRegion(regionp); + getRenderInfoFromRegion(regionp); + + // Reset this regions timer, moving to longer intervals if there are lots of avatars around + regionp->getRenderInfoRequestTimer().resetWithExpiry(SECS_BETWEEN_REGION_REQUEST + (2.f * num_avs)); + } + } + + // We scanned all the regions, reset the request timer. + sRenderInfoReportTimer.resetWithExpiry(SECS_BETWEEN_REGION_SCANS); + } +} + + +// static +// Make sRenderInfoReportTimer expire so the next call to idle() will scan and query a new region +// called via LLViewerRegion::setCapabilitiesReceived() boost signals when the capabilities +// are returned for a new LLViewerRegion, and is the earliest time to get render info +void LLAvatarRenderInfoAccountant::expireRenderInfoReportTimer() +{ + #ifdef LL_AVATAR_RENDER_INFO_LOG_SPAM + llinfos << "Viewer has new region capabilities" << llendl; + #endif // LL_AVATAR_RENDER_INFO_LOG_SPAM + + sRenderInfoReportTimer.resetWithExpiry(0.f); +} + diff --git a/indra/newview/llavatarrenderinfoaccountant.h b/indra/newview/llavatarrenderinfoaccountant.h new file mode 100644 index 0000000000..5b4a4d3db2 --- /dev/null +++ b/indra/newview/llavatarrenderinfoaccountant.h @@ -0,0 +1,54 @@ +/** + * @file llavatarrenderinfoaccountant.h + * @author Dave Simmons + * @date 2013-02-28 + * @brief + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 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 + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#if ! defined(LL_llavatarrenderinfoaccountant_H) +#define LL_llavatarrenderinfoaccountant_H + +class LLViewerRegion; + +// Class to gather avatar rendering information +// that is sent to or fetched from regions. +class LLAvatarRenderInfoAccountant +{ +public: + LLAvatarRenderInfoAccountant() {}; + ~LLAvatarRenderInfoAccountant() {}; + + static void sendRenderInfoToRegion(LLViewerRegion * regionp); + static void getRenderInfoFromRegion(LLViewerRegion * regionp); + + static void expireRenderInfoReportTimer(); + + static void idle(); + +private: + // Send data updates about once per minute, only need per-frame resolution + static LLFrameTimer sRenderInfoReportTimer; +}; + +#endif /* ! defined(LL_llavatarrenderinfoaccountant_H) */ diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index 759e1a7b4c..1d30b19308 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -1404,7 +1404,9 @@ void LLSpatialGroup::handleDestruction(const TreeNode* node) if (bridge->mAvatar.notNull()) { bridge->mAvatar->mAttachmentGeometryBytes -= mGeometryBytes; + bridge->mAvatar->mAttachmentGeometryBytes = llmax(bridge->mAvatar->mAttachmentGeometryBytes, 0); bridge->mAvatar->mAttachmentSurfaceArea -= mSurfaceArea; + bridge->mAvatar->mAttachmentSurfaceArea = llmax(bridge->mAvatar->mAttachmentSurfaceArea, 0.f); } } diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index e4234a538d..eb5a0b8d37 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -44,6 +44,7 @@ #include "llagent.h" #include "llagentcamera.h" +#include "llavatarrenderinfoaccountant.h" #include "llcallingcard.h" #include "llcaphttpsender.h" #include "llcapabilitylistener.h" @@ -333,6 +334,9 @@ LLViewerRegion::LLViewerRegion(const U64 &handle, mImpl->mObjectPartition.push_back(new LLBridgePartition()); //PARTITION_BRIDGE mImpl->mObjectPartition.push_back(new LLHUDParticlePartition());//PARTITION_HUD_PARTICLE mImpl->mObjectPartition.push_back(NULL); //PARTITION_NONE + + mRenderInfoRequestTimer.resetWithExpiry(0.f); // Set timer to be expired + setCapabilitiesReceivedCallback(boost::bind(&LLAvatarRenderInfoAccountant::expireRenderInfoReportTimer)); } @@ -1514,6 +1518,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) capabilityNames.append("AgentState"); capabilityNames.append("AttachmentResources"); capabilityNames.append("AvatarPickerSearch"); + capabilityNames.append("AvatarRenderInfo"); capabilityNames.append("CharacterProperties"); capabilityNames.append("ChatSessionRequest"); capabilityNames.append("CopyInventoryFromNotecard"); diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index c9fffaf30e..2d3a622e42 100644 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -365,6 +365,8 @@ public: LLDynamicArray<U32> mMapAvatars; LLDynamicArray<LLUUID> mMapAvatarIDs; + LLFrameTimer & getRenderInfoRequestTimer() { return mRenderInfoRequestTimer; }; + private: LLViewerRegionImpl * mImpl; @@ -421,6 +423,8 @@ private: BOOL mReleaseNotesRequested; LLSD mSimulatorFeatures; + + LLFrameTimer mRenderInfoRequestTimer; }; inline BOOL LLViewerRegion::getAllowDamage() const diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 9e5d44eb1f..1fc20fd207 100755 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -662,6 +662,9 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, mSpecialRenderMode(0), mAttachmentGeometryBytes(0), mAttachmentSurfaceArea(0.f), + mReportedVisualComplexity(-1), + mReportedAttachmentGeometryBytes(-1), + mReportedAttachmentSurfaceArea(-1.f), mTurning(FALSE), mPelvisToFoot(0.f), mLastSkeletonSerialNum( 0 ), diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 0e7bf7a6c9..495d3e9483 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -257,9 +257,20 @@ public: void calculateUpdateRenderCost(); void updateVisualComplexity() { mVisualComplexityStale = TRUE; } - S32 getVisualComplexity() { return mVisualComplexity; }; - S32 getUpdatePeriod() { return mUpdatePeriod; }; - const LLColor4 & getMutedAVColor() { return mMutedAVColor; }; + S32 getVisualComplexity() { return mVisualComplexity; }; // Numbers calculated here by rendering AV + S32 getAttachmentGeometryBytes() { return mAttachmentGeometryBytes; }; // number of bytes in attached geometry + F32 getAttachmentSurfaceArea() { return mAttachmentSurfaceArea; }; // estimated surface area of attachments + + S32 getReportedVisualComplexity() { return mReportedVisualComplexity; }; // Numbers as reported by the SL server + void setReportedVisualComplexity(S32 value) { mReportedVisualComplexity = value; }; + S32 getReportedAttachmentGeometryBytes() { return mReportedAttachmentGeometryBytes; }; //number of bytes in attached geometry + void setReportedAttachmentGeometryBytes(S32 value) { mReportedAttachmentGeometryBytes = value; }; + F32 getReportedAttachmentSurfaceArea() { return mReportedAttachmentSurfaceArea; }; //estimated surface area of attachments + void setReportedAttachmentSurfaceArea(F32 value) { mReportedAttachmentSurfaceArea = value; }; + + S32 getUpdatePeriod() { return mUpdatePeriod; }; + const LLColor4 & getMutedAVColor() { return mMutedAVColor; }; + void idleUpdateBelowWater(); @@ -469,9 +480,13 @@ public: static void restoreGL(); BOOL mIsDummy; // for special views S32 mSpecialRenderMode; // special lighting - U32 mAttachmentGeometryBytes; //number of bytes in attached geometry + S32 mAttachmentGeometryBytes; //number of bytes in attached geometry F32 mAttachmentSurfaceArea; //estimated surface area of attachments + S32 mReportedVisualComplexity; // Numbers as reported by the SL server + S32 mReportedAttachmentGeometryBytes; //number of bytes in attached geometry + F32 mReportedAttachmentSurfaceArea; //estimated surface area of attachments + private: bool shouldAlphaMask(); diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 426ad8bc21..71ee2da216 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -4242,7 +4242,9 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) if (pAvatarVO) { pAvatarVO->mAttachmentGeometryBytes -= group->mGeometryBytes; + pAvatarVO->mAttachmentGeometryBytes = llmax(pAvatarVO->mAttachmentGeometryBytes, 0); pAvatarVO->mAttachmentSurfaceArea -= group->mSurfaceArea; + pAvatarVO->mAttachmentSurfaceArea = llmax(pAvatarVO->mAttachmentSurfaceArea, 0.f); } group->mGeometryBytes = 0; |