From 6be5e1eb01a5b12ee4152ae9d4f53110a4bea246 Mon Sep 17 00:00:00 2001 From: andreykproductengine Date: Fri, 7 Oct 2016 20:29:42 +0300 Subject: MAINT-6792 Improvements for HUD warning --- indra/newview/app_settings/settings.xml | 6 +- indra/newview/llavatarrendernotifier.cpp | 259 +++++++++++++++++-------- indra/newview/llavatarrendernotifier.h | 34 +++- indra/newview/llviewerobject.cpp | 2 +- indra/newview/llviewerobject.h | 2 +- indra/newview/llvoavatar.cpp | 31 +-- indra/newview/skins/default/xui/en/strings.xml | 12 +- 7 files changed, 237 insertions(+), 109 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 674923e88d..460c0809a6 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -10148,16 +10148,16 @@ Value 6 - RenderHUDTexturesVirtualMemoryWarning + RenderHUDTexturesMemoryWarning Comment - Viewer will warn user about HUD textures using memory above this value (Virtual memory, in pixels) + Viewer will warn user about HUD textures using memory above this value (in bytes) Persist 1 Type U32 Value - 10000000 + 32000000 RenderAutoMuteSurfaceAreaLimit diff --git a/indra/newview/llavatarrendernotifier.cpp b/indra/newview/llavatarrendernotifier.cpp index f7a1ef1621..94584a623b 100644 --- a/indra/newview/llavatarrendernotifier.cpp +++ b/indra/newview/llavatarrendernotifier.cpp @@ -38,6 +38,7 @@ #include "llnotifications.h" #include "llnotificationsutil.h" #include "llnotificationtemplate.h" +#include "llslurl.h" #include "lltimer.h" #include "llvoavatarself.h" #include "llviewercontrol.h" @@ -54,7 +55,7 @@ static const U32 OVER_LIMIT_UPDATE_DELAY = 70; static const U32 WARN_HUD_OBJECTS_LIMIT = 1000; static const U32 WARN_HUD_TEXTURES_LIMIT = 200; static const U32 WARN_HUD_OVERSIZED_TEXTURES_LIMIT = 6; -static const U32 WARN_HUD_TEXTURE_MEMORY_LIMIT = 10000000; // in pixels +static const U32 WARN_HUD_TEXTURE_MEMORY_LIMIT = 32000000; // in bytes LLAvatarRenderNotifier::LLAvatarRenderNotifier() : @@ -271,7 +272,17 @@ void LLAvatarRenderNotifier::updateNotificationAgent(U32 agentComplexity) // LLHUDRenderNotifier -LLHUDRenderNotifier::LLHUDRenderNotifier() +static const char* e_hud_messages[] = +{ + "hud_render_textures_warning", + "hud_render_cramped_warning", + "hud_render_heavy_textures_warning", + "hud_render_cost_warning", + "hud_render_memory_warning", +}; + +LLHUDRenderNotifier::LLHUDRenderNotifier() : +mReportedHUDWarning(WARN_NONE) { } @@ -279,118 +290,200 @@ LLHUDRenderNotifier::~LLHUDRenderNotifier() { } -void LLHUDRenderNotifier::updateNotificationHUD(LLHUDComplexity new_complexity) +void LLHUDRenderNotifier::updateNotificationHUD(hud_complexity_list_t complexity) { - if (!isAgentAvatarValid()) + if (!isAgentAvatarValid() || !gAgentWearables.areWearablesLoaded()) { // data not ready. return; } - static const char* hud_memory = "hud_render_memory_warning"; - static const char* hud_cost = "hud_render_cost_warning"; - static const char* hud_heavy = "hud_render_heavy_textures_warning"; - static const char* hud_cramped = "hud_render_cramped_warning"; - static const char* hud_textures = "hud_render_textures_warning"; + // TODO: + // Find a way to show message with list of issues, but without making it too large + // and intrusive. - static LLCachedControl max_render_cost(gSavedSettings, "RenderAvatarMaxComplexity", 0U); // ties max HUD cost to avatar cost - static LLCachedControl max_objects_count(gSavedSettings, "RenderHUDObjectsWarning", WARN_HUD_OBJECTS_LIMIT); - static LLCachedControl max_textures_count(gSavedSettings, "RenderHUDTexturesWarning", WARN_HUD_TEXTURES_LIMIT); - static LLCachedControl max_oversized_count(gSavedSettings, "RenderHUDOversizedTexturesWarning", WARN_HUD_OVERSIZED_TEXTURES_LIMIT); - static LLCachedControl max_texture_memory(gSavedSettings, "RenderHUDTexturesVirtualMemoryWarning", WARN_HUD_TEXTURE_MEMORY_LIMIT); + LLHUDComplexity new_total_complexity; + LLHUDComplexity report_complexity; - if (mHUDPopUpDelayTimer.hasExpired()) + hud_complexity_list_t::iterator iter = complexity.begin(); + hud_complexity_list_t::iterator end = complexity.end(); + EWarnLevel warning_level = WARN_NONE; + for (; iter != end; ++iter) { - // Show warning with highest importance (5m delay between warnings by default) - // TODO: - // Consider showing message with list of issues. - // For now shows one after another if update arrives and timer expired, so - // consider showing only one most important or consider triggering not - // only in case of update - if (mReportedHUDComplexity.texturesSizeTotal < new_complexity.texturesSizeTotal - && new_complexity.texturesSizeTotal > max_texture_memory) + LLHUDComplexity object_complexity = *iter; + EWarnLevel object_level = getWarningType(object_complexity, report_complexity); + if (object_level >= 0) { - displayHUDNotification(hud_memory); - LL_DEBUGS("HUDdetail") << "HUD memory usage over limit," - << " was " << mReportedHUDComplexity.texturesSizeTotal - << " is " << new_complexity.texturesSizeTotal << LL_ENDL; - mReportedHUDComplexity.texturesSizeTotal = new_complexity.texturesSizeTotal; + warning_level = object_level; + report_complexity = object_complexity; } - else if ((mReportedHUDComplexity.objectsCost < new_complexity.objectsCost - || mReportedHUDComplexity.texturesCost < new_complexity.texturesCost) - && max_render_cost > 0 - && new_complexity.objectsCost + new_complexity.texturesCost > max_render_cost) - { - LL_DEBUGS("HUDdetail") << "HUD complexity over limit," - << " HUD textures cost: " << new_complexity.texturesCost - << " HUD objects cost: " << new_complexity.objectsCost << LL_ENDL; - displayHUDNotification(hud_cost); - mReportedHUDComplexity.objectsCost = new_complexity.objectsCost; - mReportedHUDComplexity.texturesCost = new_complexity.texturesCost; - } - else if (mReportedHUDComplexity.largeTexturesCount < new_complexity.largeTexturesCount - && new_complexity.largeTexturesCount > max_oversized_count) - { - LL_DEBUGS("HUDdetail") << "HUD contains to many large textures: " - << new_complexity.largeTexturesCount << LL_ENDL; - displayHUDNotification(hud_heavy); - mReportedHUDComplexity.largeTexturesCount = new_complexity.largeTexturesCount; - } - else if (mReportedHUDComplexity.texturesCount < new_complexity.texturesCount - && new_complexity.texturesCount > max_textures_count) - { - LL_DEBUGS("HUDdetail") << "HUD contains too many textures: " - << new_complexity.texturesCount << LL_ENDL; - displayHUDNotification(hud_cramped); - mReportedHUDComplexity.texturesCount = new_complexity.texturesCount; - } - else if (mReportedHUDComplexity.objectsCount < new_complexity.objectsCount - && new_complexity.objectsCount > max_objects_count) + new_total_complexity.objectsCost += object_complexity.objectsCost; + new_total_complexity.objectsCount += object_complexity.objectsCount; + new_total_complexity.texturesCost += object_complexity.texturesCost; + new_total_complexity.texturesCount += object_complexity.texturesCount; + new_total_complexity.largeTexturesCount += object_complexity.largeTexturesCount; + new_total_complexity.texturesMemoryTotal += object_complexity.texturesMemoryTotal; + } + + if (mHUDPopUpDelayTimer.hasExpired() || isNotificationVisible()) + { + if (warning_level >= 0) { - LL_DEBUGS("HUDdetail") << "HUD contains too many objects: " - << new_complexity.objectsCount << LL_ENDL; - displayHUDNotification(hud_textures); - mReportedHUDComplexity.objectsCount = new_complexity.objectsCount; + // Display info about most complex HUD object + // make sure it shown only once unless object's complexity or object itself changed + if (mReportedHUDComplexity.objectId != report_complexity.objectId + || mReportedHUDWarning != warning_level) + { + displayHUDNotification(warning_level, report_complexity.objectId, report_complexity.objectName, report_complexity.jointName); + mReportedHUDComplexity = report_complexity; + mReportedHUDWarning = warning_level; + } } else { - // all warnings displayed, just store everything so that we will - // be able to reduce values and show warnings again later - mReportedHUDComplexity = new_complexity; + // Check if total complexity is above threshold and above previous warning + // Show warning with highest importance (5m delay between warnings by default) + if (!mReportedHUDComplexity.objectId.isNull()) + { + mReportedHUDComplexity.reset(); + mReportedHUDWarning = WARN_NONE; + } + + warning_level = getWarningType(new_total_complexity, mReportedHUDComplexity); + if (warning_level >= 0 && mReportedHUDWarning != warning_level) + { + displayHUDNotification(warning_level); + } + mReportedHUDComplexity = new_total_complexity; + mReportedHUDWarning = warning_level; } } + else if (warning_level >= 0) + { + LL_DEBUGS("HUDdetail") << "HUD individual warning postponed" << LL_ENDL; + } + + if (mLatestHUDComplexity.objectsCost != new_total_complexity.objectsCost + || mLatestHUDComplexity.objectsCount != new_total_complexity.objectsCount + || mLatestHUDComplexity.texturesCost != new_total_complexity.texturesCost + || mLatestHUDComplexity.texturesCount != new_total_complexity.texturesCount + || mLatestHUDComplexity.largeTexturesCount != new_total_complexity.largeTexturesCount + || mLatestHUDComplexity.texturesMemoryTotal != new_total_complexity.texturesMemoryTotal) + { + LL_INFOS("HUDdetail") << "HUD textures count: " << new_total_complexity.texturesCount + << " HUD textures cost: " << new_total_complexity.texturesCost + << " Large textures: " << new_total_complexity.largeTexturesCount + << " HUD objects cost: " << new_total_complexity.objectsCost + << " HUD objects count: " << new_total_complexity.objectsCount << LL_ENDL; + + mLatestHUDComplexity = new_total_complexity; + } +} + +bool LLHUDRenderNotifier::isNotificationVisible() +{ + return mHUDNotificationPtr != NULL && mHUDNotificationPtr->isActive(); +} + +// private static +LLHUDRenderNotifier::EWarnLevel LLHUDRenderNotifier::getWarningType(LLHUDComplexity object_complexity, LLHUDComplexity cmp_complexity) +{ + static LLCachedControl max_render_cost(gSavedSettings, "RenderAvatarMaxComplexity", 0U); // ties max HUD cost to avatar cost + static LLCachedControl max_objects_count(gSavedSettings, "RenderHUDObjectsWarning", WARN_HUD_OBJECTS_LIMIT); + static LLCachedControl max_textures_count(gSavedSettings, "RenderHUDTexturesWarning", WARN_HUD_TEXTURES_LIMIT); + static LLCachedControl max_oversized_count(gSavedSettings, "RenderHUDOversizedTexturesWarning", WARN_HUD_OVERSIZED_TEXTURES_LIMIT); + static LLCachedControl max_texture_memory(gSavedSettings, "RenderHUDTexturesMemoryWarning", WARN_HUD_TEXTURE_MEMORY_LIMIT); + + if (cmp_complexity.texturesMemoryTotal < object_complexity.texturesMemoryTotal + && object_complexity.texturesMemoryTotal > (F64Bytes)max_texture_memory) + { + // Note: Memory might not be accurate since texture is still loading or discard level changes + + LL_DEBUGS("HUDdetail") << "HUD " << object_complexity.objectName << " memory usage over limit, " + << " was " << cmp_complexity.texturesMemoryTotal + << " is " << object_complexity.texturesMemoryTotal << LL_ENDL; + + return WARN_MEMORY; + } + else if ((cmp_complexity.objectsCost < object_complexity.objectsCost + || cmp_complexity.texturesCost < object_complexity.texturesCost) + && max_render_cost > 0 + && object_complexity.objectsCost + object_complexity.texturesCost > max_render_cost) + { + LL_DEBUGS("HUDdetail") << "HUD " << object_complexity.objectName << " complexity over limit," + << " HUD textures cost: " << object_complexity.texturesCost + << " HUD objects cost: " << object_complexity.objectsCost << LL_ENDL; - if (mLatestHUDComplexity.objectsCost != new_complexity.objectsCost - || mLatestHUDComplexity.objectsCount != new_complexity.objectsCount - || mLatestHUDComplexity.texturesCost != new_complexity.texturesCost - || mLatestHUDComplexity.texturesCount != new_complexity.texturesCount - || mLatestHUDComplexity.largeTexturesCount != new_complexity.largeTexturesCount - || mLatestHUDComplexity.texturesSizeTotal != new_complexity.texturesSizeTotal) + return WARN_COST; + } + else if (cmp_complexity.largeTexturesCount < object_complexity.largeTexturesCount + && object_complexity.largeTexturesCount > max_oversized_count) { - LL_INFOS("HUDdetail") << "HUD textures count: " << new_complexity.texturesCount - << " HUD textures cost: " << new_complexity.texturesCost - << " Large textures: " << new_complexity.largeTexturesCount - << " HUD objects cost: " << new_complexity.objectsCost - << " HUD objects count: " << new_complexity.objectsCount << LL_ENDL; + LL_DEBUGS("HUDdetail") << "HUD " << object_complexity.objectName << " contains to many large textures: " + << object_complexity.largeTexturesCount << LL_ENDL; - mLatestHUDComplexity = new_complexity; + return WARN_HEAVY; } - + else if (cmp_complexity.texturesCount < object_complexity.texturesCount + && object_complexity.texturesCount > max_textures_count) + { + LL_DEBUGS("HUDdetail") << "HUD " << object_complexity.objectName << " contains too many textures: " + << object_complexity.texturesCount << LL_ENDL; + + return WARN_CRAMPED; + } + else if (cmp_complexity.objectsCount < object_complexity.objectsCount + && object_complexity.objectsCount > max_objects_count) + { + LL_DEBUGS("HUDdetail") << "HUD " << object_complexity.objectName << " contains too many objects: " + << object_complexity.objectsCount << LL_ENDL; + + return WARN_TEXTURES; + } + return WARN_NONE; } -void LLHUDRenderNotifier::displayHUDNotification(const char* message) +void LLHUDRenderNotifier::displayHUDNotification(EWarnLevel warn_type, LLUUID obj_id, std::string obj_name, std::string joint_name) { static LLCachedControl pop_up_delay(gSavedSettings, "ComplexityChangesPopUpDelay", 300); static LLCachedControl expire_delay(gSavedSettings, "ShowMyComplexityChanges", 20); LLDate expire_date(LLDate::now().secondsSinceEpoch() + expire_delay); - LLSD args; - args["HUD_REASON"] = LLTrans::getString(message); + // Since we need working "ignoretext" there is no other way but to + // use single notification while constructing it from multiple pieces + LLSD reason_args; + if (obj_id.isNull()) + { + reason_args["HUD_DETAILS"] = LLTrans::getString("hud_description_total"); + } + else + { + if (obj_name.empty()) + { + LL_WARNS("HUDdetail") << "Object name not assigned" << LL_ENDL; + } + if (joint_name.empty()) + { + std::string verb = "select?name=" + LLURI::escape(obj_name); + reason_args["HUD_DETAILS"] = LLSLURL("inventory", obj_id, verb.c_str()).getSLURLString(); + } + else + { + LLSD object_args; + std::string verb = "select?name=" + LLURI::escape(obj_name); + object_args["OBJ_NAME"] = LLSLURL("inventory", obj_id, verb.c_str()).getSLURLString(); + object_args["JNT_NAME"] = LLTrans::getString(joint_name); + reason_args["HUD_DETAILS"] = LLTrans::getString("hud_name_with_joint", object_args); + } + } + + LLSD msg_args; + msg_args["HUD_REASON"] = LLTrans::getString(e_hud_messages[warn_type], reason_args); - LLNotifications::instance().add(LLNotification::Params() + mHUDNotificationPtr = LLNotifications::instance().add(LLNotification::Params() .name("HUDComplexityWarning") .expiry(expire_date) - .substitutions(args)); + .substitutions(msg_args)); mHUDPopUpDelayTimer.resetWithExpiry(pop_up_delay); } diff --git a/indra/newview/llavatarrendernotifier.h b/indra/newview/llavatarrendernotifier.h index 959bebef02..a169baef40 100644 --- a/indra/newview/llavatarrendernotifier.h +++ b/indra/newview/llavatarrendernotifier.h @@ -37,21 +37,32 @@ struct LLHUDComplexity { LLHUDComplexity() { + reset(); + } + void reset() + { + objectId = LLUUID::null; + objectName = ""; objectsCost = 0; objectsCount = 0; texturesCost = 0; texturesCount = 0; largeTexturesCount = 0; - texturesSizeTotal = 0; + texturesMemoryTotal = (F64Bytes)0; } + LLUUID objectId; + std::string objectName; + std::string jointName; U32 objectsCost; U32 objectsCount; U32 texturesCost; U32 texturesCount; U32 largeTexturesCount; - F64 texturesSizeTotal; + F64Bytes texturesMemoryTotal; }; +typedef std::list hud_complexity_list_t; + // Class to notify user about drastic changes in agent's render weights or if other agents // reported that user's agent is too 'heavy' for their settings class LLAvatarRenderNotifier : public LLSingleton @@ -107,12 +118,27 @@ public: LLHUDRenderNotifier(); ~LLHUDRenderNotifier(); - void updateNotificationHUD(LLHUDComplexity new_complexity); + void updateNotificationHUD(hud_complexity_list_t complexity); + bool isNotificationVisible(); private: - void displayHUDNotification(const char* message); + enum EWarnLevel + { + WARN_NONE = -1, + WARN_TEXTURES = 0, // least important + WARN_CRAMPED, + WARN_HEAVY, + WARN_COST, + WARN_MEMORY, //most important + }; + + LLNotificationPtr mHUDNotificationPtr; + + static EWarnLevel getWarningType(LLHUDComplexity object_complexity, LLHUDComplexity cmp_complexity); + void displayHUDNotification(EWarnLevel warn_type, LLUUID obj_id = LLUUID::null, std::string object_name = "", std::string joint_name = ""); LLHUDComplexity mReportedHUDComplexity; + EWarnLevel mReportedHUDWarning; LLHUDComplexity mLatestHUDComplexity; LLFrameTimer mHUDPopUpDelayTimer; }; diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 72a8595845..5f4eeaa37b 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -6307,7 +6307,7 @@ const LLUUID &LLViewerObject::extractAttachmentItemID() return getAttachmentItemID(); } -const std::string& LLViewerObject::getAttachmentItemName() +const std::string& LLViewerObject::getAttachmentItemName() const { static std::string empty; LLInventoryItem *item = gInventory.getItem(getAttachmentItemID()); diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index b95190c554..804b6c147b 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -172,7 +172,7 @@ public: void setOnActiveList(BOOL on_active) { mOnActiveList = on_active; } virtual BOOL isAttachment() const { return FALSE; } - const std::string& getAttachmentItemName(); + const std::string& getAttachmentItemName() const; virtual LLVOAvatar* getAvatar() const; //get the avatar this object is attached to, or NULL if object is not an attachment virtual BOOL isHUDAttachment() const { return FALSE; } diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index f79249d6fa..fe8f54b900 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -8354,7 +8354,7 @@ void LLVOAvatar::calculateUpdateRenderComplexity() { U32 cost = VISUAL_COMPLEXITY_UNKNOWN; LLVOVolume::texture_cost_t textures; - LLHUDComplexity hud_complexity; + hud_complexity_list_t hud_complexity_list; for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++) { @@ -8441,9 +8441,15 @@ void LLVOAvatar::calculateUpdateRenderComplexity() const LLVOVolume* volume = attached_object->mDrawable->getVOVolume(); if (volume) { + LLHUDComplexity hud_object_complexity; + hud_object_complexity.objectName = attached_object->getAttachmentItemName(); + hud_object_complexity.objectId = attached_object->getAttachmentItemID(); + std::string joint_name; + gAgentAvatarp->getAttachedPointName(attached_object->getAttachmentItemID(), joint_name); + hud_object_complexity.jointName = joint_name; // get cost and individual textures - hud_complexity.objectsCost += volume->getRenderCost(textures); - hud_complexity.objectsCount++; + hud_object_complexity.objectsCost += volume->getRenderCost(textures); + hud_object_complexity.objectsCount++; LLViewerObject::const_child_list_t& child_list = attached_object->getChildren(); for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); @@ -8454,30 +8460,31 @@ void LLVOAvatar::calculateUpdateRenderComplexity() if (chld_volume) { // get cost and individual textures - hud_complexity.objectsCost += chld_volume->getRenderCost(textures); - hud_complexity.objectsCount++; + hud_object_complexity.objectsCost += chld_volume->getRenderCost(textures); + hud_object_complexity.objectsCount++; } } - hud_complexity.texturesCount += textures.size(); + hud_object_complexity.texturesCount += textures.size(); for (LLVOVolume::texture_cost_t::iterator volume_texture = textures.begin(); volume_texture != textures.end(); ++volume_texture) { // add the cost of each individual texture (ignores duplicates) - hud_complexity.texturesCost += volume_texture->second; + hud_object_complexity.texturesCost += volume_texture->second; LLViewerFetchedTexture *tex = LLViewerTextureManager::getFetchedTexture(volume_texture->first); if (tex) { - F64 size = tex->getMaxVirtualSize(); // in pixels - hud_complexity.texturesSizeTotal += size; - if (size >= HUD_OVERSIZED_TEXTURE_DATA_SIZE) + // Note: Texture memory might be incorect since texture might be still loading. + hud_object_complexity.texturesMemoryTotal += tex->getTextureMemory(); + if (tex->getOriginalHeight() * tex->getOriginalWidth() >= HUD_OVERSIZED_TEXTURE_DATA_SIZE) { - hud_complexity.largeTexturesCount++; + hud_object_complexity.largeTexturesCount++; } } } + hud_complexity_list.push_back(hud_object_complexity); } } } @@ -8547,7 +8554,7 @@ void LLVOAvatar::calculateUpdateRenderComplexity() LLAvatarRenderNotifier::getInstance()->updateNotificationAgent(mVisualComplexity); // HUD complexity - LLHUDRenderNotifier::getInstance()->updateNotificationHUD(hud_complexity); + LLHUDRenderNotifier::getInstance()->updateNotificationHUD(hud_complexity_list); } } } diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 6bcf5c791f..8916725bbc 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -2501,11 +2501,13 @@ This feature is currently in Beta. Please add your name to this [http://goo.gl/f You may not be rendered by anyone around you. - Your HUD uses a lot of texture memory - Your HUD contains a lot of expensive objects and textures - Your HUD contains a lot of large textures - Your HUD contains too many objects - Your HUD contains too many textures + Your HUD + [OBJ_NAME] (worn on [JNT_NAME]) + [HUD_DETAILS] uses a lot of texture memory + [HUD_DETAILS] contains a lot of expensive objects and textures + [HUD_DETAILS] contains a lot of large textures + [HUD_DETAILS] contains too many objects + [HUD_DETAILS] contains too many textures