diff --git a/doc/contributions.txt b/doc/contributions.txt
index eb8ae60cb79a1adc4ff0e073b7fd33d5dd78c29c..2153e108882ae9445823a59db37ec683c5f5d388 100755
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -347,6 +347,7 @@ Charles Courtois
 Charlie Sazaland
 Chaser Zaks
     BUG-225599
+    BUG-227485
 Cherry Cheevers
 ChickyBabes Zuzu
 Christopher  Organiser
diff --git a/indra/llaudio/llaudiodecodemgr.cpp b/indra/llaudio/llaudiodecodemgr.cpp
index 6ab61689fd0532a8f67c65576ed2cd0c7bfcda94..e7db84f6ab2783b048a778ae5f1ef551bfa012cd 100644
--- a/indra/llaudio/llaudiodecodemgr.cpp
+++ b/indra/llaudio/llaudiodecodemgr.cpp
@@ -271,7 +271,7 @@ BOOL LLVorbisDecodeState::initDecode()
 		mWAVBuffer.reserve(size_guess);
 		mWAVBuffer.resize(WAV_HEADER_SIZE);
 	}
-	catch (std::bad_alloc)
+	catch (std::bad_alloc&)
 	{
 		LL_WARNS("AudioEngine") << "Out of memory when trying to alloc buffer: " << size_guess << LL_ENDL;
 		delete mInFilep;
diff --git a/indra/llcommon/llprocessor.cpp b/indra/llcommon/llprocessor.cpp
index a618a1cc709b75bdf7e6b65020ca361083b6556d..5d16a4b74d3b5ad306ec13f2a90ba57dd01de2e8 100644
--- a/indra/llcommon/llprocessor.cpp
+++ b/indra/llcommon/llprocessor.cpp
@@ -195,6 +195,8 @@ namespace
 	
 	std::string amd_CPUFamilyName(int composed_family) 
 	{
+        // https://en.wikipedia.org/wiki/List_of_AMD_CPU_microarchitectures
+        // https://developer.amd.com/resources/developer-guides-manuals/
 		switch(composed_family)
 		{
 		case 4: return "AMD 80486/5x86";
@@ -202,6 +204,13 @@ namespace
 		case 6: return "AMD K7";
 		case 0xF: return "AMD K8";
 		case 0x10: return "AMD K8L";
+		case 0x12: return "AMD K10";
+		case 0x14: return "AMD Bobcat";
+		case 0x15: return "AMD Bulldozer";
+		case 0x16: return "AMD Jaguar";
+		case 0x17: return "AMD Zen/Zen+/Zen2";
+		case 0x18: return "AMD Hygon Dhyana";
+		case 0x19: return "AMD Zen 3";
 		}
 		return STRINGIZE("AMD <unknown 0x" << std::hex << composed_family << ">");
 	}
diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp
index c3fb4ebc2ca415569f4a12d5123841cf6bee7b9d..79934642ae2491cb78433dad618f6c8e0a531b69 100644
--- a/indra/llcommon/llsdserialize.cpp
+++ b/indra/llcommon/llsdserialize.cpp
@@ -2251,7 +2251,7 @@ LLUZipHelper::EZipRresult LLUZipHelper::unzip_llsd(LLSD& data, std::istream& is,
 			return ZR_SIZE_ERROR;
 		}
 #endif
-		catch (std::bad_alloc)
+		catch (std::bad_alloc&)
 		{
 			free(result);
 			return ZR_MEM_ERROR;
diff --git a/indra/llcorehttp/_httpservice.cpp b/indra/llcorehttp/_httpservice.cpp
index 0b72b5318601f92834dadb93df0cfd968838576e..34268d94f64969b4746f302530a14e196fe3c72d 100644
--- a/indra/llcorehttp/_httpservice.cpp
+++ b/indra/llcorehttp/_httpservice.cpp
@@ -318,7 +318,7 @@ void HttpService::threadRun(LLCoreInt::HttpThread * thread)
         {
             LOG_UNHANDLED_EXCEPTION("");
         }
-        catch (std::bad_alloc)
+        catch (std::bad_alloc&)
         {
             LLMemory::logMemoryInfo(TRUE);
 
diff --git a/indra/llcorehttp/bufferarray.cpp b/indra/llcorehttp/bufferarray.cpp
index be534b3ce4f2fd67d11ef9158bf1f076e1565c8f..e0b2876a0016167b6dc007da55e8eef869f54287 100644
--- a/indra/llcorehttp/bufferarray.cpp
+++ b/indra/llcorehttp/bufferarray.cpp
@@ -147,7 +147,7 @@ size_t BufferArray::append(const void * src, size_t len)
         {
             block = Block::alloc(BLOCK_ALLOC_SIZE);
         }
-        catch (std::bad_alloc)
+        catch (std::bad_alloc&)
         {
             LLMemory::logMemoryInfo(TRUE);
 
diff --git a/indra/llimage/llimagejpeg.cpp b/indra/llimage/llimagejpeg.cpp
index 3b1b060c023b4ffe4146bcb8f972bf20644d5852..ead9a37fb89592633c24079c908e79e3063dc5e1 100644
--- a/indra/llimage/llimagejpeg.cpp
+++ b/indra/llimage/llimagejpeg.cpp
@@ -315,7 +315,7 @@ bool LLImageJPEG::decode(LLImageRaw* raw_image, F32 decode_time)
 		jpeg_destroy_decompress(&cinfo);
 	}
 
-	catch (std::bad_alloc)
+	catch (std::bad_alloc&)
 	{
 		setLastError( "Out of memory");
 		jpeg_destroy_decompress(&cinfo);
diff --git a/indra/llimage/llpngwrapper.cpp b/indra/llimage/llpngwrapper.cpp
index f298764cc0743a8a5856c741a7645673e920961f..f7dc6272cf94cc7c5ad4319669781eb7f63f9080 100644
--- a/indra/llimage/llpngwrapper.cpp
+++ b/indra/llimage/llpngwrapper.cpp
@@ -210,7 +210,7 @@ BOOL LLPngWrapper::readPng(U8* src, S32 dataSize, LLImageRaw* rawImage, ImageInf
 		releaseResources();
 		return (FALSE);
 	}
-	catch (std::bad_alloc)
+	catch (std::bad_alloc&)
 	{
 		mErrorMessage = "LLPngWrapper";
 		releaseResources();
diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index 2ac1eb99ce7d250ebba085d4ca251bae0750931e..7da53bf8c885ac0903bdef0ca6ce5d29ab0e2789 100644
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -2399,9 +2399,9 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
 			{ //face has no geometry, continue
 				face.resizeIndices(3);
 				face.resizeVertices(1);
-				memset(face.mPositions, 0, sizeof(LLVector4a));
-				memset(face.mNormals, 0, sizeof(LLVector4a));
-				memset(face.mTexCoords, 0, sizeof(LLVector2));
+				face.mPositions->clear();
+				face.mNormals->clear();
+				face.mTexCoords->setZero();
 				memset(face.mIndices, 0, sizeof(U16)*3);
 				continue;
 			}
@@ -2489,7 +2489,11 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
 				}
 				else
 				{
-					memset(norm_out, 0, sizeof(LLVector4a)*num_verts);
+					for (U32 j = 0; j < num_verts; ++j)
+					{
+						norm_out->clear();
+						norm_out++; // or just norm_out[j].clear();
+					}
 				}
 			}
 
@@ -2519,7 +2523,11 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
 				}
 				else
 				{
-					memset(tc_out, 0, sizeof(LLVector2)*num_verts);
+					for (U32 j = 0; j < num_verts; j += 2)
+					{
+						tc_out->clear();
+						tc_out++;
+					}
 				}
 			}
 
@@ -5288,7 +5296,7 @@ bool LLVolumeFace::cacheOptimize()
 		triangle_data.resize(mNumIndices / 3);
 		vertex_data.resize(mNumVertices);
 	}
-	catch (std::bad_alloc)
+	catch (std::bad_alloc&)
 	{
 		LL_WARNS("LLVOLUME") << "Resize failed" << LL_ENDL;
 		return false;
@@ -5442,7 +5450,7 @@ bool LLVolumeFace::cacheOptimize()
 	{
 		new_idx.resize(mNumVertices, -1);
 	}
-	catch (std::bad_alloc)
+	catch (std::bad_alloc&)
 	{
 		ll_aligned_free<64>(pos);
 		ll_aligned_free_16(wght);
@@ -6968,11 +6976,16 @@ void CalculateTangentArray(U32 vertexCount, const LLVector4a *vertex, const LLVe
 {
     //LLVector4a *tan1 = new LLVector4a[vertexCount * 2];
 	LLVector4a* tan1 = (LLVector4a*) ll_aligned_malloc_16(vertexCount*2*sizeof(LLVector4a));
+	// new(tan1) LLVector4a;
 
     LLVector4a* tan2 = tan1 + vertexCount;
 
-	memset(tan1, 0, vertexCount*2*sizeof(LLVector4a));
-        
+    U32 count = vertexCount * 2;
+    for (U32 i = 0; i < count; i++)
+    {
+        tan1[i].clear();
+    }
+
     for (U32 a = 0; a < triangleCount; a++)
     {
         U32 i1 = *index_array++;
diff --git a/indra/llmessage/llcorehttputil.cpp b/indra/llmessage/llcorehttputil.cpp
index 24387fbffd7bf869175b098557e94594eaac696b..0eae6d98263a30f27e51febc085c8ae4210759f0 100644
--- a/indra/llmessage/llcorehttputil.cpp
+++ b/indra/llmessage/llcorehttputil.cpp
@@ -597,7 +597,7 @@ LLSD HttpCoroJSONHandler::handleSuccess(LLCore::HttpResponse * response, LLCore:
     {
         bas >> jsonRoot;
     }
-    catch (std::runtime_error e)
+    catch (std::runtime_error& e)
     {   // deserialization failed.  Record the reason and pass back an empty map for markup.
         status = LLCore::HttpStatus(499, std::string(e.what()));
         return result;
@@ -625,7 +625,7 @@ LLSD HttpCoroJSONHandler::parseBody(LLCore::HttpResponse *response, bool &succes
     {
         bas >> jsonRoot;
     }
-    catch (std::runtime_error e)
+    catch (std::runtime_error&)
     {   
         success = false;
         return LLSD();
diff --git a/indra/llmessage/llhttpnode.cpp b/indra/llmessage/llhttpnode.cpp
index 04b34a296c13c4961498a4f58f6dccdf014689f2..6fd17c91549b59adce034624f8b9f4f25fb15c70 100644
--- a/indra/llmessage/llhttpnode.cpp
+++ b/indra/llmessage/llhttpnode.cpp
@@ -125,7 +125,7 @@ void LLHTTPNode::get(LLHTTPNode::ResponsePtr response, const LLSD& context) cons
 	{
 		response->result(simpleGet());
 	}
-	catch (NotImplemented)
+	catch (NotImplemented&)
 	{
 		response->methodNotAllowed();
 	}
@@ -138,7 +138,7 @@ void LLHTTPNode::put(LLHTTPNode::ResponsePtr response, const LLSD& context, cons
 	{
 		response->result(simplePut(input));
 	}
-	catch (NotImplemented)
+	catch (NotImplemented&)
 	{
 		response->methodNotAllowed();
 	}
@@ -151,7 +151,7 @@ void LLHTTPNode::post(LLHTTPNode::ResponsePtr response, const LLSD& context, con
 	{
 		response->result(simplePost(input));
 	}
-	catch (NotImplemented)
+	catch (NotImplemented&)
 	{
 		response->methodNotAllowed();
 	}
@@ -164,7 +164,7 @@ void LLHTTPNode::del(LLHTTPNode::ResponsePtr response, const LLSD& context) cons
     {
 	response->result(simpleDel(context));
     }
-    catch (NotImplemented)
+    catch (NotImplemented&)
     {
 	response->methodNotAllowed();
     }
diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index c01c15391de812273bea8f96c7ebcd03f19dbaa1..4c56b8eace2da1c8367fb92565f19ecbd3403e2c 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -50,6 +50,10 @@
 #include "llglheaders.h"
 #include "llglslshader.h"
 
+#if LL_WINDOWS
+#include "lldxhardware.h"
+#endif
+
 #ifdef _DEBUG
 //#define GL_STATE_VERIFY
 #endif
@@ -395,6 +399,8 @@ PFNGLGETACTIVEATTRIBARBPROC glGetActiveAttribARB = NULL;
 PFNGLGETATTRIBLOCATIONARBPROC glGetAttribLocationARB = NULL;
 
 #if LL_WINDOWS
+PFNWGLGETGPUIDSAMDPROC				wglGetGPUIDsAMD = NULL;
+PFNWGLGETGPUINFOAMDPROC				wglGetGPUInfoAMD = NULL;
 PFNWGLSWAPINTERVALEXTPROC			wglSwapIntervalEXT = NULL;
 #endif
 
@@ -414,6 +420,7 @@ LLGLManager::LLGLManager() :
 
 	mHasMultitexture(FALSE),
 	mHasATIMemInfo(FALSE),
+	mHasAMDAssociations(FALSE),
 	mHasNVXMemInfo(FALSE),
 	mNumTextureUnits(1),
 	mHasMipMapGeneration(FALSE),
@@ -498,7 +505,16 @@ void LLGLManager::initWGL()
 	{
 		LL_WARNS("RenderInit") << "No ARB create context extensions" << LL_ENDL;
 	}
-	
+
+	// For retreiving information per AMD adapter, 
+	// because we can't trust curently selected/default one when there are multiple
+	mHasAMDAssociations = ExtensionExists("WGL_AMD_gpu_association", gGLHExts.mSysExts);
+	if (mHasAMDAssociations)
+	{
+		GLH_EXT_NAME(wglGetGPUIDsAMD) = (PFNWGLGETGPUIDSAMDPROC)GLH_EXT_GET_PROC_ADDRESS("wglGetGPUIDsAMD");
+		GLH_EXT_NAME(wglGetGPUInfoAMD) = (PFNWGLGETGPUINFOAMDPROC)GLH_EXT_GET_PROC_ADDRESS("wglGetGPUInfoAMD");
+	}
+
 	if (ExtensionExists("WGL_EXT_swap_control", gGLHExts.mSysExts))
 	{
         GLH_EXT_NAME(wglSwapIntervalEXT) = (PFNWGLSWAPINTERVALEXTPROC)GLH_EXT_GET_PROC_ADDRESS("wglSwapIntervalEXT");
@@ -684,23 +700,78 @@ bool LLGLManager::initGL()
 	stop_glerror();
 
 	S32 old_vram = mVRAM;
+	mVRAM = 0;
 
-	if (mHasATIMemInfo)
+#if LL_WINDOWS
+	if (mHasAMDAssociations)
+	{
+		GLuint gl_gpus_count = wglGetGPUIDsAMD(0, 0);
+		if (gl_gpus_count > 0)
+		{
+			GLuint* ids = new GLuint[gl_gpus_count];
+			wglGetGPUIDsAMD(gl_gpus_count, ids);
+
+			GLuint mem_mb = 0;
+			for (U32 i = 0; i < gl_gpus_count; i++)
+			{
+				wglGetGPUInfoAMD(ids[i],
+					WGL_GPU_RAM_AMD,
+					GL_UNSIGNED_INT,
+					sizeof(GLuint),
+					&mem_mb);
+				if (mVRAM < mem_mb)
+				{
+					// basically pick the best AMD and trust driver/OS to know to switch
+					mVRAM = mem_mb;
+				}
+			}
+		}
+		if (mVRAM != 0)
+		{
+			LL_WARNS("RenderInit") << "VRAM Detected (AMDAssociations):" << mVRAM << LL_ENDL;
+		}
+	}
+#endif
+
+	if (mHasATIMemInfo && mVRAM == 0)
 	{ //ask the gl how much vram is free at startup and attempt to use no more than half of that
 		S32 meminfo[4];
 		glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, meminfo);
 
-		mVRAM = meminfo[0]/1024;
+		mVRAM = meminfo[0] / 1024;
+		LL_WARNS("RenderInit") << "VRAM Detected (ATIMemInfo):" << mVRAM << LL_ENDL;
 	}
-	else if (mHasNVXMemInfo)
+
+	if (mHasNVXMemInfo && mVRAM == 0)
 	{
 		S32 dedicated_memory;
 		glGetIntegerv(GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX, &dedicated_memory);
 		mVRAM = dedicated_memory/1024;
+		LL_WARNS("RenderInit") << "VRAM Detected (NVXMemInfo):" << mVRAM << LL_ENDL;
 	}
 
+#if LL_WINDOWS
 	if (mVRAM < 256)
-	{ //something likely went wrong using the above extensions, fall back to old method
+	{
+		// Something likely went wrong using the above extensions
+		// try WMI first and fall back to old method (from dxdiag) if all else fails
+		// Function will check all GPUs WMI knows of and will pick up the one with most
+		// memory. We need to check all GPUs because system can switch active GPU to
+		// weaker one, to preserve power when not under load.
+		S32 mem = LLDXHardware::getMBVideoMemoryViaWMI();
+		if (mem != 0)
+		{
+			mVRAM = mem;
+			LL_WARNS("RenderInit") << "VRAM Detected (WMI):" << mVRAM<< LL_ENDL;
+		}
+	}
+#endif
+
+	if (mVRAM < 256 && old_vram > 0)
+	{
+		// fall back to old method
+		// Note: on Windows value will be from LLDXHardware.
+		// Either received via dxdiag or via WMI by id from dxdiag.
 		mVRAM = old_vram;
 	}
 
@@ -962,7 +1033,7 @@ void LLGLManager::initExtensions()
 	mHasTextureRectangle = FALSE;
 #else // LL_MESA_HEADLESS //important, gGLHExts.mSysExts is uninitialized until after glh_init_extensions is called
 	mHasMultitexture = glh_init_extensions("GL_ARB_multitexture");
-	mHasATIMemInfo = ExtensionExists("GL_ATI_meminfo", gGLHExts.mSysExts);
+	mHasATIMemInfo = ExtensionExists("GL_ATI_meminfo", gGLHExts.mSysExts); //Basic AMD method, also see mHasAMDAssociations
 	mHasNVXMemInfo = ExtensionExists("GL_NVX_gpu_memory_info", gGLHExts.mSysExts);
 	mHasSeparateSpecularColor = glh_init_extensions("GL_EXT_separate_specular_color");
 	mHasAnisotropic = glh_init_extensions("GL_EXT_texture_filter_anisotropic");
diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h
index a7faea7d3315396f5e875e192fa0364f7ae99b90..91ef4e9102062f02962d2c10530cb3765d5a0ab7 100644
--- a/indra/llrender/llgl.h
+++ b/indra/llrender/llgl.h
@@ -78,6 +78,7 @@ class LLGLManager
 	// Extensions used by everyone
 	BOOL mHasMultitexture;
 	BOOL mHasATIMemInfo;
+	BOOL mHasAMDAssociations;
 	BOOL mHasNVXMemInfo;
 	S32	 mNumTextureUnits;
 	BOOL mHasMipMapGeneration;
diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h
index 722dd9050bc1819fb31c72382226805e04f5593b..36fbb381bb13425096a5713b1e692298f96d6879 100644
--- a/indra/llrender/llglheaders.h
+++ b/indra/llrender/llglheaders.h
@@ -618,6 +618,8 @@ extern PFNGLVARIANTARRAYOBJECTATIPROC		glVariantObjectArrayATI;
 extern PFNGLGETVARIANTARRAYOBJECTFVATIPROC	glGetVariantArrayObjectfvATI;
 extern PFNGLGETVARIANTARRAYOBJECTIVATIPROC	glGetVariantArrayObjectivATI;
 
+extern PFNWGLGETGPUIDSAMDPROC				wglGetGPUIDsAMD;
+extern PFNWGLGETGPUINFOAMDPROC				wglGetGPUInfoAMD;
 extern PFNWGLSWAPINTERVALEXTPROC			wglSwapIntervalEXT;
 
 // GL_ARB_occlusion_query
diff --git a/indra/llui/tests/llurlentry_test.cpp b/indra/llui/tests/llurlentry_test.cpp
index 119cbebc8146f693a69fcacef545605a28a9a1ff..3c34fd269eb7ef418491e14d44a9c4d7305f7609 100644
--- a/indra/llui/tests/llurlentry_test.cpp
+++ b/indra/llui/tests/llurlentry_test.cpp
@@ -36,6 +36,11 @@
 
 #include <boost/regex.hpp>
 
+#if LL_WINDOWS
+// because something pulls in window and lldxdiag dependencies which in turn need wbemuuid.lib
+    #pragma comment(lib, "wbemuuid.lib")
+#endif
+
 
 // namespace LLExperienceCache
 // {
diff --git a/indra/llwindow/lldxhardware.cpp b/indra/llwindow/lldxhardware.cpp
index 9397b831f724f62b7a988a8890af648476ea1e53..12a6baa3e694d57c41075d1588970768322dbbe7 100644
--- a/indra/llwindow/lldxhardware.cpp
+++ b/indra/llwindow/lldxhardware.cpp
@@ -61,7 +61,7 @@ typedef BOOL ( WINAPI* PfnCoSetProxyBlanket )( IUnknown* pProxy, DWORD dwAuthnSv
                                                OLECHAR* pServerPrincName, DWORD dwAuthnLevel, DWORD dwImpLevel,
                                                RPC_AUTH_IDENTITY_HANDLE pAuthInfo, DWORD dwCapabilities );
 
-HRESULT GetVideoMemoryViaWMI( WCHAR* strInputDeviceID, DWORD* pdwAdapterRam )
+HRESULT GetVideoMemoryViaWMI(WCHAR* strInputDeviceID, DWORD* pdwAdapterRam)
 {
     HRESULT hr;
     bool bGotMemory = false;
@@ -149,21 +149,26 @@ HRESULT GetVideoMemoryViaWMI( WCHAR* strInputDeviceID, DWORD* pdwAdapterRam )
                         if ( !pVideoControllers[iController] )
                             continue;
 
-                        pPropName = SysAllocString( L"PNPDeviceID" );
-                        hr = pVideoControllers[iController]->Get( pPropName, 0L, &var, nullptr, nullptr );
+                        // if strInputDeviceID is set find this specific device and return memory or specific device
+                        // if strInputDeviceID is not set return the best device
+                        if (strInputDeviceID)
+                        {
+                            pPropName = SysAllocString( L"PNPDeviceID" );
+                            hr = pVideoControllers[iController]->Get( pPropName, 0L, &var, nullptr, nullptr );
 #ifdef PRINTF_DEBUGGING
-                        if( FAILED( hr ) )
-                            wprintf( L"WMI: pVideoControllers[iController]->Get PNPDeviceID failed: 0x%0.8x\n", hr );
+                            if( FAILED( hr ) )
+                                wprintf( L"WMI: pVideoControllers[iController]->Get PNPDeviceID failed: 0x%0.8x\n", hr );
 #endif
-                        if( SUCCEEDED( hr ) )
-                        {
-                            if( wcsstr( var.bstrVal, strInputDeviceID ) != 0 )
-                                bFound = true;
+                            if( SUCCEEDED( hr ) && strInputDeviceID)
+                            {
+                                if( wcsstr( var.bstrVal, strInputDeviceID ) != 0 )
+                                    bFound = true;
+                            }
+                            VariantClear( &var );
+                            if( pPropName ) SysFreeString( pPropName );
                         }
-                        VariantClear( &var );
-                        if( pPropName ) SysFreeString( pPropName );
 
-                        if( bFound )
+                        if( bFound || !strInputDeviceID )
                         {
                             pPropName = SysAllocString( L"AdapterRAM" );
                             hr = pVideoControllers[iController]->Get( pPropName, 0L, &var, nullptr, nullptr );
@@ -175,13 +180,18 @@ HRESULT GetVideoMemoryViaWMI( WCHAR* strInputDeviceID, DWORD* pdwAdapterRam )
                             if( SUCCEEDED( hr ) )
                             {
                                 bGotMemory = true;
-                                *pdwAdapterRam = var.ulVal;
+                                *pdwAdapterRam = llmax(var.ulVal, *pdwAdapterRam);
                             }
                             VariantClear( &var );
                             if( pPropName ) SysFreeString( pPropName );
-                            break;
                         }
+
                         SAFE_RELEASE( pVideoControllers[iController] );
+
+                        if (bFound)
+                        {
+                            break;
+                        }
                     }
                 }
             }
@@ -207,6 +217,17 @@ HRESULT GetVideoMemoryViaWMI( WCHAR* strInputDeviceID, DWORD* pdwAdapterRam )
         return E_FAIL;
 }
 
+//static
+S32 LLDXHardware::getMBVideoMemoryViaWMI()
+{
+	DWORD vram = 0;
+	if (SUCCEEDED(GetVideoMemoryViaWMI(NULL, &vram)))
+	{
+		return vram / (1024 * 1024);;
+	}
+	return 0;
+}
+
 //Getting the version of graphics controller driver via WMI
 std::string LLDXHardware::getDriverVersionWMI()
 {
@@ -615,6 +636,8 @@ BOOL LLDXHardware::getInfo(BOOL vram_only)
 	IDxDiagContainer *driver_containerp = NULL;
 	DWORD dw_device_count;
 
+	mVRAM = 0;
+
     // CoCreate a IDxDiagProvider*
 	LL_DEBUGS("AppInit") << "CoCreateInstance IID_IDxDiagProvider" << LL_ENDL;
     hr = CoCreateInstance(CLSID_DxDiagProvider,
@@ -677,6 +700,8 @@ BOOL LLDXHardware::getInfo(BOOL vram_only)
         }
 
 		// Get device 0
+		// By default 0 device is the primary one, howhever in case of various hybrid graphics
+		// like itegrated AMD and PCI AMD GPUs system might switch.
 		LL_DEBUGS("AppInit") << "devices_containerp->GetChildContainer" << LL_ENDL;
 		hr = devices_containerp->GetChildContainer(L"0", &device_containerp);
 		if(FAILED(hr) || !device_containerp)
@@ -689,12 +714,27 @@ BOOL LLDXHardware::getInfo(BOOL vram_only)
 		WCHAR deviceID[512];
 
 		get_wstring(device_containerp, L"szDeviceID", deviceID, 512);
-		
+		// Example: searches id like 1F06 in pnp string (aka VEN_10DE&DEV_1F06)
+		// doesn't seem to work on some systems since format is unrecognizable
+		// but in such case keyDeviceID works
 		if (SUCCEEDED(GetVideoMemoryViaWMI(deviceID, &vram))) 
 		{
 			mVRAM = vram/(1024*1024);
 		}
 		else
+		{
+			get_wstring(device_containerp, L"szKeyDeviceID", deviceID, 512);
+			LL_WARNS() << "szDeviceID" << deviceID << LL_ENDL;
+			// '+9' to avoid ENUM\\PCI\\ prefix
+			// Returns string like Enum\\PCI\\VEN_10DE&DEV_1F06&SUBSYS...
+			// and since GetVideoMemoryViaWMI searches by PNPDeviceID it is sufficient
+			if (SUCCEEDED(GetVideoMemoryViaWMI(deviceID + 9, &vram)))
+			{
+				mVRAM = vram / (1024 * 1024);
+			}
+		}
+		
+		if (mVRAM == 0)
 		{ // Get the English VRAM string
 		  std::string ram_str = get_string(device_containerp, L"szDisplayMemoryEnglish");
 
diff --git a/indra/llwindow/lldxhardware.h b/indra/llwindow/lldxhardware.h
index cf33db8b3726231804b4a95faf33d726e7e0b167..1cb687e3b6d5794f71c13d088eb336649688b92b 100644
--- a/indra/llwindow/lldxhardware.h
+++ b/indra/llwindow/lldxhardware.h
@@ -94,6 +94,10 @@ class LLDXHardware
 
 	LLSD getDisplayInfo();
 
+	// Will get memory of best GPU in MB, return memory on sucsess, 0 on failure
+	// Note: WMI is not accurate in some cases
+	static S32 getMBVideoMemoryViaWMI();
+
 	// Find a particular device that matches the following specs.
 	// Empty strings indicate that you don't care.
 	// You can separate multiple devices with '|' chars to indicate you want
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index 3c69aa98c43439b1435a0b539e63e89ec5981e5a..0b3936f8a5c12b805955824c31aa183d17513a14 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -741,17 +741,27 @@ void LLWindowWin32::restore()
 	SetFocus(mWindowHandle);
 }
 
+// See SL-12170
+// According to callstack "c0000005 Access violation" happened inside __try block,
+// deep in DestroyWindow and crashed viewer, which shouldn't be possible.
+// I tried manually causing this exception and it was caught without issues, so
+// I'm turning off optimizations for this part to be sure code executes as intended
+// (it is a straw, but I have no idea why else __try can get overruled)
+#pragma optimize("", off)
 bool destroy_window_handler(HWND &hWnd)
 {
+    bool res;
     __try
     {
-        return DestroyWindow(hWnd);
+        res = DestroyWindow(hWnd);
     }
     __except (EXCEPTION_EXECUTE_HANDLER)
     {
-        return false;
+        res = false;
     }
+    return res;
 }
+#pragma optimize("", on)
 
 // close() destroys all OS-specific code associated with a window.
 // Usually called from LLWindowManager::destroyWindow()
diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt
index 4c77920fd2c5a9321491ced9a71b2ca654bf3798..a4c853ea2ea69dbd548168a6823f26d772f27f2c 100644
--- a/indra/newview/VIEWER_VERSION.txt
+++ b/indra/newview/VIEWER_VERSION.txt
@@ -1 +1 @@
-6.4.1
+6.4.2
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index c8d2524e0e4414beb48ae79667af990786018d1a..f6d6f7c8972fde96566e467b044ee61db72c13e4 100644
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -2036,6 +2036,14 @@ U8 LLAgent::getRenderState()
 //-----------------------------------------------------------------------------
 void LLAgent::endAnimationUpdateUI()
 {
+	if (LLApp::isExiting()
+		|| !gViewerWindow
+		|| !gMenuBarView
+		|| !gToolBarView
+		|| !gStatusBar)
+	{
+		return;
+	}
 	if (gAgentCamera.getCameraMode() == gAgentCamera.getLastCameraMode())
 	{
 		// We're already done endAnimationUpdateUI for this transition.
diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp
index 8edb1a5f0b4d57eadb4a9afe5814045a715a5165..85b7d7b06f3594e750cdb6e73303ac2c57a988a2 100644
--- a/indra/newview/llagentcamera.cpp
+++ b/indra/newview/llagentcamera.cpp
@@ -282,6 +282,11 @@ LLAgentCamera::~LLAgentCamera()
 //-----------------------------------------------------------------------------
 void LLAgentCamera::resetView(BOOL reset_camera, BOOL change_camera)
 {
+	if (gDisconnected)
+	{
+		return;
+	}
+
 	if (gAgent.getAutoPilot())
 	{
 		gAgent.stopAutoPilot(TRUE);
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index cbb47d71f7c2de41b9ac811de7cb6564d57acf42..ff921dcfdbbbdfab54b5d26cee9a762529ba0577 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -62,7 +62,9 @@
 #include "llallocator.h"
 #include "llcalc.h"
 #include "llconversationlog.h"
+#if LL_WINDOWS
 #include "lldxhardware.h"
+#endif
 #include "lltexturestats.h"
 #include "lltrace.h"
 #include "lltracethreadrecorder.h"
@@ -1134,7 +1136,7 @@ bool LLAppViewer::init()
 	try {
 		initializeSecHandler();
 	}
-	catch (LLProtectedDataException ex)
+	catch (LLProtectedDataException&)
 	{
 	  LLNotificationsUtil::add("CorruptedProtectedDataStore");
 	}
@@ -1348,7 +1350,7 @@ bool LLAppViewer::frame()
 		{
 			LOG_UNHANDLED_EXCEPTION("");
 		}
-		catch (std::bad_alloc)
+		catch (std::bad_alloc&)
 		{
 			LLMemory::logMemoryInfo(TRUE);
 			LLFloaterMemLeak* mem_leak_instance = LLFloaterReg::findTypedInstance<LLFloaterMemLeak>("mem_leaking");
@@ -1717,6 +1719,11 @@ bool LLAppViewer::cleanup()
 	disconnectViewer();
 
 	LL_INFOS() << "Viewer disconnected" << LL_ENDL;
+	
+	if (gKeyboard)
+	{
+		gKeyboard->resetKeys();
+	}
 
 	display_cleanup();
 
@@ -3995,7 +4002,10 @@ static LLNotificationFunctorRegistration finish_quit_reg("ConfirmQuit", finish_q
 
 void LLAppViewer::userQuit()
 {
-	if (gDisconnected || gViewerWindow->getProgressView()->getVisible())
+	if (gDisconnected
+		|| !gViewerWindow
+		|| !gViewerWindow->getProgressView()
+		|| gViewerWindow->getProgressView()->getVisible())
 	{
 		requestQuit();
 	}
diff --git a/indra/newview/llenvironment.cpp b/indra/newview/llenvironment.cpp
index 0e1c4f943468441151193def0616499d121d1831..342ee3ccf51ed19c6e230bf305e1f0f3af47cf72 100644
--- a/indra/newview/llenvironment.cpp
+++ b/indra/newview/llenvironment.cpp
@@ -2800,7 +2800,7 @@ void LLEnvironment::loadSkyWaterFromSettings(const LLSD &env_data, bool &valid,
     }
     else if (env_data.has("sky_llsd"))
     {
-        LLSettingsSky::ptr_t sky = std::make_shared<LLSettingsVOSky>(env_data["sky_llsd"]);
+        LLSettingsSky::ptr_t sky = LLSettingsVOSky::buildSky(env_data["sky_llsd"]);
         setEnvironment(ENV_LOCAL, sky);
         valid = true;
     }
@@ -2814,7 +2814,7 @@ void LLEnvironment::loadSkyWaterFromSettings(const LLSD &env_data, bool &valid,
     }
     else if (env_data.has("water_llsd"))
     {
-        LLSettingsWater::ptr_t sky = std::make_shared<LLSettingsVOWater>(env_data["water_llsd"]);
+        LLSettingsWater::ptr_t sky = LLSettingsVOWater::buildWater(env_data["water_llsd"]);
         setEnvironment(ENV_LOCAL, sky);
         valid = true;
     }
@@ -2899,8 +2899,8 @@ bool LLEnvironment::loadFromSettings()
     {
         S32 length = env_data["day_length"].asInteger();
         S32 offset = env_data["day_offset"].asInteger();
-        LLSettingsDay::ptr_t day = std::make_shared<LLSettingsVODay>(env_data["day_llsd"]);
-        setEnvironment(ENV_LOCAL, day, LLSettingsDay::Seconds(length), LLSettingsDay::Seconds(offset));
+        LLSettingsDay::ptr_t pday = LLSettingsVODay::buildDay(env_data["day_llsd"]);
+        setEnvironment(ENV_LOCAL, pday, LLSettingsDay::Seconds(length), LLSettingsDay::Seconds(offset));
         valid = true;
     }
 
diff --git a/indra/newview/llfloaterevent.cpp b/indra/newview/llfloaterevent.cpp
index 3e303e0932aa7b6431eb2eec5cee631c313775b0..a6640cc073e672c14845b9ffa1687e083dc30324 100644
--- a/indra/newview/llfloaterevent.cpp
+++ b/indra/newview/llfloaterevent.cpp
@@ -110,7 +110,7 @@ void LLFloaterEvent::setEventID(const U32 event_id)
         // get the search URL and expand all of the substitutions                                                       
         // (also adds things like [LANGUAGE], [VERSION], [OS], etc.)                                                    
 		std::ostringstream url;
-		url <<  gSavedSettings.getString("EventURL") << event_id << "/" << std::endl;
+		url <<  gSavedSettings.getString("EventURL") << event_id << std::endl;
 		// and load the URL in the web view                                                                             
         mBrowser->navigateTo(url.str());
 		
diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp
index c3375a377967215d434c1d48d801f5215a2a524b..6da7bbe2632e667af8d50e036c4fe2c1a5a9859b 100644
--- a/indra/newview/llimprocessing.cpp
+++ b/indra/newview/llimprocessing.cpp
@@ -1579,7 +1579,7 @@ void LLIMProcessing::requestOfflineMessagesCoro(std::string url)
 
     std::vector<U8> data;
     S32 binary_bucket_size = 0;
-    LLHost sender = gAgent.getRegion()->getHost();
+    LLHost sender = gAgent.getRegionHost();
 
     LLSD::array_iterator i = messages.beginArray();
     LLSD::array_iterator iEnd = messages.endArray();
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index 4b051f3e44e3726a1f891674236ceaf672246a26..657c65c68d8d399ac47e60e17f592f8a36251b19 100644
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -1809,7 +1809,7 @@ void LLItemBridge::restoreToWorld()
 
 		msg->nextBlockFast(_PREHASH_InventoryData);
 		itemp->packMessage(msg);
-		msg->sendReliable(gAgent.getRegion()->getHost());
+		msg->sendReliable(gAgent.getRegionHost());
 
 		//remove local inventory copy, sim will deal with permissions and removing the item
 		//from the actual inventory if its a no-copy etc
diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp
index 8a69acb8dcaeed94c5fe7e31b43028a73935890a..873531ef2215a255046463c1345aba1b8ebbeacf 100644
--- a/indra/newview/lllogininstance.cpp
+++ b/indra/newview/lllogininstance.cpp
@@ -62,7 +62,7 @@
 #include <boost/scoped_ptr.hpp>
 #include <sstream>
 
-const S32 LOGIN_MAX_RETRIES = 3;
+const S32 LOGIN_MAX_RETRIES = 0; // Viewer should not autmatically retry login
 const F32 LOGIN_SRV_TIMEOUT_MIN = 10;
 const F32 LOGIN_SRV_TIMEOUT_MAX = 120;
 const F32 LOGIN_DNS_TIMEOUT_FACTOR = 0.9; // make DNS wait shorter then retry time
diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp
index 1d76dd7928e98691b4669f1c798d96b8415de28f..1fce158eb40af7b34a2dcf345afdcc675f715358 100644
--- a/indra/newview/llmeshrepository.cpp
+++ b/indra/newview/llmeshrepository.cpp
@@ -1888,7 +1888,7 @@ EMeshProcessingResult LLMeshRepoThread::lodReceived(const LLVolumeParams& mesh_p
 		std::string mesh_string((char*)data, data_size);
 		stream.str(mesh_string);
 	}
-	catch (std::bad_alloc)
+	catch (std::bad_alloc&)
 	{
 		// out of memory, we won't be able to process this mesh
 		return MESH_OUT_OF_MEMORY;
diff --git a/indra/newview/llrecentpeople.h b/indra/newview/llrecentpeople.h
index 1b4295ddad9509bec5e03f0e332981db889bd8ad..18b669ff4fc81be07d5f47d1a1c78dee5aeae1e5 100644
--- a/indra/newview/llrecentpeople.h
+++ b/indra/newview/llrecentpeople.h
@@ -53,7 +53,7 @@ class LLRecentPeople: public LLSingleton<LLRecentPeople>, public LLOldEvents::LL
 	LLSINGLETON_EMPTY_CTOR(LLRecentPeople);
 	LOG_CLASS(LLRecentPeople);
 public:
-	typedef std::map <LLUUID, F32> id_to_time_map_t;
+	typedef std::map <LLUUID, F64> id_to_time_map_t;
 	typedef boost::signals2::signal<void ()> signal_t;
 	
 	/**
diff --git a/indra/newview/llsecapi.cpp b/indra/newview/llsecapi.cpp
index 72d7cf1e4522eebcf56bfb455976d79dd7abc000..10e510b8428a777587476c42062ef26004bb58e8 100644
--- a/indra/newview/llsecapi.cpp
+++ b/indra/newview/llsecapi.cpp
@@ -64,7 +64,7 @@ void initializeSecHandler()
 		{
 			handler->init();
 		}
-		catch (LLProtectedDataException e)
+		catch (LLProtectedDataException& e)
 		{
 			exception_msg = e.what();
 		}
diff --git a/indra/newview/llsettingsvo.h b/indra/newview/llsettingsvo.h
index 1f29013ecfd469efe9a6309a74a924c0328b7924..65136ad2f5ede965f256d945f2a3a66feeff011f 100644
--- a/indra/newview/llsettingsvo.h
+++ b/indra/newview/llsettingsvo.h
@@ -158,6 +158,9 @@ class LLSettingsVODay : public LLSettingsDay
 public:
     typedef std::function<void(LLSettingsDay::ptr_t day)>  asset_built_fn;
 
+    // Todo: find a way to make this cnstructor private
+    // It shouldn't be used outside shared_prt and LLSettingsVODay
+    // outside of settings only use buildDay(settings)
     LLSettingsVODay(const LLSD &data);
 
     static ptr_t    buildDay(LLSD settings);
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index a1d1e85492b167f92f1a4b2345e73935af26fd59..7673bae725aaace68d2b2a8f52d0f05d2f5fe89a 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -1879,8 +1879,7 @@ bool idle_startup()
 
 		display_startup();
 
-        // Load stored local environment if needed. Only should be done once at least
-        // initial region data got loaded to avoid race condition with region's environment
+        // Load stored local environment if needed.
         LLEnvironment::instance().loadFromSettings();
 
         // *TODO : Uncomment that line once the whole grid migrated to SLM and suppress it from LLAgent::handleTeleportFinished() (llagent.cpp)
diff --git a/indra/newview/llviewerkeyboard.cpp b/indra/newview/llviewerkeyboard.cpp
index e930eb20d3cf185affae53bb182d622dc0a0b2d3..a14041717f26a52528cb46539751cd7f06da966f 100644
--- a/indra/newview/llviewerkeyboard.cpp
+++ b/indra/newview/llviewerkeyboard.cpp
@@ -986,6 +986,11 @@ EKeyboardMode LLViewerKeyboard::getMode()
 // Called from scanKeyboard.
 void LLViewerKeyboard::scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level)
 {
+	if (LLApp::isExiting())
+	{
+		return;
+	}
+
 	S32 mode = getMode();
 	// Consider keyboard scanning as NOT mouse event. JC
 	MASK mask = gKeyboard->currentMask(FALSE);
diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp
index 06524847d1780783df9272812a8d2a33f24b2148..561319ca5d2b4eb61e555f3b4e9bbbc4271d7c17 100644
--- a/indra/newview/llviewertexturelist.cpp
+++ b/indra/newview/llviewertexturelist.cpp
@@ -1385,8 +1385,6 @@ S32Megabytes LLViewerTextureList::getMaxVideoRamSetting(bool get_recommended, fl
 		{
 			max_texmem = (S32Megabytes)128;
 		}
-
-		LL_WARNS() << "VRAM amount not detected, defaulting to " << max_texmem << " MB" << LL_ENDL;
 	}
 
 	S32Megabytes system_ram = gSysMemory.getPhysicalMemoryKB(); // In MB
@@ -1428,6 +1426,11 @@ void LLViewerTextureList::updateMaxResidentTexMem(S32Megabytes mem)
 		return; //listener will re-enter this function
 	}
 
+	if (gGLManager.mVRAM == 0)
+	{
+		LL_WARNS() << "VRAM amount not detected, defaulting to " << mem << " MB" << LL_ENDL;
+	}
+
 	// TODO: set available resident texture mem based on use by other subsystems
 	// currently max(12MB, VRAM/4) assumed...
 	
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index ae1eec81e0cbfa2c4a08e23bef90735835811b4b..f64dfcf0d462f1c98e29a60cbad6cb1415e3c776 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -2008,6 +2008,11 @@ void LLViewerWindow::initBase()
 	LLPanel* panel_holder = main_view->getChild<LLPanel>("toolbar_view_holder");
 	// Load the toolbar view from file 
 	gToolBarView = LLUICtrlFactory::getInstance()->createFromFile<LLToolBarView>("panel_toolbar_view.xml", panel_holder, LLDefaultChildRegistry::instance());
+	if (!gToolBarView)
+	{
+		LL_ERRS() << "Failed to initialize viewer: Viewer couldn't process file panel_toolbar_view.xml, "
+				<< "if this problem happens again, please validate your installation." << LL_ENDL;
+	}
 	gToolBarView->setShape(panel_holder->getLocalRect());
 	// Hide the toolbars for the moment: we'll make them visible after logging in world (see LLViewerWindow::initWorldUI())
 	gToolBarView->setVisible(FALSE);
@@ -2893,7 +2898,8 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask)
 	// If "Pressing letter keys starts local chat" option is selected, we are not in mouselook, 
 	// no view has keyboard focus, this is a printable character key (and no modifier key is 
 	// pressed except shift), then give focus to nearby chat (STORM-560)
-	if ( gSavedSettings.getS32("LetterKeysFocusChatBar") && !gAgentCamera.cameraMouselook() && 
+	if ( LLStartUp::getStartupState() >= STATE_STARTED && 
+		gSavedSettings.getS32("LetterKeysFocusChatBar") && !gAgentCamera.cameraMouselook() && 
 		!keyboard_focus && key < 0x80 && (mask == MASK_NONE || mask == MASK_SHIFT) )
 	{
 		// Initialize nearby chat if it's missing
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 7579eb1a907a736cddb833cbbb0f3e47e0ac34e5..eb461d3140c85203b81d41ebaffadc2108a16bbd 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -198,6 +198,8 @@ const F32 NAMETAG_VERT_OFFSET_WEIGHT = 0.17f;
 const U32 LLVOAvatar::VISUAL_COMPLEXITY_UNKNOWN = 0;
 const F64 HUD_OVERSIZED_TEXTURE_DATA_SIZE = 1024 * 1024;
 
+const F32 MAX_TEXTURE_WAIT_TIME_SEC = 60;
+
 enum ERenderName
 {
 	RENDER_NAME_NEVER,
@@ -664,6 +666,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
 	mFullyLoadedInitialized(FALSE),
 	mVisualComplexity(VISUAL_COMPLEXITY_UNKNOWN),
 	mLoadedCallbacksPaused(FALSE),
+	mLoadedCallbackTextures(0),
 	mRenderUnloadedAvatar(LLCachedControl<bool>(gSavedSettings, "RenderUnloadedAvatar", false)),
 	mLastRezzedStatus(-1),
 	mIsEditingAppearance(FALSE),
@@ -884,8 +887,9 @@ BOOL LLVOAvatar::hasGray() const
 S32 LLVOAvatar::getRezzedStatus() const
 {
 	if (getIsCloud()) return 0;
-	if (isFullyTextured() && allBakedTexturesCompletelyDownloaded()) return 3;
-	if (isFullyTextured()) return 2;
+	bool textured = isFullyTextured();
+	if (textured && allBakedTexturesCompletelyDownloaded()) return 3;
+	if (textured) return 2;
 	llassert(hasGray());
 	return 1; // gray
 }
@@ -4807,6 +4811,15 @@ U32 LLVOAvatar::renderSkinned()
 		BOOL first_pass = TRUE;
 		if (!LLDrawPoolAvatar::sSkipOpaque)
 		{
+			if (isUIAvatar() && mIsDummy)
+			{
+				LLViewerJoint* hair_mesh = getViewerJoint(MESH_ID_HAIR);
+				if (hair_mesh)
+				{
+					num_indices += hair_mesh->render(mAdjustedPixelArea, first_pass, mIsDummy);
+				}
+				first_pass = FALSE;
+			}
 			if (!isSelf() || gAgent.needsRenderHead() || LLPipeline::sShadowRender)
 			{
 				if (isTextureVisible(TEX_HEAD_BAKED) || isUIAvatar())
@@ -4814,7 +4827,7 @@ U32 LLVOAvatar::renderSkinned()
 					LLViewerJoint* head_mesh = getViewerJoint(MESH_ID_HEAD);
 					if (head_mesh)
 					{
-						num_indices += head_mesh->render(mAdjustedPixelArea, TRUE, mIsDummy);
+						num_indices += head_mesh->render(mAdjustedPixelArea, first_pass, mIsDummy);
 					}
 					first_pass = FALSE;
 				}
@@ -5321,12 +5334,28 @@ void LLVOAvatar::checkTextureLoading()
 	}
 	if(mLoadedCallbacksPaused == pause)
 	{
+        if (!pause && mFirstFullyVisible && mLoadedCallbackTextures < mCallbackTextureList.size())
+        {
+            // We still need to update 'loaded' textures count to decide on 'cloud' visibility
+            // Alternatively this can be done on TextureLoaded callbacks, but is harder to properly track
+            mLoadedCallbackTextures = 0;
+            for (LLLoadedCallbackEntry::source_callback_list_t::iterator iter = mCallbackTextureList.begin();
+                iter != mCallbackTextureList.end(); ++iter)
+            {
+                LLViewerFetchedTexture* tex = gTextureList.findImage(*iter);
+                if (tex && (tex->getDiscardLevel() >= 0 || tex->isMissingAsset()))
+                {
+                    mLoadedCallbackTextures++;
+                }
+            }
+        }
 		return ; 
 	}
 	
 	if(mCallbackTextureList.empty()) //when is self or no callbacks. Note: this list for self is always empty.
 	{
 		mLoadedCallbacksPaused = pause ;
+		mLoadedCallbackTextures = 0;
 		return ; //nothing to check.
 	}
 	
@@ -5334,7 +5363,9 @@ void LLVOAvatar::checkTextureLoading()
 	{
 		return ; //have not been invisible for enough time.
 	}
-	
+
+	mLoadedCallbackTextures = pause ? mCallbackTextureList.size() : 0;
+
 	for(LLLoadedCallbackEntry::source_callback_list_t::iterator iter = mCallbackTextureList.begin();
 		iter != mCallbackTextureList.end(); ++iter)
 	{
@@ -5355,9 +5386,15 @@ void LLVOAvatar::checkTextureLoading()
 
 				tex->unpauseLoadedCallbacks(&mCallbackTextureList) ;
 				tex->addTextureStats(START_AREA); //jump start the fetching again
+
+				// technically shouldn't need to account for missing, but callback might not have happened yet
+				if (tex->getDiscardLevel() >= 0 || tex->isMissingAsset())
+				{
+					mLoadedCallbackTextures++; // consider it loaded (we have at least some data)
+				}
 			}
-		}		
-	}			
+		}
+	}
 	
 	if(!pause)
 	{
@@ -7591,14 +7628,13 @@ bool LLVOAvatar::getIsCloud() const
 			);
 }
 
-void LLVOAvatar::updateRezzedStatusTimers()
+void LLVOAvatar::updateRezzedStatusTimers(S32 rez_status)
 {
 	// State machine for rezzed status. Statuses are -1 on startup, 0
 	// = cloud, 1 = gray, 2 = downloading, 3 = full.
 	// Purpose is to collect time data for each it takes avatar to reach
 	// various loading landmarks: gray, textured (partial), textured fully.
 
-	S32 rez_status = getRezzedStatus();
 	if (rez_status != mLastRezzedStatus)
 	{
 		LL_DEBUGS("Avatar") << avString() << "rez state change: " << mLastRezzedStatus << " -> " << rez_status << LL_ENDL;
@@ -7768,8 +7804,21 @@ void LLVOAvatar::logMetricsTimerRecord(const std::string& phase_name, F32 elapse
 // returns true if the value has changed.
 BOOL LLVOAvatar::updateIsFullyLoaded()
 {
-	const bool loading = getIsCloud();
-	updateRezzedStatusTimers();
+	S32 rez_status = getRezzedStatus();
+	bool loading = getIsCloud();
+	if (mFirstFullyVisible && !mIsControlAvatar)
+	{
+        loading = ((rez_status < 2)
+                   // Wait at least 60s for unfinished textures to finish on first load,
+                   // don't wait forever, it might fail. Even if it will eventually load by
+                   // itself and update mLoadedCallbackTextures (or fail and clean the list),
+                   // avatars are more time-sensitive than textures and can't wait that long.
+                   || (mLoadedCallbackTextures < mCallbackTextureList.size() && mLastTexCallbackAddedTime.getElapsedTimeF32() < MAX_TEXTURE_WAIT_TIME_SEC)
+                   || !mPendingAttachment.empty()
+                   || (rez_status < 3 && !isFullyBaked())
+                  );
+	}
+	updateRezzedStatusTimers(rez_status);
 	updateRuthTimer(loading);
 	return processFullyLoadedChange(loading);
 }
@@ -7805,13 +7854,22 @@ void LLVOAvatar::updateRuthTimer(bool loading)
 
 BOOL LLVOAvatar::processFullyLoadedChange(bool loading)
 {
-	// we wait a little bit before giving the all clear,
-	// to let textures settle down
-	const F32 PAUSE = 1.f;
+	// We wait a little bit before giving the 'all clear', to let things to
+	// settle down (models to snap into place, textures to get first packets)
+	const F32 LOADED_DELAY = 1.f;
+	const F32 FIRST_USE_DELAY = 3.f;
+
 	if (loading)
 		mFullyLoadedTimer.reset();
-	
-	mFullyLoaded = (mFullyLoadedTimer.getElapsedTimeF32() > PAUSE);
+
+	if (mFirstFullyVisible)
+	{
+		mFullyLoaded = (mFullyLoadedTimer.getElapsedTimeF32() > FIRST_USE_DELAY);
+	}
+	else
+	{
+		mFullyLoaded = (mFullyLoadedTimer.getElapsedTimeF32() > LOADED_DELAY);
+	}
 
 	if (!mPreviousFullyLoaded && !loading && mFullyLoaded)
 	{
@@ -8101,6 +8159,7 @@ void LLVOAvatar::updateMeshTextures()
 		LLViewerTexLayerSet* layerset = getTexLayerSet(i);
 		if (use_lkg_baked_layer[i] && !isUsingLocalAppearance() )
 		{
+			// use last known good layer (no new one)
 			LLViewerFetchedTexture* baked_img = LLViewerTextureManager::getFetchedTexture(mBakedTextureDatas[i].mLastTextureID);
 			mBakedTextureDatas[i].mIsUsed = TRUE;
 
@@ -8119,6 +8178,7 @@ void LLVOAvatar::updateMeshTextures()
 		}
 		else if (!isUsingLocalAppearance() && is_layer_baked[i])
 		{
+			// use new layer
 			LLViewerFetchedTexture* baked_img =
 				LLViewerTextureManager::staticCastToFetchedTexture(
 					getImage( mBakedTextureDatas[i].mTextureIndex, 0 ), TRUE) ;
@@ -8138,10 +8198,15 @@ void LLVOAvatar::updateMeshTextures()
 					 ((i == BAKED_HEAD) || (i == BAKED_UPPER) || (i == BAKED_LOWER)) )
 				{			
 					baked_img->setLoadedCallback(onBakedTextureMasksLoaded, MORPH_MASK_REQUESTED_DISCARD, TRUE, TRUE, new LLTextureMaskData( mID ), 
-						src_callback_list, paused);	
+						src_callback_list, paused);
 				}
 				baked_img->setLoadedCallback(onBakedTextureLoaded, SWITCH_TO_BAKED_DISCARD, FALSE, FALSE, new LLUUID( mID ), 
 					src_callback_list, paused );
+				if (baked_img->getDiscardLevel() < 0 && !paused)
+				{
+					// mLoadedCallbackTextures will be updated by checkTextureLoading() below
+					mLastTexCallbackAddedTime.reset();
+				}
 
 				// this could add paused texture callbacks
 				mLoadedCallbacksPaused |= paused; 
@@ -8535,13 +8600,16 @@ void LLVOAvatar::onFirstTEMessageReceived()
 				LL_DEBUGS("Avatar") << avString() << "layer_baked, setting onInitialBakedTextureLoaded as callback" << LL_ENDL;
 				image->setLoadedCallback( onInitialBakedTextureLoaded, MAX_DISCARD_LEVEL, FALSE, FALSE, new LLUUID( mID ), 
 					src_callback_list, paused );
-
+				if (image->getDiscardLevel() < 0 && !paused)
+				{
+					mLastTexCallbackAddedTime.reset();
+				}
                                // this could add paused texture callbacks
                                mLoadedCallbacksPaused |= paused; 
 			}
 		}
 
-		mMeshTexturesDirty = TRUE;
+        mMeshTexturesDirty = TRUE;
 		gPipeline.markGLRebuild(this);
 	}
 }
@@ -9188,8 +9256,6 @@ void LLVOAvatar::onBakedTextureMasksLoaded( BOOL success, LLViewerFetchedTexture
 // static
 void LLVOAvatar::onInitialBakedTextureLoaded( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata )
 {
-
-	
 	LLUUID *avatar_idp = (LLUUID *)userdata;
 	LLVOAvatar *selfp = (LLVOAvatar *)gObjectList.findObject(*avatar_idp);
 
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index 00dccc5d1215c66a7503f61109583bb79b96c403..ca6ac5c90244a4014bb3938e1227392d9f6de790 100644
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -348,7 +348,7 @@ class LLVOAvatar :
 	BOOL			isFullyTextured() const;
 	BOOL			hasGray() const; 
 	S32				getRezzedStatus() const; // 0 = cloud, 1 = gray, 2 = textured, 3 = textured and fully downloaded.
-	void			updateRezzedStatusTimers();
+	void			updateRezzedStatusTimers(S32 status);
 
 	S32				mLastRezzedStatus;
 
@@ -629,6 +629,8 @@ class LLVOAvatar :
 
 	LLLoadedCallbackEntry::source_callback_list_t mCallbackTextureList ; 
 	BOOL mLoadedCallbacksPaused;
+	S32 mLoadedCallbackTextures; // count of 'loaded' baked textures, filled from mCallbackTextureList
+	LLFrameTimer mLastTexCallbackAddedTime;
 	std::set<LLUUID>	mTextureIDs;
 	//--------------------------------------------------------------------
 	// Local Textures
diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp
index 63ace4fe5298931dcd190779cc4673915ef77700..16b27fd1445cd3283639c6087b3d50e7d5396f2a 100644
--- a/indra/newview/llvoavatarself.cpp
+++ b/indra/newview/llvoavatarself.cpp
@@ -1250,7 +1250,7 @@ BOOL LLVOAvatarSelf::detachAttachmentIntoInventory(const LLUUID &item_id)
 		gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
 		gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
 		gMessageSystem->addUUIDFast(_PREHASH_ItemID, item_id);
-		gMessageSystem->sendReliable(gAgent.getRegion()->getHost());
+		gMessageSystem->sendReliable(gAgent.getRegionHost());
 		
 		// This object might have been selected, so let the selection manager know it's gone now
 		LLViewerObject *found_obj = gObjectList.findObject(item_id);
diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp
index 739f7bd47cb340687760bc8a5937d746d14cce30..530adb89754d943579a40e5b2d4af9ea80dda3cc 100644
--- a/indra/newview/llvoicevivox.cpp
+++ b/indra/newview/llvoicevivox.cpp
@@ -5158,6 +5158,7 @@ void LLVivoxVoiceClient::setVoiceEnabled(bool enabled)
 		{
 			// Turning voice off looses your current channel -- this makes sure the UI isn't out of sync when you re-enable it.
 			LLVoiceChannel::getCurrentVoiceChannel()->deactivate();
+			gAgent.setVoiceConnected(false);
 			status = LLVoiceClientStatusObserver::STATUS_VOICE_DISABLED;
 		}
 
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index f0ed303f66571262eac266a3a6bbbc8898c3f2d7..01438bfb9f989e34f8292d97ae3005ee123e1e46 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -8740,29 +8740,24 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget* screen_target)
 						}
 					}
 
-					const LLViewerObject *vobj = drawablep->getVObj();
-					if (vobj)
-					{
-						LLVOAvatar *av = vobj->getAvatar();
-						if (av)
-						{
-							if (av->isTooComplex() || av->isInMuteList() || dist_vec(av->getPosition(), LLViewerCamera::getInstance()->getOrigin()) > RenderFarClip)
-							{
-								continue;
-							}
-						}
-						else
-						{
-							const LLViewerObject *root_obj = drawablep->getParent() ? drawablep->getParent()->getVObj() : vobj;
-							if (root_obj && dist_vec(root_obj->getPosition(), LLViewerCamera::getInstance()->getOrigin()) > RenderFarClip)
-					{
-						continue;
-					}
-						}
-					}
+                    const LLViewerObject *vobj = drawablep->getVObj();
+                    if (vobj)
+                    {
+                        LLVOAvatar *av = vobj->getAvatar();
+                        if (av && (av->isTooComplex() || av->isInMuteList()))
+                        {
+                            continue;
+                        }
+                    }
+
+                    const LLVector3 position = drawablep->getPositionAgent();
+                    if (dist_vec(position, LLViewerCamera::getInstance()->getOrigin()) > RenderFarClip + volume->getLightRadius())
+                    {
+                        continue;
+                    }
 
 					LLVector4a center;
-					center.load3(drawablep->getPositionAgent().mV);
+					center.load3(position.mV);
 					const F32* c = center.getF32ptr();
 					F32 s = volume->getLightRadius()*1.5f;
 
diff --git a/indra/newview/skins/default/xui/en/fonts.xml b/indra/newview/skins/default/xui/en/fonts.xml
index 2d5263b78f7067538af627ce1110af0192e63686..76df0abdfd68a565d081e9ed39aec9621a2fa3ef 100644
--- a/indra/newview/skins/default/xui/en/fonts.xml
+++ b/indra/newview/skins/default/xui/en/fonts.xml
@@ -21,6 +21,7 @@
       <file>AppleGothic.dfont</file>
       <file>AppleGothic.ttf</file>
       <file>AppleSDGothicNeo-Regular.otf</file>
+      <file>AppleSDGothicNeo.ttc</file>
       <file>华文细黑.ttf</file>
       <file>PingFang.ttc</file>
       <file>STIXGeneral.otf</file>
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index e228c5bdba3929502ce21fd3f31660c9a645cbc7..873b95926b7845fa650e7caec9ac5f1961b9c571 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -461,7 +461,7 @@
              name="Events">
             <menu_item_call.on_click
              function="Advanced.ShowURL"
-             parameter="http://events.secondlife.com"/>
+             parameter="https://secondlife.com/my/community/events"/>
         </menu_item_call>
         <menu_item_check
         label="Search..."
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 61a23851ede97edc9011742ac8073caa1dce4a5b..089498dfb98959b49bb16be4e1e3990381d6be27 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -1513,7 +1513,7 @@ Go to the [SECOND_LIFE] events web page?
     <tag>confirm</tag>
     <url option="0" name="url">
 
-			http://secondlife.com/events/
+			https://secondlife.com/my/community/events
     </url>
     <usetemplate
      name="okcancelbuttons"