From b00b733e3cbdd07e39f42765db220a5ec74d0705 Mon Sep 17 00:00:00 2001
From: Mnikolenko Productengine <mnikolenko@productengine.com>
Date: Fri, 26 Jun 2020 15:10:46 +0300
Subject: SL-13397 Reduce Viewer freeze when opening chat with a large group.

---
 indra/newview/llfloaterimcontainer.cpp  | 50 ++++++++++++++++++++++-----------
 indra/newview/llfloaterimcontainer.h    |  4 +++
 indra/newview/llfloaterimsessiontab.cpp |  7 +++--
 indra/newview/llfloaterimsessiontab.h   |  2 +-
 4 files changed, 42 insertions(+), 21 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp
index 21420b122b..feb8cf4277 100644
--- a/indra/newview/llfloaterimcontainer.cpp
+++ b/indra/newview/llfloaterimcontainer.cpp
@@ -57,6 +57,9 @@
 #include "llviewerobjectlist.h"
 #include "boost/foreach.hpp"
 
+
+const S32 EVENTS_PER_IDLE_LOOP = 100;
+
 //
 // LLFloaterIMContainer
 //
@@ -66,7 +69,8 @@ LLFloaterIMContainer::LLFloaterIMContainer(const LLSD& seed, const Params& param
 	mConversationsRoot(NULL),
 	mConversationsEventStream("ConversationsEvents"),
 	mInitialized(false),
-	mIsFirstLaunch(true)
+	mIsFirstLaunch(true),
+	mConversationEventQueue()
 {
     mEnableCallbackRegistrar.add("IMFloaterContainer.Check", boost::bind(&LLFloaterIMContainer::isActionChecked, this, _2));
 	mCommitCallbackRegistrar.add("IMFloaterContainer.Action", boost::bind(&LLFloaterIMContainer::onCustomAction,  this, _2));
@@ -424,7 +428,9 @@ void LLFloaterIMContainer::idle(void* user_data)
 {
 	LLFloaterIMContainer* self = static_cast<LLFloaterIMContainer*>(user_data);
 
-    if (!self->getVisible() || self->isMinimized())
+	self->idleProcessEvents();
+
+	if (!self->getVisible() || self->isMinimized())
     {
         return;
     }
@@ -485,13 +491,28 @@ void LLFloaterIMContainer::idleUpdate()
     }
 }
 
+void LLFloaterIMContainer::idleProcessEvents()
+{
+	if (!mConversationEventQueue.empty())
+	{
+		S32 events_to_handle = llmin((S32)mConversationEventQueue.size(), EVENTS_PER_IDLE_LOOP);
+		for (S32 i = 0; i < events_to_handle; i++)
+		{
+			handleConversationModelEvent(mConversationEventQueue.back());
+			mConversationEventQueue.pop_back();
+		}
+	}
+}
+
 bool LLFloaterIMContainer::onConversationModelEvent(const LLSD& event)
 {
-	// For debug only
-	//std::ostringstream llsd_value;
-	//llsd_value << LLSDOStreamer<LLSDNotationFormatter>(event) << std::endl;
-	//LL_INFOS() << "LLFloaterIMContainer::onConversationModelEvent, event = " << llsd_value.str() << LL_ENDL;
-	// end debug
+	mConversationEventQueue.push_front(event);
+	return true;
+}
+
+
+void LLFloaterIMContainer::handleConversationModelEvent(const LLSD& event)
+{
 	
 	// Note: In conversations, the model is not responsible for creating the view, which is a good thing. This means that
 	// the model could change substantially and the view could echo only a portion of this model (though currently the 
@@ -508,7 +529,7 @@ bool LLFloaterIMContainer::onConversationModelEvent(const LLSD& event)
 	if (!session_view)
 	{
 		// We skip events that are not associated with a session
-		return false;
+		return;
 	}
 	LLConversationViewParticipant* participant_view = session_view->findParticipant(participant_id);
     LLFloaterIMSessionTab *conversation_floater = (session_id.isNull() ?
@@ -535,9 +556,9 @@ bool LLFloaterIMContainer::onConversationModelEvent(const LLSD& event)
 	{
 		LLConversationItemSession* session_model = dynamic_cast<LLConversationItemSession*>(mConversationsItems[session_id]);
 		LLConversationItemParticipant* participant_model = (session_model ? session_model->findParticipant(participant_id) : NULL);
+		LLIMModel::LLIMSession * im_sessionp = LLIMModel::getInstance()->findIMSession(session_id);
 		if (!participant_view && session_model && participant_model)
-		{
-			LLIMModel::LLIMSession * im_sessionp = LLIMModel::getInstance()->findIMSession(session_id);
+		{	
 			if (session_id.isNull() || (im_sessionp && !im_sessionp->isP2PSessionType()))
 			{
 				participant_view = createConversationViewParticipant(participant_model);
@@ -548,7 +569,8 @@ bool LLFloaterIMContainer::onConversationModelEvent(const LLSD& event)
 		// Add a participant view to the conversation floater 
 		if (conversation_floater && participant_model)
 		{
-			conversation_floater->addConversationViewParticipant(participant_model);
+			bool skip_updating = im_sessionp && im_sessionp->isGroupChat();
+			conversation_floater->addConversationViewParticipant(participant_model, !skip_updating);
 		}
 	}
 	else if (type == "update_participant")
@@ -571,12 +593,6 @@ bool LLFloaterIMContainer::onConversationModelEvent(const LLSD& event)
 	
 	mConversationViewModel.requestSortAll();
 	mConversationsRoot->arrangeAll();
-	if (conversation_floater)
-	{
-		conversation_floater->refreshConversation();
-	}
-	
-	return false;
 }
 
 void LLFloaterIMContainer::draw()
diff --git a/indra/newview/llfloaterimcontainer.h b/indra/newview/llfloaterimcontainer.h
index 78b3572111..530a8e66c8 100644
--- a/indra/newview/llfloaterimcontainer.h
+++ b/indra/newview/llfloaterimcontainer.h
@@ -181,6 +181,7 @@ private:
 	bool isParticipantListExpanded();
 
 	void idleUpdate(); // for convenience (self) from static idle
+	void idleProcessEvents();
 
 	LLButton* mExpandCollapseBtn;
 	LLButton* mStubCollapseBtn;
@@ -220,6 +221,7 @@ private:
 	LLConversationViewSession* createConversationItemWidget(LLConversationItem* item);
 	LLConversationViewParticipant* createConversationViewParticipant(LLConversationItem* item);
 	bool onConversationModelEvent(const LLSD& event);
+	void handleConversationModelEvent(const LLSD& event);
 
 	// Conversation list data
 	LLPanel* mConversationsListPanel;	// This is the main widget we add conversation widget to
@@ -229,6 +231,8 @@ private:
 	LLFolderView* mConversationsRoot;
 	LLEventStream mConversationsEventStream; 
 
+	std::deque<LLSD> mConversationEventQueue;
+
 	LLTimer mParticipantRefreshTimer;
 };
 
diff --git a/indra/newview/llfloaterimsessiontab.cpp b/indra/newview/llfloaterimsessiontab.cpp
index 3aee08482b..6d326f6850 100644
--- a/indra/newview/llfloaterimsessiontab.cpp
+++ b/indra/newview/llfloaterimsessiontab.cpp
@@ -465,9 +465,10 @@ void LLFloaterIMSessionTab::appendMessage(const LLChat& chat, const LLSD &args)
 	}
 }
 
-
+static LLTrace::BlockTimerStatHandle FTM_BUILD_CONVERSATION_VIEW_PARTICIPANT("Build Conversation View");
 void LLFloaterIMSessionTab::buildConversationViewParticipant()
 {
+	LL_RECORD_BLOCK_TIME(FTM_BUILD_CONVERSATION_VIEW_PARTICIPANT);
 	// Clear the widget list since we are rebuilding afresh from the model
 	conversations_widgets_map::iterator widget_it = mConversationsWidgets.begin();
 	while (widget_it != mConversationsWidgets.end())
@@ -496,14 +497,14 @@ void LLFloaterIMSessionTab::buildConversationViewParticipant()
 	}
 }
 
-void LLFloaterIMSessionTab::addConversationViewParticipant(LLConversationItem* participant_model)
+void LLFloaterIMSessionTab::addConversationViewParticipant(LLConversationItem* participant_model, bool update_view)
 {
 	// Check if the model already has an associated view
 	LLUUID uuid = participant_model->getUUID();
 	LLFolderViewItem* widget = get_ptr_in_map(mConversationsWidgets,uuid);
 	
 	// If not already present, create the participant view and attach it to the root, otherwise, just refresh it
-	if (widget)
+	if (widget && update_view)
 	{
 		updateConversationViewParticipant(uuid); // overkill?
 	}
diff --git a/indra/newview/llfloaterimsessiontab.h b/indra/newview/llfloaterimsessiontab.h
index 1b4922fd73..5357a14ab9 100644
--- a/indra/newview/llfloaterimsessiontab.h
+++ b/indra/newview/llfloaterimsessiontab.h
@@ -84,7 +84,7 @@ public:
 	/*virtual*/ void setFocus(BOOL focus);
 	
 	// Handle the left hand participant list widgets
-	void addConversationViewParticipant(LLConversationItem* item);
+	void addConversationViewParticipant(LLConversationItem* item, bool update_view = true);
 	void removeConversationViewParticipant(const LLUUID& participant_id);
 	void updateConversationViewParticipant(const LLUUID& participant_id);
 	void refreshConversation();
-- 
cgit v1.2.3