diff --git a/indra/llcommon/tests/llprocess_test.cpp b/indra/llcommon/tests/llprocess_test.cpp
index f0eafa82019fda847313a8746dcc1e3eb6f48809..447c7f50f2e65e40831db759bc9800838884051a 100644
--- a/indra/llcommon/tests/llprocess_test.cpp
+++ b/indra/llcommon/tests/llprocess_test.cpp
@@ -356,14 +356,15 @@ namespace tut
 
         // Create a script file in a temporary place.
         NamedTempFile script("py",
+			"from __future__ import print_function" EOL
             "import sys" EOL
             "import time" EOL
             EOL
             "time.sleep(2)" EOL
-            "print >>sys.stdout, 'stdout after wait'" EOL
+            "print('stdout after wait',file=sys.stdout)" EOL
             "sys.stdout.flush()" EOL
             "time.sleep(2)" EOL
-            "print >>sys.stderr, 'stderr after wait'" EOL
+            "print('stderr after wait',file=sys.stderr)" EOL
             "sys.stderr.flush()" EOL
             );
 
@@ -568,12 +569,12 @@ namespace tut
     {
         set_test_name("arguments");
         PythonProcessLauncher py(get_test_name(),
-                                 "from __future__ import with_statement\n"
+                                 "from __future__ import with_statement, print_function\n"
                                  "import sys\n"
                                  // note nonstandard output-file arg!
                                  "with open(sys.argv[3], 'w') as f:\n"
                                  "    for arg in sys.argv[1:]:\n"
-                                 "        print >>f, arg\n");
+                                 "        print(arg,file=f)\n");
         // We expect that PythonProcessLauncher has already appended
         // its own NamedTempFile to mParams.args (sys.argv[0]).
         py.mParams.args.add("first arg");          // sys.argv[1]
@@ -857,7 +858,8 @@ namespace tut
         set_test_name("'bogus' test");
         CaptureLog recorder;
         PythonProcessLauncher py(get_test_name(),
-                                 "print 'Hello world'\n");
+                                 "from __future__ import print_function\n"
+                                 "print('Hello world')\n");
         py.mParams.files.add(LLProcess::FileParam("bogus"));
         py.mPy = LLProcess::create(py.mParams);
         ensure("should have rejected 'bogus'", ! py.mPy);
@@ -872,7 +874,8 @@ namespace tut
         // Replace this test with one or more real 'file' tests when we
         // implement 'file' support
         PythonProcessLauncher py(get_test_name(),
-                                 "print 'Hello world'\n");
+                                 "from __future__ import print_function\n"
+                                 "print('Hello world')\n");
         py.mParams.files.add(LLProcess::FileParam());
         py.mParams.files.add(LLProcess::FileParam("file"));
         py.mPy = LLProcess::create(py.mParams);
@@ -887,7 +890,8 @@ namespace tut
         // implement 'tpipe' support
         CaptureLog recorder;
         PythonProcessLauncher py(get_test_name(),
-                                 "print 'Hello world'\n");
+                                 "from __future__ import print_function\n"
+                                 "print('Hello world')\n");
         py.mParams.files.add(LLProcess::FileParam());
         py.mParams.files.add(LLProcess::FileParam("tpipe"));
         py.mPy = LLProcess::create(py.mParams);
@@ -904,7 +908,8 @@ namespace tut
         // implement 'npipe' support
         CaptureLog recorder;
         PythonProcessLauncher py(get_test_name(),
-                                 "print 'Hello world'\n");
+                                 "from __future__ import print_function\n"
+                                 "print('Hello world')\n");
         py.mParams.files.add(LLProcess::FileParam());
         py.mParams.files.add(LLProcess::FileParam());
         py.mParams.files.add(LLProcess::FileParam("npipe"));
@@ -980,7 +985,8 @@ namespace tut
     {
         set_test_name("get*Pipe() validation");
         PythonProcessLauncher py(get_test_name(),
-                                 "print 'this output is expected'\n");
+                                 "from __future__ import print_function\n"
+                                 "print('this output is expected')\n");
         py.mParams.files.add(LLProcess::FileParam("pipe")); // pipe for  stdin
         py.mParams.files.add(LLProcess::FileParam());       // inherit stdout
         py.mParams.files.add(LLProcess::FileParam("pipe")); // pipe for stderr
@@ -1000,14 +1006,15 @@ namespace tut
     {
         set_test_name("talk to stdin/stdout");
         PythonProcessLauncher py(get_test_name(),
+                                 "from __future__ import print_function\n"
                                  "import sys, time\n"
-                                 "print 'ok'\n"
+                                 "print('ok')\n"
                                  "sys.stdout.flush()\n"
                                  "# wait for 'go' from test program\n"
                                  "go = sys.stdin.readline()\n"
                                  "if go != 'go\\n':\n"
                                  "    sys.exit('expected \"go\", saw %r' % go)\n"
-                                 "print 'ack'\n");
+                                 "print('ack')\n");
         py.mParams.files.add(LLProcess::FileParam("pipe")); // stdin
         py.mParams.files.add(LLProcess::FileParam("pipe")); // stdout
         py.launch();
@@ -1118,7 +1125,8 @@ namespace tut
     {
         set_test_name("ReadPipe \"eof\" event");
         PythonProcessLauncher py(get_test_name(),
-                                 "print 'Hello from Python!'\n");
+                                 "from __future__ import print_function\n"
+                                 "print('Hello from Python!')\n");
         py.mParams.files.add(LLProcess::FileParam()); // stdin
         py.mParams.files.add(LLProcess::FileParam("pipe")); // stdout
         py.launch();
diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index 673f6cb6dfa9e713ca8ee083cc0e2783e1b90132..a269549c4910e467e2079768ec452d9cfdf4c8f8 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -62,6 +62,7 @@
 BOOL gDebugSession = FALSE;
 BOOL gClothRipple = FALSE;
 BOOL gHeadlessClient = FALSE;
+BOOL gNonInteractive = FALSE;
 BOOL gGLActive = FALSE;
 BOOL gGLDebugLoggingEnabled = TRUE;
 
diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h
index a03d5352bef9c90b32a3e94e99c7593a161827e9..6e1f5e6deb777a4b6d3d03640728dec7c6bf1dcb 100644
--- a/indra/llrender/llgl.h
+++ b/indra/llrender/llgl.h
@@ -485,6 +485,7 @@ void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor
 
 extern BOOL gClothRipple;
 extern BOOL gHeadlessClient;
+extern BOOL gNonInteractive;
 extern BOOL gGLActive;
 
 // Deal with changing glext.h definitions for newer SDK versions, specifically
diff --git a/indra/llwindow/llwindow.cpp b/indra/llwindow/llwindow.cpp
index 30bc743e72fbf31b5efb889dd4995beaeecea8e0..67ef98d7b3b1a49946adfc5081a977c4019717a9 100644
--- a/indra/llwindow/llwindow.cpp
+++ b/indra/llwindow/llwindow.cpp
@@ -137,6 +137,12 @@ BOOL LLWindow::canDelete()
 	return TRUE;
 }
 
+//virtual
+void LLWindow::setTitle(const std::string title)
+{
+    // the action happens in the platform specific impl
+}
+
 // virtual
 void LLWindow::incBusyCount()
 {
diff --git a/indra/llwindow/llwindow.h b/indra/llwindow/llwindow.h
index 1384ddfd82528255b95a5e8f2835efb910842d02..b76d313011e1461d0767adbd3175ac070c285f91 100644
--- a/indra/llwindow/llwindow.h
+++ b/indra/llwindow/llwindow.h
@@ -100,6 +100,13 @@ class LLWindow : public LLInstanceTracker<LLWindow>
 	virtual void showCursorFromMouseMove() = 0;
 	virtual void hideCursorUntilMouseMove() = 0;
 
+    // Provide a way to set the Viewer window title after the
+    // windows has been created. The initial use case for this
+    // is described in SL-16102 (update window title with agent 
+    // name, location etc. for non-interactive viewer) but it
+    // may also be useful in other cases.
+    virtual void setTitle(const std::string title);
+
 	// These two functions create a way to make a busy cursor instead
 	// of an arrow when someone's busy doing something. Draw an
 	// arrow/hour if busycount > 0.
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index bf78bcba29599a7205c7e95827b8bfdd8dbcbef6..26bb56d72da152be23a245e2cc3e74f96c7de8b9 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -1925,6 +1925,13 @@ void LLWindowWin32::moveWindow( const LLCoordScreen& position, const LLCoordScre
 	MoveWindow(mWindowHandle, position.mX, position.mY, size.mX, size.mY, TRUE);
 }
 
+void LLWindowWin32::setTitle(const std::string title)
+{
+    // TODO: Do we need to use the wide string version of this call
+    // to support non-ascii usernames (and region names?)
+    SetWindowTextA(mWindowHandle, title.c_str());
+}
+
 BOOL LLWindowWin32::setCursorPosition(const LLCoordWindow position)
 {
     ASSERT_MAIN_THREAD();
diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h
index b44d458fc67ba6aa69832ab7e58676be1ddbd606..7a9a30ccea21387d007853efdaa41d4532ace811 100644
--- a/indra/llwindow/llwindowwin32.h
+++ b/indra/llwindow/llwindowwin32.h
@@ -94,6 +94,7 @@ class LLWindowWin32 : public LLWindow
 	/*virtual*/ BOOL setSizeImpl(LLCoordScreen size);
 	/*virtual*/ BOOL setSizeImpl(LLCoordWindow size);
 	/*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp = NULL);
+    /*virtual*/ void setTitle(const std::string title);
     void* createSharedContext() override;
     void makeContextCurrent(void* context) override;
     void destroySharedContext(void* context) override;
diff --git a/indra/newview/app_settings/cmd_line.xml b/indra/newview/app_settings/cmd_line.xml
index 4e186292f77d6e4c3f99f035e75f3b80141c2179..7514913d13165b2bbf862f5ae454806ad66889c7 100644
--- a/indra/newview/app_settings/cmd_line.xml
+++ b/indra/newview/app_settings/cmd_line.xml
@@ -217,6 +217,14 @@
       <string>NoInventoryLibrary</string>
     </map>
 
+    <key>noninteractive</key>
+    <map>
+      <key>desc</key>
+      <string>Run in semi-headless mode where only login and logout need to work.</string>
+      <key>map-to</key>
+      <string>NonInteractive</string>
+    </map>
+
     <key>nonotifications</key>
     <map>
       <key>desc</key>
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index eeadea76a214feb50779518d841335f66b4bf690..aeeba58a686cd041b4af725bd306f2f3e76e2289 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -7015,6 +7015,17 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
+    <key>NonInteractive</key>
+    <map>
+      <key>Comment</key>
+      <string>Run in a semi-headless mode where only logging in and logging out needs to work.</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+	  <integer>0</integer>
+    </map>
     <key>NonvisibleObjectsInMemoryTime</key>
     <map>
       <key>Comment</key>
@@ -16644,6 +16655,17 @@
       <key>Value</key>
       <integer>1</integer>        
     </map>
+    <key>UpdateAppWindowTitleBar</key>
+    <map>
+      <key>Comment</key>
+      <string>Updates the application window title bar with brief information about user/location</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
 </map>
 </llsd>
 
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index 389448654a1120ff4b40373c21b20feb1c5ccc0c..b35eef20f7fdc27bac53e9f5a83717dd698b87b0 100644
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -1481,7 +1481,7 @@ void LLAgent::resetControlFlags()
 //-----------------------------------------------------------------------------
 void LLAgent::setAFK()
 {
-	if (!gAgent.getRegion())
+	if (gNonInteractive || !gAgent.getRegion())
 	{
 		// Don't set AFK if we're not talking to a region yet.
 		return;
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 691c3f37984a9d96cada68d01dc5a61bf1ac5f53..8492aba2224251924230dc0d9615827c40eecfb7 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1555,6 +1555,14 @@ bool LLAppViewer::doFrame()
 				ms_sleep(yield_time);
 			}
 
+			if (gNonInteractive)
+			{
+				S32 non_interactive_ms_sleep_time = 100;
+				LLAppViewer::getTextureCache()->pause();
+				LLAppViewer::getImageDecodeThread()->pause();
+				ms_sleep(non_interactive_ms_sleep_time);
+			}
+
 			// yield cooperatively when not running as foreground window
 			// and when not quiting (causes trouble at mac's cleanup stage)
 			if (!LLApp::isExiting()
@@ -1562,8 +1570,8 @@ bool LLAppViewer::doFrame()
 					|| !gFocusMgr.getAppHasFocus()))
 			{
 				// Sleep if we're not rendering, or the window is minimized.
-				static LLCachedControl<S32> s_bacground_yeild_time(gSavedSettings, "BackgroundYieldTime", 40);
-				S32 milliseconds_to_sleep = llclamp((S32)s_bacground_yeild_time, 0, 1000);
+				static LLCachedControl<S32> s_background_yield_time(gSavedSettings, "BackgroundYieldTime", 40);
+				S32 milliseconds_to_sleep = llclamp((S32)s_background_yield_time, 0, 1000);
 				// don't sleep when BackgroundYieldTime set to 0, since this will still yield to other threads
 				// of equal priority on Windows
 				if (milliseconds_to_sleep > 0)
@@ -2440,6 +2448,38 @@ namespace
     }
 } // anonymous namespace
 
+// Set a named control temporarily for this session, as when set via the command line --set option.
+// Name can be specified as "<control_group>.<control_name>", with default group being Global.
+bool tempSetControl(const std::string& name, const std::string& value)
+{
+	std::string name_part;
+	std::string group_part;
+	LLControlVariable* control = NULL;
+
+	// Name can be further split into ControlGroup.Name, with the default control group being Global
+	size_t pos = name.find('.');
+	if (pos != std::string::npos)
+	{
+		group_part = name.substr(0, pos);
+		name_part = name.substr(pos+1);
+		LL_INFOS() << "Setting " << group_part << "." << name_part << " to " << value << LL_ENDL;
+		auto g = LLControlGroup::getInstance(group_part);
+		if (g) control = g->getControl(name_part);
+	}
+	else
+	{
+		LL_INFOS() << "Setting Global." << name << " to " << value << LL_ENDL;
+		control = gSavedSettings.getControl(name);
+	}
+
+	if (control)
+	{
+		control->setValue(value, false);
+		return true;
+	}
+	return false;
+}
+
 bool LLAppViewer::initConfiguration()
 {
 	//Load settings files list
@@ -2596,9 +2636,10 @@ bool LLAppViewer::initConfiguration()
 		disableCrashlogger();
 	}
 
+	gNonInteractive = gSavedSettings.getBOOL("NonInteractive");
 	// Handle initialization from settings.
 	// Start up the debugging console before handling other options.
-	if (gSavedSettings.getBOOL("ShowConsoleWindow"))
+	if (gSavedSettings.getBOOL("ShowConsoleWindow") && !gNonInteractive)
 	{
 		initConsole();
 	}
@@ -2631,33 +2672,9 @@ bool LLAppViewer::initConfiguration()
             {
                 const std::string& name = *itr;
                 const std::string& value = *(++itr);
-                std::string name_part;
-                std::string group_part;
-				LLControlVariable* control = NULL;
-
-				// Name can be further split into ControlGroup.Name, with the default control group being Global
-				size_t pos = name.find('.');
-				if (pos != std::string::npos)
-				{
-					group_part = name.substr(0, pos);
-					name_part = name.substr(pos+1);
-					LL_INFOS() << "Setting " << group_part << "." << name_part << " to " << value << LL_ENDL;
-					auto g = LLControlGroup::getInstance(group_part);
-					if (g) control = g->getControl(name_part);
-				}
-				else
-				{
-					LL_INFOS() << "Setting Global." << name << " to " << value << LL_ENDL;
-					control = gSavedSettings.getControl(name);
-				}
-
-                if (control)
-                {
-                    control->setValue(value, false);
-                }
-                else
+                if (!tempSetControl(name,value))
                 {
-					LL_WARNS() << "Failed --set " << name << ": setting name unknown." << LL_ENDL;
+                    LL_WARNS() << "Failed --set " << name << ": setting name unknown." << LL_ENDL;
                 }
             }
         }
@@ -2743,6 +2760,19 @@ bool LLAppViewer::initConfiguration()
 		}
 	}
 
+	if (gNonInteractive)
+	{
+		tempSetControl("AllowMultipleViewers", "TRUE");
+		tempSetControl("SLURLPassToOtherInstance", "FALSE");
+		tempSetControl("RenderWater", "FALSE");
+		tempSetControl("FlyingAtExit", "FALSE");
+		tempSetControl("WindowWidth", "1024");
+		tempSetControl("WindowHeight", "200");
+		LLError::setEnabledLogTypesMask(0);
+		llassert_always(!gSavedSettings.getBOOL("SLURLPassToOtherInstance"));
+	}
+
+
 	// Handle slurl use. NOTE: Don't let SL-55321 reappear.
 	// This initial-SLURL logic, up through the call to
 	// sendURLToOtherInstance(), must precede LLSplashScreen::show() --
diff --git a/indra/newview/lldynamictexture.cpp b/indra/newview/lldynamictexture.cpp
index 8b8273d18304d4b259cfa477228d0680dc341389..31ca2531ba4af2109467d5763f197ac520d2fed3 100644
--- a/indra/newview/lldynamictexture.cpp
+++ b/indra/newview/lldynamictexture.cpp
@@ -119,8 +119,11 @@ BOOL LLViewerDynamicTexture::render()
 void LLViewerDynamicTexture::preRender(BOOL clear_depth)
 {
 	gPipeline.allocatePhysicsBuffer();
-	llassert(mFullWidth <= static_cast<S32>(gPipeline.mPhysicsDisplay.getWidth()));
-	llassert(mFullHeight <= static_cast<S32>(gPipeline.mPhysicsDisplay.getHeight()));
+	if (!gNonInteractive)
+	{
+		llassert(mFullWidth <= static_cast<S32>(gPipeline.mPhysicsDisplay.getWidth()));
+		llassert(mFullHeight <= static_cast<S32>(gPipeline.mPhysicsDisplay.getHeight()));
+	}
 
 	if (gGLManager.mHasFramebufferObject && gPipeline.mPhysicsDisplay.isComplete() && !gGLManager.mIsATI)
 	{ //using offscreen render target, just use the bottom left corner
diff --git a/indra/newview/llteleporthistory.cpp b/indra/newview/llteleporthistory.cpp
index 3c3c1c96ef99a7c285101803a77820cb66280ad8..3ece12931c6ffe365aa3b3c12ed76f0f8cb5e521 100644
--- a/indra/newview/llteleporthistory.cpp
+++ b/indra/newview/llteleporthistory.cpp
@@ -39,6 +39,11 @@
 #include "llviewerregion.h"
 #include "llworldmap.h"
 #include "llagentui.h"
+#include "llwindow.h"
+#include "llviewerwindow.h"
+#include "llavatarname.h"
+#include "llavatarnamecache.h"
+
 
 //////////////////////////////////////////////////////////////////////////////
 // LLTeleportHistoryItem
@@ -113,6 +118,20 @@ void LLTeleportHistory::handleLoginComplete()
 	updateCurrentLocation(gAgent.getPositionGlobal());
 }
 
+static void on_avatar_name_update_title(const LLAvatarName& av_name)
+{
+	if (gAgent.getRegion() && gViewerWindow && gViewerWindow->getWindow())
+	{
+		std::string region = gAgent.getRegion()->getName();
+		std::string username = av_name.getUserName();
+
+		// this first pass simply displays username and region name
+		// but could easily be extended to include other details like
+		// X/Y/Z location within a region etc.
+		std::string new_title = STRINGIZE(username << " @ " << region);
+		gViewerWindow->getWindow()->setTitle(new_title);
+	}	
+}
 
 void LLTeleportHistory::updateCurrentLocation(const LLVector3d& new_pos)
 {
@@ -174,6 +193,14 @@ void LLTeleportHistory::updateCurrentLocation(const LLVector3d& new_pos)
 	if (!mGotInitialUpdate)
 		mGotInitialUpdate = true;
 
+    // update Viewer window title with username and region name
+    // if we are in "non-interactive mode" (SL-15999) or the debug 
+    // setting to allow it is enabled (may be useful in other situations)
+    if (gNonInteractive || gSavedSettings.getBOOL("UpdateAppWindowTitleBar"))
+    {
+		LLAvatarNameCache::get(gAgent.getID(), boost::bind(&on_avatar_name_update_title, _2));
+    }
+
 	// Signal the interesting party that we've changed. 
 	onHistoryChanged();
 }
diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index 63e561147df90ff9a3ea2b3e9ce3bb244fca5d04..73a25397fd7e8d412a182e7d5c6b75336e06c5af 100644
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -1143,6 +1143,10 @@ void LLTextureFetchWorker::startWork(S32 param)
 bool LLTextureFetchWorker::doWork(S32 param)
 {
     LL_PROFILE_ZONE_SCOPED;
+	if (gNonInteractive)
+	{
+		return true;
+	}
 	static const LLCore::HttpStatus http_not_found(HTTP_NOT_FOUND);						// 404
 	static const LLCore::HttpStatus http_service_unavail(HTTP_SERVICE_UNAVAILABLE);		// 503
 	static const LLCore::HttpStatus http_not_sat(HTTP_REQUESTED_RANGE_NOT_SATISFIABLE);	// 416;
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index 33842497d1a651be7cf906aa69c09ea6b96d4067..1236695e4fc5b7413a8210cea00eef8da47243f5 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -124,7 +124,8 @@ void display_startup()
 	if (   !gViewerWindow
 		|| !gViewerWindow->getActive()
 		|| !gViewerWindow->getWindow()->getVisible() 
-		|| gViewerWindow->getWindow()->getMinimized() )
+		|| gViewerWindow->getWindow()->getMinimized()
+		|| gNonInteractive)
 	{
 		return; 
 	}
@@ -313,7 +314,8 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 	// Attempting to draw into a minimized window causes a GL error. JC
 	if (   !gViewerWindow->getActive()
 		|| !gViewerWindow->getWindow()->getVisible() 
-		|| gViewerWindow->getWindow()->getMinimized() )
+		|| gViewerWindow->getWindow()->getMinimized() 
+		|| gNonInteractive)
 	{
 		// Clean up memory the pools may have allocated
 		if (rebuild)
diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp
index 5a05f897588f723e5f975a66eec5be9b33fd59a3..98b76328dea2f0b72a33db0eac7a93298d851a26 100644
--- a/indra/newview/llviewerfloaterreg.cpp
+++ b/indra/newview/llviewerfloaterreg.cpp
@@ -192,6 +192,10 @@ LLFloaterOpenHandler gFloaterOpenHandler;
 
 void LLViewerFloaterReg::registerFloaters()
 {
+	if (gNonInteractive)
+	{
+		return;
+	}
 	// *NOTE: Please keep these alphabetized for easier merges
 
 	LLFloaterAboutUtil::registerFloater();
diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index d35dbda907d6942119f8b9714ab6b431565c408c..c347e0eb7687dd52ac6173b53cee31e41c5b8190 100644
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -1216,7 +1216,7 @@ LLCore::HttpHeaders::ptr_t LLViewerMedia::getHttpHeaders()
 /////////////////////////////////////////////////////////////////////////////////////////
 void LLViewerMedia::setOpenIDCookie(const std::string& url)
 {
-	if(!mOpenIDCookie.empty())
+	if(!gNonInteractive && !mOpenIDCookie.empty())
 	{
         std::string profileUrl = getProfileURL("");
 
@@ -1687,6 +1687,11 @@ void LLViewerMediaImpl::setMediaType(const std::string& media_type)
 /*static*/
 LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_type, LLPluginClassMediaOwner *owner /* may be NULL */, S32 default_width, S32 default_height, F64 zoom_factor, const std::string target, bool clean_browser)
 {
+	if (gNonInteractive)
+    {
+        return NULL;
+    }
+
 	std::string plugin_basename = LLMIMETypes::implType(media_type);
 	LLPluginClassMedia* media_source = NULL;
 
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 94d2d216b9452c72f38324a3c5306db3cd03f651..5e99d1320613d71a416e54efc67d67d286347269 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -2423,6 +2423,10 @@ void translateFailure(LLChat chat, LLSD toastArgs, int status, const std::string
 
 void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)
 {
+	if (gNonInteractive)
+	{
+		return;
+	}
 	LLChat	chat;
 	std::string		mesg;
 	std::string		from_name;
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index b88baf6aa72f3b3b5f8cacdb4eee85778f637b67..0832415e1e7dcd96bc846c98d0115aeed95b14aa 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -107,6 +107,7 @@
 #include "llcleanup.h"
 #include "llcallstack.h"
 #include "llmeshrepository.h"
+#include "llgl.h"
 
 //#define DEBUG_UPDATE_TYPE
 
@@ -155,11 +156,27 @@ LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pco
     
 	LLViewerObject *res = NULL;
 	LL_RECORD_BLOCK_TIME(FTM_CREATE_OBJECT);
-	
+
+	if (gNonInteractive
+		&& pcode != LL_PCODE_LEGACY_AVATAR
+		&& pcode != LL_VO_SURFACE_PATCH
+		&& pcode != LL_VO_WATER
+		&& pcode != LL_VO_VOID_WATER
+		&& pcode != LL_VO_WL_SKY
+		&& pcode != LL_VO_SKY
+		&& pcode != LL_VO_GROUND
+		&& pcode != LL_VO_PART_GROUP
+		)
+	{
+		return res;
+	}
 	switch (pcode)
 	{
 	case LL_PCODE_VOLUME:
-	  res = new LLVOVolume(id, pcode, regionp); break;
+	{
+		res = new LLVOVolume(id, pcode, regionp); break;
+		break;
+	}
 	case LL_PCODE_LEGACY_AVATAR:
 	{
 		if (id == gAgentID)
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index 0b205561043edff6109dd62e68af42fa938d7953..097b5e364599158605496da390408d749745e425 100644
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -80,6 +80,7 @@
 #include "llfloaterperms.h"
 #include "llvocache.h"
 #include "llcorehttputil.h"
+#include "llstartup.h"
 
 #include <algorithm>
 #include <iterator>
@@ -309,7 +310,7 @@ LLViewerObject* LLViewerObjectList::processObjectUpdateFromCache(LLVOCacheEntry*
 
 	LLDataPacker *cached_dpp = entry->getDP();
 
-	if (!cached_dpp)
+	if (!cached_dpp || gNonInteractive)
 	{
 		return NULL; //nothing cached.
 	}
@@ -2063,7 +2064,6 @@ LLViewerObject *LLViewerObjectList::createObjectFromCache(const LLPCode pcode, L
 LLViewerObject *LLViewerObjectList::createObject(const LLPCode pcode, LLViewerRegion *regionp,
 												 const LLUUID &uuid, const U32 local_id, const LLHost &sender)
 {
-	
 	LLUUID fullid;
 	if (uuid == LLUUID::null)
 	{
diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h
index b6b4d1e41ff378e632d7d1f8a8a69dc17645fb2d..a5a1fb2c16cb8abd81d29f09094dd9dce24ba993 100644
--- a/indra/newview/llviewertexture.h
+++ b/indra/newview/llviewertexture.h
@@ -1,796 +1,796 @@
-/** 
- * @file llviewertexture.h
- * @brief Object for managing images and their textures
- *
- * $LicenseInfo:firstyear=2000&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLVIEWERTEXTURE_H					
-#define LL_LLVIEWERTEXTURE_H
-
-#include "llgltexture.h"
-#include "lltimer.h"
-#include "llframetimer.h"
-#include "llhost.h"
-#include "llgltypes.h"
-#include "llrender.h"
-#include "llmetricperformancetester.h"
-#include "httpcommon.h"
-
-#include <map>
-#include <list>
-
-extern const S32Megabytes gMinVideoRam;
-extern const S32Megabytes gMaxVideoRam;
-
-class LLFace;
-class LLImageGL ;
-class LLImageRaw;
-class LLViewerObject;
-class LLViewerTexture;
-class LLViewerFetchedTexture ;
-class LLViewerMediaTexture ;
-class LLTexturePipelineTester ;
-
-
-typedef	void	(*loaded_callback_func)( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata );
-
-class LLVFile;
-class LLMessageSystem;
-class LLViewerMediaImpl ;
-class LLVOVolume ;
-struct LLTextureKey;
-
-class LLLoadedCallbackEntry
-{
-public:
-    typedef std::set< LLTextureKey > source_callback_list_t;
-
-public:
-	LLLoadedCallbackEntry(loaded_callback_func cb,
-						  S32 discard_level,
-						  BOOL need_imageraw, // Needs image raw for the callback
-						  void* userdata,
-						  source_callback_list_t* src_callback_list,
-						  LLViewerFetchedTexture* target,
-						  BOOL pause);
-	~LLLoadedCallbackEntry();
-	void removeTexture(LLViewerFetchedTexture* tex) ;
-
-	loaded_callback_func	mCallback;
-	S32						mLastUsedDiscard;
-	S32						mDesiredDiscard;
-	BOOL					mNeedsImageRaw;
-	BOOL                    mPaused;
-	void*					mUserData;
-	source_callback_list_t* mSourceCallbackList;
-	
-public:
-	static void cleanUpCallbackList(LLLoadedCallbackEntry::source_callback_list_t* callback_list) ;
-};
-
-class LLTextureBar;
-
-class LLViewerTexture : public LLGLTexture
-{
-public:
-	enum
-	{
-		LOCAL_TEXTURE,		
-		MEDIA_TEXTURE,
-		DYNAMIC_TEXTURE,
-		FETCHED_TEXTURE,
-		LOD_TEXTURE,
-		ATLAS_TEXTURE,
-		INVALID_TEXTURE_TYPE
-	};
-
-	typedef std::vector<class LLFace*> ll_face_list_t;
-	typedef std::vector<LLVOVolume*> ll_volume_list_t;
-
-
-protected:
-	virtual ~LLViewerTexture();
-	LOG_CLASS(LLViewerTexture);
-
-public:	
-	static void initClass();
-	static void updateClass(const F32 velocity, const F32 angular_velocity) ;
-	
-	LLViewerTexture(BOOL usemipmaps = TRUE);
-	LLViewerTexture(const LLUUID& id, BOOL usemipmaps) ;
-	LLViewerTexture(const LLImageRaw* raw, BOOL usemipmaps) ;
-	LLViewerTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps) ;
-
-	virtual S8 getType() const;
-	virtual BOOL isMissingAsset() const ;
-	virtual void dump();	// debug info to LL_INFOS()
-	
-    virtual bool isViewerMediaTexture() const { return false; }
-
-	/*virtual*/ bool bindDefaultImage(const S32 stage = 0) ;
-	/*virtual*/ bool bindDebugImage(const S32 stage = 0) ;
-	/*virtual*/ void forceImmediateUpdate() ;
-	/*virtual*/ bool isActiveFetching();
-	
-	/*virtual*/ const LLUUID& getID() const { return mID; }
-	void setBoostLevel(S32 level);
-	S32  getBoostLevel() { return mBoostLevel; }
-	void setTextureListType(S32 tex_type) { mTextureListType = tex_type; }
-	S32 getTextureListType() { return mTextureListType; }
-
-	void addTextureStats(F32 virtual_size, BOOL needs_gltexture = TRUE) const;
-	void resetTextureStats();	
-	void setMaxVirtualSizeResetInterval(S32 interval)const {mMaxVirtualSizeResetInterval = interval;}
-	void resetMaxVirtualSizeResetCounter()const {mMaxVirtualSizeResetCounter = mMaxVirtualSizeResetInterval;}
-	S32 getMaxVirtualSizeResetCounter() const { return mMaxVirtualSizeResetCounter; }
-
-	virtual F32  getMaxVirtualSize() ;
-
-	LLFrameTimer* getLastReferencedTimer() {return &mLastReferencedTimer ;}
-	
-	S32 getFullWidth() const { return mFullWidth; }
-	S32 getFullHeight() const { return mFullHeight; }	
-	/*virtual*/ void setKnownDrawSize(S32 width, S32 height);
-
-	virtual void addFace(U32 channel, LLFace* facep) ;
-	virtual void removeFace(U32 channel, LLFace* facep) ; 
-	S32 getTotalNumFaces() const;
-	S32 getNumFaces(U32 ch) const;
-	const ll_face_list_t* getFaceList(U32 channel) const {llassert(channel < LLRender::NUM_TEXTURE_CHANNELS); return &mFaceList[channel];}
-
-	virtual void addVolume(U32 channel, LLVOVolume* volumep);
-	virtual void removeVolume(U32 channel, LLVOVolume* volumep);
-	S32 getNumVolumes(U32 channel) const;
-	const ll_volume_list_t* getVolumeList(U32 channel) const { return &mVolumeList[channel]; }
-
-	
-	virtual void setCachedRawImage(S32 discard_level, LLImageRaw* imageraw) ;
-	BOOL isLargeImage() ;	
-	
-	void setParcelMedia(LLViewerMediaTexture* media) {mParcelMedia = media;}
-	BOOL hasParcelMedia() const { return mParcelMedia != NULL;}
-	LLViewerMediaTexture* getParcelMedia() const { return mParcelMedia;}
-
-	/*virtual*/ void updateBindStatsForTester() ;
-protected:
-	void cleanup() ;
-	void init(bool firstinit) ;
-	void reorganizeFaceList() ;
-	void reorganizeVolumeList() ;
-
-	void notifyAboutMissingAsset();
-	void notifyAboutCreatingTexture();
-
-private:
-	friend class LLBumpImageList;
-	friend class LLUIImageList;
-
-	virtual void switchToCachedImage();
-	
-	static bool isMemoryForTextureLow() ;
-	static bool isMemoryForTextureSuficientlyFree();
-	static void getGPUMemoryForTextures(S32Megabytes &gpu, S32Megabytes &physical);
-
-protected:
-	LLUUID mID;
-	S32 mTextureListType; // along with mID identifies where to search for this texture in TextureList
-
-	F32 mSelectedTime;				// time texture was last selected
-	mutable F32 mMaxVirtualSize;	// The largest virtual size of the image, in pixels - how much data to we need?	
-	mutable S32  mMaxVirtualSizeResetCounter ;
-	mutable S32  mMaxVirtualSizeResetInterval;
-	mutable F32 mAdditionalDecodePriority;  // priority add to mDecodePriority.
-	LLFrameTimer mLastReferencedTimer;	
-
-	ll_face_list_t    mFaceList[LLRender::NUM_TEXTURE_CHANNELS]; //reverse pointer pointing to the faces using this image as texture
-	U32               mNumFaces[LLRender::NUM_TEXTURE_CHANNELS];
-	LLFrameTimer      mLastFaceListUpdateTimer ;
-
-	ll_volume_list_t  mVolumeList[LLRender::NUM_VOLUME_TEXTURE_CHANNELS];
-	U32					mNumVolumes[LLRender::NUM_VOLUME_TEXTURE_CHANNELS];
-	LLFrameTimer	  mLastVolumeListUpdateTimer;
-
-	//do not use LLPointer here.
-	LLViewerMediaTexture* mParcelMedia ;
-
-	static F32 sTexelPixelRatio;
-public:
-	static const U32 sCurrentFileVersion;	
-	static S32 sImageCount;
-	static S32 sRawCount;
-	static S32 sAuxCount;
-	static LLFrameTimer sEvaluationTimer;
-	static F32 sDesiredDiscardBias;
-	static F32 sDesiredDiscardScale;
-	static S32Bytes sBoundTextureMemory;
-	static S32Bytes sTotalTextureMemory;
-	static S32Megabytes sMaxBoundTextureMemory;
-	static S32Megabytes sMaxTotalTextureMem;
-	static S32Bytes sMaxDesiredTextureMem ;
-	static S8  sCameraMovingDiscardBias;
-	static F32 sCameraMovingBias;
-	static S32 sMaxSculptRez ;
-	static U32 sMinLargeImageSize ;
-	static U32 sMaxSmallImageSize ;
-	static bool sFreezeImageUpdates;
-	static F32  sCurrentTime ;
-
-	enum EDebugTexels
-	{
-		DEBUG_TEXELS_OFF,
-		DEBUG_TEXELS_CURRENT,
-		DEBUG_TEXELS_DESIRED,
-		DEBUG_TEXELS_FULL
-	};
-
-	static EDebugTexels sDebugTexelsMode;
-
-	static LLPointer<LLViewerTexture> sNullImagep; // Null texture for non-textured objects.
-	static LLPointer<LLViewerTexture> sBlackImagep;	// Texture to show NOTHING (pure black)
-	static LLPointer<LLViewerTexture> sCheckerBoardImagep;	// Texture to show NOTHING (pure black)
-};
-
-
-enum FTType
-{
-	FTT_UNKNOWN = -1,
-	FTT_DEFAULT = 0, // standard texture fetched by id.
-	FTT_SERVER_BAKE, // texture produced by appearance service and fetched from there.
-	FTT_HOST_BAKE, // old-style baked texture uploaded by viewer and fetched from avatar's host.
-	FTT_MAP_TILE, // tiles are fetched from map server directly.
-	FTT_LOCAL_FILE // fetch directly from a local file.
-};
-
-const std::string& fttype_to_string(const FTType& fttype);
-
-//
-//textures are managed in gTextureList.
-//raw image data is fetched from remote or local cache
-//but the raw image this texture pointing to is fixed.
-//
-class LLViewerFetchedTexture : public LLViewerTexture
-{
-	friend class LLTextureBar; // debug info only
-	friend class LLTextureView; // debug info only
-
-protected:
-	/*virtual*/ ~LLViewerFetchedTexture();
-public:
-	LLViewerFetchedTexture(const LLUUID& id, FTType f_type, const LLHost& host = LLHost(), BOOL usemipmaps = TRUE);
-	LLViewerFetchedTexture(const LLImageRaw* raw, FTType f_type, BOOL usemipmaps);
-	LLViewerFetchedTexture(const std::string& url, FTType f_type, const LLUUID& id, BOOL usemipmaps = TRUE);
-
-public:
-	static F32 maxDecodePriority();
-	
-	struct Compare
-	{
-		// lhs < rhs
-		bool operator()(const LLPointer<LLViewerFetchedTexture> &lhs, const LLPointer<LLViewerFetchedTexture> &rhs) const
-		{
-			const LLViewerFetchedTexture* lhsp = (const LLViewerFetchedTexture*)lhs;
-			const LLViewerFetchedTexture* rhsp = (const LLViewerFetchedTexture*)rhs;
-			// greater priority is "less"
-			const F32 lpriority = lhsp->getDecodePriority();
-			const F32 rpriority = rhsp->getDecodePriority();
-			if (lpriority > rpriority) // higher priority
-				return true;
-			if (lpriority < rpriority)
-				return false;
-			return lhsp < rhsp;
-		}
-	};
-
-public:
-	/*virtual*/ S8 getType() const ;
-	FTType getFTType() const;
-	/*virtual*/ void forceImmediateUpdate() ;
-	/*virtual*/ void dump() ;
-
-	// Set callbacks to get called when the image gets updated with higher 
-	// resolution versions.
-	void setLoadedCallback(loaded_callback_func cb,
-						   S32 discard_level, BOOL keep_imageraw, BOOL needs_aux,
-						   void* userdata, LLLoadedCallbackEntry::source_callback_list_t* src_callback_list, BOOL pause = FALSE);
-	bool hasCallbacks() { return mLoadedCallbackList.empty() ? false : true; }	
-	void pauseLoadedCallbacks(const LLLoadedCallbackEntry::source_callback_list_t* callback_list);
-	void unpauseLoadedCallbacks(const LLLoadedCallbackEntry::source_callback_list_t* callback_list);
-	bool doLoadedCallbacks();
-	void deleteCallbackEntry(const LLLoadedCallbackEntry::source_callback_list_t* callback_list);
-	void clearCallbackEntryList() ;
-
-	void addToCreateTexture();
-
-    //call to determine if createTexture is necessary
-    BOOL preCreateTexture(S32 usename = 0);
-	 // ONLY call from LLViewerTextureList or ImageGL background thread
-	BOOL createTexture(S32 usename = 0);
-    void postCreateTexture();
-    void scheduleCreateTexture();
-
-	void destroyTexture() ;
-
-	virtual void processTextureStats() ;
-	F32  calcDecodePriority() ;
-
-	BOOL needsAux() const { return mNeedsAux; }
-
-	// Host we think might have this image, used for baked av textures.
-	void setTargetHost(LLHost host)			{ mTargetHost = host; }
-	LLHost getTargetHost() const			{ return mTargetHost; }
-	
-	// Set the decode priority for this image...
-	// DON'T CALL THIS UNLESS YOU KNOW WHAT YOU'RE DOING, it can mess up
-	// the priority list, and cause horrible things to happen.
-	void setDecodePriority(F32 priority = -1.0f);
-	F32 getDecodePriority() const { return mDecodePriority; };
-	F32 getAdditionalDecodePriority() const { return mAdditionalDecodePriority; };
-
-	void setAdditionalDecodePriority(F32 priority) ;
-	
-	void updateVirtualSize() ;
-
-	S32  getDesiredDiscardLevel()			 { return mDesiredDiscardLevel; }
-	void setMinDiscardLevel(S32 discard) 	{ mMinDesiredDiscardLevel = llmin(mMinDesiredDiscardLevel,(S8)discard); }
-
-	bool updateFetch();
-	bool setDebugFetching(S32 debug_level);
-	bool isInDebug() const { return mInDebug; }
-
-	void setUnremovable(BOOL value) { mUnremovable = value; }
-	bool isUnremovable() const { return mUnremovable; }
-	
-	void clearFetchedResults(); //clear all fetched results, for debug use.
-
-	// Override the computation of discard levels if we know the exact output
-	// size of the image.  Used for UI textures to not decode, even if we have
-	// more data.
-	/*virtual*/ void setKnownDrawSize(S32 width, S32 height);
-
-	void setIsMissingAsset(BOOL is_missing = true);
-	/*virtual*/ BOOL isMissingAsset() const { return mIsMissingAsset; }
-
-	// returns dimensions of original image for local files (before power of two scaling)
-	// and returns 0 for all asset system images
-	S32 getOriginalWidth() { return mOrigWidth; }
-	S32 getOriginalHeight() { return mOrigHeight; }
-
-	BOOL isInImageList() const {return mInImageList ;}
-	void setInImageList(BOOL flag) {mInImageList = flag ;}
-
-	LLFrameTimer* getLastPacketTimer() {return &mLastPacketTimer;}
-
-	U32 getFetchPriority() const { return mFetchPriority ;}
-	F32 getDownloadProgress() const {return mDownloadProgress ;}
-
-	LLImageRaw* reloadRawImage(S8 discard_level) ;
-	void destroyRawImage();
-	bool needsToSaveRawImage();
-
-	const std::string& getUrl() const {return mUrl;}
-	//---------------
-	BOOL isDeleted() ;
-	BOOL isInactive() ;
-	BOOL isDeletionCandidate();
-	void setDeletionCandidate() ;
-	void setInactive() ;
-	BOOL getUseDiscard() const { return mUseMipMaps && !mDontDiscard; }	
-	//---------------
-
-	void setForSculpt();
-	BOOL forSculpt() const {return mForSculpt;}
-	BOOL isForSculptOnly() const;
-
-	//raw image management	
-	void        checkCachedRawSculptImage() ;
-	LLImageRaw* getRawImage()const { return mRawImage ;}
-	S32         getRawImageLevel() const {return mRawDiscardLevel;}
-	LLImageRaw* getCachedRawImage() const { return mCachedRawImage ;}
-	S32         getCachedRawImageLevel() const {return mCachedRawDiscardLevel;}
-	BOOL        isCachedRawImageReady() const {return mCachedRawImageReady ;}
-	BOOL        isRawImageValid()const { return mIsRawImageValid ; }	
-	void        forceToSaveRawImage(S32 desired_discard = 0, F32 kept_time = 0.f) ;
-	void        forceToRefetchTexture(S32 desired_discard = 0, F32 kept_time = 60.f);
-	/*virtual*/ void setCachedRawImage(S32 discard_level, LLImageRaw* imageraw) ;
-	void        destroySavedRawImage() ;
-	LLImageRaw* getSavedRawImage() ;
-	BOOL        hasSavedRawImage() const ;
-	F32         getElapsedLastReferencedSavedRawImageTime() const ;
-	BOOL		isFullyLoaded() const;
-
-	BOOL        hasFetcher() const { return mHasFetcher;}
-	void        setCanUseHTTP(bool can_use_http) {mCanUseHTTP = can_use_http;}
-
-	void        forceToDeleteRequest();
-	void        loadFromFastCache();
-	void        setInFastCacheList(bool in_list) { mInFastCacheList = in_list; }
-	bool        isInFastCacheList() { return mInFastCacheList; }
-
-	/*virtual*/bool  isActiveFetching(); //is actively in fetching by the fetching pipeline.
-
-protected:
-	/*virtual*/ void switchToCachedImage();
-	S32 getCurrentDiscardLevelForFetching() ;
-
-private:
-	void init(bool firstinit) ;	
-	void cleanup() ;
-
-	void saveRawImage() ;
-	void setCachedRawImage() ;
-
-	//for atlas
-	void resetFaceAtlas() ;
-	void invalidateAtlas(BOOL rebuild_geom) ;
-	BOOL insertToAtlas() ;
-
-private:
-	BOOL  mFullyLoaded;
-	BOOL  mInDebug;
-	BOOL  mUnremovable;
-	BOOL  mInFastCacheList;
-	BOOL  mForceCallbackFetch;
-
-protected:		
-	std::string mLocalFileName;
-
-	S32 mOrigWidth;
-	S32 mOrigHeight;
-
-	// Override the computation of discard levels if we know the exact output size of the image.
-	// Used for UI textures to not decode, even if we have more data.
-	S32 mKnownDrawWidth;
-	S32	mKnownDrawHeight;
-	BOOL mKnownDrawSizeChanged ;
-	std::string mUrl;
-	
-	S32 mRequestedDiscardLevel;
-	F32 mRequestedDownloadPriority;
-	S32 mFetchState;
-	U32 mFetchPriority;
-	F32 mDownloadProgress;
-	F32 mFetchDeltaTime;
-	F32 mRequestDeltaTime;
-	F32 mDecodePriority;			// The priority for decoding this image.
-	S32	mMinDiscardLevel;
-	S8  mDesiredDiscardLevel;			// The discard level we'd LIKE to have - if we have it and there's space	
-	S8  mMinDesiredDiscardLevel;	// The minimum discard level we'd like to have
-
-	S8  mNeedsAux;					// We need to decode the auxiliary channels
-	S8  mHasAux;                    // We have aux channels
-	S8  mDecodingAux;				// Are we decoding high components
-	S8  mIsRawImageValid;
-	S8  mHasFetcher;				// We've made a fecth request
-	S8  mIsFetching;				// Fetch request is active
-	bool mCanUseHTTP;              //This texture can be fetched through http if true.
-	LLCore::HttpStatus mLastHttpGetStatus; // Result of the most recently completed http request for this texture.
-
-	FTType mFTType; // What category of image is this - map tile, server bake, etc?
-	mutable S8 mIsMissingAsset;		// True if we know that there is no image asset with this image id in the database.		
-
-	typedef std::list<LLLoadedCallbackEntry*> callback_list_t;
-	S8              mLoadedCallbackDesiredDiscardLevel;
-	BOOL            mPauseLoadedCallBacks;
-	callback_list_t mLoadedCallbackList;
-	F32             mLastCallBackActiveTime;
-
-	LLPointer<LLImageRaw> mRawImage;
-	S32 mRawDiscardLevel;
-
-	// Used ONLY for cloth meshes right now.  Make SURE you know what you're 
-	// doing if you use it for anything else! - djs
-	LLPointer<LLImageRaw> mAuxRawImage;
-
-	//keep a copy of mRawImage for some special purposes
-	//when mForceToSaveRawImage is set.
-	BOOL mForceToSaveRawImage ;
-	BOOL mSaveRawImage;
-	LLPointer<LLImageRaw> mSavedRawImage;
-	S32 mSavedRawDiscardLevel;
-	S32 mDesiredSavedRawDiscardLevel;
-	F32 mLastReferencedSavedRawImageTime ;
-	F32 mKeptSavedRawImageTime ;
-
-	//a small version of the copy of the raw image (<= 64 * 64)
-	LLPointer<LLImageRaw> mCachedRawImage;
-	S32 mCachedRawDiscardLevel;
-	BOOL mCachedRawImageReady; //the rez of the mCachedRawImage reaches the upper limit.	
-
-	LLHost mTargetHost;	// if invalid, just request from agent's simulator
-
-	// Timers
-	LLFrameTimer mLastPacketTimer;		// Time since last packet.
-	LLFrameTimer mStopFetchingTimer;	// Time since mDecodePriority == 0.f.
-
-	BOOL  mInImageList;				// TRUE if image is in list (in which case don't reset priority!)
-	BOOL  mNeedsCreateTexture;	
-
-	BOOL   mForSculpt ; //a flag if the texture is used as sculpt data.
-	BOOL   mIsFetched ; //is loaded from remote or from cache, not generated locally.
-
-public:
-	static LLPointer<LLViewerFetchedTexture> sMissingAssetImagep;	// Texture to show for an image asset that is not in the database
-	static LLPointer<LLViewerFetchedTexture> sWhiteImagep;	// Texture to show NOTHING (whiteness)
-	static LLPointer<LLViewerFetchedTexture> sDefaultImagep; // "Default" texture for error cases, the only case of fetched texture which is generated in local.
-	static LLPointer<LLViewerFetchedTexture> sSmokeImagep; // Old "Default" translucent texture
-	static LLPointer<LLViewerFetchedTexture> sFlatNormalImagep; // Flat normal map denoting no bumpiness on a surface
-};
-
-//
-//the image data is fetched from remote or from local cache
-//the resolution of the texture is adjustable: depends on the view-dependent parameters.
-//
-class LLViewerLODTexture : public LLViewerFetchedTexture
-{
-protected:
-	/*virtual*/ ~LLViewerLODTexture(){}
-
-public:
-	LLViewerLODTexture(const LLUUID& id, FTType f_type, const LLHost& host = LLHost(), BOOL usemipmaps = TRUE);
-	LLViewerLODTexture(const std::string& url, FTType f_type, const LLUUID& id, BOOL usemipmaps = TRUE);
-
-	/*virtual*/ S8 getType() const;
-	// Process image stats to determine priority/quality requirements.
-	/*virtual*/ void processTextureStats();
-	bool isUpdateFrozen() ;
-
-private:
-	void init(bool firstinit) ;
-	bool scaleDown() ;		
-
-private:
-	F32 mDiscardVirtualSize;		// Virtual size used to calculate desired discard	
-	F32 mCalculatedDiscardLevel;    // Last calculated discard level
-};
-
-//
-//the image data is fetched from the media pipeline periodically
-//the resolution of the texture is also adjusted by the media pipeline
-//
-class LLViewerMediaTexture : public LLViewerTexture
-{
-protected:
-	/*virtual*/ ~LLViewerMediaTexture() ;
-
-public:
-	LLViewerMediaTexture(const LLUUID& id, BOOL usemipmaps = TRUE, LLImageGL* gl_image = NULL) ;
-
-	/*virtual*/ S8 getType() const;
-	void reinit(BOOL usemipmaps = TRUE);	
-
-	BOOL  getUseMipMaps() {return mUseMipMaps ; }
-	void  setUseMipMaps(BOOL mipmap) ;	
-	
-	void setPlaying(BOOL playing) ;
-	BOOL isPlaying() const {return mIsPlaying;}
-	void setMediaImpl() ;
-
-    virtual bool isViewerMediaTexture() const { return true; }
-
-	void initVirtualSize() ;	
-	void invalidateMediaImpl() ;
-
-	void addMediaToFace(LLFace* facep) ;
-	void removeMediaFromFace(LLFace* facep) ;
-
-	/*virtual*/ void addFace(U32 ch, LLFace* facep) ;
-	/*virtual*/ void removeFace(U32 ch, LLFace* facep) ; 
-
-	/*virtual*/ F32  getMaxVirtualSize() ;
-private:
-	void switchTexture(U32 ch, LLFace* facep) ;
-	BOOL findFaces() ;
-	void stopPlaying() ;
-
-private:
-	//
-	//an instant list, recording all faces referencing or can reference to this media texture.
-	//NOTE: it is NOT thread safe. 
-	//
-	std::list< LLFace* > mMediaFaceList ; 
-
-	//an instant list keeping all textures which are replaced by the current media texture,
-	//is only used to avoid the removal of those textures from memory.
-	std::list< LLPointer<LLViewerTexture> > mTextureList ;
-
-	LLViewerMediaImpl* mMediaImplp ;	
-	BOOL mIsPlaying ;
-	U32  mUpdateVirtualSizeTime ;
-
-public:
-	static void updateClass() ;
-	static void cleanUpClass() ;	
-
-	static LLViewerMediaTexture* findMediaTexture(const LLUUID& media_id) ;
-	static void removeMediaImplFromTexture(const LLUUID& media_id) ;
-
-private:
-	typedef std::map< LLUUID, LLPointer<LLViewerMediaTexture> > media_map_t ;
-	static media_map_t sMediaMap ;	
-};
-
-//just an interface class, do not create instance from this class.
-class LLViewerTextureManager
-{
-private:
-	//make the constructor private to preclude creating instances from this class.
-	LLViewerTextureManager(){}
-
-public:
-    //texture pipeline tester
-	static LLTexturePipelineTester* sTesterp ;
-
-	//returns NULL if tex is not a LLViewerFetchedTexture nor derived from LLViewerFetchedTexture.
-	static LLViewerFetchedTexture*    staticCastToFetchedTexture(LLTexture* tex, BOOL report_error = FALSE) ;
-
-	//
-	//"find-texture" just check if the texture exists, if yes, return it, otherwise return null.
-	//
-	static void                       findFetchedTextures(const LLUUID& id, std::vector<LLViewerFetchedTexture*> &output);
-	static void                       findTextures(const LLUUID& id, std::vector<LLViewerTexture*> &output);
-	static LLViewerFetchedTexture*    findFetchedTexture(const LLUUID& id, S32 tex_type);
-	static LLViewerMediaTexture*      findMediaTexture(const LLUUID& id) ;
-	
-	static LLViewerMediaTexture*      createMediaTexture(const LLUUID& id, BOOL usemipmaps = TRUE, LLImageGL* gl_image = NULL) ;
-
-	//
-	//"get-texture" will create a new texture if the texture does not exist.
-	//
-	static LLViewerMediaTexture*      getMediaTexture(const LLUUID& id, BOOL usemipmaps = TRUE, LLImageGL* gl_image = NULL) ;
-	
-	static LLPointer<LLViewerTexture> getLocalTexture(BOOL usemipmaps = TRUE, BOOL generate_gl_tex = TRUE);
-	static LLPointer<LLViewerTexture> getLocalTexture(const LLUUID& id, BOOL usemipmaps, BOOL generate_gl_tex = TRUE) ;
-	static LLPointer<LLViewerTexture> getLocalTexture(const LLImageRaw* raw, BOOL usemipmaps) ;
-	static LLPointer<LLViewerTexture> getLocalTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps, BOOL generate_gl_tex = TRUE) ;
-
-	static LLViewerFetchedTexture* getFetchedTexture(const LLUUID &image_id,									 
-									 FTType f_type = FTT_DEFAULT,
-									 BOOL usemipmap = TRUE,
-									 LLViewerTexture::EBoostLevel boost_priority = LLGLTexture::BOOST_NONE,		// Get the requested level immediately upon creation.
-									 S8 texture_type = LLViewerTexture::FETCHED_TEXTURE,
-									 LLGLint internal_format = 0,
-									 LLGLenum primary_format = 0,
-									 LLHost request_from_host = LLHost()
-									 );
-	
-	static LLViewerFetchedTexture* getFetchedTextureFromFile(const std::string& filename,									 
-									 FTType f_type = FTT_LOCAL_FILE,
-									 BOOL usemipmap = TRUE,
-									 LLViewerTexture::EBoostLevel boost_priority = LLGLTexture::BOOST_NONE,
-									 S8 texture_type = LLViewerTexture::FETCHED_TEXTURE,
-									 LLGLint internal_format = 0,
-									 LLGLenum primary_format = 0,
-									 const LLUUID& force_id = LLUUID::null
-									 );
-
-	static LLViewerFetchedTexture* getFetchedTextureFromUrl(const std::string& url,									 
-									 FTType f_type,
-									 BOOL usemipmap = TRUE,
-									 LLViewerTexture::EBoostLevel boost_priority = LLGLTexture::BOOST_NONE,
-									 S8 texture_type = LLViewerTexture::FETCHED_TEXTURE,
-									 LLGLint internal_format = 0,
-									 LLGLenum primary_format = 0,
-									 const LLUUID& force_id = LLUUID::null
-									 );
-
-	static LLViewerFetchedTexture* getFetchedTextureFromHost(const LLUUID& image_id, FTType f_type, LLHost host) ;
-
-	static void init() ;
-	static void cleanup() ;
-};
-//
-//this class is used for test/debug only
-//it tracks the activities of the texture pipeline
-//records them, and outputs them to log files
-//
-class LLTexturePipelineTester : public LLMetricPerformanceTesterWithSession
-{
-	enum
-	{
-		MIN_LARGE_IMAGE_AREA = 262144  //512 * 512
-	};
-public:
-	LLTexturePipelineTester() ;
-	~LLTexturePipelineTester() ;
-
-	void update();		
-	void updateTextureBindingStats(const LLViewerTexture* imagep) ;
-	void updateTextureLoadingStats(const LLViewerFetchedTexture* imagep, const LLImageRaw* raw_imagep, BOOL from_cache) ;
-	void updateGrayTextureBinding() ;
-	void setStablizingTime() ;
-
-private:
-	void reset() ;
-	void updateStablizingTime() ;
-
-	/*virtual*/ void outputTestRecord(LLSD* sd) ;
-
-private:
-	BOOL mPause ;
-private:
-	BOOL mUsingDefaultTexture;            //if set, some textures are still gray.
-
-	U32Bytes mTotalBytesUsed ;                     //total bytes of textures bound/used for the current frame.
-	U32Bytes mTotalBytesUsedForLargeImage ;        //total bytes of textures bound/used for the current frame for images larger than 256 * 256.
-	U32Bytes mLastTotalBytesUsed ;                 //total bytes of textures bound/used for the previous frame.
-	U32Bytes mLastTotalBytesUsedForLargeImage ;    //total bytes of textures bound/used for the previous frame for images larger than 256 * 256.
-		
-	//
-	//data size
-	//
-	U32Bytes mTotalBytesLoaded ;               //total bytes fetched by texture pipeline
-	U32Bytes mTotalBytesLoadedFromCache ;      //total bytes fetched by texture pipeline from local cache	
-	U32Bytes mTotalBytesLoadedForLargeImage ;  //total bytes fetched by texture pipeline for images larger than 256 * 256. 
-	U32Bytes mTotalBytesLoadedForSculpties ;   //total bytes fetched by texture pipeline for sculpties
-
-	//
-	//time
-	//NOTE: the error tolerances of the following timers is one frame time.
-	//
-	F32 mStartFetchingTime ;
-	F32 mTotalGrayTime ;                  //total loading time when no gray textures.
-	F32 mTotalStablizingTime ;            //total stablizing time when texture memory overflows
-	F32 mStartTimeLoadingSculpties ;      //the start moment of loading sculpty images.
-	F32 mEndTimeLoadingSculpties ;        //the end moment of loading sculpty images.
-	F32 mStartStablizingTime ;
-	F32 mEndStablizingTime ;
-
-private:
-	//
-	//The following members are used for performance analyzing
-	//
-	class LLTextureTestSession : public LLTestSession
-	{
-	public:
-		LLTextureTestSession() ;
-		/*virtual*/ ~LLTextureTestSession() ;
-
-		void reset() ;
-
-		F32 mTotalFetchingTime ;
-		F32 mTotalGrayTime ;
-		F32 mTotalStablizingTime ;
-		F32 mStartTimeLoadingSculpties ; 
-		F32 mTotalTimeLoadingSculpties ;
-
-		S32 mTotalBytesLoaded ; 
-		S32 mTotalBytesLoadedFromCache ;
-		S32 mTotalBytesLoadedForLargeImage ;
-		S32 mTotalBytesLoadedForSculpties ; 
-
-		typedef struct _texture_instant_preformance_t
-		{
-			S32 mAverageBytesUsedPerSecond ;         
-			S32 mAverageBytesUsedForLargeImagePerSecond ;
-			F32 mAveragePercentageBytesUsedPerSecond ;
-			F32 mTime ;
-		}texture_instant_preformance_t ;
-		std::vector<texture_instant_preformance_t> mInstantPerformanceList ;
-		S32 mInstantPerformanceListCounter ;
-	};
-
-	/*virtual*/ LLMetricPerformanceTesterWithSession::LLTestSession* loadTestSession(LLSD* log) ;
-	/*virtual*/ void compareTestSessions(llofstream* os) ;
-};
-
-#endif
+/** 
+ * @file llviewertexture.h
+ * @brief Object for managing images and their textures
+ *
+ * $LicenseInfo:firstyear=2000&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLVIEWERTEXTURE_H					
+#define LL_LLVIEWERTEXTURE_H
+
+#include "llgltexture.h"
+#include "lltimer.h"
+#include "llframetimer.h"
+#include "llhost.h"
+#include "llgltypes.h"
+#include "llrender.h"
+#include "llmetricperformancetester.h"
+#include "httpcommon.h"
+
+#include <map>
+#include <list>
+
+extern const S32Megabytes gMinVideoRam;
+extern const S32Megabytes gMaxVideoRam;
+
+class LLFace;
+class LLImageGL ;
+class LLImageRaw;
+class LLViewerObject;
+class LLViewerTexture;
+class LLViewerFetchedTexture ;
+class LLViewerMediaTexture ;
+class LLTexturePipelineTester ;
+
+
+typedef	void	(*loaded_callback_func)( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata );
+
+class LLVFile;
+class LLMessageSystem;
+class LLViewerMediaImpl ;
+class LLVOVolume ;
+struct LLTextureKey;
+
+class LLLoadedCallbackEntry
+{
+public:
+    typedef std::set< LLTextureKey > source_callback_list_t;
+
+public:
+	LLLoadedCallbackEntry(loaded_callback_func cb,
+						  S32 discard_level,
+						  BOOL need_imageraw, // Needs image raw for the callback
+						  void* userdata,
+						  source_callback_list_t* src_callback_list,
+						  LLViewerFetchedTexture* target,
+						  BOOL pause);
+	~LLLoadedCallbackEntry();
+	void removeTexture(LLViewerFetchedTexture* tex) ;
+
+	loaded_callback_func	mCallback;
+	S32						mLastUsedDiscard;
+	S32						mDesiredDiscard;
+	BOOL					mNeedsImageRaw;
+	BOOL                    mPaused;
+	void*					mUserData;
+	source_callback_list_t* mSourceCallbackList;
+	
+public:
+	static void cleanUpCallbackList(LLLoadedCallbackEntry::source_callback_list_t* callback_list) ;
+};
+
+class LLTextureBar;
+
+class LLViewerTexture : public LLGLTexture
+{
+public:
+	enum
+	{
+		LOCAL_TEXTURE,		
+		MEDIA_TEXTURE,
+		DYNAMIC_TEXTURE,
+		FETCHED_TEXTURE,
+		LOD_TEXTURE,
+		ATLAS_TEXTURE,
+		INVALID_TEXTURE_TYPE
+	};
+
+	typedef std::vector<class LLFace*> ll_face_list_t;
+	typedef std::vector<LLVOVolume*> ll_volume_list_t;
+
+
+protected:
+	virtual ~LLViewerTexture();
+	LOG_CLASS(LLViewerTexture);
+
+public:	
+	static void initClass();
+	static void updateClass(const F32 velocity, const F32 angular_velocity) ;
+	
+	LLViewerTexture(BOOL usemipmaps = TRUE);
+	LLViewerTexture(const LLUUID& id, BOOL usemipmaps) ;
+	LLViewerTexture(const LLImageRaw* raw, BOOL usemipmaps) ;
+	LLViewerTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps) ;
+
+	virtual S8 getType() const;
+	virtual BOOL isMissingAsset() const ;
+	virtual void dump();	// debug info to LL_INFOS()
+	
+    virtual bool isViewerMediaTexture() const { return false; }
+
+	/*virtual*/ bool bindDefaultImage(const S32 stage = 0) ;
+	/*virtual*/ bool bindDebugImage(const S32 stage = 0) ;
+	/*virtual*/ void forceImmediateUpdate() ;
+	/*virtual*/ bool isActiveFetching();
+	
+	/*virtual*/ const LLUUID& getID() const { return mID; }
+	void setBoostLevel(S32 level);
+	S32  getBoostLevel() { return mBoostLevel; }
+	void setTextureListType(S32 tex_type) { mTextureListType = tex_type; }
+	S32 getTextureListType() { return mTextureListType; }
+
+	void addTextureStats(F32 virtual_size, BOOL needs_gltexture = TRUE) const;
+	void resetTextureStats();	
+	void setMaxVirtualSizeResetInterval(S32 interval)const {mMaxVirtualSizeResetInterval = interval;}
+	void resetMaxVirtualSizeResetCounter()const {mMaxVirtualSizeResetCounter = mMaxVirtualSizeResetInterval;}
+	S32 getMaxVirtualSizeResetCounter() const { return mMaxVirtualSizeResetCounter; }
+
+	virtual F32  getMaxVirtualSize() ;
+
+	LLFrameTimer* getLastReferencedTimer() {return &mLastReferencedTimer ;}
+	
+	S32 getFullWidth() const { return mFullWidth; }
+	S32 getFullHeight() const { return mFullHeight; }	
+	/*virtual*/ void setKnownDrawSize(S32 width, S32 height);
+
+	virtual void addFace(U32 channel, LLFace* facep) ;
+	virtual void removeFace(U32 channel, LLFace* facep) ; 
+	S32 getTotalNumFaces() const;
+	S32 getNumFaces(U32 ch) const;
+	const ll_face_list_t* getFaceList(U32 channel) const {llassert(channel < LLRender::NUM_TEXTURE_CHANNELS); return &mFaceList[channel];}
+
+	virtual void addVolume(U32 channel, LLVOVolume* volumep);
+	virtual void removeVolume(U32 channel, LLVOVolume* volumep);
+	S32 getNumVolumes(U32 channel) const;
+	const ll_volume_list_t* getVolumeList(U32 channel) const { return &mVolumeList[channel]; }
+
+	
+	virtual void setCachedRawImage(S32 discard_level, LLImageRaw* imageraw) ;
+	BOOL isLargeImage() ;	
+	
+	void setParcelMedia(LLViewerMediaTexture* media) {mParcelMedia = media;}
+	BOOL hasParcelMedia() const { return mParcelMedia != NULL;}
+	LLViewerMediaTexture* getParcelMedia() const { return mParcelMedia;}
+
+	/*virtual*/ void updateBindStatsForTester() ;
+protected:
+	void cleanup() ;
+	void init(bool firstinit) ;
+	void reorganizeFaceList() ;
+	void reorganizeVolumeList() ;
+
+	void notifyAboutMissingAsset();
+	void notifyAboutCreatingTexture();
+
+private:
+	friend class LLBumpImageList;
+	friend class LLUIImageList;
+
+	virtual void switchToCachedImage();
+	
+	static bool isMemoryForTextureLow() ;
+	static bool isMemoryForTextureSuficientlyFree();
+	static void getGPUMemoryForTextures(S32Megabytes &gpu, S32Megabytes &physical);
+
+protected:
+	LLUUID mID;
+	S32 mTextureListType; // along with mID identifies where to search for this texture in TextureList
+
+	F32 mSelectedTime;				// time texture was last selected
+	mutable F32 mMaxVirtualSize;	// The largest virtual size of the image, in pixels - how much data to we need?	
+	mutable S32  mMaxVirtualSizeResetCounter ;
+	mutable S32  mMaxVirtualSizeResetInterval;
+	mutable F32 mAdditionalDecodePriority;  // priority add to mDecodePriority.
+	LLFrameTimer mLastReferencedTimer;	
+
+	ll_face_list_t    mFaceList[LLRender::NUM_TEXTURE_CHANNELS]; //reverse pointer pointing to the faces using this image as texture
+	U32               mNumFaces[LLRender::NUM_TEXTURE_CHANNELS];
+	LLFrameTimer      mLastFaceListUpdateTimer ;
+
+	ll_volume_list_t  mVolumeList[LLRender::NUM_VOLUME_TEXTURE_CHANNELS];
+	U32					mNumVolumes[LLRender::NUM_VOLUME_TEXTURE_CHANNELS];
+	LLFrameTimer	  mLastVolumeListUpdateTimer;
+
+	//do not use LLPointer here.
+	LLViewerMediaTexture* mParcelMedia ;
+
+	static F32 sTexelPixelRatio;
+public:
+	static const U32 sCurrentFileVersion;	
+	static S32 sImageCount;
+	static S32 sRawCount;
+	static S32 sAuxCount;
+	static LLFrameTimer sEvaluationTimer;
+	static F32 sDesiredDiscardBias;
+	static F32 sDesiredDiscardScale;
+	static S32Bytes sBoundTextureMemory;
+	static S32Bytes sTotalTextureMemory;
+	static S32Megabytes sMaxBoundTextureMemory;
+	static S32Megabytes sMaxTotalTextureMem;
+	static S32Bytes sMaxDesiredTextureMem ;
+	static S8  sCameraMovingDiscardBias;
+	static F32 sCameraMovingBias;
+	static S32 sMaxSculptRez ;
+	static U32 sMinLargeImageSize ;
+	static U32 sMaxSmallImageSize ;
+	static bool sFreezeImageUpdates;
+	static F32  sCurrentTime ;
+
+	enum EDebugTexels
+	{
+		DEBUG_TEXELS_OFF,
+		DEBUG_TEXELS_CURRENT,
+		DEBUG_TEXELS_DESIRED,
+		DEBUG_TEXELS_FULL
+	};
+
+	static EDebugTexels sDebugTexelsMode;
+
+	static LLPointer<LLViewerTexture> sNullImagep; // Null texture for non-textured objects.
+	static LLPointer<LLViewerTexture> sBlackImagep;	// Texture to show NOTHING (pure black)
+	static LLPointer<LLViewerTexture> sCheckerBoardImagep;	// Texture to show NOTHING (pure black)
+};
+
+
+enum FTType
+{
+	FTT_UNKNOWN = -1,
+	FTT_DEFAULT = 0, // standard texture fetched by id.
+	FTT_SERVER_BAKE, // texture produced by appearance service and fetched from there.
+	FTT_HOST_BAKE, // old-style baked texture uploaded by viewer and fetched from avatar's host.
+	FTT_MAP_TILE, // tiles are fetched from map server directly.
+	FTT_LOCAL_FILE // fetch directly from a local file.
+};
+
+const std::string& fttype_to_string(const FTType& fttype);
+
+//
+//textures are managed in gTextureList.
+//raw image data is fetched from remote or local cache
+//but the raw image this texture pointing to is fixed.
+//
+class LLViewerFetchedTexture : public LLViewerTexture
+{
+	friend class LLTextureBar; // debug info only
+	friend class LLTextureView; // debug info only
+
+protected:
+	/*virtual*/ ~LLViewerFetchedTexture();
+public:
+	LLViewerFetchedTexture(const LLUUID& id, FTType f_type, const LLHost& host = LLHost(), BOOL usemipmaps = TRUE);
+	LLViewerFetchedTexture(const LLImageRaw* raw, FTType f_type, BOOL usemipmaps);
+	LLViewerFetchedTexture(const std::string& url, FTType f_type, const LLUUID& id, BOOL usemipmaps = TRUE);
+
+public:
+	static F32 maxDecodePriority();
+	
+	struct Compare
+	{
+		// lhs < rhs
+		bool operator()(const LLPointer<LLViewerFetchedTexture> &lhs, const LLPointer<LLViewerFetchedTexture> &rhs) const
+		{
+			const LLViewerFetchedTexture* lhsp = (const LLViewerFetchedTexture*)lhs;
+			const LLViewerFetchedTexture* rhsp = (const LLViewerFetchedTexture*)rhs;
+			// greater priority is "less"
+			const F32 lpriority = lhsp->getDecodePriority();
+			const F32 rpriority = rhsp->getDecodePriority();
+			if (lpriority > rpriority) // higher priority
+				return true;
+			if (lpriority < rpriority)
+				return false;
+			return lhsp < rhsp;
+		}
+	};
+
+public:
+	/*virtual*/ S8 getType() const ;
+	FTType getFTType() const;
+	/*virtual*/ void forceImmediateUpdate() ;
+	/*virtual*/ void dump() ;
+
+	// Set callbacks to get called when the image gets updated with higher 
+	// resolution versions.
+	void setLoadedCallback(loaded_callback_func cb,
+						   S32 discard_level, BOOL keep_imageraw, BOOL needs_aux,
+						   void* userdata, LLLoadedCallbackEntry::source_callback_list_t* src_callback_list, BOOL pause = FALSE);
+	bool hasCallbacks() { return mLoadedCallbackList.empty() ? false : true; }	
+	void pauseLoadedCallbacks(const LLLoadedCallbackEntry::source_callback_list_t* callback_list);
+	void unpauseLoadedCallbacks(const LLLoadedCallbackEntry::source_callback_list_t* callback_list);
+	bool doLoadedCallbacks();
+	void deleteCallbackEntry(const LLLoadedCallbackEntry::source_callback_list_t* callback_list);
+	void clearCallbackEntryList() ;
+
+	void addToCreateTexture();
+
+    //call to determine if createTexture is necessary
+    BOOL preCreateTexture(S32 usename = 0);
+	 // ONLY call from LLViewerTextureList or ImageGL background thread
+	BOOL createTexture(S32 usename = 0);
+    void postCreateTexture();
+    void scheduleCreateTexture();
+
+	void destroyTexture() ;
+
+	virtual void processTextureStats() ;
+	F32  calcDecodePriority() ;
+
+	BOOL needsAux() const { return mNeedsAux; }
+
+	// Host we think might have this image, used for baked av textures.
+	void setTargetHost(LLHost host)			{ mTargetHost = host; }
+	LLHost getTargetHost() const			{ return mTargetHost; }
+	
+	// Set the decode priority for this image...
+	// DON'T CALL THIS UNLESS YOU KNOW WHAT YOU'RE DOING, it can mess up
+	// the priority list, and cause horrible things to happen.
+	void setDecodePriority(F32 priority = -1.0f);
+	F32 getDecodePriority() const { return mDecodePriority; };
+	F32 getAdditionalDecodePriority() const { return mAdditionalDecodePriority; };
+
+	void setAdditionalDecodePriority(F32 priority) ;
+	
+	void updateVirtualSize() ;
+
+	S32  getDesiredDiscardLevel()			 { return mDesiredDiscardLevel; }
+	void setMinDiscardLevel(S32 discard) 	{ mMinDesiredDiscardLevel = llmin(mMinDesiredDiscardLevel,(S8)discard); }
+
+	bool updateFetch();
+	bool setDebugFetching(S32 debug_level);
+	bool isInDebug() const { return mInDebug; }
+
+	void setUnremovable(BOOL value) { mUnremovable = value; }
+	bool isUnremovable() const { return mUnremovable; }
+	
+	void clearFetchedResults(); //clear all fetched results, for debug use.
+
+	// Override the computation of discard levels if we know the exact output
+	// size of the image.  Used for UI textures to not decode, even if we have
+	// more data.
+	/*virtual*/ void setKnownDrawSize(S32 width, S32 height);
+
+	void setIsMissingAsset(BOOL is_missing = true);
+	/*virtual*/ BOOL isMissingAsset() const { return mIsMissingAsset; }
+
+	// returns dimensions of original image for local files (before power of two scaling)
+	// and returns 0 for all asset system images
+	S32 getOriginalWidth() { return mOrigWidth; }
+	S32 getOriginalHeight() { return mOrigHeight; }
+
+	BOOL isInImageList() const {return mInImageList ;}
+	void setInImageList(BOOL flag) {mInImageList = flag ;}
+
+	LLFrameTimer* getLastPacketTimer() {return &mLastPacketTimer;}
+
+	U32 getFetchPriority() const { return mFetchPriority ;}
+	F32 getDownloadProgress() const {return mDownloadProgress ;}
+
+	LLImageRaw* reloadRawImage(S8 discard_level) ;
+	void destroyRawImage();
+	bool needsToSaveRawImage();
+
+	const std::string& getUrl() const {return mUrl;}
+	//---------------
+	BOOL isDeleted() ;
+	BOOL isInactive() ;
+	BOOL isDeletionCandidate();
+	void setDeletionCandidate() ;
+	void setInactive() ;
+	BOOL getUseDiscard() const { return mUseMipMaps && !mDontDiscard; }	
+	//---------------
+
+	void setForSculpt();
+	BOOL forSculpt() const {return mForSculpt;}
+	BOOL isForSculptOnly() const;
+
+	//raw image management	
+	void        checkCachedRawSculptImage() ;
+	LLImageRaw* getRawImage()const { return mRawImage ;}
+	S32         getRawImageLevel() const {return mRawDiscardLevel;}
+	LLImageRaw* getCachedRawImage() const { return mCachedRawImage ;}
+	S32         getCachedRawImageLevel() const {return mCachedRawDiscardLevel;}
+	BOOL        isCachedRawImageReady() const {return mCachedRawImageReady ;}
+	BOOL        isRawImageValid()const { return mIsRawImageValid ; }	
+	void        forceToSaveRawImage(S32 desired_discard = 0, F32 kept_time = 0.f) ;
+	void        forceToRefetchTexture(S32 desired_discard = 0, F32 kept_time = 60.f);
+	/*virtual*/ void setCachedRawImage(S32 discard_level, LLImageRaw* imageraw) ;
+	void        destroySavedRawImage() ;
+	LLImageRaw* getSavedRawImage() ;
+	BOOL        hasSavedRawImage() const ;
+	F32         getElapsedLastReferencedSavedRawImageTime() const ;
+	BOOL		isFullyLoaded() const;
+
+	BOOL        hasFetcher() const { return mHasFetcher;}
+	void        setCanUseHTTP(bool can_use_http) {mCanUseHTTP = can_use_http;}
+
+	void        forceToDeleteRequest();
+	void        loadFromFastCache();
+	void        setInFastCacheList(bool in_list) { mInFastCacheList = in_list; }
+	bool        isInFastCacheList() { return mInFastCacheList; }
+
+	/*virtual*/bool  isActiveFetching(); //is actively in fetching by the fetching pipeline.
+
+protected:
+	/*virtual*/ void switchToCachedImage();
+	S32 getCurrentDiscardLevelForFetching() ;
+
+private:
+	void init(bool firstinit) ;	
+	void cleanup() ;
+
+	void saveRawImage() ;
+	void setCachedRawImage() ;
+
+	//for atlas
+	void resetFaceAtlas() ;
+	void invalidateAtlas(BOOL rebuild_geom) ;
+	BOOL insertToAtlas() ;
+
+private:
+	BOOL  mFullyLoaded;
+	BOOL  mInDebug;
+	BOOL  mUnremovable;
+	BOOL  mInFastCacheList;
+	BOOL  mForceCallbackFetch;
+
+protected:		
+	std::string mLocalFileName;
+
+	S32 mOrigWidth;
+	S32 mOrigHeight;
+
+	// Override the computation of discard levels if we know the exact output size of the image.
+	// Used for UI textures to not decode, even if we have more data.
+	S32 mKnownDrawWidth;
+	S32	mKnownDrawHeight;
+	BOOL mKnownDrawSizeChanged ;
+	std::string mUrl;
+	
+	S32 mRequestedDiscardLevel;
+	F32 mRequestedDownloadPriority;
+	S32 mFetchState;
+	U32 mFetchPriority;
+	F32 mDownloadProgress;
+	F32 mFetchDeltaTime;
+	F32 mRequestDeltaTime;
+	F32 mDecodePriority;			// The priority for decoding this image.
+	S32	mMinDiscardLevel;
+	S8  mDesiredDiscardLevel;			// The discard level we'd LIKE to have - if we have it and there's space	
+	S8  mMinDesiredDiscardLevel;	// The minimum discard level we'd like to have
+
+	S8  mNeedsAux;					// We need to decode the auxiliary channels
+	S8  mHasAux;                    // We have aux channels
+	S8  mDecodingAux;				// Are we decoding high components
+	S8  mIsRawImageValid;
+	S8  mHasFetcher;				// We've made a fecth request
+	S8  mIsFetching;				// Fetch request is active
+	bool mCanUseHTTP;              //This texture can be fetched through http if true.
+	LLCore::HttpStatus mLastHttpGetStatus; // Result of the most recently completed http request for this texture.
+
+	FTType mFTType; // What category of image is this - map tile, server bake, etc?
+	mutable S8 mIsMissingAsset;		// True if we know that there is no image asset with this image id in the database.		
+
+	typedef std::list<LLLoadedCallbackEntry*> callback_list_t;
+	S8              mLoadedCallbackDesiredDiscardLevel;
+	BOOL            mPauseLoadedCallBacks;
+	callback_list_t mLoadedCallbackList;
+	F32             mLastCallBackActiveTime;
+
+	LLPointer<LLImageRaw> mRawImage;
+	S32 mRawDiscardLevel;
+
+	// Used ONLY for cloth meshes right now.  Make SURE you know what you're 
+	// doing if you use it for anything else! - djs
+	LLPointer<LLImageRaw> mAuxRawImage;
+
+	//keep a copy of mRawImage for some special purposes
+	//when mForceToSaveRawImage is set.
+	BOOL mForceToSaveRawImage ;
+	BOOL mSaveRawImage;
+	LLPointer<LLImageRaw> mSavedRawImage;
+	S32 mSavedRawDiscardLevel;
+	S32 mDesiredSavedRawDiscardLevel;
+	F32 mLastReferencedSavedRawImageTime ;
+	F32 mKeptSavedRawImageTime ;
+
+	//a small version of the copy of the raw image (<= 64 * 64)
+	LLPointer<LLImageRaw> mCachedRawImage;
+	S32 mCachedRawDiscardLevel;
+	BOOL mCachedRawImageReady; //the rez of the mCachedRawImage reaches the upper limit.	
+
+	LLHost mTargetHost;	// if invalid, just request from agent's simulator
+
+	// Timers
+	LLFrameTimer mLastPacketTimer;		// Time since last packet.
+	LLFrameTimer mStopFetchingTimer;	// Time since mDecodePriority == 0.f.
+
+	BOOL  mInImageList;				// TRUE if image is in list (in which case don't reset priority!)
+	BOOL  mNeedsCreateTexture;	
+
+	BOOL   mForSculpt ; //a flag if the texture is used as sculpt data.
+	BOOL   mIsFetched ; //is loaded from remote or from cache, not generated locally.
+
+public:
+	static LLPointer<LLViewerFetchedTexture> sMissingAssetImagep;	// Texture to show for an image asset that is not in the database
+	static LLPointer<LLViewerFetchedTexture> sWhiteImagep;	// Texture to show NOTHING (whiteness)
+	static LLPointer<LLViewerFetchedTexture> sDefaultImagep; // "Default" texture for error cases, the only case of fetched texture which is generated in local.
+	static LLPointer<LLViewerFetchedTexture> sSmokeImagep; // Old "Default" translucent texture
+	static LLPointer<LLViewerFetchedTexture> sFlatNormalImagep; // Flat normal map denoting no bumpiness on a surface
+};
+
+//
+//the image data is fetched from remote or from local cache
+//the resolution of the texture is adjustable: depends on the view-dependent parameters.
+//
+class LLViewerLODTexture : public LLViewerFetchedTexture
+{
+protected:
+	/*virtual*/ ~LLViewerLODTexture(){}
+
+public:
+	LLViewerLODTexture(const LLUUID& id, FTType f_type, const LLHost& host = LLHost(), BOOL usemipmaps = TRUE);
+	LLViewerLODTexture(const std::string& url, FTType f_type, const LLUUID& id, BOOL usemipmaps = TRUE);
+
+	/*virtual*/ S8 getType() const;
+	// Process image stats to determine priority/quality requirements.
+	/*virtual*/ void processTextureStats();
+	bool isUpdateFrozen() ;
+
+private:
+	void init(bool firstinit) ;
+	bool scaleDown() ;		
+
+private:
+	F32 mDiscardVirtualSize;		// Virtual size used to calculate desired discard	
+	F32 mCalculatedDiscardLevel;    // Last calculated discard level
+};
+
+//
+//the image data is fetched from the media pipeline periodically
+//the resolution of the texture is also adjusted by the media pipeline
+//
+class LLViewerMediaTexture : public LLViewerTexture
+{
+protected:
+	/*virtual*/ ~LLViewerMediaTexture() ;
+
+public:
+	LLViewerMediaTexture(const LLUUID& id, BOOL usemipmaps = TRUE, LLImageGL* gl_image = NULL) ;
+
+	/*virtual*/ S8 getType() const;
+	void reinit(BOOL usemipmaps = TRUE);	
+
+	BOOL  getUseMipMaps() {return mUseMipMaps ; }
+	void  setUseMipMaps(BOOL mipmap) ;	
+	
+	void setPlaying(BOOL playing) ;
+	BOOL isPlaying() const {return mIsPlaying;}
+	void setMediaImpl() ;
+
+    virtual bool isViewerMediaTexture() const { return true; }
+
+	void initVirtualSize() ;	
+	void invalidateMediaImpl() ;
+
+	void addMediaToFace(LLFace* facep) ;
+	void removeMediaFromFace(LLFace* facep) ;
+
+	/*virtual*/ void addFace(U32 ch, LLFace* facep) ;
+	/*virtual*/ void removeFace(U32 ch, LLFace* facep) ; 
+
+	/*virtual*/ F32  getMaxVirtualSize() ;
+private:
+	void switchTexture(U32 ch, LLFace* facep) ;
+	BOOL findFaces() ;
+	void stopPlaying() ;
+
+private:
+	//
+	//an instant list, recording all faces referencing or can reference to this media texture.
+	//NOTE: it is NOT thread safe. 
+	//
+	std::list< LLFace* > mMediaFaceList ; 
+
+	//an instant list keeping all textures which are replaced by the current media texture,
+	//is only used to avoid the removal of those textures from memory.
+	std::list< LLPointer<LLViewerTexture> > mTextureList ;
+
+	LLViewerMediaImpl* mMediaImplp ;	
+	BOOL mIsPlaying ;
+	U32  mUpdateVirtualSizeTime ;
+
+public:
+	static void updateClass() ;
+	static void cleanUpClass() ;	
+
+	static LLViewerMediaTexture* findMediaTexture(const LLUUID& media_id) ;
+	static void removeMediaImplFromTexture(const LLUUID& media_id) ;
+
+private:
+	typedef std::map< LLUUID, LLPointer<LLViewerMediaTexture> > media_map_t ;
+	static media_map_t sMediaMap ;	
+};
+
+//just an interface class, do not create instance from this class.
+class LLViewerTextureManager
+{
+private:
+	//make the constructor private to preclude creating instances from this class.
+	LLViewerTextureManager(){}
+
+public:
+    //texture pipeline tester
+	static LLTexturePipelineTester* sTesterp ;
+
+	//returns NULL if tex is not a LLViewerFetchedTexture nor derived from LLViewerFetchedTexture.
+	static LLViewerFetchedTexture*    staticCastToFetchedTexture(LLTexture* tex, BOOL report_error = FALSE) ;
+
+	//
+	//"find-texture" just check if the texture exists, if yes, return it, otherwise return null.
+	//
+	static void                       findFetchedTextures(const LLUUID& id, std::vector<LLViewerFetchedTexture*> &output);
+	static void                       findTextures(const LLUUID& id, std::vector<LLViewerTexture*> &output);
+	static LLViewerFetchedTexture*    findFetchedTexture(const LLUUID& id, S32 tex_type);
+	static LLViewerMediaTexture*      findMediaTexture(const LLUUID& id) ;
+	
+	static LLViewerMediaTexture*      createMediaTexture(const LLUUID& id, BOOL usemipmaps = TRUE, LLImageGL* gl_image = NULL) ;
+
+	//
+	//"get-texture" will create a new texture if the texture does not exist.
+	//
+	static LLViewerMediaTexture*      getMediaTexture(const LLUUID& id, BOOL usemipmaps = TRUE, LLImageGL* gl_image = NULL) ;
+	
+	static LLPointer<LLViewerTexture> getLocalTexture(BOOL usemipmaps = TRUE, BOOL generate_gl_tex = TRUE);
+	static LLPointer<LLViewerTexture> getLocalTexture(const LLUUID& id, BOOL usemipmaps, BOOL generate_gl_tex = TRUE) ;
+	static LLPointer<LLViewerTexture> getLocalTexture(const LLImageRaw* raw, BOOL usemipmaps) ;
+	static LLPointer<LLViewerTexture> getLocalTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps, BOOL generate_gl_tex = TRUE) ;
+
+	static LLViewerFetchedTexture* getFetchedTexture(const LLUUID &image_id,									 
+									 FTType f_type = FTT_DEFAULT,
+									 BOOL usemipmap = TRUE,
+									 LLViewerTexture::EBoostLevel boost_priority = LLGLTexture::BOOST_NONE,		// Get the requested level immediately upon creation.
+									 S8 texture_type = LLViewerTexture::FETCHED_TEXTURE,
+									 LLGLint internal_format = 0,
+									 LLGLenum primary_format = 0,
+									 LLHost request_from_host = LLHost()
+									 );
+	
+	static LLViewerFetchedTexture* getFetchedTextureFromFile(const std::string& filename,									 
+									 FTType f_type = FTT_LOCAL_FILE,
+									 BOOL usemipmap = TRUE,
+									 LLViewerTexture::EBoostLevel boost_priority = LLGLTexture::BOOST_NONE,
+									 S8 texture_type = LLViewerTexture::FETCHED_TEXTURE,
+									 LLGLint internal_format = 0,
+									 LLGLenum primary_format = 0,
+									 const LLUUID& force_id = LLUUID::null
+									 );
+
+	static LLViewerFetchedTexture* getFetchedTextureFromUrl(const std::string& url,									 
+									 FTType f_type,
+									 BOOL usemipmap = TRUE,
+									 LLViewerTexture::EBoostLevel boost_priority = LLGLTexture::BOOST_NONE,
+									 S8 texture_type = LLViewerTexture::FETCHED_TEXTURE,
+									 LLGLint internal_format = 0,
+									 LLGLenum primary_format = 0,
+									 const LLUUID& force_id = LLUUID::null
+									 );
+
+	static LLViewerFetchedTexture* getFetchedTextureFromHost(const LLUUID& image_id, FTType f_type, LLHost host) ;
+
+	static void init() ;
+	static void cleanup() ;
+};
+//
+//this class is used for test/debug only
+//it tracks the activities of the texture pipeline
+//records them, and outputs them to log files
+//
+class LLTexturePipelineTester : public LLMetricPerformanceTesterWithSession
+{
+	enum
+	{
+		MIN_LARGE_IMAGE_AREA = 262144  //512 * 512
+	};
+public:
+	LLTexturePipelineTester() ;
+	~LLTexturePipelineTester() ;
+
+	void update();		
+	void updateTextureBindingStats(const LLViewerTexture* imagep) ;
+	void updateTextureLoadingStats(const LLViewerFetchedTexture* imagep, const LLImageRaw* raw_imagep, BOOL from_cache) ;
+	void updateGrayTextureBinding() ;
+	void setStablizingTime() ;
+
+private:
+	void reset() ;
+	void updateStablizingTime() ;
+
+	/*virtual*/ void outputTestRecord(LLSD* sd) ;
+
+private:
+	BOOL mPause ;
+private:
+	BOOL mUsingDefaultTexture;            //if set, some textures are still gray.
+
+	U32Bytes mTotalBytesUsed ;                     //total bytes of textures bound/used for the current frame.
+	U32Bytes mTotalBytesUsedForLargeImage ;        //total bytes of textures bound/used for the current frame for images larger than 256 * 256.
+	U32Bytes mLastTotalBytesUsed ;                 //total bytes of textures bound/used for the previous frame.
+	U32Bytes mLastTotalBytesUsedForLargeImage ;    //total bytes of textures bound/used for the previous frame for images larger than 256 * 256.
+		
+	//
+	//data size
+	//
+	U32Bytes mTotalBytesLoaded ;               //total bytes fetched by texture pipeline
+	U32Bytes mTotalBytesLoadedFromCache ;      //total bytes fetched by texture pipeline from local cache	
+	U32Bytes mTotalBytesLoadedForLargeImage ;  //total bytes fetched by texture pipeline for images larger than 256 * 256. 
+	U32Bytes mTotalBytesLoadedForSculpties ;   //total bytes fetched by texture pipeline for sculpties
+
+	//
+	//time
+	//NOTE: the error tolerances of the following timers is one frame time.
+	//
+	F32 mStartFetchingTime ;
+	F32 mTotalGrayTime ;                  //total loading time when no gray textures.
+	F32 mTotalStablizingTime ;            //total stablizing time when texture memory overflows
+	F32 mStartTimeLoadingSculpties ;      //the start moment of loading sculpty images.
+	F32 mEndTimeLoadingSculpties ;        //the end moment of loading sculpty images.
+	F32 mStartStablizingTime ;
+	F32 mEndStablizingTime ;
+
+private:
+	//
+	//The following members are used for performance analyzing
+	//
+	class LLTextureTestSession : public LLTestSession
+	{
+	public:
+		LLTextureTestSession() ;
+		/*virtual*/ ~LLTextureTestSession() ;
+
+		void reset() ;
+
+		F32 mTotalFetchingTime ;
+		F32 mTotalGrayTime ;
+		F32 mTotalStablizingTime ;
+		F32 mStartTimeLoadingSculpties ; 
+		F32 mTotalTimeLoadingSculpties ;
+
+		S32 mTotalBytesLoaded ; 
+		S32 mTotalBytesLoadedFromCache ;
+		S32 mTotalBytesLoadedForLargeImage ;
+		S32 mTotalBytesLoadedForSculpties ; 
+
+		typedef struct _texture_instant_preformance_t
+		{
+			S32 mAverageBytesUsedPerSecond ;         
+			S32 mAverageBytesUsedForLargeImagePerSecond ;
+			F32 mAveragePercentageBytesUsedPerSecond ;
+			F32 mTime ;
+		}texture_instant_preformance_t ;
+		std::vector<texture_instant_preformance_t> mInstantPerformanceList ;
+		S32 mInstantPerformanceListCounter ;
+	};
+
+	/*virtual*/ LLMetricPerformanceTesterWithSession::LLTestSession* loadTestSession(LLSD* log) ;
+	/*virtual*/ void compareTestSessions(llofstream* os) ;
+};
+
+#endif
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index ce73037006fe3a01d1476f94404e3c100739f012..7dc7b339387e3ea15e9e9a050394a7438c05b660 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -1516,8 +1516,15 @@ BOOL LLViewerWindow::handleCloseRequest(LLWindow *window)
 
 void LLViewerWindow::handleQuit(LLWindow *window)
 {
-	LL_INFOS() << "Window forced quit" << LL_ENDL;
-	LLAppViewer::instance()->forceQuit();
+	if (gNonInteractive)
+	{
+		LLAppViewer::instance()->requestQuit();
+	}
+	else
+	{
+		LL_INFOS() << "Window forced quit" << LL_ENDL;
+		LLAppViewer::instance()->forceQuit();
+	}
 }
 
 void LLViewerWindow::handleResize(LLWindow *window,  S32 width,  S32 height)
@@ -2189,6 +2196,14 @@ void LLViewerWindow::initBase()
 
 void LLViewerWindow::initWorldUI()
 {
+	if (gNonInteractive)
+	{
+		gIMMgr = LLIMMgr::getInstance();
+		LLNavigationBar::getInstance();
+		gFloaterView->pushVisibleAll(FALSE);
+		return;
+	}
+	
 	S32 height = mRootView->getRect().getHeight();
 	S32 width = mRootView->getRect().getWidth();
 	LLRect full_window(0, height, width, 0);
@@ -2199,12 +2214,15 @@ void LLViewerWindow::initWorldUI()
 	//getRootView()->sendChildToFront(gFloaterView);
 	//getRootView()->sendChildToFront(gSnapshotFloaterView);
 
-	LLPanel* chiclet_container = getRootView()->getChild<LLPanel>("chiclet_container");
-	LLChicletBar* chiclet_bar = LLChicletBar::getInstance();
-	chiclet_bar->setShape(chiclet_container->getLocalRect());
-	chiclet_bar->setFollowsAll();
-	chiclet_container->addChild(chiclet_bar);
-	chiclet_container->setVisible(TRUE);
+	if (!gNonInteractive)
+	{
+		LLPanel* chiclet_container = getRootView()->getChild<LLPanel>("chiclet_container");
+		LLChicletBar* chiclet_bar = LLChicletBar::getInstance();
+		chiclet_bar->setShape(chiclet_container->getLocalRect());
+		chiclet_bar->setFollowsAll();
+		chiclet_container->addChild(chiclet_bar);
+		chiclet_container->setVisible(TRUE);
+	}
 
 	LLRect morph_view_rect = full_window;
 	morph_view_rect.stretch( -STATUS_BAR_HEIGHT );
@@ -2293,21 +2311,24 @@ void LLViewerWindow::initWorldUI()
 		gToolBarView->setVisible(TRUE);
 	}
 
-	LLMediaCtrl* destinations = LLFloaterReg::getInstance("destinations")->getChild<LLMediaCtrl>("destination_guide_contents");
-	if (destinations)
-	{
-		destinations->setErrorPageURL(gSavedSettings.getString("GenericErrorPageURL"));
-		std::string url = gSavedSettings.getString("DestinationGuideURL");
-		url = LLWeb::expandURLSubstitutions(url, LLSD());
-		destinations->navigateTo(url, HTTP_CONTENT_TEXT_HTML);
-	}
-	LLMediaCtrl* avatar_picker = LLFloaterReg::getInstance("avatar")->findChild<LLMediaCtrl>("avatar_picker_contents");
-	if (avatar_picker)
+	if (!gNonInteractive)
 	{
-		avatar_picker->setErrorPageURL(gSavedSettings.getString("GenericErrorPageURL"));
-		std::string url = gSavedSettings.getString("AvatarPickerURL");
-		url = LLWeb::expandURLSubstitutions(url, LLSD());
-		avatar_picker->navigateTo(url, HTTP_CONTENT_TEXT_HTML);
+		LLMediaCtrl* destinations = LLFloaterReg::getInstance("destinations")->getChild<LLMediaCtrl>("destination_guide_contents");
+		if (destinations)
+		{
+			destinations->setErrorPageURL(gSavedSettings.getString("GenericErrorPageURL"));
+			std::string url = gSavedSettings.getString("DestinationGuideURL");
+			url = LLWeb::expandURLSubstitutions(url, LLSD());
+			destinations->navigateTo(url, HTTP_CONTENT_TEXT_HTML);
+		}
+		LLMediaCtrl* avatar_picker = LLFloaterReg::getInstance("avatar")->findChild<LLMediaCtrl>("avatar_picker_contents");
+		if (avatar_picker)
+		{
+			avatar_picker->setErrorPageURL(gSavedSettings.getString("GenericErrorPageURL"));
+			std::string url = gSavedSettings.getString("AvatarPickerURL");
+			url = LLWeb::expandURLSubstitutions(url, LLSD());
+			avatar_picker->navigateTo(url, HTTP_CONTENT_TEXT_HTML);
+		}
 	}
 }
 
@@ -2551,7 +2572,7 @@ void LLViewerWindow::reshape(S32 width, S32 height)
 			mWindow->setMinSize(min_window_width, min_window_height);
 
 			LLCoordScreen window_rect;
-			if (mWindow->getSize(&window_rect))
+			if (!gNonInteractive && mWindow->getSize(&window_rect))
 			{
 			// Only save size if not maximized
 				gSavedSettings.setU32("WindowWidth", window_rect.mX);
diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp
index 4d2eac8c094018b8467d06ecbf7c573d1c00742e..86fe7c19bdc03906d642e8ecc9ec3afc2d6d06ce 100644
--- a/indra/newview/llvoicevivox.cpp
+++ b/indra/newview/llvoicevivox.cpp
@@ -5358,7 +5358,9 @@ void LLVivoxVoiceClient::setVoiceEnabled(bool enabled)
 
 bool LLVivoxVoiceClient::voiceEnabled()
 {
-	return gSavedSettings.getBOOL("EnableVoiceChat") && !gSavedSettings.getBOOL("CmdLineDisableVoice");
+    return gSavedSettings.getBOOL("EnableVoiceChat") &&
+          !gSavedSettings.getBOOL("CmdLineDisableVoice") &&
+          !gNonInteractive;
 }
 
 void LLVivoxVoiceClient::setLipSyncEnabled(BOOL enabled)
diff --git a/indra/newview/llworldmapmessage.cpp b/indra/newview/llworldmapmessage.cpp
index 8be340de4c42ec8d95073e2b8e7ae8616502d80e..e4a9f9afdb5908dbab14f6d845a248e4eecde596 100644
--- a/indra/newview/llworldmapmessage.cpp
+++ b/indra/newview/llworldmapmessage.cpp
@@ -150,6 +150,10 @@ void LLWorldMapMessage::sendMapBlockRequest(U16 min_x, U16 min_y, U16 max_x, U16
 // public static
 void LLWorldMapMessage::processMapBlockReply(LLMessageSystem* msg, void**)
 {
+	if (gNonInteractive)
+	{
+		return;
+	}
 	U32 agent_flags;
 	msg->getU32Fast(_PREHASH_AgentData, _PREHASH_Flags, agent_flags);
 
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index c4976c4bbc64b391ba1b5623ee18dfeac91b515f..7aa05fb22fa5fe3fb1adc3964a2c6b631c6926b9 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -485,6 +485,10 @@ void LLPipeline::init()
 	{
 		clearAllRenderTypes();
 	}
+	else if (gNonInteractive)
+	{
+		clearAllRenderTypes();
+	}
 	else
 	{
 		setAllRenderTypes(); // By default, all rendering types start enabled
@@ -1151,6 +1155,12 @@ void LLPipeline::refreshCachedSettings()
 	RenderAutoHideSurfaceAreaLimit = gSavedSettings.getF32("RenderAutoHideSurfaceAreaLimit");
 	RenderSpotLight = nullptr;
 	updateRenderDeferred();
+
+	if (gNonInteractive)
+	{
+		LLVOAvatar::sMaxNonImpostors = 1;
+		LLVOAvatar::updateImpostorRendering(LLVOAvatar::sMaxNonImpostors);
+	}
 }
 
 void LLPipeline::releaseGLBuffers()
@@ -3997,7 +4007,10 @@ void LLPipeline::postSort(LLCamera& camera)
 	{
 		mSelectedFaces.clear();
 
-		LLPipeline::setRenderHighlightTextureChannel(gFloaterTools->getPanelFace()->getTextureChannelToEdit());
+		if (!gNonInteractive)
+		{
+			LLPipeline::setRenderHighlightTextureChannel(gFloaterTools->getPanelFace()->getTextureChannelToEdit());
+		}
 
 		// Draw face highlights for selected faces.
 		if (LLSelectMgr::getInstance()->getTEMode())
diff --git a/scripts/perf/perfbot_run.py b/scripts/perf/perfbot_run.py
new file mode 100644
index 0000000000000000000000000000000000000000..55ea2fae66dd9d25a33a336eca3718efbe6f592f
--- /dev/null
+++ b/scripts/perf/perfbot_run.py
@@ -0,0 +1,204 @@
+#!/usr/bin/env python3
+"""\
+@file perfbot_run.py
+@brief Run a number of non interactive Viewers (PerfBots) with
+       a variety of options and settings. Pass --help for details.
+
+$LicenseInfo:firstyear=2007&license=viewerlgpl$
+Second Life Viewer Source Code
+Copyright (C) 2021, Linden Research, Inc.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation;
+version 2.1 of the License only.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+$/LicenseInfo$
+"""
+
+import argparse
+import subprocess
+import os
+import math
+import time
+
+# Required parameters that are always passed in
+# Specify noninteractive mode (SL-15999 for details)
+PARAM_NON_INTERACTIVE = "--noninteractive"
+# Run multiple Viewers at once
+PARAM_MULTI = "--multiple"
+# Specify username (first and last) and password
+PARAM_LOGIN = "--login"
+# SLURL to teleport to after login
+PARAM_SLURL = "--slurl"
+
+
+def gen_niv_script(args):
+    print(f"Reading creds from {(args.creds)} folder")
+    print(f"Using the non interactive Viewer from {(args.viewer)}")
+    print(f"Sleeping for {args.sleep}ms between Viewer launches")
+
+    # Read the lines from the creds file.  Typically this will be
+    # stored in the build-secrets-git private repository but you
+    # can point to any location with the --creds parameter
+    creds_lines = []
+    with open(args.creds) as file:
+        creds_lines = file.readlines()
+        creds_lines = [line.rstrip() for line in creds_lines]
+        creds_lines = [line for line in creds_lines if not line.startswith("#") and len(line)]
+    # We cannot log in more users than we have credentials for
+    if args.num==0:
+        args.num = len(creds_lines)
+    if args.num > len(creds_lines):
+        print(
+            f"The number of agents specified ({(args.num)}) exceeds "
+            f"the number of valid entries ({(len(creds_lines))}) in "
+            f"the creds file "
+        )
+        return
+
+    print(f"Launching {(args.num)} instances of the Viewer")
+
+    # The Viewer (in dev environments at least) needs a well specified
+    # working directory to function properly. We try to guess what it
+    # might be based on the full path to the Viewer executable but
+    # you can also specify it explicitly with the --cwd parameter
+    # (required for dev builds)
+    args.viewer = os.path.abspath(args.viewer)
+    if len(args.cwd) == 0:
+        working_dir = os.path.dirname(os.path.abspath(args.viewer))
+    else:
+        working_dir = os.path.abspath(args.cwd)
+    print(f"Working directory is {working_dir}, cwd {args.cwd}")
+    os.chdir(working_dir)
+
+    if args.dryrun:
+        print("Running in dry-run mode - no Viewers will be started")
+    print("")
+
+    for inst in range(args.num):
+
+        # Format of each cred line is username_first username_last password
+        # A space is used to separate each and a # at the start of a line
+        # removes it from the pool (useful if someone else is using a subset
+        # of the available ones)
+        creds = creds_lines[inst].split(" ")
+        username_first = creds[0]
+        username_last = creds[1]
+        password = creds[2]
+
+        # The default layout is an evenly spaced circle in the
+        # center of the region.  We may extend this to allow other
+        # patterns like a square/rectangle or a spiral. (Hint: it
+        # likely won't be needed :))
+        center_x = 128
+        center_y = 128
+        if args.layout == "circle":
+            radius = 6
+            angle = (2 * math.pi / args.num) * inst
+            region_x = int(math.sin(angle) * radius + center_x)
+            region_y = int(math.cos(angle) * radius + center_y)
+            region_z = 0
+        elif args.layout == "square":
+            region_x = center_x
+            region_y = center_y
+        elif args.layout == "spiral":
+            region_x = center_x
+            region_y = center_y
+        slurl = f"secondlife://{args.region}/{region_x}/{region_y}/{region_z}"
+
+        # Build the script line
+        script_cmd = [args.viewer]
+        script_cmd.append(PARAM_NON_INTERACTIVE)
+        script_cmd.append(PARAM_MULTI)
+        script_cmd.append(PARAM_LOGIN)
+        script_cmd.append(username_first)
+        script_cmd.append(username_last)
+        script_cmd.append(password)
+        script_cmd.append(PARAM_SLURL)
+        script_cmd.append(slurl)
+
+        # Display the script we will execute.
+        cmd = ""
+        for p in script_cmd:
+            cmd = cmd + " " + p
+        print(cmd)
+
+        # If --dry-run is specified, we do everything (including, most
+        # usefully, display the script lines) but do not start the Viewer
+        if args.dryrun == False:
+            print("opening viewer session with",script_cmd)
+            viewer_session = subprocess.Popen(script_cmd)
+
+        # Sleeping a bit between launches seems to help avoid a CPU
+        # surge when N Viewers are started simulatanously. The default
+        # value can be changed with the --sleep parameter
+        time.sleep(args.sleep / 1000)
+
+
+if __name__ == "__main__":
+    parser = argparse.ArgumentParser(allow_abbrev=False)
+    parser.add_argument(
+        "--num",
+        type=int,
+        default=0,
+        dest="num",
+        help="How many avatars to add to the script",
+    )
+    parser.add_argument(
+        "--creds",
+        default="../../../build-secrets-git/perf/perfbot_creds.txt",
+        dest="creds",
+        help="Location of the text file containing user credentials",
+    )
+    parser.add_argument(
+        "--viewer",
+        default="C:/Program Files/SecondLife/SecondLifeViewer.exe",
+        dest="viewer",
+        help="Location of the non interactive Viewer build",
+    )
+    parser.add_argument(
+        "--cwd",
+        default="",
+        dest="cwd",
+        help="Location of the current working directory to use",
+    )
+    parser.add_argument(
+        "--region",
+        default="Lag Me 5",
+        dest="region",
+        help="The SLURL for the Second Life region to visit",
+    )
+    parser.add_argument(
+        "--layout",
+        default="circle",
+        dest="layout",
+        choices={"circle", "square", "spiral"},
+        help="The geometric layout of the avatar destination locations",
+    )
+    parser.add_argument(
+        "--sleep",
+        type=int,
+        default=1000,
+        dest="sleep",
+        help="Time to sleep between launches in milliseconds",
+    )
+    parser.add_argument(
+        "--dry-run",
+        action="store_true",
+        dest="dryrun",
+        help="Dryrun mode - display parameters and script lines but do not start any Viewers",
+    )
+    args = parser.parse_args()
+
+    gen_niv_script(args)