summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
authorAndrey Kleshchev <117672381+akleshchev@users.noreply.github.com>2026-05-26 00:53:11 +0300
committerAndrey Kleshchev <117672381+akleshchev@users.noreply.github.com>2026-05-29 01:52:15 +0300
commite0b3b7fc3f07e0823726deba920db2ee5c382746 (patch)
tree5cc9ac178ec953691044899f6f99de9804533bd9 /indra
parent0be27809566c1378fa613aa7c42bfd2406a9f764 (diff)
#3729 Reduce inventory memory overhead
UI elements already cache display name, getDisplayName() calls are rare and only come with other calls. For items, any UI calls already engage internal getItem optimizations, so doing getItem in getDisplayName() has negligible performance overhead while avoiding storing a dupplicate of item's name. This also cuts performance overhead from allocations, so it's a net benefit performance wise on first load. System folders do utilize display names that are different from default names, but they are not panel specific, they are global localizations. Store those in the model, not in the bridge. Usage example: LLFolderViewItem::postBuild() already calls getName after getDisplayName(), so getItem will utilize mLastItem either way and the only refresh needed happens if user renames the item. Without the user the update happens only once.
Diffstat (limited to 'indra')
-rw-r--r--indra/newview/llinventorybridge.cpp97
-rw-r--r--indra/newview/llinventorybridge.h11
-rw-r--r--indra/newview/llinventorypanel.cpp15
-rw-r--r--indra/newview/llviewerinventory.cpp49
-rw-r--r--indra/newview/llviewerinventory.h22
5 files changed, 134 insertions, 60 deletions
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index c8ea14a11e..8e4e70474f 100644
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -4,7 +4,7 @@
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
+ * Copyright (C) 2026, 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
@@ -249,11 +249,27 @@ const std::string& LLInvFVBridge::getName() const
const std::string& LLInvFVBridge::getDisplayName() const
{
- if(mDisplayName.empty())
+ if(mSearchableName.empty())
{
- buildDisplayName();
+ // first request of display name, build search string and cache it for later use
+ buildSearchableName();
}
- return mDisplayName;
+
+ LLInventoryModel* model = getInventoryModel();
+ if (model)
+ {
+ LLViewerInventoryCategory* cat = model->getCategory(mUUID);
+ if (cat)
+ {
+ return cat->getDisplayName();
+ }
+ LLViewerInventoryItem* item = model->getItem(mUUID);
+ if (item)
+ {
+ return item->getName();
+ }
+ }
+ return LLStringUtil::null;
}
std::string LLInvFVBridge::getSearchableDescription() const
@@ -2035,22 +2051,22 @@ PermissionMask LLItemBridge::getPermissionMask() const
}
// virtual
-void LLItemBridge::buildDisplayName() const
+void LLItemBridge::buildSearchableName() const
{
- if (getItem())
+ LLViewerInventoryItem* item = getItem();
+ if (item)
{
- mDisplayName.assign(getItem()->getName());
+ // for items, display name matches item name
+ mSearchableName.assign(item->getName());
}
else
{
- mDisplayName.assign(LLStringUtil::null);
+ mSearchableName.assign(LLStringUtil::null);
}
-
- mSearchableName.assign(mDisplayName);
mSearchableName.append(getLabelSuffix());
LLStringUtil::toUpper(mSearchableName);
- // Name set, so trigger a sort
+ // Searchable and name set, so trigger a sort
LLInventorySort sorter = static_cast<LLFolderViewModelInventory&>(mRootViewModel).getSorter();
if (mParent && !sorter.isByDate())
{
@@ -2371,39 +2387,17 @@ void LLFolderBridge::selectItem()
}
}
-void LLFolderBridge::buildDisplayName() const
+void LLFolderBridge::buildSearchableName() const
{
- LLFolderType::EType preferred_type = getPreferredType();
-
- // *TODO: to be removed when database supports multi language. This is a
- // temporary attempt to display the inventory folder in the user locale.
- // mantipov: *NOTE: be sure this code is synchronized with LLFriendCardsManager::findChildFolderUUID
- // it uses the same way to find localized string
-
- // HACK: EXT - 6028 ([HARD CODED]? Inventory > Library > "Accessories" folder)
- // Translation of Accessories folder in Library inventory folder
- bool accessories = false;
- if(getName() == "Accessories")
+ LLViewerInventoryCategory* cat = gInventory.getCategory(getUUID());
+ if (cat)
{
- //To ensure that Accessories folder is in Library we have to check its parent folder.
- //Due to parent LLFolderViewFloder is not set to this item yet we have to check its parent via Inventory Model
- LLInventoryCategory* cat = gInventory.getCategory(getUUID());
- if(cat)
- {
- const LLUUID& parent_folder_id = cat->getParentUUID();
- accessories = (parent_folder_id == gInventory.getLibraryRootFolderID());
- }
+ mSearchableName.assign(cat->getDisplayName());
}
-
- //"Accessories" inventory category has folder type FT_NONE. So, this folder
- //can not be detected as protected with LLFolderType::lookupIsProtectedType
- mDisplayName.assign(getName());
- if (accessories || LLFolderType::lookupIsProtectedType(preferred_type))
+ else
{
- LLTrans::findString(mDisplayName, std::string("InvFolder ") + getName(), LLSD());
+ mSearchableName.assign(LLStringUtil::null);
}
-
- mSearchableName.assign(mDisplayName);
mSearchableName.append(getLabelSuffix());
LLStringUtil::toUpper(mSearchableName);
@@ -2417,6 +2411,8 @@ void LLFolderBridge::buildDisplayName() const
std::string LLFolderBridge::getLabelSuffix() const
{
+ // Folders, unlike items, have context dependent suffixes
+ // that may change as the folder is loaded
static LLCachedControl<bool> xui_debug(gSavedSettings, "DebugShowXUINames", 0);
if (mIsLoading && mTimeSinceRequestStart.getElapsedTimeF32() >= FOLDER_LOADING_MESSAGE_DELAY)
@@ -6576,18 +6572,29 @@ void LLCallingCardBridge::refreshFolderViewItem()
void LLCallingCardBridge::checkSearchBySuffixChanges()
{
- if (!mDisplayName.empty())
+ if (!mSearchableName.empty())
{
- // changes in mDisplayName are processed by rename function and here it will be always same
+ LLViewerInventoryItem* item = getItem();
+ if (!item)
+ {
+ // checkSearchBySuffixChanges is only used by friend list
+ // so if item is not found, we removed the calling card or
+ // are no longer friends.
+ mSearchableName.clear();
+ return;
+ }
+
+ // changes in display name are processed by rename function and here it will be always same
// suffixes are also of fixed length, and we are processing change of one at a time,
// so it should be safe to use length (note: mSearchableName is capitalized)
- auto old_length = mSearchableName.length();
- auto new_length = mDisplayName.length() + getLabelSuffix().length();
+ size_t old_length = mSearchableName.length();
+ const std::string& display_name = item->getName();
+ size_t new_length = display_name.length() + getLabelSuffix().length();
if (old_length == new_length)
{
return;
}
- mSearchableName.assign(mDisplayName);
+ mSearchableName.assign(display_name);
mSearchableName.append(getLabelSuffix());
LLStringUtil::toUpper(mSearchableName);
if (new_length<old_length)
@@ -7465,7 +7472,7 @@ bool LLObjectBridge::renameItem(const std::string& new_name)
new_item->updateServer(false);
model->updateItem(new_item);
model->notifyObservers();
- buildDisplayName();
+ buildSearchableName();
if (isAgentAvatarValid())
{
diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h
index decb2c0528..68e7a7f80e 100644
--- a/indra/newview/llinventorybridge.h
+++ b/indra/newview/llinventorybridge.h
@@ -4,7 +4,7 @@
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
+ * Copyright (C) 2026, 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
@@ -87,7 +87,7 @@ public:
virtual const LLUUID& getUUID() const { return mUUID; }
virtual const LLUUID& getThumbnailUUID() const { return LLUUID::null; }
virtual bool isFavorite() const { return false; }
- virtual void clearDisplayName() { mDisplayName.clear(); }
+ virtual void clearSearchableName() { mSearchableName.clear(); }
virtual void restoreItem() {}
virtual void restoreToWorld() {}
@@ -202,12 +202,11 @@ protected:
LLInventoryType::EType mInvType;
bool mIsLink;
LLTimer mTimeSinceRequestStart;
- mutable std::string mDisplayName;
mutable std::string mSearchableName;
void purgeItem(LLInventoryModel *model, const LLUUID &uuid);
void removeObject(LLInventoryModel *model, const LLUUID &uuid);
- virtual void buildDisplayName() const {}
+ virtual void buildSearchableName() const {}
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -266,7 +265,7 @@ public:
protected:
bool confirmRemoveItem(const LLSD& notification, const LLSD& response);
virtual bool isItemPermissive() const;
- virtual void buildDisplayName() const;
+ virtual void buildSearchableName() const;
void doActionOnCurSelectedLandmark(LLLandmarkList::loaded_callback_t cb);
private:
@@ -287,7 +286,7 @@ public:
void callback_dropItemIntoFolder(const LLSD& notification, const LLSD& response, LLInventoryItem* inv_item);
void callback_dropCategoryIntoFolder(const LLSD& notification, const LLSD& response, LLInventoryCategory* inv_category);
- virtual void buildDisplayName() const;
+ virtual void buildSearchableName() const;
virtual void performAction(LLInventoryModel* model, std::string action);
virtual void openItem();
diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp
index 06dd830416..e87ef025c6 100644
--- a/indra/newview/llinventorypanel.cpp
+++ b/indra/newview/llinventorypanel.cpp
@@ -4,7 +4,7 @@
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
+ * Copyright (C) 2026, 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
@@ -581,8 +581,9 @@ void LLInventoryPanel::itemChanged(const LLUUID& item_id, U32 mask, const LLInve
LLInvFVBridge* bridge = (LLInvFVBridge*)view_item->getViewModelItem();
if(bridge)
{
- // Clear the display name first, so it gets properly re-built during refresh()
- bridge->clearDisplayName();
+ // Clear the searchable name first, so it gets
+ // properly re-built during refresh()
+ bridge->clearSearchableName();
view_item->refresh();
}
@@ -1676,7 +1677,7 @@ void LLInventoryPanel::onSelectionChange(const std::deque<LLFolderViewItem*>& it
LLFolderBridge* prev_bridge = (LLFolderBridge*)prev_folder_item->getViewModelItem();
if(prev_bridge)
{
- prev_bridge->clearDisplayName();
+ prev_bridge->clearSearchableName();
prev_bridge->setShowDescendantsCount(false);
prev_folder_item->refresh();
}
@@ -1685,7 +1686,7 @@ void LLInventoryPanel::onSelectionChange(const std::deque<LLFolderViewItem*>& it
LLFolderBridge* bridge = (LLFolderBridge*)folder_item->getViewModelItem();
if(bridge)
{
- bridge->clearDisplayName();
+ bridge->clearSearchableName();
bridge->setShowDescendantsCount(true);
folder_item->refresh();
mPreviousSelectedFolder = bridge->getUUID();
@@ -1700,7 +1701,7 @@ void LLInventoryPanel::onSelectionChange(const std::deque<LLFolderViewItem*>& it
LLFolderBridge* prev_bridge = (LLFolderBridge*)prev_folder_item->getViewModelItem();
if(prev_bridge)
{
- prev_bridge->clearDisplayName();
+ prev_bridge->clearSearchableName();
prev_bridge->setShowDescendantsCount(false);
prev_folder_item->refresh();
}
@@ -1720,7 +1721,7 @@ void LLInventoryPanel::updateFolderLabel(const LLUUID& folder_id)
LLFolderBridge* bridge = (LLFolderBridge*)folder_item->getViewModelItem();
if(bridge)
{
- bridge->clearDisplayName();
+ bridge->clearSearchableName();
bridge->setShowDescendantsCount(true);
folder_item->refresh();
}
diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp
index efa3f5cd1e..707b2f1993 100644
--- a/indra/newview/llviewerinventory.cpp
+++ b/indra/newview/llviewerinventory.cpp
@@ -4,7 +4,7 @@
*
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
* Second Life Viewer Source Code
- * Copyright (C) 2014, Linden Research, Inc.
+ * Copyright (C) 2026, 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
@@ -673,6 +673,25 @@ void LLViewerInventoryCategory::setVersion(S32 version)
mVersion = version;
}
+const std::string& LLViewerInventoryCategory::getDisplayName() const
+{
+ if (mNeedsDisplayNameUpdate)
+ {
+ buildDisplayName();
+ }
+ if (!mDisplayName.empty())
+ {
+ return mDisplayName;
+ }
+ return getName();
+}
+
+void LLViewerInventoryCategory::invalidateDisplayName()
+{
+ mNeedsDisplayNameUpdate = true;
+ mDisplayName.clear();
+}
+
bool LLViewerInventoryCategory::fetch(S32 expiry_seconds)
{
if((VERSION_UNKNOWN == getVersion())
@@ -889,6 +908,34 @@ void LLViewerInventoryCategory::localizeName()
LLLocalizedInventoryItemsDictionary::getInstance()->localizeInventoryObjectName(mName);
}
+void LLViewerInventoryCategory::buildDisplayName() const
+{
+ // Secure and library folders can't be renamed,
+ // so we only need to do this once.
+ mNeedsDisplayNameUpdate = false;
+
+ //"Accessories" inventory category has folder type FT_NONE. So, this folder
+ //can not be detected as protected with LLFolderType::lookupIsProtectedType
+ //
+ // HACK: EXT - 6028 ([HARD CODED]? Inventory > Library > "Accessories" folder)
+ // Translation of Accessories folder in Library inventory folder
+ LLFolderType::EType preferred_type = getPreferredType();
+
+ bool is_accessories = false;
+ if (getName() == "Accessories")
+ {
+ // To ensure that Accessories folder is in Library we have to check its parent folder.
+ const LLUUID& parent_folder_id = getParentUUID();
+ is_accessories = (parent_folder_id == gInventory.getLibraryRootFolderID());
+ }
+
+ if (is_accessories || LLFolderType::lookupIsProtectedType(preferred_type))
+ {
+ // All predefined folders have translations in strings.xml.
+ LLTrans::findString(mDisplayName, std::string("InvFolder ") + getName(), LLSD());
+ }
+}
+
// virtual
bool LLViewerInventoryCategory::unpackMessage(const LLSD& category)
{
diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h
index a42bdaa2b0..f14850da5a 100644
--- a/indra/newview/llviewerinventory.h
+++ b/indra/newview/llviewerinventory.h
@@ -4,7 +4,7 @@
*
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
* Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
+ * Copyright (C) 2026, 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
@@ -209,6 +209,13 @@ public:
S32 getVersion() const;
void setVersion(S32 version);
+ const std::string& getDisplayName() const;
+ // The display name gets cached on demand, so needs a cleanup method.
+ // But in practice only secure folders' display name mismatches
+ // actual name, and those folders can't be renamed, so in practice
+ // this is useless unless we want to free memory.
+ void invalidateDisplayName();
+
// Returns true if a fetch was issued (not nessesary in progress).
// no requests will happen during expiry_seconds even if fetch completed
bool fetch(S32 expiry_seconds = 10);
@@ -253,6 +260,19 @@ protected:
S32 mDescendentCount;
EFetchType mFetching;
LLFrameTimer mDescendentsRequested;
+
+ // Display names are generated on demand and cached.
+ // buildDisplayName is essentially a way to localize
+ // system and library folders.
+ //
+ // TODO: This is on demand and mutable because that's how it
+ // worked in inventory bridge, before it was moved.
+ // But system folders always get loaded, it's likely better
+ // to just generate from the get go.
+ // Consider merging with localizeName.
+ void buildDisplayName() const;
+ mutable std::string mDisplayName;
+ mutable bool mNeedsDisplayNameUpdate = true;
};
class LLInventoryCallback : public LLRefCount