MAINT-2426 : Viewer support for new simulator AvatarRenderInfo capability. Reviewed by Kelly

meow-7.2.2
simon 2013-03-28 16:06:07 -07:00
parent 6bb7fd40d0
commit d8dc74b833
10 changed files with 455 additions and 4 deletions

View File

@ -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

View File

@ -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);

View File

@ -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);
}

View File

@ -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) */

View File

@ -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);
}
}

View File

@ -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");

View File

@ -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

View File

@ -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 ),

View File

@ -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();

View File

@ -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;