#4724 Fix performance problems with My Outfits - <FS:PP> Cherry pick for FIRE-35936
# Conflicts: # indra/newview/lloutfitslist.cppmaster
parent
42df6526a2
commit
fa7cacc755
|
|
@ -303,8 +303,11 @@ void LLAccordionCtrl::ctrlSetLeftTopAndSize(LLView* panel, S32 left, S32 top, S3
|
||||||
return;
|
return;
|
||||||
LLRect panel_rect = panel->getRect();
|
LLRect panel_rect = panel->getRect();
|
||||||
panel_rect.setLeftTopAndSize( left, top, width, height);
|
panel_rect.setLeftTopAndSize( left, top, width, height);
|
||||||
panel->reshape( width, height, 1);
|
if (panel->getRect() != panel_rect)
|
||||||
panel->setRect(panel_rect);
|
{
|
||||||
|
panel->reshape( width, height, 1);
|
||||||
|
panel->setRect(panel_rect);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLAccordionCtrl::ctrlShiftVertical(LLView* panel, S32 delta)
|
void LLAccordionCtrl::ctrlShiftVertical(LLView* panel, S32 delta)
|
||||||
|
|
@ -494,6 +497,7 @@ void LLAccordionCtrl::arrangeMultiple()
|
||||||
|
|
||||||
void LLAccordionCtrl::arrange()
|
void LLAccordionCtrl::arrange()
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED;
|
||||||
updateNoTabsHelpTextVisibility();
|
updateNoTabsHelpTextVisibility();
|
||||||
|
|
||||||
if (mAccordionTabs.empty())
|
if (mAccordionTabs.empty())
|
||||||
|
|
|
||||||
|
|
@ -248,10 +248,22 @@ void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::draw()
|
||||||
void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::reshape(S32 width, S32 height, bool called_from_parent /* = true */)
|
void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::reshape(S32 width, S32 height, bool called_from_parent /* = true */)
|
||||||
{
|
{
|
||||||
S32 header_height = mHeaderTextbox->getTextPixelHeight();
|
S32 header_height = mHeaderTextbox->getTextPixelHeight();
|
||||||
|
LLRect old_header_rect = mHeaderTextbox->getRect();
|
||||||
|
|
||||||
LLRect textboxRect(HEADER_TEXT_LEFT_OFFSET, (height + header_height) / 2, width, (height - header_height) / 2);
|
LLRect textboxRect(HEADER_TEXT_LEFT_OFFSET, (height + header_height) / 2, width, (height - header_height) / 2);
|
||||||
mHeaderTextbox->reshape(textboxRect.getWidth(), textboxRect.getHeight());
|
if (old_header_rect.getHeight() != textboxRect.getHeight()
|
||||||
mHeaderTextbox->setRect(textboxRect);
|
|| old_header_rect.mLeft != textboxRect.mLeft
|
||||||
|
|| old_header_rect.mTop != textboxRect.mTop
|
||||||
|
|| old_header_rect.getWidth() > textboxRect.getWidth() // reducing header's width
|
||||||
|
|| (old_header_rect.getWidth() < textboxRect.getWidth() && old_header_rect.getWidth() < mHeaderTextbox->getTextPixelWidth()))
|
||||||
|
{
|
||||||
|
// Expensive text reflow
|
||||||
|
// Update if position or height changes
|
||||||
|
// Update if width reduces
|
||||||
|
// But do not update if text already fits and width increases (arguably LLTextBox::reshape should be smarter, not Accordion)
|
||||||
|
mHeaderTextbox->reshape(textboxRect.getWidth(), textboxRect.getHeight());
|
||||||
|
mHeaderTextbox->setRect(textboxRect);
|
||||||
|
}
|
||||||
|
|
||||||
if (mHeaderTextbox->getTextPixelWidth() > mHeaderTextbox->getRect().getWidth())
|
if (mHeaderTextbox->getTextPixelWidth() > mHeaderTextbox->getRect().getWidth())
|
||||||
{
|
{
|
||||||
|
|
@ -416,8 +428,11 @@ void LLAccordionCtrlTab::reshape(S32 width, S32 height, bool called_from_parent
|
||||||
LLRect headerRect;
|
LLRect headerRect;
|
||||||
|
|
||||||
headerRect.setLeftTopAndSize(0, height, width, HEADER_HEIGHT);
|
headerRect.setLeftTopAndSize(0, height, width, HEADER_HEIGHT);
|
||||||
mHeader->setRect(headerRect);
|
if (mHeader->getRect() != headerRect)
|
||||||
mHeader->reshape(headerRect.getWidth(), headerRect.getHeight());
|
{
|
||||||
|
mHeader->setRect(headerRect);
|
||||||
|
mHeader->reshape(headerRect.getWidth(), headerRect.getHeight());
|
||||||
|
}
|
||||||
|
|
||||||
if (!mDisplayChildren)
|
if (!mDisplayChildren)
|
||||||
return;
|
return;
|
||||||
|
|
@ -932,7 +947,7 @@ void LLAccordionCtrlTab::adjustContainerPanel(const LLRect& child_rect)
|
||||||
show_hide_scrollbar(child_rect);
|
show_hide_scrollbar(child_rect);
|
||||||
updateLayout(child_rect);
|
updateLayout(child_rect);
|
||||||
}
|
}
|
||||||
else
|
else if (mContainerPanel->getRect() != child_rect)
|
||||||
{
|
{
|
||||||
mContainerPanel->reshape(child_rect.getWidth(), child_rect.getHeight());
|
mContainerPanel->reshape(child_rect.getWidth(), child_rect.getHeight());
|
||||||
mContainerPanel->setRect(child_rect);
|
mContainerPanel->setRect(child_rect);
|
||||||
|
|
|
||||||
|
|
@ -1592,6 +1592,8 @@ void LLTextBase::reshape(S32 width, S32 height, bool called_from_parent)
|
||||||
// up-to-date mVisibleTextRect
|
// up-to-date mVisibleTextRect
|
||||||
updateRects();
|
updateRects();
|
||||||
|
|
||||||
|
// Todo: This might be wrong. updateRects already sets needsReflow conditionaly.
|
||||||
|
// Reflow is expensive and doing it at any twith can be too much.
|
||||||
needsReflow();
|
needsReflow();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,10 @@
|
||||||
#include "llinventorymodel.h"
|
#include "llinventorymodel.h"
|
||||||
#include "llviewerinventory.h"
|
#include "llviewerinventory.h"
|
||||||
|
|
||||||
|
bool LLInventoryItemsList::sListIdleRegistered = false;
|
||||||
|
LLInventoryItemsList::all_list_t LLInventoryItemsList::sAllLists;
|
||||||
|
LLInventoryItemsList::all_list_t::iterator LLInventoryItemsList::sAllListIter;
|
||||||
|
|
||||||
LLInventoryItemsList::Params::Params()
|
LLInventoryItemsList::Params::Params()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
|
@ -55,13 +59,39 @@ LLInventoryItemsList::LLInventoryItemsList(const LLInventoryItemsList::Params& p
|
||||||
|
|
||||||
setNoFilteredItemsMsg(LLTrans::getString("InventoryNoMatchingItems"));
|
setNoFilteredItemsMsg(LLTrans::getString("InventoryNoMatchingItems"));
|
||||||
|
|
||||||
gIdleCallbacks.addFunction(idle, this);
|
sAllLists.push_back(this);
|
||||||
|
sAllListIter = sAllLists.begin();
|
||||||
|
|
||||||
|
if (!sListIdleRegistered)
|
||||||
|
{
|
||||||
|
sAllListIter = sAllLists.begin();
|
||||||
|
gIdleCallbacks.addFunction(idle, nullptr);
|
||||||
|
|
||||||
|
LLEventPumps::instance().obtain("LLApp").listen(
|
||||||
|
"LLInventoryItemsList",
|
||||||
|
[](const LLSD& stat)
|
||||||
|
{
|
||||||
|
std::string status(stat["status"]);
|
||||||
|
if (status != "running")
|
||||||
|
{
|
||||||
|
// viewer is starting shutdown
|
||||||
|
gIdleCallbacks.deleteFunction(idle, nullptr);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
sListIdleRegistered = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// virtual
|
// virtual
|
||||||
LLInventoryItemsList::~LLInventoryItemsList()
|
LLInventoryItemsList::~LLInventoryItemsList()
|
||||||
{
|
{
|
||||||
gIdleCallbacks.deleteFunction(idle, this);
|
auto it = std::find(sAllLists.begin(), sAllLists.end(), this);
|
||||||
|
if (it != sAllLists.end())
|
||||||
|
{
|
||||||
|
sAllLists.erase(it);
|
||||||
|
sAllListIter = sAllLists.begin();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLInventoryItemsList::refreshList(const LLInventoryModel::item_array_t item_array)
|
void LLInventoryItemsList::refreshList(const LLInventoryModel::item_array_t item_array)
|
||||||
|
|
@ -111,25 +141,55 @@ void LLInventoryItemsList::updateSelection()
|
||||||
mSelectTheseIDs.clear();
|
mSelectTheseIDs.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLInventoryItemsList::doIdle()
|
bool LLInventoryItemsList::doIdle()
|
||||||
{
|
{
|
||||||
if (mRefreshState == REFRESH_COMPLETE) return;
|
if (mRefreshState == REFRESH_COMPLETE) return true; // done
|
||||||
|
|
||||||
if (isInVisibleChain() || mForceRefresh || !getFilterSubString().empty())
|
if (isInVisibleChain() || mForceRefresh || !getFilterSubString().empty())
|
||||||
{
|
{
|
||||||
refresh();
|
refresh();
|
||||||
|
|
||||||
mRefreshCompleteSignal(this, LLSD());
|
mRefreshCompleteSignal(this, LLSD());
|
||||||
|
return false; // keep going
|
||||||
}
|
}
|
||||||
|
return true; // done
|
||||||
}
|
}
|
||||||
|
|
||||||
//static
|
//static
|
||||||
void LLInventoryItemsList::idle(void* user_data)
|
void LLInventoryItemsList::idle(void* user_data)
|
||||||
{
|
{
|
||||||
LLInventoryItemsList* self = static_cast<LLInventoryItemsList*>(user_data);
|
if (sAllLists.empty())
|
||||||
if ( self )
|
return;
|
||||||
{ // Do the real idle
|
|
||||||
self->doIdle();
|
LL_PROFILE_ZONE_SCOPED;
|
||||||
|
|
||||||
|
using namespace std::chrono;
|
||||||
|
auto start = steady_clock::now();
|
||||||
|
const milliseconds time_limit = milliseconds(3);
|
||||||
|
const auto end_time = start + time_limit;
|
||||||
|
S32 max_update_count = 50;
|
||||||
|
|
||||||
|
if (sAllListIter == sAllLists.end())
|
||||||
|
{
|
||||||
|
sAllListIter = sAllLists.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
S32 updated = 0;
|
||||||
|
while (steady_clock::now() < end_time
|
||||||
|
&& updated < max_update_count
|
||||||
|
&& sAllListIter != sAllLists.end())
|
||||||
|
{
|
||||||
|
LLInventoryItemsList* list = *sAllListIter;
|
||||||
|
// Refresh is split into multiple separate parts,
|
||||||
|
// so keep repeating it while there is time, until done.
|
||||||
|
// Todo: refresh() split is pointless now?
|
||||||
|
// Or still useful for large folders?
|
||||||
|
if (list->doIdle())
|
||||||
|
{
|
||||||
|
// Item is done
|
||||||
|
++sAllListIter;
|
||||||
|
updated++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -141,6 +201,7 @@ void LLInventoryItemsList::refresh()
|
||||||
{
|
{
|
||||||
case REFRESH_ALL:
|
case REFRESH_ALL:
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_NAMED("items_refresh_all");
|
||||||
mAddedItems.clear();
|
mAddedItems.clear();
|
||||||
mRemovedItems.clear();
|
mRemovedItems.clear();
|
||||||
computeDifference(getIDs(), mAddedItems, mRemovedItems);
|
computeDifference(getIDs(), mAddedItems, mRemovedItems);
|
||||||
|
|
@ -163,6 +224,7 @@ void LLInventoryItemsList::refresh()
|
||||||
}
|
}
|
||||||
case REFRESH_LIST_ERASE:
|
case REFRESH_LIST_ERASE:
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_NAMED("items_refresh_erase");
|
||||||
uuid_vec_t::const_iterator it = mRemovedItems.begin();
|
uuid_vec_t::const_iterator it = mRemovedItems.begin();
|
||||||
for (; mRemovedItems.end() != it; ++it)
|
for (; mRemovedItems.end() != it; ++it)
|
||||||
{
|
{
|
||||||
|
|
@ -175,6 +237,7 @@ void LLInventoryItemsList::refresh()
|
||||||
}
|
}
|
||||||
case REFRESH_LIST_APPEND:
|
case REFRESH_LIST_APPEND:
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_NAMED("items_refresh_append");
|
||||||
static const unsigned ADD_LIMIT = 25; // Note: affects perfomance
|
static const unsigned ADD_LIMIT = 25; // Note: affects perfomance
|
||||||
|
|
||||||
unsigned int nadded = 0;
|
unsigned int nadded = 0;
|
||||||
|
|
@ -239,6 +302,7 @@ void LLInventoryItemsList::refresh()
|
||||||
}
|
}
|
||||||
case REFRESH_LIST_SORT:
|
case REFRESH_LIST_SORT:
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_NAMED("items_refresh_sort");
|
||||||
// Filter, sort, rearrange and notify parent about shape changes
|
// Filter, sort, rearrange and notify parent about shape changes
|
||||||
filterItems(true, true);
|
filterItems(true, true);
|
||||||
|
|
||||||
|
|
@ -255,7 +319,10 @@ void LLInventoryItemsList::refresh()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
{
|
||||||
|
mRefreshState = REFRESH_COMPLETE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setForceRefresh(mRefreshState != REFRESH_COMPLETE);
|
setForceRefresh(mRefreshState != REFRESH_COMPLETE);
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,10 @@ public:
|
||||||
* Sets the flag indicating that the list needs to be refreshed even if it is
|
* Sets the flag indicating that the list needs to be refreshed even if it is
|
||||||
* not currently visible.
|
* not currently visible.
|
||||||
*/
|
*/
|
||||||
void setForceRefresh(bool force_refresh) { mForceRefresh = force_refresh; }
|
void setForceRefresh(bool force_refresh)
|
||||||
|
{
|
||||||
|
mForceRefresh = force_refresh;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If refreshes when invisible.
|
* If refreshes when invisible.
|
||||||
|
|
@ -76,7 +79,7 @@ public:
|
||||||
* This is needed for example to filter items of the list hidden by closed
|
* This is needed for example to filter items of the list hidden by closed
|
||||||
* accordion tab.
|
* accordion tab.
|
||||||
*/
|
*/
|
||||||
virtual void doIdle(); // Real idle routine
|
bool doIdle(); // Real idle routine
|
||||||
static void idle(void* user_data); // static glue to doIdle()
|
static void idle(void* user_data); // static glue to doIdle()
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
@ -126,6 +129,12 @@ private:
|
||||||
bool mForceRefresh;
|
bool mForceRefresh;
|
||||||
|
|
||||||
commit_signal_t mRefreshCompleteSignal;
|
commit_signal_t mRefreshCompleteSignal;
|
||||||
|
|
||||||
|
// Update synchronization
|
||||||
|
typedef std::vector<LLInventoryItemsList*> all_list_t;
|
||||||
|
static all_list_t sAllLists;
|
||||||
|
static all_list_t::iterator sAllListIter;
|
||||||
|
static bool sListIdleRegistered;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //LL_LLINVENTORYITEMSLIST_H
|
#endif //LL_LLINVENTORYITEMSLIST_H
|
||||||
|
|
|
||||||
|
|
@ -818,6 +818,7 @@ void LLOutfitGallery::getCurrentCategories(uuid_vec_t& vcur)
|
||||||
|
|
||||||
void LLOutfitGallery::updateAddedCategory(LLUUID cat_id)
|
void LLOutfitGallery::updateAddedCategory(LLUUID cat_id)
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED;
|
||||||
LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id);
|
LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id);
|
||||||
if (!cat) return;
|
if (!cat) return;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -189,6 +189,7 @@ void LLOutfitsList::onOpen(const LLSD& info)
|
||||||
|
|
||||||
void LLOutfitsList::updateAddedCategory(LLUUID cat_id)
|
void LLOutfitsList::updateAddedCategory(LLUUID cat_id)
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED;
|
||||||
LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id);
|
LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id);
|
||||||
if (!cat) return;
|
if (!cat) return;
|
||||||
|
|
||||||
|
|
@ -260,7 +261,9 @@ void LLOutfitsList::updateAddedCategory(LLUUID cat_id)
|
||||||
|
|
||||||
if (AISAPI::isAvailable() && LLInventoryModelBackgroundFetch::instance().folderFetchActive())
|
if (AISAPI::isAvailable() && LLInventoryModelBackgroundFetch::instance().folderFetchActive())
|
||||||
{
|
{
|
||||||
// for reliability just fetch it whole, linked items included
|
// For reliability just fetch it whole, linked items included
|
||||||
|
// Todo: list is not warrantied to exist once callback arrives
|
||||||
|
// Fix it!
|
||||||
LLInventoryModelBackgroundFetch::instance().fetchFolderAndLinks(cat_id, [cat_id, list]
|
LLInventoryModelBackgroundFetch::instance().fetchFolderAndLinks(cat_id, [cat_id, list]
|
||||||
{
|
{
|
||||||
if (list)
|
if (list)
|
||||||
|
|
@ -1153,6 +1156,7 @@ void LLOutfitListBase::onIdle(void* userdata)
|
||||||
|
|
||||||
void LLOutfitListBase::onIdleRefreshList()
|
void LLOutfitListBase::onIdleRefreshList()
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED;
|
||||||
if (LLAppViewer::instance()->quitRequested())
|
if (LLAppViewer::instance()->quitRequested())
|
||||||
{
|
{
|
||||||
mRefreshListState.CategoryUUID.setNull();
|
mRefreshListState.CategoryUUID.setNull();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue