Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 6 additions & 11 deletions indra/llcommon/llsingleton.h
Original file line number Diff line number Diff line change
Expand Up @@ -524,16 +524,13 @@ class LLSingleton : public LLSingletonBase
case INITIALIZING:
// here if DERIVED_TYPE::initSingleton() (directly or indirectly)
// calls DERIVED_TYPE::getInstance(): go ahead and allow it
// record the dependency: check if we got here from another
case INITIALIZED:
// normal subsequent calls
// record the dependency, if any: check if we got here from another
// LLSingleton's constructor or initSingleton() method
capture_dependency(lk->mInstance);
return lk->mInstance;

case INITIALIZED:
// normal subsequent calls - skip capture_dependency() for performance
// dependencies are only tracked during initialization
return lk->mInstance;

case DELETED:
// called after deleteSingleton()
logwarns({"Trying to access deleted singleton ",
Expand Down Expand Up @@ -733,12 +730,10 @@ class LLParamSingleton : public LLSingleton<DERIVED_TYPE>

case super::INITIALIZING:
// As with LLSingleton, explicitly permit circular calls from
// within initSingleton() and capture dependencies
super::capture_dependency(lk->mInstance);
return lk->mInstance;

// within initSingleton()
case super::INITIALIZED:
// normal subsequent calls - skip capture_dependency() for performance
// for any valid call, capture dependencies
super::capture_dependency(lk->mInstance);
return lk->mInstance;

case super::DELETED:
Expand Down
14 changes: 11 additions & 3 deletions indra/llui/llview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,11 @@ void LLView::setName(const std::string& name)

if (parent && !mName.empty())
{
parent->mChildNameCache.erase(mName);
auto it = parent->mChildNameCache.find(mName);
if (it != parent->mChildNameCache.end() && it->second == this)
{
parent->mChildNameCache.erase(it);
}
}

mName = name;
Expand Down Expand Up @@ -373,10 +377,14 @@ void LLView::removeChild(LLView* child)
llassert(!child->mInDraw);
mChildList.remove( child );

// Remove from name cache
// Remove from name cache - verify pointer to handle duplicate names
if (child->hasName())
{
mChildNameCache.erase(child->getName());
auto it = mChildNameCache.find(child->getName());
if (it != mChildNameCache.end() && it->second == child)
{
mChildNameCache.erase(it);
}
}

child->mParentView = NULL;
Expand Down
6 changes: 6 additions & 0 deletions indra/newview/llasyncinventoryskeletonloader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ bool gAsyncAgentCacheHydrated = false;
bool gAsyncLibraryCacheHydrated = false;
bool gAsyncParentChildMapPrimed = false;

LLAsyncInventorySkeletonLoader::~LLAsyncInventorySkeletonLoader()
{
disconnectCapsCallback();
removeIdleCallback();
}

void LLAsyncInventorySkeletonLoader::reset()
{
disconnectCapsCallback();
Expand Down
2 changes: 2 additions & 0 deletions indra/newview/llasyncinventoryskeletonloader.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ class LLViewerRegion;
class LLAsyncInventorySkeletonLoader
{
public:
~LLAsyncInventorySkeletonLoader();

void start(bool force_async);
void update();
bool isRunning() const;
Expand Down
23 changes: 14 additions & 9 deletions indra/newview/llinventorymodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2459,7 +2459,7 @@ void LLInventoryModel::cache(
LL_WARNS(LOG_INV) << "Nothing to cache for " << parent_folder_id << LL_ENDL;
return;
}

// Fallback pass: catch any categories/items that collectDescendentsIf missed.
// This can happen when:
// 1. Categories have VERSION_UNKNOWN (e.g., during async loading)
Expand Down Expand Up @@ -5031,17 +5031,22 @@ LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const
}
else if (cats->size() + items->size() != cat->getDescendentCount())
{
// In the case of library this is not unexpected, since
// different user accounts may be getting the library
// contents from different inventory hosts.
if (topmost_ancestor_id.isNull() || topmost_ancestor_id != getLibraryRootFolderID())
// During async loading, descendent counts are expected to mismatch
// since only a subset of inventory is locally present.
if (!mAllowAsyncInventoryUpdates)
{
LL_WARNS(LOG_INV) << "invalid desc count for " << cat_id << " [" << getFullPath(cat) << "]"
// In the case of library this is not unexpected, since
// different user accounts may be getting the library
// contents from different inventory hosts.
if (topmost_ancestor_id.isNull() || topmost_ancestor_id != getLibraryRootFolderID())
{
LL_WARNS(LOG_INV) << "invalid desc count for " << cat_id << " [" << getFullPath(cat) << "]"
<< " cached " << cat->getDescendentCount()
<< " expected " << cats->size() << "+" << items->size()
<< "=" << cats->size() +items->size() << LL_ENDL;
validation_info->mWarnings["invalid_descendent_count"]++;
warning_count++;
<< "=" << cats->size() + items->size() << LL_ENDL;
validation_info->mWarnings["invalid_descendent_count"]++;
warning_count++;
}
}
}
if (cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN)
Expand Down
54 changes: 46 additions & 8 deletions indra/newview/llinventorypanel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1044,25 +1044,63 @@ void LLInventoryPanel::initializeViews(F64 max_time)

void LLInventoryPanel::initRootContent()
{
// Optimization: Only build root folder widget initially, no children.
// Children will be built lazily when folders are expanded/opened.
// This dramatically reduces startup time with large inventories (100k+ items).
// Instead of creating 430k widgets upfront (12 seconds), we create them on-demand.
// Optimization: Build root folder and its immediate children (system folders)
// but not grandchildren. Essential system folders (Calling Cards, My Outfits,
// Marketplace, etc.) also get their immediate children built so that nested
// system content (e.g. Friends subfolder, outfit folders) is available at init.
// Everything deeper is built lazily when folders are expanded.
LLUUID root_id = getRootFolderID();
if (root_id.notNull())
{
LLInventoryObject const* objectp = mInventory->getObject(root_id);
buildNewViews(root_id, objectp, nullptr, BUILD_NO_CHILDREN);
buildNewViews(root_id, objectp, nullptr, BUILD_ONE_FOLDER);
buildEssentialChildViews(root_id);
}
else
{
// Default case: always add "My Inventory" root first, "Library" root second
// Build only root widgets - children will load on-demand when expanded
LLInventoryObject const* my_inv = mInventory->getObject(gInventory.getRootFolderID());
buildNewViews(gInventory.getRootFolderID(), my_inv, nullptr, BUILD_NO_CHILDREN);
buildNewViews(gInventory.getRootFolderID(), my_inv, nullptr, BUILD_ONE_FOLDER);
Comment thread
marchcat marked this conversation as resolved.
buildEssentialChildViews(gInventory.getRootFolderID());

LLInventoryObject const* library = mInventory->getObject(gInventory.getLibraryRootFolderID());
buildNewViews(gInventory.getLibraryRootFolderID(), library, nullptr, BUILD_NO_CHILDREN);
buildNewViews(gInventory.getLibraryRootFolderID(), library, nullptr, BUILD_ONE_FOLDER);
}
}

void LLInventoryPanel::buildEssentialChildViews(const LLUUID& root_id)
{
// After building root + immediate children, also build one level deeper
// for essential system folders so their content is available at startup.
LLInventoryModel::cat_array_t* categories = nullptr;
LLInventoryModel::item_array_t* items = nullptr;
mInventory->getDirectDescendentsOf(root_id, categories, items);
if (!categories)
{
return;
}

for (const auto& cat : *categories)
{
if (!cat)
{
continue;
}
const LLFolderType::EType pref_type = cat->getPreferredType();
if (pref_type == LLFolderType::FT_NONE)
{
continue;
}
// Build immediate children for essential system folders
if (LLFolderType::lookupIsEssentialType(pref_type))
{
const LLUUID& cat_id = cat->getUUID();
LLInventoryObject const* objectp = mInventory->getObject(cat_id);
if (objectp)
{
buildNewViews(cat_id, objectp, getItemByID(cat_id), BUILD_ONE_FOLDER);
}
}
}
}

Expand Down
1 change: 1 addition & 0 deletions indra/newview/llinventorypanel.h
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,7 @@ class LLInventoryPanel : public LLPanel
// Builds the UI. Call this once the inventory is usable.
void initializeViews(F64 max_time);
virtual void initRootContent();
void buildEssentialChildViews(const LLUUID& root_id);
virtual void findAndInitRootContent(const LLUUID& root_id) {};

// Specific inventory colors
Expand Down
Loading