diff --git a/indra/llcommon/llprofiler.h b/indra/llcommon/llprofiler.h
index 65def060ad7d9e8365fc9958eba25da7531e5f80..e1458f415f9e9c5638b8b3f64e9a43503bcbe5f6 100644
--- a/indra/llcommon/llprofiler.h
+++ b/indra/llcommon/llprofiler.h
@@ -120,6 +120,7 @@ extern thread_local bool gProfilerEnabled;
         #define LL_PROFILER_THREAD_END(name)            (void)(name)
         #define LL_RECORD_BLOCK_TIME(name)                                                                  const LLTrace::BlockTimer& LL_GLUE_TOKENS(block_time_recorder, __LINE__)(LLTrace::timeThisBlock(name)); (void)LL_GLUE_TOKENS(block_time_recorder, __LINE__);
         #define LL_PROFILE_ZONE_NAMED(name)             // LL_PROFILE_ZONE_NAMED is a no-op when Tracy is disabled
+        #define LL_PROFILE_ZONE_NAMED_COLOR(name,color) // LL_PROFILE_ZONE_NAMED_COLOR is a no-op when Tracy is disabled
         #define LL_PROFILE_ZONE_SCOPED                  // LL_PROFILE_ZONE_SCOPED is a no-op when Tracy is disabled
         #define LL_PROFILE_ZONE_COLOR(name,color)       // LL_RECORD_BLOCK_TIME(name)
 
diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp
index edb0d8aaa8e71bc9f3c647a4659b1de9499fff80..62506f68928c0921b5859646c9a4b2cfe1ea3dc7 100644
--- a/indra/llcommon/llsdserialize.cpp
+++ b/indra/llcommon/llsdserialize.cpp
@@ -464,6 +464,7 @@ void LLSDParser::account(llssize bytes) const
 // virtual
 S32 LLSDNotationParser::doParse(std::istream& istr, LLSD& data, S32 max_depth) const
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD
 	// map: { string:object, string:object }
 	// array: [ object, object, object ]
 	// undef: !
@@ -723,6 +724,7 @@ S32 LLSDNotationParser::doParse(std::istream& istr, LLSD& data, S32 max_depth) c
 
 S32 LLSDNotationParser::parseMap(std::istream& istr, LLSD& map, S32 max_depth) const
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD
 	// map: { string:object, string:object }
 	map = LLSD::emptyMap();
 	S32 parse_count = 0;
@@ -783,6 +785,7 @@ S32 LLSDNotationParser::parseMap(std::istream& istr, LLSD& map, S32 max_depth) c
 
 S32 LLSDNotationParser::parseArray(std::istream& istr, LLSD& array, S32 max_depth) const
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD
 	// array: [ object, object, object ]
 	array = LLSD::emptyArray();
 	S32 parse_count = 0;
@@ -822,6 +825,7 @@ S32 LLSDNotationParser::parseArray(std::istream& istr, LLSD& array, S32 max_dept
 
 bool LLSDNotationParser::parseString(std::istream& istr, LLSD& data) const
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD
 	std::string value;
 	auto count = deserialize_string(istr, value, mMaxBytesLeft);
 	if(PARSE_FAILURE == count) return false;
@@ -832,6 +836,7 @@ bool LLSDNotationParser::parseString(std::istream& istr, LLSD& data) const
 
 bool LLSDNotationParser::parseBinary(std::istream& istr, LLSD& data) const
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD
 	// binary: b##"ff3120ab1"
 	// or: b(len)"..."
 
@@ -926,6 +931,7 @@ bool LLSDNotationParser::parseBinary(std::istream& istr, LLSD& data) const
 // virtual
 S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data, S32 max_depth) const
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD
 /**
  * Undefined: '!'<br>
  * Boolean: '1' for true '0' for false<br>
diff --git a/indra/llcommon/llsdserialize_xml.cpp b/indra/llcommon/llsdserialize_xml.cpp
index 580d87f40e595fe44d4397db1a466f2faf93d7d0..bbed84537ad232a820ca3b640e4e302c83cc921b 100644
--- a/indra/llcommon/llsdserialize_xml.cpp
+++ b/indra/llcommon/llsdserialize_xml.cpp
@@ -947,6 +947,8 @@ void LLSDXMLParser::parsePart(const char *buf, llssize len)
 // virtual
 S32 LLSDXMLParser::doParse(std::istream& input, LLSD& data, S32 max_depth) const
 {
+	LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD
+
 	#ifdef XML_PARSER_PERFORMANCE_TESTS
 	XML_Timer timer( &parseTime );
 	#endif	// XML_PARSER_PERFORMANCE_TESTS
diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp
index cd8fabea053a4f076ad1115fa90584a464a440aa..9075e949775f7527c39488eee98ccda775f5c735 100644
--- a/indra/llinventory/llinventory.cpp
+++ b/indra/llinventory/llinventory.cpp
@@ -896,6 +896,8 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new)
 		mInventoryType = LLInventoryType::IT_NONE;
 		mAssetUUID.setNull();
 	}
+
+#if 0  // old implementation.  makes a LOT of temporary copies and LLSD::safe(impl) calls
 	std::string w;
 
 	w = INV_ITEM_ID_LABEL;
@@ -1042,6 +1044,159 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new)
 	{
 		mCreationDate = sd[w].asInteger();
 	}
+#else  // if 0 - new implementation follows
+
+    mThumbnailUUID.setNull();
+
+    // iterate as map to avoid making unnecessary temp copies of everything
+    LLSD::map_const_iterator i, end;
+    end = sd.endMap();
+    for (i = sd.beginMap(); i != end; ++i)
+    {
+        if (i->first == INV_ITEM_ID_LABEL)
+        {
+            mUUID = i->second;
+        }
+
+        if (i->first == INV_PARENT_ID_LABEL)
+        {
+            mParentUUID = i->second;
+        }
+
+        if (i->first == INV_THUMBNAIL_LABEL)
+        {
+            const LLSD &thumbnail_map = i->second;
+            const std::string w = INV_ASSET_ID_LABEL;
+            if (thumbnail_map.has(w))
+            {
+                mThumbnailUUID = thumbnail_map[w];
+            }
+            /* Example:
+                <key> asset_id </key>
+                <uuid> acc0ec86 - 17f2 - 4b92 - ab41 - 6718b1f755f7 </uuid>
+                <key> perms </key>
+                <integer> 8 </integer>
+                <key>service</key>
+                <integer> 3 </integer>
+                <key>version</key>
+                <integer> 1 </key>
+            */
+        }
+
+        if (i->first == INV_THUMBNAIL_ID_LABEL)
+        {
+            mThumbnailUUID = i->second.asUUID();
+        }
+
+        if (i->first == INV_PERMISSIONS_LABEL)
+        {
+            mPermissions = ll_permissions_from_sd(i->second);
+        }
+
+        if (i->first == INV_SALE_INFO_LABEL)
+        {
+            // Sale info used to contain next owner perm. It is now in
+            // the permissions. Thus, we read that out, and fix legacy
+            // objects. It's possible this op would fail, but it
+            // should pick up the vast majority of the tasks.
+            BOOL has_perm_mask = FALSE;
+            U32  perm_mask     = 0;
+            if (!mSaleInfo.fromLLSD(i->second, has_perm_mask, perm_mask))
+            {
+                goto fail;
+            }
+            if (has_perm_mask)
+            {
+                if (perm_mask == PERM_NONE)
+                {
+                    perm_mask = mPermissions.getMaskOwner();
+                }
+                // fair use fix.
+                if (!(perm_mask & PERM_COPY))
+                {
+                    perm_mask |= PERM_TRANSFER;
+                }
+                mPermissions.setMaskNext(perm_mask);
+            }
+        }
+
+        if (i->first == INV_SHADOW_ID_LABEL)
+        {
+            mAssetUUID = i->second;
+            LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES);
+            cipher.decrypt(mAssetUUID.mData, UUID_BYTES);
+        }
+
+        if (i->first == INV_ASSET_ID_LABEL)
+        {
+            mAssetUUID = i->second;
+        }
+
+        if (i->first == INV_LINKED_ID_LABEL)
+        {
+            mAssetUUID = i->second;
+        }
+
+        if (i->first == INV_ASSET_TYPE_LABEL)
+        {
+            LLSD const &label = i->second;
+            if (label.isString())
+            {
+                mType = LLAssetType::lookup(label.asString().c_str());
+            }
+            else if (label.isInteger())
+            {
+                S8 type = (U8) label.asInteger();
+                mType   = static_cast<LLAssetType::EType>(type);
+            }
+        }
+
+        if (i->first == INV_INVENTORY_TYPE_LABEL)
+        {
+            LLSD const &label = i->second;
+            if (label.isString())
+            {
+                mInventoryType = LLInventoryType::lookup(label.asString().c_str());
+            }
+            else if (label.isInteger())
+            {
+                S8 type        = (U8) label.asInteger();
+                mInventoryType = static_cast<LLInventoryType::EType>(type);
+            }
+        }
+
+        if (i->first == INV_FLAGS_LABEL)
+        {
+            LLSD const &label = i->second;
+            if (label.isBinary())
+            {
+                mFlags = ll_U32_from_sd(label);
+            }
+            else if (label.isInteger())
+            {
+                mFlags = label.asInteger();
+            }
+        }
+
+        if (i->first == INV_NAME_LABEL)
+        {
+            mName = i->second.asString();
+            LLStringUtil::replaceNonstandardASCII(mName, ' ');
+            LLStringUtil::replaceChar(mName, '|', ' ');
+        }
+
+        if (i->first == INV_DESC_LABEL)
+        {
+            mDescription = i->second.asString();
+            LLStringUtil::replaceNonstandardASCII(mDescription, ' ');
+        }
+
+        if (i->first == INV_CREATION_DATE_LABEL)
+        {
+            mCreationDate = i->second.asInteger();
+        }
+    }
+#endif // new version
 
 	// Need to convert 1.0 simstate files to a useful inventory type
 	// and potentially deal with bad inventory tyes eg, a landmark
diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp
index a8a71ad8dbbe12128fd799653414019a53fb8bc5..0763eb17ea6b09d449c5d8a3c5751faa1e0a45db 100644
--- a/indra/llwindow/llwindowmacosx.cpp
+++ b/indra/llwindow/llwindowmacosx.cpp
@@ -1921,10 +1921,12 @@ class sharedContext
 void* LLWindowMacOSX::createSharedContext()
 {
     sharedContext* sc = new sharedContext();
-    CGLError err = CGLCreateContext(mPixelFormat, mContext, &(sc->mContext));
-    llassert(err == kCGLNoError);
-
-    CGLEnable(mContext, kCGLCEMPEngine);
+    CGLCreateContext(mPixelFormat, mContext, &(sc->mContext));
+    
+    if (sUseMultGL)
+    {
+        CGLEnable(mContext, kCGLCEMPEngine);
+    }
 
     return (void *)sc;
 }
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 16377037f5cbda5cf65c51d33c5c485bbd081375..c45be78039d2798bb98311e8f287f5ab30952eec 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -9561,7 +9561,7 @@
     <key>Type</key>
     <string>Boolean</string>
     <key>Value</key>
-    <integer>1</integer>
+    <integer>0</integer>
   </map>
     <key>RenderPerformanceTest</key>
     <map>
diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp
index 4a5a62ac0f5e7121cb5d7d2facddb5ac1f85f5e5..84c7e66bae51138deba5ef334a10b67d01ac888f 100644
--- a/indra/newview/llinventorymodel.cpp
+++ b/indra/newview/llinventorymodel.cpp
@@ -66,6 +66,7 @@
 #include "bufferstream.h"
 #include "llcorehttputil.h"
 #include "hbxxh.h"
+#include "llstartup.h"
 // [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a)
 #include "rlvhandler.h"
 #include "rlvlocks.h"
@@ -2816,6 +2817,7 @@ bool LLInventoryModel::loadSkeleton(
 	const LLSD& options,
 	const LLUUID& owner_id)
 {
+    LL_PROFILE_ZONE_SCOPED;
 #ifdef SHOW_DEBUG
 	LL_DEBUGS(LOG_INV) << "importing inventory skeleton for " << owner_id << LL_ENDL;
 #endif
@@ -3501,6 +3503,8 @@ bool LLInventoryModel::loadFromFile(const std::string& filename,
 									LLInventoryModel::changed_items_t& cats_to_update,
 									bool &is_cache_obsolete)
 {
+    LL_PROFILE_ZONE_NAMED("inventory load from file");
+
 	if(filename.empty())
 	{
 		LL_ERRS(LOG_INV) << "filename is Null!" << LL_ENDL;
@@ -3518,6 +3522,7 @@ bool LLInventoryModel::loadFromFile(const std::string& filename,
 
 	is_cache_obsolete = true; // Obsolete until proven current
 
+	U64 lines_count = 0U;
 	std::string line;
 	LLPointer<LLSDParser> parser = new LLSDNotationParser();
 	while (std::getline(file, line)) 
@@ -3566,7 +3571,7 @@ bool LLInventoryModel::loadFromFile(const std::string& filename,
 			{
 				if(inv_item->getUUID().isNull())
 				{
-					LL_WARNS(LOG_INV) << "Ignoring inventory with null item id: "
+					LL_DEBUGS(LOG_INV) << "Ignoring inventory with null item id: "
 						<< inv_item->getName() << LL_ENDL;
 				}
 				else
@@ -3582,6 +3587,13 @@ bool LLInventoryModel::loadFromFile(const std::string& filename,
 				}
 			}	
 		}
+
+		static constexpr U64 BATCH_SIZE = 512U;
+		if ((++lines_count % BATCH_SIZE) == 0)
+		{
+			// SL-19968 - make sure message system code gets a chance to run every so often
+			pump_idle_startup_network();
+		}
 	}
 
 	file.close();
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index b298648bec30b026feb51c9455c4d63309df7e8e..dc9a0d1a91a862502406a7ae4c91069e0535a3fb 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -315,10 +315,22 @@ void callback_cache_name(const LLUUID& id, const std::string& full_name, bool is
 // exported functionality
 //
 
+void pump_idle_startup_network(void)
+{
+    {
+        LockMessageChecker lmc(gMessageSystem);
+        while (lmc.checkAllMessages(gFrameCount, gServicePump))
+        {
+            display_startup();
+        }
+        lmc.processAcks();
+    }
+    display_startup();
+}
+
 //
 // local classes
 //
-
 void update_texture_fetch()
 {
 	LLAppViewer::getTextureCache()->update(1); // unpauses the texture cache thread
@@ -1707,15 +1719,7 @@ bool idle_startup()
 		{
 			LLStartUp::setStartupState( STATE_AGENT_SEND );
 		}
-		{
-			LockMessageChecker lmc(gMessageSystem);
-			while (lmc.checkAllMessages(gFrameCount, gServicePump))
-			{
-				display_startup();
-			}
-			lmc.processAcks();
-		}
-		display_startup();
+		pump_idle_startup_network();
 		return FALSE;
 	}
 
@@ -1820,6 +1824,7 @@ bool idle_startup()
 	//---------------------------------------------------------------------
 	if (STATE_INVENTORY_SEND == LLStartUp::getStartupState())
 	{
+		LL_PROFILE_ZONE_NAMED("State inventory send")
 		display_startup();
 
         // request mute list
@@ -1856,7 +1861,7 @@ bool idle_startup()
 			}
 		}
 		display_startup();
- 		
+
 		LLSD inv_lib_owner = response["inventory-lib-owner"];
 		if(inv_lib_owner.isDefined())
 		{
@@ -1864,30 +1869,52 @@ bool idle_startup()
 			LLSD id = inv_lib_owner[0]["agent_id"];
 			if(id.isDefined())
 			{
-				gInventory.setLibraryOwnerID( LLUUID(id.asUUID()));
+				gInventory.setLibraryOwnerID(LLUUID(id.asUUID()));
 			}
 		}
 		display_startup();
-
-		LLSD inv_skel_lib = response["inventory-skel-lib"];
- 		if(inv_skel_lib.isDefined() && gInventory.getLibraryOwnerID().notNull())
- 		{
- 			if(!gInventory.loadSkeleton(inv_skel_lib, gInventory.getLibraryOwnerID()))
- 			{
- 				LL_WARNS("AppInit") << "Problem loading inventory-skel-lib" << LL_ENDL;
- 			}
- 		}
+		LLStartUp::setStartupState(STATE_INVENTORY_SKEL);
 		display_startup();
+		return FALSE;
+	}
 
-		LLSD inv_skeleton = response["inventory-skeleton"];
- 		if(inv_skeleton.isDefined())
- 		{
- 			if(!gInventory.loadSkeleton(inv_skeleton, gAgent.getID()))
- 			{
- 				LL_WARNS("AppInit") << "Problem loading inventory-skel-targets" << LL_ENDL;
- 			}
- 		}
-		display_startup();
+    if (STATE_INVENTORY_SKEL == LLStartUp::getStartupState())
+    {
+        LL_PROFILE_ZONE_NAMED("State inventory load skeleton")
+
+		LLSD response = LLLoginInstance::getInstance()->getResponse();
+
+        LLSD inv_skel_lib = response["inventory-skel-lib"];
+        if (inv_skel_lib.isDefined() && gInventory.getLibraryOwnerID().notNull())
+        {
+            LL_PROFILE_ZONE_NAMED("load library inv")
+            if (!gInventory.loadSkeleton(inv_skel_lib, gInventory.getLibraryOwnerID()))
+            {
+                LL_WARNS("AppInit") << "Problem loading inventory-skel-lib" << LL_ENDL;
+            }
+        }
+        display_startup();
+
+        LLSD inv_skeleton = response["inventory-skeleton"];
+        if (inv_skeleton.isDefined())
+        {
+            LL_PROFILE_ZONE_NAMED("load personal inv")
+            if (!gInventory.loadSkeleton(inv_skeleton, gAgent.getID()))
+            {
+                LL_WARNS("AppInit") << "Problem loading inventory-skel-targets" << LL_ENDL;
+            }
+        }
+        display_startup();
+        LLStartUp::setStartupState(STATE_INVENTORY_SEND2);
+        display_startup();
+        return FALSE;
+    }
+
+    if (STATE_INVENTORY_SEND2 == LLStartUp::getStartupState())
+    {
+        LL_PROFILE_ZONE_NAMED("State inventory send2")
+
+		LLSD response = LLLoginInstance::getInstance()->getResponse();
 
 		LLSD inv_basic = response["inventory-basic"];
  		if(inv_basic.isDefined())
diff --git a/indra/newview/llstartup.h b/indra/newview/llstartup.h
index 4b6f3b38498d297b7951c48d5bd5efd54bc51997..383822a3ff70c1e101e1c8f13c2bd46e73c2aca0 100644
--- a/indra/newview/llstartup.h
+++ b/indra/newview/llstartup.h
@@ -39,6 +39,7 @@ class LLSLURL;
 bool idle_startup();
 void release_start_screen();
 bool login_alert_done(const LLSD& notification, const LLSD& response);
+void pump_idle_startup_network();
 
 // start location constants
 enum EStartLocation
@@ -71,6 +72,8 @@ typedef enum {
 	STATE_AGENT_WAIT,				// Wait for region
 	STATE_INVENTORY_SEND,			// Do inventory transfer
 	STATE_INVENTORY_CALLBACKS,		// Wait for missing system folders and register callbacks
+	STATE_INVENTORY_SKEL,			// Do more inventory skeleton loading
+	STATE_INVENTORY_SEND2,			// Do more inventory init after skeleton is loaded
 	STATE_MISC,						// Do more things (set bandwidth, start audio, save location, etc)
 	STATE_PRECACHE,					// Wait a bit for textures to download
 	STATE_WEARABLES_WAIT,			// Wait for clothing to download