From e0b3b7fc3f07e0823726deba920db2ee5c382746 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> Date: Tue, 26 May 2026 00:53:11 +0300 Subject: #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. --- indra/newview/llinventorypanel.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'indra/newview/llinventorypanel.cpp') 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& 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& 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& 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(); } -- cgit v1.3 From ec82c45f0ebae8c09691d09baacf5662c89d969d Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> Date: Tue, 26 May 2026 20:39:07 +0300 Subject: #3729 Don't store tooltips for inventory Tooltips are just names, there is no point buffering them. --- indra/llui/llfolderviewitem.cpp | 17 ++++++++++++++--- indra/llui/llfolderviewitem.h | 7 ++++++- indra/newview/llinventorypanel.cpp | 3 --- indra/newview/llpanelmarketplaceinboxinventory.cpp | 4 +--- indra/newview/llpanelobjectinventory.cpp | 4 +--- 5 files changed, 22 insertions(+), 13 deletions(-) (limited to 'indra/newview/llinventorypanel.cpp') diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp index fcc1964bd6..ac759393d0 100644 --- a/indra/llui/llfolderviewitem.cpp +++ b/indra/llui/llfolderviewitem.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 @@ -248,7 +248,6 @@ bool LLFolderViewItem::postBuild() // it also sets search strings so it requires a filter reset mLabel = utf8str_to_wstring(vmi->getDisplayName()); mIsFavorite = vmi->isFavorite() && !vmi->isItemInTrash(); - setToolTip(vmi->getName()); // Dirty the filter flag of the model from the view (CHUI-849) vmi->dirtyFilter(); @@ -363,7 +362,6 @@ void LLFolderViewItem::refresh() mLabel = utf8str_to_wstring(vmi.getDisplayName()); mLabelFontBuffer.reset(); mIsFavorite = vmi.isFavorite() && !vmi.isItemInTrash(); - setToolTip(vmi.getName()); // icons are slightly expensive to get, can be optimized // see LLInventoryIcon::getIcon() mIcon = vmi.getIcon(); @@ -623,6 +621,19 @@ const std::string& LLFolderViewItem::getName( void ) const return getViewModelItem() ? getViewModelItem()->getName() : noName; } +const std::string LLFolderViewItem::getToolTip() const +{ + // Return the item name as tooltip without storing it + if (!LLView::sDebugUnicode) + { + if (const LLFolderViewModelItem* vmi = getViewModelItem()) + { + return vmi->getName(); + } + } + return LLView::getToolTip(); +} + // LLView functionality bool LLFolderViewItem::handleRightMouseDown( S32 x, S32 y, MASK mask ) { diff --git a/indra/llui/llfolderviewitem.h b/indra/llui/llfolderviewitem.h index 258a806b91..8d6de2fee3 100644 --- a/indra/llui/llfolderviewitem.h +++ b/indra/llui/llfolderviewitem.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 @@ -253,6 +253,11 @@ public: // viewed. This method will ask the viewed object itself. const std::string& getName( void ) const; + // Override to provide lazy tooltip generation without memory overhead + // Inventory can consist of millions of items, yet most stay invisible, + // much less need to show a tooltip, so avoid storing tooltips. + virtual const std::string getToolTip() const; + // This method returns the label displayed on the view. This // method was primarily added to allow sorting on the folder // contents possible before the entire view has been constructed. diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index e87ef025c6..0a6c95f309 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -198,7 +198,6 @@ LLFolderView * LLInventoryPanel::createFolderRoot(LLUUID root_id ) p.title = getLabel(); p.rect = LLRect(0, 0, getRect().getWidth(), 0); p.parent_panel = this; - p.tool_tip = p.name; p.listener = mInvFVBridgeBuilder->createBridge( LLAssetType::AT_CATEGORY, LLAssetType::AT_CATEGORY, LLInventoryType::IT_CATEGORY, @@ -1067,7 +1066,6 @@ LLFolderViewFolder * LLInventoryPanel::createFolderViewFolder(LLInvFVBridge * br params.name = bridge->getDisplayName(); params.root = mFolderRoot.get(); params.listener = bridge; - params.tool_tip = params.name; params.allow_drop = allow_drop; params.font_color = (bridge->isLibraryItem() ? sLibraryColor : sDefaultColor); @@ -1085,7 +1083,6 @@ LLFolderViewItem * LLInventoryPanel::createFolderViewItem(LLInvFVBridge * bridge params.root = mFolderRoot.get(); params.listener = bridge; params.rect = LLRect (0, 0, 0, 0); - params.tool_tip = params.name; params.font_color = (bridge->isLibraryItem() ? sLibraryColor : sDefaultColor); params.font_highlight_color = (bridge->isLibraryItem() ? sLibraryColor : sDefaultHighlightColor); diff --git a/indra/newview/llpanelmarketplaceinboxinventory.cpp b/indra/newview/llpanelmarketplaceinboxinventory.cpp index 557c7bbd7b..cb2906d633 100644 --- a/indra/newview/llpanelmarketplaceinboxinventory.cpp +++ b/indra/newview/llpanelmarketplaceinboxinventory.cpp @@ -4,7 +4,7 @@ * * $LicenseInfo:firstyear=2009&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 @@ -85,7 +85,6 @@ LLFolderViewFolder * LLInboxInventoryPanel::createFolderViewFolder(LLInvFVBridge params.name = bridge->getDisplayName(); params.root = mFolderRoot.get(); params.listener = bridge; - params.tool_tip = params.name; params.font_color = item_color; params.font_highlight_color = item_color; params.allow_drop = allow_drop; @@ -104,7 +103,6 @@ LLFolderViewItem * LLInboxInventoryPanel::createFolderViewItem(LLInvFVBridge * b params.root = mFolderRoot.get(); params.listener = bridge; params.rect = LLRect (0, 0, 0, 0); - params.tool_tip = params.name; params.font_color = item_color; params.font_highlight_color = item_color; diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp index d27ce81e4f..126f6d3776 100644 --- a/indra/newview/llpanelobjectinventory.cpp +++ b/indra/newview/llpanelobjectinventory.cpp @@ -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 @@ -1611,7 +1611,6 @@ void LLPanelObjectInventory::createViewsForCategory(LLInventoryObject::object_li params.name = obj->getName(); params.root = mFolders; params.listener = bridge; - params.tool_tip = params.name; params.font_color = item_color; params.font_highlight_color = item_color; view = LLUICtrlFactory::create(params); @@ -1625,7 +1624,6 @@ void LLPanelObjectInventory::createViewsForCategory(LLInventoryObject::object_li params.listener = bridge; params.creation_date = bridge->getCreationDate(); params.rect = LLRect(); - params.tool_tip = params.name; params.font_color = item_color; params.font_highlight_color = item_color; view = LLUICtrlFactory::create(params); -- cgit v1.3 From 0a7b6a8e506bddc514deaf814abe611fc5600849 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> Date: Tue, 26 May 2026 21:51:59 +0300 Subject: #3729 Avoid storing inventory item names in UI outside of debug --- indra/llui/llfolderview.cpp | 3 ++- indra/llui/llfolderviewitem.cpp | 13 +++++------ indra/newview/llinventorypanel.cpp | 27 ++++++++++++++++++++-- indra/newview/llpanelmarketplaceinboxinventory.cpp | 26 +++++++++++++++++++-- 4 files changed, 57 insertions(+), 12 deletions(-) (limited to 'indra/newview/llinventorypanel.cpp') diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index db4ab8487e..758b4bb176 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.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 @@ -1423,6 +1423,7 @@ bool LLFolderView::search(LLFolderViewItem* first_item, const std::string &searc } } + // Note: for inventory getSearchableName should already be 'upper' case. std::string current_item_label(search_item->getViewModelItem()->getSearchableName()); LLStringUtil::toUpper(current_item_label); auto search_string_length = llmin(upper_case_string.size(), current_item_label.size()); diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp index ac759393d0..c8ef421677 100644 --- a/indra/llui/llfolderviewitem.cpp +++ b/indra/llui/llfolderviewitem.cpp @@ -190,7 +190,7 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p) mItemHeight(p.item_height), mControlLabelRotation(0.f), mDragAndDropTarget(false), - mLabel(utf8str_to_wstring(p.name)), + mLabel(utf8str_to_wstring(p.name)), // will be immediately reset in postBuild() mRoot(p.root), mViewModelItem(p.listener), mIsMouseOverTitle(false), @@ -244,8 +244,10 @@ bool LLFolderViewItem::postBuild() llassert(vmi); // not supposed to happen, if happens, find out why and fix if (vmi) { - // getDisplayName() is expensive (due to internal getLabelSuffix() and name building) - // it also sets search strings so it requires a filter reset + // First getDisplayName() is expensive due to internal + // lazy getLabelSuffix(), it is however needed as it sets + // search string, which can later determine visibility. + // Refreshing a search string also requires a filter reset. mLabel = utf8str_to_wstring(vmi->getDisplayName()); mIsFavorite = vmi->isFavorite() && !vmi->isItemInTrash(); @@ -253,11 +255,8 @@ bool LLFolderViewItem::postBuild() vmi->dirtyFilter(); } - // Don't do full refresh on constructor if it is possible to avoid + // Don't do full refresh on constructor if it is possible to avoid, // it significantly slows down bulk view creation. - // Todo: Ideally we need to move getDisplayName() out of constructor as well. - // Like: make a logic that will let filter update search string, - // while LLFolderViewItem::arrange() updates visual part mSuffixNeedsRefresh = true; mLabelWidthDirty = true; return true; diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 0a6c95f309..301a0a0cc9 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -1063,7 +1063,18 @@ LLFolderViewFolder * LLInventoryPanel::createFolderViewFolder(LLInvFVBridge * br { LLFolderViewFolder::Params params(mParams.folder); - params.name = bridge->getDisplayName(); +#ifndef LL_RELEASE_FOR_DOWNLOAD + // Only usable for debug and first call has a large + // overhead from search string construction. + // As inventory names aren't unique and can change, + // there is little we can use them for in release builds. + params.name = bridge->getName(); +#else + // We don't have a source of unique names and inventory + // items can reach millions in quantity, just use + // a short descriptor + params.name = "fld"; +#endif params.root = mFolderRoot.get(); params.listener = bridge; params.allow_drop = allow_drop; @@ -1078,7 +1089,19 @@ LLFolderViewItem * LLInventoryPanel::createFolderViewItem(LLInvFVBridge * bridge { LLFolderViewItem::Params params(mParams.item); - params.name = bridge->getDisplayName(); +#ifndef LL_RELEASE_FOR_DOWNLOAD + // Only usable for debug and first call has a large + // overhead from search string construction. + // As inventory names aren't unique, are large and can change, + // there is little we can use them for in release builds. + // Prefer shorter + params.name = bridge->getName(); +#else + // We don't have a source of unique names and inventory + // items can reach millions in quantity, just use + // a short descriptor + params.name = "itm"; +#endif params.creation_date = bridge->getCreationDate(); params.root = mFolderRoot.get(); params.listener = bridge; diff --git a/indra/newview/llpanelmarketplaceinboxinventory.cpp b/indra/newview/llpanelmarketplaceinboxinventory.cpp index cb2906d633..e0dbd9acd2 100644 --- a/indra/newview/llpanelmarketplaceinboxinventory.cpp +++ b/indra/newview/llpanelmarketplaceinboxinventory.cpp @@ -82,7 +82,18 @@ LLFolderViewFolder * LLInboxInventoryPanel::createFolderViewFolder(LLInvFVBridge LLInboxFolderViewFolder::Params params; - params.name = bridge->getDisplayName(); +#ifndef LL_RELEASE_FOR_DOWNLOAD + // Only usable for debug and first call has a large + // overhead from search string construction. + // As inventory names aren't unique and can change, + // there is little we can use them for in release builds. + params.name = bridge->getName(); +#else + // We don't have a source of unique names and inventory + // items can reach millions in quantity, just use + // a short descriptor + params.name = "fld"; +#endif params.root = mFolderRoot.get(); params.listener = bridge; params.font_color = item_color; @@ -98,7 +109,18 @@ LLFolderViewItem * LLInboxInventoryPanel::createFolderViewItem(LLInvFVBridge * b LLInboxFolderViewItem::Params params; - params.name = bridge->getDisplayName(); +#ifndef LL_RELEASE_FOR_DOWNLOAD + // Only usable for debug and first call has a large + // overhead from search string construction. + // As inventory names aren't unique and can change, + // there is little we can use them for in release builds. + params.name = bridge->getName(); +#else + // We don't have a source of unique names and inventory + // items can reach millions in quantity, just use + // a short descriptor + params.name = "itm"; +#endif params.creation_date = bridge->getCreationDate(); params.root = mFolderRoot.get(); params.listener = bridge; -- cgit v1.3