diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index cd8f9d2065f0bb6066964b1437874263543fcf89..584808167e193174dc09bc6c0e7109e3ea8b013c 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1276,7 +1276,6 @@ bool LLAppViewer::init()
 
     //LLSimpleton creations
     LLEnvironment::createInstance();
-    LLEnvironment::getInstance()->initSingleton();
     LLWorld::createInstance();
     LLSelectMgr::createInstance();
     LLViewerCamera::createInstance();
diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp
index 684cf55b6b2721cbe66c212e37e198fd510598a6..343aeb3201dd42233ede899937df43b005100265 100644
--- a/indra/newview/lldrawpoolbump.cpp
+++ b/indra/newview/lldrawpoolbump.cpp
@@ -41,6 +41,7 @@
 #include "lldrawable.h"
 #include "llface.h"
 #include "llsky.h"
+#include "llstartup.h"
 #include "lltextureentry.h"
 #include "llviewercamera.h"
 #include "llviewertexturelist.h"
@@ -79,11 +80,6 @@ static S32 bump_channel = -1;
 
 #define LL_BUMPLIST_MULTITHREADED 0 // TODO -- figure out why this doesn't work
 
-// static 
-void LLStandardBumpmap::init()
-{
-	LLStandardBumpmap::restoreGL();
-}
 
 // static 
 void LLStandardBumpmap::shutdown()
@@ -94,7 +90,7 @@ void LLStandardBumpmap::shutdown()
 // static 
 void LLStandardBumpmap::restoreGL()
 {
-	addstandard();
+    addstandard();
 }
 
 // static
@@ -107,6 +103,12 @@ void LLStandardBumpmap::addstandard()
 		return ;
 	}
 
+    if (LLStartUp::getStartupState() < STATE_SEED_CAP_GRANTED)
+    {
+        // Not ready, need caps for images
+        return;
+    }
+
 	// can't assert; we destroyGL and restoreGL a lot during *first* startup, which populates this list already, THEN we explicitly init the list as part of *normal* startup.  Sigh.  So clear the list every time before we (re-)add the standard bumpmaps.
 	//llassert( LLStandardBumpmap::sStandardBumpmapCount == 0 );
 	clear();
@@ -786,8 +788,6 @@ void LLBumpImageList::init()
 	llassert( mBrightnessEntries.size() == 0 );
 	llassert( mDarknessEntries.size() == 0 );
 
-	LLStandardBumpmap::init();
-
 	LLStandardBumpmap::restoreGL();
     sMainQueue = LL::WorkQueue::getInstance("mainloop");
     sTexUpdateQueue = LL::WorkQueue::getInstance("LLImageGL"); // Share work queue with tex loader.
diff --git a/indra/newview/lldrawpoolbump.h b/indra/newview/lldrawpoolbump.h
index e8a027967bcca922e44c560f2471874a1c22bed1..cf463f4458ecc48981628764271a63204d90cbbe 100644
--- a/indra/newview/lldrawpoolbump.h
+++ b/indra/newview/lldrawpoolbump.h
@@ -118,7 +118,6 @@ class LLStandardBumpmap
 	static void clear();
 	static void addstandard();
 
-	static void init();
 	static void shutdown();
 	static void restoreGL();
 	static void destroyGL();
diff --git a/indra/newview/llenvironment.cpp b/indra/newview/llenvironment.cpp
index 64d89282e22ddc16581c81380724d49c74556623..efe4ad2af2df6dae9c2bffda949d89d5b8d9e23d 100644
--- a/indra/newview/llenvironment.cpp
+++ b/indra/newview/llenvironment.cpp
@@ -874,26 +874,37 @@ void LLEnvironment::initSingleton()
 
     requestRegion();
 
-    gAgent.addParcelChangedCallback([this]() { onParcelChange(); });
+    if (!mParcelCallbackConnection.connected())
+    {
+        mParcelCallbackConnection = gAgent.addParcelChangedCallback([this]() { onParcelChange(); });
 
-    //TODO: This frequently results in one more request than we need.  It isn't breaking, but should be nicer.
-    // We need to know new env version to fix this, without it we can only do full re-request
-    // Happens: on updates, on opening LLFloaterRegionInfo, on region crossing if info floater is open
-    LLRegionInfoModel::instance().setUpdateCallback([this]() { requestRegion(); });
-    gAgent.addRegionChangedCallback([this]() { onRegionChange(); });
+        //TODO: This frequently results in one more request than we need.  It isn't breaking, but should be nicer.
+        // We need to know new env version to fix this, without it we can only do full re-request
+        // Happens: on updates, on opening LLFloaterRegionInfo, on region crossing if info floater is open
+        mRegionUpdateCallbackConnection = LLRegionInfoModel::instance().setUpdateCallback([this]() { requestRegion(); });
+        mRegionChangeCallbackConnection = gAgent.addRegionChangedCallback([this]() { onRegionChange(); });
 
-    gAgent.whenPositionChanged([this](const LLVector3 &localpos, const LLVector3d &) { onAgentPositionHasChanged(localpos); });
+        mPositionCallbackConnection = gAgent.whenPositionChanged([this](const LLVector3 &localpos, const LLVector3d &) { onAgentPositionHasChanged(localpos); });
+    }
 
     if (!gGenericDispatcher.isHandlerPresent(MESSAGE_PUSHENVIRONMENT))
     {
         gGenericDispatcher.addHandler(MESSAGE_PUSHENVIRONMENT, &environment_push_dispatch_handler);
     }
 
+    LLEventPumps::instance().obtain(PUMP_EXPERIENCE).stopListening(LISTENER_NAME);
     LLEventPumps::instance().obtain(PUMP_EXPERIENCE).listen(LISTENER_NAME, [this](LLSD message) { listenExperiencePump(message); return false; });
 }
 
 void LLEnvironment::cleanupSingleton()
 {
+    if (mParcelCallbackConnection.connected())
+    {
+        mParcelCallbackConnection.disconnect();
+        mRegionUpdateCallbackConnection.disconnect();
+        mRegionChangeCallbackConnection.disconnect();
+        mPositionCallbackConnection.disconnect();
+    }
     LLEventPumps::instance().obtain(PUMP_EXPERIENCE).stopListening(LISTENER_NAME);
 }
 
diff --git a/indra/newview/llenvironment.h b/indra/newview/llenvironment.h
index 330de2bea87da56123b2164818e82dff3c237251..64fd170e43c51194ce187c0e8a1d5451f1328586 100644
--- a/indra/newview/llenvironment.h
+++ b/indra/newview/llenvironment.h
@@ -402,6 +402,11 @@ class LLEnvironment : public LLSimpleton<LLEnvironment>
     bool                        mShowMoonBeacon;
     S32                         mEditorCounter;
 
+    connection_t                mParcelCallbackConnection;
+    connection_t                mRegionUpdateCallbackConnection;
+    connection_t                mRegionChangeCallbackConnection;
+    connection_t                mPositionCallbackConnection;
+
     struct UpdateInfo
     {
         typedef std::shared_ptr<UpdateInfo> ptr_t;
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 862db08e625044b0d24f16348ea8c79e11dee67f..325ab1e224dc435c36144234b44f179043a85d84 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -1435,6 +1435,9 @@ bool idle_startup()
         // to hapen with caps granted
         gTextureList.doPrefetchImages();
 
+        // will init images, should be done with caps, but before gSky.init()
+        LLEnvironment::getInstance()->initSingleton();
+
         display_startup();
 		update_texture_fetch();
 		display_startup();
@@ -2918,6 +2921,7 @@ void reset_login()
 	gAgentWearables.cleanup();
 	gAgentCamera.cleanup();
 	gAgent.cleanup();
+    gSky.cleanup(); // mVOSkyp is an inworld object.
 	LLWorld::getInstance()->resetClass();
 
 	if ( gViewerWindow )
diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp
index 338aac2cccdb0a2718586bdf09b5afad138fa5fa..674c3874308bc02d8ed721cec39b211cdf4b20c2 100644
--- a/indra/newview/llviewertexturelist.cpp
+++ b/indra/newview/llviewertexturelist.cpp
@@ -45,6 +45,7 @@
 #include "llxmltree.h"
 #include "message.h"
 
+#include "lldrawpoolbump.h" // to init bumpmap images
 #include "lltexturecache.h"
 #include "lltexturefetch.h"
 #include "llviewercontrol.h"
@@ -135,9 +136,6 @@ void LLViewerTextureList::doPreloadImages()
 	//uv_test->setClamp(FALSE, FALSE);
 	//uv_test->setMipFilterNearest(TRUE, TRUE);
 
-	// prefetch specific UUIDs
-	LLViewerTextureManager::getFetchedTexture(IMG_SHOT);
-	LLViewerTextureManager::getFetchedTexture(IMG_SMOKE_POOF);
 	LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTextureFromFile("silhouette.j2c", FTT_LOCAL_FILE, MIPMAP_YES, LLViewerFetchedTexture::BOOST_UI);
 	if (image) 
 	{
@@ -206,13 +204,26 @@ void LLViewerTextureList::doPrefetchImages()
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
 
-    LLViewerFetchedTexture* imagep = LLViewerTextureManager::getFetchedTexture(DEFAULT_WATER_NORMAL, FTT_DEFAULT, MIPMAP_YES, LLViewerFetchedTexture::BOOST_UI);
-    if (imagep)
+    // todo: do not load without getViewerAssetUrl()
+    // either fail login without caps or provide this
+    // in some other way, textures won't load otherwise
+    LLViewerFetchedTexture *imagep = findImage(DEFAULT_WATER_NORMAL, TEX_LIST_STANDARD);
+    if (!imagep)
     {
-        imagep->setAddressMode(LLTexUnit::TAM_WRAP);
-        mImagePreloads.insert(imagep);
+        // add it to mImagePreloads only once
+        imagep = LLViewerTextureManager::getFetchedTexture(DEFAULT_WATER_NORMAL, FTT_DEFAULT, MIPMAP_YES, LLViewerFetchedTexture::BOOST_UI);
+        if (imagep)
+        {
+            imagep->setAddressMode(LLTexUnit::TAM_WRAP);
+            mImagePreloads.insert(imagep);
+        }
     }
 
+    LLViewerTextureManager::getFetchedTexture(IMG_SHOT);
+    LLViewerTextureManager::getFetchedTexture(IMG_SMOKE_POOF);
+
+    LLStandardBumpmap::addstandard();
+
     if (LLAppViewer::instance()->getPurgeCache())
 	{
 		// cache was purged, no point