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: 11 additions & 6 deletions indra/llcommon/llsingleton.h
Original file line number Diff line number Diff line change
Expand Up @@ -522,13 +522,16 @@ class LLSingleton : public LLSingletonBase
case INITIALIZING:
// here if DERIVED_TYPE::initSingleton() (directly or indirectly)
// calls DERIVED_TYPE::getInstance(): go ahead and allow it
case INITIALIZED:
// normal subsequent calls
// record the dependency, if any: check if we got here from another
// record the dependency: 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 @@ -728,12 +731,14 @@ class LLParamSingleton : public LLSingleton<DERIVED_TYPE>

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

case super::INITIALIZED:
// normal subsequent calls - skip capture_dependency() for performance
return lk->mInstance;

case super::DELETED:
super::logerrs({"Trying to access deleted param singleton ",
super::template classname<DERIVED_TYPE>()});
Expand Down
18 changes: 18 additions & 0 deletions indra/llinventory/llfoldertype.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,24 @@ bool LLFolderType::lookupIsEnsembleType(EType folder_type)
folder_type <= FT_ENSEMBLE_END);
}

// static
bool LLFolderType::lookupIsEssentialType(EType folder_type)
{
if (folder_type == FT_NONE)
{
return false;
}

if (folder_type == FT_ROOT_INVENTORY)
{
return true;
}

// Essential folders are those needed for basic viewer operation:
// singleton system folders and ensemble (outfit) folders
return lookupIsSingletonType(folder_type) || lookupIsEnsembleType(folder_type);
}

// static
LLAssetType::EType LLFolderType::folderTypeToAssetType(LLFolderType::EType folder_type)
{
Expand Down
2 changes: 2 additions & 0 deletions indra/llinventory/llfoldertype.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ class LL_COMMON_API LLFolderType
static bool lookupIsAutomaticType(EType folder_type);
static bool lookupIsSingletonType(EType folder_type);
static bool lookupIsEnsembleType(EType folder_type);
// Returns true if this folder type should be fully loaded during async inventory startup
static bool lookupIsEssentialType(EType folder_type);

static LLAssetType::EType folderTypeToAssetType(LLFolderType::EType folder_type);
static LLFolderType::EType assetTypeToFolderType(LLAssetType::EType asset_type);
Expand Down
43 changes: 27 additions & 16 deletions indra/llui/llpanel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -489,58 +489,69 @@ bool LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr outpu
LL_RECORD_BLOCK_TIME(FTM_PANEL_SETUP);

LLXMLNodePtr referenced_xml;
std::string xml_filename = mXMLFilename;

// if the panel didn't provide a filename, check the node
if (xml_filename.empty())
if (mXMLFilename.empty())
{
node->getAttributeString("filename", xml_filename);
setXMLFilename(xml_filename);
std::string temp_filename;
node->getAttributeString("filename", temp_filename);
setXMLFilename(temp_filename);
}

// Cache singleton and filename to avoid repeated calls
LLUICtrlFactory* factory = LLUICtrlFactory::getInstance();

// Cache node name pointer to avoid repeated dereferencing
const LLStringTableEntry* node_name = node->getName();

// Cache registry to avoid repeated singleton access
const child_registry_t& registry = child_registry_t::instance();

LLXUIParser parser;

if (!xml_filename.empty())
if (!mXMLFilename.empty())
{
if (output_node)
{
//if we are exporting, we want to export the current xml
//not the referenced xml
parser.readXUI(node, params, LLUICtrlFactory::getInstance()->getCurFileName());
parser.readXUI(node, params, factory->getCurFileName());
Params output_params(params);
setupParamsForExport(output_params, parent);
output_node->setName(node->getName()->mString);
output_node->setName(node_name->mString);
parser.writeXUI(output_node, output_params, LLInitParam::default_parse_rules(), &default_params);
return true;
}

LLUICtrlFactory::instance().pushFileName(xml_filename);
factory->pushFileName(mXMLFilename);

LL_RECORD_BLOCK_TIME(FTM_EXTERNAL_PANEL_LOAD);
if (!LLUICtrlFactory::getLayeredXMLNode(xml_filename, referenced_xml))
if (!LLUICtrlFactory::getLayeredXMLNode(mXMLFilename, referenced_xml))
{
LL_WARNS() << "Couldn't parse panel from: " << xml_filename << LL_ENDL;
LL_WARNS() << "Couldn't parse panel from: " << mXMLFilename << LL_ENDL;

return false;
}

parser.readXUI(referenced_xml, params, LLUICtrlFactory::getInstance()->getCurFileName());
// Get filename after pushFileName
const std::string& updated_filename = factory->getCurFileName();
parser.readXUI(referenced_xml, params, updated_filename);

// add children using dimensions from referenced xml for consistent layout
setShape(params.rect);
LLUICtrlFactory::createChildren(this, referenced_xml, child_registry_t::instance());
LLUICtrlFactory::createChildren(this, referenced_xml, registry);

LLUICtrlFactory::instance().popFileName();
factory->popFileName();
}

// ask LLUICtrlFactory for filename, since xml_filename might be empty
parser.readXUI(node, params, LLUICtrlFactory::getInstance()->getCurFileName());
parser.readXUI(node, params, factory->getCurFileName());

if (output_node)
{
Params output_params(params);
setupParamsForExport(output_params, parent);
output_node->setName(node->getName()->mString);
output_node->setName(node_name->mString);
parser.writeXUI(output_node, output_params, LLInitParam::default_parse_rules(), &default_params);
}

Expand All @@ -552,7 +563,7 @@ bool LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr outpu
}

// add children
LLUICtrlFactory::createChildren(this, node, child_registry_t::instance(), output_node);
LLUICtrlFactory::createChildren(this, node, registry, output_node);

// Connect to parent after children are built, because tab containers
// do a reshape() on their child panels, which requires that the children
Expand Down
62 changes: 61 additions & 1 deletion indra/llui/llview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,28 @@ const std::string& LLView::getName() const
return mName.empty() ? no_name : mName;
}

void LLView::setName(const std::string& name)
{
if (name == mName)
{
return;
}

LLView* parent = mParentView;

if (parent && !mName.empty())
{
parent->mChildNameCache.erase(mName);
}

mName = name;

if (parent && !mName.empty())
{
parent->mChildNameCache[mName] = this;
}
}

void LLView::sendChildToFront(LLView* child)
{
// llassert_always(sDepth == 0); // Avoid re-ordering while drawing; it can cause subtle iterator bugs
Expand Down Expand Up @@ -305,6 +327,12 @@ bool LLView::addChild(LLView* child, S32 tab_group)
// add to front of child list, as normal
mChildList.push_front(child);

// Add to name cache for fast lookup
if (child->hasName())
{
mChildNameCache[child->getName()] = child;
}

// add to tab order list
if (tab_group != 0)
{
Expand Down Expand Up @@ -344,6 +372,13 @@ void LLView::removeChild(LLView* child)
// if we are removing an item we are currently iterating over, that would be bad
llassert(!child->mInDraw);
mChildList.remove( child );

// Remove from name cache
if (child->hasName())
{
mChildNameCache.erase(child->getName());
}

child->mParentView = NULL;
child_tab_order_t::iterator found = mTabOrder.find(child);
if (found != mTabOrder.end())
Expand Down Expand Up @@ -1649,15 +1684,40 @@ LLView* LLView::findChildView(std::string_view name, bool recurse) const
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;

// Check cache first for direct children - O(1) lookup instead of O(n)
if (!mChildNameCache.empty())
{
std::string lookup_key(name);
auto cache_it = mChildNameCache.find(lookup_key);
if (cache_it != mChildNameCache.end())
{
return cache_it->second;
}
}

// Look for direct children *first*
for (LLView* childp : mChildList)
{
llassert(childp);
if (childp->getName() == name)
const std::string& child_name = childp->getName();

if (child_name.empty())
{
if (name.empty())
{
return childp;
}
continue;
}

if (child_name == name)
{
// Cache the result for next lookup
mChildNameCache[child_name] = childp;
return childp;
}
}

if (recurse)
{
// Look inside each child as well.
Expand Down
7 changes: 6 additions & 1 deletion indra/llui/llview.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
#include "llfocusmgr.h"

#include <list>
#include <unordered_map>
#include <boost/function.hpp>
#include <boost/noncopyable.hpp>

Expand Down Expand Up @@ -237,7 +238,8 @@ class LLView
void setFollowsAll() { mReshapeFlags |= FOLLOWS_ALL; }

void setSoundFlags(U8 flags) { mSoundFlags = flags; }
void setName(std::string name) { mName = name; }
void setName(const std::string& name);
bool hasName() const { return !mName.empty(); }
void setUseBoundingRect( bool use_bounding_rect );
bool getUseBoundingRect() const;

Expand Down Expand Up @@ -589,6 +591,9 @@ class LLView
LLView* mParentView;
child_list_t mChildList;

// Cache for fast child lookup by name - O(1) instead of O(n)
mutable std::unordered_map<std::string, LLView*> mChildNameCache;

// location in pixels, relative to surrounding structure, bottom,left=0,0
bool mVisible;
LLRect mRect;
Expand Down
2 changes: 2 additions & 0 deletions indra/newview/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ set(viewer_SOURCE_FILES
llappearancemgr.cpp
llappviewer.cpp
llappviewerlistener.cpp
llasyncinventoryskeletonloader.cpp
llattachmentsmgr.cpp
llaudiosourcevo.cpp
llautoreplace.cpp
Expand Down Expand Up @@ -780,6 +781,7 @@ set(viewer_HEADER_FILES
llappearancemgr.h
llappviewer.h
llappviewerlistener.h
llasyncinventoryskeletonloader.h
llattachmentsmgr.h
llaudiosourcevo.h
llautoreplace.h
Expand Down
66 changes: 66 additions & 0 deletions indra/newview/app_settings/settings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3258,6 +3258,72 @@
<key>Value</key>
<integer>255</integer>
</map>
<key>ForceAsyncInventorySkeleton</key>
<map>
<key>Comment</key>
<string>Force viewer to skip legacy login inventory skeleton and rely on async AIS fetching (QA only).</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>AsyncInventoryMaxConcurrentFetches</key>
<map>
<key>Comment</key>
<string>Maximum number of concurrent AIS fetches used during async inventory skeleton loading.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>U32</string>
<key>Value</key>
<integer>2</integer>
</map>
<key>AsyncInventoryNotifyMinInterval</key>
<map>
<key>Comment</key>
<string>Minimum seconds between inventory observer notifications while async inventory loading is active.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>0.05</real>
</map>
<key>AsyncInventoryCapsTimeout</key>
<map>
<key>Comment</key>
<string>Maximum seconds to wait for inventory capabilities during async skeleton loading.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>45.0</real>
</map>
<key>AsyncInventoryFetchTimeout</key>
<map>
<key>Comment</key>
<string>Maximum seconds for the entire async inventory skeleton fetch process.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>180.0</real>
</map>
<key>AsyncInventoryEssentialTimeout</key>
<map>
<key>Comment</key>
<string>Maximum seconds to wait for essential inventory folders during async loading.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>90.0</real>
</map>
<key>ForceLoginURL</key>
<map>
<key>Comment</key>
Expand Down
Loading