diff options
Diffstat (limited to 'indra/newview/llavatarrenderinfoaccountant.cpp')
-rw-r--r-- | indra/newview/llavatarrenderinfoaccountant.cpp | 534 |
1 files changed, 288 insertions, 246 deletions
diff --git a/indra/newview/llavatarrenderinfoaccountant.cpp b/indra/newview/llavatarrenderinfoaccountant.cpp index 38e153137c..d351b38653 100644 --- a/indra/newview/llavatarrenderinfoaccountant.cpp +++ b/indra/newview/llavatarrenderinfoaccountant.cpp @@ -28,14 +28,17 @@ // 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 "httprequest.h" +#include "httphandler.h" +#include "httpresponse.h" +#include "llcorehttputil.h" +#include "llappcorehttp.h" +#include "llavatarrendernotifier.h" #include "lltimer.h" #include "llviewercontrol.h" #include "llviewermenu.h" @@ -43,233 +46,290 @@ #include "llviewerregion.h" #include "llvoavatar.h" #include "llworld.h" +// associated header +#include "llavatarrenderinfoaccountant.h" static const std::string KEY_AGENTS = "agents"; // map static const std::string KEY_WEIGHT = "weight"; // integer +static const std::string KEY_TOO_COMPLEX = "tooComplex"; // bool +static const std::string KEY_OVER_COMPLEXITY_LIMIT = "overlimit"; // integer +static const std::string KEY_REPORTING_COMPLEXITY_LIMIT = "reportinglimit"; // integer 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; +static const F32 SECS_BETWEEN_REGION_SCANS = 5.f; // Scan the region list every 5 seconds +static const F32 SECS_BETWEEN_REGION_REQUEST = 15.0; // Look for new avs every 15 seconds +static const F32 SECS_BETWEEN_REGION_REPORTS = 60.0; // Update each region every 60 seconds + + +// The policy class for HTTP traffic; this is the right value for all capability requests. +static LLCore::HttpRequest::policy_t http_policy(LLAppCoreHttp::AP_REPORTING); + +// Priority for HTTP requests. Use 0U. +static LLCore::HttpRequest::priority_t http_priority(0U); +LLAvatarRenderInfoAccountant::LLAvatarRenderInfoAccountant() + : mHttpRequest(new LLCore::HttpRequest) + , mHttpHeaders(new LLCore::HttpHeaders) + , mHttpOptions(new LLCore::HttpOptions) +{ + mHttpOptions->setTransferTimeout(SECS_BETWEEN_REGION_SCANS); + + mHttpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_LLSD_XML); + mHttpHeaders->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_LLSD_XML); +} + +LLAvatarRenderInfoAccountant::~LLAvatarRenderInfoAccountant() +{ + mHttpOptions->release(); + mHttpHeaders->release(); + // delete mHttpRequest; ??? +} // HTTP responder class for GET request for avatar render weight information -class LLAvatarRenderInfoGetResponder : public LLHTTPClient::Responder +class LLAvatarRenderInfoGetHandler : public LLCore::HttpHandler { +private: + LOG_CLASS(LLAvatarRenderInfoGetHandler); + public: - LLAvatarRenderInfoGetResponder(U64 region_handle) : mRegionHandle(region_handle) - { - } - - virtual void error(U32 statusNum, const std::string& reason) + LLAvatarRenderInfoGetHandler() : LLCore::HttpHandler() { - LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); - if (regionp) - { - LL_WARNS() << "HTTP error result for avatar weight GET: " << statusNum - << ", " << reason - << " returned by region " << regionp->getName() - << LL_ENDL; - } - else - { - LL_WARNS() << "Avatar render weight GET error recieved but region not found for " - << mRegionHandle - << ", error " << statusNum - << ", " << reason - << LL_ENDL; - } - } - virtual void result(const LLSD& content) + void onCompleted(LLCore::HttpHandle handle, + LLCore::HttpResponse* response) { - LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); - if (regionp) - { - if (LLAvatarRenderInfoAccountant::logRenderInfo()) - { - LL_INFOS() << "LRI: Result for avatar weights request for region " << regionp->getName() << ":" << LL_ENDL; - } - - if (content.isMap()) - { - if (content.has(KEY_AGENTS)) + LLCore::HttpStatus status = response->getStatus(); + if (status) + { + LL_DEBUGS("AvatarRenderInfo") << "response"<<LL_ENDL; + LLSD avatar_render_info; + if (LLCoreHttpUtil::responseToLLSD(response, false /* quiet logging */, + avatar_render_info)) { - const LLSD & agents = content[KEY_AGENTS]; - if (agents.isMap()) + if (avatar_render_info.isMap()) { - LLSD::map_const_iterator report_iter = agents.beginMap(); - while (report_iter != agents.endMap()) + if ( avatar_render_info.has(KEY_REPORTING_COMPLEXITY_LIMIT) + && avatar_render_info.has(KEY_OVER_COMPLEXITY_LIMIT)) { - 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 - - if (LLAvatarRenderInfoAccountant::logRenderInfo()) - { - LL_INFOS() << "LRI: Agent " << target_agent_id - << ": " << agent_info_map << LL_ENDL; - } + U32 reporting = avatar_render_info[KEY_REPORTING_COMPLEXITY_LIMIT].asInteger(); + U32 overlimit = avatar_render_info[KEY_OVER_COMPLEXITY_LIMIT].asInteger(); - if (agent_info_map.has(KEY_WEIGHT)) + LL_DEBUGS("AvatarRenderInfo") << "complexity limit: "<<reporting<<" reporting, "<<overlimit<<" over limit"<<LL_ENDL; + + LLAvatarRenderNotifier::getInstance()->updateNotificationRegion(reporting, overlimit); + } + + if (avatar_render_info.has(KEY_AGENTS)) + { + const LLSD & agents = avatar_render_info[KEY_AGENTS]; + if (agents.isMap()) + { + for (LLSD::map_const_iterator agent_iter = agents.beginMap(); + agent_iter != agents.endMap(); + agent_iter++ + ) { - ((LLVOAvatar *) avatarp)->setReportedVisualComplexity(agent_info_map[KEY_WEIGHT].asInteger()); - } + LLUUID target_agent_id = LLUUID(agent_iter->first); + LLViewerObject* avatarp = gObjectList.findObject(target_agent_id); + if (avatarp && avatarp->isAvatar()) + { + const LLSD & agent_info_map = agent_iter->second; + if (agent_info_map.isMap()) + { + LL_DEBUGS("AvatarRenderInfo") << " Agent " << target_agent_id + << ": " << agent_info_map << LL_ENDL; + + if (agent_info_map.has(KEY_WEIGHT)) + { + ((LLVOAvatar *) avatarp)->setReportedVisualComplexity(agent_info_map[KEY_WEIGHT].asInteger()); + } + } + else + { + LL_WARNS("AvatarRenderInfo") << "agent entry invalid" + << " agent " << target_agent_id + << " map " << agent_info_map + << LL_ENDL; + } + } + else + { + LL_DEBUGS("AvatarRenderInfo") << "Unknown agent " << target_agent_id << LL_ENDL; + } + } // for agent_iter } - report_iter++; + else + { + LL_WARNS("AvatarRenderInfo") << "malformed get response agents avatar_render_info is not map" << LL_ENDL; + } + } // has "agents" + else if (avatar_render_info.has(KEY_ERROR)) + { + const LLSD & error = avatar_render_info[KEY_ERROR]; + LL_WARNS("AvatarRenderInfo") << "Avatar render info GET error: " + << error[KEY_IDENTIFIER] + << ": " << error[KEY_MESSAGE] + << LL_ENDL; + } + else + { + LL_WARNS("AvatarRenderInfo") << "no agent key in get response" << LL_ENDL; } } - } // has "agents" - else if (content.has(KEY_ERROR)) + else + { + LL_WARNS("AvatarRenderInfo") << "malformed get response is not map" << LL_ENDL; + } + } + else { - const LLSD & error = content[KEY_ERROR]; - LL_WARNS() << "Avatar render info GET error: " - << error[KEY_IDENTIFIER] - << ": " << error[KEY_MESSAGE] - << " from region " << regionp->getName() - << LL_ENDL; + LL_WARNS("AvatarRenderInfo") << "malformed get response parse failure" << LL_ENDL; } - } - } - else - { - LL_INFOS() << "Avatar render weight info recieved but region not found for " - << mRegionHandle << LL_ENDL; + } + else + { + // Something went wrong. Translate the status to + // a meaningful message. + LL_WARNS("AvatarRenderInfo") << "GET failed Status: " + << status.toTerseString() + << ", Reason: " << status.toString() + << LL_ENDL; + } + + delete this; // release the handler object } - } - -private: - U64 mRegionHandle; }; // HTTP responder class for POST request for avatar render weight information -class LLAvatarRenderInfoPostResponder : public LLHTTPClient::Responder +class LLAvatarRenderInfoPostHandler : public LLCore::HttpHandler { -public: - LLAvatarRenderInfoPostResponder(U64 region_handle) : mRegionHandle(region_handle) - { - } + private: + LOG_CLASS(LLAvatarRenderInfoPostHandler); - virtual void error(U32 statusNum, const std::string& reason) + public: + LLAvatarRenderInfoPostHandler() : LLCore::HttpHandler() { - LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); - if (regionp) - { - LL_WARNS() << "HTTP error result for avatar weight POST: " << statusNum - << ", " << reason - << " returned by region " << regionp->getName() - << LL_ENDL; - } - else - { - LL_WARNS() << "Avatar render weight POST error recieved but region not found for " - << mRegionHandle - << ", error " << statusNum - << ", " << reason - << LL_ENDL; - } } - virtual void result(const LLSD& content) - { - LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); - if (regionp) + void onCompleted(LLCore::HttpHandle handle, + LLCore::HttpResponse* response) { - if (LLAvatarRenderInfoAccountant::logRenderInfo()) + LLCore::HttpStatus status = response->getStatus(); + if (status) { - LL_INFOS() << "LRI: Result for avatar weights POST for region " << regionp->getName() - << ": " << content << LL_ENDL; + LL_DEBUGS("AvatarRenderInfo") << "post succeeded" << LL_ENDL; } - - if (content.isMap()) + else { - if (content.has(KEY_ERROR)) - { - const LLSD & error = content[KEY_ERROR]; - LL_WARNS() << "Avatar render info POST error: " - << error[KEY_IDENTIFIER] - << ": " << error[KEY_MESSAGE] - << " from region " << regionp->getName() - << LL_ENDL; - } - } + // Something went wrong. Translate the status to + // a meaningful message. + LL_WARNS("AvatarRenderInfo") << "POST failed Status: " + << status.toTerseString() + << ", Reason: " << status.toString() + << LL_ENDL; + } + + delete this; // release the handler object } - else - { - LL_INFOS() << "Avatar render weight POST result recieved but region not found for " - << mRegionHandle << LL_ENDL; - } - } - -private: - U64 mRegionHandle; }; -// static -// Send request for one region, no timer checks +// Send request for avatar weights in one region +// called when the mRenderInfoScanTimer expires (forced when entering a new region) void LLAvatarRenderInfoAccountant::sendRenderInfoToRegion(LLViewerRegion * regionp) { - std::string url = regionp->getCapability("AvatarRenderInfo"); - if (!url.empty()) + if ( regionp->getRenderInfoReportTimer().hasExpired() ) // Time to make request { - if (logRenderInfo()) + U32 num_avs = 0; + + std::string url = regionp->getCapability("AvatarRenderInfo"); + if (!url.empty()) { - LL_INFOS() << "LRI: Sending avatar render info to region " - << regionp->getName() - << " from " << url - << LL_ENDL; - } - - // Build the render info to POST to the region - LLSD report = LLSD::emptyMap(); - LLSD agents = LLSD::emptyMap(); + // Build the render info to POST to the region + 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 && // Mostly rezzed (maybe without baked textures downloaded) - !avatar->isDead() && // Not dead yet - avatar->getObjectHost() == regionp->getHost()) // Ensure it's on the same region + std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin(); + while( iter != LLCharacter::sInstances.end() ) { - avatar->calculateUpdateRenderCost(); // Make sure the numbers are up-to-date - - LLSD info = LLSD::emptyMap(); - if (avatar->getVisualComplexity() > 0) + LLVOAvatar* avatar = dynamic_cast<LLVOAvatar*>(*iter); + if (avatar && + avatar->getRezzedStatus() >= 2 && // Mostly rezzed (maybe without baked textures downloaded) + !avatar->isDead() && // Not dead yet + avatar->getObjectHost() == regionp->getHost()) // Ensure it's on the same region { - info[KEY_WEIGHT] = avatar->getVisualComplexity(); - agents[avatar->getID().asString()] = info; + avatar->calculateUpdateRenderComplexity(); // Make sure the numbers are up-to-date - if (logRenderInfo()) + LLSD info = LLSD::emptyMap(); + U32 avatar_complexity = avatar->getVisualComplexity(); + if (avatar_complexity > 0) { - LL_INFOS() << "LRI: Sending avatar render info for " << avatar->getID() - << ": " << info << LL_ENDL; - LL_INFOS() << "LRI: other info geometry " << avatar->getAttachmentGeometryBytes() - << ", area " << avatar->getAttachmentSurfaceArea() - << LL_ENDL; + // the weight/complexity is unsigned, but LLSD only stores signed integers, + // so if it's over that (which would be ridiculously high), just store the maximum signed int value + info[KEY_WEIGHT] = (S32)(avatar_complexity < S32_MAX ? avatar_complexity : S32_MAX); + info[KEY_TOO_COMPLEX] = LLSD::Boolean(avatar->isTooComplex()); + agents[avatar->getID().asString()] = info; + + LL_DEBUGS("AvatarRenderInfo") << "Sending avatar render info for " << avatar->getID() + << ": " << info << LL_ENDL; + num_avs++; } } + iter++; } - iter++; - } - report[KEY_AGENTS] = agents; - if (agents.size() > 0) + if (num_avs > 0) + { + LLSD report = LLSD::emptyMap(); + report[KEY_AGENTS] = agents; + + LLCore::HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID); + LLAvatarRenderInfoPostHandler* handler = new LLAvatarRenderInfoPostHandler; + + handle = LLCoreHttpUtil::requestPostWithLLSD(mHttpRequest, + http_policy, + http_priority, + url, + report, + mHttpOptions, + mHttpHeaders, + handler); + if (LLCORE_HTTP_HANDLE_INVALID == handle) + { + LLCore::HttpStatus status(mHttpRequest->getStatus()); + LL_WARNS("AvatarRenderInfo") << "HTTP POST request failed" + << " Status: " << status.toTerseString() + << " Reason: '" << status.toString() << "'" + << LL_ENDL; + delete handler; + } + else + { + LL_INFOS("AvatarRenderInfo") << "Sent render costs for " << num_avs + << " avatars to region " << regionp->getName() + << LL_ENDL; + + + } + } + else + { + LL_DEBUGS("AvatarRenderInfo") << "no agent info to send" << LL_ENDL; + } + } + else { - LLHTTPClient::post(url, report, new LLAvatarRenderInfoPostResponder(regionp->getHandle())); + LL_WARNS("AvatarRenderInfo") << "AvatarRenderInfo cap is empty" << LL_ENDL; } + + // Reset this regions timer, moving to longer intervals if there are lots of avatars around + regionp->getRenderInfoReportTimer().resetWithExpiry(SECS_BETWEEN_REGION_REPORTS + (2.f * num_avs)); } } @@ -280,19 +340,39 @@ void LLAvatarRenderInfoAccountant::sendRenderInfoToRegion(LLViewerRegion * regio // Send request for one region, no timer checks void LLAvatarRenderInfoAccountant::getRenderInfoFromRegion(LLViewerRegion * regionp) { - std::string url = regionp->getCapability("AvatarRenderInfo"); - if (!url.empty()) + if (regionp->getRenderInfoRequestTimer().hasExpired()) { - if (logRenderInfo()) + std::string url = regionp->getCapability("AvatarRenderInfo"); + if (!url.empty()) { - LL_INFOS() << "LRI: Requesting avatar render info for region " - << regionp->getName() - << " from " << url - << LL_ENDL; + + LLAvatarRenderInfoGetHandler* handler = new LLAvatarRenderInfoGetHandler; + // First send a request to get the latest data + LLCore::HttpHandle handle = mHttpRequest->requestGet(http_policy, + http_priority, + url, + NULL, + NULL, + handler); + if (LLCORE_HTTP_HANDLE_INVALID != handle) + { + LL_INFOS("AvatarRenderInfo") << "Requested avatar render info for region " + << regionp->getName() + << LL_ENDL; + } + else + { + LL_WARNS("AvatarRenderInfo") << "Failed to launch HTTP GET request. Try again." + << LL_ENDL; + delete handler; + } + } + else + { + LL_WARNS("AvatarRenderInfo") << "no AvatarRenderInfo cap for " << regionp->getName() << LL_ENDL; } - // First send a request to get the latest data - LLHTTPClient::get(url, new LLAvatarRenderInfoGetResponder(regionp->getHandle())); + regionp->getRenderInfoRequestTimer().resetWithExpiry(SECS_BETWEEN_REGION_REQUEST); } } @@ -301,98 +381,60 @@ void LLAvatarRenderInfoAccountant::getRenderInfoFromRegion(LLViewerRegion * regi // 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 + mHttpRequest->update(0); // give any pending http operations a chance to call completion methods - S32 num_avs = LLCharacter::sInstances.size(); - - if (logRenderInfo()) - { - LL_INFOS() << "LRI: Scanning all regions and checking for render info updates" - << LL_ENDL; - } + if (mRenderInfoScanTimer.hasExpired()) + { + LL_DEBUGS("AvatarRenderInfo") << "Scanning regions for render info updates" + << LL_ENDL; - // Check all regions and see if it's time to fetch/send data + // Check all regions for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); - iter != LLWorld::getInstance()->getRegionList().end(); ++iter) + 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 + if ( regionp + && regionp->isAlive() + && regionp->capabilitiesReceived()) { + // each of these is further governed by and resets its own timer 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 LLCachedControl<U32> render_auto_mute_functions(gSavedSettings, "RenderAutoMuteFunctions", 0); - static U32 prev_render_auto_mute_functions = (U32) -1; - if (prev_render_auto_mute_functions != render_auto_mute_functions) - { - prev_render_auto_mute_functions = render_auto_mute_functions; - - // Adjust menus - BOOL show_items = (BOOL)(render_auto_mute_functions & 0x04); - gMenuAvatarOther->setItemVisible( std::string("Normal"), show_items); - gMenuAvatarOther->setItemVisible( std::string("Always use impostor"), show_items); - gMenuAvatarOther->setItemVisible( std::string("Never use impostor"), show_items); - gMenuAvatarOther->setItemVisible( std::string("Impostor seperator"), show_items); - - gMenuAttachmentOther->setItemVisible( std::string("Normal"), show_items); - gMenuAttachmentOther->setItemVisible( std::string("Always use impostor"), show_items); - gMenuAttachmentOther->setItemVisible( std::string("Never use impostor"), show_items); - gMenuAttachmentOther->setItemVisible( std::string("Impostor seperator"), show_items); - - if (!show_items) - { // Turning off visual muting - for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin(); - iter != LLCharacter::sInstances.end(); ++iter) - { // Make sure all AVs have the setting cleared - LLVOAvatar* inst = (LLVOAvatar*) *iter; - inst->setCachedVisualMute(false); - } - } + mRenderInfoScanTimer.resetWithExpiry(SECS_BETWEEN_REGION_SCANS); } } +void LLAvatarRenderInfoAccountant::resetRenderInfoScanTimer() +{ + // this will force the next frame to rescan + mRenderInfoScanTimer.reset(); +} // 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 +// 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(const LLUUID& region_id) +void LLAvatarRenderInfoAccountant::scanNewRegion(const LLUUID& region_id) { - if (logRenderInfo()) - { - LL_INFOS() << "LRI: Viewer has new region capabilities, clearing global render info timer" - << " and timer for region " << region_id - << LL_ENDL; - } + LL_INFOS("AvatarRenderInfo") << region_id << LL_ENDL; - // Reset the global timer so it will scan regions immediately - sRenderInfoReportTimer.reset(); + // Reset the global timer so it will scan regions on the next call to ::idle + LLAvatarRenderInfoAccountant::getInstance()->resetRenderInfoScanTimer(); LLViewerRegion* regionp = LLWorld::instance().getRegionFromID(region_id); if (regionp) - { // Reset the region's timer so it will request data immediately + { // Reset the region's timers so we will: + // * request render info from it immediately + // * report on the following scan regionp->getRenderInfoRequestTimer().reset(); + regionp->getRenderInfoReportTimer().resetWithExpiry(SECS_BETWEEN_REGION_SCANS); + } + else + { + LL_WARNS("AvatarRenderInfo") << "unable to resolve region "<<region_id<<LL_ENDL; } -} - -// static -bool LLAvatarRenderInfoAccountant::logRenderInfo() -{ - static LLCachedControl<bool> render_mute_logging_enabled(gSavedSettings, "RenderAutoMuteLogging", false); - return render_mute_logging_enabled; } |