diff --git a/doc/contributions.txt b/doc/contributions.txt
index 1fcfb8273863f038a18bafda1f115aff8f2b8e7a..b66298371c0b85a5d4e5f35b873d99a1ad6fc5bb 100644
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -108,6 +108,9 @@ Carjay McGinnis
 Catherine Pfeffer
 	VWR-1282
 	VWR-8624
+Celierra Darling
+	VWR-1274
+	VWR-6975
 Dale Glass
 	VWR-120
 	VWR-560
@@ -375,6 +378,7 @@ Renault Clio
 	VWR-1976
 Robin Cornelius
 	VWR-2488
+	VWR-9557
 Ryozu Kojima
 	VWR-287
 Sammy Frederix
diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake
index 333860a31a9c65026536259293a13a9bab0c7743..c939afc863b22394c90e5e04a233f807c2988d5a 100644
--- a/indra/cmake/00-Common.cmake
+++ b/indra/cmake/00-Common.cmake
@@ -9,9 +9,9 @@ include(Variables)
 
 set(CMAKE_CXX_FLAGS_DEBUG "-D_DEBUG -DLL_DEBUG=1")
 set(CMAKE_CXX_FLAGS_RELEASE
-    "-DLL_RELEASE=1 -DLL_RELEASE_FOR_DOWNLOAD=1 -DLL_SEND_CRASH_REPORTS=1 -DNDEBUG")
+    "-DLL_RELEASE=1 -DLL_RELEASE_FOR_DOWNLOAD=1 -D_SECURE_SCL=0 -DLL_SEND_CRASH_REPORTS=1 -DNDEBUG")
 set(CMAKE_CXX_FLAGS_RELWITHDEBINFO 
-    "-DLL_RELEASE=1 -DLL_SEND_CRASH_REPORTS=0 -DNDEBUG -DLL_RELEASE_WITH_DEBUG_INFO=1")
+    "-DLL_RELEASE=1 -D_SECURE_SCL=0 -DLL_SEND_CRASH_REPORTS=0 -DNDEBUG -DLL_RELEASE_WITH_DEBUG_INFO=1")
 
 
 # Don't bother with a MinSizeRel build.
@@ -26,15 +26,18 @@ if (WINDOWS)
   # Don't build DLLs.
   set(BUILD_SHARED_LIBS OFF)
 
-  set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /Od /Zi /MTd"
+  set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /Od /Zi /MDd"
       CACHE STRING "C++ compiler debug options" FORCE)
   set(CMAKE_CXX_FLAGS_RELWITHDEBINFO 
-      "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Od /Zi /MT"
+      "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Od /Zi /MD"
       CACHE STRING "C++ compiler release-with-debug options" FORCE)
   set(CMAKE_CXX_FLAGS_RELEASE
-      "${CMAKE_CXX_FLAGS_RELEASE} ${LL_CXX_FLAGS} /O2 /Zi /MT"
+      "${CMAKE_CXX_FLAGS_RELEASE} ${LL_CXX_FLAGS} /O2 /Zi /MD"
       CACHE STRING "C++ compiler release options" FORCE)
 
+  set(CMAKE_CXX_STANDARD_LIBRARIES "")
+  set(CMAKE_C_STANDARD_LIBRARIES "")
+
   add_definitions(
       /DLL_WINDOWS=1
       /DUNICODE
diff --git a/indra/cmake/APR.cmake b/indra/cmake/APR.cmake
index 2563a98c52121f101fe6e89e3f8e35caf833bc21..25ee364db82eee577936c736302a7caa7a3f3fa4 100644
--- a/indra/cmake/APR.cmake
+++ b/indra/cmake/APR.cmake
@@ -1,5 +1,3 @@
-# -*- cmake -*-
-
 include(BerkeleyDB)
 include(Linking)
 include(Prebuilt)
@@ -19,12 +17,14 @@ else (STANDALONE)
       debug ${ARCH_PREBUILT_DIRS_DEBUG}/apr-1.lib
       optimized ${ARCH_PREBUILT_DIRS_RELEASE}/apr-1.lib
       )
+    set(APRICONV_LIBRARIES 
+      debug ${ARCH_PREBUILT_DIRS_DEBUG}/apriconv-1.lib
+      optimized ${ARCH_PREBUILT_DIRS_RELEASE}/apriconv-1.lib
+      )
     set(APRUTIL_LIBRARIES 
-      debug ${ARCH_PREBUILT_DIRS_DEBUG}/aprutil-1.lib
-      optimized ${ARCH_PREBUILT_DIRS_RELEASE}/aprutil-1.lib
+      debug ${ARCH_PREBUILT_DIRS_DEBUG}/aprutil-1.lib ${APRICONV_LIBRARIES}
+      optimized ${ARCH_PREBUILT_DIRS_RELEASE}/aprutil-1.lib ${APRICONV_LIBRARIES}
       )
-    # Doesn't need to link with iconv.dll
-    set(APRICONV_LIBRARIES "")
   elseif (DARWIN)
     set(APR_LIBRARIES 
       debug ${ARCH_PREBUILT_DIRS_DEBUG}/libapr-1.a
diff --git a/indra/cmake/Audio.cmake b/indra/cmake/Audio.cmake
index c6ccab26133b9c7963f0e1f1ce3e358571298fd7..d23bc2f9c6a04763d29f734bab5b3dd7d20909c9 100644
--- a/indra/cmake/Audio.cmake
+++ b/indra/cmake/Audio.cmake
@@ -14,10 +14,18 @@ else (STANDALONE)
   set(VORBISFILE_INCLUDE_DIRS ${VORBIS_INCLUDE_DIRS})
 
   if (WINDOWS)
-    set(OGG_LIBRARIES ogg_static_mt)
-    set(VORBIS_LIBRARIES vorbis_static_mt)
-    set(VORBISENC_LIBRARIES vorbisenc_static_mt)
-    set(VORBISFILE_LIBRARIES vorbisfile_static_mt)
+    set(OGG_LIBRARIES
+        optimized ogg_static
+        debug ogg_static_d)
+    set(VORBIS_LIBRARIES
+        optimized vorbis_static
+        debug vorbis_static_d)
+    set(VORBISENC_LIBRARIES
+        optimized vorbisenc_static
+        debug vorbisenc_static_d)
+    set(VORBISFILE_LIBRARIES
+        optimized vorbisfile_static
+        debug vorbisfile_static_d)
   else (WINDOWS)
     set(OGG_LIBRARIES ogg)
     set(VORBIS_LIBRARIES vorbis)
diff --git a/indra/cmake/Boost.cmake b/indra/cmake/Boost.cmake
index a7db67c915d13985339ee4d8076fe63e94a72186..0578ae95ffa7edc027d74c6ef0bab0ba48b0ee3d 100644
--- a/indra/cmake/Boost.cmake
+++ b/indra/cmake/Boost.cmake
@@ -28,14 +28,14 @@ else (STANDALONE)
           debug libboost_signals-vc71-mt-sgd-${BOOST_VERSION})
     else (MSVC71)
       set(BOOST_PROGRAM_OPTIONS_LIBRARY 
-          optimized libboost_program_options-vc80-mt-s-${BOOST_VERSION}
-          debug libboost_program_options-vc80-mt-sgd-${BOOST_VERSION})
+          optimized libboost_program_options-vc80-mt-${BOOST_VERSION}
+          debug libboost_program_options-vc80-mt-gd-${BOOST_VERSION})
       set(BOOST_REGEX_LIBRARY
-          optimized libboost_regex-vc80-mt-s-${BOOST_VERSION}
-          debug libboost_regex-vc80-mt-sgd-${BOOST_VERSION})
+          optimized libboost_regex-vc80-mt-${BOOST_VERSION}
+          debug libboost_regex-vc80-mt-gd-${BOOST_VERSION})
       set(BOOST_SIGNALS_LIBRARY 
-          optimized libboost_signals-vc80-mt-s-${BOOST_VERSION}
-          debug libboost_signals-vc80-mt-sgd-${BOOST_VERSION})
+          optimized libboost_signals-vc80-mt-${BOOST_VERSION}
+          debug libboost_signals-vc80-mt-gd-${BOOST_VERSION})
     endif (MSVC71)
   elseif (DARWIN)
     set(BOOST_PROGRAM_OPTIONS_LIBRARY boost_program_options-mt)
diff --git a/indra/cmake/GooglePerfTools.cmake b/indra/cmake/GooglePerfTools.cmake
index 25e9f6d4f494ee70fc343790713dadaadc0244a0..aff65cb53e55c86f640426ab7cfdef45d8daf96a 100644
--- a/indra/cmake/GooglePerfTools.cmake
+++ b/indra/cmake/GooglePerfTools.cmake
@@ -5,6 +5,11 @@ if (STANDALONE)
   include(FindGooglePerfTools)
 else (STANDALONE)
   use_prebuilt_binary(google)
+  if (WINDOWS)
+    set(TCMALLOC_LIBRARIES 
+        debug libtcmalloc_minimal-debug
+        optimized libtcmalloc_minimal-debug)
+  endif (WINDOWS)
   if (LINUX)
     set(TCMALLOC_LIBRARIES tcmalloc)
     set(STACKTRACE_LIBRARIES stacktrace)
diff --git a/indra/cmake/JPEG.cmake b/indra/cmake/JPEG.cmake
index 5d0ee0d2fdec21004cf5467d9eb3a45f8eec73d5..9514d59f64b459eb095028d6a457f00e144ee0c5 100644
--- a/indra/cmake/JPEG.cmake
+++ b/indra/cmake/JPEG.cmake
@@ -17,7 +17,7 @@ else (STANDALONE)
       debug ${ARCH_PREBUILT_DIRS_DEBUG}/liblljpeg.a
       )
   elseif (WINDOWS)
-    set(JPEG_LIBRARIES jpeglib_6b)
+    set(JPEG_LIBRARIES jpeglib)
   endif (LINUX)
   set(JPEG_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include)
 endif (STANDALONE)
diff --git a/indra/cmake/LLRender.cmake b/indra/cmake/LLRender.cmake
index bbcf4cd57d7bb26d88574a637d8a1624dcab47f2..c47e8878e95e74fbd55c95ffaf7dbf4702c65518 100644
--- a/indra/cmake/LLRender.cmake
+++ b/indra/cmake/LLRender.cmake
@@ -18,8 +18,8 @@ endif (SERVER AND LINUX)
 
 # mapserver requires certain files to be copied so LL_MESA_HEADLESS can be set
 # differently for different object files.
-macro (copy_server_sources _copied_SOURCES)
-  foreach (PREFIX ${_copied_SOURCES})
+macro (copy_server_sources )
+  foreach (PREFIX ${ARGV})
     add_custom_command(
         OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${PREFIX}_server.cpp
         COMMAND ${CMAKE_COMMAND}
diff --git a/indra/cmake/LLWindow.cmake b/indra/cmake/LLWindow.cmake
index c0efa27f6e0e993389308235535b23b0a219a341..e749055abf92da378c2494b4349e26f19b1b28aa 100644
--- a/indra/cmake/LLWindow.cmake
+++ b/indra/cmake/LLWindow.cmake
@@ -40,4 +40,9 @@ else (SERVER AND LINUX)
   set(LLWINDOW_LIBRARIES
       llwindow
       )
+  if (WINDOWS)
+      list(APPEND LLWINDOW_LIBRARIES
+          comdlg32
+          )
+  endif (WINDOWS)
 endif (SERVER AND LINUX)
diff --git a/indra/cmake/Linking.cmake b/indra/cmake/Linking.cmake
index 167c5dd31cc38841401e04c9108321bb2c8a5ffb..2bddb95178908fcd585e1416c82770104c98b05f 100644
--- a/indra/cmake/Linking.cmake
+++ b/indra/cmake/Linking.cmake
@@ -32,11 +32,16 @@ endif (LINUX)
 
 if (WINDOWS)
   set(WINDOWS_LIBRARIES
+      advapi32
+      shell32
       ws2_32
       mswsock
       psapi
       winmm
       netapi32
+      wldap32
+      gdi32
+      user32
       )
 else (WINDOWS)
   set(WINDOWS_LIBRARIES "")
diff --git a/indra/cmake/PNG.cmake b/indra/cmake/PNG.cmake
index 4d0b7b2d8d3742e2422291719b7090267857e5df..cf10c2dda58356478163f713395a924a6787582a 100644
--- a/indra/cmake/PNG.cmake
+++ b/indra/cmake/PNG.cmake
@@ -8,6 +8,12 @@ if (STANDALONE)
   include(FindPNG)
 else (STANDALONE)
   use_prebuilt_binary(libpng)
-  set(PNG_LIBRARIES png12)
+  if (WINDOWS)
+    set(PNG_LIBRARIES 
+      debug libpngd
+      optimized libpng)
+  else (WINDOWS)
+    set(PNG_LIBRARIES png12)
+  endif (WINDOWS)
   set(PNG_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include)
 endif (STANDALONE)
diff --git a/indra/cmake/ZLIB.cmake b/indra/cmake/ZLIB.cmake
index 80d41919718493fed8e7dab3173c73bd6e11bb8c..c133248bed70a299ed61eeba3f04b10e18d6c465 100644
--- a/indra/cmake/ZLIB.cmake
+++ b/indra/cmake/ZLIB.cmake
@@ -10,7 +10,9 @@ if (STANDALONE)
 else (STANDALONE)
   use_prebuilt_binary(zlib)
   if (WINDOWS)
-    set(ZLIB_LIBRARIES zlib)
+    set(ZLIB_LIBRARIES 
+      debug zlibd
+      optimized zlib)
   else (WINDOWS)
     set(ZLIB_LIBRARIES z)
   endif (WINDOWS)
diff --git a/indra/llcharacter/llbvhloader.cpp b/indra/llcharacter/llbvhloader.cpp
index 7b53de06b92826215a7c960edd3345084cf24339..e1f8ce53fb9972a30f3c63f637bb00132bedfa12 100644
--- a/indra/llcharacter/llbvhloader.cpp
+++ b/indra/llcharacter/llbvhloader.cpp
@@ -178,7 +178,9 @@ LLBVHLoader::Status LLBVHLoader::loadTranslationTable(const char *fileName)
 	//--------------------------------------------------------------------
 	std::string path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,fileName);
 
-	apr_file_t *fp = ll_apr_file_open(path, LL_APR_R);
+	LLAPRFile infile ;
+	infile.open(path, LL_APR_R);
+	apr_file_t *fp = infile.getFileHandle();
 	if (!fp)
 		return ST_NO_XLT_FILE;
 
@@ -187,8 +189,7 @@ LLBVHLoader::Status LLBVHLoader::loadTranslationTable(const char *fileName)
 	//--------------------------------------------------------------------
 	// register file to be closed on function exit
 	//--------------------------------------------------------------------
-	FileCloser fileCloser(fp);
-
+	
 	//--------------------------------------------------------------------
 	// load header
 	//--------------------------------------------------------------------
@@ -618,6 +619,8 @@ LLBVHLoader::Status LLBVHLoader::loadTranslationTable(const char *fileName)
 		}
 
 	}
+
+	infile.close() ;
 	return ST_OK;
 }
 
diff --git a/indra/llcharacter/llkeyframemotionparam.cpp b/indra/llcharacter/llkeyframemotionparam.cpp
index c0af6250c2b2f22f220e88b2b48fdb7e0024e516..a9c1f6fc456bd89d75cd343403007f7f070a6e91 100644
--- a/indra/llcharacter/llkeyframemotionparam.cpp
+++ b/indra/llcharacter/llkeyframemotionparam.cpp
@@ -354,7 +354,9 @@ BOOL LLKeyframeMotionParam::loadMotions()
 	// open the file
 	//-------------------------------------------------------------------------
 	S32 fileSize = 0;
-	apr_file_t* fp = ll_apr_file_open(path, LL_APR_R, &fileSize);
+	LLAPRFile infile ;
+	infile.open(path, LL_APR_R, NULL, &fileSize);
+	apr_file_t* fp = infile.getFileHandle() ;
 	if (!fp || fileSize == 0)
 	{
 		llinfos << "ERROR: can't open: " << path << llendl;
@@ -366,7 +368,6 @@ BOOL LLKeyframeMotionParam::loadMotions()
 	if ( !text )
 	{
 		llinfos << "ERROR: can't allocated keyframe text buffer." << llendl;
-		apr_file_close(fp);
 		return FALSE;
 	}
 
@@ -393,7 +394,7 @@ BOOL LLKeyframeMotionParam::loadMotions()
 	//-------------------------------------------------------------------------
 	// close the file
 	//-------------------------------------------------------------------------
-	apr_file_close( fp );
+	infile.close();
 
 	//-------------------------------------------------------------------------
 	// check for error
diff --git a/indra/llcharacter/llstatemachine.cpp b/indra/llcharacter/llstatemachine.cpp
index 5a2faf6e712747a9f0a7b85ee236fcf8a64d58ac..73c69512112c81c75a6e429b5e1a5245e7c87f84 100644
--- a/indra/llcharacter/llstatemachine.cpp
+++ b/indra/llcharacter/llstatemachine.cpp
@@ -209,7 +209,9 @@ LLFSMState* LLStateDiagram::getState(U32 state_id)
 
 BOOL LLStateDiagram::saveDotFile(const std::string& filename)
 {
-	apr_file_t* dot_file = ll_apr_file_open(filename, LL_APR_W);
+	LLAPRFile outfile ;
+	outfile.open(filename, LL_APR_W);
+	apr_file_t* dot_file = outfile.getFileHandle() ;
 
 	if (!dot_file)
 	{
@@ -258,8 +260,6 @@ BOOL LLStateDiagram::saveDotFile(const std::string& filename)
 
 	apr_file_printf(dot_file, "}\n");
 
-	apr_file_close(dot_file);
-
 	return TRUE;
 }
 
diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp
index 74d821c72145837f1f62678dd100c1e9b1d9811e..82530b14891efccd263a0d4d71fbc0878074d007 100644
--- a/indra/llcommon/llapr.cpp
+++ b/indra/llcommon/llapr.cpp
@@ -36,8 +36,10 @@
 #include "llapr.h"
 
 apr_pool_t *gAPRPoolp = NULL; // Global APR memory pool
+LLVolatileAPRPool *LLAPRFile::sAPRFilePoolp = NULL ; //global volatile APR memory pool.
 apr_thread_mutex_t *gLogMutexp = NULL;
 
+const S32 FULL_VOLATILE_APR_POOL = 1024 ; //number of references to LLVolatileAPRPool
 
 void ll_init_apr()
 {
@@ -46,10 +48,15 @@ void ll_init_apr()
 		// Initialize APR and create the global pool
 		apr_initialize();
 		apr_pool_create(&gAPRPoolp, NULL);
-
+		
 		// Initialize the logging mutex
 		apr_thread_mutex_create(&gLogMutexp, APR_THREAD_MUTEX_UNNESTED, gAPRPoolp);
 	}
+
+	if(!LLAPRFile::sAPRFilePoolp)
+	{
+		LLAPRFile::sAPRFilePoolp = new LLVolatileAPRPool() ;
+	}
 }
 
 
@@ -70,31 +77,127 @@ void ll_cleanup_apr()
 		apr_pool_destroy(gAPRPoolp);
 		gAPRPoolp = NULL;
 	}
+	if (LLAPRFile::sAPRFilePoolp)
+	{
+		delete LLAPRFile::sAPRFilePoolp ;
+		LLAPRFile::sAPRFilePoolp = NULL ;
+	}
 	apr_terminate();
 }
 
+//
 //
 //LLAPRPool
 //
-LLAPRPool::LLAPRPool(apr_pool_t *parent, apr_size_t size) 
+LLAPRPool::LLAPRPool(apr_pool_t *parent, apr_size_t size, BOOL releasePoolFlag) 
 {
-	mStatus = apr_pool_create(&mPool, parent);
+	mParent = parent ;
+	mReleasePoolFlag = releasePoolFlag ;
+	mMaxSize = size ;
+	mPool = NULL ;
+
+	createAPRPool() ;
+}
+
+LLAPRPool::~LLAPRPool() 
+{
+	releaseAPRPool() ;
+}
 
-	if(size > 0) //size is the number of blocks (which is usually 4K), NOT bytes.
+void LLAPRPool::createAPRPool()
+{
+	if(mPool)
+	{
+		return ;
+	}
+
+	mStatus = apr_pool_create(&mPool, mParent);
+	ll_apr_warn_status(mStatus) ;
+
+	if(mMaxSize > 0) //size is the number of blocks (which is usually 4K), NOT bytes.
 	{
 		apr_allocator_t *allocator = apr_pool_allocator_get(mPool); 
 		if (allocator) 
 		{ 
-			apr_allocator_max_free_set(allocator, size) ;
+			apr_allocator_max_free_set(allocator, mMaxSize) ;
 		}
 	}
 }
 
-LLAPRPool::~LLAPRPool() 
+void LLAPRPool::releaseAPRPool()
+{
+	if(!mPool)
+	{
+		return ;
+	}
+
+	if(!mParent || mReleasePoolFlag)
+	{
+		apr_pool_destroy(mPool) ;
+		mPool = NULL ;
+	}
+}
+
+apr_pool_t* LLAPRPool::getAPRPool() 
 {
-	apr_pool_destroy(mPool) ;
+	if(!mPool)
+	{
+		createAPRPool() ;
+	}
+	
+	return mPool ; 
+}
+LLVolatileAPRPool::LLVolatileAPRPool(apr_pool_t *parent, apr_size_t size, BOOL releasePoolFlag) 
+				  : LLAPRPool(parent, size, releasePoolFlag)
+{
+	mNumActiveRef = 0 ;
+	mNumTotalRef = 0 ;
 }
 
+apr_pool_t* LLVolatileAPRPool::getVolatileAPRPool() 
+{
+	mNumTotalRef++ ;
+	mNumActiveRef++ ;
+	return getAPRPool() ;
+}
+
+void LLVolatileAPRPool::clearVolatileAPRPool() 
+{
+	if(mNumActiveRef > 0)
+	{
+		mNumActiveRef--;
+		if(mNumActiveRef < 1)
+		{
+			if(isFull()) 
+			{
+				mNumTotalRef = 0 ;
+
+				//destroy the apr_pool.
+				releaseAPRPool() ;
+			}
+			else 
+			{
+				//This does not actually free the memory, 
+				//it just allows the pool to re-use this memory for the next allocation. 
+				apr_pool_clear(mPool) ;
+			}
+		}
+	}
+	else
+	{
+		llassert_always(mNumActiveRef > 0) ;
+	}
+
+	//paranoia check if the pool is jammed.
+	//will remove the check before going to release.
+	llassert_always(mNumTotalRef < (FULL_VOLATILE_APR_POOL << 2)) ;
+}
+
+BOOL LLVolatileAPRPool::isFull()
+{
+	return mNumTotalRef > FULL_VOLATILE_APR_POOL ;
+}
+//---------------------------------------------------------------------
 //
 // LLScopedLock
 //
@@ -133,9 +236,8 @@ void LLScopedLock::unlock()
 	}
 }
 
-//
-// Misc functions
-//
+//---------------------------------------------------------------------
+
 bool ll_apr_warn_status(apr_status_t status)
 {
 	if(APR_SUCCESS == status) return false;
@@ -151,55 +253,110 @@ void ll_apr_assert_status(apr_status_t status)
 	llassert(ll_apr_warn_status(status) == false);
 }
 
-// File I/O
-apr_file_t* ll_apr_file_open(const std::string& filename, apr_int32_t flags, S32* sizep, apr_pool_t* pool)
+//---------------------------------------------------------------------
+//
+// LLAPRFile functions
+//
+LLAPRFile::LLAPRFile()
+{
+	mFile = NULL ;
+	mCurrentFilePoolp = NULL ;
+}
+LLAPRFile::~LLAPRFile()
+{
+	close() ;
+}
+
+apr_status_t LLAPRFile::close() 
+{
+	apr_status_t ret = APR_SUCCESS ;
+	if(mFile)
+	{
+		ret = apr_file_close(mFile);
+		mFile = NULL ;
+	}
+
+	if(mCurrentFilePoolp)
+	{
+		mCurrentFilePoolp->clearVolatileAPRPool() ;
+		mCurrentFilePoolp = NULL ;
+	}
+
+	return ret ;
+}
+
+apr_status_t LLAPRFile::open(LLVolatileAPRPool* pool, const std::string& filename, apr_int32_t flags, S32* sizep)
+{
+	apr_status_t s ;
+	s = open(filename, flags, pool ? pool->getVolatileAPRPool() : NULL, sizep) ;
+	
+	if(!mCurrentFilePoolp)
+	{
+		mCurrentFilePoolp = pool ;
+
+		if(!mFile)
+		{
+			close() ;
+		}
+	}
+
+	return s ;
+}
+apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, apr_pool_t* pool, S32* sizep)
 {
-	apr_file_t* apr_file;
 	apr_status_t s;
-	if (pool == NULL) pool = gAPRPoolp;
-	s = apr_file_open(&apr_file, filename.c_str(), flags, APR_OS_DEFAULT, pool);
-	if (s != APR_SUCCESS)
+
+	//check if already open some file
+	llassert_always(!mFile) ;
+	llassert_always(!mCurrentFilePoolp) ;
+	
+	s = apr_file_open(&mFile, filename.c_str(), flags, APR_OS_DEFAULT, getAPRFilePool(pool));
+	if (s != APR_SUCCESS || !mFile)
 	{
+		mFile = NULL ;
+		close() ;
 		if (sizep)
 		{
 			*sizep = 0;
 		}
-		return NULL;
+		return s;
 	}
 
 	if (sizep)
 	{
 		S32 file_size = 0;
 		apr_off_t offset = 0;
-		if (apr_file_seek(apr_file, APR_END, &offset) == APR_SUCCESS)
+		if (apr_file_seek(mFile, APR_END, &offset) == APR_SUCCESS)
 		{
 			llassert_always(offset <= 0x7fffffff);
 			file_size = (S32)offset;
 			offset = 0;
-			apr_file_seek(apr_file, APR_SET, &offset);
+			apr_file_seek(mFile, APR_SET, &offset);
 		}
 		*sizep = file_size;
 	}
 
-	return apr_file;
+	return s;
 }
-apr_file_t* ll_apr_file_open(const std::string& filename, apr_int32_t flags, S32* sizep)
-{
-	return ll_apr_file_open(filename, flags, sizep, NULL);
-}
-apr_file_t* ll_apr_file_open(const std::string& filename, apr_int32_t flags, apr_pool_t* pool)
-{
-	return ll_apr_file_open(filename, flags, NULL, pool);
-}
-apr_file_t* ll_apr_file_open(const std::string& filename, apr_int32_t flags)
-{
-	return ll_apr_file_open(filename, flags, NULL, NULL);
+
+apr_pool_t* LLAPRFile::getAPRFilePool(apr_pool_t* pool)
+{	
+	if(!pool)
+	{
+		mCurrentFilePoolp = sAPRFilePoolp ;
+		return mCurrentFilePoolp->getVolatileAPRPool() ;
+	}
+
+	return pool ;
 }
 
-S32 ll_apr_file_read(apr_file_t* apr_file, void *buf, S32 nbytes)
+// File I/O
+S32 LLAPRFile::read(void *buf, S32 nbytes)
 {
+	llassert_always(mFile) ;
+	
 	apr_size_t sz = nbytes;
-	apr_status_t s = apr_file_read(apr_file, buf, &sz);
+	apr_status_t s = apr_file_read(mFile, buf, &sz);
 	if (s != APR_SUCCESS)
 	{
 		return 0;
@@ -211,165 +368,273 @@ S32 ll_apr_file_read(apr_file_t* apr_file, void *buf, S32 nbytes)
 	}
 }
 
-S32 ll_apr_file_read_ex(const std::string& filename, apr_pool_t* pool, void *buf, S32 offset, S32 nbytes)
+S32 LLAPRFile::write(const void *buf, S32 nbytes)
 {
-	if (pool == NULL) pool = gAPRPoolp;
-	apr_file_t* filep = ll_apr_file_open(filename, APR_READ|APR_BINARY, pool);
-	if (!filep)
+	llassert_always(mFile) ;
+	
+	apr_size_t sz = nbytes;
+	apr_status_t s = apr_file_write(mFile, buf, &sz);
+	if (s != APR_SUCCESS)
 	{
 		return 0;
 	}
-	S32 off;
-	if (offset < 0)
-		off = ll_apr_file_seek(filep, APR_END, 0);
 	else
-		off = ll_apr_file_seek(filep, APR_SET, offset);
-	S32 bytes_read;
-	if (off < 0)
 	{
-		bytes_read = 0;
+		llassert_always(sz <= 0x7fffffff);
+		return (S32)sz;
 	}
-	else
+}
+
+S32 LLAPRFile::seek(apr_seek_where_t where, S32 offset)
+{
+	return LLAPRFile::seek(mFile, where, offset) ;
+}
+
+//
+//*******************************************************************************************************************************
+//static components of LLAPRFile
+//
+
+//static
+apr_status_t LLAPRFile::close(apr_file_t* file_handle, LLVolatileAPRPool* pool) 
+{
+	apr_status_t ret = APR_SUCCESS ;
+	if(file_handle)
 	{
-		bytes_read = ll_apr_file_read(filep, buf, nbytes );
+		ret = apr_file_close(file_handle);
+		file_handle = NULL ;
 	}
-	apr_file_close(filep);
 
-	return bytes_read;
+	if(pool)
+	{
+		pool->clearVolatileAPRPool() ;
+	}
+
+	return ret ;
 }
 
-S32 ll_apr_file_write(apr_file_t* apr_file, const void *buf, S32 nbytes)
+//static
+apr_file_t* LLAPRFile::open(const std::string& filename, LLVolatileAPRPool* pool, apr_int32_t flags)
 {
-	apr_size_t sz = nbytes;
-	apr_status_t s = apr_file_write(apr_file, buf, &sz);
+	apr_status_t s;
+	apr_file_t* file_handle ;
+
+	pool = pool ? pool : LLAPRFile::sAPRFilePoolp ;
+
+	s = apr_file_open(&file_handle, filename.c_str(), flags, APR_OS_DEFAULT, pool->getVolatileAPRPool());
+	if (s != APR_SUCCESS || !file_handle)
+	{
+		file_handle = NULL ;
+		close(file_handle, pool) ;
+		return NULL;
+	}
+
+	return file_handle ;
+}
+
+//static
+S32 LLAPRFile::seek(apr_file_t* file_handle, apr_seek_where_t where, S32 offset)
+{
+	if(!file_handle)
+	{
+		return -1 ;
+	}
+
+	apr_status_t s;
+	apr_off_t apr_offset;
+	if (offset >= 0)
+	{
+		apr_offset = (apr_off_t)offset;
+		s = apr_file_seek(file_handle, where, &apr_offset);
+	}
+	else
+	{
+		apr_offset = 0;
+		s = apr_file_seek(file_handle, APR_END, &apr_offset);
+	}
 	if (s != APR_SUCCESS)
+	{
+		return -1;
+	}
+	else
+	{
+		llassert_always(apr_offset <= 0x7fffffff);
+		return (S32)apr_offset;
+	}
+}
+
+//static
+S32 LLAPRFile::readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool)
+{
+	//*****************************************
+	apr_file_t* file_handle = open(filename, pool, APR_READ|APR_BINARY); 
+	//*****************************************	
+	if (!file_handle)
 	{
 		return 0;
 	}
+
+	S32 off;
+	if (offset < 0)
+		off = LLAPRFile::seek(file_handle, APR_END, 0);
 	else
+		off = LLAPRFile::seek(file_handle, APR_SET, offset);
+	
+	apr_size_t bytes_read;
+	if (off < 0)
 	{
-		llassert_always(sz <= 0x7fffffff);
-		return (S32)sz;
+		bytes_read = 0;
 	}
+	else
+	{
+		bytes_read = nbytes ;		
+		apr_status_t s = apr_file_read(file_handle, buf, &bytes_read);
+		if (s != APR_SUCCESS)
+		{
+			bytes_read = 0;
+		}
+		else
+		{
+			llassert_always(bytes_read <= 0x7fffffff);		
+		}
+	}
+	
+	//*****************************************
+	close(file_handle, pool) ; 
+	//*****************************************
+	return (S32)bytes_read;
 }
 
-S32 ll_apr_file_write_ex(const std::string& filename, apr_pool_t* pool, void *buf, S32 offset, S32 nbytes)
+//static
+S32 LLAPRFile::writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool)
 {
-	if (pool == NULL) pool = gAPRPoolp;
 	apr_int32_t flags = APR_CREATE|APR_WRITE|APR_BINARY;
 	if (offset < 0)
 	{
 		flags |= APR_APPEND;
 		offset = 0;
 	}
-	apr_file_t* filep = ll_apr_file_open(filename, flags, pool);
-	if (!filep)
+	
+	//*****************************************
+	apr_file_t* file_handle = open(filename, pool, flags);
+	//*****************************************
+	if (!file_handle)
 	{
 		return 0;
 	}
+
 	if (offset > 0)
 	{
-		offset = ll_apr_file_seek(filep, APR_SET, offset);
+		offset = LLAPRFile::seek(file_handle, APR_SET, offset);
 	}
-	S32 bytes_written;
+	
+	apr_size_t bytes_written;
 	if (offset < 0)
 	{
 		bytes_written = 0;
 	}
 	else
 	{
-		bytes_written = ll_apr_file_write(filep, buf, nbytes );
+		bytes_written = nbytes ;		
+		apr_status_t s = apr_file_write(file_handle, buf, &bytes_written);
+		if (s != APR_SUCCESS)
+		{
+			bytes_written = 0;
+		}
+		else
+		{
+			llassert_always(bytes_written <= 0x7fffffff);
+		}
 	}
-	apr_file_close(filep);
 
-	return bytes_written;
-}
+	//*****************************************
+	LLAPRFile::close(file_handle, pool);
+	//*****************************************
 
-S32 ll_apr_file_seek(apr_file_t* apr_file, apr_seek_where_t where, S32 offset)
-{
-	apr_status_t s;
-	apr_off_t apr_offset;
-	if (offset >= 0)
-	{
-		apr_offset = (apr_off_t)offset;
-		s = apr_file_seek(apr_file, where, &apr_offset);
-	}
-	else
-	{
-		apr_offset = 0;
-		s = apr_file_seek(apr_file, APR_END, &apr_offset);
-	}
-	if (s != APR_SUCCESS)
-	{
-		return -1;
-	}
-	else
-	{
-		llassert_always(apr_offset <= 0x7fffffff);
-		return (S32)apr_offset;
-	}
+	return (S32)bytes_written;
 }
 
-bool ll_apr_file_remove(const std::string& filename, apr_pool_t* pool)
+//static
+bool LLAPRFile::remove(const std::string& filename, LLVolatileAPRPool* pool)
 {
 	apr_status_t s;
-	if (pool == NULL) pool = gAPRPoolp;
-	s = apr_file_remove(filename.c_str(), pool);
+
+	pool = pool ? pool : LLAPRFile::sAPRFilePoolp ;
+	s = apr_file_remove(filename.c_str(), pool->getVolatileAPRPool());
+	pool->clearVolatileAPRPool() ;
+
 	if (s != APR_SUCCESS)
 	{
-		LL_DEBUGS("APR") << "ll_apr_file_remove failed on file: " << filename << LL_ENDL;
+		LL_DEBUGS("APR") << "LLAPRFile::remove failed on file: " << filename << LL_ENDL;
 		ll_apr_warn_status(s);
 		return false;
 	}
 	return true;
 }
 
-bool ll_apr_file_rename(const std::string& filename, const std::string& newname, apr_pool_t* pool)
+//static
+bool LLAPRFile::rename(const std::string& filename, const std::string& newname, LLVolatileAPRPool* pool)
 {
 	apr_status_t s;
-	if (pool == NULL) pool = gAPRPoolp;
-	s = apr_file_rename(filename.c_str(), newname.c_str(), pool);
+
+	pool = pool ? pool : LLAPRFile::sAPRFilePoolp ;
+	s = apr_file_rename(filename.c_str(), newname.c_str(), pool->getVolatileAPRPool());
+	pool->clearVolatileAPRPool() ;
+	
 	if (s != APR_SUCCESS)
 	{
-		LL_DEBUGS("APR") << "ll_apr_file_rename failed on file: " << filename << LL_ENDL;
+		LL_DEBUGS("APR") << "LLAPRFile::rename failed on file: " << filename << LL_ENDL;
 		ll_apr_warn_status(s);
 		return false;
 	}
 	return true;
 }
 
-bool ll_apr_file_exists(const std::string& filename, apr_pool_t* pool)
+//static
+bool LLAPRFile::isExist(const std::string& filename, LLVolatileAPRPool* pool, apr_int32_t flags)
 {
 	apr_file_t* apr_file;
 	apr_status_t s;
-	if (pool == NULL) pool = gAPRPoolp;
-	s = apr_file_open(&apr_file, filename.c_str(), APR_READ, APR_OS_DEFAULT, pool);
+
+	pool = pool ? pool : LLAPRFile::sAPRFilePoolp ;
+	s = apr_file_open(&apr_file, filename.c_str(), flags, APR_OS_DEFAULT, pool->getVolatileAPRPool());	
+
 	if (s != APR_SUCCESS || !apr_file)
 	{
+		pool->clearVolatileAPRPool() ;
 		return false;
 	}
 	else
 	{
-		apr_file_close(apr_file);
+		apr_file_close(apr_file) ;
+		pool->clearVolatileAPRPool() ;
 		return true;
 	}
 }
 
-S32 ll_apr_file_size(const std::string& filename, apr_pool_t* pool)
+//static
+S32 LLAPRFile::size(const std::string& filename, LLVolatileAPRPool* pool)
 {
 	apr_file_t* apr_file;
 	apr_finfo_t info;
 	apr_status_t s;
-	if (pool == NULL) pool = gAPRPoolp;
-	s = apr_file_open(&apr_file, filename.c_str(), APR_READ, APR_OS_DEFAULT, pool);
+	
+	pool = pool ? pool : LLAPRFile::sAPRFilePoolp ;
+	s = apr_file_open(&apr_file, filename.c_str(), APR_READ, APR_OS_DEFAULT, pool->getVolatileAPRPool());
+	
 	if (s != APR_SUCCESS || !apr_file)
-	{
+	{		
+		pool->clearVolatileAPRPool() ;
+		
 		return 0;
 	}
 	else
 	{
-		apr_status_t s = apr_file_info_get(&info, APR_FINFO_SIZE, apr_file);
-		apr_file_close(apr_file);
+		apr_status_t s = apr_file_info_get(&info, APR_FINFO_SIZE, apr_file);		
+
+		apr_file_close(apr_file) ;
+		pool->clearVolatileAPRPool() ;
+		
 		if (s == APR_SUCCESS)
 		{
 			return (S32)info.size;
@@ -381,31 +646,42 @@ S32 ll_apr_file_size(const std::string& filename, apr_pool_t* pool)
 	}
 }
 
-bool ll_apr_dir_make(const std::string& dirname, apr_pool_t* pool)
+//static
+bool LLAPRFile::makeDir(const std::string& dirname, LLVolatileAPRPool* pool)
 {
 	apr_status_t s;
-	if (pool == NULL) pool = gAPRPoolp;
-	s = apr_dir_make(dirname.c_str(), APR_FPROT_OS_DEFAULT, pool);
+
+	pool = pool ? pool : LLAPRFile::sAPRFilePoolp ;
+	s = apr_dir_make(dirname.c_str(), APR_FPROT_OS_DEFAULT, pool->getVolatileAPRPool());
+	pool->clearVolatileAPRPool() ;
+		
 	if (s != APR_SUCCESS)
 	{
-		LL_DEBUGS("APR") << "ll_apr_dir_make failed on file: " << dirname << LL_ENDL;
+		LL_DEBUGS("APR") << "LLAPRFile::makeDir failed on file: " << dirname << LL_ENDL;
 		ll_apr_warn_status(s);
 		return false;
 	}
 	return true;
 }
 
-bool ll_apr_dir_remove(const std::string& dirname, apr_pool_t* pool)
+//static
+bool LLAPRFile::removeDir(const std::string& dirname, LLVolatileAPRPool* pool)
 {
 	apr_status_t s;
-	if (pool == NULL) pool = gAPRPoolp;
-	s = apr_file_remove(dirname.c_str(), pool);
+
+	pool = pool ? pool : LLAPRFile::sAPRFilePoolp ;
+	s = apr_file_remove(dirname.c_str(), pool->getVolatileAPRPool());
+	pool->clearVolatileAPRPool() ;
+	
 	if (s != APR_SUCCESS)
 	{
-		LL_DEBUGS("APR") << "ll_apr_dir_remove failed on file: " << dirname << LL_ENDL;
+		LL_DEBUGS("APR") << "LLAPRFile::removeDir failed on file: " << dirname << LL_ENDL;
 		ll_apr_warn_status(s);
 		return false;
 	}
 	return true;
 }
-
+//
+//end of static components of LLAPRFile
+//*******************************************************************************************************************************
+//
diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h
index b8723562d71b13e7192689e50d6488fa48804fd3..44ad2dd50f9c60ec26272376916c87f8e0bc5395 100644
--- a/indra/llcommon/llapr.h
+++ b/indra/llcommon/llapr.h
@@ -61,18 +61,51 @@ void ll_init_apr();
  */
 void ll_cleanup_apr();
 
+//
+//LL apr_pool
+//manage apr_pool_t, destroy allocated apr_pool in the destruction function.
+//
 class LLAPRPool
 {
 public:
-	LLAPRPool(apr_pool_t *parent = NULL, apr_size_t size = 0) ;
+	LLAPRPool(apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE) ;
 	~LLAPRPool() ;
 
-	apr_pool_t* getAPRPool() {return mPool ; }
+	apr_pool_t* getAPRPool() ;
 	apr_status_t getStatus() {return mStatus ; }
 
+protected:
+	void releaseAPRPool() ;
+	void createAPRPool() ;
+
+protected:
+	apr_pool_t*  mPool ;              //pointing to an apr_pool
+	apr_pool_t*  mParent ;			  //parent pool
+	apr_size_t   mMaxSize ;           //max size of mPool, mPool should return memory to system if allocated memory beyond this limit. However it seems not to work.
+	apr_status_t mStatus ;            //status when creating the pool
+	BOOL         mReleasePoolFlag ;   //if set, mPool is destroyed when LLAPRPool is deleted. default value is true.
+};
+
+//
+//volatile LL apr_pool
+//which clears memory automatically.
+//so it can not hold static data or data after memory is cleared
+//
+class LLVolatileAPRPool : public LLAPRPool
+{
+public:
+	LLVolatileAPRPool(apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE);
+	~LLVolatileAPRPool(){}
+
+	apr_pool_t* getVolatileAPRPool() ;
+	
+	void        clearVolatileAPRPool() ;
+
+	BOOL        isFull() ;
+	BOOL        isEmpty() {return !mNumActiveRef ;}
 private:
-	apr_pool_t*  mPool ;
-	apr_status_t mStatus ;
+	S32 mNumActiveRef ; //number of active pointers pointing to the apr_pool.
+	S32 mNumTotalRef ;  //number of total pointers pointing to the apr_pool since last creating.   
 } ;
 
 /** 
@@ -145,24 +178,71 @@ typedef LLAtomic32<S32> LLAtomicS32;
 #define LL_APR_WB (APR_CREATE|APR_TRUNCATE|APR_WRITE|APR_BINARY) // "wb"
 #define LL_APR_RPB (APR_READ|APR_WRITE|APR_BINARY) // "r+b"
 #define LL_APR_WPB (APR_CREATE|APR_TRUNCATE|APR_READ|APR_WRITE|APR_BINARY) // "w+b"
-apr_file_t* ll_apr_file_open(const std::string& filename, apr_int32_t flags, S32* sizep, apr_pool_t* pool);
-apr_file_t* ll_apr_file_open(const std::string& filename, apr_int32_t flags, S32* sizep);
-apr_file_t* ll_apr_file_open(const std::string& filename, apr_int32_t flags, apr_pool_t* pool);
-apr_file_t* ll_apr_file_open(const std::string& filename, apr_int32_t flags);
-// Returns actual offset, -1 if seek fails
-S32 ll_apr_file_seek(apr_file_t* apr_file, apr_seek_where_t where, S32 offset);
-// Returns bytes read/written, 0 if read/write fails:
-S32 ll_apr_file_read(apr_file_t* apr_file, void* buf, S32 nbytes);
-S32 ll_apr_file_read_ex(const std::string& filename, apr_pool_t* pool, void *buf, S32 offset, S32 nbytes);
-S32 ll_apr_file_write(apr_file_t* apr_file, const void* buf, S32 nbytes);
-S32 ll_apr_file_write_ex(const std::string& filename, apr_pool_t* pool, void *buf, S32 offset, S32 nbytes);
-// returns false if failure:
-bool ll_apr_file_remove(const std::string& filename, apr_pool_t* pool = NULL);
-bool ll_apr_file_rename(const std::string& filename, const std::string& newname, apr_pool_t* pool = NULL);
-bool ll_apr_file_exists(const std::string& filename, apr_pool_t* pool = NULL);
-S32 ll_apr_file_size(const std::string& filename, apr_pool_t* pool = NULL);
-bool ll_apr_dir_make(const std::string& dirname, apr_pool_t* pool = NULL);
-bool ll_apr_dir_remove(const std::string& dirname, apr_pool_t* pool = NULL);
+
+//
+//apr_file manager
+//which: 1)only keeps one file open;
+//       2)closes the open file in the destruction function
+//       3)informs the apr_pool to clean the memory when the file is closed.
+//Note: please close an open file at the earliest convenience. 
+//      especially do not put some time-costly operations between open() and close().
+//      otherwise it might lock the APRFilePool.
+//there are two different apr_pools the APRFile can use:
+//      1, a temperary pool passed to an APRFile function, which is used within this function and only once.
+//      2, a global pool.
+//
+class LLAPRFile
+{
+private:
+	apr_file_t* mFile ;
+	LLVolatileAPRPool *mCurrentFilePoolp ; //currently in use apr_pool, could be one of them: sAPRFilePoolp, or a temp pool. 
+
+public:
+	LLAPRFile() ;
+	~LLAPRFile() ;
+
+	apr_status_t open(LLVolatileAPRPool* pool, const std::string& filename, apr_int32_t flags, S32* sizep = NULL);
+	apr_status_t open(const std::string& filename, apr_int32_t flags, apr_pool_t* pool = NULL, S32* sizep = NULL);
+	apr_status_t close() ;
+
+	// Returns actual offset, -1 if seek fails
+	S32 seek(apr_seek_where_t where, S32 offset);
+	apr_status_t eof() { return apr_file_eof(mFile);}
+
+	// Returns bytes read/written, 0 if read/write fails:
+	S32 read(void* buf, S32 nbytes);
+	S32 write(const void* buf, S32 nbytes);
+	
+	apr_file_t* getFileHandle() {return mFile;}	
+
+private:
+	apr_pool_t* getAPRFilePool(apr_pool_t* pool) ;
+
+//
+//*******************************************************************************************************************************
+//static components
+//
+public:
+	static LLVolatileAPRPool *sAPRFilePoolp ; //a global apr_pool for APRFile, which is used only when local pool does not exist.
+
+private:
+	static apr_file_t* open(const std::string& filename, LLVolatileAPRPool* pool, apr_int32_t flags);
+	static apr_status_t close(apr_file_t* file, LLVolatileAPRPool* pool) ;
+	static S32 seek(apr_file_t* file, apr_seek_where_t where, S32 offset);
+public:
+	// returns false if failure:
+	static bool remove(const std::string& filename, LLVolatileAPRPool* pool = NULL);
+	static bool rename(const std::string& filename, const std::string& newname, LLVolatileAPRPool* pool = NULL);
+	static bool isExist(const std::string& filename, LLVolatileAPRPool* pool = NULL, apr_int32_t flags = APR_READ);
+	static S32 size(const std::string& filename, LLVolatileAPRPool* pool = NULL);
+	static bool makeDir(const std::string& dirname, LLVolatileAPRPool* pool = NULL);
+	static bool removeDir(const std::string& dirname, LLVolatileAPRPool* pool = NULL);
+
+	// Returns bytes read/written, 0 if read/write fails:
+	static S32 readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL);	
+	static S32 writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL);	
+//*******************************************************************************************************************************
+};
 
 /**
  * @brief Function which approprately logs error or remains quiet on
diff --git a/indra/llcommon/llcrc.cpp b/indra/llcommon/llcrc.cpp
index ad4211f9e820483491b3603eace60cbe022155df..7f183dc9aefbe25a7b13f990c907481fae2d085a 100644
--- a/indra/llcommon/llcrc.cpp
+++ b/indra/llcommon/llcrc.cpp
@@ -197,6 +197,10 @@ void LLCRC::update(const std::string& filename)
 			update(data, nread);
 			delete[] data;
 		}
+		else
+		{
+			fclose(fp);
+		}
 	}
 }
 
diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp
index 2943d7b288a308f4fb74a299ced38c6197f9e628..5e520afab968035a7fdf41a25a0cbbc6e65cfd6e 100644
--- a/indra/llcommon/llerror.cpp
+++ b/indra/llcommon/llerror.cpp
@@ -990,6 +990,38 @@ namespace LLError
 		
 		return new std::ostringstream;
 	}
+	
+	void Log::flush(std::ostringstream* out, char* message)
+    {
+       LogLock lock;
+       if (!lock.ok())
+       {
+           return;
+       }
+       
+	   if(strlen(out->str().c_str()) < 128)
+	   {
+		   strcpy(message, out->str().c_str());
+	   }
+	   else
+	   {
+		   strncpy(message, out->str().c_str(), 127);
+		   message[127] = '\0' ;
+	   }
+	   
+	   Globals& g = Globals::get();
+       if (out == &g.messageStream)
+       {
+           g.messageStream.clear();
+           g.messageStream.str("");
+           g.messageStreamInUse = false;
+       }
+       else
+       {
+           delete out;
+       }
+	   return ;
+    }
 
 	void Log::flush(std::ostringstream* out, const CallSite& site)
 	{
@@ -1205,3 +1237,94 @@ namespace LLError
 	}
 }
 
+namespace LLError
+{     
+	char** LLCallStacks::sBuffer = NULL ;
+	S32    LLCallStacks::sIndex  = 0 ;
+
+	//static
+   void LLCallStacks::push(const char* function, const int line)
+   {
+	   if(!sBuffer)
+	   {
+		   sBuffer = new char*[512] ;
+		   sBuffer[0] = new char[512 * 128] ;
+		   for(S32 i = 1 ; i < 512 ; i++)
+		   {
+			   sBuffer[i] = sBuffer[i-1] + 128 ;
+		   }
+		   sIndex = 0 ;
+	   }
+
+	   if(sIndex > 511)
+	   {
+		   clear() ;
+	   }
+
+	   strcpy(sBuffer[sIndex], function) ;
+	   sprintf(sBuffer[sIndex] + strlen(function), " line: %d ", line) ;
+	   sIndex++ ;
+
+	   return ;
+   }
+
+	//static
+   std::ostringstream* LLCallStacks::insert(const char* function, const int line)
+   {
+       std::ostringstream* _out = LLError::Log::out();
+	   *_out << function << " line " << line << " " ;
+             
+	   return _out ;
+   }
+
+   //static
+   void LLCallStacks::end(std::ostringstream* _out)
+   {
+	   if(!sBuffer)
+	   {
+		   sBuffer = new char*[512] ;
+		   sBuffer[0] = new char[512 * 128] ;
+		   for(S32 i = 1 ; i < 512 ; i++)
+		   {
+			   sBuffer[i] = sBuffer[i-1] + 128 ;
+		   }
+		   sIndex = 0 ;
+	   }
+
+	   if(sIndex > 511)
+	   {
+		   clear() ;
+	   }
+
+	   LLError::Log::flush(_out, sBuffer[sIndex++]) ;	   
+   }
+
+   //static
+   void LLCallStacks::print()
+   {
+       if(sIndex > 0)
+       {
+           llinfos << " ************* PRINT OUT LL CALL STACKS ************* " << llendl ;
+           while(sIndex > 0)
+           {                  
+			   sIndex-- ;
+               llinfos << sBuffer[sIndex] << llendl ;
+           }
+           llinfos << " *************** END OF LL CALL STACKS *************** " << llendl ;
+       }
+
+	   if(sBuffer)
+	   {
+		   delete[] sBuffer[0] ;
+		   delete[] sBuffer ;
+		   sBuffer = NULL ;
+	   }
+   }
+
+   //static
+   void LLCallStacks::clear()
+   {
+       sIndex = 0 ;
+   }
+}
+
diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h
index e39d19741bfdf97cfd64ac49171626a2bda499c4..6794be4904966c3fc2e7f45e469043e22cdda452 100644
--- a/indra/llcommon/llerror.h
+++ b/indra/llcommon/llerror.h
@@ -38,6 +38,7 @@
 #include <typeinfo>
 
 #include "llerrorlegacy.h"
+#include "stdtypes.h"
 
 
 /* Error Logging Facility
@@ -135,6 +136,7 @@ namespace LLError
 	public:
 		static bool shouldLog(CallSite&);
 		static std::ostringstream* out();
+		static void flush(std::ostringstream* out, char* message)  ;
 		static void flush(std::ostringstream*, const CallSite&);
 	};
 	
@@ -179,9 +181,41 @@ namespace LLError
 		
 	class NoClassInfo { };
 		// used to indicate no class info known for logging
-}
 
+   //LLCallStacks keeps track of call stacks and output the call stacks to log file
+   //when LLAppViewer::handleViewerCrash() is triggered.
+   //
+   //Note: to be simple, efficient and necessary to keep track of correct call stacks, 
+	//LLCallStacks is designed not to be thread-safe.
+   //so try not to use it in multiple parallel threads at same time.
+   //Used in a single thread at a time is fine.
+   class LLCallStacks
+   {
+   private:
+       static char**  sBuffer ;
+	   static S32     sIndex ;
+          
+   public:   
+	   static void push(const char* function, const int line) ;
+	   static std::ostringstream* insert(const char* function, const int line) ;
+       static void print() ;
+       static void clear() ;
+	   static void end(std::ostringstream* _out) ;
+   }; 
+}
 
+//this is cheaper than llcallstacks if no need to output other variables to call stacks. 
+#define llpushcallstacks LLError::LLCallStacks::push(__FUNCTION__, __LINE__)
+#define llcallstacks \
+	{\
+       std::ostringstream* _out = LLError::LLCallStacks::insert(__FUNCTION__, __LINE__) ; \
+       (*_out)
+#define llcallstacksendl \
+		LLError::End(); \
+		LLError::LLCallStacks::end(_out) ; \
+	}
+#define llclearcallstacks LLError::LLCallStacks::clear()
+#define llprintcallstacks LLError::LLCallStacks::print() 
 
 /*
 	Class type information for logging
diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h
index 666aac70fc03926de9ea27cb3feb2a7c0885672a..94b51119e4e1f71d3507940512b33ccc32ef504d 100644
--- a/indra/llcommon/llfasttimer.h
+++ b/indra/llcommon/llfasttimer.h
@@ -71,6 +71,14 @@ class LLFastTimer
 		FTM_UPDATE_AVATAR,
 		
 		// common render components
+		FTM_SHADOW_GEOMETRY,
+		FTM_SHADOW_RENDER,
+		FTM_SHADOW_TERRAIN,
+		FTM_SHADOW_AVATAR,
+		FTM_SHADOW_SIMPLE,
+		FTM_SHADOW_ALPHA,
+		FTM_SHADOW_TREE,
+		
 		FTM_RENDER_GEOMETRY,
 		 FTM_RENDER_TERRAIN,
 		 FTM_RENDER_SIMPLE,
@@ -186,11 +194,13 @@ class LLFastTimer
 	enum { FTM_MAX_DEPTH = 64 };
 	
 public:
+	static LLFastTimer::EFastTimerType sCurType;
+
 	LLFastTimer(EFastTimerType type)
 	{
 #if FAST_TIMER_ON
 		mType = type;
-
+		sCurType = type;
 		// These don't get counted, because they use CPU clockticks
 		//gTimerBins[gCurTimerBin]++;
 		//LLTimer::sNumTimerCalls++;
diff --git a/indra/llcommon/llfixedbuffer.cpp b/indra/llcommon/llfixedbuffer.cpp
index d4cb604c5b37554c338ceaa6fa0942cf49fafe2d..e9d602937831c73a2d3cba94b0006898da8f2bff 100644
--- a/indra/llcommon/llfixedbuffer.cpp
+++ b/indra/llcommon/llfixedbuffer.cpp
@@ -33,6 +33,7 @@
 #include "llfixedbuffer.h"
 
 LLFixedBuffer::LLFixedBuffer(const U32 max_lines)
+			  : mMutex(NULL)
 {
 	mMaxLines = max_lines;
 	mTimer.reset();
@@ -47,9 +48,11 @@ LLFixedBuffer::~LLFixedBuffer()
 
 void LLFixedBuffer::clear()
 {
+	mMutex.lock() ;
 	mLines.clear();
 	mAddTimes.clear();
 	mLineLengths.clear();
+	mMutex.unlock() ;
 
 	mTimer.reset();
 }
@@ -70,9 +73,11 @@ void LLFixedBuffer::addLine(const LLWString& line)
 
 	removeExtraLines();
 
+	mMutex.lock() ;
 	mLines.push_back(line);
 	mLineLengths.push_back((S32)line.length());
 	mAddTimes.push_back(mTimer.getElapsedTimeF32());
+	mMutex.unlock() ;
 }
 
 
@@ -86,10 +91,12 @@ void LLFixedBuffer::setMaxLines(S32 max_lines)
 
 void LLFixedBuffer::removeExtraLines()
 {
+	mMutex.lock() ;
 	while ((S32)mLines.size() > llmax((S32)0, (S32)(mMaxLines - 1)))
 	{
 		mLines.pop_front();
 		mAddTimes.pop_front();
 		mLineLengths.pop_front();
 	}
+	mMutex.unlock() ;
 }
diff --git a/indra/llcommon/llfixedbuffer.h b/indra/llcommon/llfixedbuffer.h
index 5d84cd96cbe59173c57924ef259e8969b9cb6cb3..992a024df1a12594886ef7e45cc048f4421196ca 100644
--- a/indra/llcommon/llfixedbuffer.h
+++ b/indra/llcommon/llfixedbuffer.h
@@ -37,6 +37,7 @@
 #include <deque>
 #include <string>
 #include "llstring.h"
+#include "llthread.h"
 
 // Fixed size buffer for console output and other things.
 
@@ -53,14 +54,19 @@ class LLFixedBuffer
 	std::deque<S32>			mLineLengths;
 
 	void clear(); // Clear the buffer, and reset it.
-	virtual void addLine(const std::string& utf8line);
-	virtual void addLine(const LLWString& line);
+
+	//do not make these two "virtual"
+	void addLine(const std::string& utf8line);
+	void addLine(const LLWString& line);
 
 	// Get lines currently in the buffer, up to max_size chars, max_length lines
 	char *getLines(U32 max_size = 0, U32 max_length = 0); 
 	void setMaxLines(S32 max_lines);
 protected:
 	virtual void removeExtraLines();
+
+protected:
+	LLMutex mMutex ;
 };
 
 const U32 FIXED_BUF_MAX_LINE_LEN = 255; // Not including termnating 0
diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp
index 01647c671bfe43b56aa2b7d981696b77a08f5f0d..920d8c09777d0b0c148150e01216b5db443b7a41 100644
--- a/indra/llcommon/llthread.cpp
+++ b/indra/llcommon/llthread.cpp
@@ -102,12 +102,20 @@ LLThread::LLThread(const std::string& name, apr_pool_t *poolp) :
 		apr_pool_create(&mAPRPoolp, NULL); // Create a subpool for this thread
 	}
 	mRunCondition = new LLCondition(mAPRPoolp);
+
+	mLocalAPRFilePoolp = NULL ;
 }
 
 
 LLThread::~LLThread()
 {
 	shutdown();
+
+	if(mLocalAPRFilePoolp)
+	{
+		delete mLocalAPRFilePoolp ;
+		mLocalAPRFilePoolp = NULL ;
+	}
 }
 
 void LLThread::shutdown()
diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h
index d48d1ba7fa7bb03944db1f84a5d090fe8cce5508..c8c9fd4eecadc04347788f3e908b3ebc9b95ea1e 100644
--- a/indra/llcommon/llthread.h
+++ b/indra/llcommon/llthread.h
@@ -83,7 +83,8 @@ class LLThread
 	void start(void);
 
 	apr_pool_t *getAPRPool() { return mAPRPoolp; }
-	
+	LLVolatileAPRPool* getLocalAPRFilePool() { return mLocalAPRFilePoolp ; }
+
 private:
 	BOOL				mPaused;
 	
@@ -99,6 +100,11 @@ class LLThread
 	BOOL				mIsLocalPool;
 	EThreadStatus		mStatus;
 
+	//a local apr_pool for APRFile operations in this thread. If it exists, LLAPRFile::sAPRFilePoolp should not be used.
+	//Note: this pool is used by APRFile ONLY, do NOT use it for any other purposes.
+	//      otherwise it will cause severe memory leaking!!! --bao
+	LLVolatileAPRPool  *mLocalAPRFilePoolp ; 
+
 	void setQuitting();
 	
 	// virtual function overridden by subclass -- this will be called when the thread runs
diff --git a/indra/llcommon/llworkerthread.cpp b/indra/llcommon/llworkerthread.cpp
index cdc7c0234800a3065447bde5e4c7e9fa30b5c53e..5dda60075534e902230bdf28a28a3e847c8e758c 100644
--- a/indra/llcommon/llworkerthread.cpp
+++ b/indra/llcommon/llworkerthread.cpp
@@ -37,16 +37,18 @@
 #include "llframecallbackmanager.h"
 #endif
 
-BOOL LLWorkerClass::sDeleteLock = FALSE ;
 //============================================================================
 // Run on MAIN thread
 
 LLWorkerThread::LLWorkerThread(const std::string& name, bool threaded) :
-	LLQueuedThread(name, threaded),
-	mWorkerAPRPoolp(NULL)
+	LLQueuedThread(name, threaded)
 {
-	apr_pool_create(&mWorkerAPRPoolp, NULL);
-	mDeleteMutex = new LLMutex(getAPRPool());
+	mDeleteMutex = new LLMutex(NULL);
+
+	if(!mLocalAPRFilePoolp)
+	{
+		mLocalAPRFilePoolp = new LLVolatileAPRPool() ;
+	}
 }
 
 LLWorkerThread::~LLWorkerThread()
@@ -96,7 +98,6 @@ S32 LLWorkerThread::update(U32 max_time_ms)
 	{
 		(*iter)->abortWork(false);
 	}
-	LLWorkerClass::sDeleteLock = TRUE ;
 	for (std::vector<LLWorkerClass*>::iterator iter = delete_list.begin();
 		 iter != delete_list.end(); ++iter)
 	{
@@ -110,8 +111,7 @@ S32 LLWorkerThread::update(U32 max_time_ms)
 		}
 		delete *iter;
 	}
-	LLWorkerClass::sDeleteLock = FALSE ;
-    // delete and aborted entries mean there's still work to do
+	// delete and aborted entries mean there's still work to do
 	res += delete_list.size() + abort_list.size();
 	return res;
 }
@@ -188,7 +188,7 @@ LLWorkerClass::LLWorkerClass(LLWorkerThread* workerthread, const std::string& na
 	: mWorkerThread(workerthread),
 	  mWorkerClassName(name),
 	  mRequestHandle(LLWorkerThread::nullHandle()),
-	  mMutex(workerthread->getWorkerAPRPool()),
+	  mMutex(NULL),
 	  mWorkFlags(0)
 {
 	if (!mWorkerThread)
diff --git a/indra/llcommon/llworkerthread.h b/indra/llcommon/llworkerthread.h
index 745310840b1bb1949271ec16f4e6b884321f5e8e..19407f4463886b922163d9857a2bed49457db130 100644
--- a/indra/llcommon/llworkerthread.h
+++ b/indra/llcommon/llworkerthread.h
@@ -38,6 +38,7 @@
 #include <set>
 
 #include "llqueuedthread.h"
+#include "llapr.h"
 
 #define USE_FRAME_CALLBACK_MANAGER 0
 
@@ -82,14 +83,11 @@ class LLWorkerThread : public LLQueuedThread
 	typedef std::list<LLWorkerClass*> delete_list_t;
 	delete_list_t mDeleteList;
 	LLMutex* mDeleteMutex;
-	apr_pool_t* mWorkerAPRPoolp;
 	
 public:
 	LLWorkerThread(const std::string& name, bool threaded = true);
 	~LLWorkerThread();
 
-	apr_pool_t* getWorkerAPRPool() { return mWorkerAPRPoolp; }
-	
 	/*virtual*/ S32 update(U32 max_time_ms);
 	
 	handle_t addWorkRequest(LLWorkerClass* workerclass, S32 param, U32 priority = PRIORITY_NORMAL);
@@ -120,8 +118,6 @@ class LLWorkerClass
 	friend class LLWorkerThread;
 	friend class LLWorkerThread::WorkRequest;
 
-public:
-	static BOOL sDeleteLock ;
 public:
 	typedef LLWorkerThread::handle_t handle_t;
 	enum FLAGS
diff --git a/indra/llcrashlogger/llcrashlogger.cpp b/indra/llcrashlogger/llcrashlogger.cpp
index c550304c6b9eab8d84d23e2e03d632c65a7fc68b..78c4f8e7423eccf0b27a40b99a7f37d13012737a 100755
--- a/indra/llcrashlogger/llcrashlogger.cpp
+++ b/indra/llcrashlogger/llcrashlogger.cpp
@@ -392,7 +392,7 @@ bool LLCrashLogger::init()
 	if( gDirUtilp )
 	{
 		std::string marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.exec_marker");
-		ll_apr_file_remove( marker_file );
+		LLAPRFile::remove( marker_file );
 	}
 	
 	return true;
diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp
index bfa129ea1dcd21e60edb321e76db997aea194c5f..88edc9943c68ac0c8ffbaa6745bafa6b68ea6fb0 100644
--- a/indra/llimage/llimage.cpp
+++ b/indra/llimage/llimage.cpp
@@ -1513,7 +1513,9 @@ BOOL LLImageFormatted::load(const std::string &filename)
 	resetLastError();
 
 	S32 file_size = 0;
-	apr_file_t* apr_file = ll_apr_file_open(filename, LL_APR_RB, &file_size);
+	LLAPRFile infile ;
+	infile.open(filename, LL_APR_RB, NULL, &file_size);
+	apr_file_t* apr_file = infile.getFileHandle();
 	if (!apr_file)
 	{
 		setLastError("Unable to open file for reading", filename);
@@ -1522,7 +1524,6 @@ BOOL LLImageFormatted::load(const std::string &filename)
 	if (file_size == 0)
 	{
 		setLastError("File is empty",filename);
-		apr_file_close(apr_file);
 		return FALSE;
 	}
 
@@ -1540,8 +1541,7 @@ BOOL LLImageFormatted::load(const std::string &filename)
 	{
 		res = updateData();
 	}
-	apr_file_close(apr_file);
-
+	
 	return res;
 }
 
@@ -1549,16 +1549,16 @@ BOOL LLImageFormatted::save(const std::string &filename)
 {
 	resetLastError();
 
-	apr_file_t* apr_file = ll_apr_file_open(filename, LL_APR_WB);
-	if (!apr_file)
+	LLAPRFile outfile ;
+	outfile.open(filename, LL_APR_WB);
+	if (!outfile.getFileHandle())
 	{
 		setLastError("Unable to open file for writing", filename);
 		return FALSE;
 	}
 	
-	ll_apr_file_write(apr_file, getData(), 	getDataSize());
-	apr_file_close(apr_file);
-
+	outfile.write(getData(), 	getDataSize());
+	outfile.close() ;
 	return TRUE;
 }
 
diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp
index 52eb009cb7d25bf6e9e9a3965819455d87dd004e..1b93c219824c5974499dc6057768458174fd36fc 100644
--- a/indra/llimage/llimagej2c.cpp
+++ b/indra/llimage/llimagej2c.cpp
@@ -419,7 +419,9 @@ BOOL LLImageJ2C::loadAndValidate(const std::string &filename)
 	resetLastError();
 
 	S32 file_size = 0;
-	apr_file_t* apr_file = ll_apr_file_open(filename, LL_APR_RB, &file_size);
+	LLAPRFile infile ;
+	infile.open(filename, LL_APR_RB, NULL, &file_size);
+	apr_file_t* apr_file = infile.getFileHandle() ;
 	if (!apr_file)
 	{
 		setLastError("Unable to open file for reading", filename);
@@ -428,7 +430,6 @@ BOOL LLImageJ2C::loadAndValidate(const std::string &filename)
 	else if (file_size == 0)
 	{
 		setLastError("File is empty",filename);
-		apr_file_close(apr_file);
 		res = FALSE;
 	}
 	else
@@ -436,7 +437,8 @@ BOOL LLImageJ2C::loadAndValidate(const std::string &filename)
 		U8 *data = new U8[file_size];
 		apr_size_t bytes_read = file_size;
 		apr_status_t s = apr_file_read(apr_file, data, &bytes_read); // modifies bytes_read	
-		apr_file_close(apr_file);
+		infile.close() ;
+
 		if (s != APR_SUCCESS || (S32)bytes_read != file_size)
 		{
 			delete[] data;
@@ -448,7 +450,7 @@ BOOL LLImageJ2C::loadAndValidate(const std::string &filename)
 			res = validate(data, file_size);
 		}
 	}
-
+	
 	if (!mLastError.empty())
 	{
 		LLImage::setLastError(mLastError);
diff --git a/indra/llmath/llcamera.cpp b/indra/llmath/llcamera.cpp
index b782d4f3b9119e0efb96e78c480ba28bfce1411a..0f343bcefeefb6cf5a403c7de3170c6c6b8bc17c 100644
--- a/indra/llmath/llcamera.cpp
+++ b/indra/llmath/llcamera.cpp
@@ -178,28 +178,95 @@ S32 LLCamera::AABBInFrustum(const LLVector3 &center, const LLVector3& radius)
 	U8 mask = 0;
 	S32 result = 2;
 
-	for (U32 i = 0; i < mPlaneCount; i++)
-	{
-		mask = mAgentPlanes[i].mask;
-		LLPlane p = mAgentPlanes[i].p;
-		LLVector3 n = LLVector3(p);
-		float d = p.mV[3];
-		LLVector3 rscale = radius.scaledVec(scaler[mask]);
+	if (radius.magVecSquared() > mFrustumCornerDist * mFrustumCornerDist)
+	{ //box is larger than frustum, check frustum quads against box planes
 
-		LLVector3 minp = center - rscale;
-		LLVector3 maxp = center + rscale;
-
-		if (n * minp > -d) 
+		static const LLVector3 dir[] = 
 		{
-			return 0;
+			LLVector3(1, 0, 0),
+			LLVector3(-1, 0, 0),
+			LLVector3(0, 1, 0),
+			LLVector3(0, -1, 0),
+			LLVector3(0, 0, 1),
+			LLVector3(0, 0, -1)
+		};
+
+		U32 quads[] = 
+		{
+			0, 1, 2, 3,
+			0, 1, 5, 4,
+			2, 3, 7, 6,
+			3, 0, 7, 4,
+			1, 2, 6, 4,
+			4, 5, 6, 7
+		};
+
+		result = 0;
+
+		BOOL total_inside = TRUE;
+		for (U32 i = 0; i < 6; i++)
+		{ 
+			LLVector3 p = center + radius.scaledVec(dir[i]);
+			F32 d = -p*dir[i];
+
+			for (U32 j = 0; j <	6; j++)
+			{ //for each quad
+				F32 dist = mAgentFrustum[quads[j*4+0]]*dir[i] + d;
+				if (dist > 0)
+				{ //at least one frustum point is outside the AABB
+					total_inside = FALSE;
+					for (U32 k = 1; k < 4; k++)
+					{ //for each other point on quad
+						if ( mAgentFrustum[quads[j*4+k]]*dir[i]+d  <= 0.f)
+						{ //quad is straddling some plane of AABB
+							return 1;
+						}
+					}
+				}
+				else
+				{
+					for (U32 k = 1; k < 4; k++)
+					{
+						if (mAgentFrustum[quads[j*4+k]]*dir[i]+d > 0.f)
+						{
+							return 1;
+						}
+					}
+				}
+			}
 		}
-	
-		if (n * maxp > -d)
+
+		if (total_inside)
 		{
 			result = 1;
 		}
 	}
+	else
+	{
+		for (U32 i = 0; i < mPlaneCount; i++)
+		{
+			mask = mAgentPlanes[i].mask;
+			LLPlane p = mAgentPlanes[i].p;
+			LLVector3 n = LLVector3(p);
+			float d = p.mV[3];
+			LLVector3 rscale = radius.scaledVec(scaler[mask]);
+
+			LLVector3 minp = center - rscale;
+			LLVector3 maxp = center + rscale;
+
+			if (n * minp > -d) 
+			{
+				return 0;
+			}
+		
+			if (n * maxp > -d)
+			{
+				result = 1;
+			}
+		}
+	}
 
+	
 	return result;
 }
 
diff --git a/indra/llmath/llmath.h b/indra/llmath/llmath.h
index 5e987f31937b55379d0e622ccfd858cc77127bdd..12fc11671415caae0e0455646e1fb769717016ad 100644
--- a/indra/llmath/llmath.h
+++ b/indra/llmath/llmath.h
@@ -86,6 +86,8 @@ const F32	GRAVITY			= -9.8f;
 const F32	F_PI		= 3.1415926535897932384626433832795f;
 const F32	F_TWO_PI	= 6.283185307179586476925286766559f;
 const F32	F_PI_BY_TWO	= 1.5707963267948966192313216916398f;
+const F32	F_SQRT_TWO_PI = 2.506628274631000502415765284811f;
+const F32	F_E			= 2.71828182845904523536f;
 const F32	F_SQRT2		= 1.4142135623730950488016887242097f;
 const F32	F_SQRT3		= 1.73205080756888288657986402541f;
 const F32	OO_SQRT2	= 0.7071067811865475244008443621049f;
@@ -548,4 +550,10 @@ inline U32 get_next_power_two(U32 val, U32 max_power_two)
 	return val;
 }
 
+//get the gaussian value given the linear distance from axis x and guassian value o
+inline F32 llgaussian(F32 x, F32 o)
+{
+	return 1.f/(F_SQRT_TWO_PI*o)*powf(F_E, -(x*x)/(2*o*o));
+}
+
 #endif
diff --git a/indra/llmessage/llares.cpp b/indra/llmessage/llares.cpp
index af6b7fee2cbe5e5ace6b31add7a93bc316ddf97c..fe37fe8142c1fd6102cda912f9787ee4dae642fc 100644
--- a/indra/llmessage/llares.cpp
+++ b/indra/llmessage/llares.cpp
@@ -470,9 +470,7 @@ bool LLAres::process(U64 timeout)
 
 	int socks[ARES_GETSOCK_MAXNUM];
 	apr_pollfd_t aprFds[ARES_GETSOCK_MAXNUM];
-	apr_int32_t nsds = 0;
-	apr_status_t status;
-	apr_pool_t *pool;
+	apr_int32_t nsds = 0;	
 	int nactive = 0;
 	int bitmask;
 
@@ -480,10 +478,12 @@ bool LLAres::process(U64 timeout)
 
 	if (bitmask == 0)
 	{
-		goto bail;
+		return nsds > 0;
 	}
 
-	status = apr_pool_create(&pool, gAPRPoolp);
+	apr_status_t status;
+	LLAPRPool pool;
+	status = pool.getStatus() ;
 	ll_apr_assert_status(status);
 
 	for (int i = 0; i < ARES_GETSOCK_MAXNUM; i++)
@@ -501,16 +501,16 @@ bool LLAres::process(U64 timeout)
 
 		apr_socket_t *aprSock = NULL;
 
-		status = apr_os_sock_put(&aprSock, (apr_os_sock_t *) &socks[i], pool);
+		status = apr_os_sock_put(&aprSock, (apr_os_sock_t *) &socks[i], pool.getAPRPool());
 		if (status != APR_SUCCESS)
 		{
 			ll_apr_warn_status(status);
-			goto bail_pool;
+			return nsds > 0;
 		}
 
 		aprFds[nactive].desc.s = aprSock;
 		aprFds[nactive].desc_type = APR_POLL_SOCKET;
-		aprFds[nactive].p = pool;
+		aprFds[nactive].p = pool.getAPRPool();
 		aprFds[nactive].rtnevents = 0;
 		aprFds[nactive].client_data = &socks[i];
 
@@ -538,10 +538,6 @@ bool LLAres::process(U64 timeout)
 		}
 	}
 
-bail_pool:
-	apr_pool_destroy(pool);
-
-bail:
 	return nsds > 0;
 }
 
diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp
index 6ef97bea586bfb205f4b1214f0d28a1e2ec5963c..46e976fe35ddab9c9e4f29ec5f9e369209303d74 100644
--- a/indra/llmessage/llurlrequest.cpp
+++ b/indra/llmessage/llurlrequest.cpp
@@ -44,7 +44,7 @@
 #include "llsd.h"
 #include "llstring.h"
 #include "apr_env.h"
-
+#include "llapr.h"
 static const U32 HTTP_STATUS_PIPE_ERROR = 499;
 
 /**
@@ -166,18 +166,16 @@ void LLURLRequest::useProxy(bool use_proxy)
     if (use_proxy && (env_proxy == NULL))
     {
         apr_status_t status;
-        apr_pool_t* pool;
-        apr_pool_create(&pool, NULL);
-        status = apr_env_get(&env_proxy, "ALL_PROXY", pool);
+        LLAPRPool pool;
+		status = apr_env_get(&env_proxy, "ALL_PROXY", pool.getAPRPool());
         if (status != APR_SUCCESS)
         {
-            status = apr_env_get(&env_proxy, "http_proxy", pool);
+			status = apr_env_get(&env_proxy, "http_proxy", pool.getAPRPool());
         }
         if (status != APR_SUCCESS)
         {
            use_proxy = FALSE;
         }
-        apr_pool_destroy(pool);
     }
 
 
diff --git a/indra/llrender/CMakeLists.txt b/indra/llrender/CMakeLists.txt
index 76858d9839507ecea7894dab9fc8960a8666a6d4..72aa3715c088150c7f7f95fd54d863128bf2f1c7 100644
--- a/indra/llrender/CMakeLists.txt
+++ b/indra/llrender/CMakeLists.txt
@@ -27,9 +27,7 @@ set(llrender_SOURCE_FILES
     llglslshader.cpp
     llimagegl.cpp
     llpostprocess.cpp
-    llrender.cpp
     llrendersphere.cpp
-    llrendertarget.cpp
     llshadermgr.cpp
     llvertexbuffer.cpp
     )
@@ -50,7 +48,6 @@ set(llrender_HEADER_FILES
     llpostprocess.h
     llrender.h
     llrendersphere.h
-    llrendertarget.h
     llshadermgr.h
     llvertexbuffer.h
     )
@@ -63,6 +60,7 @@ list(APPEND llrender_SOURCE_FILES ${llrender_HEADER_FILES})
 if (SERVER AND NOT WINDOWS AND NOT DARWIN)
   copy_server_sources(
       llgl
+      llrender
       )
 
 
@@ -78,6 +76,8 @@ if (SERVER AND NOT WINDOWS AND NOT DARWIN)
 else (SERVER AND NOT WINDOWS AND NOT DARWIN)
   list(APPEND llrender_SOURCE_FILES
       llgl.cpp
+      llrender.cpp
+      llrendertarget.cpp
       )
 endif (SERVER AND NOT WINDOWS AND NOT DARWIN)
 add_library (llrender ${llrender_SOURCE_FILES})
diff --git a/indra/llrender/llcubemap.cpp b/indra/llrender/llcubemap.cpp
index 14b95c25e73193feb828f43b50802c68690fd47b..754d90c854071562504c53eb5078b88fcc54be94 100644
--- a/indra/llrender/llcubemap.cpp
+++ b/indra/llrender/llcubemap.cpp
@@ -85,9 +85,9 @@ void LLCubeMap::initGL()
 		// Not initialized, do stuff.
 		if (mImages[0].isNull())
 		{
-			GLuint texname = 0;
+			U32 texname = 0;
 			
-			glGenTextures(1, &texname);
+			LLImageGL::generateTextures(1, &texname);
 
 			for (int i = 0; i < 6; i++)
 			{
@@ -97,9 +97,10 @@ void LLCubeMap::initGL()
 				mImages[i]->createGLTexture(0, mRawImages[i], texname);
 				
 				gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_CUBE_MAP, texname); 
-				mImages[i]->setClampCubemap (TRUE, TRUE, TRUE);
+				mImages[i]->setAddressMode(LLTexUnit::TAM_CLAMP);
 				stop_glerror();
 			}
+			gGL.getTexUnit(0)->disable();
 		}
 		disable();
 	}
@@ -311,8 +312,8 @@ void LLCubeMap::restoreMatrix()
 void LLCubeMap::setReflection (void)
 {
 	gGL.getTexUnit(mTextureStage)->bindManual(LLTexUnit::TT_CUBE_MAP, getGLName());
-	mImages[0]->setMipFilterNearest (FALSE, FALSE);
-	mImages[0]->setClampCubemap (TRUE, TRUE);
+	mImages[0]->setFilteringOption(LLTexUnit::TFO_ANISOTROPIC);
+	mImages[0]->setAddressMode(LLTexUnit::TAM_CLAMP);
 }
 
 LLVector3 LLCubeMap::map(U8 side, U16 v_val, U16 h_val) const
diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp
index 846f18f4a992318607c4d699e6f9c5e222068a16..3829306e25a075e6c5cafd9e649ebf87c599e8df 100644
--- a/indra/llrender/llfontgl.cpp
+++ b/indra/llrender/llfontgl.cpp
@@ -535,7 +535,7 @@ BOOL LLFontGL::loadFace(const std::string& filename,
 	}
 	mImageGLp->createGLTexture(0, mRawImageGLp);
 	gGL.getTexUnit(0)->bind(mImageGLp);
-	mImageGLp->setMipFilterNearest(TRUE, TRUE);
+	mImageGLp->setFilteringOption(LLTexUnit::TFO_POINT);
 	return TRUE;
 }
 
@@ -549,7 +549,7 @@ BOOL LLFontGL::addChar(const llwchar wch)
 	stop_glerror();
 	mImageGLp->setSubImage(mRawImageGLp, 0, 0, mImageGLp->getWidth(), mImageGLp->getHeight());
 	gGL.getTexUnit(0)->bind(mImageGLp);
-	mImageGLp->setMipFilterNearest(TRUE, TRUE);
+	mImageGLp->setFilteringOption(LLTexUnit::TFO_POINT);
 	stop_glerror();
 	return TRUE;
 }
@@ -565,7 +565,7 @@ S32 LLFontGL::renderUTF8(const std::string &text, const S32 offset,
 					 BOOL use_ellipses) const
 {
 	LLWString wstr = utf8str_to_wstring(text);
-	return render(wstr, offset, x, y, color, halign, valign, style, max_chars, max_pixels, right_x, use_ellipses);
+	return render(wstr, offset, x, y, color, halign, valign, style, max_chars, max_pixels, right_x, FALSE, use_ellipses);
 }
 
 S32 LLFontGL::render(const LLWString &wstr, 
@@ -1104,59 +1104,32 @@ S32	LLFontGL::firstDrawableChar(const llwchar* wchars, F32 max_pixels, S32 text_
 		llwchar wch = wchars[i];
 
 		const embedded_data_t* ext_data = getEmbeddedCharData(wch);
-		if (ext_data)
-		{
-			F32 char_width = getEmbeddedCharAdvance(ext_data);
-
-			if( scaled_max_pixels < (total_width + char_width) )
-			{
-				break;
-			}
-
-			total_width += char_width;
-
-			drawable_chars++;
-			if( max_chars >= 0 && drawable_chars >= max_chars )
-			{
-				break;
-			}
-
-			if ( i > 0 )
-			{
-				total_width += EXT_KERNING * sScaleX;
-			}
+		F32 char_width = ext_data ? getEmbeddedCharAdvance(ext_data) : getXAdvance(wch);
 
-			// Round after kerning.
-			total_width = (F32)llfloor(total_width + 0.5f);
-		}
-		else
+		if( scaled_max_pixels < (total_width + char_width) )
 		{
-			F32 char_width = getXAdvance(wch);
-			if( scaled_max_pixels < (total_width + char_width) )
-			{
-				break;
-			}
-
-			total_width += char_width;
+			break;
+		}
 
-			drawable_chars++;
-			if( max_chars >= 0 && drawable_chars >= max_chars )
-			{
-				break;
-			}
+		total_width += char_width;
+		drawable_chars++;
 
-			if ( i > 0 )
-			{
-				// Kerning
-				total_width += getXKerning(wchars[i-1], wch);
-			}
+		if( max_chars >= 0 && drawable_chars >= max_chars )
+		{
+			break;
+		}
 
-			// Round after kerning.
-			total_width = (F32)llfloor(total_width + 0.5f);
+		if ( i > 0 )
+		{
+			// kerning
+			total_width += ext_data ? (EXT_KERNING * sScaleX) : getXKerning(wchars[i-1], wch);
 		}
+
+		// Round after kerning.
+		total_width = llround(total_width);
 	}
 
-	return text_len - drawable_chars;
+	return start_pos - drawable_chars;
 }
 
 
diff --git a/indra/llrender/llfontgl.h b/indra/llrender/llfontgl.h
index b369e42ce1e5acd23e787b5464014a49fdb017c8..f8da460de2785389759c2cd1119e7a8c587f86cb 100644
--- a/indra/llrender/llfontgl.h
+++ b/indra/llrender/llfontgl.h
@@ -181,7 +181,7 @@ class LLFontGL : public LLFont
 								 F32* drawn_pixels = NULL) const;
 
 	// Returns the index of the first complete characters from text that can be drawn in max_pixels
-	// starting on the right side (at character start_pos).
+	// given that the character at start_pos should be the last character (or as close to last as possible).
 	virtual S32	firstDrawableChar(const llwchar* wchars, F32 max_pixels, S32 text_len, S32 start_pos=S32_MAX, S32 max_chars = S32_MAX) const;
 
 	// Returns the index of the character closest to pixel position x (ignoring text to the right of max_pixels and max_chars)
diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index 74313974c965478cf9d9dd3fddd204abd1c75860..61194c4ecfa3a48f413e1d9012f5b669be659728 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -133,6 +133,15 @@ PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT = NULL;
 PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glGetFramebufferAttachmentParameterivEXT = NULL;
 PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT = NULL;
 
+// GL_EXT_framebuffer_multisample
+PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glRenderbufferStorageMultisampleEXT = NULL;
+
+// GL_EXT_framebuffer_blit
+PFNGLBLITFRAMEBUFFEREXTPROC glBlitFramebufferEXT = NULL;
+
+// GL_ARB_draw_buffers
+PFNGLDRAWBUFFERSARBPROC glDrawBuffersARB = NULL;
+
 //shader object prototypes
 PFNGLDELETEOBJECTARBPROC glDeleteObjectARB = NULL;
 PFNGLGETHANDLEARBPROC glGetHandleARB = NULL;
@@ -249,6 +258,12 @@ PFNGLGETATTRIBLOCATIONARBPROC glGetAttribLocationARB = NULL;
 PFNWGLSWAPINTERVALEXTPROC			wglSwapIntervalEXT = NULL;
 #endif
 
+#if LL_LINUX_NV_GL_HEADERS
+// linux nvidia headers.  these define these differently to mesa's.  ugh.
+PFNGLACTIVETEXTUREARBPROC glActiveTextureARB = NULL;
+PFNGLCLIENTACTIVETEXTUREARBPROC glClientActiveTextureARB = NULL;
+PFNGLDRAWRANGEELEMENTSPROC glDrawRangeElements = NULL;
+#endif // LL_LINUX_NV_GL_HEADERS
 #endif
 
 LLGLManager gGLManager;
@@ -262,6 +277,7 @@ LLGLManager::LLGLManager() :
 	mHasMipMapGeneration(FALSE),
 	mHasCompressedTextures(FALSE),
 	mHasFramebufferObject(FALSE),
+	mHasFramebufferMultisample(FALSE),
 
 	mHasVertexBufferObject(FALSE),
 	mHasPBuffer(FALSE),
@@ -560,6 +576,16 @@ void LLGLManager::initExtensions()
 	mHasFramebufferObject = TRUE;
 # else
 	mHasFramebufferObject = FALSE;
+# endif
+# if GL_EXT_framebuffer_multisample
+	mHasFramebufferMultisample = TRUE;
+# else
+	mHasFramebufferMultisample = FALSE;
+# endif
+# if GL_ARB_draw_buffers
+	mHasDrawBuffers = TRUE;
+#else
+	mHasDrawBuffers = FALSE;
 # endif
 	mHasMipMapGeneration = FALSE;
 	mHasSeparateSpecularColor = FALSE;
@@ -584,6 +610,8 @@ void LLGLManager::initExtensions()
 	// mask out FBO support when packed_depth_stencil isn't there 'cause we need it for LLRenderTarget -Brad
 	mHasFramebufferObject = ExtensionExists("GL_EXT_framebuffer_object", gGLHExts.mSysExts)
 		&& ExtensionExists("GL_EXT_packed_depth_stencil", gGLHExts.mSysExts);
+	mHasFramebufferMultisample = mHasFramebufferObject && ExtensionExists("GL_EXT_framebuffer_multisample", gGLHExts.mSysExts);
+	mHasDrawBuffers = ExtensionExists("GL_ARB_draw_buffers", gGLHExts.mSysExts);
 #if !LL_DARWIN
 	mHasPointParameters = !mIsATI && ExtensionExists("GL_ARB_point_parameters", gGLHExts.mSysExts);
 #endif
@@ -604,6 +632,8 @@ void LLGLManager::initExtensions()
 		mHasCompressedTextures = FALSE;
 		mHasVertexBufferObject = FALSE;
 		mHasFramebufferObject = FALSE;
+		mHasFramebufferMultisample = FALSE;
+		mHasDrawBuffers = FALSE;
 		mHasMipMapGeneration = FALSE;
 		mHasSeparateSpecularColor = FALSE;
 		mHasAnisotropic = FALSE;
@@ -653,6 +683,9 @@ void LLGLManager::initExtensions()
 		if (strchr(blacklist,'o')) mHasFragmentShader = FALSE;//S
 		if (strchr(blacklist,'p')) mHasPointParameters = FALSE;//S
 		if (strchr(blacklist,'q')) mHasFramebufferObject = FALSE;//S
+		if (strchr(blacklist,'r')) mHasDrawBuffers = FALSE;//S
+		if (strchr(blacklist,'s')) mHasFramebufferMultisample = FALSE;
+
 	}
 #endif // LL_LINUX || LL_SOLARIS
 	
@@ -761,15 +794,29 @@ void LLGLManager::initExtensions()
 		glGetFramebufferAttachmentParameterivEXT = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glGetFramebufferAttachmentParameterivEXT");
 		glGenerateMipmapEXT = (PFNGLGENERATEMIPMAPEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glGenerateMipmapEXT");
 	}
-#if !LL_LINUX && !LL_SOLARIS
-	// This is expected to be a static symbol on Linux GL implementations
+	if (mHasFramebufferMultisample)
+	{
+		glRenderbufferStorageMultisampleEXT = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glRenderbufferStorageMultisampleEXT");
+		glBlitFramebufferEXT = (PFNGLBLITFRAMEBUFFEREXTPROC) GLH_EXT_GET_PROC_ADDRESS("glBlitFramebufferEXT");
+	}
+	if (mHasDrawBuffers)
+	{
+		glDrawBuffersARB = (PFNGLDRAWBUFFERSARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDrawBuffersARB");
+	}
+#if (!LL_LINUX && !LL_SOLARIS) || LL_LINUX_NV_GL_HEADERS
+	// This is expected to be a static symbol on Linux GL implementations, except if we use the nvidia headers - bah
 	glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC)GLH_EXT_GET_PROC_ADDRESS("glDrawRangeElements");
 	if (!glDrawRangeElements)
 	{
 		mGLMaxVertexRange = 0;
 		mGLMaxIndexRange = 0;
 	}
-#endif // !LL_LINUX
+#endif // !LL_LINUX || LL_LINUX_NV_GL_HEADERS
+#if LL_LINUX_NV_GL_HEADERS
+	// nvidia headers are critically different from mesa-esque
+ 	glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC)GLH_EXT_GET_PROC_ADDRESS("glActiveTextureARB");
+ 	glClientActiveTextureARB = (PFNGLCLIENTACTIVETEXTUREARBPROC)GLH_EXT_GET_PROC_ADDRESS("glClientActiveTextureARB");
+#endif // LL_LINUX_NV_GL_HEADERS
 
 	if (mHasOcclusionQuery)
 	{
@@ -946,7 +993,7 @@ void assert_glerror()
 		{
 			// gluErrorString returns NULL for some extensions' error codes.
 			// you'll probably have to grep for the number in glext.h.
-			LL_WARNS("RenderState") << "GL Error: UNKNOWN 0x" << std::hex << error << LL_ENDL;
+			LL_WARNS("RenderState") << "GL Error: UNKNOWN 0x" << std::hex << error << std::dec << LL_ENDL;
 		}
 		error = glGetError();
 #endif
@@ -986,6 +1033,11 @@ void LLGLState::initClass()
 	//make sure multisample defaults to disabled
 	sStateMap[GL_MULTISAMPLE_ARB] = GL_FALSE;
 	glDisable(GL_MULTISAMPLE_ARB);
+
+	sStateMap[GL_MULTISAMPLE_ARB] = GL_FALSE;
+	glDisable(GL_MULTISAMPLE_ARB);
+
+	glEnableClientState(GL_VERTEX_ARRAY);
 }
 
 //static
@@ -1037,7 +1089,7 @@ void LLGLState::checkStates(const std::string& msg)
 	
 	if (src != GL_SRC_ALPHA || dst != GL_ONE_MINUS_SRC_ALPHA)
 	{
-		LL_GL_ERRS << "Blend function corrupted: " << std::hex << src << " " << std::hex << dst << "  " << msg << LL_ENDL;
+		LL_GL_ERRS << "Blend function corrupted: " << std::hex << src << " " << std::hex << dst << "  " << msg << std::dec << LL_ENDL;
 	}
 	
 	for (std::map<LLGLenum, LLGLboolean>::iterator iter = sStateMap.begin();
@@ -1076,7 +1128,7 @@ void LLGLState::checkTextureChannels(const std::string& msg)
 		if (tex_env_mode != GL_MODULATE)
 		{
 			error = TRUE;
-			LL_WARNS("RenderState") << "GL_TEXTURE_ENV_MODE invalid: " << std::hex << tex_env_mode << LL_ENDL;
+			LL_WARNS("RenderState") << "GL_TEXTURE_ENV_MODE invalid: " << std::hex << tex_env_mode << std::dec << LL_ENDL;
 		}
 	}
 
@@ -1092,7 +1144,8 @@ void LLGLState::checkTextureChannels(const std::string& msg)
 		"GL_TEXTURE_GEN_S",
 		"GL_TEXTURE_GEN_T",
 		"GL_TEXTURE_GEN_Q",
-		"GL_TEXTURE_GEN_R"
+		"GL_TEXTURE_GEN_R",
+		"GL_TEXTURE_RECTANGLE_ARB"
 	};
 
 	static GLint value[] =
@@ -1104,7 +1157,8 @@ void LLGLState::checkTextureChannels(const std::string& msg)
 		GL_TEXTURE_GEN_S,
 		GL_TEXTURE_GEN_T,
 		GL_TEXTURE_GEN_Q,
-		GL_TEXTURE_GEN_R
+		GL_TEXTURE_GEN_R,
+		GL_TEXTURE_RECTANGLE_ARB
 	};
 
 	GLint stackDepth = 0;
@@ -1132,7 +1186,7 @@ void LLGLState::checkTextureChannels(const std::string& msg)
 			LL_WARNS("RenderState") << "Texture matrix in channel " << i << " corrupt." << LL_ENDL;
 		}
 
-		for (S32 j = (i == 0 ? 1 : 0); j < 8; j++)
+		for (S32 j = (i == 0 ? 1 : 0); j < 9; j++)
 		{
 			if (glIsEnabled(value[j]))
 			{
@@ -1140,6 +1194,18 @@ void LLGLState::checkTextureChannels(const std::string& msg)
 				LL_WARNS("RenderState") << "Texture channel " << i << " still has " << label[j] << " enabled." << LL_ENDL;
 			}
 		}
+
+		glh::matrix4f mat;
+		glh::matrix4f identity;
+		identity.identity();
+
+		glGetFloatv(GL_TEXTURE_MATRIX, mat.m);
+
+		if (mat != identity)
+		{
+			error = TRUE;
+			LL_WARNS("RenderState") << "Texture matrix " << i << " is not identity." << LL_ENDL;
+		}
 	}
 
 	gGL.getTexUnit(0)->activate();
@@ -1261,6 +1327,22 @@ void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask)
 	glClientActiveTextureARB(GL_TEXTURE0_ARB);
 	gGL.getTexUnit(0)->activate();
 
+	if (gGLManager.mHasVertexShader)
+	{	//make sure vertex attribs are all disabled
+		GLint count;
+		glGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, &count);
+		for (GLint i = 0; i < count; i++)
+		{
+			GLint enabled;
+			glGetVertexAttribivARB((GLuint) i, GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB, &enabled);
+			if (enabled)
+			{
+				error = TRUE;
+				LL_WARNS("RenderState") << "GL still has vertex attrib array " << i << " enabled." << LL_ENDL;
+			}
+		}
+	}
+
 	if (error)
 	{
 		LL_GL_ERRS << "GL client array corruption detected.  " << msg << LL_ENDL;
@@ -1646,6 +1728,7 @@ void LLGLNamePool::cleanupPools()
 LLGLDepthTest::LLGLDepthTest(GLboolean depth_enabled, GLboolean write_enabled, GLenum depth_func)
 : mPrevDepthEnabled(sDepthEnabled), mPrevDepthFunc(sDepthFunc), mPrevWriteEnabled(sWriteEnabled)
 {
+	stop_glerror();
 	if (depth_enabled != sDepthEnabled)
 	{
 		gGL.flush();
diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h
index 8caef2016e4cf79f4d98d8836c22f1ce78d9d064..00ff1e2f53d3631a4374d433494697a99894ce6d 100644
--- a/indra/llrender/llgl.h
+++ b/indra/llrender/llgl.h
@@ -77,7 +77,8 @@ class LLGLManager
 	BOOL mHasMipMapGeneration;
 	BOOL mHasCompressedTextures;
 	BOOL mHasFramebufferObject;
-
+	BOOL mHasFramebufferMultisample;
+	
 	// ARB Extensions
 	BOOL mHasVertexBufferObject;
 	BOOL mHasPBuffer;
@@ -86,6 +87,7 @@ class LLGLManager
 	BOOL mHasFragmentShader;
 	BOOL mHasOcclusionQuery;
 	BOOL mHasPointParameters;
+	BOOL mHasDrawBuffers;
 
 	// Other extensions.
 	BOOL mHasAnisotropic;
diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h
index e9a9ad1a7722a308811783293e633adb8c6c0018..91a01a926645577f1fa318116478493218aa1b1c 100644
--- a/indra/llrender/llglheaders.h
+++ b/indra/llrender/llglheaders.h
@@ -281,6 +281,18 @@ extern PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT;
 #undef Status
 #endif // LL_LINUX && !LL_MESA_HEADLESS
 
+#if LL_LINUX && defined(WINGDIAPI)
+// WINGDIAPI gets set if we are using the linux nvidia gl.h header which needs
+// the functions below setting up.
+# define LL_LINUX_NV_GL_HEADERS
+#endif // LL_LINUX && defined(WINGDIAPI)
+
+#ifdef LL_LINUX_NV_GL_HEADERS
+// Missing functions when using nvidia headers:
+extern PFNGLACTIVETEXTUREARBPROC	glActiveTextureARB;
+extern PFNGLCLIENTACTIVETEXTUREARBPROC	glClientActiveTextureARB;
+extern PFNGLDRAWRANGEELEMENTSPROC 	glDrawRangeElements;
+#endif // LL_LINUX_NV_GL_HEADERS
 
 // GL_ARB_vertex_buffer_object
 extern PFNGLBINDBUFFERARBPROC		glBindBufferARB;
@@ -435,8 +447,6 @@ extern PFNGLGETATTRIBLOCATIONARBPROC glGetAttribLocationARB;
 extern PFNGLCOMPRESSEDTEXIMAGE2DARBPROC glCompressedTexImage2DARB;
 extern PFNGLGETCOMPRESSEDTEXIMAGEARBPROC glGetCompressedTexImageARB;
 
-extern PFNGLCOLORTABLEEXTPROC glColorTableEXT;
-
 //GL_EXT_framebuffer_object
 extern PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT;
 extern PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT;
@@ -456,6 +466,14 @@ extern PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT;
 extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glGetFramebufferAttachmentParameterivEXT;
 extern PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT;
 
+// GL_EXT_framebuffer_multisample
+extern PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glRenderbufferStorageMultisampleEXT;
+
+// GL_EXT_framebuffer_blit
+extern PFNGLBLITFRAMEBUFFEREXTPROC glBlitFramebufferEXT;
+
+//GL_ARB_draw_buffers
+extern PFNGLDRAWBUFFERSARBPROC glDrawBuffersARB;
 
 #elif LL_WINDOWS
 
@@ -644,6 +662,14 @@ extern PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT;
 extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glGetFramebufferAttachmentParameterivEXT;
 extern PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT;
 
+// GL_EXT_framebuffer_multisample
+extern PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glRenderbufferStorageMultisampleEXT;
+
+// GL_EXT_framebuffer_blit
+extern PFNGLBLITFRAMEBUFFEREXTPROC glBlitFramebufferEXT;
+
+//GL_ARB_draw_buffers
+extern PFNGLDRAWBUFFERSARBPROC glDrawBuffersARB;
 
 #elif LL_DARWIN
 //----------------------------------------------------------------------------
@@ -680,6 +706,8 @@ extern void glFramebufferRenderbufferEXT(GLenum target, GLenum attachment, GLenu
 extern void glGetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, GLenum pname, GLint *params) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER;
 extern void glGenerateMipmapEXT(GLenum target) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER;
 
+// GL_ARB_draw_buffers
+extern void glDrawBuffersARB(GLsizei n, const GLenum* bufs) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER;
 
 #ifdef __cplusplus
 extern "C" {
diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp
index 6464846c63e97a1f06765c54068e41733924dbdf..08d654805e38330cb3dab79fbb684dc0f6c98b0b 100644
--- a/indra/llrender/llglslshader.cpp
+++ b/indra/llrender/llglslshader.cpp
@@ -256,6 +256,14 @@ void LLGLSLShader::mapUniform(GLint index, const vector<string> * uniforms)
 	S32 location = glGetUniformLocationARB(mProgramObject, name);
 	if (location != -1)
 	{
+		//chop off "[0]" so we can always access the first element
+		//of an array by the array name
+		char* is_array = strstr(name, "[0]");
+		if (is_array)
+		{
+			is_array[0] = 0;
+		}
+
 		mUniformMap[name] = location;
 		LL_DEBUGS("ShaderLoading") << "Uniform " << name << " is at location " << location << LL_ENDL;
 	
@@ -353,11 +361,17 @@ void LLGLSLShader::unbind()
 {
 	if (gGLManager.mHasShaderObjects)
 	{
-		for (U32 i = 0; i < mAttribute.size(); ++i)
+		stop_glerror();
+		if (gGLManager.mIsNVIDIA)
 		{
-			vertexAttrib4f(i, 0,0,0,1);
+			for (U32 i = 0; i < mAttribute.size(); ++i)
+			{
+				vertexAttrib4f(i, 0,0,0,1);
+				stop_glerror();
+			}
 		}
 		glUseProgramObjectARB(0);
+		stop_glerror();
 	}
 }
 
@@ -390,14 +404,39 @@ S32 LLGLSLShader::disableTexture(S32 uniform, LLTexUnit::eTextureType mode)
 		return -1;
 	}
 	S32 index = mTexture[uniform];
-	if (index != -1)
+	if (index != -1 && gGL.getTexUnit(index)->getCurrType() != LLTexUnit::TT_NONE)
 	{
-		gGL.getTexUnit(index)->activate();
+		if (gDebugGL && gGL.getTexUnit(index)->getCurrType() != mode)
+		{
+			llerrs << "Texture channel " << index << " texture type corrupted." << llendl;
+		}
 		gGL.getTexUnit(index)->disable();
 	}
 	return index;
 }
 
+void LLGLSLShader::uniform1i(U32 index, GLint x)
+{
+	if (mProgramObject > 0)
+	{	
+		if (mUniform.size() <= index)
+		{
+			UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL;
+			return;
+		}
+
+		if (mUniform[index] >= 0)
+		{
+			std::map<GLint, LLVector4>::iterator iter = mValue.find(mUniform[index]);
+			if (iter == mValue.end() || iter->second.mV[0] != x)
+			{
+				glUniform1iARB(mUniform[index], x);
+				mValue[mUniform[index]] = LLVector4(x,0.f,0.f,0.f);
+			}
+		}
+	}
+}
+
 void LLGLSLShader::uniform1f(U32 index, GLfloat x)
 {
 	if (mProgramObject > 0)
@@ -489,6 +528,29 @@ void LLGLSLShader::uniform4f(U32 index, GLfloat x, GLfloat y, GLfloat z, GLfloat
 	}
 }
 
+void LLGLSLShader::uniform1iv(U32 index, U32 count, const GLint* v)
+{
+	if (mProgramObject > 0)
+	{	
+		if (mUniform.size() <= index)
+		{
+			UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL;
+			return;
+		}
+
+		if (mUniform[index] >= 0)
+		{
+			std::map<GLint, LLVector4>::iterator iter = mValue.find(mUniform[index]);
+			LLVector4 vec(v[0],0.f,0.f,0.f);
+			if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1)
+			{
+				glUniform1ivARB(mUniform[index], count, v);
+				mValue[mUniform[index]] = vec;
+			}
+		}
+	}
+}
+
 void LLGLSLShader::uniform1fv(U32 index, U32 count, const GLfloat* v)
 {
 	if (mProgramObject > 0)
@@ -647,6 +709,22 @@ GLint LLGLSLShader::getUniformLocation(const string& uniform)
 	return -1;
 }
 
+void LLGLSLShader::uniform1i(const string& uniform, GLint v)
+{
+	GLint location = getUniformLocation(uniform);
+				
+	if (location >= 0)
+	{
+		std::map<GLint, LLVector4>::iterator iter = mValue.find(location);
+		LLVector4 vec(v,0.f,0.f,0.f);
+		if (iter == mValue.end() || shouldChange(iter->second,vec))
+		{
+			glUniform1iARB(location, v);
+			mValue[location] = vec;
+		}
+	}
+}
+
 void LLGLSLShader::uniform1f(const string& uniform, GLfloat v)
 {
 	GLint location = getUniformLocation(uniform);
diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h
index c495a087267870553813704e0b4f711940d2349f..166d4af04cab5be2363c668e0ff36515ab122ce8 100644
--- a/indra/llrender/llglslshader.h
+++ b/indra/llrender/llglslshader.h
@@ -78,18 +78,22 @@ class LLGLSLShader
 	BOOL mapAttributes(const std::vector<std::string> * attributes);
 	BOOL mapUniforms(const std::vector<std::string> * uniforms);
 	void mapUniform(GLint index, const std::vector<std::string> * uniforms);
+	void uniform1i(U32 index, GLint i);
 	void uniform1f(U32 index, GLfloat v);
 	void uniform2f(U32 index, GLfloat x, GLfloat y);
 	void uniform3f(U32 index, GLfloat x, GLfloat y, GLfloat z);
 	void uniform4f(U32 index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+	void uniform1iv(U32 index, U32 count, const GLint* i);
 	void uniform1fv(U32 index, U32 count, const GLfloat* v);
 	void uniform2fv(U32 index, U32 count, const GLfloat* v);
 	void uniform3fv(U32 index, U32 count, const GLfloat* v);
 	void uniform4fv(U32 index, U32 count, const GLfloat* v);
+	void uniform1i(const std::string& uniform, GLint i);
 	void uniform1f(const std::string& uniform, GLfloat v);
 	void uniform2f(const std::string& uniform, GLfloat x, GLfloat y);
 	void uniform3f(const std::string& uniform, GLfloat x, GLfloat y, GLfloat z);
 	void uniform4f(const std::string& uniform, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+	void uniform1iv(const std::string& uniform, U32 count, const GLint* i);
 	void uniform1fv(const std::string& uniform, U32 count, const GLfloat* v);
 	void uniform2fv(const std::string& uniform, U32 count, const GLfloat* v);
 	void uniform3fv(const std::string& uniform, U32 count, const GLfloat* v);
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index f5b596b963a9f2fc7a6ef4980fb74932a3ca4b4d..307147798edd4324a9fa46b0c436569b15d042a1 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -63,7 +63,6 @@ BOOL LLImageGL::sGlobalUseAnisotropic	= FALSE;
 F32 LLImageGL::sLastFrameTime			= 0.f;
 
 std::set<LLImageGL*> LLImageGL::sImageList;
-
 //**************************************************************************************
 //below are functions for debug use
 //do not delete them even though they are not currently being used.
@@ -309,21 +308,21 @@ void LLImageGL::init(BOOL usemipmaps)
 #endif
 
 	mPickMask		  = NULL;
+	mTextureState       = NO_DELETE ;
 	mTextureMemory    = 0;
 	mLastBindTime     = 0.f;
 
 	mTarget			  = GL_TEXTURE_2D;
 	mBindTarget		  = LLTexUnit::TT_TEXTURE;
 	mUseMipMaps		  = usemipmaps;
-	mHasMipMaps		  = FALSE;
+	mHasMipMaps		  = false;
 	mAutoGenMips	  = FALSE;
 	mTexName          = 0;
 	mIsResident       = 0;
-	mClampS			  = FALSE;
-	mClampT			  = FALSE;
-	mClampR			  = FALSE;
-	mMagFilterNearest  = FALSE;
-	mMinFilterNearest  = FALSE;
+
+	mTexOptionsDirty = true;
+	mAddressMode = LLTexUnit::TAM_WRAP;
+	mFilterOption = LLTexUnit::TFO_ANISOTROPIC;
 	mWidth				= 0;
 	mHeight				= 0;
 	mComponents			= 0;
@@ -339,6 +338,7 @@ void LLImageGL::init(BOOL usemipmaps)
 	mHasExplicitFormat = FALSE;
 
 	mGLTextureCreated = FALSE ;
+	mIsMask = FALSE;
 }
 
 void LLImageGL::cleanup()
@@ -469,6 +469,11 @@ bool LLImageGL::bindDefaultImage(const S32 stage) const
 	return false;
 }
 
+//virtual
+void LLImageGL::forceImmediateUpdate()
+{
+	return ;
+}
 
 void LLImageGL::setExplicitFormat( LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format, BOOL swap_bytes )
 {
@@ -498,7 +503,7 @@ void LLImageGL::setImage(const LLImageRaw* imageraw)
 void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
 {
 // 	LLFastTimer t1(LLFastTimer::FTM_TEMP1);
-	
+	llpushcallstacks ;
 	bool is_compressed = false;
 	if (mFormatPrimary >= GL_COMPRESSED_RGBA_S3TC_DXT1_EXT && mFormatPrimary <= GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)
 	{
@@ -519,6 +524,7 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
 			// are stored BEFORE the largest image
 			for (S32 d=mCurrentDiscardLevel; d<=mMaxDiscardLevel; d++)
 			{
+				
 				S32 w = getWidth(d);
 				S32 h = getHeight(d);
 				S32 gl_level = d-mCurrentDiscardLevel;
@@ -529,7 +535,7 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
 				if (is_compressed)
 				{
 // 					LLFastTimer t2(LLFastTimer::FTM_TEMP4);
-					S32 tex_size = dataFormatBytes(mFormatPrimary, w, h);
+ 					S32 tex_size = dataFormatBytes(mFormatPrimary, w, h);
 					glCompressedTexImage2DARB(mTarget, gl_level, mFormatPrimary, w, h, 0, tex_size, (GLvoid *)data_in);
 					stop_glerror();
 				}
@@ -543,7 +549,11 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
 						stop_glerror();
 					}
 						
-					glTexImage2D(mTarget, gl_level, mFormatInternal, w, h, 0, mFormatPrimary, GL_UNSIGNED_BYTE, (GLvoid*)data_in);
+					LLImageGL::setManualImage(mTarget, gl_level, mFormatInternal, w, h, mFormatPrimary, GL_UNSIGNED_BYTE, (GLvoid*)data_in);
+					if (gl_level == 0)
+					{
+						analyzeAlpha(data_in, w, h);
+					}
 					updatePickMask(w, h, data_in);
 
 					if(mFormatSwapBytes)
@@ -575,10 +585,11 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
 					S32 w = getWidth(mCurrentDiscardLevel);
 					S32 h = getHeight(mCurrentDiscardLevel);
 
-					glTexImage2D(mTarget, 0, mFormatInternal,
-								 w, h, 0,
+					LLImageGL::setManualImage(mTarget, 0, mFormatInternal,
+								 w, h, 
 								 mFormatPrimary, mFormatType,
 								 data_in);
+					analyzeAlpha(data_in, w, h);
 					stop_glerror();
 
 					updatePickMask(w, h, data_in);
@@ -630,7 +641,11 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
 							stop_glerror();
 						}
 
-						glTexImage2D(mTarget, m, mFormatInternal, w, h, 0, mFormatPrimary, mFormatType, cur_mip_data);
+						LLImageGL::setManualImage(mTarget, m, mFormatInternal, w, h, mFormatPrimary, mFormatType, cur_mip_data);
+						if (m == 0)
+						{
+							analyzeAlpha(data_in, w, h);
+						}
 						stop_glerror();
 						if (m == 0)
 						{
@@ -663,7 +678,7 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
 		{
 			llerrs << "Compressed Image has mipmaps but data does not (can not auto generate compressed mips)" << llendl;
 		}
-		mHasMipMaps = TRUE;
+		mHasMipMaps = true;
 	}
 	else
 	{
@@ -684,8 +699,10 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
 				stop_glerror();
 			}
 
-			glTexImage2D(mTarget, 0, mFormatInternal, w, h, 0,
+			LLImageGL::setManualImage(mTarget, 0, mFormatInternal, w, h,
 						 mFormatPrimary, mFormatType, (GLvoid *)data_in);
+			analyzeAlpha(data_in, w, h);
+			
 			updatePickMask(w, h, data_in);
 
 			stop_glerror();
@@ -697,14 +714,16 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
 			}
 
 		}
-		mHasMipMaps = FALSE;
+		mHasMipMaps = false;
 	}
 	stop_glerror();
 	mGLTextureCreated = true;
+	llpushcallstacks ;
 }
 
 BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height)
 {
+	llpushcallstacks ;
 	if (!width || !height)
 	{
 		return TRUE;
@@ -780,6 +799,7 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3
 
 		glTexSubImage2D(mTarget, 0, x_pos, y_pos, 
 						width, height, mFormatPrimary, mFormatType, datap);
+		gGL.getTexUnit(0)->disable();
 		stop_glerror();
 
 		if(mFormatSwapBytes)
@@ -792,6 +812,7 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3
 		stop_glerror();
 		mGLTextureCreated = true;
 	}
+	llpushcallstacks ;
 	return TRUE;
 }
 
@@ -816,6 +837,24 @@ BOOL LLImageGL::setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_
 	}
 }
 
+// static
+void LLImageGL::generateTextures(S32 numTextures, U32 *textures)
+{
+	glGenTextures(numTextures, (GLuint*)textures);
+}
+
+// static
+void LLImageGL::deleteTextures(S32 numTextures, U32 *textures)
+{
+	glDeleteTextures(numTextures, (GLuint*)textures);
+}
+
+// static
+void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels)
+{
+	glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, pixels);
+}
+
 //create an empty GL texture: just create a texture name
 //the texture is assiciate with some image by calling glTexImage outside LLImageGL
 BOOL LLImageGL::createGLTexture()
@@ -848,6 +887,7 @@ BOOL LLImageGL::createGLTexture()
 
 BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename/*=0*/)
 {
+	llpushcallstacks ;
 	if (gGLManager.mIsDisabled)
 	{
 		llwarns << "Trying to create a texture while GL is disabled!" << llendl;
@@ -908,6 +948,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S
 
 BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_hasmips, S32 usename)
 {
+	llpushcallstacks ;
 	llassert(data_in);
 
 	if (discard_level < 0)
@@ -924,7 +965,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_
 		return TRUE;
 	}
 	
-	GLuint old_name = mTexName;
+	U32 old_name = mTexName;
 // 	S32 old_discard = mCurrentDiscardLevel;
 	
 	if (usename != 0)
@@ -933,7 +974,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_
 	}
 	else
 	{
-		glGenTextures(1, (GLuint*)&mTexName);
+		LLImageGL::generateTextures(1, &mTexName);
 		stop_glerror();
 		{
 // 			LLFastTimer t1(LLFastTimer::FTM_TEMP6);
@@ -963,9 +1004,11 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_
 
 	setImage(data_in, data_hasmips);
 
-	setClamp(mClampS, mClampT);
-	setMipFilterNearest(mMagFilterNearest);
-	
+	// Set texture options to our defaults.
+	gGL.getTexUnit(0)->setHasMipMaps(mHasMipMaps);
+	gGL.getTexUnit(0)->setTextureAddressMode(mAddressMode);
+	gGL.getTexUnit(0)->setTextureFilteringOption(mFilterOption);
+
 	// things will break if we don't unbind after creation
 	gGL.getTexUnit(0)->unbind(mBindTarget);
 	stop_glerror();
@@ -973,16 +1016,18 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_
 	if (old_name != 0)
 	{
 		sGlobalTextureMemory -= mTextureMemory;
-		glDeleteTextures(1, &old_name);
+		LLImageGL::deleteTextures(1, &old_name);
 		stop_glerror();
 	}
 
 	mTextureMemory = getMipBytes(discard_level);
 	sGlobalTextureMemory += mTextureMemory;
-		
+	setActive() ;
+
 	// mark this as bound at this point, so we don't throw it out immediately
 	mLastBindTime = sLastFrameTime;
 
+	llpushcallstacks ;
 	return TRUE;
 }
 
@@ -1055,6 +1100,7 @@ BOOL LLImageGL::isValidForSculpt(S32 discard_level, S32 image_width, S32 image_h
 
 BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok)
 {
+	llpushcallstacks ;
 	if (discard_level < 0)
 	{
 		discard_level = mCurrentDiscardLevel;
@@ -1069,7 +1115,7 @@ BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compre
 
 	//explicitly unbind texture 
 	gGL.getTexUnit(0)->unbind(mBindTarget);
-	llverify(gGL.getTexUnit(0)->bind(this));	
+	llverify(gGL.getTexUnit(0)->bindManual(mBindTarget, mTexName));	
 
 	//debug code, leave it there commented.
 	//checkTexSize() ;
@@ -1157,7 +1203,7 @@ BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compre
 		return FALSE ;
 	}
 	//-----------------------------------------------------------------------------------------------
-	
+	llpushcallstacks ;
 	return TRUE ;
 }
 
@@ -1179,8 +1225,10 @@ void LLImageGL::destroyGLTexture()
 		sGlobalTextureMemory -= mTextureMemory;
 		mTextureMemory = 0;
 
-		glDeleteTextures(1, (GLuint*)&mTexName);
+		LLImageGL::deleteTextures(1, &mTexName);
+		mTextureState = DELETED ;		
 		mTexName = 0;
+		mCurrentDiscardLevel = -1 ; //invalidate mCurrentDiscardLevel.
 		mGLTextureCreated = FALSE ;
 		stop_glerror();
 	}
@@ -1188,89 +1236,35 @@ void LLImageGL::destroyGLTexture()
 
 //----------------------------------------------------------------------------
 
-void LLImageGL::glClampCubemap (BOOL clamps, BOOL clampt, BOOL clampr)
-{
-	glTexParameteri (GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_S, clamps ? GL_CLAMP_TO_EDGE : GL_REPEAT);
-	glTexParameteri (GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_T, clamps ? GL_CLAMP_TO_EDGE : GL_REPEAT);
-	glTexParameteri (GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_R, clamps ? GL_CLAMP_TO_EDGE : GL_REPEAT);
-}
-
-void LLImageGL::glClamp (BOOL clamps, BOOL clampt)
+void LLImageGL::setAddressMode(LLTexUnit::eTextureAddressMode mode)
 {
-	if (mTexName != 0)
+	if (mAddressMode != mode)
 	{
-		glTexParameteri (LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_WRAP_S, clamps ? GL_CLAMP_TO_EDGE : GL_REPEAT);
-		glTexParameteri (LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_WRAP_T, clampt ? GL_CLAMP_TO_EDGE : GL_REPEAT);
+		mTexOptionsDirty = true;
+		mAddressMode = mode;
 	}
-}
 
-void LLImageGL::setClampCubemap (BOOL clamps, BOOL clampt, BOOL clampr)
-{
-	mClampS = clamps;
-	mClampT = clampt;
-	mClampR = clampr;
-	glClampCubemap (clamps, clampt, clampr);
-}
-
-void LLImageGL::setClamp(BOOL clamps, BOOL clampt)
-{
-	mClampS = clamps;
-	mClampT = clampt;
-	glClamp (clamps, clampt);
-}
-
-void LLImageGL::overrideClamp (BOOL clamps, BOOL clampt)
-{
-	glClamp (clamps, clampt);
-}
-
-void LLImageGL::restoreClamp (void)
-{
-	glClamp (mClampS, mClampT);
+	if (gGL.getTexUnit(gGL.getCurrentTexUnitIndex())->getCurrTexture() == mTexName)
+	{
+		gGL.getTexUnit(gGL.getCurrentTexUnitIndex())->setTextureAddressMode(mode);
+		mTexOptionsDirty = false;
+	}
 }
 
-void LLImageGL::setMipFilterNearest(BOOL mag_nearest, BOOL min_nearest)
+void LLImageGL::setFilteringOption(LLTexUnit::eTextureFilterOptions option)
 {
-	mMagFilterNearest = mag_nearest;
-	mMinFilterNearest = min_nearest;
+	if (mFilterOption != option)
+	{
+		mTexOptionsDirty = true;
+		mFilterOption = option;
+	}
 
-	if (mTexName != 0)
+	if (gGL.getTexUnit(gGL.getCurrentTexUnitIndex())->getCurrTexture() == mTexName)
 	{
-		if (mMinFilterNearest)
-		{
-			glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-		}
-		else if (mHasMipMaps)
-		{
-			glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
-		}
-		else
-		{
-			glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-		}
-		if (mMagFilterNearest)
-		{
-			glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-		}
-		else 
-		{
-			glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-		}
-		if (gGLManager.mHasAnisotropic)
-		{
-			if (sGlobalUseAnisotropic && !mMagFilterNearest)
-			{
-				F32 largest_anisotropy;
-				glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &largest_anisotropy);
-				glTexParameterf(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_MAX_ANISOTROPY_EXT, largest_anisotropy);
-			}
-			else
-			{
-				glTexParameterf(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.f);
-			}
-		}
-		stop_glerror();
-	}	
+		gGL.getTexUnit(gGL.getCurrentTexUnitIndex())->setTextureFilteringOption(option);
+		mTexOptionsDirty = false;
+	}
+	stop_glerror();
 }
 
 BOOL LLImageGL::getIsResident(BOOL test_now)
@@ -1357,6 +1351,115 @@ void LLImageGL::setTarget(const LLGLenum target, const LLTexUnit::eTextureType b
 	mBindTarget = bind_target;
 }
 
+void LLImageGL::analyzeAlpha(const void* data_in, S32 w, S32 h)
+{
+	if (mFormatType != GL_UNSIGNED_BYTE)
+	{
+		llwarns << "Cannot analyze alpha for image with format type " << std::hex << mFormatType << std::dec << llendl;
+	}
+
+	U32 stride = 0;
+	switch (mFormatPrimary)
+	{
+	case GL_LUMINANCE:
+	case GL_ALPHA:
+		stride = 1;
+		break;
+	case GL_LUMINANCE_ALPHA:
+		stride = 2;
+		break;
+	case GL_RGB:
+		//no alpha
+		mIsMask = FALSE;
+		return;
+	case GL_RGBA:
+		stride = 4;
+		break;
+	default:
+		llwarns << "Cannot analyze alpha of image with primary format " << std::hex << mFormatPrimary << std::dec << llendl;
+		return;
+	}
+
+	U32 length = w * h;
+	const GLubyte* current = ((const GLubyte*) data_in)+stride-1;
+	
+	S32 sample[16];
+	memset(sample, 0, sizeof(S32)*16);
+
+	for (U32 i = 0; i < length; i++)
+	{
+		++sample[*current/16];
+		current += stride;
+	}
+
+	U32 total = 0;
+	for (U32 i = 4; i < 11; i++)
+	{
+		total += sample[i];
+	}
+
+	if (total > length/16)
+	{
+		mIsMask = FALSE;
+	}
+	else
+	{
+		mIsMask = TRUE;
+	}
+}
+
+BOOL LLImageGL::isDeleted()  
+{ 
+	return mTextureState == DELETED ; 
+}
+
+BOOL LLImageGL::isInactive()  
+{ 
+	return mTextureState == INACTIVE ; 
+}
+
+BOOL LLImageGL::isDeletionCandidate()  
+{ 
+	return mTextureState == DELETION_CANDIDATE ; 
+}
+
+void LLImageGL::setDeletionCandidate()  
+{ 
+	if(mTexName && (mTextureState == INACTIVE))
+	{
+		mTextureState = DELETION_CANDIDATE ;		
+	}
+}
+
+void LLImageGL::forceActive()
+{
+	mTextureState = ACTIVE ; 
+}
+
+void LLImageGL::setActive() 
+{ 
+	if(mTextureState != NO_DELETE)
+	{
+		mTextureState = ACTIVE ; 
+	}
+}
+
+//set the texture inactive
+void LLImageGL::setInactive()
+{
+	if(mTexName && (mTextureState == ACTIVE) && !getBoundRecently())
+	{
+		mTextureState = INACTIVE ; 
+	}
+}
+
+//set the texture to stay in memory
+void LLImageGL::setNoDelete() 
+{ 
+	mTextureState = NO_DELETE ;
+}
+
+//----------------------------------------------------------------------------
 void LLImageGL::updatePickMask(S32 width, S32 height, const U8* data_in)
 {
 	if (mFormatType != GL_UNSIGNED_BYTE ||
@@ -1469,7 +1572,7 @@ BOOL LLImageGL::getMask(const LLVector2 &tc)
 			llassert(w > 0 && h > 0 && cur_mip_data);
 			U8 test = cur_mip_data[w*h*mComponents-1];
 			{
-				glTexImage2D(mTarget, m, mFormatInternal, w, h, 0, mFormatPrimary, mFormatType, cur_mip_data);
+				LLImageGL::setManualImage(mTarget, m, mFormatInternal, w, h, mFormatPrimary, mFormatType, cur_mip_data);
 				stop_glerror();
 			}
 			if (prev_mip_data && prev_mip_data != rawdata)
diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h
index cb565939d9b99505af5e0e7f91e71306e263cfca..4f737bcaae3caf474c8a322e6430e2708ce3a797 100644
--- a/indra/llrender/llimagegl.h
+++ b/indra/llrender/llimagegl.h
@@ -46,6 +46,7 @@
 
 class LLImageGL : public LLRefCount
 {
+	friend class LLTexUnit;
 public:
 	// Size calculation
 	static S32 dataFormatBits(S32 dataformat);
@@ -80,17 +81,22 @@ class LLImageGL : public LLRefCount
 protected:
 	virtual ~LLImageGL();
 
-private:
-	void glClamp (BOOL clamps, BOOL clampt);
-	void glClampCubemap (BOOL clamps, BOOL clampt, BOOL clampr = FALSE);
+	void analyzeAlpha(const void* data_in, S32 w, S32 h);
 
 public:
 	virtual void dump();	// debugging info to llinfos
 	virtual bool bindError(const S32 stage = 0) const;
 	virtual bool bindDefaultImage(const S32 stage = 0) const;
+	virtual void forceImmediateUpdate() ;
 
 	void setSize(S32 width, S32 height, S32 ncomponents);
 
+	// These 3 functions currently wrap glGenTextures(), glDeleteTextures(), and glTexImage2D() 
+	// for tracking purposes and will be deprecated in the future
+	static void generateTextures(S32 numTextures, U32 *textures);
+	static void deleteTextures(S32 numTextures, U32 *textures);
+	static void setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels);
+
 	BOOL createGLTexture() ;
 	BOOL createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0);
 	BOOL createGLTexture(S32 discard_level, const U8* data, BOOL data_hasmips = FALSE, S32 usename = 0);
@@ -103,14 +109,9 @@ class LLImageGL : public LLRefCount
 	// Read back a raw image for this discard level, if it exists
 	BOOL readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok); 
 	void destroyGLTexture();
-	
-	void setClampCubemap (BOOL clamps, BOOL clampt, BOOL clampr = FALSE);
-	void setClamp(BOOL clamps, BOOL clampt);
-	void overrideClamp (BOOL clamps, BOOL clampt);
-	void restoreClamp (void);
-	void setMipFilterNearest(BOOL mag_nearest, BOOL min_nearest = FALSE);
+
 	void setExplicitFormat(LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format = 0, BOOL swap_bytes = FALSE);
-	void dontDiscard() { mDontDiscard = 1; }
+	void dontDiscard() { mDontDiscard = 1; mTextureState = NO_DELETE; }
 
 	S32	 getDiscardLevel() const		{ return mCurrentDiscardLevel; }
 	S32	 getMaxDiscardLevel() const		{ return mMaxDiscardLevel; }
@@ -124,15 +125,12 @@ class LLImageGL : public LLRefCount
 	S32  getMipBytes(S32 discard_level = -1) const;
 	BOOL getBoundRecently() const;
 	LLGLenum getPrimaryFormat() const { return mFormatPrimary; }
-	
-	BOOL getClampS() const { return mClampS; }
-	BOOL getClampT() const { return mClampT; }
-	BOOL getClampR() const { return mClampR; }
-	BOOL getMipFilterNearest() const { return mMagFilterNearest; }
-	
+
 	BOOL getHasGLTexture() const { return mTexName != 0; }
 	LLGLuint getTexName() const { return mTexName; }
 
+	BOOL getIsAlphaMask() const { return mIsMask; }
+
 	BOOL getIsResident(BOOL test_now = FALSE); // not const
 
 	void setTarget(const LLGLenum target, const LLTexUnit::eTextureType bind_target);
@@ -152,6 +150,27 @@ class LLImageGL : public LLRefCount
 	BOOL getMask(const LLVector2 &tc);
 
 	void checkTexSize() const ;
+	
+	// Sets the addressing mode used to sample the texture 
+	//  (such as wrapping, mirrored wrapping, and clamp)
+	// Note: this actually gets set the next time the texture is bound.
+	void setAddressMode(LLTexUnit::eTextureAddressMode mode);
+	LLTexUnit::eTextureAddressMode getAddressMode(void) const { return mAddressMode; }
+
+	// Sets the filtering options used to sample the texture 
+	//  (such as point sampling, bilinear interpolation, mipmapping, and anisotropic filtering)
+	// Note: this actually gets set the next time the texture is bound.
+	void setFilteringOption(LLTexUnit::eTextureFilterOptions option);
+	LLTexUnit::eTextureFilterOptions getFilteringOption(void) const { return mFilterOption; }
+
+	BOOL isDeleted() ;
+	BOOL isInactive() ;
+	BOOL isDeletionCandidate();
+	void setDeletionCandidate() ;
+	void setInactive() ;
+	void setActive() ;
+	void forceActive() ;
+	void setNoDelete() ;
 
 protected:
 	void init(BOOL usemipmaps);
@@ -166,9 +185,10 @@ class LLImageGL : public LLRefCount
 	LLPointer<LLImageRaw> mSaveData; // used for destroyGL/restoreGL
 	U8* mPickMask;  //downsampled bitmap approximation of alpha channel.  NULL if no alpha channel
 	S8 mUseMipMaps;
-	S8 mHasMipMaps;
 	S8 mHasExplicitFormat; // If false (default), GL format is f(mComponents)
 	S8 mAutoGenMips;
+
+	BOOL mIsMask;
 	
 	bool     mGLTextureCreated ;
 	LLGLuint mTexName;
@@ -179,6 +199,7 @@ class LLImageGL : public LLRefCount
 protected:
 	LLGLenum mTarget;		// Normally GL_TEXTURE2D, sometimes something else (ex. cube maps)
 	LLTexUnit::eTextureType mBindTarget;	// Normally TT_TEXTURE, sometimes something else (ex. cube maps)
+	bool mHasMipMaps;
 	
 	LLGLboolean mIsResident;
 	
@@ -186,17 +207,27 @@ class LLImageGL : public LLRefCount
 	S8 mMaxDiscardLevel;	
 	S8 mDontDiscard;			// Keep full res version of this image (for UI, etc)
 
-	S8 mClampS;					// Need to save clamp state
-	S8 mClampT;
-	S8 mClampR;
-	S8 mMagFilterNearest;		// if TRUE, set magfilter to GL_NEAREST
-	S8 mMinFilterNearest;		// if TRUE, set minfilter to GL_NEAREST
+	bool	mTexOptionsDirty;
+	LLTexUnit::eTextureAddressMode		mAddressMode;	// Defaults to TAM_WRAP
+	LLTexUnit::eTextureFilterOptions	mFilterOption;	// Defaults to TFO_TRILINEAR
+
 	
 	LLGLint  mFormatInternal; // = GL internalformat
 	LLGLenum mFormatPrimary;  // = GL format (pixel data format)
 	LLGLenum mFormatType;
 	BOOL	 mFormatSwapBytes;// if true, use glPixelStorei(GL_UNPACK_SWAP_BYTES, 1)
 
+protected:
+	typedef enum 
+	{
+		DELETED = 0,         //removed from memory
+		DELETION_CANDIDATE,  //ready to be removed from memory
+		INACTIVE,            //not be used for the last certain period (i.e., 30 seconds).
+		ACTIVE,              //just being used, can become inactive if not being used for a certain time (10 seconds).
+		NO_DELETE = 99       //stay in memory, can not be removed.
+	} LLGLTexureState;
+	LLGLTexureState  mTextureState ;
+	
 	// STATICS
 public:	
 	static std::set<LLImageGL*> sImageList;
diff --git a/indra/llrender/llpostprocess.cpp b/indra/llrender/llpostprocess.cpp
index 940abb54d441473b4aa73983e2b9bd05ed77f83f..7f4be6a86625c6ec0ae183e7cfe31a76b2dfef32 100644
--- a/indra/llrender/llpostprocess.cpp
+++ b/indra/llrender/llpostprocess.cpp
@@ -208,7 +208,7 @@ void LLPostProcess::applyShaders(void)
 		/// If any of the above shaders have been called update the frame buffer;
 		if (tweaks.useColorFilter())
 		{
-			GLuint tex = mSceneRenderTexture->getTexName() ;
+			U32 tex = mSceneRenderTexture->getTexName() ;
 			copyFrameBuffer(tex, screenW, screenH);
 		}
 		applyNightVisionShader();
@@ -218,7 +218,7 @@ void LLPostProcess::applyShaders(void)
 		/// If any of the above shaders have been called update the frame buffer;
 		if (tweaks.useColorFilter().asBoolean() || tweaks.useNightVisionShader().asBoolean())
 		{
-			GLuint tex = mSceneRenderTexture->getTexName() ;
+			U32 tex = mSceneRenderTexture->getTexName() ;
 			copyFrameBuffer(tex, screenW, screenH);
 		}
 		applyBloomShader();
@@ -360,7 +360,7 @@ void LLPostProcess::doEffects(void)
 
 	/// Copy the screen buffer to the render texture
 	{
-		GLuint tex = mSceneRenderTexture->getTexName() ;
+		U32 tex = mSceneRenderTexture->getTexName() ;
 		copyFrameBuffer(tex, screenW, screenH);
 	}
 
@@ -386,7 +386,7 @@ void LLPostProcess::doEffects(void)
 	checkError();
 }
 
-void LLPostProcess::copyFrameBuffer(GLuint & texture, unsigned int width, unsigned int height)
+void LLPostProcess::copyFrameBuffer(U32 & texture, unsigned int width, unsigned int height)
 {
 	gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_RECT_TEXTURE, texture);
 	glCopyTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, 0, 0, width, height, 0);
@@ -503,10 +503,8 @@ void LLPostProcess::createTexture(LLPointer<LLImageGL>& texture, unsigned int wi
 		gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_RECT_TEXTURE, texture->getTexName());
 		glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, width, height, 0,
 			GL_RGBA, GL_UNSIGNED_BYTE, &data[0]);
-		glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
-		glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
-		glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-		glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+		gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
+		gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
 	}
 }
 
@@ -523,11 +521,9 @@ void LLPostProcess::createNoiseTexture(LLPointer<LLImageGL>& texture)
 	if(texture->createGLTexture())
 	{
 		gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, texture->getTexName());
-		glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, NOISE_SIZE, NOISE_SIZE, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &buffer[0]);
-		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR);
-		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR);
-		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
-		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+		LLImageGL::setManualImage(GL_TEXTURE_2D, 0, GL_LUMINANCE, NOISE_SIZE, NOISE_SIZE, GL_LUMINANCE, GL_UNSIGNED_BYTE, &buffer[0]);
+		gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
+		gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_WRAP);
 	}
 }
 
diff --git a/indra/llrender/llpostprocess.h b/indra/llrender/llpostprocess.h
index e5e34d920cf14f1197c9b53754f6d1bf457ef804..009e4bd41508c0f26c47fcff6c05be313cc0e6d4 100644
--- a/indra/llrender/llpostprocess.h
+++ b/indra/llrender/llpostprocess.h
@@ -256,7 +256,7 @@ class LLPostProcess
 	/// OpenGL Helper Functions
 	void getShaderUniforms(glslUniforms & uniforms, GLhandleARB & prog);
 	void createTexture(LLPointer<LLImageGL>& texture, unsigned int width, unsigned int height);
-	void copyFrameBuffer(GLuint & texture, unsigned int width, unsigned int height);
+	void copyFrameBuffer(U32 & texture, unsigned int width, unsigned int height);
 	void createNoiseTexture(LLPointer<LLImageGL>& texture);
 	bool checkError(void);
 	void checkShaderError(GLhandleARB shader);
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index c7068133d2398a5e98b90b2f70a9b51b6cd640fd..bee41f556e76b9aada8a93734e35abc172dabd91 100644
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -75,7 +75,7 @@ static GLenum sGLCompareFunc[] =
 	GL_GREATER
 };
 
-const U32 immediate_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_TEXCOORD;
+const U32 immediate_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_TEXCOORD0;
 
 static GLenum sGLBlendFactor[] =
 {
@@ -96,7 +96,8 @@ LLTexUnit::LLTexUnit(S32 index)
 mCurrColorOp(TBO_MULT), mCurrAlphaOp(TBO_MULT),
 mCurrColorSrc1(TBS_TEX_COLOR), mCurrColorSrc2(TBS_PREV_COLOR),
 mCurrAlphaSrc1(TBS_TEX_ALPHA), mCurrAlphaSrc2(TBS_PREV_ALPHA),
-mCurrColorScale(1), mCurrAlphaScale(1), mCurrTexture(0)
+mCurrColorScale(1), mCurrAlphaScale(1), mCurrTexture(0),
+mHasMipMaps(false)
 {
 	llassert_always(index < LL_NUM_TEXTURE_LAYERS);
 	mIndex = index;
@@ -176,8 +177,9 @@ void LLTexUnit::disable(void)
 	}
 }
 
-bool LLTexUnit::bind(const LLImageGL* texture, bool forceBind)
+bool LLTexUnit::bind(LLImageGL* texture, bool forceBind)
 {
+	stop_glerror();
 	if (mIndex < 0) return false;
 
 	gGL.flush();
@@ -190,15 +192,30 @@ bool LLTexUnit::bind(const LLImageGL* texture, bool forceBind)
 	
 	if (!texture->getTexName()) //if texture does not exist
 	{
+		//if deleted, will re-generate it immediately
+		texture->forceImmediateUpdate() ;
+
 		return texture->bindDefaultImage(mIndex);
 	}
-	// Disabled caching of binding state.
-	activate();
-	enable(texture->getTarget());
-	mCurrTexture = texture->getTexName();
-	glBindTexture(sGLTextureType[texture->getTarget()], mCurrTexture);
-	texture->updateBindStats();
-	return true;
+	
+	if (texture != NULL && ((mCurrTexture != texture->getTexName()) || forceBind))
+	{
+		activate();
+		enable(texture->getTarget());
+		mCurrTexture = texture->getTexName();
+		glBindTexture(sGLTextureType[texture->getTarget()], mCurrTexture);
+		texture->updateBindStats();
+		texture->setActive() ;
+		mHasMipMaps = texture->mHasMipMaps;
+		if (texture->mTexOptionsDirty)
+		{
+			texture->mTexOptionsDirty = false;
+			setTextureAddressMode(texture->mAddressMode);
+			setTextureFilteringOption(texture->mFilterOption);
+		}
+		return true;
+	}
+	return false;
 }
 
 bool LLTexUnit::bind(LLCubeMap* cubeMap)
@@ -207,8 +224,7 @@ bool LLTexUnit::bind(LLCubeMap* cubeMap)
 
 	gGL.flush();
 
-	// Disabled caching of binding state.
-	if (cubeMap != NULL)
+	if (cubeMap != NULL && mCurrTexture != cubeMap->mImages[0]->getTexName())
 	{
 		if (gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps)
 		{
@@ -216,8 +232,14 @@ bool LLTexUnit::bind(LLCubeMap* cubeMap)
 			enable(LLTexUnit::TT_CUBE_MAP);
 			mCurrTexture = cubeMap->mImages[0]->getTexName();
 			glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, mCurrTexture);
+			mHasMipMaps = cubeMap->mImages[0]->mHasMipMaps;
 			cubeMap->mImages[0]->updateBindStats();
-			cubeMap->mImages[0]->setMipFilterNearest (FALSE, FALSE);
+			if (cubeMap->mImages[0]->mTexOptionsDirty)
+			{
+				cubeMap->mImages[0]->mTexOptionsDirty = false;
+				setTextureAddressMode(cubeMap->mImages[0]->mAddressMode);
+				setTextureFilteringOption(cubeMap->mImages[0]->mFilterOption);
+			}
 			return true;
 		}
 		else
@@ -228,6 +250,8 @@ bool LLTexUnit::bind(LLCubeMap* cubeMap)
 	return false;
 }
 
+// LLRenderTarget is unavailible on the mapserver since it uses FBOs.
+#if !LL_MESA_HEADLESS
 bool LLTexUnit::bind(LLRenderTarget* renderTarget, bool bindDepth)
 {
 	if (mIndex < 0) return false;
@@ -245,23 +269,26 @@ bool LLTexUnit::bind(LLRenderTarget* renderTarget, bool bindDepth)
 
 	return true;
 }
+#endif // LL_MESA_HEADLESS
 
-bool LLTexUnit::bindManual(eTextureType type, U32 texture)
+bool LLTexUnit::bindManual(eTextureType type, U32 texture, bool hasMips)
 {
-	if (mIndex < 0) return false;
+	if (mIndex < 0 || mCurrTexture == texture) return false;
 
-	// Disabled caching of binding state.
 	gGL.flush();
 	
 	activate();
 	enable(type);
 	mCurrTexture = texture;
 	glBindTexture(sGLTextureType[type], texture);
+	mHasMipMaps = hasMips;
 	return true;
 }
 
 void LLTexUnit::unbind(eTextureType type)
 {
+	stop_glerror();
+
 	if (mIndex < 0) return;
 
 	// Disabled caching of binding state.
@@ -277,17 +304,57 @@ void LLTexUnit::unbind(eTextureType type)
 
 void LLTexUnit::setTextureAddressMode(eTextureAddressMode mode)
 {
-	if (mIndex < 0) return;
+	if (mIndex < 0 || mCurrTexture == 0) return;
+
+	activate();
 
-	if (true)
+	glTexParameteri (sGLTextureType[mCurrTexType], GL_TEXTURE_WRAP_S, sGLAddressMode[mode]);
+	glTexParameteri (sGLTextureType[mCurrTexType], GL_TEXTURE_WRAP_T, sGLAddressMode[mode]);
+	if (mCurrTexType == TT_CUBE_MAP)
 	{
-		activate();
+		glTexParameteri (GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_R, sGLAddressMode[mode]);
+	}
+}
+
+void LLTexUnit::setTextureFilteringOption(LLTexUnit::eTextureFilterOptions option)
+{
+	if (mIndex < 0 || mCurrTexture == 0) return;
+
+	if (option == TFO_POINT)
+	{
+		glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+	}
+	else
+	{
+		glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+	}
+
+	if (option >= TFO_TRILINEAR && mHasMipMaps)
+	{
+		glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+	} 
+	else if (option >= TFO_BILINEAR)
+	{
+		glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+	}
+	else
+	{
+		glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+	}
 
-		glTexParameteri (sGLTextureType[mCurrTexType], GL_TEXTURE_WRAP_S, sGLAddressMode[mode]);
-		glTexParameteri (sGLTextureType[mCurrTexType], GL_TEXTURE_WRAP_T, sGLAddressMode[mode]);
-		if (mCurrTexType == TT_CUBE_MAP)
+	if (gGLManager.mHasAnisotropic)
+	{
+		if (LLImageGL::sGlobalUseAnisotropic && option == TFO_ANISOTROPIC)
 		{
-			glTexParameteri (GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_R, sGLAddressMode[mode]);
+			if (gGL.mMaxAnisotropy < 1.f)
+			{
+				glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &gGL.mMaxAnisotropy);
+			}
+			glTexParameterf(sGLTextureType[mCurrTexType], GL_TEXTURE_MAX_ANISOTROPY_EXT, gGL.mMaxAnisotropy);
+		}
+		else
+		{
+			glTexParameterf(sGLTextureType[mCurrTexType], GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.f);
 		}
 	}
 }
@@ -590,12 +657,13 @@ void LLTexUnit::debugTextureUnit(void)
 
 
 LLRender::LLRender()
-: mDirty(false), mCount(0), mMode(LLRender::TRIANGLES)
+: mDirty(false), mCount(0), mMode(LLRender::TRIANGLES),
+	mMaxAnisotropy(0.f) 
 {
 	mBuffer = new LLVertexBuffer(immediate_mask, 0);
 	mBuffer->allocateBuffer(4096, 0, TRUE);
 	mBuffer->getVertexStrider(mVerticesp);
-	mBuffer->getTexCoordStrider(mTexcoordsp);
+	mBuffer->getTexCoord0Strider(mTexcoordsp);
 	mBuffer->getColorStrider(mColorsp);
 	
 	mTexUnits.reserve(LL_NUM_TEXTURE_LAYERS);
@@ -688,7 +756,10 @@ void LLRender::setColorMask(bool writeColorR, bool writeColorG, bool writeColorB
 	mCurrColorMask[2] = writeColorB;
 	mCurrColorMask[3] = writeAlpha;
 
-	glColorMask(writeColorR, writeColorG, writeColorB, writeAlpha);
+	glColorMask(writeColorR ? GL_TRUE : GL_FALSE, 
+				writeColorG ? GL_TRUE : GL_FALSE,
+				writeColorB ? GL_TRUE : GL_FALSE,
+				writeAlpha ? GL_TRUE : GL_FALSE);
 }
 
 void LLRender::setSceneBlendType(eBlendType type)
@@ -768,6 +839,14 @@ bool LLRender::verifyTexUnitActive(U32 unitToVerify)
 	}
 }
 
+void LLRender::clearErrors()
+{
+	while (glGetError())
+	{
+		//loop until no more error flags left
+	}
+}
+
 void LLRender::begin(const GLuint& mode)
 {
 	if (mode != mMode)
@@ -853,13 +932,14 @@ void LLRender::flush()
 				
 		mBuffer->setBuffer(immediate_mask);
 		mBuffer->drawArrays(mMode, 0, mCount);
-
+		
 		mVerticesp[0] = mVerticesp[mCount];
 		mTexcoordsp[0] = mTexcoordsp[mCount];
 		mColorsp[0] = mColorsp[mCount];
 		mCount = 0;
 	}
 }
+
 void LLRender::vertex3f(const GLfloat& x, const GLfloat& y, const GLfloat& z)
 { 
 	//the range of mVerticesp, mColorsp and mTexcoordsp is [0, 4095]
diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h
index 752a4e0b378c8a9cabcebed2fcee53785c246090..437c715c2f64bb7f7186081b975fae7c6acecd78 100644
--- a/indra/llrender/llrender.h
+++ b/indra/llrender/llrender.h
@@ -71,6 +71,14 @@ class LLTexUnit
 		TAM_CLAMP 				// No texture type is currently enabled
 	} eTextureAddressMode;
 
+	typedef enum
+	{	// Note: If mipmapping or anisotropic are not enabled or supported it should fall back gracefully
+		TFO_POINT = 0,			// Equal to: min=point, mag=point, mip=none.
+		TFO_BILINEAR,			// Equal to: min=linear, mag=linear, mip=point.
+		TFO_TRILINEAR,			// Equal to: min=linear, mag=linear, mip=linear.
+		TFO_ANISOTROPIC			// Equal to: min=anisotropic, max=anisotropic, mip=linear.
+	} eTextureFilterOptions;
+
 	typedef enum 
 	{
 		TB_REPLACE = 0,
@@ -131,30 +139,43 @@ class LLTexUnit
 	// Sets this tex unit to be the currently active one
 	void activate(void); 
 
-	// Enables this texture unit for the given texture type (automatically disables any previously enabled texture type)
+	// Enables this texture unit for the given texture type 
+	// (automatically disables any previously enabled texture type)
 	void enable(eTextureType type); 
+
 	// Disables the current texture unit
 	void disable(void);	
 	
 	// Binds the LLImageGL to this texture unit 
 	// (automatically enables the unit for the LLImageGL's texture type)
-	bool bind(const LLImageGL* texture, bool forceBind = false);
+	bool bind(LLImageGL* texture, bool forceBind = false);
 
 	// Binds a cubemap to this texture unit 
 	// (automatically enables the texture unit for cubemaps)
 	bool bind(LLCubeMap* cubeMap);
 
-	// Binds a render target to this texture unit (automatically enables the texture unit for the RT's texture type)
+	// Binds a render target to this texture unit 
+	// (automatically enables the texture unit for the RT's texture type)
 	bool bind(LLRenderTarget * renderTarget, bool bindDepth = false);
 
-	// Manually binds a texture to the texture unit (automatically enables the tex unit for the given texture type)
-	bool bindManual(eTextureType type, U32 texture);
+	// Manually binds a texture to the texture unit 
+	// (automatically enables the tex unit for the given texture type)
+	bool bindManual(eTextureType type, U32 texture, bool hasMips = false);
 	
-	// Unbinds the currently bound texture of the given type (only if there's a texture of the given type currently bound)
+	// Unbinds the currently bound texture of the given type 
+	// (only if there's a texture of the given type currently bound)
 	void unbind(eTextureType type);
 
+	// Sets the addressing mode used to sample the texture
+	// Warning: this stays set for the bound texture forever, 
+	// make sure you want to permanently change the address mode  for the bound texture.
 	void setTextureAddressMode(eTextureAddressMode mode);
 
+	// Sets the filtering options used to sample the texture
+	// Warning: this stays set for the bound texture forever, 
+	// make sure you want to permanently change the filtering for the bound texture.
+	void setTextureFilteringOption(LLTexUnit::eTextureFilterOptions option);
+
 	void setTextureBlendType(eTextureBlendType type);
 
 	inline void setTextureColorBlend(eTextureBlendOp op, eTextureBlendSrc src1, eTextureBlendSrc src2 = TBS_PREV_COLOR)
@@ -166,6 +187,12 @@ class LLTexUnit
 
 	static U32 getInternalType(eTextureType type);
 
+	U32 getCurrTexture(void) { return mCurrTexture; }
+
+	eTextureType getCurrType(void) { return mCurrTexType; }
+
+	void setHasMipMaps(bool hasMips) { mHasMipMaps = hasMips; }
+
 protected:
 	S32					mIndex;
 	U32					mCurrTexture;
@@ -179,6 +206,7 @@ class LLTexUnit
 	eTextureBlendSrc	mCurrAlphaSrc2;
 	S32					mCurrColorScale;
 	S32					mCurrAlphaScale;
+	bool				mHasMipMaps;
 	
 	void debugTextureUnit(void);
 	void setColorScale(S32 scale);
@@ -292,6 +320,8 @@ class LLRender
 
 	void debugTexUnits(void);
 
+	void clearErrors();
+
 	struct Vertex
 	{
 		GLfloat v[3];
@@ -316,6 +346,8 @@ class LLRender
 	LLStrider<LLColor4U>		mColorsp;
 	std::vector<LLTexUnit*>		mTexUnits;
 	LLTexUnit*			mDummyTexUnit;
+
+	F32				mMaxAnisotropy;
 };
 
 extern F64 gGLModelView[16];
diff --git a/indra/llrender/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp
index 623c1df4db2c357ec6ac212c68f65f4009420069..b7f31779ca0decd5471e378fbb1c6a184d7d7e97 100644
--- a/indra/llrender/llrendertarget.cpp
+++ b/indra/llrender/llrendertarget.cpp
@@ -37,6 +37,24 @@
 #include "llgl.h"
 
 
+void check_framebuffer_status()
+{
+	if (gDebugGL)
+	{
+		GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
+		switch (status)
+		{
+		case GL_FRAMEBUFFER_COMPLETE_EXT:
+			break;
+		case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
+			llerrs << "WTF?" << llendl;
+			break;
+		default:
+			llerrs << "WTF?" << llendl;
+		}
+	}
+}
+
 BOOL LLRenderTarget::sUseFBO = FALSE;
 
 LLRenderTarget::LLRenderTarget() :
@@ -48,7 +66,9 @@ LLRenderTarget::LLRenderTarget() :
 	mStencil(0),
 	mUseDepth(FALSE),
 	mRenderDepth(FALSE),
-	mUsage(LLTexUnit::TT_TEXTURE)
+	mUsage(LLTexUnit::TT_TEXTURE),
+	mSamples(0),
+	mSampleBuffer(NULL)
 {
 }
 
@@ -57,40 +77,26 @@ LLRenderTarget::~LLRenderTarget()
 	release();
 }
 
-void LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, BOOL depth, LLTexUnit::eTextureType usage, BOOL use_fbo)
+
+void LLRenderTarget::setSampleBuffer(LLMultisampleBuffer* buffer)
+{
+	mSampleBuffer = buffer;
+}
+
+void LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, BOOL depth, BOOL stencil, LLTexUnit::eTextureType usage, BOOL use_fbo)
 {
 	stop_glerror();
 	mResX = resx;
 	mResY = resy;
 
+	mStencil = stencil;
 	mUsage = usage;
 	mUseDepth = depth;
-	release();
-
-	glGenTextures(1, (GLuint *) &mTex);
-	gGL.getTexUnit(0)->bindManual(mUsage, mTex);
-	glTexImage2D(LLTexUnit::getInternalType(mUsage), 0, color_fmt, mResX, mResY, 0, color_fmt, GL_UNSIGNED_BYTE, NULL);
-
-	glTexParameteri(LLTexUnit::getInternalType(mUsage), GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-	glTexParameteri(LLTexUnit::getInternalType(mUsage), GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-
-	if (mUsage != LLTexUnit::TT_RECT_TEXTURE)
-	{
-		glTexParameteri(LLTexUnit::getInternalType(mUsage), GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
-		glTexParameteri(LLTexUnit::getInternalType(mUsage), GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
-	}
-	else
-	{
-		// ATI doesn't support mirrored repeat for rectangular textures.
-		glTexParameteri(LLTexUnit::getInternalType(mUsage), GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-		glTexParameteri(LLTexUnit::getInternalType(mUsage), GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-	}
 
-	stop_glerror();
+	release();
 
 	if ((sUseFBO || use_fbo) && gGLManager.mHasFramebufferObject)
 	{
-
 		if (depth)
 		{
 			stop_glerror();
@@ -100,37 +106,141 @@ void LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, BOOL depth, LLT
 
 		glGenFramebuffersEXT(1, (GLuint *) &mFBO);
 
+		if (mDepth)
+		{
+			glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO);
+			if (mStencil)
+			{
+				glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, mDepth);
+				stop_glerror();
+				glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, mDepth);
+				stop_glerror();
+			}
+			else
+			{
+				glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, LLTexUnit::getInternalType(mUsage), mDepth, 0);
+				stop_glerror();
+			}
+			glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+		}
+		
 		stop_glerror();
+	}
 
-		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO);
+	addColorAttachment(color_fmt);
+}
 
-		stop_glerror();
+void LLRenderTarget::addColorAttachment(U32 color_fmt)
+{
+	if (color_fmt == 0)
+	{
+		return;
+	}
 
-		if (mDepth)
-		{
-			glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, LLTexUnit::getInternalType(mUsage), mDepth, 0);
-			stop_glerror();
-			glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, LLTexUnit::getInternalType(mUsage), mDepth, 0);
-			stop_glerror();
-		}
+	U32 offset = mTex.size();
+	if (offset >= 4 ||
+		offset > 0 && (mFBO == 0 || !gGLManager.mHasDrawBuffers))
+	{
+		llerrs << "Too many color attachments!" << llendl;
+	}
 
-		glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
-						LLTexUnit::getInternalType(mUsage), mTex, 0);
-		stop_glerror();
+	U32 tex;
+	LLImageGL::generateTextures(1, &tex);
+	gGL.getTexUnit(0)->bindManual(mUsage, tex);
+
+	stop_glerror();
+
+	LLImageGL::setManualImage(LLTexUnit::getInternalType(mUsage), 0, color_fmt, mResX, mResY, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
 
+	stop_glerror();
+
+	if (offset == 0)
+	{
+		gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
+	}
+	else
+	{ //don't filter data attachments
+		gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+	}
+	if (mUsage != LLTexUnit::TT_RECT_TEXTURE)
+	{
+		gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_MIRROR);
+	}
+	else
+	{
+		// ATI doesn't support mirrored repeat for rectangular textures.
+		gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
+	}
+	if (mFBO)
+	{
+		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO);
+		glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT+offset,
+			LLTexUnit::getInternalType(mUsage), tex, 0);
+			stop_glerror();
+
+		check_framebuffer_status();
+		
 		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
-		stop_glerror();
 	}
+
+	mTex.push_back(tex);
+
 }
 
 void LLRenderTarget::allocateDepth()
 {
-	glGenTextures(1, (GLuint *) &mDepth);
-	gGL.getTexUnit(0)->bindManual(mUsage, mDepth);
-	U32 internal_type = LLTexUnit::getInternalType(mUsage);
-	glTexParameteri(internal_type, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-	glTexParameteri(internal_type, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-	glTexImage2D(internal_type, 0, GL_DEPTH24_STENCIL8_EXT, mResX, mResY, 0, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, NULL);
+	if (mStencil)
+	{
+		//use render buffers where stencil buffers are in play
+		glGenRenderbuffersEXT(1, (GLuint *) &mDepth);
+		glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, mDepth);
+		glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, mResX, mResY);
+		glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
+	}
+	else
+	{
+		LLImageGL::generateTextures(1, &mDepth);
+		gGL.getTexUnit(0)->bindManual(mUsage, mDepth);
+		U32 internal_type = LLTexUnit::getInternalType(mUsage);
+		gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+		LLImageGL::setManualImage(internal_type, 0, GL_DEPTH24_STENCIL8_EXT, mResX, mResY, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, NULL);
+	}
+}
+
+void LLRenderTarget::shareDepthBuffer(LLRenderTarget& target)
+{
+	if (!mFBO || !target.mFBO)
+	{
+		llerrs << "Cannot share depth buffer between non FBO render targets." << llendl;
+	}
+
+	if (mDepth)
+	{
+		stop_glerror();
+		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, target.mFBO);
+		stop_glerror();
+
+		if (mStencil)
+		{
+			glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, mDepth);
+			stop_glerror();
+			glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, mDepth);			
+			stop_glerror();
+		}
+		else
+		{
+			glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, LLTexUnit::getInternalType(mUsage), mDepth, 0);
+			stop_glerror();
+			if (mStencil)
+			{
+				glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, LLTexUnit::getInternalType(mUsage), mDepth, 0);
+				stop_glerror();
+			}
+		}
+		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+
+		target.mUseDepth = TRUE;
+	}
 }
 
 void LLRenderTarget::release()
@@ -141,24 +251,63 @@ void LLRenderTarget::release()
 		mFBO = 0;
 	}
 
-	if (mTex)
+	if (mTex.size() > 0)
 	{
-		glDeleteTextures(1, (GLuint *) &mTex);
-		mTex = 0;
+		LLImageGL::deleteTextures(mTex.size(), &mTex[0]);
+		mTex.clear();
 	}
 
 	if (mDepth)
 	{
-		glDeleteTextures(1, (GLuint *) &mDepth);
+		if (mStencil)
+		{
+			glDeleteRenderbuffersEXT(1, (GLuint*) &mDepth);
+			stop_glerror();
+		}
+		else
+		{
+			LLImageGL::deleteTextures(1, &mDepth);
+			stop_glerror();
+		}
 		mDepth = 0;
 	}
+
+	mSampleBuffer = NULL;
 }
 
 void LLRenderTarget::bindTarget()
 {
 	if (mFBO)
 	{
-		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO);
+		stop_glerror();
+		if (mSampleBuffer)
+		{
+			mSampleBuffer->bindTarget(this);
+			stop_glerror();
+		}
+		else
+		{
+			glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO);
+			stop_glerror();
+			if (gGLManager.mHasDrawBuffers)
+			{ //setup multiple render targets
+				GLenum drawbuffers[] = {GL_COLOR_ATTACHMENT0_EXT,
+										GL_COLOR_ATTACHMENT1_EXT,
+										GL_COLOR_ATTACHMENT2_EXT,
+										GL_COLOR_ATTACHMENT3_EXT};
+				glDrawBuffersARB(mTex.size(), drawbuffers);
+			}
+			
+			if (mTex.empty())
+			{ //no color buffer to draw to
+				glDrawBuffer(GL_NONE);
+				glReadBuffer(GL_NONE);
+			}
+
+			check_framebuffer_status();
+
+			stop_glerror();
+		}
 	}
 
 	glViewport(0, 0, mResX, mResY);
@@ -173,7 +322,7 @@ void LLRenderTarget::unbindTarget()
 	}
 }
 
-void LLRenderTarget::clear()
+void LLRenderTarget::clear(U32 mask_in)
 {
 	U32 mask = GL_COLOR_BUFFER_BIT;
 	if (mUseDepth)
@@ -182,15 +331,36 @@ void LLRenderTarget::clear()
 	}
 	if (mFBO)
 	{
-		glClear(mask);
+		check_framebuffer_status();
+		stop_glerror();
+		glClear(mask & mask_in);
+		stop_glerror();
 	}
 	else
 	{
 		LLGLEnable scissor(GL_SCISSOR_TEST);
 		glScissor(0, 0, mResX, mResY);
 		stop_glerror();
-		glClear(mask);
+		glClear(mask & mask_in);
+	}
+}
+
+U32 LLRenderTarget::getTexture(U32 attachment) const
+{
+	if (attachment > mTex.size()-1)
+	{
+		llerrs << "Invalid attachment index." << llendl;
+	}
+	return mTex[attachment];
+}
+
+void LLRenderTarget::bindTexture(U32 index, S32 channel)
+{
+	if (index > mTex.size()-1)
+	{
+		llerrs << "Invalid attachment index." << llendl;
 	}
+	gGL.getTexUnit(channel)->bindManual(mUsage, mTex[index]);
 }
 
 void LLRenderTarget::flush(BOOL fetch_depth)
@@ -211,16 +381,87 @@ void LLRenderTarget::flush(BOOL fetch_depth)
 			gGL.getTexUnit(0)->bind(this, true);
 			glCopyTexImage2D(LLTexUnit::getInternalType(mUsage), 0, GL_DEPTH24_STENCIL8_EXT, 0, 0, mResX, mResY, 0);
 		}
+
+		gGL.getTexUnit(0)->disable();
+	}
+	else
+	{
+#if !LL_DARWIN
+
+		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+	
+		if (mSampleBuffer)
+		{
+			LLGLEnable multisample(GL_MULTISAMPLE_ARB);
+			stop_glerror();
+			glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO);
+			stop_glerror();
+			check_framebuffer_status();
+			glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, mSampleBuffer->mFBO);
+			check_framebuffer_status();
+			
+			stop_glerror();
+			glBlitFramebufferEXT(0, 0, mResX, mResY, 0, 0, mResX, mResY, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
+			stop_glerror();		
+
+			if (mTex.size() > 1)
+			{		
+				for (U32 i = 1; i < mTex.size(); ++i)
+				{
+					glFramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+										LLTexUnit::getInternalType(mUsage), mTex[i], 0);
+					stop_glerror();
+					glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, mSampleBuffer->mTex[i]);
+					stop_glerror();
+					glBlitFramebufferEXT(0, 0, mResX, mResY, 0, 0, mResX, mResY, GL_COLOR_BUFFER_BIT, GL_NEAREST);		
+					stop_glerror();
+				}
+
+				for (U32 i = 0; i < mTex.size(); ++i)
+				{
+					glFramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT+i,
+										LLTexUnit::getInternalType(mUsage), mTex[i], 0);
+					stop_glerror();
+					glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT+i, GL_RENDERBUFFER_EXT, mSampleBuffer->mTex[i]);
+					stop_glerror();
+				}
+			}
+		}
+#endif
+
+		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+		glFlush();
+	}
+}
+
+void LLRenderTarget::copyContents(LLRenderTarget& source, S32 srcX0, S32 srcY0, S32 srcX1, S32 srcY1,
+						S32 dstX0, S32 dstY0, S32 dstX1, S32 dstY1, U32 mask, U32 filter)
+{
+#if !LL_DARWIN
+	if (!source.mFBO || !mFBO)
+	{
+		llerrs << "Cannot copy framebuffer contents for non FBO render targets." << llendl;
+	}
+
+	if (mSampleBuffer)
+	{
+		mSampleBuffer->copyContents(source, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
 	}
 	else
 	{
+		glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, source.mFBO);
+		glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, mFBO);
+
+		glBlitFramebufferEXT(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
+
 		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
 	}
+#endif
 }
 
 BOOL LLRenderTarget::isComplete() const
 {
-	return (mTex || mDepth) ? TRUE : FALSE;
+	return (!mTex.empty() || mDepth) ? TRUE : FALSE;
 }
 
 void LLRenderTarget::getViewport(S32* viewport)
@@ -231,3 +472,191 @@ void LLRenderTarget::getViewport(S32* viewport)
 	viewport[3] = mResY;
 }
 
+//==================================================
+// LLMultisampleBuffer implementation
+//==================================================
+LLMultisampleBuffer::LLMultisampleBuffer()
+{
+
+}
+
+LLMultisampleBuffer::~LLMultisampleBuffer()
+{
+	releaseSampleBuffer();
+}
+
+void LLMultisampleBuffer::releaseSampleBuffer()
+{
+	if (mFBO)
+	{
+		glDeleteFramebuffersEXT(1, (GLuint *) &mFBO);
+		mFBO = 0;
+	}
+
+	if (mTex.size() > 0)
+	{
+		glDeleteRenderbuffersEXT(mTex.size(), (GLuint *) &mTex[0]);
+		mTex.clear();
+	}
+
+	if (mDepth)
+	{
+		glDeleteRenderbuffersEXT(1, (GLuint *) &mDepth);
+		mDepth = 0;
+	}
+}
+
+void LLMultisampleBuffer::bindTarget()
+{
+	bindTarget(this);
+}
+
+void LLMultisampleBuffer::bindTarget(LLRenderTarget* ref)
+{
+	if (!ref)
+	{
+		ref = this;
+	}
+
+	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO);
+	if (gGLManager.mHasDrawBuffers)
+	{ //setup multiple render targets
+		GLenum drawbuffers[] = {GL_COLOR_ATTACHMENT0_EXT,
+								GL_COLOR_ATTACHMENT1_EXT,
+								GL_COLOR_ATTACHMENT2_EXT,
+								GL_COLOR_ATTACHMENT3_EXT};
+		glDrawBuffersARB(ref->mTex.size(), drawbuffers);
+	}
+
+	check_framebuffer_status();
+
+	glViewport(0, 0, mResX, mResY);
+
+}
+
+void LLMultisampleBuffer::allocate(U32 resx, U32 resy, U32 color_fmt, BOOL depth, BOOL stencil,  LLTexUnit::eTextureType usage, BOOL use_fbo )
+{
+	allocate(resx,resy,color_fmt,depth,stencil,usage,use_fbo,2);
+}
+
+void LLMultisampleBuffer::allocate(U32 resx, U32 resy, U32 color_fmt, BOOL depth, BOOL stencil,  LLTexUnit::eTextureType usage, BOOL use_fbo, U32 samples )
+{
+	stop_glerror();
+	mResX = resx;
+	mResY = resy;
+
+	mUsage = usage;
+	mUseDepth = depth;
+	mStencil = stencil;
+
+	releaseSampleBuffer();
+
+	if (!gGLManager.mHasFramebufferMultisample)
+	{
+		llerrs << "Attempting to allocate unsupported render target type!" << llendl;
+	}
+
+	mSamples = samples;
+	
+	if (mSamples <= 1)
+	{
+		llerrs << "Cannot create a multisample buffer with less than 2 samples." << llendl;
+	}
+
+	stop_glerror();
+
+	if ((sUseFBO || use_fbo) && gGLManager.mHasFramebufferObject)
+	{
+
+		if (depth)
+		{
+			stop_glerror();
+			allocateDepth();
+			stop_glerror();
+		}
+
+		glGenFramebuffersEXT(1, (GLuint *) &mFBO);
+
+		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO);
+
+		if (mDepth)
+		{
+			glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, mDepth);
+			if (mStencil)
+			{
+				glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, mDepth);			
+			}
+			glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+		}
+		
+		stop_glerror();
+
+		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+		stop_glerror();
+	}
+
+	addColorAttachment(color_fmt);
+}
+
+void LLMultisampleBuffer::addColorAttachment(U32 color_fmt)
+{
+#if !LL_DARWIN
+	if (color_fmt == 0)
+	{
+		return;
+	}
+
+	U32 offset = mTex.size();
+	if (offset >= 4 ||
+		offset > 0 && (mFBO == 0 || !gGLManager.mHasDrawBuffers))
+	{
+		llerrs << "Too many color attachments!" << llendl;
+	}
+
+	U32 tex;
+	glGenRenderbuffersEXT(1, &tex);
+	
+	glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, tex);
+	glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, mSamples, color_fmt, mResX, mResY);
+	stop_glerror();
+
+	if (mFBO)
+	{
+		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO);
+		glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT+offset, GL_RENDERBUFFER_EXT, tex);
+		stop_glerror();
+		GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
+		switch (status)
+		{
+		case GL_FRAMEBUFFER_COMPLETE_EXT:
+			break;
+		case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
+			llerrs << "WTF?" << llendl;
+			break;
+		default:
+			llerrs << "WTF?" << llendl;
+		}
+
+		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+	}
+
+	mTex.push_back(tex);
+#endif
+}
+
+void LLMultisampleBuffer::allocateDepth()
+{
+#if !LL_DARWIN
+	glGenRenderbuffersEXT(1, (GLuint* ) &mDepth);
+	glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, mDepth);
+	if (mStencil)
+	{
+		glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, mSamples, GL_DEPTH24_STENCIL8_EXT, mResX, mResY);	
+	}
+	else
+	{
+		glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, mSamples, GL_DEPTH_COMPONENT16_ARB, mResX, mResY);	
+	}
+#endif
+}
+
diff --git a/indra/llrender/llrendertarget.h b/indra/llrender/llrendertarget.h
index d6db054e45cb027d2a5fd19fa77d33c2df44c137..d5d809b791da1dd2fc1679a9ba5518c018a368e1 100644
--- a/indra/llrender/llrendertarget.h
+++ b/indra/llrender/llrendertarget.h
@@ -33,6 +33,9 @@
 #ifndef LL_LLRENDERTARGET_H
 #define LL_LLRENDERTARGET_H
 
+// LLRenderTarget is unavailible on the mapserver since it uses FBOs.
+#if !LL_MESA_HEADLESS
+
 #include "llgl.h"
 #include "llrender.h"
 
@@ -60,6 +63,7 @@
 
 */
 
+class LLMultisampleBuffer;
 
 class LLRenderTarget
 {
@@ -68,15 +72,25 @@ class LLRenderTarget
 	static BOOL sUseFBO; 
 
 	LLRenderTarget();
-	~LLRenderTarget();
+	virtual ~LLRenderTarget();
 
 	//allocate resources for rendering
 	//must be called before use
 	//multiple calls will release previously allocated resources
-	void allocate(U32 resx, U32 resy, U32 color_fmt, BOOL depth, LLTexUnit::eTextureType usage = LLTexUnit::TT_TEXTURE, BOOL use_fbo = FALSE);
+	void allocate(U32 resx, U32 resy, U32 color_fmt, BOOL depth, BOOL stencil, LLTexUnit::eTextureType usage = LLTexUnit::TT_TEXTURE, BOOL use_fbo = FALSE);
+
+	//provide this render target with a multisample resource.
+	void setSampleBuffer(LLMultisampleBuffer* buffer);
+
+	//add color buffer attachment
+	//limit of 4 color attachments per render target
+	virtual void addColorAttachment(U32 color_fmt);
 
 	//allocate a depth texture
-	void allocateDepth();
+	virtual void allocateDepth();
+
+	//share depth buffer with provided render target
+	virtual void shareDepthBuffer(LLRenderTarget& target);
 
 	//free any allocated resources
 	//safe to call redundantly
@@ -84,14 +98,14 @@ class LLRenderTarget
 
 	//bind target for rendering
 	//applies appropriate viewport
-	void bindTarget();
+	virtual void bindTarget();
 
 	//unbind target for rendering
 	static void unbindTarget();
 	
 	//clear render targer, clears depth buffer if present,
 	//uses scissor rect if in copy-to-texture mode
-	void clear();
+	void clear(U32 mask = 0xFFFFFFFF);
 	
 	//get applied viewport
 	void getViewport(S32* viewport);
@@ -104,10 +118,12 @@ class LLRenderTarget
 
 	LLTexUnit::eTextureType getUsage(void) const { return mUsage; }
 
-	U32 getTexture(void) const { return mTex; }
+	U32 getTexture(U32 attachment = 0) const;
 
 	U32 getDepth(void) const { return mDepth; }
 
+	void bindTexture(U32 index, S32 channel);
+
 	//flush rendering operations
 	//must be called when rendering is complete
 	//should be used 1:1 with bindTarget 
@@ -116,23 +132,47 @@ class LLRenderTarget
 	// the current depth texture.  A depth texture will be allocated if needed.
 	void flush(BOOL fetch_depth = FALSE);
 
+	void copyContents(LLRenderTarget& source, S32 srcX0, S32 srcY0, S32 srcX1, S32 srcY1,
+						S32 dstX0, S32 dstY0, S32 dstX1, S32 dstY1, U32 mask, U32 filter);
+
 	//Returns TRUE if target is ready to be rendered into.
 	//That is, if the target has been allocated with at least
 	//one renderable attachment (i.e. color buffer, depth buffer).
 	BOOL isComplete() const;
 
-private:
+protected:
+	friend class LLMultisampleBuffer;
 	U32 mResX;
 	U32 mResY;
-	U32 mTex;
+	std::vector<U32> mTex;
 	U32 mFBO;
 	U32 mDepth;
-	U32 mStencil;
+	BOOL mStencil;
 	BOOL mUseDepth;
 	BOOL mRenderDepth;
 	LLTexUnit::eTextureType mUsage;
+	U32 mSamples;
+	LLMultisampleBuffer* mSampleBuffer;
 	
 };
 
+class LLMultisampleBuffer : public LLRenderTarget
+{
+public:
+	LLMultisampleBuffer();
+	virtual ~LLMultisampleBuffer();
+
+	void releaseSampleBuffer();
+
+	virtual void bindTarget();
+	void bindTarget(LLRenderTarget* ref);
+	virtual void allocate(U32 resx, U32 resy, U32 color_fmt, BOOL depth, BOOL stencil, LLTexUnit::eTextureType usage, BOOL use_fbo);
+	void allocate(U32 resx, U32 resy, U32 color_fmt, BOOL depth, BOOL stencil, LLTexUnit::eTextureType usage, BOOL use_fbo, U32 samples);
+	virtual void addColorAttachment(U32 color_fmt);
+	virtual void allocateDepth();
+};
+
+#endif //!LL_MESA_HEADLESS
+
 #endif
 
diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp
index 4d16741794091de8da7d900e0f0f1105ea4c1295..461edbeec7bd18d0ff4f6e6544abe8261632c8fb 100644
--- a/indra/llrender/llvertexbuffer.cpp
+++ b/indra/llrender/llvertexbuffer.cpp
@@ -69,8 +69,10 @@ S32 LLVertexBuffer::sTypeOffsets[LLVertexBuffer::TYPE_MAX] =
 {
 	sizeof(LLVector3), // TYPE_VERTEX,
 	sizeof(LLVector3), // TYPE_NORMAL,
-	sizeof(LLVector2), // TYPE_TEXCOORD,
+	sizeof(LLVector2), // TYPE_TEXCOORD0,
+	sizeof(LLVector2), // TYPE_TEXCOORD1,
 	sizeof(LLVector2), // TYPE_TEXCOORD2,
+	sizeof(LLVector2), // TYPE_TEXCOORD3,
 	sizeof(LLColor4U), // TYPE_COLOR,
 	sizeof(LLVector3), // TYPE_BINORMAL,
 	sizeof(F32),	   // TYPE_WEIGHT,
@@ -103,8 +105,8 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask)
 		{
 			MAP_VERTEX,
 			MAP_NORMAL,
-			MAP_TEXCOORD,
-			MAP_COLOR
+			MAP_TEXCOORD0,
+			MAP_COLOR,
 		};
 		
 		GLenum array[] =
@@ -112,7 +114,7 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask)
 			GL_VERTEX_ARRAY,
 			GL_NORMAL_ARRAY,
 			GL_TEXTURE_COORD_ARRAY,
-			GL_COLOR_ARRAY
+			GL_COLOR_ARRAY,
 		};
 
 		for (U32 i = 0; i < 4; ++i)
@@ -123,7 +125,7 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask)
 				{ //needs to be disabled
 					glDisableClientState(array[i]);
 				}
-				else
+				else if (gDebugGL)
 				{ //needs to be enabled, make sure it was (DEBUG TEMPORARY)
 					if (i > 0 && !glIsEnabled(array[i]))
 					{
@@ -137,29 +139,55 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask)
 				{ //needs to be enabled
 					glEnableClientState(array[i]);
 				}
-				else if (glIsEnabled(array[i]))
+				else if (gDebugGL && glIsEnabled(array[i]))
 				{ //needs to be disabled, make sure it was (DEBUG TEMPORARY)
 					llerrs << "Bad client state! " << array[i] << " enabled." << llendl;
 				}
 			}
 		}
 
-		if (sLastMask & MAP_TEXCOORD2)
+		U32 map_tc[] = 
 		{
-			if (!(data_mask & MAP_TEXCOORD2))
+			MAP_TEXCOORD1,
+			MAP_TEXCOORD2,
+			MAP_TEXCOORD3
+		};
+
+		for (U32 i = 0; i < 3; i++)
+		{
+			if (sLastMask & map_tc[i])
 			{
-				glClientActiveTextureARB(GL_TEXTURE1_ARB);
+				if (!(data_mask & map_tc[i]))
+				{
+					glClientActiveTextureARB(GL_TEXTURE1_ARB+i);
+					glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+					glClientActiveTextureARB(GL_TEXTURE0_ARB);
+				}
+			}
+			else if (data_mask & map_tc[i])
+			{
+				glClientActiveTextureARB(GL_TEXTURE1_ARB+i);
+				glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+				glClientActiveTextureARB(GL_TEXTURE0_ARB);
+			}
+		}
+
+		if (sLastMask & MAP_BINORMAL)
+		{
+			if (!(data_mask & MAP_BINORMAL))
+			{
+				glClientActiveTextureARB(GL_TEXTURE2_ARB);
 				glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 				glClientActiveTextureARB(GL_TEXTURE0_ARB);
 			}
 		}
-		else if (data_mask & MAP_TEXCOORD2)
+		else if (data_mask & MAP_BINORMAL)
 		{
-			glClientActiveTextureARB(GL_TEXTURE1_ARB);
+			glClientActiveTextureARB(GL_TEXTURE2_ARB);
 			glEnableClientState(GL_TEXTURE_COORD_ARRAY);
 			glClientActiveTextureARB(GL_TEXTURE0_ARB);
 		}
-
+	
 		sLastMask = data_mask;
 	}
 }
@@ -194,6 +222,7 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi
 		return;
 	}
 
+	stop_glerror();
 	glDrawRangeElements(sGLMode[mode], start, end, count, GL_UNSIGNED_SHORT, 
 		((U16*) getIndicesPointer()) + indices_offset);
 	stop_glerror();
@@ -223,13 +252,14 @@ void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const
 		return;
 	}
 
+	stop_glerror();
 	glDrawElements(sGLMode[mode], count, GL_UNSIGNED_SHORT,
 		((U16*) getIndicesPointer()) + indices_offset);
+	stop_glerror();
 }
 
 void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const
 {
-	
 	if (first >= (U32) mRequestedNumVerts ||
 		first + count > (U32) mRequestedNumVerts)
 	{
@@ -247,6 +277,7 @@ void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const
 		return;
 	}
 
+	stop_glerror();
 	glDrawArrays(sGLMode[mode], first, count);
 	stop_glerror();
 }
@@ -767,11 +798,7 @@ U8* LLVertexBuffer::mapBuffer(S32 access)
 		stop_glerror();
 		mMappedIndexData = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
 		stop_glerror();
-		/*if (sMapped)
-		{
-			llerrs << "Mapped two VBOs at the same time!" << llendl;
-		}
-		sMapped = TRUE;*/		
+
 		if (!mMappedData)
 		{
 			//--------------------
@@ -896,14 +923,22 @@ bool LLVertexBuffer::getIndexStrider(LLStrider<U16>& strider, S32 index)
 {
 	return VertexBufferStrider<U16,TYPE_INDEX>::get(*this, strider, index);
 }
-bool LLVertexBuffer::getTexCoordStrider(LLStrider<LLVector2>& strider, S32 index)
+bool LLVertexBuffer::getTexCoord0Strider(LLStrider<LLVector2>& strider, S32 index)
+{
+	return VertexBufferStrider<LLVector2,TYPE_TEXCOORD0>::get(*this, strider, index);
+}
+bool LLVertexBuffer::getTexCoord1Strider(LLStrider<LLVector2>& strider, S32 index)
 {
-	return VertexBufferStrider<LLVector2,TYPE_TEXCOORD>::get(*this, strider, index);
+	return VertexBufferStrider<LLVector2,TYPE_TEXCOORD1>::get(*this, strider, index);
 }
-bool LLVertexBuffer::getTexCoord2Strider(LLStrider<LLVector2>& strider, S32 index)
+/*bool LLVertexBuffer::getTexCoord2Strider(LLStrider<LLVector2>& strider, S32 index)
 {
 	return VertexBufferStrider<LLVector2,TYPE_TEXCOORD2>::get(*this, strider, index);
 }
+bool LLVertexBuffer::getTexCoord3Strider(LLStrider<LLVector2>& strider, S32 index)
+{
+	return VertexBufferStrider<LLVector2,TYPE_TEXCOORD3>::get(*this, strider, index);
+}*/
 bool LLVertexBuffer::getNormalStrider(LLStrider<LLVector3>& strider, S32 index)
 {
 	return VertexBufferStrider<LLVector3,TYPE_NORMAL>::get(*this, strider, index);
@@ -1101,24 +1136,39 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) const
 	{
 		glNormalPointer(GL_FLOAT, stride, (void*)(base + mOffsets[TYPE_NORMAL]));
 	}
+	if (data_mask & MAP_TEXCOORD3)
+	{
+		glClientActiveTextureARB(GL_TEXTURE3_ARB);
+		glTexCoordPointer(2,GL_FLOAT, stride, (void*)(base + mOffsets[TYPE_TEXCOORD3]));
+		glClientActiveTextureARB(GL_TEXTURE0_ARB);
+	}
 	if (data_mask & MAP_TEXCOORD2)
 	{
-		glClientActiveTextureARB(GL_TEXTURE1_ARB);
+		glClientActiveTextureARB(GL_TEXTURE2_ARB);
 		glTexCoordPointer(2,GL_FLOAT, stride, (void*)(base + mOffsets[TYPE_TEXCOORD2]));
 		glClientActiveTextureARB(GL_TEXTURE0_ARB);
 	}
-	if (data_mask & MAP_TEXCOORD)
+	if (data_mask & MAP_TEXCOORD1)
 	{
-		glTexCoordPointer(2,GL_FLOAT, stride, (void*)(base + mOffsets[TYPE_TEXCOORD]));
+		glClientActiveTextureARB(GL_TEXTURE1_ARB);
+		glTexCoordPointer(2,GL_FLOAT, stride, (void*)(base + mOffsets[TYPE_TEXCOORD1]));
+		glClientActiveTextureARB(GL_TEXTURE0_ARB);
 	}
-	if (data_mask & MAP_COLOR)
+	if (data_mask & MAP_BINORMAL)
 	{
-		glColorPointer(4, GL_UNSIGNED_BYTE, stride, (void*)(base + mOffsets[TYPE_COLOR]));
+		glClientActiveTextureARB(GL_TEXTURE2_ARB);
+		glTexCoordPointer(3,GL_FLOAT, stride, (void*)(base + mOffsets[TYPE_BINORMAL]));
+		glClientActiveTextureARB(GL_TEXTURE0_ARB);
 	}
-	if (data_mask & MAP_BINORMAL)
+	if (data_mask & MAP_TEXCOORD0)
 	{
-		glVertexAttribPointerARB(6, 3, GL_FLOAT, FALSE,  stride, (void*)(base + mOffsets[TYPE_BINORMAL]));
+		glTexCoordPointer(2,GL_FLOAT, stride, (void*)(base + mOffsets[TYPE_TEXCOORD0]));
 	}
+	if (data_mask & MAP_COLOR)
+	{
+		glColorPointer(4, GL_UNSIGNED_BYTE, stride, (void*)(base + mOffsets[TYPE_COLOR]));
+	}
+	
 	if (data_mask & MAP_WEIGHT)
 	{
 		glVertexAttribPointerARB(1, 1, GL_FLOAT, FALSE, stride, (void*)(base + mOffsets[TYPE_WEIGHT]));
diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h
index fbddd9d887e707b81cbdc3e808034aba2ac24594..aad948e17fd8c23a2533e3e6685bc6d454f5d965 100644
--- a/indra/llrender/llvertexbuffer.h
+++ b/indra/llrender/llvertexbuffer.h
@@ -100,8 +100,10 @@ class LLVertexBuffer : public LLRefCount
 	enum {
 		TYPE_VERTEX,
 		TYPE_NORMAL,
-		TYPE_TEXCOORD,
+		TYPE_TEXCOORD0,
+		TYPE_TEXCOORD1,
 		TYPE_TEXCOORD2,
+		TYPE_TEXCOORD3,
 		TYPE_COLOR,
 		// These use VertexAttribPointer and should possibly be made generic
 		TYPE_BINORMAL,
@@ -113,16 +115,15 @@ class LLVertexBuffer : public LLRefCount
 	enum {
 		MAP_VERTEX = (1<<TYPE_VERTEX),
 		MAP_NORMAL = (1<<TYPE_NORMAL),
-		MAP_TEXCOORD = (1<<TYPE_TEXCOORD),
+		MAP_TEXCOORD0 = (1<<TYPE_TEXCOORD0),
+		MAP_TEXCOORD1 = (1<<TYPE_TEXCOORD1),
 		MAP_TEXCOORD2 = (1<<TYPE_TEXCOORD2),
+		MAP_TEXCOORD3 = (1<<TYPE_TEXCOORD3),
 		MAP_COLOR = (1<<TYPE_COLOR),
 		// These use VertexAttribPointer and should possibly be made generic
 		MAP_BINORMAL = (1<<TYPE_BINORMAL),
 		MAP_WEIGHT = (1<<TYPE_WEIGHT),
 		MAP_CLOTHWEIGHT = (1<<TYPE_CLOTHWEIGHT),
-		MAP_DRAW = 0x2000, // Buffer is in draw (read-only) mode
-		MAP_MAPPED = 0x4000, // Indicates that buffer has been mapped, but not to any type of data
-		MAP_UNMAPPED = 0x8000 // Indicates that buffer has been logically un-mapped
 	};
 	
 protected:
@@ -165,8 +166,8 @@ class LLVertexBuffer : public LLRefCount
 	//   vb->unmapBuffer();
 	bool getVertexStrider(LLStrider<LLVector3>& strider, S32 index=0);
 	bool getIndexStrider(LLStrider<U16>& strider, S32 index=0);
-	bool getTexCoordStrider(LLStrider<LLVector2>& strider, S32 index=0);
-	bool getTexCoord2Strider(LLStrider<LLVector2>& strider, S32 index=0);
+	bool getTexCoord0Strider(LLStrider<LLVector2>& strider, S32 index=0);
+	bool getTexCoord1Strider(LLStrider<LLVector2>& strider, S32 index=0);
 	bool getNormalStrider(LLStrider<LLVector3>& strider, S32 index=0);
 	bool getBinormalStrider(LLStrider<LLVector3>& strider, S32 index=0);
 	bool getColorStrider(LLStrider<LLColor4U>& strider, S32 index=0);
diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp
index 16c7d69b32257a84cbcc9ef42190a7bd1fdd484f..609763ce15520f90cdea074d58205bde32650a1a 100644
--- a/indra/llui/lllineeditor.cpp
+++ b/indra/llui/lllineeditor.cpp
@@ -362,7 +362,7 @@ void LLLineEditor::setCursor( S32 pos )
 	{
 		S32 width_chars_to_left = mGLFont->getWidth(mText.getWString().c_str(), 0, mScrollHPos);
 		S32 last_visible_char = mGLFont->maxDrawableChars(mText.getWString().c_str(), llmax(0.f, (F32)(mMaxHPixels - mMinHPixels + width_chars_to_left))); 
-		S32 min_scroll = mGLFont->firstDrawableChar(mText.getWString().c_str(), (F32)(mMaxHPixels - mMinHPixels), mText.length(), getCursor());
+		S32 min_scroll = mGLFont->firstDrawableChar(mText.getWString().c_str(), (F32)(mMaxHPixels - mMinHPixels - UI_LINEEDITOR_CURSOR_THICKNESS - UI_LINEEDITOR_H_PAD), mText.length(), getCursor());
 		if (old_cursor_pos == last_visible_char)
 		{
 			mScrollHPos = llmin(mText.length(), llmax(min_scroll, mScrollHPos + SCROLL_INCREMENT_ADD));
diff --git a/indra/llui/llviewborder.cpp b/indra/llui/llviewborder.cpp
index ce6cf6574f4b12386e4407da1c2ccc6e9babba6a..d4a9e9d1bf165ea2fc5c712587da599532927f3d 100644
--- a/indra/llui/llviewborder.cpp
+++ b/indra/llui/llviewborder.cpp
@@ -232,8 +232,7 @@ void LLViewBorder::drawTextures()
 	//gGL.color4fv(UI_VERTEX_COLOR.mV);
 
 	//gGL.getTexUnit(0)->bind(mTexture);
-	//glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
-	//glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
+	//gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_WRAP);
 
 	//drawTextureTrapezoid(   0.f, mBorderWidth, getRect().getWidth(),  0,					0 );
 	//drawTextureTrapezoid(  90.f, mBorderWidth, getRect().getHeight(), (F32)getRect().getWidth(),0 );
diff --git a/indra/llvfs/lllfsthread.cpp b/indra/llvfs/lllfsthread.cpp
index a55b5402ed57765944ed280a736ed7ae4ba6e13b..704e1ab14274d0c51af38e375e3f59a9d404d863 100644
--- a/indra/llvfs/lllfsthread.cpp
+++ b/indra/llvfs/lllfsthread.cpp
@@ -73,6 +73,10 @@ LLLFSThread::LLLFSThread(bool threaded) :
 	LLQueuedThread("LFS", threaded),
 	mPriorityCounter(PRIORITY_LOWBITS)
 {
+	if(!mLocalAPRFilePoolp)
+	{
+		mLocalAPRFilePoolp = new LLVolatileAPRPool() ;
+	}
 }
 
 LLLFSThread::~LLLFSThread()
@@ -184,8 +188,9 @@ bool LLLFSThread::Request::processRequest()
 	if (mOperation ==  FILE_READ)
 	{
 		llassert(mOffset >= 0);
-		apr_file_t* filep = ll_apr_file_open(mFileName, LL_APR_RB, mThread->mAPRPoolp);
-		if (!filep)
+		LLAPRFile infile ;
+		infile.open(mThread->getLocalAPRFilePool(), mFileName, LL_APR_RB);
+		if (!infile.getFileHandle())
 		{
 			llwarns << "LLLFS: Unable to read file: " << mFileName << llendl;
 			mBytesRead = 0; // fail
@@ -193,13 +198,13 @@ bool LLLFSThread::Request::processRequest()
 		}
 		S32 off;
 		if (mOffset < 0)
-			off = ll_apr_file_seek(filep, APR_END, 0);
+			off = infile.seek(APR_END, 0);
 		else
-			off = ll_apr_file_seek(filep, APR_SET, mOffset);
+			off = infile.seek(APR_SET, mOffset);
 		llassert_always(off >= 0);
-		mBytesRead = ll_apr_file_read(filep, mBuffer, mBytes );
-		apr_file_close(filep);
+		mBytesRead = infile.read(mBuffer, mBytes );
 		complete = true;
+		infile.close() ;
 // 		llinfos << "LLLFSThread::READ:" << mFileName << " Bytes: " << mBytesRead << llendl;
 	}
 	else if (mOperation ==  FILE_WRITE)
@@ -207,8 +212,9 @@ bool LLLFSThread::Request::processRequest()
 		apr_int32_t flags = APR_CREATE|APR_WRITE|APR_BINARY;
 		if (mOffset < 0)
 			flags |= APR_APPEND;
-		apr_file_t* filep = ll_apr_file_open(mFileName, flags, mThread->mAPRPoolp);
-		if (!filep)
+		LLAPRFile outfile ;
+		outfile.open(mThread->getLocalAPRFilePool(), mFileName, flags);
+		if (!outfile.getFileHandle())
 		{
 			llwarns << "LLLFS: Unable to write file: " << mFileName << llendl;
 			mBytesRead = 0; // fail
@@ -216,18 +222,17 @@ bool LLLFSThread::Request::processRequest()
 		}
 		if (mOffset >= 0)
 		{
-			S32 seek = ll_apr_file_seek(filep, APR_SET, mOffset);
+			S32 seek = outfile.seek(APR_SET, mOffset);
 			if (seek < 0)
 			{
-				apr_file_close(filep);
 				llwarns << "LLLFS: Unable to write file (seek failed): " << mFileName << llendl;
 				mBytesRead = 0; // fail
 				return true;
 			}
 		}
-		mBytesRead = ll_apr_file_write(filep, mBuffer, mBytes );
+		mBytesRead = outfile.write(mBuffer, mBytes );
 		complete = true;
-		apr_file_close(filep);
+
 // 		llinfos << "LLLFSThread::WRITE:" << mFileName << " Bytes: " << mBytesRead << "/" << mBytes << " Offset:" << mOffset << llendl;
 	}
 	else
diff --git a/indra/llvfs/llvfs.cpp b/indra/llvfs/llvfs.cpp
index 30d20bb35a5971a1f05b60143159e0360adf4b53..8c0ea5fd146cb7e03bcb468683f9cd78434422bf 100644
--- a/indra/llvfs/llvfs.cpp
+++ b/indra/llvfs/llvfs.cpp
@@ -2070,9 +2070,11 @@ void LLVFS::dumpFiles()
 			std::string extension = get_extension(type);
 			std::string filename = id.asString() + extension;
 			llinfos << " Writing " << filename << llendl;
-			apr_file_t* file = ll_apr_file_open(filename, LL_APR_WB);
-			ll_apr_file_write(file, buffer, size);
-			apr_file_close(file);
+			
+			LLAPRFile outfile ;
+			outfile.open(filename, LL_APR_WB);
+			outfile.write(buffer, size);
+			outfile.close();
 			delete[] buffer;
 			files_extracted++;
 		}
diff --git a/indra/llwindow/llwindowsdl.cpp b/indra/llwindow/llwindowsdl.cpp
index 6b1b6f4d609982390df0e4ec54e19422a129adb7..1a724b5f7732b90149d37e29abce9ed59ba4f964 100644
--- a/indra/llwindow/llwindowsdl.cpp
+++ b/indra/llwindow/llwindowsdl.cpp
@@ -271,7 +271,7 @@ static SDL_Surface *Load_BMP_Resource(const char *basename)
 #if LL_X11
 // This is an XFree86/XOrg-specific hack for detecting the amount of Video RAM
 // on this machine.  It works by searching /var/log/var/log/Xorg.?.log or
-// /var/log/XFree86.?.log for a ': (VideoRAM|Memory): (%d+) kB' regex, where
+// /var/log/XFree86.?.log for a ': (VideoRAM ?|Memory): (%d+) kB' regex, where
 // '?' is the X11 display number derived from $DISPLAY
 static int x11_detect_VRAM_kb_fp(FILE *fp, const char *prefix_str)
 {
@@ -285,6 +285,8 @@ static int x11_detect_VRAM_kb_fp(FILE *fp, const char *prefix_str)
 		// favourite regex implementation - libboost_regex - is
 		// quite a heavy and troublesome dependency for the client, so
 		// it seems a shame to introduce it for such a simple task.
+		// *FIXME: libboost_regex is a dependency now anyway, so we may
+		// as well use it instead of this hand-rolled nonsense.
 		const char *part1_template = prefix_str;
 		const char part2_template[] = " kB";
 		char *part1 = strstr(line_buf, part1_template);
@@ -361,8 +363,17 @@ static int x11_detect_VRAM_kb()
 			fp = fopen(fname.c_str(), "r");
 			if (fp)
 			{
-				rtn = x11_detect_VRAM_kb_fp(fp, ": Memory: ");
+				rtn = x11_detect_VRAM_kb_fp(fp, ": Video RAM: ");
 				fclose(fp);
+				if (0 == rtn)
+				{
+					fp = fopen(fname.c_str(), "r");
+					if (fp)
+					{
+						rtn = x11_detect_VRAM_kb_fp(fp, ": Memory: ");
+						fclose(fp);
+					}
+				}
 			}
 		}
 	}
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index d1fdc8caa18213a326b0fd9c9bb0e35f67afe3e3..b1eb4d93910b27ed354f602af1635d927edbc99d 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -373,6 +373,8 @@ LLWindowWin32::LLWindowWin32(const std::string& title, const std::string& name,
 	mMousePositionModified = FALSE;
 	mInputProcessingPaused = FALSE;
 	mPreeditor = NULL;
+	mhDC = NULL;
+	mhRC = NULL;
 
 	// Initialize the keyboard
 	gKeyboard = new LLKeyboardWin32();
@@ -418,7 +420,7 @@ LLWindowWin32::LLWindowWin32(const std::string& title, const std::string& name,
 	mhInstance = GetModuleHandle(NULL);
 	mWndProc = NULL;
 
-	mSwapMethod = SWAP_METHOD_EXCHANGE;
+	mSwapMethod = SWAP_METHOD_UNDEFINED;
 
 	// No WPARAM yet.
 	mLastSizeWParam = 0;
@@ -844,8 +846,13 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO
 	RECT	window_rect;
 	S32 width = size.mX;
 	S32 height = size.mY;
+	BOOL auto_show = FALSE;
 
-	resetDisplayResolution();
+	if (mhRC)
+	{
+		auto_show = TRUE;
+		resetDisplayResolution();
+	}
 
 	if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode))
 	{
@@ -1183,8 +1190,28 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO
 			LL_INFOS("Window") << "Choosing pixel formats: " << num_formats << " pixel formats returned" << LL_ENDL;
 		}
 
-		pixel_format = pixel_formats[0];
+		
+
+		S32 swap_method = 0;
+		S32 cur_format = num_formats-1;
+		GLint swap_query = WGL_SWAP_METHOD_ARB;
+
+		BOOL found_format = FALSE;
 
+		while (!found_format && wglGetPixelFormatAttribivARB(mhDC, pixel_format, 0, 1, &swap_query, &swap_method))
+		{
+			if (swap_method == WGL_SWAP_UNDEFINED_ARB || cur_format <= 0)
+			{
+				found_format = TRUE;
+			}
+			else
+			{
+				--cur_format;
+			}
+		}
+		
+		pixel_format = pixel_formats[cur_format];
+		
 		if (mhDC != 0)											// Does The Window Have A Device Context?
 		{
 			wglMakeCurrent(mhDC, 0);							// Set The Current Active Rendering Context To Zero
@@ -1227,9 +1254,6 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO
 			return FALSE;
 		}
 
-		int swap_method = 0;
-		GLint swap_query = WGL_SWAP_METHOD_ARB;
-
 		if (wglGetPixelFormatAttribivARB(mhDC, pixel_format, 0, 1, &swap_query, &swap_method))
 		{
 			switch (swap_method)
@@ -1342,13 +1366,21 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO
 	}
 
 	SetWindowLong(mWindowHandle, GWL_USERDATA, (U32)this);
-	show();
-
+	
 	//register joystick timer callback
 	SetTimer( mWindowHandle, 0, 1000 / 30, NULL ); // 30 fps timer
 
 	// ok to post quit messages now
 	mPostQuit = TRUE;
+
+	if (auto_show)
+	{
+		show();
+		glClearColor(0.0f, 0.0f, 0.0f, 0.f);
+		glClear(GL_COLOR_BUFFER_BIT);
+		swapBuffers();
+	}
+
 	return TRUE;
 }
 
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index e532793a827a38f199698739e4eb5ce8739d1aee..123f3b72a3ecca638be32200810edd6d79caf675 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -30,6 +30,7 @@ include(LScript)
 include(Linking)
 include(Mozlib)
 include(NDOF)
+include(GooglePerfTools)
 include(TemplateCheck)
 include(UI)
 include(UnixInstall)
@@ -1330,8 +1331,8 @@ if (WINDOWS)
     
     set_target_properties(${VIEWER_BINARY_NAME}
         PROPERTIES
-        LINK_FLAGS "/debug /NODEFAULTLIB:MSVCRT /SUBSYSTEM:WINDOWS"
-        LINK_FLAGS_DEBUG "/NODEFAULTLIB:LIBCMT /NODEFAULTLIB:MSVCRTD"
+        LINK_FLAGS "/debug /NODEFAULTLIB:LIBCMT /SUBSYSTEM:WINDOWS"
+        LINK_FLAGS_DEBUG "/NODEFAULTLIB:\"LIBCMT;LIBCMTD;MSVCRT\""
         LINK_FLAGS_RELEASE ${release_flags}
         )
 
diff --git a/indra/newview/app_settings/logcontrol.xml b/indra/newview/app_settings/logcontrol.xml
index d7bb64ce8a7787b39abc4bf24ebfc954571cdfdb..a49ccb77b416cd0f416342aa3d6435d8dd5e1ded 100644
--- a/indra/newview/app_settings/logcontrol.xml
+++ b/indra/newview/app_settings/logcontrol.xml
@@ -40,6 +40,7 @@
 						</array>
 					<key>tags</key>
 						<array>
+              <string>ShaderLoading</string>
 						</array>
 				</map>
 			</array>
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 2cc8224fc6cde877999ac724f5c788c955b44324..523032bf6734133ffd034130b708f939c9fbfa20 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -2256,7 +2256,18 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
-    <key>DebugShowTime</key>
+  <key>DebugShowRenderMatrices</key>
+  <map>
+    <key>Comment</key>
+    <string>Display values of current view and projection matrices.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Boolean</string>
+    <key>Value</key>
+    <integer>0</integer>
+  </map>
+  <key>DebugShowTime</key>
     <map>
       <key>Comment</key>
       <string>Show depth buffer contents</string>
@@ -2635,6 +2646,17 @@
       <key>Value</key>
       <real>60.0</real>
     </map>
+    <key>FPSLogFrequency</key>
+        <map>
+        <key>Comment</key>
+            <string>Seconds between display of FPS in log (0 for never)</string>
+        <key>Persist</key>
+            <integer>1</integer>
+        <key>Type</key>
+            <string>F32</string>
+        <key>Value</key>
+            <real>10.0</real>
+        </map>
     <key>FilterItemsPerFrame</key>
     <map>
       <key>Comment</key>
@@ -6141,7 +6163,102 @@
       <key>Value</key>
       <integer>1</integer>
     </map>
-    <key>RenderBumpmapMinDistanceSquared</key>
+
+  <key>RenderShadowGaussian</key>
+  <map>
+    <key>Comment</key>
+    <string>Gaussian coefficients for the two shadow/SSAO blurring passes (z component unused).</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Vector3</string>
+    <key>Value</key>
+    <array>
+      <real>2.0</real>
+      <real>2.0</real>
+      <real>0.0</real>
+    </array>
+  </map>
+
+  <key>RenderShadowNearDist</key>
+  <map>
+    <key>Comment</key>
+    <string>Near clip plane of shadow camera (affects precision of depth shadows).</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Vector3</string>
+    <key>Value</key>
+    <array>
+      <real>256</real>
+      <real>256</real>
+      <real>256</real>
+    </array>
+  </map>
+  <key>RenderShadowClipPlanes</key>
+  <map>
+    <key>Comment</key>
+    <string>Near clip plane split distances for shadow map frusta.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Vector3</string>
+    <key>Value</key>
+    <array>
+      <real>4.0</real>
+      <real>8.0</real>
+      <real>24.0</real>
+    </array>
+  </map>
+  <key>RenderSSAOScale</key>
+  <map>
+    <key>Comment</key>
+    <string>Scaling factor for the area to sample for occluders (pixels at 1 meter away, inversely varying with distance)</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>500.0</real>
+  </map>
+  <key>RenderSSAOMaxScale</key>
+  <map>
+    <key>Comment</key>
+    <string>Maximum screen radius for sampling (pixels)</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>U32</string>
+    <key>Value</key>
+    <integer>60</integer>
+  </map>
+  <key>RenderSSAOFactor</key>
+  <map>
+    <key>Comment</key>
+    <string>Occlusion sensitivity factor for ambient occlusion (larger is more)</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>0.30</real>
+  </map>
+  <key>RenderSSAOEffect</key>
+  <map>
+    <key>Comment</key>
+    <string>Multiplier for (1) value and (2) saturation (HSV definition), for areas which are totally occluded.  Blends with original color for partly-occluded areas.  (Third component is unused.)</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Vector3</string>
+    <key>Value</key>
+    <array>
+      <real>0.40</real>
+      <real>1.00</real>
+      <real>0.00</real>
+    </array>
+  </map>
+  <key>RenderBumpmapMinDistanceSquared</key>
     <map>
       <key>Comment</key>
       <string>Maximum distance at which to render bumpmapped primitives (distance in meters, squared)</string>
@@ -6152,6 +6269,17 @@
       <key>Value</key>
       <real>100.0</real>
     </map>
+  <key>RenderNormalMapScale</key>
+  <map>
+    <key>Comment</key>
+    <string>Scaler applied to height map when generating normal maps</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>128</real>
+  </map>
     <key>RenderCubeMap</key>
     <map>
       <key>Comment</key>
@@ -6192,7 +6320,7 @@
       <key>Persist</key>
       <integer>1</integer>
       <key>Type</key>
-      <string>Boolean</string>
+      <string>Boolean</string> 
       <key>Value</key>
       <integer>0</integer>
     </map>
@@ -6207,18 +6335,129 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
-    <key>RenderDeferred</key>
-    <map>
-      <key>Comment</key>
-      <string>Use deferred rendering pipeline.</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>Boolean</string>
-      <key>Value</key>
-      <integer>0</integer>
-    </map>
-    <key>RenderDynamicLOD</key>
+  <key>RenderDelayCreation</key>
+  <map>
+    <key>Comment</key>
+    <string>Throttle creation of drawables.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Boolean</string>
+    <key>Value</key>
+    <integer>0</integer>
+  </map>
+  <key>RenderAnimateRes</key>
+  <map>
+    <key>Comment</key>
+    <string>Animate rezing prims.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Boolean</string>
+    <key>Value</key>
+    <integer>0</integer>
+  </map>
+
+  <key>RenderAnimateTrees</key>
+  <map>
+    <key>Comment</key>
+    <string>Use GL matrix ops to animate tree branches.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Boolean</string>
+    <key>Value</key>
+    <integer>0</integer>
+  </map>
+  <key>RenderDeferredAlphaSoften</key>
+  <map>
+    <key>Comment</key>
+    <string>Scalar for softening alpha surfaces (for soft particles).</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>0.75</real>
+  </map>
+  <key>RenderDeferredNoise</key>
+  <map>
+    <key>Comment</key>
+    <string>Noise scalar to hide banding in deferred render.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>4</real>
+  </map>
+  <key>RenderDeferred</key>
+  <map>
+    <key>Comment</key>
+    <string>Use deferred rendering pipeline.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Boolean</string>
+    <key>Value</key>
+    <integer>0</integer>
+  </map>
+  <key>RenderDeferredSunShadow</key>
+  <map>
+    <key>Comment</key>
+    <string>Generate shadows from the sun.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Boolean</string>
+    <key>Value</key>
+    <integer>1</integer>
+  </map>
+  <key>RenderDeferredSunWash</key>
+  <map>
+    <key>Comment</key>
+    <string>Amount local lights are washed out by sun.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>0.5</real>
+  </map>
+  <key>RenderShadowNoise</key>
+  <map>
+    <key>Comment</key>
+    <string>Magnitude of noise on shadow samples.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>-0.0001</real>
+  </map>
+  <key>RenderShadowBlurSize</key>
+  <map>
+    <key>Comment</key>
+    <string>Scale of shadow softening kernel.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>0.7</real>
+  </map>
+  <key>RenderShadowBlurSamples</key>
+  <map>
+    <key>Comment</key>
+    <string>Number of samples to take for each pass of shadow blur (value range 1-16).  Actual number of samples is value * 2 - 1.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>U32</string>
+    <key>Value</key>
+    <real>5</real>
+  </map>
+  <key>RenderDynamicLOD</key>
     <map>
       <key>Comment</key>
       <string>Dynamically adjust level of detail.</string>
@@ -6368,13 +6607,13 @@
     <key>RenderGlowMinLuminance</key>
     <map>
       <key>Comment</key>
-      <string>Min luminance intensity necessary to consider an object bright enough to automatically glow. (Gets clamped to 0 - 1.0 range)</string>
+      <string>Min luminance intensity necessary to consider an object bright enough to automatically glow.</string>
       <key>Persist</key>
       <integer>1</integer>
       <key>Type</key>
       <string>F32</string>
       <key>Value</key>
-      <real>1.0</real>
+      <real>2.5</real>
     </map>
     <key>RenderGlowResolutionPow</key>
     <map>
@@ -6534,6 +6773,17 @@
       <key>Value</key>
       <integer>4096</integer>
     </map>
+  <key>RenderMaxNodeSize</key>
+  <map>
+    <key>Comment</key>
+    <string>Maximum size of a single node's vertex data (in KB).</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>S32</string>
+    <key>Value</key>
+    <integer>4096</integer>
+  </map>
     <key>RenderMaxVBOSize</key>
     <map>
       <key>Comment</key>
@@ -6543,7 +6793,7 @@
       <key>Type</key>
       <string>S32</string>
       <key>Value</key>
-      <integer>32</integer>
+      <integer>512</integer>
     </map>
     <key>RenderName</key>
     <map>
@@ -6644,6 +6894,17 @@
       <key>Value</key>
       <integer>1</integer>
     </map>
+    <key>RenderShaderLightingMaxLevel</key>
+    <map>
+      <key>Comment</key>
+      <string>Max lighting level to use in the shader (class 3 is default, 2 is less lights, 1 is sun/moon only.  Works around shader compiler bugs on certain platforms.)</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>S32</string>
+      <key>Value</key>
+      <integer>3</integer>
+    </map>
     <key>RenderShaderLODThreshold</key>
     <map>
       <key>Comment</key>
@@ -9760,6 +10021,17 @@
       <key>Value</key>
       <integer>1</integer>
     </map>
+    <key>RenderDelayVBUpdate</key>
+    <map>
+      <key>Comment</key>
+      <string>Delay vertex buffer updates until just before rendering</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>1</integer>
+    </map>
     <key>UseStartScreen</key>
     <map>
       <key>Comment</key>
@@ -10507,7 +10779,7 @@
       <key>Type</key>
       <string>Boolean</string>
       <key>Value</key>
-      <integer>1</integer>
+      <integer>0</integer>
     </map>
     <key>WindowWidth</key>
     <map>
diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..a91e9fa15b762f22a675c3a91d80929cb922756d
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl
@@ -0,0 +1,88 @@
+/** 
+ * @file alphaF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#extension GL_ARB_texture_rectangle : enable
+
+uniform sampler2D diffuseMap;
+uniform sampler2DShadow shadowMap0;
+uniform sampler2DShadow shadowMap1;
+uniform sampler2DShadow shadowMap2;
+uniform sampler2DShadow shadowMap3;
+uniform sampler2D noiseMap;
+uniform sampler2DRect positionMap;
+
+uniform mat4 shadow_matrix[4];
+uniform vec4 shadow_clip;
+uniform vec2 screen_res;
+
+vec3 atmosLighting(vec3 light);
+vec3 scaleSoftClip(vec3 light);
+
+varying vec3 vary_ambient;
+varying vec3 vary_directional;
+varying vec3 vary_fragcoord;
+varying vec3 vary_position;
+
+uniform float alpha_soften;
+
+void main() 
+{
+	vec2 frag = vary_fragcoord.xy/vary_fragcoord.z*0.5+0.5;
+	frag *= screen_res;
+	
+	vec3 samp_pos = texture2DRect(positionMap, frag).xyz;
+	
+	float shadow = 1.0;
+	vec4 pos = vec4(vary_position, 1.0);
+	
+	if (pos.z > -shadow_clip.w)
+	{	
+		if (pos.z < -shadow_clip.z)
+		{
+			vec4 lpos = shadow_matrix[3]*pos;
+			shadow = shadow2DProj(shadowMap3, lpos).x;
+			shadow += max((pos.z+shadow_clip.z)/(shadow_clip.z-shadow_clip.w)*2.0-1.0, 0.0);
+		}
+		else if (pos.z < -shadow_clip.y)
+		{
+			vec4 lpos = shadow_matrix[2]*pos;
+			shadow = shadow2DProj(shadowMap2, lpos).x;
+		}
+		else if (pos.z < -shadow_clip.x)
+		{
+			vec4 lpos = shadow_matrix[1]*pos;
+			shadow = shadow2DProj(shadowMap1, lpos).x;
+		}
+		else
+		{
+			vec4 lpos = shadow_matrix[0]*pos;
+			shadow = shadow2DProj(shadowMap0, lpos).x;
+		}
+	}
+	
+	vec4 col = vec4(vary_ambient + vary_directional.rgb*shadow, gl_Color.a);
+	vec4 color = texture2D(diffuseMap, gl_TexCoord[0].xy) * col;
+	
+	color.rgb = atmosLighting(color.rgb);
+
+	color.rgb = scaleSoftClip(color.rgb);
+
+	if (samp_pos.z != 0.0)
+	{
+		float dist_factor = alpha_soften;
+		float a = gl_Color.a;
+		a *= a;
+		dist_factor *= 1.0/(1.0-a);
+		color.a *= min((pos.z-samp_pos.z)*dist_factor, 1.0);
+	}
+	
+	//gl_FragColor = gl_Color;
+	gl_FragColor = color;
+	//gl_FragColor = vec4(1,0,1,1);
+	
+}
+
diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..b496bd674faf079c6bb37470070f7a8e6cd13aae
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl
@@ -0,0 +1,69 @@
+/** 
+ * @file alphaV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol);
+void calcAtmospherics(vec3 inPositionEye);
+
+float calcDirectionalLight(vec3 n, vec3 l);
+float calcPointLight(vec3 v, vec3 n, vec4 lp, float la);
+
+vec3 atmosAmbient(vec3 light);
+vec3 atmosAffectDirectionalLight(float lightIntensity);
+vec3 scaleDownLight(vec3 light);
+vec3 scaleUpLight(vec3 light);
+
+varying vec3 vary_ambient;
+varying vec3 vary_directional;
+varying vec3 vary_fragcoord;
+varying vec3 vary_position;
+
+uniform float near_clip;
+
+void main()
+{
+	//transform vertex
+	gl_Position = ftransform(); 
+	
+	gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
+	
+	vec4 pos = (gl_ModelViewMatrix * gl_Vertex);
+	vec3 norm = normalize(gl_NormalMatrix * gl_Normal);
+	vary_position = pos.xyz;
+	
+	calcAtmospherics(pos.xyz);
+
+	//vec4 color = calcLighting(pos.xyz, norm, gl_Color, vec4(0.));
+	vec4 col;
+	col.a = gl_Color.a;
+	
+	// Add windlight lights
+	col.rgb = atmosAmbient(vec3(0.));
+	col.rgb = scaleUpLight(col.rgb);
+
+	// Collect normal lights (need to be divided by two, as we later multiply by 2)
+	col.rgb += gl_LightSource[2].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[2].position, gl_LightSource[2].linearAttenuation);
+	col.rgb += gl_LightSource[3].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[3].position, gl_LightSource[3].linearAttenuation);
+	col.rgb += gl_LightSource[4].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[4].position, gl_LightSource[4].linearAttenuation);
+	col.rgb += gl_LightSource[5].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[5].position, gl_LightSource[5].linearAttenuation);
+ 	col.rgb += gl_LightSource[6].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[6].position, gl_LightSource[6].linearAttenuation);
+ 	col.rgb += gl_LightSource[7].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[7].position, gl_LightSource[7].linearAttenuation);
+	col.rgb += gl_LightSource[1].diffuse.rgb*calcDirectionalLight(norm, gl_LightSource[1].position.xyz);
+	col.rgb = scaleDownLight(col.rgb);
+	
+	vary_ambient = col.rgb*gl_Color.rgb;
+	vary_directional.rgb = gl_Color.rgb*atmosAffectDirectionalLight(max(calcDirectionalLight(norm, gl_LightSource[0].position.xyz), (1.0-gl_Color.a)*(1.0-gl_Color.a)));
+	
+	col.rgb = min(col.rgb*gl_Color.rgb, 1.0);
+	
+	gl_FrontColor = col;
+
+	gl_FogFragCoord = pos.z;
+	
+	pos = gl_ModelViewProjectionMatrix * gl_Vertex;
+	vary_fragcoord.xyz = pos.xyz + vec3(0,0,near_clip);
+	
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaF.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaF.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..6c94f5c5a7aedb758437767ca275af916cff9c4f
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaF.glsl
@@ -0,0 +1,68 @@
+/** 
+ * @file avatarAlphaF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+uniform sampler2D diffuseMap;
+uniform sampler2DShadow shadowMap0;
+uniform sampler2DShadow shadowMap1;
+uniform sampler2DShadow shadowMap2;
+uniform sampler2DShadow shadowMap3;
+uniform sampler2D noiseMap;
+
+uniform mat4 shadow_matrix[4];
+uniform vec4 shadow_clip;
+
+vec3 atmosLighting(vec3 light);
+vec3 scaleSoftClip(vec3 light);
+
+varying vec3 vary_ambient;
+varying vec3 vary_directional;
+varying vec4 vary_position;
+varying vec3 vary_normal;
+
+void main() 
+{
+	float shadow = 1.0;
+	vec4 pos = vary_position;
+	vec3 norm = normalize(vary_normal);
+	
+	vec3 nz = texture2D(noiseMap, gl_FragCoord.xy/128.0).xyz;
+
+	if (pos.z > -shadow_clip.w)
+	{	
+		
+		if (pos.z < -shadow_clip.z)
+		{
+			vec4 lpos = shadow_matrix[3]*pos;
+			shadow = shadow2DProj(shadowMap3, lpos).x;
+		}
+		else if (pos.z < -shadow_clip.y)
+		{
+			vec4 lpos = shadow_matrix[2]*pos;
+			shadow = shadow2DProj(shadowMap2, lpos).x;
+		}
+		else if (pos.z < -shadow_clip.x)
+		{
+			vec4 lpos = shadow_matrix[1]*pos;
+			shadow = shadow2DProj(shadowMap1, lpos).x;
+		}
+		else
+		{
+			vec4 lpos = shadow_matrix[0]*pos;
+			shadow = shadow2DProj(shadowMap0, lpos).x;
+		}
+	}
+	
+	
+	vec4 col = vec4(vary_ambient + vary_directional*shadow, gl_Color.a);	
+	vec4 color = texture2D(diffuseMap, gl_TexCoord[0].xy) * col;
+	
+	color.rgb = atmosLighting(color.rgb);
+
+	color.rgb = scaleSoftClip(color.rgb);
+
+	gl_FragColor = color;
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaV.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaV.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..c1988d3c783e4f9ddff80957ec8abfe5bf4b8a6a
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaV.glsl
@@ -0,0 +1,78 @@
+/** 
+ * @file avatarAlphaV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol);
+mat4 getSkinnedTransform();
+void calcAtmospherics(vec3 inPositionEye);
+
+float calcDirectionalLight(vec3 n, vec3 l);
+float calcPointLight(vec3 v, vec3 n, vec4 lp, float la);
+
+vec3 atmosAmbient(vec3 light);
+vec3 atmosAffectDirectionalLight(float lightIntensity);
+vec3 scaleDownLight(vec3 light);
+vec3 scaleUpLight(vec3 light);
+
+varying vec4 vary_position;
+varying vec3 vary_ambient;
+varying vec3 vary_directional;
+varying vec3 vary_normal;
+
+void main()
+{
+	gl_TexCoord[0] = gl_MultiTexCoord0;
+				
+	vec4 pos;
+	vec3 norm;
+	
+	mat4 trans = getSkinnedTransform();
+	pos.x = dot(trans[0], gl_Vertex);
+	pos.y = dot(trans[1], gl_Vertex);
+	pos.z = dot(trans[2], gl_Vertex);
+	pos.w = 1.0;
+	
+	norm.x = dot(trans[0].xyz, gl_Normal);
+	norm.y = dot(trans[1].xyz, gl_Normal);
+	norm.z = dot(trans[2].xyz, gl_Normal);
+	norm = normalize(norm);
+		
+	gl_Position = gl_ProjectionMatrix * pos;
+	vary_position = pos;
+	vary_normal = norm;	
+	
+	calcAtmospherics(pos.xyz);
+
+	//vec4 color = calcLighting(pos.xyz, norm, gl_Color, vec4(0.));
+	vec4 col;
+	col.a = gl_Color.a;
+	
+	// Add windlight lights
+	col.rgb = atmosAmbient(vec3(0.));
+	col.rgb = scaleUpLight(col.rgb);
+
+	// Collect normal lights (need to be divided by two, as we later multiply by 2)
+	col.rgb += gl_LightSource[2].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[2].position, gl_LightSource[2].linearAttenuation);
+	col.rgb += gl_LightSource[3].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[3].position, gl_LightSource[3].linearAttenuation);
+	col.rgb += gl_LightSource[4].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[4].position, gl_LightSource[4].linearAttenuation);
+	col.rgb += gl_LightSource[5].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[5].position, gl_LightSource[5].linearAttenuation);
+ 	col.rgb += gl_LightSource[6].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[6].position, gl_LightSource[6].linearAttenuation);
+ 	col.rgb += gl_LightSource[7].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[7].position, gl_LightSource[7].linearAttenuation);
+	col.rgb += gl_LightSource[1].diffuse.rgb*calcDirectionalLight(norm, gl_LightSource[1].position.xyz);
+	col.rgb = scaleDownLight(col.rgb);
+	
+	vary_ambient = col.rgb*gl_Color.rgb;
+	vary_directional = gl_Color.rgb*atmosAffectDirectionalLight(max(calcDirectionalLight(norm, gl_LightSource[0].position.xyz), (1.0-gl_Color.a)*(1.0-gl_Color.a)));
+	
+	col.rgb = min(col.rgb*gl_Color.rgb, 1.0);
+	
+	gl_FrontColor = col;
+
+	gl_FogFragCoord = pos.z;
+
+}
+
+
diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarF.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarF.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..58aa5a9cb5dd7448b40067a779400f6468db20bb
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/avatarF.glsl
@@ -0,0 +1,20 @@
+/** 
+ * @file avatarF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+uniform sampler2D diffuseMap;
+
+varying vec3 vary_normal;
+varying vec4 vary_position;
+
+void main() 
+{
+	gl_FragData[0] = gl_Color * texture2D(diffuseMap, gl_TexCoord[0].xy);
+	gl_FragData[1] = vec4(0,0,0,0);
+	gl_FragData[2] = vec4(normalize(vary_normal), 0.0);
+	gl_FragData[3] = vary_position;
+}
+
diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarShadowF.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarShadowF.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..27c09db92200ff96cf73f8193e315d11bc92b251
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/avatarShadowF.glsl
@@ -0,0 +1,15 @@
+/** 
+ * @file avatarShadowF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+uniform sampler2D diffuseMap;
+
+
+void main() 
+{
+	gl_FragColor = vec4(1,1,1,gl_Color.a * texture2D(diffuseMap, gl_TexCoord[0].xy));
+}
+
diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarShadowV.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarShadowV.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..14da6b1ad45eed70f0eec005a4d9e82a634c9fa1
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/avatarShadowV.glsl
@@ -0,0 +1,38 @@
+/** 
+ * @file avatarShadowV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+mat4 getSkinnedTransform();
+
+attribute vec4 weight;
+
+void main()
+{
+	gl_TexCoord[0] = gl_MultiTexCoord0;
+				
+	vec4 pos;
+	vec3 norm;
+	
+	mat4 trans = getSkinnedTransform();
+	pos.x = dot(trans[0], gl_Vertex);
+	pos.y = dot(trans[1], gl_Vertex);
+	pos.z = dot(trans[2], gl_Vertex);
+	pos.w = 1.0;
+	
+	norm.x = dot(trans[0].xyz, gl_Normal);
+	norm.y = dot(trans[1].xyz, gl_Normal);
+	norm.z = dot(trans[2].xyz, gl_Normal);
+	norm = normalize(norm);
+	
+	pos = gl_ProjectionMatrix * pos;
+	//smash geometry against near clip plane
+	pos.z = max(pos.z, -1.0);
+	gl_Position = pos;
+	
+	gl_FrontColor = gl_Color;
+}
+
+
diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarV.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarV.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..12a7ff7f2978c333416ea44d46fa4d25087c3dcb
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/avatarV.glsl
@@ -0,0 +1,42 @@
+/** 
+ * @file avatarV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+mat4 getSkinnedTransform();
+
+attribute vec4 weight;
+
+varying vec3 vary_normal;
+varying vec4 vary_position;
+
+void main()
+{
+	gl_TexCoord[0] = gl_MultiTexCoord0;
+				
+	vec4 pos;
+	vec3 norm;
+	
+	mat4 trans = getSkinnedTransform();
+	pos.x = dot(trans[0], gl_Vertex);
+	pos.y = dot(trans[1], gl_Vertex);
+	pos.z = dot(trans[2], gl_Vertex);
+	pos.w = 1.0;
+	
+	norm.x = dot(trans[0].xyz, gl_Normal);
+	norm.y = dot(trans[1].xyz, gl_Normal);
+	norm.z = dot(trans[2].xyz, gl_Normal);
+	norm = normalize(norm);
+	
+	vary_position = pos;
+	vary_normal = norm;
+	
+	gl_Position = gl_ProjectionMatrix * pos;
+	//gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;	
+	
+	gl_FrontColor = gl_Color;
+}
+
+
diff --git a/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..3c6700a871f4581508c2b503d7e8a0840f457ab5
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl
@@ -0,0 +1,48 @@
+/** 
+ * @file blurLightF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#extension GL_ARB_texture_rectangle : enable
+
+uniform sampler2DRect positionMap;
+uniform sampler2DRect normalMap;
+uniform sampler2DRect lightMap;
+
+uniform float blur_size;
+uniform vec2 delta;
+uniform vec3 kern[32];
+uniform int kern_length;
+uniform float kern_scale;
+
+varying vec2 vary_fragcoord;
+
+void main() 
+{
+	vec3 norm = texture2DRect(normalMap, vary_fragcoord.xy).xyz;
+	vec3 pos = texture2DRect(positionMap, vary_fragcoord.xy).xyz;
+	vec2 ccol = texture2DRect(lightMap, vary_fragcoord.xy).rg;
+	
+	vec2 dlt = kern_scale * delta / (1.0+norm.xy*norm.xy);
+	
+	vec2 defined_weight = kern[0].xy; // special case the first (centre) sample's weight in the blur; we have to sample it anyway so we get it for 'free'
+	vec2 col = defined_weight * ccol;
+	
+	for (int i = 1; i < kern_length; i++)
+	{
+		vec2 tc = vary_fragcoord.xy + kern[i].z*dlt;
+	        vec3 samppos = texture2DRect(positionMap, tc).xyz;
+		float d = dot(norm.xyz, samppos.xyz-pos.xyz);// dist from plane
+		if (d*d <= 0.003)
+		{
+			col += texture2DRect(lightMap, tc).rg*kern[i].xy;
+			defined_weight += kern[i].xy;
+		}
+	}
+
+	col /= defined_weight;
+
+	gl_FragColor = vec4(col.r, col.g, 0.0, 1.0);
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/blurLightV.glsl b/indra/newview/app_settings/shaders/class1/deferred/blurLightV.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..b7f07e5702050e9bff2b848056e9b834881c49e8
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/blurLightV.glsl
@@ -0,0 +1,17 @@
+/** 
+ * @file blurLightF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+varying vec2 vary_fragcoord;
+uniform vec2 screen_res;
+
+void main()
+{
+	//transform vertex
+	gl_Position = ftransform(); 
+	vec4 pos = gl_ModelViewProjectionMatrix * gl_Vertex;
+	vary_fragcoord = (pos.xy*0.5+0.5)*screen_res;
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl b/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..a8712bc8cc73e7220fcbe112487dd60abe1a1328
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl
@@ -0,0 +1,29 @@
+/** 
+ * @file bumpF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+uniform sampler2D diffuseMap;
+uniform sampler2D bumpMap;
+
+varying vec3 vary_mat0;
+varying vec3 vary_mat1;
+varying vec3 vary_mat2;
+varying vec4 vary_position;
+
+void main() 
+{
+	vec3 col = texture2D(diffuseMap, gl_TexCoord[0].xy).rgb;
+	vec3 norm = texture2D(bumpMap, gl_TexCoord[0].xy).rgb * 2.0 - 1.0;
+
+	vec3 tnorm = vec3(dot(norm,vary_mat0),
+					  dot(norm,vary_mat1),
+					  dot(norm,vary_mat2));
+						
+	gl_FragData[0].rgb = gl_Color.rgb*col;
+	gl_FragData[1] = vec4(col*(gl_Color.a*1.5), gl_Color.a);
+	gl_FragData[2] = vec4(normalize(tnorm), 0.0);
+	gl_FragData[3] = vary_position;
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/bumpV.glsl b/indra/newview/app_settings/shaders/class1/deferred/bumpV.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..ba180922cc1487c648a1060b612d705f76c781cf
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/bumpV.glsl
@@ -0,0 +1,30 @@
+/** 
+ * @file bumpV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+varying vec3 vary_mat0;
+varying vec3 vary_mat1;
+varying vec3 vary_mat2;
+varying vec4 vary_position;
+
+void main()
+{
+	//transform vertex
+	gl_Position = ftransform(); 
+	gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
+	
+	vary_position = gl_ModelViewMatrix * gl_Vertex;
+	
+	vec3 n = normalize(gl_NormalMatrix * gl_Normal);
+	vec3 b = normalize(gl_NormalMatrix * gl_MultiTexCoord2.xyz);
+	vec3 t = cross(b, n);
+	
+	vary_mat0 = vec3(t.x, b.x, n.x);
+	vary_mat1 = vec3(t.y, b.y, n.y);
+	vary_mat2 = vec3(t.z, b.z, n.z);
+	
+	gl_FrontColor = gl_Color;
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl
index 14e6361f83fd6e909ff00a7bed85318f95a4f21a..f2ba2df69a0d577731cbd0f35d68ada52dbff2b5 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl
@@ -8,9 +8,13 @@
 uniform sampler2D diffuseMap;
 
 varying vec3 vary_normal;
+varying vec4 vary_position;
 
 void main() 
 {
-	gl_FragColor = gl_Color * texture2D(diffuseMap, gl_TexCoord[0].xy);
-	gl_FragColor.rgb = vary_normal*0.5+0.5;
+	vec3 col = texture2D(diffuseMap, gl_TexCoord[0].xy).rgb;
+	gl_FragData[0] = vec4(gl_Color.rgb*col, 1.0);
+	gl_FragData[1] = vec4(col*(gl_Color.a*1.5), gl_Color.a);
+	gl_FragData[2] = vec4(normalize(vary_normal), 0.0);
+	gl_FragData[3] = vary_position;
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl
index 8e9069368ae5ede92ebb149ade87a6619cc1a0d8..3413a7f9d6ec1e581b2338f3d0b8d27daa83697b 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl
@@ -6,7 +6,7 @@
  */
 
 varying vec3 vary_normal;
-varying vec3 vary_position;
+varying vec4 vary_position;
 
 void main()
 {
@@ -14,7 +14,7 @@ void main()
 	gl_Position = ftransform(); 
 	gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
 	
-	vary_position = (gl_ModelViewMatrix * gl_Vertex).xyz;
+	vary_position = gl_ModelViewMatrix * gl_Vertex;
 	
 	vary_normal = normalize(gl_NormalMatrix * gl_Normal);
 
diff --git a/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..2a811c58971881956b008460667c8e46163fda06
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl
@@ -0,0 +1,63 @@
+/** 
+ * @file fullbrightF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#extension GL_ARB_texture_rectangle : enable
+
+uniform sampler2D diffuseMap;
+uniform sampler2DShadow shadowMap0;
+uniform sampler2DShadow shadowMap1;
+uniform sampler2DShadow shadowMap2;
+uniform sampler2DShadow shadowMap3;
+uniform sampler2D noiseMap;
+uniform sampler2DRect positionMap;
+
+uniform mat4 shadow_matrix[4];
+uniform vec4 shadow_clip;
+uniform vec2 screen_res;
+
+vec3 fullbrightAtmosTransport(vec3 light);
+vec3 fullbrightScaleSoftClip(vec3 light);
+
+varying vec3 vary_ambient;
+varying vec3 vary_directional;
+varying vec4 vary_position;
+varying vec3 vary_normal;
+varying vec3 vary_fragcoord;
+
+uniform float alpha_soften;
+
+void main() 
+{
+	vec2 frag = vary_fragcoord.xy/vary_fragcoord.z*0.5+0.5;
+	frag *= screen_res;
+	
+	vec3 samp_pos = texture2DRect(positionMap, frag).xyz;
+	
+	float shadow = 1.0;
+	vec4 pos = vary_position;
+
+	vec4 color = texture2D(diffuseMap, gl_TexCoord[0].xy)*gl_Color;
+	
+	color.rgb = fullbrightAtmosTransport(color.rgb);
+
+	color.rgb = fullbrightScaleSoftClip(color.rgb);
+
+	if (samp_pos.z != 0.0)
+	{
+		float dist_factor = alpha_soften;
+		float a = gl_Color.a;
+		a *= a;
+		dist_factor *= 1.0/(1.0-a);
+		color.a *= min((pos.z-samp_pos.z)*dist_factor, 1.0);
+	}
+
+	//gl_FragColor = gl_Color;
+	gl_FragColor = color;
+	//gl_FragColor = vec4(1,0,1,1);
+	
+}
+
diff --git a/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl b/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..6381a1ced8cbaa7e7d7794590c3f9cae4544dd89
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl
@@ -0,0 +1,41 @@
+/** 
+ * @file fullbrightV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+void calcAtmospherics(vec3 inPositionEye);
+
+vec3 atmosAmbient(vec3 light);
+vec3 atmosAffectDirectionalLight(float lightIntensity);
+vec3 scaleDownLight(vec3 light);
+vec3 scaleUpLight(vec3 light);
+
+varying vec4 vary_position;
+varying vec3 vary_ambient;
+varying vec3 vary_directional;
+varying vec3 vary_normal;
+varying vec3 vary_fragcoord;
+uniform float near_clip;
+
+void main()
+{
+	//transform vertex
+	gl_Position = ftransform(); 
+	
+	gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
+	
+	vec4 pos = (gl_ModelViewMatrix * gl_Vertex);
+	vary_position = pos;
+		
+	calcAtmospherics(pos.xyz);
+	
+	gl_FrontColor = gl_Color;
+
+	gl_FogFragCoord = pos.z;
+	
+	pos = gl_ModelViewProjectionMatrix * gl_Vertex;
+	vary_fragcoord.xyz = pos.xyz + vec3(0,0,near_clip);
+	
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl b/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..20a3f3df5b59bb09c402f124ec8b59fab81f0ae7
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl
@@ -0,0 +1,20 @@
+/** 
+ * @file impostorF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+uniform sampler2D diffuseMap;
+uniform sampler2D normalMap;
+uniform sampler2D specularMap;
+
+varying vec4 vary_position;
+
+void main() 
+{
+	gl_FragData[0] = texture2D(diffuseMap, gl_TexCoord[0].xy);
+	gl_FragData[1] = texture2D(specularMap, gl_TexCoord[0].xy);
+	gl_FragData[2] = vec4(texture2D(normalMap, gl_TexCoord[0].xy).xyz, vary_position.z);
+	gl_FragData[3] = vary_position;
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/impostorV.glsl b/indra/newview/app_settings/shaders/class1/deferred/impostorV.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..9c5ae315415f73987a19aed2d3adcb7ff8343df5
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/impostorV.glsl
@@ -0,0 +1,19 @@
+/** 
+ * @file impostorV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+varying vec4 vary_position;
+
+void main()
+{
+	//transform vertex
+	gl_Position = ftransform(); 
+	gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
+	
+	vary_position = gl_ModelViewMatrix * gl_Vertex;
+
+	gl_FrontColor = gl_Color;
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..3689d12840a9be90537686d4a054807231997731
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl
@@ -0,0 +1,83 @@
+/** 
+ * @file multiPointLightF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#extension GL_ARB_texture_rectangle : enable
+
+uniform sampler2DRect diffuseRect;
+uniform sampler2DRect specularRect;
+uniform sampler2DRect positionMap;
+uniform sampler2DRect normalMap;
+uniform samplerCube environmentMap;
+uniform sampler2DRect lightMap;
+uniform sampler2D noiseMap;
+
+uniform vec3 env_mat[3];
+uniform float sun_wash;
+
+uniform int light_count;
+
+uniform vec4 light[16];
+uniform vec4 light_col[16];
+
+varying vec3 vary_fragcoord;
+uniform vec2 screen_res;
+
+void main() 
+{
+	vec2 frag = (vary_fragcoord.xy*0.5+0.5)*screen_res;
+	vec3 pos = texture2DRect(positionMap, frag.xy).xyz;
+	vec3 norm = normalize(texture2DRect(normalMap, frag.xy).xyz);
+	vec4 spec = texture2DRect(specularRect, frag.xy);
+	vec3 diff = texture2DRect(diffuseRect, frag.xy).rgb;
+	float noise = texture2D(noiseMap, frag.xy/128.0).b;
+	vec3 out_col = vec3(0,0,0);
+	
+	for (int i = 0; i < light_count; ++i)
+	{
+		vec3 lv = light[i].xyz-pos;
+		float dist2 = dot(lv,lv);
+		if (dist2 > light[i].w)
+		{
+			continue;
+		}
+		
+		float da = dot(norm, lv);
+		if (da < 0.0)
+		{
+			continue;
+		}
+				
+		lv = normalize(lv);
+		da = dot(norm, lv);
+				
+		float fa = light_col[i].a+1.0;
+		float dist_atten = clamp(1.0-(dist2-light[i].w*(1.0-fa))/(light[i].w*fa), 0.0, 1.0);
+		dist_atten *= noise;
+
+		float lit = da * dist_atten;
+		
+		vec3 col = light_col[i].rgb*lit*diff;
+		
+		if (spec.a > 0.0)
+		{
+			vec3 ref = reflect(normalize(pos), norm);
+			float sa = dot(ref,lv);
+			sa = max(sa, 0.0);
+			sa = pow(sa, 128.0 * spec.a*spec.a/dist_atten)*min(dist_atten*4.0, 1.0);
+			sa *= noise;
+			col += da*sa*light_col[i].rgb*spec.rgb;
+		}
+		
+		out_col += col;	
+	}
+	
+	//attenuate point light contribution by SSAO component
+	out_col *= texture2DRect(lightMap, frag.xy).g;
+	
+	gl_FragColor.rgb = out_col;
+	gl_FragColor.a = 0.0;
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..52bad1f34cc3c792b6ba6b5b5d2fd963f405c1b0
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl
@@ -0,0 +1,75 @@
+/** 
+ * @file pointLightF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#extension GL_ARB_texture_rectangle : enable
+
+uniform sampler2DRect diffuseRect;
+uniform sampler2DRect specularRect;
+uniform sampler2DRect positionMap;
+uniform sampler2DRect normalMap;
+uniform samplerCube environmentMap;
+uniform sampler2DRect lightMap;
+uniform sampler2D noiseMap;
+
+uniform vec3 env_mat[3];
+uniform float sun_wash;
+
+varying vec4 vary_light;
+
+varying vec3 vary_fragcoord;
+uniform vec2 screen_res;
+
+void main() 
+{
+	vec2 frag = vary_fragcoord.xy/vary_fragcoord.z*0.5+0.5;
+	frag *= screen_res;	
+	vec3 pos = texture2DRect(positionMap, frag).xyz;
+	vec3 lv = vary_light.xyz-pos;
+	float dist2 = dot(lv,lv);
+	if (dist2 > vary_light.w)
+	{
+		discard;
+	}
+	
+	vec3 norm = texture2DRect(normalMap, frag).xyz;
+	float da = dot(norm, lv);
+	if (da < 0.0)
+	{
+		discard;
+	}
+	
+	norm = normalize(norm);
+	lv = normalize(lv);
+	da = dot(norm, lv);
+	
+	float noise = texture2D(noiseMap, frag/128.0).b;
+	
+	vec3 col = texture2DRect(diffuseRect, frag).rgb;
+	float fa = gl_Color.a+1.0;
+	float dist_atten = clamp(1.0-(dist2-vary_light.w*(1.0-fa))/(vary_light.w*fa), 0.0, 1.0);
+	float lit = da * dist_atten * noise;
+	
+	col = gl_Color.rgb*lit*col;
+
+	vec4 spec = texture2DRect(specularRect, frag);
+	if (spec.a > 0.0)
+	{
+		vec3 ref = reflect(normalize(pos), norm);
+		float sa = dot(ref,lv);
+		sa = max(sa, 0.0);
+		sa = pow(sa, 128.0 * spec.a*spec.a/dist_atten)*min(dist_atten*4.0, 1.0);
+		sa *= noise;
+		col += da*sa*gl_Color.rgb*spec.rgb;
+	}
+	
+	//attenuate point light contribution by SSAO component
+	col *= texture2DRect(lightMap, frag.xy).g;
+	
+
+	gl_FragColor.rgb = col;	
+	gl_FragColor.a = 0.0;
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/pointLightV.glsl b/indra/newview/app_settings/shaders/class1/deferred/pointLightV.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..a4edb88259fdf6de355b082c8b17af35c11b7282
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/pointLightV.glsl
@@ -0,0 +1,28 @@
+/** 
+ * @file pointLightF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+varying vec4 vary_light;
+varying vec3 vary_fragcoord;
+
+uniform vec2 screen_res;
+uniform float near_clip;
+
+void main()
+{
+	//transform vertex
+	gl_Position = ftransform(); 
+
+	vec4 pos = gl_ModelViewProjectionMatrix * gl_Vertex;
+	vary_fragcoord.xyz = pos.xyz + vec3(0,0,near_clip);
+		
+	vec4 tex = gl_MultiTexCoord0;
+	tex.w = 1.0;
+	
+	vary_light = gl_MultiTexCoord0;
+		
+	gl_FrontColor = gl_Color;
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/shadowF.glsl b/indra/newview/app_settings/shaders/class1/deferred/shadowF.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..b3758c3638ec06809aee7bd3ea4aa02344b60d01
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/shadowF.glsl
@@ -0,0 +1,14 @@
+/** 
+ * @file shadowF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+uniform sampler2D diffuseMap;
+
+
+void main() 
+{
+	gl_FragColor = vec4(1,1,1,texture2D(diffuseMap, gl_TexCoord[0].xy).a * gl_Color.a);
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/shadowV.glsl b/indra/newview/app_settings/shaders/class1/deferred/shadowV.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..aae1beeae35df06044fe1bdce66d3667add0cce3
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/shadowV.glsl
@@ -0,0 +1,17 @@
+/** 
+ * @file shadowV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+void main()
+{
+	//transform vertex
+	vec4 pos = gl_ModelViewProjectionMatrix*gl_Vertex;
+	//smash geometry against the near clip plane (great for ortho projections)
+	pos.z = max(pos.z, -1.0);
+	gl_Position = pos;
+	gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
+	gl_FrontColor = gl_Color;
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..d5671a6ce4448b03356a6b44de20196ebe9b6cc0
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl
@@ -0,0 +1,279 @@
+/** 
+ * @file softenLightF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#extension GL_ARB_texture_rectangle : enable
+
+uniform sampler2DRect diffuseRect;
+uniform sampler2DRect specularRect;
+uniform sampler2DRect positionMap;
+uniform sampler2DRect normalMap;
+uniform sampler2DRect depthMap;
+uniform sampler2DRect lightMap;
+uniform sampler2D	  noiseMap;
+uniform samplerCube environmentMap;
+
+uniform float blur_size;
+uniform float blur_fidelity;
+
+// Inputs
+uniform vec4 morphFactor;
+uniform vec3 camPosLocal;
+//uniform vec4 camPosWorld;
+uniform vec4 gamma;
+uniform vec4 lightnorm;
+uniform vec4 sunlight_color;
+uniform vec4 ambient;
+uniform vec4 blue_horizon;
+uniform vec4 blue_density;
+uniform vec4 haze_horizon;
+uniform vec4 haze_density;
+uniform vec4 cloud_shadow;
+uniform vec4 density_multiplier;
+uniform vec4 distance_multiplier;
+uniform vec4 max_y;
+uniform vec4 glow;
+uniform float scene_light_strength;
+uniform vec3 env_mat[3];
+uniform mat4 shadow_matrix[3];
+uniform vec4 shadow_clip;
+uniform mat3 ssao_effect_mat;
+
+varying vec4 vary_light;
+varying vec2 vary_fragcoord;
+
+vec3 vary_PositionEye;
+
+vec3 vary_SunlitColor;
+vec3 vary_AmblitColor;
+vec3 vary_AdditiveColor;
+vec3 vary_AtmosAttenuation;
+
+vec3 getPositionEye()
+{
+	return vary_PositionEye;
+}
+vec3 getSunlitColor()
+{
+	return vary_SunlitColor;
+}
+vec3 getAmblitColor()
+{
+	return vary_AmblitColor;
+}
+vec3 getAdditiveColor()
+{
+	return vary_AdditiveColor;
+}
+vec3 getAtmosAttenuation()
+{
+	return vary_AtmosAttenuation;
+}
+
+
+void setPositionEye(vec3 v)
+{
+	vary_PositionEye = v;
+}
+
+void setSunlitColor(vec3 v)
+{
+	vary_SunlitColor = v;
+}
+
+void setAmblitColor(vec3 v)
+{
+	vary_AmblitColor = v;
+}
+
+void setAdditiveColor(vec3 v)
+{
+	vary_AdditiveColor = v;
+}
+
+void setAtmosAttenuation(vec3 v)
+{
+	vary_AtmosAttenuation = v;
+}
+
+void calcAtmospherics(vec3 inPositionEye, float ambFactor) {
+
+	vec3 P = inPositionEye;
+	setPositionEye(P);
+	
+	//(TERRAIN) limit altitude
+	if (P.y > max_y.x) P *= (max_y.x / P.y);
+	if (P.y < -max_y.x) P *= (-max_y.x / P.y);
+
+	vec3 tmpLightnorm = lightnorm.xyz;
+
+	vec3 Pn = normalize(P);
+	float Plen = length(P);
+
+	vec4 temp1 = vec4(0);
+	vec3 temp2 = vec3(0);
+	vec4 blue_weight;
+	vec4 haze_weight;
+	vec4 sunlight = sunlight_color;
+	vec4 light_atten;
+
+	//sunlight attenuation effect (hue and brightness) due to atmosphere
+	//this is used later for sunlight modulation at various altitudes
+	light_atten = (blue_density * 1.0 + vec4(haze_density.r) * 0.25) * (density_multiplier.x * max_y.x);
+		//I had thought blue_density and haze_density should have equal weighting,
+		//but attenuation due to haze_density tends to seem too strong
+
+	temp1 = blue_density + vec4(haze_density.r);
+	blue_weight = blue_density / temp1;
+	haze_weight = vec4(haze_density.r) / temp1;
+
+	//(TERRAIN) compute sunlight from lightnorm only (for short rays like terrain)
+	temp2.y = max(0.0, tmpLightnorm.y);
+	temp2.y = 1. / temp2.y;
+	sunlight *= exp( - light_atten * temp2.y);
+
+	// main atmospheric scattering line integral
+	temp2.z = Plen * density_multiplier.x;
+
+	// Transparency (-> temp1)
+	// ATI Bugfix -- can't store temp1*temp2.z*distance_multiplier.x in a variable because the ati
+	// compiler gets confused.
+	temp1 = exp(-temp1 * temp2.z * distance_multiplier.x);
+
+	//final atmosphere attenuation factor
+	setAtmosAttenuation(temp1.rgb);
+	
+	//compute haze glow
+	//(can use temp2.x as temp because we haven't used it yet)
+	temp2.x = dot(Pn, tmpLightnorm.xyz);
+	temp2.x = 1. - temp2.x;
+		//temp2.x is 0 at the sun and increases away from sun
+	temp2.x = max(temp2.x, .03);	//was glow.y
+		//set a minimum "angle" (smaller glow.y allows tighter, brighter hotspot)
+	temp2.x *= glow.x;
+		//higher glow.x gives dimmer glow (because next step is 1 / "angle")
+	temp2.x = pow(temp2.x, glow.z);
+		//glow.z should be negative, so we're doing a sort of (1 / "angle") function
+
+	//add "minimum anti-solar illumination"
+	temp2.x += .25;
+	
+	//increase ambient when there are more clouds
+	vec4 tmpAmbient = ambient + (vec4(1.) - ambient) * cloud_shadow.x * 0.5;
+	
+	/*  decrease value and saturation (that in HSV, not HSL) for occluded areas
+	 * // for HSV color/geometry used here, see http://gimp-savvy.com/BOOK/index.html?node52.html
+	 * // The following line of code performs the equivalent of:
+	 * float ambAlpha = tmpAmbient.a;
+	 * float ambValue = dot(vec3(tmpAmbient), vec3(0.577)); // projection onto <1/rt(3), 1/rt(3), 1/rt(3)>, the neutral white-black axis
+	 * vec3 ambHueSat = vec3(tmpAmbient) - vec3(ambValue);
+	 * tmpAmbient = vec4(RenderSSAOEffect.valueFactor * vec3(ambValue) + RenderSSAOEffect.saturationFactor *(1.0 - ambFactor) * ambHueSat, ambAlpha);
+	 */
+	tmpAmbient = vec4(mix(ssao_effect_mat * tmpAmbient.rgb, tmpAmbient.rgb, ambFactor), tmpAmbient.a);
+
+	//haze color
+	setAdditiveColor(
+		vec3(blue_horizon * blue_weight * (sunlight*(1.-cloud_shadow.x) + tmpAmbient)
+	  + (haze_horizon.r * haze_weight) * (sunlight*(1.-cloud_shadow.x) * temp2.x
+		  + tmpAmbient)));
+
+	//brightness of surface both sunlight and ambient
+	setSunlitColor(vec3(sunlight * .5));
+	setAmblitColor(vec3(tmpAmbient * .25));
+	setAdditiveColor(getAdditiveColor() * vec3(1.0 - temp1));
+}
+
+vec3 atmosLighting(vec3 light)
+{
+	light *= getAtmosAttenuation().r;
+	light += getAdditiveColor();
+	return (2.0 * light);
+}
+
+vec3 atmosTransport(vec3 light) {
+	light *= getAtmosAttenuation().r;
+	light += getAdditiveColor() * 2.0;
+	return light;
+}
+vec3 atmosGetDiffuseSunlightColor()
+{
+	return getSunlitColor();
+}
+
+vec3 scaleDownLight(vec3 light)
+{
+	return (light / scene_light_strength );
+}
+
+vec3 scaleUpLight(vec3 light)
+{
+	return (light * scene_light_strength);
+}
+
+vec3 atmosAmbient(vec3 light)
+{
+	return getAmblitColor() + light / 2.0;
+}
+
+vec3 atmosAffectDirectionalLight(float lightIntensity)
+{
+	return getSunlitColor() * lightIntensity;
+}
+
+vec3 scaleSoftClip(vec3 light)
+{
+	//soft clip effect:
+	light = 1. - clamp(light, vec3(0.), vec3(1.));
+	light = 1. - pow(light, gamma.xxx);
+
+	return light;
+}
+
+void main() 
+{
+	vec2 tc = vary_fragcoord.xy;
+	vec3 pos = texture2DRect(positionMap, tc).xyz;
+	vec3 norm = texture2DRect(normalMap, tc).xyz;
+	vec3 nz = texture2D(noiseMap, vary_fragcoord.xy/128.0).xyz;
+	
+	float da = max(dot(norm.xyz, vary_light.xyz), 0.0);
+	
+	vec4 diffuse = vec4(texture2DRect(diffuseRect, tc).rgb, 1.0);
+	vec4 spec = texture2DRect(specularRect, vary_fragcoord.xy);
+	
+	vec2 scol_ambocc = texture2DRect(lightMap, vary_fragcoord.xy).rg;
+	float scol = scol_ambocc.r; 
+	float ambocc = scol_ambocc.g;
+	
+	calcAtmospherics(pos.xyz, ambocc);
+	
+	vec3 col = atmosAmbient(vec3(0));
+	col += atmosAffectDirectionalLight(min(da, scol));
+	
+	col *= diffuse.rgb;
+	
+	if (spec.a > 0.2)
+	{
+		vec3 ref = reflect(pos.xyz, norm.xyz);
+		vec3 rc;
+		rc.x = dot(ref, env_mat[0]);
+		rc.y = dot(ref, env_mat[1]);
+		rc.z = dot(ref, env_mat[2]);
+		
+		vec3 refcol = textureCube(environmentMap, rc).rgb;
+		col.rgb += refcol * spec.rgb; 
+	}
+	
+	col = atmosLighting(col);
+	col = scaleSoftClip(col);
+	
+	gl_FragColor.rgb = col;
+	gl_FragColor.a = 0.0;
+	//gl_FragColor.rg = scol_ambocc.rg;
+	//gl_FragColor.rgb = norm.rgb*0.5+0.5;
+	//gl_FragColor.rgb = vec3(ambocc);
+	//gl_FragColor.rgb = vec3(scol);
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/softenLightV.glsl b/indra/newview/app_settings/shaders/class1/deferred/softenLightV.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..ad8af4780d4426f1da5608f7ee0b78eb57f5cd46
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/softenLightV.glsl
@@ -0,0 +1,24 @@
+/** 
+ * @file softenLightF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+uniform vec2 screen_res;
+
+varying vec4 vary_light;
+varying vec2 vary_fragcoord;
+void main()
+{
+	//transform vertex
+	gl_Position = ftransform(); 
+	
+	vec4 pos = gl_ModelViewProjectionMatrix * gl_Vertex;
+	vary_fragcoord = (pos.xy*0.5+0.5)*screen_res;
+		
+	vec4 tex = gl_MultiTexCoord0;
+	tex.w = 1.0;
+	
+	vary_light = gl_MultiTexCoord0;
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/sunLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/sunLightF.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..d43fe6ca95e3e6a039541b4edc8c3242816926cf
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/sunLightF.glsl
@@ -0,0 +1,139 @@
+/** 
+ * @file sunLightF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#extension GL_ARB_texture_rectangle : enable
+
+uniform sampler2DRect positionMap;
+uniform sampler2DRect normalMap;
+uniform sampler2DRect depthMap;
+uniform sampler2DShadow shadowMap0;
+uniform sampler2DShadow shadowMap1;
+uniform sampler2DShadow shadowMap2;
+uniform sampler2DShadow shadowMap3;
+uniform sampler2D noiseMap;
+
+// Inputs
+uniform mat4 shadow_matrix[4];
+uniform vec4 shadow_clip;
+uniform float ssao_radius;
+uniform float ssao_max_radius;
+uniform float ssao_factor;
+uniform float ssao_factor_inv;
+
+varying vec2 vary_fragcoord;
+varying vec4 vary_light;
+
+//calculate decreases in ambient lighting when crowded out (SSAO)
+float calcAmbientOcclusion(vec4 pos, vec3 norm)
+{
+	vec2 kern[8];
+	// exponentially (^2) distant occlusion samples spread around origin
+	kern[0] = vec2(-1.0, 0.0) * 0.125*0.125;
+	kern[1] = vec2(1.0, 0.0) * 0.250*0.250;
+	kern[2] = vec2(0.0, 1.0) * 0.375*0.375;
+	kern[3] = vec2(0.0, -1.0) * 0.500*0.500;
+	kern[4] = vec2(0.7071, 0.7071) * 0.625*0.625;
+	kern[5] = vec2(-0.7071, -0.7071) * 0.750*0.750;
+	kern[6] = vec2(-0.7071, 0.7071) * 0.875*0.875;
+	kern[7] = vec2(0.7071, -0.7071) * 1.000*1.000;
+
+	vec2 pos_screen = vary_fragcoord.xy;
+	vec3 pos_world = pos.xyz;
+	vec2 noise_reflect = texture2D(noiseMap, vary_fragcoord.xy/128.0).xy;
+	
+	float angle_hidden = 0.0;
+	int points = 0;
+	
+	float scale = min(ssao_radius / -pos_world.z, ssao_max_radius);
+	
+	// it was found that keeping # of samples a constant was the fastest, probably due to compiler optimizations (unrolling?)
+	for (int i = 0; i < 8; i++)
+	{
+		vec2 samppos_screen = pos_screen + scale * reflect(kern[i], noise_reflect);
+		vec3 samppos_world = texture2DRect(positionMap, samppos_screen).xyz;
+		
+		vec3 diff = pos_world - samppos_world;
+		float dist2 = dot(diff, diff);
+		
+		// assume each sample corresponds to an occluding sphere with constant radius, constant x-sectional area
+		// --> solid angle shrinking by the square of distance
+		//radius is somewhat arbitrary, can approx with just some constant k * 1 / dist^2
+		//(k should vary inversely with # of samples, but this is taken care of later)
+		
+		//if (dot((samppos_world - 0.05*norm - pos_world), norm) > 0.0)  // -0.05*norm to shift sample point back slightly for flat surfaces
+		//	angle_hidden += min(1.0/dist2, ssao_factor_inv); // dist != 0 follows from conditional.  max of 1.0 (= ssao_factor_inv * ssao_factor)
+		angle_hidden = angle_hidden + float(dot((samppos_world - 0.05*norm - pos_world), norm) > 0.0) * min(1.0/dist2, ssao_factor_inv);
+		
+		// 'blocked' samples (significantly closer to camera relative to pos_world) are "no data", not "no occlusion" 
+		points = points + int(diff.z > -1.0);
+	}
+	
+	angle_hidden = min(ssao_factor*angle_hidden/float(points), 1.0);
+	
+	return 1.0 - (float(points != 0) * angle_hidden);
+}
+
+void main() 
+{
+	vec2 pos_screen = vary_fragcoord.xy;
+	vec4 pos = vec4(texture2DRect(positionMap, pos_screen).xyz, 1.0);
+        vec3 norm = texture2DRect(normalMap, pos_screen).xyz;
+	
+	/*if (pos.z == 0.0) // do nothing for sky *FIX: REMOVE THIS IF/WHEN THE POSITION MAP IS BEING USED AS A STENCIL
+	{
+		gl_FragColor = vec4(0.0); // doesn't matter
+		return;
+	}*/
+	
+	float shadow = 1.0;
+        float dp_directional_light = max(0.0, dot(norm, vary_light.xyz));
+
+	if (dp_directional_light == 0.0)
+	{
+		// if we know this point is facing away from the sun then we know it's in shadow without having to do a squirrelly shadow-map lookup
+		shadow = 0.0;
+	}
+	else if (pos.z > -shadow_clip.w)
+	{	
+		if (pos.z < -shadow_clip.z)
+		{
+			vec4 lpos = shadow_matrix[3]*pos;
+			shadow = shadow2DProj(shadowMap3, lpos).x;
+			shadow += max((pos.z+shadow_clip.z)/(shadow_clip.z-shadow_clip.w)*2.0-1.0, 0.0);
+		}
+		else if (pos.z < -shadow_clip.y)
+		{
+			vec4 lpos = shadow_matrix[2]*pos;
+			shadow = shadow2DProj(shadowMap2, lpos).x;
+		}
+		else if (pos.z < -shadow_clip.x)
+		{
+			vec4 lpos = shadow_matrix[1]*pos;
+			shadow = shadow2DProj(shadowMap1, lpos).x;
+		}
+		else
+		{
+			vec4 lpos = shadow_matrix[0]*pos;
+			shadow = shadow2DProj(shadowMap0, lpos).x;
+		}
+
+		// take the most-shadowed value out of these two:
+		//  * the blurred sun shadow in the light (shadow) map
+		//  * an unblurred dot product between the sun and this norm
+		// the goal is to err on the side of most-shadow to fill-in shadow holes and reduce artifacting
+		shadow = min(shadow, dp_directional_light);
+	}
+	else
+	{
+		// more distant than the shadow map covers - just use directional shading as shadow
+		shadow = dp_directional_light;
+	}
+	
+	gl_FragColor[0] = shadow;
+	gl_FragColor[1] = calcAmbientOcclusion(pos, norm);
+	//gl_FragColor[2] is unused as of August 2008, may be used for debugging
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/sunLightV.glsl b/indra/newview/app_settings/shaders/class1/deferred/sunLightV.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..5081485c4be75666ebb3e6f9c573567292196cce
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/sunLightV.glsl
@@ -0,0 +1,25 @@
+/** 
+ * @file sunLightF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+varying vec4 vary_light;
+varying vec2 vary_fragcoord;
+
+uniform vec2 screen_res;
+
+void main()
+{
+	//transform vertex
+	gl_Position = ftransform(); 
+	vec4 pos = gl_ModelViewProjectionMatrix * gl_Vertex;
+	vary_fragcoord = (pos.xy * 0.5 + 0.5)*screen_res;	
+	vec4 tex = gl_MultiTexCoord0;
+	tex.w = 1.0;
+	
+	vary_light = gl_MultiTexCoord0;
+		
+	gl_FrontColor = gl_Color;
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/terrainF.glsl b/indra/newview/app_settings/shaders/class1/deferred/terrainF.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..211b2e03970f3d12a13e9e74e0fe8c80c927be09
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/terrainF.glsl
@@ -0,0 +1,36 @@
+/** 
+ * @file terrainF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+uniform sampler2D detail_0;
+uniform sampler2D detail_1;
+uniform sampler2D detail_2;
+uniform sampler2D detail_3;
+uniform sampler2D alpha_ramp;
+
+varying vec3 vary_normal;
+varying vec4 vary_position;
+
+void main()
+{
+	/// Note: This should duplicate the blending functionality currently used for the terrain rendering.
+	
+	vec4 color0 = texture2D(detail_0, gl_TexCoord[0].xy);
+	vec4 color1 = texture2D(detail_1, gl_TexCoord[0].xy);
+	vec4 color2 = texture2D(detail_2, gl_TexCoord[0].xy);
+	vec4 color3 = texture2D(detail_3, gl_TexCoord[0].xy);
+
+	float alpha1 = texture2D(alpha_ramp, gl_TexCoord[0].zw).a;
+	float alpha2 = texture2D(alpha_ramp,gl_TexCoord[1].xy).a;
+	float alphaFinal = texture2D(alpha_ramp, gl_TexCoord[1].zw).a;
+	vec4 outColor = mix( mix(color3, color2, alpha2), mix(color1, color0, alpha1), alphaFinal );
+	
+	gl_FragData[0] = vec4(outColor.rgb, 1.0);
+	gl_FragData[1] = vec4(outColor.rgb*0.2, 0.2);
+	gl_FragData[2] = vec4(normalize(vary_normal), 0.0);
+	gl_FragData[3] = vary_position;
+}
+
diff --git a/indra/newview/app_settings/shaders/class1/deferred/terrainV.glsl b/indra/newview/app_settings/shaders/class1/deferred/terrainV.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..e9d6dcabff8e54e07a2e068c9cdda30f24ce1970
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/terrainV.glsl
@@ -0,0 +1,41 @@
+/** 
+ * @file terrainV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+varying vec3 vary_normal;
+varying vec4 vary_position;
+
+vec4 texgen_object(vec4  vpos, vec4 tc, mat4 mat, vec4 tp0, vec4 tp1)
+{
+	vec4 tcoord;
+	
+	tcoord.x = dot(vpos, tp0);
+	tcoord.y = dot(vpos, tp1);
+	tcoord.z = tc.z;
+	tcoord.w = tc.w;
+	
+	tcoord = mat * tcoord; 
+	
+	return tcoord; 
+}
+
+void main()
+{
+	//transform vertex
+	gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
+			
+	vary_position = gl_ModelViewMatrix * gl_Vertex;
+	vary_normal = normalize(gl_NormalMatrix * gl_Normal);
+	
+	// Transform and pass tex coords
+ 	gl_TexCoord[0].xy = texgen_object(gl_Vertex, gl_MultiTexCoord0, gl_TextureMatrix[0], gl_ObjectPlaneS[0], gl_ObjectPlaneT[0]).xy;
+	
+	vec4 t = gl_MultiTexCoord1;
+	
+	gl_TexCoord[0].zw = t.xy;
+	gl_TexCoord[1].xy = t.xy-vec2(2.0, 0.0);
+	gl_TexCoord[1].zw = t.xy-vec2(1.0, 0.0);
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/treeF.glsl b/indra/newview/app_settings/shaders/class1/deferred/treeF.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..bc2c9816dc41e71af86a034530f0aa84ff90c6c8
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/treeF.glsl
@@ -0,0 +1,20 @@
+/** 
+ * @file treeF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+uniform sampler2D diffuseMap;
+
+varying vec3 vary_normal;
+varying vec4 vary_position;
+
+void main() 
+{
+	vec4 col = texture2D(diffuseMap, gl_TexCoord[0].xy);
+	gl_FragData[0] = gl_Color*col;
+	gl_FragData[1] = vec4(0,0,0,0);
+	gl_FragData[2] = vec4(normalize(vary_normal), 0.0);
+	gl_FragData[3] = vary_position;
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/treeV.glsl b/indra/newview/app_settings/shaders/class1/deferred/treeV.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..9131d7c2b32a55588542fb87222389ec470e2b7c
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/treeV.glsl
@@ -0,0 +1,22 @@
+/** 
+ * @file treeV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+varying vec3 vary_normal;
+varying vec4 vary_position;
+
+void main()
+{
+	//transform vertex
+	gl_Position = ftransform(); 
+	gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
+	
+	vary_position = gl_ModelViewMatrix * gl_Vertex;
+	
+	vary_normal = normalize(gl_NormalMatrix * gl_Normal);
+
+	gl_FrontColor = gl_Color;
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl b/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..0a1f019e3d9490094b8282e94505fbe2e97070f4
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl
@@ -0,0 +1,157 @@
+/** 
+ * @file waterF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+vec3 scaleSoftClip(vec3 inColor);
+vec3 atmosTransport(vec3 inColor);
+
+uniform sampler2D bumpMap;   
+uniform sampler2D screenTex;
+uniform sampler2D refTex;
+uniform sampler2DShadow shadowMap0;
+uniform sampler2DShadow shadowMap1;
+uniform sampler2DShadow shadowMap2;
+uniform sampler2DShadow shadowMap3;
+uniform sampler2D noiseMap;
+
+uniform mat4 shadow_matrix[4];
+uniform vec4 shadow_clip;
+
+uniform float sunAngle;
+uniform float sunAngle2;
+uniform vec3 lightDir;
+uniform vec3 specular;
+uniform float lightExp;
+uniform float refScale;
+uniform float kd;
+uniform vec2 screenRes;
+uniform vec3 normScale;
+uniform float fresnelScale;
+uniform float fresnelOffset;
+uniform float blurMultiplier;
+
+
+//bigWave is (refCoord.w, view.w);
+varying vec4 refCoord;
+varying vec4 littleWave;
+varying vec4 view;
+varying vec4 vary_position;
+
+void main() 
+{
+	vec4 color;
+	float dist = length(view.xy);
+	
+	//normalize view vector
+	vec3 viewVec = normalize(view.xyz);
+	
+	//get wave normals
+	vec3 wave1 = texture2D(bumpMap, vec2(refCoord.w, view.w)).xyz*2.0-1.0;
+	vec3 wave2 = texture2D(bumpMap, littleWave.xy).xyz*2.0-1.0;
+	vec3 wave3 = texture2D(bumpMap, littleWave.zw).xyz*2.0-1.0;
+	//get base fresnel components	
+	
+	vec3 df = vec3(
+					dot(viewVec, wave1),
+					dot(viewVec, (wave2 + wave3) * 0.5),
+					dot(viewVec, wave3)
+				 ) * fresnelScale + fresnelOffset;
+	df *= df;
+		    
+	vec2 distort = (refCoord.xy/refCoord.z) * 0.5 + 0.5;
+	
+	float dist2 = dist;
+	dist = max(dist, 5.0);
+	
+	float dmod = sqrt(dist);
+	
+	vec2 dmod_scale = vec2(dmod*dmod, dmod);
+	
+	//get reflected color
+	vec2 refdistort1 = wave1.xy*normScale.x;
+	vec2 refvec1 = distort+refdistort1/dmod_scale;
+	vec4 refcol1 = texture2D(refTex, refvec1);
+	
+	vec2 refdistort2 = wave2.xy*normScale.y;
+	vec2 refvec2 = distort+refdistort2/dmod_scale;
+	vec4 refcol2 = texture2D(refTex, refvec2);
+	
+	vec2 refdistort3 = wave3.xy*normScale.z;
+	vec2 refvec3 = distort+refdistort3/dmod_scale;
+	vec4 refcol3 = texture2D(refTex, refvec3);
+
+	vec4 refcol = refcol1 + refcol2 + refcol3;
+	float df1 = df.x + df.y + df.z;
+	refcol *= df1 * 0.333;
+	
+	vec3 wavef = (wave1 + wave2 * 0.4 + wave3 * 0.6) * 0.5;
+	wavef.z *= max(-viewVec.z, 0.1);
+	wavef = normalize(wavef);
+	
+	float df2 = dot(viewVec, wavef) * fresnelScale+fresnelOffset;
+	
+	vec2 refdistort4 = wavef.xy*0.125;
+	refdistort4.y -= abs(refdistort4.y);
+	vec2 refvec4 = distort+refdistort4/dmod;
+	float dweight = min(dist2*blurMultiplier, 1.0);
+	vec4 baseCol = texture2D(refTex, refvec4);
+	refcol = mix(baseCol*df2, refcol, dweight);
+
+	//get specular component
+	float spec = clamp(dot(lightDir, (reflect(viewVec,wavef))),0.0,1.0);
+		
+	//harden specular
+	spec = pow(spec, 128.0);
+
+	//figure out distortion vector (ripply)   
+	vec2 distort2 = distort+wavef.xy*refScale/max(dmod*df1, 1.0);
+		
+	vec4 fb = texture2D(screenTex, distort2);
+	
+	//mix with reflection
+	// Note we actually want to use just df1, but multiplying by 0.999999 gets around and nvidia compiler bug
+	color.rgb = mix(fb.rgb, refcol.rgb, df1 * 0.99999);
+	
+	float shadow = 1.0;
+	vec4 pos = vary_position;
+	
+	vec3 nz = texture2D(noiseMap, gl_FragCoord.xy/128.0).xyz;
+
+	if (pos.z > -shadow_clip.w)
+	{	
+		vec4 spos = pos;
+			
+		if (pos.z < -shadow_clip.z)
+		{
+			vec4 lpos = (shadow_matrix[3]*spos);
+			shadow = shadow2DProj(shadowMap3, lpos).x;
+		}
+		else if (pos.z < -shadow_clip.y)
+		{
+			vec4 lpos = (shadow_matrix[2]*spos);
+			shadow = shadow2DProj(shadowMap2, lpos).x;
+		}
+		else if (pos.z < -shadow_clip.x)
+		{
+			vec4 lpos = (shadow_matrix[1]*spos);
+			shadow = shadow2DProj(shadowMap1, lpos).x;
+		}
+		else
+		{
+			vec4 lpos = (shadow_matrix[0]*spos);
+			shadow = shadow2DProj(shadowMap0, lpos).x;
+		}
+	}
+	
+	spec *= shadow;
+	color.rgb += spec * specular;
+	
+	color.rgb = atmosTransport(color.rgb);
+	color.rgb = scaleSoftClip(color.rgb);
+	color.a = spec * sunAngle2;
+
+	gl_FragColor = color;
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/waterV.glsl b/indra/newview/app_settings/shaders/class1/deferred/waterV.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..b45e5c53026a44d08f22507209b45dc341dedb59
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/waterV.glsl
@@ -0,0 +1,76 @@
+/** 
+ * @file waterV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+void calcAtmospherics(vec3 inPositionEye);
+
+uniform vec2 d1;
+uniform vec2 d2;
+uniform float time;
+uniform vec3 eyeVec;
+uniform float waterHeight;
+
+varying vec4 refCoord;
+varying vec4 littleWave;
+varying vec4 view;
+
+varying vec4 vary_position;
+
+float wave(vec2 v, float t, float f, vec2 d, float s) 
+{
+   return (dot(d, v)*f + t*s)*f;
+}
+
+void main()
+{
+	//transform vertex
+	vec4 position = gl_Vertex;
+	mat4 modelViewProj = gl_ModelViewProjectionMatrix;
+	
+	vec4 oPosition;
+		    
+	//get view vector
+	vec3 oEyeVec;
+	oEyeVec.xyz = position.xyz-eyeVec;
+		
+	float d = length(oEyeVec.xy);
+	float ld = min(d, 2560.0);
+	
+	position.xy = eyeVec.xy + oEyeVec.xy/d*ld;
+	view.xyz = oEyeVec;
+		
+	d = clamp(ld/1536.0-0.5, 0.0, 1.0);	
+	d *= d;
+		
+	oPosition = position;
+	oPosition.z = mix(oPosition.z, max(eyeVec.z*0.75, 0.0), d);
+	vary_position = gl_ModelViewMatrix * oPosition;
+	oPosition = modelViewProj * oPosition;
+	
+	refCoord.xyz = oPosition.xyz + vec3(0,0,0.2);
+	
+	//get wave position parameter (create sweeping horizontal waves)
+	vec3 v = position.xyz;
+	v.x += (cos(v.x*0.08/*+time*0.01*/)+sin(v.y*0.02))*6.0;
+	    
+	//push position for further horizon effect.
+	position.xyz = oEyeVec.xyz*(waterHeight/oEyeVec.z);
+	position.w = 1.0;
+	position = position*gl_ModelViewMatrix;
+	
+	calcAtmospherics((gl_ModelViewMatrix * gl_Vertex).xyz);
+	
+	
+	//pass wave parameters to pixel shader
+	vec2 bigWave =  (v.xy) * vec2(0.04,0.04)  + d1 * time * 0.055;
+	//get two normal map (detail map) texture coordinates
+	littleWave.xy = (v.xy) * vec2(0.45, 0.9)   + d2 * time * 0.13;
+	littleWave.zw = (v.xy) * vec2(0.1, 0.2) + d1 * time * 0.1;
+	view.w = bigWave.y;
+	refCoord.w = bigWave.x;
+	
+	gl_Position = oPosition;
+}
diff --git a/indra/newview/app_settings/shaders/class1/effects/glowExtractF.glsl b/indra/newview/app_settings/shaders/class1/effects/glowExtractF.glsl
index dbdfe1174c4cb97bf7cb2cb0b1d4988c04b0c14e..5d7af2c13a07c8c60673cfc1fe5b274f7cc428fd 100644
--- a/indra/newview/app_settings/shaders/class1/effects/glowExtractF.glsl
+++ b/indra/newview/app_settings/shaders/class1/effects/glowExtractF.glsl
@@ -20,8 +20,8 @@ void main()
 
 	/// CALCULATING LUMINANCE (Using NTSC lum weights)
 	/// http://en.wikipedia.org/wiki/Luma_%28video%29
-	float lum = smoothstep(minLuminance, 1.0, dot(col.rgb, lumWeights ) );
-	float warmth = smoothstep(minLuminance, 1.0, max(col.r * warmthWeights.r, max(col.g * warmthWeights.g, col.b * warmthWeights.b)) ); 
+	float lum = smoothstep(minLuminance, minLuminance+1.0, dot(col.rgb, lumWeights ) );
+	float warmth = smoothstep(minLuminance, minLuminance+1.0, max(col.r * warmthWeights.r, max(col.g * warmthWeights.g, col.b * warmthWeights.b)) ); 
 	
 	gl_FragColor.rgb = col.rgb; 
 	gl_FragColor.a = max(col.a, mix(lum, warmth, warmthAmount) * maxExtractAlpha);
diff --git a/indra/newview/app_settings/shaders/class1/environment/waterF.glsl b/indra/newview/app_settings/shaders/class1/environment/waterF.glsl
index bd9b30a07568a3198c68d5493c541d3b4903fa94..7e1788678da59d1ec8ec1df8fdb369bbfccb143e 100644
--- a/indra/newview/app_settings/shaders/class1/environment/waterF.glsl
+++ b/indra/newview/app_settings/shaders/class1/environment/waterF.glsl
@@ -7,6 +7,7 @@
 
 vec3 scaleSoftClip(vec3 inColor);
 vec3 atmosTransport(vec3 inColor);
+vec3 applyWaterFog(vec4 inColor);
 
 uniform sampler2D diffuseMap;
 uniform sampler2D bumpMap;   
diff --git a/indra/newview/featuretable.txt b/indra/newview/featuretable.txt
index c02ba86d6c6c97c47d193175c75bbc9a4ab08215..05bdf64b426b387c87f0bf870327ec79186c53fa 100644
--- a/indra/newview/featuretable.txt
+++ b/indra/newview/featuretable.txt
@@ -54,6 +54,8 @@ WLSkyDetail					1	128
 Disregard128DefaultDrawDistance	1	1
 Disregard96DefaultDrawDistance	1	1
 RenderTextureMemoryMultiple		1	1.0
+RenderShaderLightingMaxLevel	1	3
+
 
 //
 // Low Graphics Settings
@@ -473,17 +475,47 @@ list NVIDIA_GeForce_Go_6
 RenderVBOEnable				1	0
 Disregard128DefaultDrawDistance	1	0
 
+list NVIDIA_GeForce_7000
+RenderShaderLightingMaxLevel	1	2
+list NVIDIA_GeForce_7100
+RenderShaderLightingMaxLevel	1	2
 list NVIDIA_GeForce_7200
 Disregard128DefaultDrawDistance	1	0
+RenderShaderLightingMaxLevel	1	2
 list NVIDIA_GeForce_7300
 Disregard128DefaultDrawDistance	1	0
+RenderShaderLightingMaxLevel	1	2
 list NVIDIA_GeForce_7400
 Disregard128DefaultDrawDistance	1	0
+RenderShaderLightingMaxLevel	1	2
+list NVIDIA_GeForce_7500
+RenderShaderLightingMaxLevel	1	2
+list NVIDIA_GeForce_7600
+RenderShaderLightingMaxLevel	1	2
+list NVIDIA_GeForce_7700
+RenderShaderLightingMaxLevel	1	2
+list NVIDIA_GeForce_7800
+RenderShaderLightingMaxLevel	1	2
+list NVIDIA_GeForce_7900
+RenderShaderLightingMaxLevel	1	2
 
 list NVIDIA_GeForce_Go_7200
 Disregard128DefaultDrawDistance	1	0
+RenderShaderLightingMaxLevel	1	2
 list NVIDIA_GeForce_Go_7300
 Disregard128DefaultDrawDistance	1	0
+RenderShaderLightingMaxLevel	1	2
+list NVIDIA_GeForce_Go_7300_LE
+RenderShaderLightingMaxLevel	1	2
 list NVIDIA_GeForce_Go_7400
 Disregard128DefaultDrawDistance	1	0
+RenderShaderLightingMaxLevel	1	2
+list NVIDIA_GeForce_Go_7600
+RenderShaderLightingMaxLevel	1	2
+list NVIDIA_GeForce_Go_7700
+RenderShaderLightingMaxLevel	1	2
+list NVIDIA_GeForce_Go_7800
+RenderShaderLightingMaxLevel	1	2
+list NVIDIA_GeForce_Go_7900
+RenderShaderLightingMaxLevel	1	2
 
diff --git a/indra/newview/licenses-win32.txt b/indra/newview/licenses-win32.txt
index 5f6cf14c05d855bd05f93ee388ad2aba5b458532..7e6d4b4561ce44100f2a395517ccf3964e85acf2 100644
--- a/indra/newview/licenses-win32.txt
+++ b/indra/newview/licenses-win32.txt
@@ -735,3 +735,37 @@ From Vivox:
      Attn: customer support 
      40 Speen Street Suite 402 
      Framingham, MA 01701 
+
+
+========================
+google-perftools license
+========================
+
+Copyright (c) 2005, Google Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+    * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index 7ef757f1bad1358464f5bb1d1c4d3bb985b60349..569de267e72c40d86f48556f8e91ad258a53c276 100644
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -358,7 +358,6 @@ LLAgent::LLAgent() :
 
 	mFrameAgent(),
 
-	mCrouching(FALSE),
 	mIsBusy(FALSE),
 
 	mAtKey(0), // Either 1, 0, or -1... indicates that movement-key is pressed
@@ -477,8 +476,16 @@ void LLAgent::cleanup()
 {
 	setSitCamera(LLUUID::null);
 	mAvatarObject = NULL;
-	mLookAt = NULL;
-	mPointAt = NULL;
+	if(mLookAt)
+	{
+		mLookAt->markDead() ;
+		mLookAt = NULL;
+	}
+	if(mPointAt)
+	{
+		mPointAt->markDead() ;
+		mPointAt = NULL;
+	}
 	mRegionp = NULL;
 	setFocusObject(NULL);
 }
@@ -2726,7 +2733,7 @@ BOOL LLAgent::needsRenderAvatar()
 // TRUE if we need to render your own avatar's head.
 BOOL LLAgent::needsRenderHead()
 {
-	return mShowAvatar && !cameraMouselook();
+	return (LLVOAvatar::sVisibleInFirstPerson && LLPipeline::sReflectionRender) || (mShowAvatar && !cameraMouselook());
 }
 
 //-----------------------------------------------------------------------------
diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h
index c9e256fbbcd7e1266a5fd0f355fad8f1b6466fc6..9d08c94150a0cc6860649a56e6c338e8387673cb 100644
--- a/indra/newview/llagent.h
+++ b/indra/newview/llagent.h
@@ -544,6 +544,7 @@ class LLAgent : public LLObservable
 	void			setHomePosRegion( const U64& region_handle, const LLVector3& pos_region );
 	BOOL			getHomePosGlobal( LLVector3d* pos_global );
 	void			setCameraAnimating( BOOL b )	{ mCameraAnimating = b; }
+	BOOL			getCameraAnimating( )			{ return mCameraAnimating; }
 	void			setAnimationDuration( F32 seconds ) { mAnimationDuration = seconds; }
 
 	F32				getNearChatRadius() { return mNearChatRadius; }
@@ -811,7 +812,6 @@ class LLAgent : public LLObservable
 
 	LLCoordFrame	mFrameAgent;					// Agent position and view, agent-region coordinates
 
-	BOOL			mCrouching;
 	BOOL			mIsBusy;
 
 	S32 			mAtKey;							// Either 1, 0, or -1... indicates that movement-key is pressed
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 9a8d211cf69c99e37449e862f77a09c8513e510c..fc37c42f994763cc26078eaec1939ebfb21257dc 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -159,7 +159,7 @@
 #include "llimview.h"
 #include "llviewerthrottle.h"
 #include "llparcel.h"
-// 
+
 
 #include "llinventoryview.h"
 
@@ -508,7 +508,7 @@ LLWorkerThread* LLAppViewer::sImageDecodeThread = NULL;
 LLTextureFetch* LLAppViewer::sTextureFetch = NULL; 
 
 LLAppViewer::LLAppViewer() : 
-	mMarkerFile(NULL),
+	mMarkerFile(),
 	mReportedCrash(false),
 	mNumSessions(0),
 	mPurgeCache(false),
@@ -1056,6 +1056,9 @@ bool LLAppViewer::mainLoop()
 			}
 			else
 			{
+				//output possible call stacks to log file.
+				LLError::LLCallStacks::print() ;
+
 				llerrs << "Bad memory allocation in LLAppViewer::mainLoop()!" << llendl ;
 			}
 		}
@@ -1091,6 +1094,16 @@ bool LLAppViewer::mainLoop()
 
 bool LLAppViewer::cleanup()
 {
+	//----------------------------------------------
+	//this test code will be removed after the test
+	//test manual call stack tracer
+	if(gSavedSettings.getBOOL("QAMode"))
+	{
+		LLError::LLCallStacks::print() ;
+	}
+	//end of the test code
+	//----------------------------------------------
+
 	//flag all elements as needing to be destroyed immediately
 	// to ensure shutdown order
 	LLMortician::setZealous(TRUE);
@@ -1110,6 +1123,9 @@ bool LLAppViewer::cleanup()
 	llinfos << "Cleaning Up" << llendflush;
 
 	// Must clean up texture references before viewer window is destroyed.
+	LLHUDManager::getInstance()->updateEffects();
+	LLHUDObject::updateAll();
+	LLHUDManager::getInstance()->cleanupEffects();
 	LLHUDObject::cleanupHUDObjects();
 	llinfos << "HUD Objects cleaned up" << llendflush;
 
@@ -2118,7 +2134,7 @@ bool LLAppViewer::initWindow()
 	gViewerWindow->initBase();
 
 	// show viewer window
-	gViewerWindow->mWindow->show();
+	//gViewerWindow->mWindow->show();
 
 	
 	return true;
@@ -2264,6 +2280,9 @@ void LLAppViewer::handleViewerCrash()
 {
 	llinfos << "Handle viewer crash entry." << llendl;
 
+	//print out recorded call stacks if there are any.
+	LLError::LLCallStacks::print() ;
+
 	LLAppViewer* pApp = LLAppViewer::instance();
 	if (pApp->beingDebugged())
 	{
@@ -2348,16 +2367,17 @@ void LLAppViewer::handleViewerCrash()
 		if(gLLErrorActivated) crash_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,LLERROR_MARKER_FILE_NAME);
 		else crash_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,ERROR_MARKER_FILE_NAME);
 		llinfos << "Creating crash marker file " << crash_file_name << llendl;
-		apr_file_t* crash_file =  ll_apr_file_open(crash_file_name, LL_APR_W);
-		if (crash_file)
+		
+		LLAPRFile crash_file ;
+		crash_file.open(crash_file_name, LL_APR_W);
+		if (crash_file.getFileHandle())
 		{
 			LL_INFOS("MarkerFile") << "Created crash marker file " << crash_file_name << LL_ENDL;
 		}
 		else
 		{
 			LL_WARNS("MarkerFile") << "Cannot create error marker file " << crash_file_name << LL_ENDL;
-		}
-		apr_file_close(crash_file);
+		}		
 	}
 	
 	if (gMessageSystem && gDirUtilp)
@@ -2411,13 +2431,13 @@ bool LLAppViewer::anotherInstanceRunning()
 	LL_DEBUGS("MarkerFile") << "Checking marker file for lock..." << LL_ENDL;
 
 	//Freeze case checks
-	apr_file_t* fMarker = ll_apr_file_open(marker_file, LL_APR_RB);		
-	if (fMarker != NULL)
+	if (LLAPRFile::isExist(marker_file, NULL, LL_APR_RB))
 	{
 		// File exists, try opening with write permissions
-		apr_file_close(fMarker);
-		fMarker = ll_apr_file_open(marker_file, LL_APR_WB);
-		if (fMarker == NULL)
+		LLAPRFile outfile ;
+		outfile.open(marker_file, LL_APR_WB);
+		apr_file_t* fMarker = outfile.getFileHandle() ; 
+		if (!fMarker)
 		{
 			// Another instance is running. Skip the rest of these operations.
 			LL_INFOS("MarkerFile") << "Marker file is locked." << LL_ENDL;
@@ -2425,12 +2445,10 @@ bool LLAppViewer::anotherInstanceRunning()
 		}
 		if (apr_file_lock(fMarker, APR_FLOCK_NONBLOCK | APR_FLOCK_EXCLUSIVE) != APR_SUCCESS) //flock(fileno(fMarker), LOCK_EX | LOCK_NB) == -1)
 		{
-			apr_file_close(fMarker);
 			LL_INFOS("MarkerFile") << "Marker file is locked." << LL_ENDL;
 			return true;
 		}
-		// No other instances; we'll lock this file now & delete on quit.
-		apr_file_close(fMarker);
+		// No other instances; we'll lock this file now & delete on quit.		
 	}
 	LL_DEBUGS("MarkerFile") << "Marker file isn't locked." << LL_ENDL;
 	return false;
@@ -2456,33 +2474,27 @@ void LLAppViewer::initMarkerFile()
 	std::string llerror_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LLERROR_MARKER_FILE_NAME);
 	std::string error_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ERROR_MARKER_FILE_NAME);
 
-	apr_file_t* fMarker = ll_apr_file_open(logout_marker_file, LL_APR_RB);
-	if(fMarker != NULL)
+	if(LLAPRFile::isExist(logout_marker_file, NULL, LL_APR_RB))
 	{
-		apr_file_close(fMarker);
 		LL_INFOS("MarkerFile") << "Last exec LLError crashed, setting LastExecEvent to " << LAST_EXEC_LLERROR_CRASH << LL_ENDL;
 		gLastExecEvent = LAST_EXEC_LOGOUT_FROZE;
-	}	
-	fMarker = ll_apr_file_open(llerror_marker_file, LL_APR_RB);
-	if(fMarker != NULL)
+	}
+	if(LLAPRFile::isExist(llerror_marker_file, NULL, LL_APR_RB))
 	{
-		apr_file_close(fMarker);
 		llinfos << "Last exec LLError crashed, setting LastExecEvent to " << LAST_EXEC_LLERROR_CRASH << llendl;
 		if(gLastExecEvent == LAST_EXEC_LOGOUT_FROZE) gLastExecEvent = LAST_EXEC_LOGOUT_CRASH;
 		else gLastExecEvent = LAST_EXEC_LLERROR_CRASH;
 	}
-	fMarker = ll_apr_file_open(error_marker_file, LL_APR_RB);
-	if(fMarker != NULL)
+	if(LLAPRFile::isExist(error_marker_file, NULL, LL_APR_RB))
 	{
-		apr_file_close(fMarker);
 		LL_INFOS("MarkerFile") << "Last exec crashed, setting LastExecEvent to " << LAST_EXEC_OTHER_CRASH << LL_ENDL;
 		if(gLastExecEvent == LAST_EXEC_LOGOUT_FROZE) gLastExecEvent = LAST_EXEC_LOGOUT_CRASH;
 		else gLastExecEvent = LAST_EXEC_OTHER_CRASH;
 	}
-
-	ll_apr_file_remove(logout_marker_file);
-	ll_apr_file_remove(llerror_marker_file);
-	ll_apr_file_remove(error_marker_file);
+	
+	LLAPRFile::remove(logout_marker_file);
+	LLAPRFile::remove(llerror_marker_file);
+	LLAPRFile::remove(error_marker_file);
 	
 	//Freeze case checks
 	if(anotherInstanceRunning()) 
@@ -2490,17 +2502,17 @@ void LLAppViewer::initMarkerFile()
 		return;
 	}
 	
-	fMarker = ll_apr_file_open(mMarkerFileName, LL_APR_RB);		
-	if (fMarker != NULL)
-	{
-		apr_file_close(fMarker);
+	if (LLAPRFile::isExist(mMarkerFileName, NULL, LL_APR_RB))
+	{		
 		gLastExecEvent = LAST_EXEC_FROZE;
 		LL_INFOS("MarkerFile") << "Exec marker found: program froze on previous execution" << LL_ENDL;
 	}
-
+	
 	// Create the marker file for this execution & lock it
-	mMarkerFile =  ll_apr_file_open(mMarkerFileName, LL_APR_W);
-	if (mMarkerFile)
+	apr_status_t s;
+	s = mMarkerFile.open(mMarkerFileName, LL_APR_W, gAPRPoolp);	
+
+	if (s == APR_SUCCESS && mMarkerFile.getFileHandle())
 	{
 		LL_DEBUGS("MarkerFile") << "Marker file created." << LL_ENDL;
 	}
@@ -2509,9 +2521,9 @@ void LLAppViewer::initMarkerFile()
 		LL_INFOS("MarkerFile") << "Failed to create marker file." << LL_ENDL;
 		return;
 	}
-	if (apr_file_lock(mMarkerFile, APR_FLOCK_NONBLOCK | APR_FLOCK_EXCLUSIVE) != APR_SUCCESS) 
+	if (apr_file_lock(mMarkerFile.getFileHandle(), APR_FLOCK_NONBLOCK | APR_FLOCK_EXCLUSIVE) != APR_SUCCESS) 
 	{
-		apr_file_close(mMarkerFile);
+		mMarkerFile.close() ;
 		LL_INFOS("MarkerFile") << "Marker file cannot be locked." << LL_ENDL;
 		return;
 	}
@@ -2522,14 +2534,14 @@ void LLAppViewer::initMarkerFile()
 void LLAppViewer::removeMarkerFile(bool leave_logout_marker)
 {
 	LL_DEBUGS("MarkerFile") << "removeMarkerFile()" << LL_ENDL;
-	if (mMarkerFile != NULL)
+	if (mMarkerFile.getFileHandle())
 	{
-		ll_apr_file_remove( mMarkerFileName );
-		mMarkerFile = NULL;
+		mMarkerFile.close() ;
+		LLAPRFile::remove( mMarkerFileName );
 	}
 	if (mLogoutMarkerFile != NULL && !leave_logout_marker)
 	{
-		ll_apr_file_remove( mLogoutMarkerFileName );
+		LLAPRFile::remove( mLogoutMarkerFileName );
 		mLogoutMarkerFile = NULL;
 	}
 }
@@ -2556,6 +2568,7 @@ void LLAppViewer::requestQuit()
 	effectp->setPositionGlobal(gAgent.getPositionGlobal());
 	effectp->setColor(LLColor4U(gAgent.getEffectColor()));
 	LLHUDManager::getInstance()->sendEffects();
+	effectp->markDead() ;//remove it.
 
 	// Attempt to close all floaters that might be
 	// editing things.
@@ -3228,6 +3241,7 @@ void LLAppViewer::idle()
 	    //
     
 	    gFrameStats.start(LLFrameStats::IDLE_NETWORK);
+		stop_glerror();
 		idleNetwork();
 	    stop_glerror();
 	        
@@ -3535,7 +3549,10 @@ void LLAppViewer::sendLogoutRequest()
 		//Set internal status variables and marker files
 		gLogoutInProgress = TRUE;
 		mLogoutMarkerFileName = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,LOGOUT_MARKER_FILE_NAME);
-		mLogoutMarkerFile =  ll_apr_file_open(mLogoutMarkerFileName, LL_APR_W);
+		
+		LLAPRFile outfile ;
+		outfile.open(mLogoutMarkerFileName, LL_APR_W);
+		mLogoutMarkerFile =  outfile.getFileHandle() ;
 		if (mLogoutMarkerFile)
 		{
 			llinfos << "Created logout marker file " << mLogoutMarkerFileName << llendl;
@@ -3544,7 +3561,7 @@ void LLAppViewer::sendLogoutRequest()
 		else
 		{
 			llwarns << "Cannot create logout marker file " << mLogoutMarkerFileName << llendl;
-		}
+		}		
 	}
 }
 
@@ -3562,6 +3579,8 @@ static F32 CheckMessagesMaxTime = CHECK_MESSAGES_DEFAULT_MAX_TIME;
 void LLAppViewer::idleNetwork()
 {
 	pingMainloopTimeout("idleNetwork");
+	LLError::LLCallStacks::clear() ;
+	llpushcallstacks ;
 
 	gObjectList.mNumNewObjects = 0;
 	S32 total_decoded = 0;
@@ -3572,7 +3591,7 @@ void LLAppViewer::idleNetwork()
 		
 		// deal with any queued name requests and replies.
 		gCacheName->processPending();
-
+		llpushcallstacks ;
 		LLTimer check_message_timer;
 		//  Read all available packets from network 
 		stop_glerror();
@@ -3644,16 +3663,16 @@ void LLAppViewer::idleNetwork()
 			gPrintMessagesThisFrame = FALSE;
 		}
 	}
-
+	llpushcallstacks ;
 	gObjectList.mNumNewObjectsStat.addValue(gObjectList.mNumNewObjects);
 
 	// Retransmit unacknowledged packets.
 	gXferManager->retransmitUnackedPackets();
 	gAssetStorage->checkForTimeouts();
-
+	llpushcallstacks ;
 	gViewerThrottle.updateDynamicThrottle();
 
-
+	llpushcallstacks ;
 	// Check that the circuit between the viewer and the agent's current
 	// region is still alive
 	LLViewerRegion *agent_region = gAgent.getRegion();
@@ -3669,6 +3688,7 @@ void LLAppViewer::idleNetwork()
 		mAgentRegionLastID = this_region_id;
 		mAgentRegionLastAlive = this_region_alive;
 	}
+	llpushcallstacks ;
 }
 
 void LLAppViewer::disconnectViewer()
diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h
index 638bd241ce9ad42174958c7357afb5f1fd7e137e..cb10ad36617b4c7531b4d8a3d9188c7712e66d6b 100644
--- a/indra/newview/llappviewer.h
+++ b/indra/newview/llappviewer.h
@@ -198,7 +198,7 @@ class LLAppViewer : public LLApp
     bool mSecondInstance; // Is this a second instance of the app?
 
 	std::string mMarkerFileName;
-	apr_file_t* mMarkerFile; // A file created to indicate the app is running.
+	LLAPRFile mMarkerFile; // A file created to indicate the app is running.
 
 	std::string mLogoutMarkerFileName;
 	apr_file_t* mLogoutMarkerFile; // A file created to indicate the app is running.
diff --git a/indra/newview/llcloud.cpp b/indra/newview/llcloud.cpp
index 4656fb45a636af9352c62982486bbc1725c885c4..0099817de478cdab3d9783348a93d8091cb0aed3 100644
--- a/indra/newview/llcloud.cpp
+++ b/indra/newview/llcloud.cpp
@@ -122,7 +122,7 @@ void LLCloudGroup::updatePuffs(const F32 dt)
 		mVOCloudsp->setScale(LLVector3(256.f/CLOUD_GROUPS_PER_EDGE + CLOUD_PUFF_WIDTH,
 										 256.f/CLOUD_GROUPS_PER_EDGE + CLOUD_PUFF_WIDTH,
 										 CLOUD_HEIGHT_RANGE + CLOUD_PUFF_HEIGHT)*0.5f);
-		gPipeline.addObject(mVOCloudsp);
+		gPipeline.createObject(mVOCloudsp);
 	}
 
 	LLVector3 velocity;
diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp
index d5619f2bf065d967d89999f65e543ecc8cf8a56e..47e4a2278f4fdc0b4fdf640eba4764c884c8c662 100644
--- a/indra/newview/lldrawable.cpp
+++ b/indra/newview/lldrawable.cpp
@@ -532,10 +532,10 @@ F32 LLDrawable::updateXform(BOOL undamped)
 
 	if ((mCurrentScale != target_scale) ||
 		(!isRoot() && 
-		 (dist_squared >= MIN_INTERPOLATE_DISTANCE_SQUARED) || 
+		 (dist_squared >= MIN_INTERPOLATE_DISTANCE_SQUARED || 
 		 !mVObjp->getAngularVelocity().isExactlyZero() ||
 		 target_pos != mXform.getPosition() ||
-		 target_rot != mXform.getRotation()))
+		 target_rot != mXform.getRotation())))
 	{ //child prim moving or scale change requires immediate rebuild
 		gPipeline.markRebuild(this, LLDrawable::REBUILD_POSITION, TRUE);
 	}
@@ -1233,7 +1233,8 @@ void LLSpatialBridge::setVisible(LLCamera& camera_in, std::vector<LLDrawable*>*
 	LLVector3 center = (mExtents[0] + mExtents[1]) * 0.5f;
 	LLVector3 size = (mExtents[1]-mExtents[0]) * 0.5f;
 
-	if (LLPipeline::sImpostorRender ||
+	if ((LLPipeline::sShadowRender && camera_in.AABBInFrustum(center, size)) ||
+		LLPipeline::sImpostorRender ||
 		(camera_in.AABBInFrustumNoFarClip(center, size) && 
 		AABBSphereIntersect(mExtents[0], mExtents[1], camera_in.getOrigin(), camera_in.mFrustumCornerDist)))
 	{
@@ -1290,7 +1291,6 @@ void LLSpatialBridge::updateDistance(LLCamera& camera_in)
 			LLDrawable* drawable = child->mDrawable;					
 			if (!drawable)
 			{
-				llwarns << "Corrupt drawable found while updating spatial bridge distance." << llendl;
 				continue;
 			}
 
diff --git a/indra/newview/lldrawable.h b/indra/newview/lldrawable.h
index 77715cbedfe8b398778d65181c7eceed247f134d..f5a66a3a784d2eea649f9cf2548a1f7b9501c5be 100644
--- a/indra/newview/lldrawable.h
+++ b/indra/newview/lldrawable.h
@@ -98,6 +98,7 @@ class LLDrawable : public LLRefCount
 	const LLVector3		  getPositionAgent() const;
 	const LLVector3d&	  getPositionGroup() const		{ return mPositionGroup; }
 	const LLVector3&	  getScale() const				{ return mCurrentScale; }
+	void				  setScale(const LLVector3& scale) { mCurrentScale = scale; }
 	const LLQuaternion&   getWorldRotation() const		{ return mXform.getWorldRotation(); }
 	const LLQuaternion&   getRotation() const			{ return mXform.getRotation(); }
 	F32			          getIntensity() const			{ return llmin(mXform.getScale().mV[0], 4.f); }
diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp
index bd30d47426f22a633f6ef40e3506c0c4c73e7638..9f05ce3c460fc53b818f4b9845ccba0c18282ce9 100644
--- a/indra/newview/lldrawpool.cpp
+++ b/indra/newview/lldrawpool.cpp
@@ -68,6 +68,12 @@ LLDrawPool *LLDrawPool::createPool(const U32 type, LLViewerImage *tex0)
 	case POOL_SIMPLE:
 		poolp = new LLDrawPoolSimple();
 		break;
+	case POOL_GRASS:
+		poolp = new LLDrawPoolGrass();
+		break;
+	case POOL_FULLBRIGHT:
+		poolp = new LLDrawPoolFullbright();
+		break;
 	case POOL_INVISIBLE:
 		poolp = new LLDrawPoolInvisible();
 		break;
@@ -133,11 +139,89 @@ void LLDrawPool::beginRenderPass( S32 pass )
 {
 }
 
+//virtual 
+S32	 LLDrawPool::getNumPasses()
+{
+	return 1;
+}
+	
+//virtual 
+void LLDrawPool::beginDeferredPass(S32 pass)
+{
+
+}
+
+//virtual 
+void LLDrawPool::endDeferredPass(S32 pass)
+{
+
+}
+
+//virtual 
+S32 LLDrawPool::getNumDeferredPasses()
+{
+	return 0;
+}
+
+//virtual 
+void LLDrawPool::renderDeferred(S32 pass)
+{
+
+}
+
+//virtual 
+void LLDrawPool::beginPostDeferredPass(S32 pass)
+{
+
+}
+
+//virtual 
+void LLDrawPool::endPostDeferredPass(S32 pass)
+{
+
+}
+
+//virtual 
+S32 LLDrawPool::getNumPostDeferredPasses()
+{
+	return 0;
+}
+
+//virtual 
+void LLDrawPool::renderPostDeferred(S32 pass)
+{
+
+}
+
 //virtual
 void LLDrawPool::endRenderPass( S32 pass )
 {
 }
 
+//virtual 
+void LLDrawPool::beginShadowPass(S32 pass)
+{
+
+}
+
+//virtual 
+void LLDrawPool::endShadowPass(S32 pass)
+{
+
+}
+
+//virtual 
+S32 LLDrawPool::getNumShadowPasses()
+{
+	return 0;
+}
+
+//virtual 
+void LLDrawPool::renderShadow(S32 pass)
+{
+
+}
+
 //=============================
 // Face Pool Implementation
 //=============================
@@ -414,6 +498,10 @@ void LLRenderPass::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture)
 	
 	if (params.mVertexBuffer.notNull())
 	{
+		if (params.mGroup)
+		{
+			params.mGroup->rebuildMesh();
+		}
 		params.mVertexBuffer->setBuffer(mask);
 		params.mVertexBuffer->drawRange(LLRender::TRIANGLES, params.mStart, params.mEnd, params.mCount, params.mOffset);
 		gPipeline.addTrianglesDrawn(params.mCount/3);
diff --git a/indra/newview/lldrawpool.h b/indra/newview/lldrawpool.h
index 45a47f4c3f9ca7ece6d2a04699763bae331767a4..b75de02ffc712b6162880896e37c2b7b6d60cde1 100644
--- a/indra/newview/lldrawpool.h
+++ b/indra/newview/lldrawpool.h
@@ -58,10 +58,12 @@ class LLDrawPool
 		POOL_SKY,
 		POOL_WL_SKY,
 		POOL_GROUND,
-		POOL_BUMP,
 		POOL_INVISIBLE,
 		POOL_AVATAR,
 		POOL_WATER,
+		POOL_GRASS,
+		POOL_FULLBRIGHT,
+		POOL_BUMP,
 		POOL_GLOW,
 		POOL_ALPHA,
 		NUM_POOL_TYPES,
@@ -78,7 +80,23 @@ class LLDrawPool
 	virtual LLViewerImage *getDebugTexture();
 	virtual void beginRenderPass( S32 pass );
 	virtual void endRenderPass( S32 pass );
-	virtual S32	 getNumPasses() { return 1; }
+	virtual S32	 getNumPasses();
+	
+	virtual void beginDeferredPass(S32 pass);
+	virtual void endDeferredPass(S32 pass);
+	virtual S32 getNumDeferredPasses();
+	virtual void renderDeferred(S32 pass = 0);
+
+	virtual void beginPostDeferredPass(S32 pass);
+	virtual void endPostDeferredPass(S32 pass);
+	virtual S32 getNumPostDeferredPasses();
+	virtual void renderPostDeferred(S32 pass = 0);
+
+	virtual void beginShadowPass(S32 pass);
+	virtual void endShadowPass(S32 pass);
+	virtual S32 getNumShadowPasses();
+	virtual void renderShadow(S32 pass = 0);
+
 	virtual void render(S32 pass = 0) = 0;
 	virtual void prerender() = 0;
 	virtual U32 getVertexDataMask() = 0;
@@ -112,6 +130,9 @@ class LLRenderPass : public LLDrawPool
 		PASS_BUMP,
 		PASS_GLOW,
 		PASS_ALPHA,
+		PASS_ALPHA_MASK,
+		PASS_FULLBRIGHT_ALPHA_MASK,
+		PASS_ALPHA_SHADOW,
 		NUM_RENDER_TYPES,
 	};
 
diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp
index 8c4a0ab2b55fcfe9f363ca00e87dd584b88d9b46..7e470bd01f498225c858b38c7fe8129b08203db1 100644
--- a/indra/newview/lldrawpoolalpha.cpp
+++ b/indra/newview/lldrawpoolalpha.cpp
@@ -57,7 +57,7 @@
 
 BOOL LLDrawPoolAlpha::sShowDebugAlpha = FALSE;
 
-
+static BOOL deferred_render = FALSE;
 
 LLDrawPoolAlpha::LLDrawPoolAlpha(U32 type) :
 		LLRenderPass(type), current_shader(NULL), target_shader(NULL),
@@ -76,6 +76,67 @@ void LLDrawPoolAlpha::prerender()
 	mVertexShaderLevel = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT);
 }
 
+S32 LLDrawPoolAlpha::getNumDeferredPasses()
+{
+	return 1;
+}
+
+void LLDrawPoolAlpha::beginDeferredPass(S32 pass)
+{
+	
+}
+
+void LLDrawPoolAlpha::endDeferredPass(S32 pass)
+{
+	gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.4f);
+	{
+		LLFastTimer t(LLFastTimer::FTM_RENDER_GRASS);
+		gDeferredTreeProgram.bind();
+		LLGLEnable test(GL_ALPHA_TEST);
+		//render alpha masked objects
+		LLRenderPass::renderTexture(LLRenderPass::PASS_ALPHA_MASK, getVertexDataMask());
+	}			
+	gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
+}
+
+void LLDrawPoolAlpha::renderDeferred(S32 pass)
+{
+	
+}
+
+
+S32 LLDrawPoolAlpha::getNumPostDeferredPasses() 
+{ 
+	return 1; 
+}
+
+void LLDrawPoolAlpha::beginPostDeferredPass(S32 pass) 
+{ 
+	LLFastTimer t(LLFastTimer::FTM_RENDER_ALPHA);
+
+	simple_shader = &gDeferredAlphaProgram;
+	fullbright_shader = &gDeferredFullbrightProgram;
+	
+	deferred_render = TRUE;
+	if (mVertexShaderLevel > 0)
+	{
+		// Start out with no shaders.
+		current_shader = target_shader = NULL;
+	}
+	gPipeline.enableLightsDynamic();
+}
+
+void LLDrawPoolAlpha::endPostDeferredPass(S32 pass) 
+{ 
+	deferred_render = FALSE;
+	endRenderPass(pass);
+}
+
+void LLDrawPoolAlpha::renderPostDeferred(S32 pass) 
+{ 
+	render(pass); 
+}
+
 void LLDrawPoolAlpha::beginRenderPass(S32 pass)
 {
 	LLFastTimer t(LLFastTimer::FTM_RENDER_ALPHA);
@@ -115,12 +176,40 @@ void LLDrawPoolAlpha::render(S32 pass)
 {
 	LLFastTimer t(LLFastTimer::FTM_RENDER_ALPHA);
 
-	LLGLDepthTest depth(GL_TRUE, LLDrawPoolWater::sSkipScreenCopy ? GL_TRUE : GL_FALSE);
-
 	LLGLSPipelineAlpha gls_pipeline_alpha;
-	
+
+	if (LLPipeline::sFastAlpha && !deferred_render)
+	{
+		gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.33f);
+		if (mVertexShaderLevel > 0)
+		{
+			if (!LLPipeline::sRenderDeferred)
+			{
+				simple_shader->bind();
+				pushBatches(LLRenderPass::PASS_ALPHA_MASK, getVertexDataMask());
+			}
+			fullbright_shader->bind();
+			pushBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, getVertexDataMask());
+			LLGLSLShader::bindNoShader();
+		}
+		else
+		{
+			gPipeline.enableLightsFullbright(LLColor4(1,1,1,1));
+			pushBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, getVertexDataMask());
+			gPipeline.enableLightsDynamic();
+			pushBatches(LLRenderPass::PASS_ALPHA_MASK, getVertexDataMask());
+		}
+		gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
+	}
+
+	LLGLDepthTest depth(GL_TRUE, LLDrawPoolWater::sSkipScreenCopy ? GL_TRUE : GL_FALSE);
 	renderAlpha(getVertexDataMask());
 
+	if (deferred_render && current_shader != NULL)
+	{
+		gPipeline.unbindDeferredShader(*current_shader);
+	}
+
 	if (sShowDebugAlpha)
 	{
 		if(gPipeline.canUseWindLightShaders()) 
@@ -132,20 +221,7 @@ void LLDrawPoolAlpha::render(S32 pass)
 		LLViewerImage::sSmokeImagep->addTextureStats(1024.f*1024.f);
 		gGL.getTexUnit(0)->bind(LLViewerImage::sSmokeImagep.get());
 		renderAlphaHighlight(LLVertexBuffer::MAP_VERTEX |
-							LLVertexBuffer::MAP_TEXCOORD);
-	}
-}
-
-void LLDrawPoolAlpha::renderAlpha(U32 mask)
-{
-	for (LLCullResult::sg_list_t::iterator i = gPipeline.beginAlphaGroups(); i != gPipeline.endAlphaGroups(); ++i)
-	{
-		LLSpatialGroup* group = *i;
-		if (group->mSpatialPartition->mRenderByGroup &&
-			!group->isDead())
-		{
-			renderGroupAlpha(group,LLRenderPass::PASS_ALPHA,mask,TRUE);
-		}
+							LLVertexBuffer::MAP_TEXCOORD0);
 	}
 }
 
@@ -169,7 +245,10 @@ void LLDrawPoolAlpha::renderAlphaHighlight(U32 mask)
 				}
 
 				LLRenderPass::applyModelMatrix(params);
-
+				if (params.mGroup)
+				{
+					params.mGroup->rebuildMesh();
+				}
 				params.mVertexBuffer->setBuffer(mask);
 				params.mVertexBuffer->drawRange(LLRender::TRIANGLES, params.mStart, params.mEnd, params.mCount, params.mOffset);
 				gPipeline.addTrianglesDrawn(params.mCount/3);
@@ -178,40 +257,15 @@ void LLDrawPoolAlpha::renderAlphaHighlight(U32 mask)
 	}
 }
 
-void LLDrawPoolAlpha::renderGroupAlpha(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture)
+void LLDrawPoolAlpha::renderAlpha(U32 mask)
 {
 	BOOL initialized_lighting = FALSE;
 	BOOL light_enabled = TRUE;
-	BOOL is_particle = FALSE;
+	//BOOL is_particle = FALSE;
 	BOOL use_shaders = (LLPipeline::sUnderWaterRender && gPipeline.canUseVertexShaders())
 		|| gPipeline.canUseWindLightShadersOnObjects();
-	F32 dist;
-
-	// check to see if it's a particle and if it's "close"
-	is_particle = !LLPipeline::sUnderWaterRender && (group->mSpatialPartition->mDrawableType == LLPipeline::RENDER_TYPE_PARTICLES);
-	dist = group->mDistance;
 	
-	// don't use shader if debug setting is off and it's close or if it's a particle
-	// and it's close
-	if(is_particle && !gSavedSettings.getBOOL("RenderUseShaderNearParticles"))
-	{
-		if((dist < LLViewerCamera::getInstance()->getFar() * gSavedSettings.getF32("RenderShaderParticleThreshold")))
-		{
-			use_shaders = FALSE;
-		}
-	}
-
-	LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[type];
-
-	if (group->mSpatialPartition->mDrawableType == LLPipeline::RENDER_TYPE_CLOUDS)
-	{		
-		if (!gSavedSettings.getBOOL("SkyUseClassicClouds"))
-		{
-			return;
-		}
-		gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
-	}
-	else
+	// check to see if it's a particle and if it's "close"
 	{
 		if (LLPipeline::sImpostorRender)
 		{
@@ -223,79 +277,109 @@ void LLDrawPoolAlpha::renderGroupAlpha(LLSpatialGroup* group, U32 type, U32 mask
 		}
 	}
 
-	for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k)	
+	for (LLCullResult::sg_list_t::iterator i = gPipeline.beginAlphaGroups(); i != gPipeline.endAlphaGroups(); ++i)
 	{
-		LLDrawInfo& params = **k;
-
-		LLRenderPass::applyModelMatrix(params);
-
-		if (texture && params.mTexture.notNull())
+		LLSpatialGroup* group = *i;
+		if (group->mSpatialPartition->mRenderByGroup &&
+			!group->isDead())
 		{
-			gGL.getTexUnit(0)->activate();
-			gGL.getTexUnit(0)->bind(params.mTexture.get());
-			params.mTexture->addTextureStats(params.mVSize);
-			if (params.mTextureMatrix)
-			{
-				glMatrixMode(GL_TEXTURE);
-				glLoadMatrixf((GLfloat*) params.mTextureMatrix->mMatrix);
-				gPipeline.mTextureMatrixOps++;
-			}
-		}
+			LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[LLRenderPass::PASS_ALPHA];
 
-		if (params.mFullbright)
-		{
-			// Turn off lighting if it hasn't already been so.
-			if (light_enabled || !initialized_lighting)
+			for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k)	
 			{
-				initialized_lighting = TRUE;
-				if (use_shaders) 
+				LLDrawInfo& params = **k;
+
+				LLRenderPass::applyModelMatrix(params);
+
+				if (params.mTexture.notNull())
 				{
-					target_shader = fullbright_shader;
+					gGL.getTexUnit(0)->activate();
+					gGL.getTexUnit(0)->bind(params.mTexture.get());
+					params.mTexture->addTextureStats(params.mVSize);
+					if (params.mTextureMatrix)
+					{
+						glMatrixMode(GL_TEXTURE);
+						glLoadMatrixf((GLfloat*) params.mTextureMatrix->mMatrix);
+						gPipeline.mTextureMatrixOps++;
+					}
 				}
-				else
+
+				if (params.mFullbright)
 				{
-					gPipeline.enableLightsFullbright(LLColor4(1,1,1,1));
+					// Turn off lighting if it hasn't already been so.
+					if (light_enabled || !initialized_lighting)
+					{
+						initialized_lighting = TRUE;
+						if (use_shaders) 
+						{
+							target_shader = fullbright_shader;
+						}
+						else
+						{
+							gPipeline.enableLightsFullbright(LLColor4(1,1,1,1));
+						}
+						light_enabled = FALSE;
+					}
+				}
+				// Turn on lighting if it isn't already.
+				else if (!light_enabled || !initialized_lighting)
+				{
+					initialized_lighting = TRUE;
+					if (use_shaders) 
+					{
+						target_shader = simple_shader;
+					}
+					else
+					{
+						gPipeline.enableLightsDynamic();
+					}
+					light_enabled = TRUE;
 				}
-				light_enabled = FALSE;
-			}
-		}
-		// Turn on lighting if it isn't already.
-		else if (!light_enabled || !initialized_lighting)
-		{
-			initialized_lighting = TRUE;
-			if (use_shaders) 
-			{
-				target_shader = simple_shader;
-			}
-			else
-			{
-				gPipeline.enableLightsDynamic();
-			}
-			light_enabled = TRUE;
-		}
 
-		// If we need shaders, and we're not ALREADY using the proper shader, then bind it
-		// (this way we won't rebind shaders unnecessarily).
-		if(use_shaders && (current_shader != target_shader))
-		{
-			llassert(target_shader != NULL);
-			current_shader = target_shader;
-			current_shader->bind();
-		}
-		else if (!use_shaders && current_shader != NULL)
-		{
-			LLGLSLShader::bindNoShader();
-			current_shader = NULL;
-		}
+				// If we need shaders, and we're not ALREADY using the proper shader, then bind it
+				// (this way we won't rebind shaders unnecessarily).
+				if(use_shaders && (current_shader != target_shader))
+				{
+					llassert(target_shader != NULL);
+					if (deferred_render && current_shader != NULL)
+					{
+						gPipeline.unbindDeferredShader(*current_shader);
+					}
+					current_shader = target_shader;
+					if (deferred_render)
+					{
+						gPipeline.bindDeferredShader(*current_shader);
+					}
+					else
+					{
+						current_shader->bind();
+					}
+				}
+				else if (!use_shaders && current_shader != NULL)
+				{
+					LLGLSLShader::bindNoShader();
+					if (deferred_render)
+					{
+						gPipeline.unbindDeferredShader(*current_shader);
+					}
+					current_shader = NULL;
+				}
 
-		params.mVertexBuffer->setBuffer(mask);
-		params.mVertexBuffer->drawRange(LLRender::TRIANGLES, params.mStart, params.mEnd, params.mCount, params.mOffset);
-		gPipeline.addTrianglesDrawn(params.mCount/3);
+				if (params.mGroup)
+				{
+					params.mGroup->rebuildMesh();
+				}
+				params.mVertexBuffer->setBuffer(mask);
+				params.mVertexBuffer->drawRange(LLRender::TRIANGLES, params.mStart, params.mEnd, params.mCount, params.mOffset);
+				gPipeline.addTrianglesDrawn(params.mCount/3);
 
-		if (params.mTextureMatrix && texture && params.mTexture.notNull())
-		{
-			glLoadIdentity();
-			glMatrixMode(GL_MODELVIEW);
+				if (params.mTextureMatrix && params.mTexture.notNull())
+				{
+					gGL.getTexUnit(0)->activate();
+					glLoadIdentity();
+					glMatrixMode(GL_MODELVIEW);
+				}
+			}
 		}
 	}
 
diff --git a/indra/newview/lldrawpoolalpha.h b/indra/newview/lldrawpoolalpha.h
index bae3c6f2252f94e57c08980ec9269f158356cc4e..3aa752f72c58f69d24c727239fc62bbf9b04185a 100644
--- a/indra/newview/lldrawpoolalpha.h
+++ b/indra/newview/lldrawpoolalpha.h
@@ -48,13 +48,23 @@ class LLDrawPoolAlpha: public LLRenderPass
 		VERTEX_DATA_MASK =	LLVertexBuffer::MAP_VERTEX |
 							LLVertexBuffer::MAP_NORMAL |
 							LLVertexBuffer::MAP_COLOR |
-							LLVertexBuffer::MAP_TEXCOORD
+							LLVertexBuffer::MAP_TEXCOORD0
 	};
 	virtual U32 getVertexDataMask() { return VERTEX_DATA_MASK; }
 
 	LLDrawPoolAlpha(U32 type = LLDrawPool::POOL_ALPHA);
 	/*virtual*/ ~LLDrawPoolAlpha();
 
+	/*virtual*/ S32 getNumDeferredPasses();
+	/*virtual*/ void beginDeferredPass(S32 pass);
+	/*virtual*/ void endDeferredPass(S32 pass);
+	/*virtual*/ void renderDeferred(S32 pass);
+
+	/*virtual*/ S32 getNumPostDeferredPasses();
+	/*virtual*/ void beginPostDeferredPass(S32 pass);
+	/*virtual*/ void endPostDeferredPass(S32 pass);
+	/*virtual*/ void renderPostDeferred(S32 pass);
+
 	/*virtual*/ void beginRenderPass(S32 pass = 0);
 	/*virtual*/ void endRenderPass( S32 pass );
 	/*virtual*/ S32	 getNumPasses() { return 1; }
diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp
index 563f537b11317a874abf0a8b7a9c37e32167912c..9db91975005f23babee63fd98ba454a3dca2e23f 100644
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -48,12 +48,19 @@
 #include "pipeline.h"
 #include "llviewershadermgr.h"
 #include "llappviewer.h"
+#include "llrendersphere.h"
+#include "llviewerpartsim.h"
 
 static U32 sDataMask = LLDrawPoolAvatar::VERTEX_DATA_MASK;
 static U32 sBufferUsage = GL_STREAM_DRAW_ARB;
 static U32 sShaderLevel = 0;
 static LLGLSLShader* sVertexProgram = NULL;
 
+BOOL	LLDrawPoolAvatar::sSkipOpaque = FALSE;
+BOOL	LLDrawPoolAvatar::sSkipTransparent = FALSE;
+
+extern BOOL gUseGLPick;
+
 F32 CLOTHING_GRAVITY_EFFECT = 0.7f;
 F32 CLOTHING_ACCEL_FORCE_FACTOR = 0.2f;
 const S32 NUM_TEST_AVATARS = 30;
@@ -85,6 +92,8 @@ S32 AVATAR_VERTEX_BYTES = 48;
 
 BOOL gAvatarEmbossBumpMap = FALSE;
 static BOOL sRenderingSkinned = FALSE;
+S32 normal_channel = -1;
+S32 specular_channel = -1;
 
 LLDrawPoolAvatar::LLDrawPoolAvatar() :
 LLFacePool(POOL_AVATAR)
@@ -111,6 +120,7 @@ S32 LLDrawPoolAvatar::getVertexShaderLevel() const
 void LLDrawPoolAvatar::prerender()
 {
 	mVertexShaderLevel = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_AVATAR);
+	
 	sShaderLevel = mVertexShaderLevel;
 	
 	if (sShaderLevel > 0)
@@ -139,6 +149,177 @@ LLMatrix4& LLDrawPoolAvatar::getModelView()
 // render()
 //-----------------------------------------------------------------------------
 
+
+S32 LLDrawPoolAvatar::getNumDeferredPasses()
+{
+	return getNumPasses();
+}
+
+void LLDrawPoolAvatar::beginDeferredPass(S32 pass)
+{
+	LLFastTimer t(LLFastTimer::FTM_RENDER_CHARACTERS);
+	
+	if (LLPipeline::sImpostorRender)
+	{
+		beginDeferredSkinned();
+		return;
+	}
+
+	switch (pass)
+	{
+	case 0:
+		beginDeferredImpostor();
+		break;
+	case 1:
+		beginDeferredRigid();
+		break;
+	case 2:
+		beginDeferredSkinned();
+		break;
+	}
+}
+
+void LLDrawPoolAvatar::endDeferredPass(S32 pass)
+{
+	LLFastTimer t(LLFastTimer::FTM_RENDER_CHARACTERS);
+
+	if (LLPipeline::sImpostorRender)
+	{
+		endDeferredSkinned();
+		return;
+	}
+
+	switch (pass)
+	{
+	case 0:
+		endDeferredImpostor();
+		break;
+	case 1:
+		endDeferredRigid();
+		break;
+	case 2:
+		endDeferredSkinned();
+		break;
+	}
+}
+
+void LLDrawPoolAvatar::renderDeferred(S32 pass)
+{
+	render(pass);
+}
+
+S32 LLDrawPoolAvatar::getNumPostDeferredPasses()
+{
+	return 1;
+}
+
+void LLDrawPoolAvatar::beginPostDeferredPass(S32 pass)
+{
+	sSkipOpaque = TRUE;
+	sShaderLevel = mVertexShaderLevel;
+	sVertexProgram = &gDeferredAvatarAlphaProgram;
+
+	sRenderingSkinned = TRUE;
+
+	gPipeline.bindDeferredShader(*sVertexProgram);
+	
+	enable_vertex_weighting(sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_WEIGHT]);
+}
+
+void LLDrawPoolAvatar::endPostDeferredPass(S32 pass)
+{
+	// if we're in software-blending, remember to set the fence _after_ we draw so we wait till this rendering is done
+	sRenderingSkinned = FALSE;
+	sSkipOpaque = FALSE;
+	disable_vertex_weighting(sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_WEIGHT]);
+	
+	gPipeline.unbindDeferredShader(*sVertexProgram);
+
+	sShaderLevel = mVertexShaderLevel;
+}
+
+void LLDrawPoolAvatar::renderPostDeferred(S32 pass)
+{
+	render(2); //pass 2 = skinned
+}
+
+
+S32 LLDrawPoolAvatar::getNumShadowPasses()
+{
+	return 1;
+}
+
+void LLDrawPoolAvatar::beginShadowPass(S32 pass)
+{
+	LLFastTimer t(LLFastTimer::FTM_SHADOW_AVATAR);
+	
+	sVertexProgram = &gDeferredAvatarShadowProgram;
+	if (sShaderLevel > 0)
+	{
+		gAvatarMatrixParam = sVertexProgram->mUniform[LLViewerShaderMgr::AVATAR_MATRIX];
+	}
+	gGL.setAlphaRejectSettings(LLRender::CF_GREATER_EQUAL, 0.2f);
+	
+	glColor4f(1,1,1,1);
+
+	if ((sShaderLevel > 0))  // for hardware blending
+	{
+		sRenderingSkinned = TRUE;
+		sVertexProgram->bind();
+		enable_vertex_weighting(sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_WEIGHT]);
+	}
+
+}
+
+void LLDrawPoolAvatar::endShadowPass(S32 pass)
+{
+	LLFastTimer t(LLFastTimer::FTM_SHADOW_AVATAR);
+
+	if (sShaderLevel > 0)
+	{
+		sRenderingSkinned = FALSE;
+		sVertexProgram->unbind();
+		disable_vertex_weighting(sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_WEIGHT]);
+	}
+
+	gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
+}
+
+void LLDrawPoolAvatar::renderShadow(S32 pass)
+{
+	LLFastTimer t(LLFastTimer::FTM_SHADOW_AVATAR);
+	if (!gRenderAvatar)
+	{
+		return;
+	}
+
+	if (mDrawFace.empty())
+	{
+		return;
+	}
+
+	const LLFace *facep = mDrawFace[0];
+	if (!facep->getDrawable())
+	{
+		return;
+	}
+	LLVOAvatar *avatarp = (LLVOAvatar *)facep->getDrawable()->getVObj().get();
+
+	if (avatarp->isDead() || avatarp->mIsDummy || avatarp->mDrawable.isNull())
+	{
+		return;
+	}
+
+	BOOL impostor = avatarp->isImpostor();
+	if (impostor)
+	{
+		return;
+	}
+	
+	avatarp->renderSkinned(AVATAR_RENDER_PASS_SINGLE);
+
+}
+
 S32 LLDrawPoolAvatar::getNumPasses()
 {
 	return LLPipeline::sImpostorRender ? 1 : 3;
@@ -254,6 +435,46 @@ void LLDrawPoolAvatar::endRigid()
 	}
 }
 
+void LLDrawPoolAvatar::beginDeferredImpostor()
+{
+	if (!LLPipeline::sReflectionRender)
+	{
+		LLVOAvatar::sRenderDistance = llclamp(LLVOAvatar::sRenderDistance, 16.f, 256.f);
+		LLVOAvatar::sNumVisibleAvatars = 0;
+	}
+
+	sVertexProgram = &gDeferredImpostorProgram;
+
+	normal_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::DEFERRED_NORMAL);
+	specular_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::SPECULAR_MAP);
+				
+	sVertexProgram->bind();
+}
+
+void LLDrawPoolAvatar::endDeferredImpostor()
+{
+	sShaderLevel = mVertexShaderLevel;
+	sVertexProgram->disableTexture(LLViewerShaderMgr::DEFERRED_NORMAL);
+	sVertexProgram->disableTexture(LLViewerShaderMgr::SPECULAR_MAP);
+	sVertexProgram->unbind();
+	gGL.getTexUnit(0)->activate();
+}
+
+void LLDrawPoolAvatar::beginDeferredRigid()
+{
+	sVertexProgram = &gDeferredDiffuseProgram;
+				
+	sVertexProgram->bind();
+}
+
+void LLDrawPoolAvatar::endDeferredRigid()
+{
+	sShaderLevel = mVertexShaderLevel;
+	sVertexProgram->unbind();
+	gGL.getTexUnit(0)->activate();
+}
+
+
 void LLDrawPoolAvatar::beginSkinned()
 {
 	if (sShaderLevel > 0)
@@ -283,7 +504,7 @@ void LLDrawPoolAvatar::beginSkinned()
 	if (sShaderLevel > 0)  // for hardware blending
 	{
 		sRenderingSkinned = TRUE;
-		
+
 		sVertexProgram->bind();
 		if (sShaderLevel >= SHADER_LEVEL_CLOTH)
 		{
@@ -344,6 +565,34 @@ void LLDrawPoolAvatar::endSkinned()
 	gGL.getTexUnit(0)->activate();
 }
 
+void LLDrawPoolAvatar::beginDeferredSkinned()
+{
+	sSkipTransparent = TRUE;
+	sShaderLevel = mVertexShaderLevel;
+	sVertexProgram = &gDeferredAvatarProgram;
+
+	sRenderingSkinned = TRUE;
+
+	sVertexProgram->bind();
+	
+	enable_vertex_weighting(sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_WEIGHT]);
+
+	gGL.getTexUnit(0)->activate();
+}
+
+void LLDrawPoolAvatar::endDeferredSkinned()
+{
+	sSkipTransparent = FALSE;
+	// if we're in software-blending, remember to set the fence _after_ we draw so we wait till this rendering is done
+	sRenderingSkinned = FALSE;
+	disable_vertex_weighting(sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_WEIGHT]);
+	sVertexProgram->unbind();
+
+	sShaderLevel = mVertexShaderLevel;
+
+	gGL.getTexUnit(0)->activate();
+}
+
 
 void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass)
 {
@@ -393,27 +642,25 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass)
 		return;
 	}
 
-	if (!single_avatar && !avatarp->isFullyLoaded())
+	if (!single_avatar && !avatarp->isFullyLoaded() )
 	{
-		
-		/* // debug code to draw a cube in place of avatar
-		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-		LLVector3 pos = avatarp->getPositionAgent();
-
-		gGL.color4f(1.0f, 0.0f, 0.0f, 0.8f);
-		gGL.begin(GL_LINES);
+		if (pass==1 && (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES) || LLViewerPartSim::getMaxPartCount() <= 0))
 		{
-			gGL.vertex3fv((pos - LLVector3(0.2f, 0.f, 0.f)).mV);
-			gGL.vertex3fv((pos + LLVector3(0.2f, 0.f, 0.f)).mV);
-			gGL.vertex3fv((pos - LLVector3(0.f, 0.2f, 0.f)).mV);
-			gGL.vertex3fv((pos + LLVector3(0.f, 0.2f, 0.f)).mV);
-			gGL.vertex3fv((pos - LLVector3(0.f, 0.f, 0.2f)).mV);
-			gGL.vertex3fv((pos + LLVector3(0.f, 0.f, 0.2f)).mV);
+			// debug code to draw a sphere in place of avatar
+			gGL.getTexUnit(0)->bind(LLViewerImage::sWhiteImagep.get());
+			gGL.setColorMask(true, true);
+			LLVector3 pos = avatarp->getPositionAgent();
+			gGL.color4f(1.0f, 1.0f, 1.0f, 0.7f);
+			
+			gGL.pushMatrix();	 
+			gGL.translatef((F32)(pos.mV[VX]),	 
+						   (F32)(pos.mV[VY]),	 
+							(F32)(pos.mV[VZ]));	 
+			 gGL.scalef(0.15f, 0.15f, 0.3f);	 
+			 gSphere.render();	 
+			 gGL.popMatrix();
+			 gGL.setColorMask(true, false);
 		}
-		gGL.end();
-		*/
-
-		
 		// don't render please
 		return;
 	}
@@ -441,9 +688,20 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass)
 
 		if (impostor)
 		{
+			if (LLPipeline::sRenderDeferred && avatarp->mImpostor.isComplete()) 
+			{
+				if (normal_channel > -1)
+				{
+					avatarp->mImpostor.bindTexture(2, normal_channel);
+				}
+				if (specular_channel > -1)
+				{
+					avatarp->mImpostor.bindTexture(1, specular_channel);
+				}
+			}
 			avatarp->renderImpostor();
 		}
-		else if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FOOT_SHADOWS))
+		else if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FOOT_SHADOWS) && !LLPipeline::sRenderDeferred)
 		{
 			avatarp->renderFootShadows();	
 		}
@@ -680,11 +938,7 @@ void LLVertexBufferAvatar::setupVertexBuffer(U32 data_mask) const
 
 		glVertexPointer(3,GL_FLOAT, mStride, (void*)(base + 0));
 		glNormalPointer(GL_FLOAT, mStride, (void*)(base + mOffsets[TYPE_NORMAL]));
-	
-		glClientActiveTextureARB(GL_TEXTURE1_ARB);
-		glTexCoordPointer(2,GL_FLOAT, mStride, (void*)(base + mOffsets[TYPE_TEXCOORD2]));
-		glClientActiveTextureARB(GL_TEXTURE0_ARB);
-		glTexCoordPointer(2,GL_FLOAT, mStride, (void*)(base + mOffsets[TYPE_TEXCOORD]));
+		glTexCoordPointer(2,GL_FLOAT, mStride, (void*)(base + mOffsets[TYPE_TEXCOORD0]));
 		
 		set_vertex_weights(sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_WEIGHT], mStride, (F32*)(base + mOffsets[TYPE_WEIGHT]));
 
diff --git a/indra/newview/lldrawpoolavatar.h b/indra/newview/lldrawpoolavatar.h
index 9df510f1e0243149ff42f0a8abb9a09f9b4cf1fa..0dc95ff5360585ab3a34fef265b441828d3ca53f 100644
--- a/indra/newview/lldrawpoolavatar.h
+++ b/indra/newview/lldrawpoolavatar.h
@@ -52,7 +52,7 @@ class LLDrawPoolAvatar : public LLFacePool
 	{
 		VERTEX_DATA_MASK =	LLVertexBuffer::MAP_VERTEX |
 							LLVertexBuffer::MAP_NORMAL |
-							LLVertexBuffer::MAP_TEXCOORD |
+							LLVertexBuffer::MAP_TEXCOORD0 |
 							LLVertexBuffer::MAP_WEIGHT |
 							LLVertexBuffer::MAP_CLOTHWEIGHT
 	};
@@ -74,6 +74,21 @@ class LLDrawPoolAvatar : public LLFacePool
 	/*virtual*/ void render(S32 pass = 0);
 	/*virtual*/ void renderForSelect();
 
+	/*virtual*/ S32 getNumDeferredPasses();
+	/*virtual*/ void beginDeferredPass(S32 pass);
+	/*virtual*/ void endDeferredPass(S32 pass);
+	/*virtual*/ void renderDeferred(S32 pass);
+
+	/*virtual*/ S32 getNumPostDeferredPasses();
+	/*virtual*/ void beginPostDeferredPass(S32 pass);
+	/*virtual*/ void endPostDeferredPass(S32 pass);
+	/*virtual*/ void renderPostDeferred(S32 pass);
+
+	/*virtual*/ S32 getNumShadowPasses();
+	/*virtual*/ void beginShadowPass(S32 pass);
+	/*virtual*/ void endShadowPass(S32 pass);
+	/*virtual*/ void renderShadow(S32 pass);
+
 	void beginRigid();
 	void beginFootShadow();
 	void beginSkinned();
@@ -81,11 +96,22 @@ class LLDrawPoolAvatar : public LLFacePool
 	void endRigid();
 	void endFootShadow();
 	void endSkinned();
+
+	void beginDeferredImpostor();
+	void beginDeferredRigid();
+	void beginDeferredSkinned();
+	
+	void endDeferredImpostor();
+	void endDeferredRigid();
+	void endDeferredSkinned();
 		
 	/*virtual*/ LLViewerImage *getDebugTexture();
 	/*virtual*/ LLColor3 getDebugColor() const; // For AGP debug display
 
 	void renderAvatars(LLVOAvatar *single_avatar, S32 pass = -1); // renders only one avatar if single_avatar is not null.
+
+	static BOOL sSkipOpaque;
+	static BOOL sSkipTransparent;
 };
 
 
diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp
index 60c41159d28e0f4b052b013a68d9b2543018bfd6..b11dcc1608a3645ba8fee8aaa1fe36a009d26ea5 100644
--- a/indra/newview/lldrawpoolbump.cpp
+++ b/indra/newview/lldrawpoolbump.cpp
@@ -71,13 +71,14 @@ LLBumpImageList gBumpImageList;
 const S32 STD_BUMP_LATEST_FILE_VERSION = 1;
 
 const U32 VERTEX_MASK_SHINY = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_COLOR;
-const U32 VERTEX_MASK_BUMP = LLVertexBuffer::MAP_VERTEX |LLVertexBuffer::MAP_TEXCOORD | LLVertexBuffer::MAP_TEXCOORD2;
+const U32 VERTEX_MASK_BUMP = LLVertexBuffer::MAP_VERTEX |LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TEXCOORD1;
 
 U32 LLDrawPoolBump::sVertexMask = VERTEX_MASK_SHINY;
 
 static LLGLSLShader* shader = NULL;
 static S32 cube_channel = -1;
 static S32 diffuse_channel = -1;
+static S32 bump_channel = -1;
 
 // static 
 void LLStandardBumpmap::init()
@@ -146,7 +147,8 @@ void LLStandardBumpmap::restoreGL()
 										TRUE, 
 										FALSE, 
 										0, 
-										0);
+										0);																								
+		gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mImage->setLoadedCallback(LLBumpImageList::onSourceStandardLoaded, 0, TRUE, FALSE, NULL );
 		LLStandardBumpmap::sStandardBumpmapCount++;
 	}
 
@@ -318,7 +320,7 @@ void LLDrawPoolBump::beginShiny(bool invisible)
 	// Second pass: environment map
 	if (!invisible && mVertexShaderLevel > 1)
 	{
-		sVertexMask = VERTEX_MASK_SHINY | LLVertexBuffer::MAP_TEXCOORD;
+		sVertexMask = VERTEX_MASK_SHINY | LLVertexBuffer::MAP_TEXCOORD0;
 	}
 	
 	if (LLPipeline::sUnderWaterRender)
@@ -432,15 +434,7 @@ void LLDrawPoolBump::endShiny(bool invisible)
 					shader->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
 				}
 			}
-
 			shader->unbind();
-			gGL.getTexUnit(0)->activate();
-			gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
-		}
-		if (cube_channel >= 0)
-		{
-			gGL.getTexUnit(cube_channel)->enable(LLTexUnit::TT_TEXTURE);
-			gGL.getTexUnit(cube_channel)->setTextureBlendType(LLTexUnit::TB_MULT);
 		}
 	}
 	gGL.getTexUnit(diffuse_channel)->disable();
@@ -462,7 +456,7 @@ void LLDrawPoolBump::beginFullbrightShiny()
 		return;
 	}
 
-	sVertexMask = VERTEX_MASK_SHINY | LLVertexBuffer::MAP_TEXCOORD;
+	sVertexMask = VERTEX_MASK_SHINY | LLVertexBuffer::MAP_TEXCOORD0;
 
 	// Second pass: environment map
 	
@@ -561,6 +555,10 @@ void LLDrawPoolBump::renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL
 		
 		applyModelMatrix(params);
 
+		if (params.mGroup)
+		{
+			params.mGroup->rebuildMesh();
+		}
 		params.mVertexBuffer->setBuffer(mask);
 		params.mVertexBuffer->drawRange(LLRender::TRIANGLES, params.mStart, params.mEnd, params.mCount, params.mOffset);
 		gPipeline.addTrianglesDrawn(params.mCount/3);
@@ -569,7 +567,7 @@ void LLDrawPoolBump::renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL
 
 
 // static
-BOOL LLDrawPoolBump::bindBumpMap(LLDrawInfo& params)
+BOOL LLDrawPoolBump::bindBumpMap(LLDrawInfo& params, S32 channel)
 {
 	LLImageGL* bump = NULL;
 
@@ -600,10 +598,19 @@ BOOL LLDrawPoolBump::bindBumpMap(LLDrawInfo& params)
 
 	if (bump)
 	{
-		gGL.getTexUnit(1)->bind(bump);
-		gGL.getTexUnit(0)->bind(bump);
+		if (channel == -2)
+		{
+			gGL.getTexUnit(1)->bind(bump);
+			gGL.getTexUnit(0)->bind(bump);
+		}
+		else
+		{
+			gGL.getTexUnit(channel)->bind(bump);
+		}
+
 		return TRUE;
 	}
+	
 	return FALSE;
 }
 
@@ -691,6 +698,73 @@ void LLDrawPoolBump::endBump()
 	gGL.setSceneBlendType(LLRender::BT_ALPHA);
 }
 
+void LLDrawPoolBump::beginDeferredPass(S32 pass)
+{
+	if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_BUMP))
+	{
+		return;
+	}
+	LLFastTimer ftm(LLFastTimer::FTM_RENDER_BUMP);
+	mShiny = TRUE;
+	gDeferredBumpProgram.bind();
+	diffuse_channel = gDeferredBumpProgram.enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+	bump_channel = gDeferredBumpProgram.enableTexture(LLViewerShaderMgr::BUMP_MAP);
+	gGL.getTexUnit(diffuse_channel)->unbind(LLTexUnit::TT_TEXTURE);
+	gGL.getTexUnit(bump_channel)->unbind(LLTexUnit::TT_TEXTURE);
+}
+
+void LLDrawPoolBump::endDeferredPass(S32 pass)
+{
+	if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_BUMP))
+	{
+		return;
+	}
+	LLFastTimer ftm(LLFastTimer::FTM_RENDER_BUMP);
+	mShiny = FALSE;
+	gDeferredBumpProgram.disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+	gDeferredBumpProgram.disableTexture(LLViewerShaderMgr::BUMP_MAP);
+	gDeferredBumpProgram.unbind();
+	gGL.getTexUnit(0)->activate();
+}
+
+void LLDrawPoolBump::renderDeferred(S32 pass)
+{
+	if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_BUMP))
+	{
+		return;
+	}
+	LLFastTimer ftm(LLFastTimer::FTM_RENDER_BUMP);
+
+	U32 type = LLRenderPass::PASS_BUMP;
+	LLCullResult::drawinfo_list_t::iterator begin = gPipeline.beginRenderMap(type);
+	LLCullResult::drawinfo_list_t::iterator end = gPipeline.endRenderMap(type);
+
+	U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_BINORMAL | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_COLOR;
+	
+	for (LLCullResult::drawinfo_list_t::iterator i = begin; i != end; ++i)	
+	{
+		LLDrawInfo& params = **i;
+
+		LLDrawPoolBump::bindBumpMap(params, bump_channel);
+		pushBatch(params, mask, TRUE);
+	}
+}
+
+void LLDrawPoolBump::beginPostDeferredPass(S32 pass)
+{
+	beginFullbrightShiny();
+}
+
+void LLDrawPoolBump::endPostDeferredPass(S32 pass)
+{
+	endFullbrightShiny();
+}
+
+void LLDrawPoolBump::renderPostDeferred(S32 pass)
+{
+	renderFullbrightShiny();
+}
+
 ////////////////////////////////////////////////////////////////
 // List of one-component bump-maps created from other texures.
 
@@ -748,6 +822,7 @@ void LLBumpImageList::addTextureStats(U8 bump, const LLUUID& base_image_id, F32
 
 void LLBumpImageList::updateImages()
 {	
+	llpushcallstacks ;
 	for (bump_image_map_t::iterator iter = mBrightnessEntries.begin(); iter != mBrightnessEntries.end(); )
 	{
 		bump_image_map_t::iterator curiter = iter++;
@@ -774,7 +849,7 @@ void LLBumpImageList::updateImages()
 			}
 		}
 	}
-
+	llpushcallstacks ;
 	for (bump_image_map_t::iterator iter = mDarknessEntries.begin(); iter != mDarknessEntries.end(); )
 	{
 		bump_image_map_t::iterator curiter = iter++;
@@ -801,7 +876,7 @@ void LLBumpImageList::updateImages()
 			}
 		}
 	}
-
+	llpushcallstacks ;
 }
 
 
@@ -886,6 +961,71 @@ void LLBumpImageList::onSourceDarknessLoaded( BOOL success, LLViewerImage *src_v
 	}
 }
 
+void LLBumpImageList::onSourceStandardLoaded( BOOL success, LLViewerImage* src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata)
+{
+	if (success && LLPipeline::sRenderDeferred)
+	{
+		LLPointer<LLImageRaw> nrm_image = new LLImageRaw(src->getWidth(), src->getHeight(), 4);
+		generateNormalMapFromAlpha(src, nrm_image);
+		src_vi->setExplicitFormat(GL_RGBA, GL_RGBA);
+		src_vi->createGLTexture(0, nrm_image);
+	}
+}
+
+void LLBumpImageList::generateNormalMapFromAlpha(LLImageRaw* src, LLImageRaw* nrm_image)
+{
+	U8* nrm_data = nrm_image->getData();
+	S32 resX = src->getWidth();
+	S32 resY = src->getHeight();
+
+	U8* src_data = src->getData();
+
+	S32 src_cmp = src->getComponents();
+
+	F32 norm_scale = gSavedSettings.getF32("RenderNormalMapScale");
+
+	U32 idx = 0;
+	//generate normal map from pseudo-heightfield
+	for (S32 j = 0; j < resY; ++j)
+	{
+		for (S32 i = 0; i < resX; ++i)
+		{
+			S32 rX = (i+1)%resX;
+			S32 rY = (j+1)%resY;
+			S32 lX = (i-1)%resX;
+			S32 lY = (j-1)%resY;
+
+			if (lX < 0)
+			{
+				lX += resX;
+			}
+			if (lY < 0)
+			{
+				lY += resY;
+			}
+
+			F32 cH = (F32) src_data[(j*resX+i)*src_cmp+src_cmp-1];
+
+			LLVector3 right = LLVector3(norm_scale, 0, (F32) src_data[(j*resX+rX)*src_cmp+src_cmp-1]-cH);
+			LLVector3 left = LLVector3(-norm_scale, 0, (F32) src_data[(j*resX+lX)*src_cmp+src_cmp-1]-cH);
+			LLVector3 up = LLVector3(0, -norm_scale, (F32) src_data[(rY*resX+i)*src_cmp+src_cmp-1]-cH);
+			LLVector3 down = LLVector3(0, norm_scale, (F32) src_data[(lY*resX+i)*src_cmp+src_cmp-1]-cH);
+
+			LLVector3 norm = right%down + down%left + left%up + up%right;
+		
+			norm.normVec();
+			
+			norm *= 0.5f;
+			norm += LLVector3(0.5f,0.5f,0.5f);
+
+			idx = (j*resX+i)*4;
+			nrm_data[idx+0]= (U8) (norm.mV[0]*255);
+			nrm_data[idx+1]= (U8) (norm.mV[1]*255);
+			nrm_data[idx+2]= (U8) (norm.mV[2]*255);
+			nrm_data[idx+3]= src_data[(j*resX+i)*src_cmp+src_cmp-1];
+		}
+	}
+}
 
 // static
 void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerImage *src_vi, LLImageRaw* src, LLUUID& source_asset_id, EBumpEffect bump_code )
@@ -1005,14 +1145,26 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerImage *src_vi, LLIma
 			}
 
 			//---------------------------------------------------
-			LLImageGL* bump = new LLImageGL( TRUE);
 			//immediately assign bump to a global smart pointer in case some local smart pointer
 			//accidently releases it.
+			LLPointer<LLImageGL> bump = new LLImageGL( TRUE);
+			
+			if (!LLPipeline::sRenderDeferred)
+			{
+				bump->setExplicitFormat(GL_ALPHA8, GL_ALPHA);
+				bump->createGLTexture(0, dst_image);
+			}
+			else
+			{
+				LLPointer<LLImageRaw> nrm_image = new LLImageRaw(src->getWidth(), src->getHeight(), 4);
+				generateNormalMapFromAlpha(src, nrm_image);
+				bump->setExplicitFormat(GL_RGBA, GL_RGBA);
+				bump->createGLTexture(0, nrm_image);
+			}
+
+			
 			iter->second = bump; // derefs (and deletes) old image
 			//---------------------------------------------------
-
-			bump->setExplicitFormat(GL_ALPHA8, GL_ALPHA);
-			bump->createGLTexture(0, dst_image);			
 		}
 		else
 		{
@@ -1040,21 +1192,6 @@ void LLDrawPoolBump::renderBump(U32 type, U32 mask)
 	}
 }
 
-void LLDrawPoolBump::renderGroupBump(LLSpatialGroup* group, U32 type, U32 mask)
-{					
-	LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[type];	
-	
-	for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k) 
-	{
-		LLDrawInfo& params = **k;
-		
-		if (LLDrawPoolBump::bindBumpMap(params))
-		{
-			pushBatch(params, mask, FALSE);
-		}
-	}
-}
-
 void LLDrawPoolBump::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture)
 {
 	applyModelMatrix(params);
@@ -1088,10 +1225,14 @@ void LLDrawPoolBump::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture)
 		}
 		else
 		{
-			gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+			gGL.getTexUnit(diffuse_channel)->unbind(LLTexUnit::TT_TEXTURE);
 		}
 	}
 	
+	if (params.mGroup)
+	{
+		params.mGroup->rebuildMesh();
+	}
 	params.mVertexBuffer->setBuffer(mask);
 	params.mVertexBuffer->drawRange(LLRender::TRIANGLES, params.mStart, params.mEnd, params.mCount, params.mOffset);
 	gPipeline.addTrianglesDrawn(params.mCount/3);
@@ -1131,3 +1272,33 @@ void LLDrawPoolInvisible::render(S32 pass)
 	}
 }
 
+void LLDrawPoolInvisible::beginDeferredPass(S32 pass)
+{
+	beginRenderPass(pass);
+}
+
+void LLDrawPoolInvisible::endDeferredPass( S32 pass )
+{
+	endRenderPass(pass);
+}
+
+void LLDrawPoolInvisible::renderDeferred( S32 pass )
+{ //render invisiprims; this doesn't work becaue it also blocks all the post-deferred stuff
+	LLFastTimer t(LLFastTimer::FTM_RENDER_INVISIBLE);
+  
+	U32 invisi_mask = LLVertexBuffer::MAP_VERTEX;
+	glStencilMask(0);
+	glStencilOp(GL_ZERO, GL_KEEP, GL_REPLACE);
+	gGL.setColorMask(false, false);
+	pushBatches(LLRenderPass::PASS_INVISIBLE, invisi_mask, FALSE);
+	gGL.setColorMask(true, true);
+	glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
+	glStencilMask(0xFFFFFFFF);
+	
+	if (gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY))
+	{
+		beginShiny(true);
+		renderShiny(true);
+		endShiny(true);
+	}
+}
diff --git a/indra/newview/lldrawpoolbump.h b/indra/newview/lldrawpoolbump.h
index f5cb0cb76949e2aace189777dc98b4163ac48703..34c1e9c29f40fcea2fbfa2a68252726ac692007c 100644
--- a/indra/newview/lldrawpoolbump.h
+++ b/indra/newview/lldrawpoolbump.h
@@ -49,7 +49,7 @@ protected :
 public:
 	static U32 sVertexMask;
 	BOOL mShiny;
-
+	
 	virtual U32 getVertexDataMask() { return sVertexMask; }
 
 	LLDrawPoolBump();
@@ -63,8 +63,7 @@ protected :
 
 	void renderBump(U32 type, U32 mask);
 	void renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture);
-	void renderGroupBump(LLSpatialGroup* group, U32 type, U32 mask);
-	
+		
 	S32 numBumpPasses();
 	
 	void beginShiny(bool invisible = false);
@@ -78,7 +77,18 @@ protected :
 	void beginBump();
 	void renderBump();
 	void endBump();
-	BOOL bindBumpMap(LLDrawInfo& params);
+
+	virtual S32 getNumDeferredPasses() { return 1; }
+	/*virtual*/ void beginDeferredPass(S32 pass);
+	/*virtual*/ void endDeferredPass(S32 pass);
+	/*virtual*/ void renderDeferred(S32 pass);
+
+	virtual S32 getNumPostDeferredPasses() { return 1; }
+	/*virtual*/ void beginPostDeferredPass(S32 pass);
+	/*virtual*/ void endPostDeferredPass(S32 pass);
+	/*virtual*/ void renderPostDeferred(S32 pass);
+
+	BOOL bindBumpMap(LLDrawInfo& params, S32 channel = -2);
 };
 
 enum EBumpEffect
@@ -136,6 +146,9 @@ class LLBumpImageList
 
 	static void onSourceBrightnessLoaded( BOOL success, LLViewerImage *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata );
 	static void onSourceDarknessLoaded( BOOL success, LLViewerImage *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata );
+	static void onSourceStandardLoaded( BOOL success, LLViewerImage *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata );
+	static void generateNormalMapFromAlpha(LLImageRaw* src, LLImageRaw* nrm_image);
+
 
 private:
 	static void onSourceLoaded( BOOL success, LLViewerImage *src_vi, LLImageRaw* src, LLUUID& source_asset_id, EBumpEffect bump );
@@ -166,6 +179,11 @@ class LLDrawPoolInvisible : public LLDrawPoolBump
 	virtual void beginRenderPass( S32 pass ) { }
 	virtual void endRenderPass( S32 pass ) { }
 	virtual S32	 getNumPasses() {return 1;}
+
+	virtual S32 getNumDeferredPasses() { return 1; }
+	/*virtual*/ void beginDeferredPass(S32 pass);
+	/*virtual*/ void endDeferredPass(S32 pass);
+	/*virtual*/ void renderDeferred(S32 pass);
 };
 
 
diff --git a/indra/newview/lldrawpoolclouds.h b/indra/newview/lldrawpoolclouds.h
index 0346e1aa4ef6681117b062a8c6c7d131fb9e6143..c70dd41f788fe3f883e1d432751db51bcfe426ba 100644
--- a/indra/newview/lldrawpoolclouds.h
+++ b/indra/newview/lldrawpoolclouds.h
@@ -42,7 +42,7 @@ class LLDrawPoolClouds : public LLDrawPool
 	{
 		VERTEX_DATA_MASK =	LLVertexBuffer::MAP_VERTEX |
 							LLVertexBuffer::MAP_NORMAL |
-							LLVertexBuffer::MAP_TEXCOORD
+							LLVertexBuffer::MAP_TEXCOORD0
 	};
 
 	BOOL addFace(LLFace* face);
diff --git a/indra/newview/lldrawpoolground.h b/indra/newview/lldrawpoolground.h
index 0badb59968c5b36021c01a9b1ebef8e5c47b5a38..6c7d20becaa0e5533f640da5ef80b53910097db0 100644
--- a/indra/newview/lldrawpoolground.h
+++ b/indra/newview/lldrawpoolground.h
@@ -42,7 +42,7 @@ class LLDrawPoolGround : public LLFacePool
 	enum
 	{
 		VERTEX_DATA_MASK =	LLVertexBuffer::MAP_VERTEX |
-							LLVertexBuffer::MAP_TEXCOORD
+							LLVertexBuffer::MAP_TEXCOORD0
 	};
 
 	virtual U32 getVertexDataMask() { return VERTEX_DATA_MASK; }
diff --git a/indra/newview/lldrawpoolsimple.cpp b/indra/newview/lldrawpoolsimple.cpp
index d4bdfc494a4f37f02f46bc33a523d782d0fcf1f6..1fdf87f6d26c521974968e8b9f341e32c2922f83 100644
--- a/indra/newview/lldrawpoolsimple.cpp
+++ b/indra/newview/lldrawpoolsimple.cpp
@@ -103,18 +103,15 @@ void LLDrawPoolSimple::beginRenderPass(S32 pass)
 	if (LLPipeline::sUnderWaterRender)
 	{
 		simple_shader = &gObjectSimpleWaterProgram;
-		fullbright_shader = &gObjectFullbrightWaterProgram;
 	}
 	else
 	{
 		simple_shader = &gObjectSimpleProgram;
-		fullbright_shader = &gObjectFullbrightProgram;
 	}
 
 	if (mVertexShaderLevel > 0)
 	{
 		simple_shader->bind();
-		simple_shader->uniform1f(LLViewerShaderMgr::FULLBRIGHT, 0.f);
 	}
 	else 
 	{
@@ -140,39 +137,204 @@ void LLDrawPoolSimple::endRenderPass(S32 pass)
 void LLDrawPoolSimple::render(S32 pass)
 {
 	LLGLDisable blend(GL_BLEND);
-	LLGLState alpha_test(GL_ALPHA_TEST, gPipeline.canUseWindLightShadersOnObjects());
-	gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f);
-
+	LLGLDisable alpha_test(GL_ALPHA_TEST);
+	
 	{ //render simple
 		LLFastTimer t(LLFastTimer::FTM_RENDER_SIMPLE);
 		gPipeline.enableLightsDynamic();
 		renderTexture(LLRenderPass::PASS_SIMPLE, getVertexDataMask());
+
+		if (LLPipeline::sRenderDeferred)
+		{
+			renderTexture(LLRenderPass::PASS_BUMP, getVertexDataMask());
+		}
 	}
+}
+
+//===============================
+//DEFERRED IMPLEMENTATION
+//===============================
+
+void LLDrawPoolSimple::beginDeferredPass(S32 pass)
+{
+	LLFastTimer t(LLFastTimer::FTM_RENDER_SIMPLE);
+	gDeferredDiffuseProgram.bind();
+}
+
+void LLDrawPoolSimple::endDeferredPass(S32 pass)
+{
+	LLFastTimer t(LLFastTimer::FTM_RENDER_SIMPLE);
+	LLRenderPass::endRenderPass(pass);
+
+	gDeferredDiffuseProgram.unbind();
+}
+
+void LLDrawPoolSimple::renderDeferred(S32 pass)
+{
+	LLGLDisable blend(GL_BLEND);
+	LLGLDisable alpha_test(GL_ALPHA_TEST);
+
+	{ //render simple
+		LLFastTimer t(LLFastTimer::FTM_RENDER_SIMPLE);
+		renderTexture(LLRenderPass::PASS_SIMPLE, getVertexDataMask());
+	}
+}
+
+// grass drawpool
+LLDrawPoolGrass::LLDrawPoolGrass() :
+ LLRenderPass(POOL_GRASS)
+{
+
+}
+
+void LLDrawPoolGrass::prerender()
+{
+	mVertexShaderLevel = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT);
+}
+
+
+void LLDrawPoolGrass::beginRenderPass(S32 pass)
+{
+	LLFastTimer t(LLFastTimer::FTM_RENDER_GRASS);
+
+	if (LLPipeline::sUnderWaterRender)
+	{
+		simple_shader = &gObjectSimpleWaterProgram;
+	}
+	else
+	{
+		simple_shader = &gObjectSimpleProgram;
+	}
+
+	if (mVertexShaderLevel > 0)
+	{
+		simple_shader->bind();
+	}
+	else 
+	{
+		// don't use shaders!
+		if (gGLManager.mHasShaderObjects)
+		{
+			LLGLSLShader::bindNoShader();
+		}		
+	}
+}
+
+void LLDrawPoolGrass::endRenderPass(S32 pass)
+{
+	LLFastTimer t(LLFastTimer::FTM_RENDER_GRASS);
+	LLRenderPass::endRenderPass(pass);
+
+	if (mVertexShaderLevel > 0)
+	{
+		simple_shader->unbind();
+	}
+}
+
+void LLDrawPoolGrass::render(S32 pass)
+{
+	LLGLDisable blend(GL_BLEND);
+	gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f);
 
 	{
 		LLFastTimer t(LLFastTimer::FTM_RENDER_GRASS);
 		LLGLEnable test(GL_ALPHA_TEST);
-		LLGLEnable blend(GL_BLEND);
 		gGL.setSceneBlendType(LLRender::BT_ALPHA);
 		//render grass
 		LLRenderPass::renderTexture(LLRenderPass::PASS_GRASS, getVertexDataMask());
 	}			
 
-	{ //render fullbright
-		if (mVertexShaderLevel > 0)
-		{
-			fullbright_shader->bind();
-			fullbright_shader->uniform1f(LLViewerShaderMgr::FULLBRIGHT, 1.f);
-		}
-		else
-		{
-			gPipeline.enableLightsFullbright(LLColor4(1,1,1,1));
-		}
-		LLFastTimer t(LLFastTimer::FTM_RENDER_FULLBRIGHT);
-		U32 fullbright_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD | LLVertexBuffer::MAP_COLOR;
-		renderTexture(LLRenderPass::PASS_FULLBRIGHT, fullbright_mask);
-	}
+	gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
+}
+
+void LLDrawPoolGrass::beginDeferredPass(S32 pass)
+{
+
+}
+
+void LLDrawPoolGrass::endDeferredPass(S32 pass)
+{
+
+}
+
+void LLDrawPoolGrass::renderDeferred(S32 pass)
+{
+	gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f);
+
+	{
+		LLFastTimer t(LLFastTimer::FTM_RENDER_GRASS);
+		gDeferredTreeProgram.bind();
+		LLGLEnable test(GL_ALPHA_TEST);
+		//render grass
+		LLRenderPass::renderTexture(LLRenderPass::PASS_GRASS, getVertexDataMask());
+	}			
 
 	gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
 }
 
+
+// Fullbright drawpool
+LLDrawPoolFullbright::LLDrawPoolFullbright() :
+	LLRenderPass(POOL_FULLBRIGHT)
+{
+}
+
+void LLDrawPoolFullbright::prerender()
+{
+	mVertexShaderLevel = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT);
+}
+
+void LLDrawPoolFullbright::beginRenderPass(S32 pass)
+{
+	LLFastTimer t(LLFastTimer::FTM_RENDER_FULLBRIGHT);
+	
+	if (LLPipeline::sUnderWaterRender)
+	{
+		fullbright_shader = &gObjectFullbrightWaterProgram;
+	}
+	else
+	{
+		fullbright_shader = &gObjectFullbrightProgram;
+	}
+}
+
+void LLDrawPoolFullbright::endRenderPass(S32 pass)
+{
+	LLFastTimer t(LLFastTimer::FTM_RENDER_FULLBRIGHT);
+	LLRenderPass::endRenderPass(pass);
+
+	if (mVertexShaderLevel > 0)
+	{
+		fullbright_shader->unbind();
+	}
+}
+
+void LLDrawPoolFullbright::render(S32 pass)
+{ //render fullbright
+	LLFastTimer t(LLFastTimer::FTM_RENDER_FULLBRIGHT);
+	if (mVertexShaderLevel > 0)
+	{
+		fullbright_shader->bind();
+		fullbright_shader->uniform1f(LLViewerShaderMgr::FULLBRIGHT, 1.f);
+	}
+	else
+	{
+		gPipeline.enableLightsFullbright(LLColor4(1,1,1,1));
+	}
+	
+	//gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.25f);
+	
+	//LLGLEnable test(GL_ALPHA_TEST);
+	//LLGLEnable blend(GL_BLEND);
+	gGL.setSceneBlendType(LLRender::BT_ALPHA);
+	U32 fullbright_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR;
+	renderTexture(LLRenderPass::PASS_FULLBRIGHT, fullbright_mask);
+
+	//gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
+}
+
+S32 LLDrawPoolFullbright::getNumPasses()
+{ 
+	return 1;
+}
+
diff --git a/indra/newview/lldrawpoolsimple.h b/indra/newview/lldrawpoolsimple.h
index 6702715b9ed3ada8b33363c2b6512cd9a56d6e6a..f561510375ce1e81ae2b94a833acf770de168c99 100644
--- a/indra/newview/lldrawpoolsimple.h
+++ b/indra/newview/lldrawpoolsimple.h
@@ -42,19 +42,77 @@ class LLDrawPoolSimple : public LLRenderPass
 	{
 		VERTEX_DATA_MASK =	LLVertexBuffer::MAP_VERTEX |
 							LLVertexBuffer::MAP_NORMAL |
-							LLVertexBuffer::MAP_TEXCOORD |
+							LLVertexBuffer::MAP_TEXCOORD0 |
 							LLVertexBuffer::MAP_COLOR
 	};
 	virtual U32 getVertexDataMask() { return VERTEX_DATA_MASK; }
 
 	LLDrawPoolSimple();
 	
+	/*virtual*/ S32 getNumDeferredPasses() { return 1; }
+	/*virtual*/ void beginDeferredPass(S32 pass);
+	/*virtual*/ void endDeferredPass(S32 pass);
+	/*virtual*/ void renderDeferred(S32 pass);
+
+	/*virtual*/ void beginRenderPass(S32 pass);
+	/*virtual*/ void endRenderPass(S32 pass);
+	/// We need two passes so we can handle emissive materials separately.
+	/*virtual*/ S32	 getNumPasses() { return 1; }
+	/*virtual*/ void render(S32 pass = 0);
+	/*virtual*/ void prerender();
+
+};
+
+class LLDrawPoolGrass : public LLRenderPass
+{
+public:
+	enum
+	{
+		VERTEX_DATA_MASK =	LLVertexBuffer::MAP_VERTEX |
+							LLVertexBuffer::MAP_NORMAL |
+							LLVertexBuffer::MAP_TEXCOORD0 |
+							LLVertexBuffer::MAP_COLOR
+	};
+	virtual U32 getVertexDataMask() { return VERTEX_DATA_MASK; }
+
+	LLDrawPoolGrass();
+	
+	/*virtual*/ S32 getNumDeferredPasses() { return 1; }
+	/*virtual*/ void beginDeferredPass(S32 pass);
+	/*virtual*/ void endDeferredPass(S32 pass);
+	/*virtual*/ void renderDeferred(S32 pass);
+
 	/*virtual*/ void beginRenderPass(S32 pass);
 	/*virtual*/ void endRenderPass(S32 pass);
 	/// We need two passes so we can handle emissive materials separately.
 	/*virtual*/ S32	 getNumPasses() { return 1; }
 	/*virtual*/ void render(S32 pass = 0);
 	/*virtual*/ void prerender();
+};
+
+class LLDrawPoolFullbright : public LLRenderPass
+{
+public:
+	enum
+	{
+		VERTEX_DATA_MASK =	LLVertexBuffer::MAP_VERTEX |
+							LLVertexBuffer::MAP_TEXCOORD0 |
+							LLVertexBuffer::MAP_COLOR
+	};
+	virtual U32 getVertexDataMask() { return VERTEX_DATA_MASK; }
+
+	LLDrawPoolFullbright();
+	
+	/*virtual*/ S32 getNumPostDeferredPasses() { return 1; }
+	/*virtual*/ void beginPostDeferredPass(S32 pass) { beginRenderPass(pass); }
+	/*virtual*/ void endPostDeferredPass(S32 pass) { endRenderPass(pass); }
+	/*virtual*/ void renderPostDeferred(S32 pass) { render(pass); }
+
+	/*virtual*/ void beginRenderPass(S32 pass);
+	/*virtual*/ void endRenderPass(S32 pass);
+	/*virtual*/ S32	 getNumPasses();
+	/*virtual*/ void render(S32 pass = 0);
+	/*virtual*/ void prerender();
 
 };
 
@@ -66,13 +124,18 @@ class LLDrawPoolGlow : public LLRenderPass
 	enum
 	{
 		VERTEX_DATA_MASK =	LLVertexBuffer::MAP_VERTEX |
-							LLVertexBuffer::MAP_TEXCOORD
+							LLVertexBuffer::MAP_TEXCOORD0
 	};
 
 	virtual U32 getVertexDataMask() { return VERTEX_DATA_MASK; }
 
 	virtual void prerender() { }
 
+	/*virtual*/ S32 getNumPostDeferredPasses() { return 1; }
+	/*virtual*/ void beginPostDeferredPass(S32 pass) { beginRenderPass(pass); }
+	/*virtual*/ void endPostDeferredPass(S32 pass) { endRenderPass(pass); }
+	/*virtual*/ void renderPostDeferred(S32 pass) { render(pass); }
+
 	void render(S32 pass = 0);
 	void pushBatch(LLDrawInfo& params, U32 mask, BOOL texture = TRUE);
 
diff --git a/indra/newview/lldrawpoolsky.cpp b/indra/newview/lldrawpoolsky.cpp
index 027b925e095b493afd294de7369fbbe31eaa7b5f..7f21adcc94d95236aa570e2a2d9c30c3dd52c466 100644
--- a/indra/newview/lldrawpoolsky.cpp
+++ b/indra/newview/lldrawpoolsky.cpp
@@ -62,7 +62,7 @@ LLDrawPool *LLDrawPoolSky::instancePool()
 void LLDrawPoolSky::prerender()
 {
 	mVertexShaderLevel = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_ENVIRONMENT);
-	gSky.mVOSkyp->updateGeometry(gSky.mVOSkyp->mDrawable);
+//	gSky.mVOSkyp->updateGeometry(gSky.mVOSkyp->mDrawable);
 }
 
 void LLDrawPoolSky::render(S32 pass)
diff --git a/indra/newview/lldrawpoolsky.h b/indra/newview/lldrawpoolsky.h
index a7fad72ea139c20c5a4bb14a1022ad820d8bbe63..f35b1147303deb9f3c418af552c60ebcb7dd3f87 100644
--- a/indra/newview/lldrawpoolsky.h
+++ b/indra/newview/lldrawpoolsky.h
@@ -50,7 +50,7 @@ class LLDrawPoolSky : public LLFacePool
 	enum
 	{
 		VERTEX_DATA_MASK =	LLVertexBuffer::MAP_VERTEX |
-							LLVertexBuffer::MAP_TEXCOORD
+							LLVertexBuffer::MAP_TEXCOORD0
 	};
 
 	virtual U32 getVertexDataMask() { return VERTEX_DATA_MASK; }
@@ -59,6 +59,11 @@ class LLDrawPoolSky : public LLFacePool
 
 	/*virtual*/ LLDrawPool *instancePool();
 
+	/*virtual*/ S32 getNumPostDeferredPasses() { return getNumPasses(); }
+	/*virtual*/ void beginPostDeferredPass(S32 pass) { beginRenderPass(pass); }
+	/*virtual*/ void endPostDeferredPass(S32 pass) { endRenderPass(pass); }
+	/*virtual*/ void renderPostDeferred(S32 pass) { render(pass); }
+
 	/*virtual*/ void prerender();
 	/*virtual*/ void render(S32 pass = 0);
 	/*virtual*/ void renderForSelect();
diff --git a/indra/newview/lldrawpoolterrain.cpp b/indra/newview/lldrawpoolterrain.cpp
index 3080f99d9f81266a810660f98391c32aa3ce7fe3..2c644b0fd53165b03e5982a206d9c72d3c517619 100644
--- a/indra/newview/lldrawpoolterrain.cpp
+++ b/indra/newview/lldrawpoolterrain.cpp
@@ -74,14 +74,14 @@ LLDrawPoolTerrain::LLDrawPoolTerrain(LLViewerImage *texturep) :
 													LLUUID("e97cf410-8e61-7005-ec06-629eba4cd1fb"));
 
 	gGL.getTexUnit(0)->bind(mAlphaRampImagep.get());
-	mAlphaRampImagep->setClamp(TRUE, TRUE);
+	mAlphaRampImagep->setAddressMode(LLTexUnit::TAM_CLAMP);
 
 	m2DAlphaRampImagep = gImageList.getImageFromFile("alpha_gradient_2d.j2c",
 													TRUE, TRUE, GL_ALPHA8, GL_ALPHA,
 													LLUUID("38b86f85-2575-52a9-a531-23108d8da837"));
 
 	gGL.getTexUnit(0)->bind(m2DAlphaRampImagep.get());
-	m2DAlphaRampImagep->setClamp(TRUE, TRUE);
+	m2DAlphaRampImagep->setAddressMode(LLTexUnit::TAM_CLAMP);
 	
 	mTexturep->setBoostLevel(LLViewerImage::BOOST_TERRAIN);
 	
@@ -100,6 +100,18 @@ LLDrawPool *LLDrawPoolTerrain::instancePool()
 }
 
 
+U32 LLDrawPoolTerrain::getVertexDataMask() 
+{ 
+	if (LLPipeline::sShadowRender)
+	{
+		return LLVertexBuffer::MAP_VERTEX;
+	}
+	else
+	{
+		return VERTEX_DATA_MASK; 
+	}
+}
+
 void LLDrawPoolTerrain::prerender()
 {
 	mVertexShaderLevel = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_ENVIRONMENT);
@@ -217,6 +229,60 @@ void LLDrawPoolTerrain::render(S32 pass)
 	}
 }
 
+void LLDrawPoolTerrain::beginDeferredPass(S32 pass)
+{
+	LLFastTimer t(LLFastTimer::FTM_RENDER_TERRAIN);
+	LLFacePool::beginRenderPass(pass);
+
+	sShader = &gDeferredTerrainProgram;
+
+	sShader->bind();
+}
+
+void LLDrawPoolTerrain::endDeferredPass(S32 pass)
+{
+	LLFastTimer t(LLFastTimer::FTM_RENDER_TERRAIN);
+	LLFacePool::endRenderPass(pass);
+	sShader->unbind();
+}
+
+void LLDrawPoolTerrain::renderDeferred(S32 pass)
+{
+	LLFastTimer t(LLFastTimer::FTM_RENDER_TERRAIN);
+	if (mDrawFace.empty())
+	{
+		return;
+	}
+	renderFullShader();
+}
+
+void LLDrawPoolTerrain::beginShadowPass(S32 pass)
+{
+	LLFastTimer t(LLFastTimer::FTM_SHADOW_TERRAIN);
+	LLFacePool::beginRenderPass(pass);
+	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+	gDeferredShadowProgram.bind();
+}
+
+void LLDrawPoolTerrain::endShadowPass(S32 pass)
+{
+	LLFastTimer t(LLFastTimer::FTM_SHADOW_TERRAIN);
+	LLFacePool::endRenderPass(pass);
+	gDeferredShadowProgram.unbind();
+}
+
+void LLDrawPoolTerrain::renderShadow(S32 pass)
+{
+	LLFastTimer t(LLFastTimer::FTM_SHADOW_TERRAIN);
+	if (mDrawFace.empty())
+	{
+		return;
+	}
+	//LLGLEnable offset(GL_POLYGON_OFFSET);
+	//glCullFace(GL_FRONT);
+	drawLoop();
+	//glCullFace(GL_BACK);
+}
 
 void LLDrawPoolTerrain::renderFullShader()
 {
@@ -360,9 +426,6 @@ void LLDrawPoolTerrain::renderFullShader()
 
 void LLDrawPoolTerrain::renderFull4TU()
 {
-	glEnableClientState(GL_VERTEX_ARRAY);
-	glEnableClientState(GL_NORMAL_ARRAY);
-
 	// Hack! Get the region that this draw pool is rendering from!
 	LLViewerRegion *regionp = mDrawFace[0]->getDrawable()->getVObj()->getRegion();
 	LLVLComposition *compp = regionp->getComposition();
@@ -390,7 +453,6 @@ void LLDrawPoolTerrain::renderFull4TU()
 	//
 	gGL.getTexUnit(0)->activate();
 	gGL.getTexUnit(0)->bind(detail_texture0p);
-	glClientActiveTextureARB(GL_TEXTURE0_ARB);
 	
 	glEnable(GL_TEXTURE_GEN_S);
 	glEnable(GL_TEXTURE_GEN_T);
@@ -409,9 +471,7 @@ void LLDrawPoolTerrain::renderFull4TU()
 	gGL.getTexUnit(1)->bind(m2DAlphaRampImagep.get());
 	gGL.getTexUnit(1)->enable(LLTexUnit::TT_TEXTURE);
 	gGL.getTexUnit(1)->activate();
-	glClientActiveTextureARB(GL_TEXTURE1_ARB);
-	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-
+	
 	// Care about alpha only
 	gGL.getTexUnit(1)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_COLOR);
 	gGL.getTexUnit(1)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_ALPHA);
@@ -423,9 +483,6 @@ void LLDrawPoolTerrain::renderFull4TU()
 	gGL.getTexUnit(2)->enable(LLTexUnit::TT_TEXTURE);
 	gGL.getTexUnit(2)->activate();
 
-	glClientActiveTextureARB(GL_TEXTURE2_ARB);
-	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-
 	glEnable(GL_TEXTURE_GEN_S);
 	glEnable(GL_TEXTURE_GEN_T);
 	glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
@@ -441,14 +498,12 @@ void LLDrawPoolTerrain::renderFull4TU()
 	gGL.getTexUnit(3)->bind(detail_texture1p);
 	gGL.getTexUnit(3)->enable(LLTexUnit::TT_TEXTURE);
 	gGL.getTexUnit(3)->activate();
-	glClientActiveTextureARB(GL_TEXTURE3_ARB);
-
+	
 	// Set alpha texture and do lighting modulation
 	gGL.getTexUnit(3)->setTextureColorBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_PREV_COLOR, LLTexUnit::TBS_VERT_COLOR);
 
 	gGL.getTexUnit(0)->activate();
-	glClientActiveTextureARB(GL_TEXTURE0_ARB);
-
+	
 	// GL_BLEND disabled by default
 	drawLoop();
 
@@ -459,9 +514,7 @@ void LLDrawPoolTerrain::renderFull4TU()
 	//
 	gGL.getTexUnit(0)->activate();
 	gGL.getTexUnit(0)->bind(detail_texture3p);
-	glClientActiveTextureARB(GL_TEXTURE0_ARB);
 
-	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 	glEnable(GL_TEXTURE_GEN_S);
 	glEnable(GL_TEXTURE_GEN_T);
 	glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
@@ -477,9 +530,6 @@ void LLDrawPoolTerrain::renderFull4TU()
 	gGL.getTexUnit(1)->bind(m2DAlphaRampImagep.get());
 	gGL.getTexUnit(1)->enable(LLTexUnit::TT_TEXTURE);
 	gGL.getTexUnit(1)->activate();
-	glClientActiveTextureARB(GL_TEXTURE1_ARB);
-
-	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
 
 	// Set the texture matrix
 	glMatrixMode(GL_TEXTURE);
@@ -490,7 +540,6 @@ void LLDrawPoolTerrain::renderFull4TU()
 	gGL.getTexUnit(1)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_COLOR);
 	gGL.getTexUnit(1)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_ALPHA);
 
-
 	//
 	// Stage 2: Interpolate detail2 with existing based on ramp
 	//
@@ -498,9 +547,6 @@ void LLDrawPoolTerrain::renderFull4TU()
 	gGL.getTexUnit(2)->enable(LLTexUnit::TT_TEXTURE);
 	gGL.getTexUnit(2)->activate();
 
-	glClientActiveTextureARB(GL_TEXTURE2_ARB);
-	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-
 	glEnable(GL_TEXTURE_GEN_S);
 	glEnable(GL_TEXTURE_GEN_T);
 	glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
@@ -517,9 +563,6 @@ void LLDrawPoolTerrain::renderFull4TU()
 	gGL.getTexUnit(3)->enable(LLTexUnit::TT_TEXTURE);
 	gGL.getTexUnit(3)->activate();
 
-	glClientActiveTextureARB(GL_TEXTURE3_ARB);
-	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-
 	// Set the texture matrix
 	glMatrixMode(GL_TEXTURE);
 	glLoadIdentity();
@@ -530,7 +573,6 @@ void LLDrawPoolTerrain::renderFull4TU()
 	gGL.getTexUnit(3)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_ALPHA);
 
 	gGL.getTexUnit(0)->activate();
-	glClientActiveTextureARB(GL_TEXTURE0_ARB);
 	{
 		LLGLEnable blend(GL_BLEND);
 		drawLoop();
@@ -541,9 +583,7 @@ void LLDrawPoolTerrain::renderFull4TU()
 	gGL.getTexUnit(3)->unbind(LLTexUnit::TT_TEXTURE);
 	gGL.getTexUnit(3)->disable();
 	gGL.getTexUnit(3)->activate();
-	glClientActiveTextureARB(GL_TEXTURE3_ARB);
-	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-
+	
 	glMatrixMode(GL_TEXTURE);
 	glLoadIdentity();
 	glMatrixMode(GL_MODELVIEW);
@@ -551,9 +591,7 @@ void LLDrawPoolTerrain::renderFull4TU()
 	gGL.getTexUnit(2)->unbind(LLTexUnit::TT_TEXTURE);
 	gGL.getTexUnit(2)->disable();
 	gGL.getTexUnit(2)->activate();
-	glClientActiveTextureARB(GL_TEXTURE2_ARB);
-	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-
+	
 	glDisable(GL_TEXTURE_GEN_S);
 	glDisable(GL_TEXTURE_GEN_T);
 	glMatrixMode(GL_TEXTURE);
@@ -563,9 +601,7 @@ void LLDrawPoolTerrain::renderFull4TU()
 	gGL.getTexUnit(1)->unbind(LLTexUnit::TT_TEXTURE);	
 	gGL.getTexUnit(1)->disable();
 	gGL.getTexUnit(1)->activate();
- 	glClientActiveTextureARB(GL_TEXTURE1_ARB);
- 	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-
+ 	
 	glMatrixMode(GL_TEXTURE);
 	glLoadIdentity();
 	glMatrixMode(GL_MODELVIEW);
@@ -579,9 +615,7 @@ void LLDrawPoolTerrain::renderFull4TU()
 	gGL.getTexUnit(0)->activate();
 	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 
-	glClientActiveTextureARB(GL_TEXTURE0_ARB);
-	glDisableClientState(GL_NORMAL_ARRAY);
-
+	
 	glDisable(GL_TEXTURE_GEN_S);
 	glDisable(GL_TEXTURE_GEN_T);
 	glMatrixMode(GL_TEXTURE);
@@ -856,7 +890,7 @@ void LLDrawPoolTerrain::renderOwnership()
 	{
 		LLFace *facep = *iter;
 		facep->renderIndexed(LLVertexBuffer::MAP_VERTEX |
-							LLVertexBuffer::MAP_TEXCOORD);
+							LLVertexBuffer::MAP_TEXCOORD0);
 	}
 
 	glMatrixMode(GL_TEXTURE);
diff --git a/indra/newview/lldrawpoolterrain.h b/indra/newview/lldrawpoolterrain.h
index b243486bf45c28400e1ef7242c9c2f6f7e5b3857..19d09e2febffe649060a29486d9682c0d96b66fa 100644
--- a/indra/newview/lldrawpoolterrain.h
+++ b/indra/newview/lldrawpoolterrain.h
@@ -43,12 +43,14 @@ class LLDrawPoolTerrain : public LLFacePool
 	{
 		VERTEX_DATA_MASK =	LLVertexBuffer::MAP_VERTEX |
 							LLVertexBuffer::MAP_NORMAL |
-							LLVertexBuffer::MAP_TEXCOORD |
+							LLVertexBuffer::MAP_TEXCOORD0 |
+							LLVertexBuffer::MAP_TEXCOORD1 |
 							LLVertexBuffer::MAP_TEXCOORD2 |
+							LLVertexBuffer::MAP_TEXCOORD3 |
 							LLVertexBuffer::MAP_COLOR
 	};
 
-	virtual U32 getVertexDataMask() { return VERTEX_DATA_MASK; }
+	virtual U32 getVertexDataMask();
 	static S32 getDetailMode();
 
 	LLDrawPoolTerrain(LLViewerImage *texturep);
@@ -56,6 +58,15 @@ class LLDrawPoolTerrain : public LLFacePool
 
 	/*virtual*/ LLDrawPool *instancePool();
 
+	/*virtual*/ S32 getNumDeferredPasses() { return 1; }
+	/*virtual*/ void beginDeferredPass(S32 pass);
+	/*virtual*/ void endDeferredPass(S32 pass);
+	/*virtual*/ void renderDeferred(S32 pass);
+
+	/*virtual*/ S32 getNumShadowPasses() { return 1; }
+	/*virtual*/ void beginShadowPass(S32 pass);
+	/*virtual*/ void endShadowPass(S32 pass);
+	/*virtual*/ void renderShadow(S32 pass);
 
 	/*virtual*/ void render(S32 pass = 0);
 	/*virtual*/ void prerender();
diff --git a/indra/newview/lldrawpooltree.cpp b/indra/newview/lldrawpooltree.cpp
index 616461d06e06000aeb9d6dc0a4398b2f520ed72c..2f2b07232a2d7b80ed0162830c2cb1425bcae646 100644
--- a/indra/newview/lldrawpooltree.cpp
+++ b/indra/newview/lldrawpooltree.cpp
@@ -43,6 +43,7 @@
 #include "llviewercamera.h"
 #include "llviewershadermgr.h"
 #include "llrender.h"
+#include "llviewercontrol.h"
 
 S32 LLDrawPoolTree::sDiffTex = 0;
 static LLGLSLShader* shader = NULL;
@@ -52,7 +53,7 @@ LLDrawPoolTree::LLDrawPoolTree(LLViewerImage *texturep) :
 	mTexturep(texturep)
 {
 	gGL.getTexUnit(0)->bind(mTexturep.get());
-	mTexturep->setClamp(FALSE, FALSE);
+	mTexturep->setAddressMode(LLTexUnit::TAM_WRAP);
 }
 
 LLDrawPool *LLDrawPoolTree::instancePool()
@@ -91,7 +92,7 @@ void LLDrawPoolTree::beginRenderPass(S32 pass)
 
 void LLDrawPoolTree::render(S32 pass)
 {
-	LLFastTimer t(LLFastTimer::FTM_RENDER_TREES);
+	LLFastTimer t(LLPipeline::sShadowRender ? LLFastTimer::FTM_SHADOW_TREE : LLFastTimer::FTM_RENDER_TREES);
 
 	if (mDrawFace.empty())
 	{
@@ -101,7 +102,23 @@ void LLDrawPoolTree::render(S32 pass)
 	LLGLEnable test(GL_ALPHA_TEST);
 	LLOverrideFaceColor color(this, 1.f, 1.f, 1.f, 1.f);
 
-	renderTree();
+	if (gSavedSettings.getBOOL("RenderAnimateTrees"))
+	{
+		renderTree();
+	}
+	else
+	{
+		gGL.getTexUnit(sDiffTex)->bind(mTexturep);
+					
+		for (std::vector<LLFace*>::iterator iter = mDrawFace.begin();
+			 iter != mDrawFace.end(); iter++)
+		{
+			LLFace *face = *iter;
+			face->mVertexBuffer->setBuffer(LLDrawPoolTree::VERTEX_DATA_MASK);
+			face->mVertexBuffer->drawRange(LLRender::TRIANGLES, 0, face->mVertexBuffer->getRequestedVerts()-1, face->mVertexBuffer->getRequestedIndices(), 0); 
+			gPipeline.addTrianglesDrawn(face->mVertexBuffer->getRequestedIndices()/3);
+		}
+	}
 }
 
 void LLDrawPoolTree::endRenderPass(S32 pass)
@@ -115,6 +132,54 @@ void LLDrawPoolTree::endRenderPass(S32 pass)
 	}
 }
 
+//============================================
+// deferred implementation
+//============================================
+void LLDrawPoolTree::beginDeferredPass(S32 pass)
+{
+	LLFastTimer t(LLFastTimer::FTM_RENDER_TREES);
+	gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f);
+		
+	shader = &gDeferredTreeProgram;
+	shader->bind();
+}
+
+void LLDrawPoolTree::renderDeferred(S32 pass)
+{
+	render(pass);
+}
+
+void LLDrawPoolTree::endDeferredPass(S32 pass)
+{
+	LLFastTimer t(LLFastTimer::FTM_RENDER_TREES);
+	gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
+	
+	shader->unbind();
+}
+
+//============================================
+// shadow implementation
+//============================================
+void LLDrawPoolTree::beginShadowPass(S32 pass)
+{
+	LLFastTimer t(LLFastTimer::FTM_SHADOW_TREE);
+	gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f);
+	gDeferredShadowProgram.bind();
+}
+
+void LLDrawPoolTree::renderShadow(S32 pass)
+{
+	render(pass);
+}
+
+void LLDrawPoolTree::endShadowPass(S32 pass)
+{
+	LLFastTimer t(LLFastTimer::FTM_SHADOW_TREE);
+	gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
+	gDeferredShadowProgram.unbind();
+}
+
+
 void LLDrawPoolTree::renderForSelect()
 {
 	if (mDrawFace.empty())
@@ -133,7 +198,43 @@ void LLDrawPoolTree::renderForSelect()
 	gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_COLOR);
 	gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_ALPHA, LLTexUnit::TBS_VERT_ALPHA);
 
-	renderTree(TRUE);
+	if (gSavedSettings.getBOOL("RenderAnimateTrees"))
+	{
+		renderTree(TRUE);
+	}
+	else
+	{
+		gGL.getTexUnit(sDiffTex)->bind(mTexturep);
+				
+		for (std::vector<LLFace*>::iterator iter = mDrawFace.begin();
+			 iter != mDrawFace.end(); iter++)
+		{
+			LLFace *face = *iter;
+			LLDrawable *drawablep = face->getDrawable();
+
+			if (drawablep->isDead() || face->mVertexBuffer.isNull())
+			{
+				continue;
+			}
+
+			// Render each of the trees
+			LLVOTree *treep = (LLVOTree *)drawablep->getVObj().get();
+
+			LLColor4U color(255,255,255,255);
+
+			if (treep->mGLName != 0)
+			{
+				S32 name = treep->mGLName;
+				color = LLColor4U((U8)(name >> 16), (U8)(name >> 8), (U8)name, 255);
+				
+				LLFacePool::LLOverrideFaceColor col(this, color);
+				
+				face->mVertexBuffer->setBuffer(LLDrawPoolTree::VERTEX_DATA_MASK);
+				face->mVertexBuffer->drawRange(LLRender::TRIANGLES, 0, face->mVertexBuffer->getRequestedVerts()-1, face->mVertexBuffer->getRequestedIndices(), 0); 
+				gPipeline.addTrianglesDrawn(face->mVertexBuffer->getRequestedIndices()/3);
+			}
+		}
+	}
 
 	gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
 	gGL.setSceneBlendType(LLRender::BT_ALPHA);
diff --git a/indra/newview/lldrawpooltree.h b/indra/newview/lldrawpooltree.h
index 5fbbb20bc0167eef56e10b0cc49044b17e7cf493..80c4fdfffe2ae25a58aabfb3e9ede839b04e4f3d 100644
--- a/indra/newview/lldrawpooltree.h
+++ b/indra/newview/lldrawpooltree.h
@@ -43,7 +43,7 @@ class LLDrawPoolTree : public LLFacePool
 	{
 		VERTEX_DATA_MASK =	LLVertexBuffer::MAP_VERTEX |
 							LLVertexBuffer::MAP_NORMAL |
-							LLVertexBuffer::MAP_TEXCOORD							
+							LLVertexBuffer::MAP_TEXCOORD0							
 	};
 
 	virtual U32 getVertexDataMask() { return VERTEX_DATA_MASK; }
@@ -53,6 +53,17 @@ class LLDrawPoolTree : public LLFacePool
 	/*virtual*/ LLDrawPool *instancePool();
 
 	/*virtual*/ void prerender();
+
+	/*virtual*/ S32 getNumDeferredPasses() { return 1; }
+	/*virtual*/ void beginDeferredPass(S32 pass);
+	/*virtual*/ void endDeferredPass(S32 pass);
+	/*virtual*/ void renderDeferred(S32 pass);
+
+	/*virtual*/ S32 getNumShadowPasses() { return 1; }
+	/*virtual*/ void beginShadowPass(S32 pass);
+	/*virtual*/ void endShadowPass(S32 pass);
+	/*virtual*/ void renderShadow(S32 pass);
+
 	/*virtual*/ void beginRenderPass( S32 pass );
 	/*virtual*/ void render(S32 pass = 0);
 	/*virtual*/ void endRenderPass( S32 pass );
diff --git a/indra/newview/lldrawpoolwater.cpp b/indra/newview/lldrawpoolwater.cpp
index 2005184454925eff5d347a5c8e89f4181efe0084..ce3425dd9e656d792974714ccc66b51335f3024c 100644
--- a/indra/newview/lldrawpoolwater.cpp
+++ b/indra/newview/lldrawpoolwater.cpp
@@ -59,6 +59,8 @@ const LLUUID WATER_TEST("2bfd3884-7e27-69b9-ba3a-3e673f680004");
 
 static float sTime;
 
+BOOL deferred_render = FALSE;
+
 BOOL LLDrawPoolWater::sSkipScreenCopy = FALSE;
 BOOL LLDrawPoolWater::sNeedsReflectionUpdate = TRUE;
 BOOL LLDrawPoolWater::sNeedsDistortionUpdate = TRUE;
@@ -70,14 +72,16 @@ LLDrawPoolWater::LLDrawPoolWater() :
 {
 	mHBTex[0] = gImageList.getImage(gSunTextureID, TRUE, TRUE);
 	gGL.getTexUnit(0)->bind(mHBTex[0].get());
-	mHBTex[0]->setClamp(TRUE, TRUE);
+	mHBTex[0]->setAddressMode(LLTexUnit::TAM_CLAMP);
 
 	mHBTex[1] = gImageList.getImage(gMoonTextureID, TRUE, TRUE);
 	gGL.getTexUnit(0)->bind(mHBTex[1].get());
-	mHBTex[1]->setClamp(TRUE, TRUE);
+	mHBTex[1]->setAddressMode(LLTexUnit::TAM_CLAMP);
 
 	mWaterImagep = gImageList.getImage(WATER_TEST);
+	mWaterImagep->setNoDelete() ;
 	mWaterNormp = gImageList.getImage(DEFAULT_WATER_NORMAL);
+	mWaterNormp->setNoDelete() ;
 
 	restoreGL();
 }
@@ -121,6 +125,18 @@ S32 LLDrawPoolWater::getNumPasses()
 	return 0;
 }
 
+void LLDrawPoolWater::beginPostDeferredPass(S32 pass)
+{
+	beginRenderPass(pass);
+	deferred_render = TRUE;
+}
+
+void LLDrawPoolWater::endPostDeferredPass(S32 pass)
+{
+	endRenderPass(pass);
+	deferred_render = FALSE;
+}
+
 void LLDrawPoolWater::render(S32 pass)
 {
 	LLFastTimer ftm(LLFastTimer::FTM_RENDER_WATER);
@@ -271,10 +287,7 @@ void LLDrawPoolWater::render(S32 pass)
 
 		gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
 
-		if (gSky.mVOSkyp->getCubeMap())
-		{
-			gSky.mVOSkyp->getCubeMap()->disable();
-		}
+		gSky.mVOSkyp->getCubeMap()->disable();
 		
 		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 		gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
@@ -375,7 +388,11 @@ void LLDrawPoolWater::shade()
 
 	F32 eyedepth = LLViewerCamera::getInstance()->getOrigin().mV[2] - gAgent.getRegion()->getWaterHeight();
 	
-	if (eyedepth < 0.f && LLPipeline::sWaterReflections)
+	if (deferred_render)
+	{
+		shader = &gDeferredWaterProgram;
+	}
+	else if (eyedepth < 0.f && LLPipeline::sWaterReflections)
 	{
 		shader = &gUnderWaterProgram;
 	}
@@ -408,21 +425,36 @@ void LLDrawPoolWater::shade()
 
 	mWaterNormp->addTextureStats(1024.f*1024.f);
 	gGL.getTexUnit(bumpTex)->bind(mWaterNormp.get());
-	mWaterNormp->setMipFilterNearest (mWaterNormp->getMipFilterNearest(),
-									  !gSavedSettings.getBOOL("RenderWaterMipNormal"));
+	if (gSavedSettings.getBOOL("RenderWaterMipNormal"))
+	{
+		mWaterNormp->setFilteringOption(LLTexUnit::TFO_ANISOTROPIC);
+	}
+	else 
+	{
+		mWaterNormp->setFilteringOption(LLTexUnit::TFO_POINT);
+	}
 	
 	S32 screentex = shader->enableTexture(LLViewerShaderMgr::WATER_SCREENTEX);	
-	stop_glerror();
+		
+	if (deferred_render)
+	{
+		gPipeline.bindDeferredShader(*shader);
+	}
+	else
+	{
+		shader->bind();
+	}
 	
-	shader->bind();
-
 	if (screentex > -1)
 	{
 		shader->uniform4fv(LLViewerShaderMgr::WATER_FOGCOLOR, 1, sWaterFogColor.mV);
 		shader->uniform1f(LLViewerShaderMgr::WATER_FOGDENSITY, 
 			param_mgr->getFogDensity());
+		gPipeline.mWaterDis.bindTexture(0, screentex);
 	}
-
+	
+	stop_glerror();
+	
 	gGL.getTexUnit(screentex)->bind(&gPipeline.mWaterDis);	
 
 	if (mVertexShaderLevel == 1)
@@ -534,7 +566,15 @@ void LLDrawPoolWater::shade()
 	shader->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
 	shader->disableTexture(LLViewerShaderMgr::WATER_REFTEX);
 	shader->disableTexture(LLViewerShaderMgr::WATER_SCREENDEPTH);
-	shader->unbind();
+
+	if (deferred_render)
+	{
+		gPipeline.unbindDeferredShader(*shader);
+	}
+	else
+	{
+		shader->unbind();
+	}
 
 	gGL.getTexUnit(0)->activate();
 	gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
diff --git a/indra/newview/lldrawpoolwater.h b/indra/newview/lldrawpoolwater.h
index 2eb358b28956b2d2137f17fc783a6609df5e6bad..63510411405769fbdd829cab178008ddd664fdba 100644
--- a/indra/newview/lldrawpoolwater.h
+++ b/indra/newview/lldrawpoolwater.h
@@ -60,7 +60,7 @@ class LLDrawPoolWater: public LLFacePool
 	{
 		VERTEX_DATA_MASK =	LLVertexBuffer::MAP_VERTEX |
 							LLVertexBuffer::MAP_NORMAL |
-							LLVertexBuffer::MAP_TEXCOORD	
+							LLVertexBuffer::MAP_TEXCOORD0	
 	};
 
 	virtual U32 getVertexDataMask() { return VERTEX_DATA_MASK; }
@@ -70,6 +70,11 @@ class LLDrawPoolWater: public LLFacePool
 
 	/*virtual*/ LLDrawPool *instancePool();
 	static void restoreGL();
+	
+	/*virtual*/ S32 getNumPostDeferredPasses() { return getNumPasses(); }
+	/*virtual*/ void beginPostDeferredPass(S32 pass);
+	/*virtual*/ void endPostDeferredPass(S32 pass);
+	/*virtual*/ void renderPostDeferred(S32 pass) { render(pass); }
 
 	/*virtual*/ S32 getNumPasses();
 	/*virtual*/ void render(S32 pass = 0);
diff --git a/indra/newview/lldrawpoolwlsky.h b/indra/newview/lldrawpoolwlsky.h
index 1eb3e5fd90178b9535a43ce5eacf853eb59a8a08..c7a1f3fe27884ea05b9ee8af1b71cca7b6c5559e 100644
--- a/indra/newview/lldrawpoolwlsky.h
+++ b/indra/newview/lldrawpoolwlsky.h
@@ -41,7 +41,7 @@ class LLDrawPoolWLSky : public LLDrawPool {
 public:
 
 	static const U32 SKY_VERTEX_DATA_MASK =	LLVertexBuffer::MAP_VERTEX |
-							LLVertexBuffer::MAP_TEXCOORD;
+							LLVertexBuffer::MAP_TEXCOORD0;
 	static const U32 STAR_VERTEX_DATA_MASK =	LLVertexBuffer::MAP_VERTEX |
 							LLVertexBuffer::MAP_COLOR;
 
@@ -50,6 +50,11 @@ class LLDrawPoolWLSky : public LLDrawPool {
 
 	/*virtual*/ BOOL isDead() { return FALSE; }
 
+	/*virtual*/ S32 getNumPostDeferredPasses() { return getNumPasses(); }
+	/*virtual*/ void beginPostDeferredPass(S32 pass) { beginRenderPass(pass); }
+	/*virtual*/ void endPostDeferredPass(S32 pass) { endRenderPass(pass); }
+	/*virtual*/ void renderPostDeferred(S32 pass) { render(pass); }
+
 	/*virtual*/ LLViewerImage *getDebugTexture();
 	/*virtual*/ void beginRenderPass( S32 pass );
 	/*virtual*/ void endRenderPass( S32 pass );
diff --git a/indra/newview/lldynamictexture.cpp b/indra/newview/lldynamictexture.cpp
index 6951f3a96a8b2081e612649cb41ab89955b0c6c2..62fcf60e7ff06952cf421d92c10112f973b84c12 100644
--- a/indra/newview/lldynamictexture.cpp
+++ b/indra/newview/lldynamictexture.cpp
@@ -112,7 +112,7 @@ void LLDynamicTexture::generateGLTexture(LLGLint internal_format, LLGLenum prima
 	}
 // 	llinfos << "ALLOCATING " << (mWidth*mHeight*mComponents)/1024 << "K" << llendl;
 	mTexture->createGLTexture(0, raw_image);
-	mTexture->setClamp(mClamp, mClamp);
+	mTexture->setAddressMode((mClamp) ? LLTexUnit::TAM_CLAMP : LLTexUnit::TAM_WRAP);
 	mTexture->setGLTextureCreated(false);
 }
 
diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp
index dc3e2f1896c12d48e22c9db553455950762edf48..e096bc07bda90f273be83a03f6031adac637de9b 100644
--- a/indra/newview/llface.cpp
+++ b/indra/newview/llface.cpp
@@ -165,6 +165,7 @@ void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp)
 	mReferenceIndex = -1;
 
 	mTextureMatrix = NULL;
+	mDrawInfo = NULL;
 
 	mFaceColor = LLColor4(1,0,0,1);
 
@@ -178,9 +179,6 @@ void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp)
 
 void LLFace::destroy()
 {
-	mDrawablep = NULL;
-	mVObjp = NULL;
-
 	if (mDrawPoolp)
 	{
 		mDrawPoolp->removeFace(this);
@@ -191,7 +189,21 @@ void LLFace::destroy()
 	{
 		delete mTextureMatrix;
 		mTextureMatrix = NULL;
+
+		if (mDrawablep.notNull())
+		{
+			LLSpatialGroup* group = mDrawablep->getSpatialGroup();
+			if (group)
+			{
+				group->dirtyGeom();
+			}
+		}
 	}
+
+	setDrawInfo(NULL);
+	
+	mDrawablep = NULL;
+	mVObjp = NULL;
 }
 
 
@@ -289,7 +301,7 @@ U16 LLFace::getGeometryAvatar(
 	{
 		mVertexBuffer->getVertexStrider      (vertices, mGeomIndex);
 		mVertexBuffer->getNormalStrider      (normals, mGeomIndex);
-		mVertexBuffer->getTexCoordStrider    (tex_coords, mGeomIndex);
+		mVertexBuffer->getTexCoord0Strider    (tex_coords, mGeomIndex);
 		mVertexBuffer->getWeightStrider(vertex_weights, mGeomIndex);
 		mVertexBuffer->getClothWeightStrider(clothing_weights, mGeomIndex);
 	}
@@ -309,9 +321,9 @@ U16 LLFace::getGeometry(LLStrider<LLVector3> &vertices, LLStrider<LLVector3> &no
 		{
 			mVertexBuffer->getNormalStrider(normals,    mGeomIndex);
 		}
-		if (mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD))
+		if (mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD0))
 		{
-			mVertexBuffer->getTexCoordStrider(tex_coords, mGeomIndex);
+			mVertexBuffer->getTexCoord0Strider(tex_coords, mGeomIndex);
 		}
 
 		mVertexBuffer->getIndexStrider(indicesp, mIndicesIndex);
@@ -435,12 +447,13 @@ void LLFace::renderSelected(LLImageGL *imagep, const LLColor4& color)
 		setFaceColor(color);
 		renderSetColor();
 
-		mVertexBuffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD);
+		mVertexBuffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0);
 #if !LL_RELEASE_FOR_DOWNLOAD
-		LLGLState::checkClientArrays("", LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD);
+		LLGLState::checkClientArrays("", LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0);
 #endif
 		mVertexBuffer->draw(LLRender::TRIANGLES, mIndicesCount, mIndicesIndex);
-				
+
+		unsetFaceColor();
 		unsetFaceColor();
 		gGL.popMatrix();
 	}
@@ -477,9 +490,27 @@ void LLFace::renderSelectedUV()
 	glMatrixMode(GL_MODELVIEW);
 	gGL.blendFunc(LLRender::BF_SOURCE_ALPHA, LLRender::BF_ONE_MINUS_SOURCE_ALPHA);
 }
-
 */
 
+void LLFace::setDrawInfo(LLDrawInfo* draw_info)
+{
+	if (draw_info)
+	{
+		if (draw_info->mFace)
+		{
+			draw_info->mFace->setDrawInfo(NULL);
+		}
+		draw_info->mFace = this;
+	}
+	
+	if (mDrawInfo)
+	{
+		mDrawInfo->mFace = NULL;
+	}
+
+	mDrawInfo = draw_info;
+}
+
 void LLFace::printDebugInfo() const
 {
 	LLFacePool *poolp = getPool();
@@ -587,11 +618,11 @@ BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f,
 	//get bounding box
 	if (mDrawablep->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION))
 	{
-		if (mDrawablep->isState(LLDrawable::REBUILD_VOLUME))
-		{ //vertex buffer no longer valid
-			mVertexBuffer = NULL;
-			mLastVertexBuffer = NULL;
-		}
+		//if (mDrawablep->isState(LLDrawable::REBUILD_VOLUME))
+		//{ //vertex buffer no longer valid
+		//	mVertexBuffer = NULL;
+		//	mLastVertexBuffer = NULL;
+		//}
 
 		LLVector3 min,max;
 	
@@ -739,6 +770,34 @@ LLVector2 LLFace::surfaceToTexture(LLVector2 surface_coord, LLVector3 position,
 	return tc;
 }
 
+void LLFace::updateRebuildFlags()
+{
+	if (!mDrawablep->isState(LLDrawable::REBUILD_VOLUME))
+	{
+		BOOL moved = TRUE;
+		if (mLastVertexBuffer == mVertexBuffer && 
+			!mVertexBuffer->isEmpty())
+		{	//this face really doesn't need to be regenerated, try real hard not to do so
+			if (mLastGeomCount == mGeomCount &&
+				mLastGeomIndex == mGeomIndex &&
+				mLastIndicesCount == mIndicesCount &&
+				mLastIndicesIndex == mIndicesIndex)
+			{ //data is in same location in vertex buffer
+				moved = FALSE;
+			}
+		}
+		mLastMoveTime = gFrameTimeSeconds;
+		
+		if (moved)
+		{
+			mDrawablep->setState(LLDrawable::REBUILD_VOLUME);
+		}
+	}
+	else
+	{
+		mLastUpdateTime = gFrameTimeSeconds;
+	}
+}
 
 BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 							   const S32 &f,
@@ -764,16 +823,16 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 		}
 	}
 
-	LLStrider<LLVector3> old_verts,vertices;
-	LLStrider<LLVector2> old_texcoords,tex_coords;
-	LLStrider<LLVector2> old_texcoords2,tex_coords2;
-	LLStrider<LLVector3> old_normals,normals;
-	LLStrider<LLColor4U> old_colors,colors;
+	LLStrider<LLVector3> vertices;
+	LLStrider<LLVector2> tex_coords;
+	LLStrider<LLVector2> tex_coords2;
+	LLStrider<LLVector3> normals;
+	LLStrider<LLColor4U> colors;
+	LLStrider<LLVector3> binormals;
 	LLStrider<U16> indicesp;
 
 	BOOL full_rebuild = mDrawablep->isState(LLDrawable::REBUILD_VOLUME);
-	BOOL moved = TRUE;
-
+	
 	BOOL global_volume = mDrawablep->getVOVolume()->isVolumeGlobal();
 	LLVector3 scale;
 	if (global_volume)
@@ -784,35 +843,12 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 	{
 		scale = mVObjp->getScale();
 	}
-
-	if (!full_rebuild)
-	{   
-		if (mLastVertexBuffer == mVertexBuffer && 
-			!mVertexBuffer->isEmpty())
-		{	//this face really doesn't need to be regenerated, try real hard not to do so
-			if (mLastGeomCount == mGeomCount &&
-				mLastGeomIndex == mGeomIndex &&
-				mLastIndicesCount == mIndicesCount &&
-				mLastIndicesIndex == mIndicesIndex)
-			{ //data is in same location in vertex buffer
-				moved = FALSE;
-			}
-			
-			if (!moved && !mDrawablep->isState(LLDrawable::REBUILD_ALL))
-			{ //nothing needs to be done
-				return FALSE;
-			}
-		}
-		mLastMoveTime = gFrameTimeSeconds;
-	}
-	else
-	{
-		mLastUpdateTime = gFrameTimeSeconds;
-	}
 	
-	BOOL rebuild_pos = full_rebuild || moved || mDrawablep->isState(LLDrawable::REBUILD_POSITION);
-	BOOL rebuild_color = full_rebuild || moved || mDrawablep->isState(LLDrawable::REBUILD_COLOR);
-	BOOL rebuild_tcoord = full_rebuild || moved || mDrawablep->isState(LLDrawable::REBUILD_TCOORD);
+	BOOL rebuild_pos = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_POSITION);
+	BOOL rebuild_color = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_COLOR);
+	BOOL rebuild_tcoord = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_TCOORD);
+	BOOL rebuild_normal = rebuild_pos && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_NORMAL);
+	BOOL rebuild_binormal = rebuild_pos && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_BINORMAL);
 
 	const LLTextureEntry *tep = mVObjp->getTE(f);
 	U8  bump_code = tep ? tep->getBumpmap() : 0;
@@ -820,14 +856,21 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 	if (rebuild_pos)
 	{
 		mVertexBuffer->getVertexStrider(vertices, mGeomIndex);
+	}
+	if (rebuild_normal)
+	{
 		mVertexBuffer->getNormalStrider(normals, mGeomIndex);
 	}
+	if (rebuild_binormal)
+	{
+		mVertexBuffer->getBinormalStrider(binormals, mGeomIndex);
+	}
 	if (rebuild_tcoord)
 	{
-		mVertexBuffer->getTexCoordStrider(tex_coords, mGeomIndex);
-		if (bump_code)
+		mVertexBuffer->getTexCoord0Strider(tex_coords, mGeomIndex);
+		if (bump_code && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1))
 		{
-			mVertexBuffer->getTexCoord2Strider(tex_coords2, mGeomIndex);
+			mVertexBuffer->getTexCoord1Strider(tex_coords2, mGeomIndex);
 		}
 	}
 	if (rebuild_color)
@@ -922,14 +965,14 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 			0.75f
 		};
 
-		if (getPoolType() != LLDrawPool::POOL_ALPHA && LLPipeline::sRenderBump && tep->getShiny())
+		if (getPoolType() != LLDrawPool::POOL_ALPHA && (LLPipeline::sRenderDeferred || LLPipeline::sRenderBump && tep->getShiny()))
 		{
 			color.mV[3] = U8 (alpha[tep->getShiny()] * 255);
 		}
 	}
 
     // INDICES
-	if (full_rebuild || moved)
+	if (full_rebuild)
 	{
 		mVertexBuffer->getIndexStrider(indicesp, mIndicesIndex);
 		for (U16 i = 0; i < num_indices; i++)
@@ -1046,7 +1089,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 			*tex_coords++ = tc;
 		
-			if (bump_code)
+			if (bump_code && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1))
 			{
 				LLVector3 tangent = vf.mVertices[i].mBinormal % vf.mVertices[i].mNormal;
 
@@ -1066,38 +1109,31 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 				*tex_coords2++ = tc;
 			}	
 		}
-		else if (moved)
-		{
-			*tex_coords++ = *old_texcoords++;
-			if (bump_code)
-			{
-				*tex_coords2++ = *old_texcoords2++;
-			}
-		}
 			
 		if (rebuild_pos)
 		{
 			*vertices++ = vf.mVertices[i].mPosition * mat_vert;
-
+		}
+		
+		if (rebuild_normal)
+		{
 			LLVector3 normal = vf.mVertices[i].mNormal * mat_normal;
 			normal.normVec();
 			
 			*normals++ = normal;
 		}
-		else if (moved)
+		
+		if (rebuild_binormal)
 		{
-			*normals++ = *old_normals++;
-			*vertices++ = *old_verts++;
+			LLVector3 binormal = vf.mVertices[i].mBinormal * mat_normal;
+			binormal.normVec();
+			*binormals++ = binormal;
 		}
-
+		
 		if (rebuild_color)
 		{
 			*colors++ = color;		
 		}
-		else if (moved)
-		{
-			*colors++ = *old_colors++;
-		}
 	}
 
 	if (rebuild_tcoord)
diff --git a/indra/newview/llface.h b/indra/newview/llface.h
index dfe5ab6277862717caad73575078434d8ffb067d..4a551ff261cbe9eedfb9272fc998239e7f306619 100644
--- a/indra/newview/llface.h
+++ b/indra/newview/llface.h
@@ -134,7 +134,9 @@ class LLFace
 	const LLColor4&	getFaceColor() const { return mFaceColor; } 
 	const LLColor4& getRenderColor() const;
 	
+
 	//for volumes
+	void updateRebuildFlags();
 	BOOL getGeometryVolume(const LLVolume& volume,
 						const S32 &f,
 						const LLMatrix4& mat_vert, const LLMatrix3& mat_normal,
@@ -169,7 +171,7 @@ class LLFace
 	void		updateCenterAgent(); // Update center when xform has changed.
 	void		renderSelectedUV();
 
-	void		renderForSelect(U32 data_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD);
+	void		renderForSelect(U32 data_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0);
 	void		renderSelected(LLImageGL *image, const LLColor4 &color);
 
 	F32			getKey()					const	{ return mDistance; }
@@ -182,10 +184,12 @@ class LLFace
 
 	void		setGeomIndex(U16 idx) { mGeomIndex = idx; }
 	void		setIndicesIndex(S32 idx) { mIndicesIndex = idx; }
-	
+	void		setDrawInfo(LLDrawInfo* draw_info);
+
 protected:
 
 public:
+	
 	LLVector3		mCenterLocal;
 	LLVector3		mCenterAgent;
 	LLVector3		mExtents[2];
@@ -196,6 +200,7 @@ class LLFace
 	F32			mLastUpdateTime;
 	F32			mLastMoveTime;
 	LLMatrix4*	mTextureMatrix;
+	LLDrawInfo* mDrawInfo;
 
 protected:
 	friend class LLGeometryManager;
diff --git a/indra/newview/llfasttimerview.cpp b/indra/newview/llfasttimerview.cpp
index 25a26f05d87ed7038ab5396c1ca94504b4b2637f..340254a909db7377d8e0c42799b4e3568c70a58c 100644
--- a/indra/newview/llfasttimerview.cpp
+++ b/indra/newview/llfasttimerview.cpp
@@ -162,8 +162,14 @@ static struct ft_display_info ft_display_table[] =
 //	{ LLFastTimer::FTM_REBUILD_TREE_VB,		"     Tree",		&LLColor4::cyan1, 0 },
 	{ LLFastTimer::FTM_REBUILD_PARTICLE_VB,	"     Particle",	&LLColor4::cyan2, 0 },
 //	{ LLFastTimer::FTM_REBUILD_CLOUD_VB,	"     Cloud",		&LLColor4::cyan3, 0 },
-//	{ LLFastTimer::FTM_REBUILD_GRASS_VB,	"     Grass",		&LLColor4::cyan4, 0 },
- 	{ LLFastTimer::FTM_RENDER_GEOMETRY,		"  Geometry",		&LLColor4::green2, 1 },
+	{ LLFastTimer::FTM_REBUILD_GRASS_VB,	"     Grass",		&LLColor4::cyan4, 0 },
+ 	{ LLFastTimer::FTM_SHADOW_RENDER,		"  Shadow",			&LLColor4::green5, 1 },
+	{ LLFastTimer::FTM_SHADOW_SIMPLE,		"   Simple",		&LLColor4::yellow2, 1 },
+	{ LLFastTimer::FTM_SHADOW_ALPHA,		"   Alpha",			&LLColor4::yellow6, 1 },
+	{ LLFastTimer::FTM_SHADOW_TERRAIN,		"   Terrain",		&LLColor4::green6, 1 },
+	{ LLFastTimer::FTM_SHADOW_AVATAR,		"   Avatar",		&LLColor4::yellow1, 1 },
+	{ LLFastTimer::FTM_SHADOW_TREE,			"   Tree",			&LLColor4::yellow8, 1 },
+	{ LLFastTimer::FTM_RENDER_GEOMETRY,		"  Geometry",		&LLColor4::green2, 1 },
 	{ LLFastTimer::FTM_POOLS,				"   Pools",			&LLColor4::green3, 1 },
 	{ LLFastTimer::FTM_POOLRENDER,			"    RenderPool",	&LLColor4::green4, 1 },
 	{ LLFastTimer::FTM_RENDER_TERRAIN,		"     Terrain",		&LLColor4::green6, 0 },
diff --git a/indra/newview/llfloaterabout.cpp b/indra/newview/llfloaterabout.cpp
index c23d58cb7ad14d590dcfb86d7586225b3ea67e23..2652387bfe966df2fca85eddbb4d8e961a0be20f 100644
--- a/indra/newview/llfloaterabout.cpp
+++ b/indra/newview/llfloaterabout.cpp
@@ -122,6 +122,14 @@ LLFloaterAbout::LLFloaterAbout()
 	std::string support;
 	support.append("\n\n");
 
+#if LL_MSVC
+    support.append(llformat("Built with MSVC version %d\n\n", _MSC_VER));
+#endif
+
+#if LL_GNUC
+    support.append(llformat("Built with GCC version %d\n\n", GCC_VERSION));
+#endif
+
 	// Position
 	LLViewerRegion* region = gAgent.getRegion();
 	if (region)
diff --git a/indra/newview/llfloateranimpreview.cpp b/indra/newview/llfloateranimpreview.cpp
index 045ca6aa364cd7bb90a8310fa385a6b39e09d72e..747b685b5efd0921f8e153b461dcec6c8755d4ba 100644
--- a/indra/newview/llfloateranimpreview.cpp
+++ b/indra/newview/llfloateranimpreview.cpp
@@ -236,9 +236,11 @@ BOOL LLFloaterAnimPreview::postBuild()
 
 		// now load bvh file
 		S32 file_size;
-		apr_file_t* fp = ll_apr_file_open(mFilenameAndPath, LL_APR_RB, &file_size);
-
-		if (!fp)
+		
+		LLAPRFile infile ;
+		infile.open(mFilenameAndPath, LL_APR_RB, NULL, &file_size);
+		
+		if (!infile.getFileHandle())
 		{
 			llwarns << "Can't open BVH file:" << mFilename << llendl;	
 		}
@@ -248,14 +250,14 @@ BOOL LLFloaterAnimPreview::postBuild()
 
 			file_buffer = new char[file_size + 1];
 
-			if (file_size == ll_apr_file_read(fp, file_buffer, file_size))
+			if (file_size == infile.read(file_buffer, file_size))
 			{
 				file_buffer[file_size] = '\0';
 				llinfos << "Loading BVH file " << mFilename << llendl;
 				loaderp = new LLBVHLoader(file_buffer);
 			}
 
-			apr_file_close(fp);
+			infile.close() ;
 			delete[] file_buffer;
 		}
 	}
diff --git a/indra/newview/llfloaterauction.cpp b/indra/newview/llfloaterauction.cpp
index 2dabb55eaa4284f119b2327b9ee33a66de29a3ca..747431fb1912f6b982516d9971841d60975541e4 100644
--- a/indra/newview/llfloaterauction.cpp
+++ b/indra/newview/llfloaterauction.cpp
@@ -207,7 +207,7 @@ void LLFloaterAuction::onClickSnapshot(void* data)
 
 		self->mImage = new LLImageGL((LLImageRaw*)raw, FALSE);
 		gGL.getTexUnit(0)->bind(self->mImage);
-		self->mImage->setClamp(TRUE, TRUE);
+		self->mImage->setAddressMode(LLTexUnit::TAM_CLAMP);
 	}
 	else
 	{
diff --git a/indra/newview/llfloatercolorpicker.cpp b/indra/newview/llfloatercolorpicker.cpp
index 4f8c5ce4eb09ab125b232318d213569ebfa5a6c0..f82d692dd3a8e31e1e18819531318f15e01a2399 100644
--- a/indra/newview/llfloatercolorpicker.cpp
+++ b/indra/newview/llfloatercolorpicker.cpp
@@ -167,7 +167,7 @@ createUI ()
 	}
 	mRGBImage = new LLImageGL ( (LLImageRaw*)raw, FALSE );
 	gGL.getTexUnit(0)->bind(mRGBImage);
-	mRGBImage->setClamp(TRUE, TRUE);
+	mRGBImage->setAddressMode(LLTexUnit::TAM_CLAMP);
 	
 	// create palette
 	for ( S32 each = 0; each < numPaletteColumns * numPaletteRows; ++each )
diff --git a/indra/newview/llfloaterimagepreview.cpp b/indra/newview/llfloaterimagepreview.cpp
index 67be553ae7cedf7336fcf003fef0eb46b7c522a3..689f9f48d0bdb596d4faffe8ab0b9feefa23b978 100644
--- a/indra/newview/llfloaterimagepreview.cpp
+++ b/indra/newview/llfloaterimagepreview.cpp
@@ -234,8 +234,7 @@ void LLFloaterImagePreview::draw()
 				gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mImagep->getTexName());
 				stop_glerror();
 
-				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+				gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
 				
 				gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
 				if (mAvatarPreview)
diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp
index 14caed9d97aa5964883a1eff960d5ed6575bffdd..164c33b10d90244e00b5ff47772591aa7efbba71 100644
--- a/indra/newview/llfloatersnapshot.cpp
+++ b/indra/newview/llfloatersnapshot.cpp
@@ -862,9 +862,17 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview )
 			}
 
 			previewp->mViewerImage[previewp->mCurImageIndex] = new LLImageGL(scaled, FALSE);
-			previewp->mViewerImage[previewp->mCurImageIndex]->setMipFilterNearest(previewp->getSnapshotType() != SNAPSHOT_TEXTURE);
-			gGL.getTexUnit(0)->bind(previewp->mViewerImage[previewp->mCurImageIndex]);
-			previewp->mViewerImage[previewp->mCurImageIndex]->setClamp(TRUE, TRUE);
+			LLPointer<LLImageGL> curr_preview_image = previewp->mViewerImage[previewp->mCurImageIndex];
+			gGL.getTexUnit(0)->bind(curr_preview_image);
+			if (previewp->getSnapshotType() != SNAPSHOT_TEXTURE)
+			{
+				curr_preview_image->setFilteringOption(LLTexUnit::TFO_POINT);
+			}
+			else
+			{
+				curr_preview_image->setFilteringOption(LLTexUnit::TFO_ANISOTROPIC);
+			}
+			curr_preview_image->setAddressMode(LLTexUnit::TAM_CLAMP);
 
 			previewp->mSnapshotUpToDate = TRUE;
 			previewp->generateThumbnailImage(TRUE) ;
diff --git a/indra/newview/llhudicon.cpp b/indra/newview/llhudicon.cpp
index 0c7d785ae092597736bf13ebc8f4851f35ab7aa8..3535fe185c9a9b63880299f5006dfc8c89355b96 100644
--- a/indra/newview/llhudicon.cpp
+++ b/indra/newview/llhudicon.cpp
@@ -184,7 +184,7 @@ void LLHUDIcon::renderIcon(BOOL for_select)
 void LLHUDIcon::setImage(LLViewerImage* imagep)
 {
 	mImagep = imagep;
-	mImagep->setClamp(TRUE, TRUE);
+	mImagep->setAddressMode(LLTexUnit::TAM_CLAMP);
 }
 
 void LLHUDIcon::setScale(F32 fraction_of_fov)
diff --git a/indra/newview/llhudobject.cpp b/indra/newview/llhudobject.cpp
index 0e9f7c16a624aad3ac780c091b97e31938742287..bdff49294838ad6aa29042788d7e3a71d7b7af8b 100644
--- a/indra/newview/llhudobject.cpp
+++ b/indra/newview/llhudobject.cpp
@@ -131,7 +131,7 @@ void LLHUDObject::cleanupHUDObjects()
 		(*object_it)->markDead();
 		if ((*object_it)->getNumRefs() > 1)
 		{
-			llinfos << "LLHUDObject " << (LLHUDObject *)(*object_it) << " has " << (*object_it)->getNumRefs() << " refs!" << llendl;
+			llinfos << "LLHUDObject " << (LLHUDObject *)(*object_it) << " type " << (S32)(*object_it)->getType() << " has " << (*object_it)->getNumRefs() << " refs!" << llendl;			
 		}
 	}
 	sHUDObjects.clear();
diff --git a/indra/newview/llhudtext.cpp b/indra/newview/llhudtext.cpp
index e3483fdaca2bbbc7e077a3f9cb118c89e89973ea..2e59240c49249a4b2e6e12775cc5696b9d932950 100644
--- a/indra/newview/llhudtext.cpp
+++ b/indra/newview/llhudtext.cpp
@@ -737,11 +737,12 @@ void LLHUDText::updateVisibility()
 	dir_from_camera.normVec();
 
 	if (dir_from_camera * LLViewerCamera::getInstance()->getAtAxis() <= 0.f)
-	{
-		mPositionAgent -= projected_vec(vec_from_camera, LLViewerCamera::getInstance()->getAtAxis()) * 1.f;
-		mPositionAgent += LLViewerCamera::getInstance()->getAtAxis() * (LLViewerCamera::getInstance()->getNear() + 0.1f);
+	{ //text is behind camera, don't render
+		mVisible = FALSE;
+		return;
 	}
-	else if (vec_from_camera * LLViewerCamera::getInstance()->getAtAxis() <= LLViewerCamera::getInstance()->getNear() + 0.1f + mSourceObject->getVObjRadius())
+		
+	if (vec_from_camera * LLViewerCamera::getInstance()->getAtAxis() <= LLViewerCamera::getInstance()->getNear() + 0.1f + mSourceObject->getVObjRadius())
 	{
 		mPositionAgent = LLViewerCamera::getInstance()->getOrigin() + vec_from_camera * ((LLViewerCamera::getInstance()->getNear() + 0.1f) / (vec_from_camera * LLViewerCamera::getInstance()->getAtAxis()));
 	}
@@ -1068,6 +1069,10 @@ void LLHUDText::markDead()
 
 void LLHUDText::renderAllHUD()
 {
+	LLGLState::checkStates();
+	LLGLState::checkTextureChannels();
+	LLGLState::checkClientArrays();
+	
 	LLGLEnable color_mat(GL_COLOR_MATERIAL);
 	LLGLDepthTest depth(GL_FALSE, GL_FALSE);
 	
@@ -1077,6 +1082,10 @@ void LLHUDText::renderAllHUD()
 	{
 		(*text_it)->renderText(FALSE);
 	}
+
+	LLGLState::checkStates();
+	LLGLState::checkTextureChannels();
+	LLGLState::checkClientArrays();
 }
 
 void LLHUDText::shiftAll(const LLVector3& offset)
diff --git a/indra/newview/lljoystickbutton.cpp b/indra/newview/lljoystickbutton.cpp
index 95825aa2f2f1acab1996c9f9ad0111c681d9ceef..326c511fcf1e46de8ceb802cfaba7b7471beb8b0 100644
--- a/indra/newview/lljoystickbutton.cpp
+++ b/indra/newview/lljoystickbutton.cpp
@@ -639,7 +639,7 @@ void LLJoystickCameraRotate::draw()
 }
 
 // Draws image rotated by multiples of 90 degrees
-void LLJoystickCameraRotate::drawRotatedImage( const LLImageGL* image, S32 rotations )
+void LLJoystickCameraRotate::drawRotatedImage( LLImageGL* image, S32 rotations )
 {
 	S32 width = image->getWidth();
 	S32 height = image->getHeight();
diff --git a/indra/newview/lljoystickbutton.h b/indra/newview/lljoystickbutton.h
index e7d4beb375d001b4e0859c82057e1ed50349b675..076a506f148b81564455e88ad0bd7762dc31e9d5 100644
--- a/indra/newview/lljoystickbutton.h
+++ b/indra/newview/lljoystickbutton.h
@@ -134,7 +134,7 @@ class LLJoystickCameraRotate
 protected:
 	F32				getOrbitRate();
 	virtual void	updateSlop();
-	void			drawRotatedImage( const LLImageGL* image, S32 rotations );
+	void			drawRotatedImage( LLImageGL* image, S32 rotations );
 
 protected:
 	BOOL			mInLeft;
diff --git a/indra/newview/llmaniptranslate.cpp b/indra/newview/llmaniptranslate.cpp
index 959a575950a4eef1ec8af60779337d293f834a03..dfa624a59c1df544a6bedb585990e6f7bfe28cb2 100644
--- a/indra/newview/llmaniptranslate.cpp
+++ b/indra/newview/llmaniptranslate.cpp
@@ -164,8 +164,7 @@ void LLManipTranslate::restoreGL()
 	GLuint* d = new GLuint[rez*rez];	
 
 	gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, sGridTex->getTexName());
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+	gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_TRILINEAR);
 
 	while (rez >= 1)
 	{
@@ -261,9 +260,9 @@ void LLManipTranslate::restoreGL()
 			}
 		}
 #ifdef LL_WINDOWS
-		glTexImage2D(GL_TEXTURE_2D, mip, GL_RGBA, rez, rez, 0, GL_RGBA, GL_UNSIGNED_BYTE, d);
+		LLImageGL::setManualImage(GL_TEXTURE_2D, mip, GL_RGBA, rez, rez, GL_RGBA, GL_UNSIGNED_BYTE, d);
 #else
-		glTexImage2D(GL_TEXTURE_2D, mip, GL_RGBA, rez, rez, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, d);
+		LLImageGL::setManualImage(GL_TEXTURE_2D, mip, GL_RGBA, rez, rez, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, d);
 #endif
 		rez = rez >> 1;
 		mip++;
diff --git a/indra/newview/llmimetypes.h b/indra/newview/llmimetypes.h
index 4b48bd8daa282d285676c044be94228bd2492c05..7a50c29429af38a8c3dc9b574e83cda25c72dedc 100644
--- a/indra/newview/llmimetypes.h
+++ b/indra/newview/llmimetypes.h
@@ -101,10 +101,10 @@ class LLMIMETypes
 		std::string mPlayTip;
 			// custom tool tip to display for Play button
 
-		bool mAllowResize;
+		BOOL mAllowResize;
 			// enable/disable media size edit fields
 
-		bool mAllowLooping;
+		BOOL mAllowLooping;
 			// enable/disable media looping checkbox
 	};
 	typedef std::map< std::string, LLMIMEInfo > mime_info_map_t;
diff --git a/indra/newview/llsky.cpp b/indra/newview/llsky.cpp
index 24fea645d4011fbb9fd5c0c34578a96c047f321e..b779aa0f83c3b706b192bd9b6188b3b4c876e758 100644
--- a/indra/newview/llsky.cpp
+++ b/indra/newview/llsky.cpp
@@ -285,18 +285,37 @@ LLColor4U LLSky::getFadeColor() const
 
 void LLSky::init(const LLVector3 &sun_direction)
 {
+	LLGLState::checkStates();
+	LLGLState::checkTextureChannels();
+
 	mVOWLSkyp = static_cast<LLVOWLSky*>(gObjectList.createObjectViewer(LLViewerObject::LL_VO_WL_SKY, NULL));
 	mVOWLSkyp->initSunDirection(sun_direction, LLVector3::zero);
-	gPipeline.addObject(mVOWLSkyp.get());
+	gPipeline.createObject(mVOWLSkyp.get());
+
+	LLGLState::checkStates();
+	LLGLState::checkTextureChannels();
 
 	mVOSkyp = (LLVOSky *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_SKY, NULL);
+
+	LLGLState::checkStates();
+	LLGLState::checkTextureChannels();
+
 	mVOSkyp->initSunDirection(sun_direction, LLVector3());
-	gPipeline.addObject((LLViewerObject *)mVOSkyp);
 
+	LLGLState::checkStates();
+	LLGLState::checkTextureChannels();
+
+	gPipeline.createObject((LLViewerObject *)mVOSkyp);
+
+	LLGLState::checkStates();
+	LLGLState::checkTextureChannels();
 
 	mVOGroundp = (LLVOGround*)gObjectList.createObjectViewer(LLViewerObject::LL_VO_GROUND, NULL);
 	LLVOGround *groundp = mVOGroundp;
-	gPipeline.addObject((LLViewerObject *)groundp);
+	gPipeline.createObject((LLViewerObject *)groundp);
+
+	LLGLState::checkStates();
+	LLGLState::checkTextureChannels();
 
 	gSky.setFogRatio(gSavedSettings.getF32("RenderFogRatio"));	
 
@@ -309,6 +328,8 @@ void LLSky::init(const LLVector3 &sun_direction)
 	// Get the parameters.
 	mSunDefaultPosition = gSavedSettings.getVector3("SkySunDefaultPosition");
 
+	LLGLState::checkStates();
+	LLGLState::checkTextureChannels();
 
 	if (gSavedSettings.getBOOL("SkyOverrideSimSunPosition") || mOverrideSimSunPosition)
 	{
@@ -319,6 +340,8 @@ void LLSky::init(const LLVector3 &sun_direction)
 		setSunDirection(sun_direction, LLVector3(0.f, 0.f, 0.f));
 	}
 
+	LLGLState::checkStates();
+	LLGLState::checkTextureChannels();
 
 	mUpdatedThisFrame = TRUE;
 }
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index dc4b8134dca314a75130ca7bfef7d36927f5ddfa..6e5231bddd661726bd7ab700b64545e6d2d3f2ac 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -49,7 +49,7 @@
 #include "lloctree.h"
 #include "llvoavatar.h"
 
-const F32 SG_OCCLUSION_FUDGE = 1.01f;
+const F32 SG_OCCLUSION_FUDGE = 0.25f;
 #define SG_DISCARD_TOLERANCE 0.01f
 
 #if LL_OCTREE_PARANOIA_CHECK
@@ -191,7 +191,7 @@ static U8 sOcclusionIndices[] =
 		b000, b110, b100, b101, b001, b011, b010, b110,
 };
 
-U8* get_occlusion_indices(LLCamera* camera, const LLVector3& center)
+U8* get_box_fan_indices(LLCamera* camera, const LLVector3& center)
 {
 	LLVector3 d = center - camera->getOrigin();
 
@@ -219,7 +219,7 @@ void LLSpatialGroup::buildOcclusion()
 		mOcclusionVerts = new F32[8*3];
 	}
 
-	LLVector3 r = mBounds[1]*SG_OCCLUSION_FUDGE + LLVector3(0.1f,0.1f,0.1f);
+	LLVector3 r = mBounds[1] + LLVector3(SG_OCCLUSION_FUDGE, SG_OCCLUSION_FUDGE, SG_OCCLUSION_FUDGE);
 
 	for (U32 k = 0; k < 3; k++)
 	{
@@ -562,8 +562,21 @@ void LLSpatialGroup::rebuildGeom()
 	}
 }
 
+void LLSpatialGroup::rebuildMesh()
+{
+	if (!isDead())
+	{
+		mSpatialPartition->rebuildMesh(this);
+	}
+}
+
 void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group)
 {
+	if (!gPipeline.hasRenderType(mDrawableType))
+	{
+		return;
+	}
+
 	if (group->changeLOD())
 	{
 		group->mLastUpdateDistance = group->mDistance;
@@ -612,6 +625,11 @@ void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group)
 	group->clearState(LLSpatialGroup::GEOM_DIRTY);
 }
 
+void LLSpatialPartition::rebuildMesh(LLSpatialGroup* group)
+{
+
+}
+
 BOOL LLSpatialGroup::boundObjects(BOOL empty, LLVector3& minOut, LLVector3& maxOut)
 {	
 	const OctreeNode* node = mOctreeNode;
@@ -778,7 +796,7 @@ void LLSpatialGroup::shift(const LLVector3 &offset)
 	mObjectExtents[0] += offset;
 	mObjectExtents[1] += offset;
 
-	if (!mSpatialPartition->mRenderByGroup)
+	//if (!mSpatialPartition->mRenderByGroup)
 	{
 		setState(GEOM_DIRTY);
 	}
@@ -1271,8 +1289,8 @@ void LLSpatialGroup::checkOcclusion()
 
 			clearState(QUERY_PENDING | DISCARD_QUERY);
 		}
-		else if (mSpatialPartition->mOcclusionEnabled)
-		{
+		else if (mSpatialPartition->isOcclusionEnabled() && isState(LLSpatialGroup::OCCLUDED))
+		{	//check occlusion has been issued for occluded node that has not had a query issued
 			assert_states_valid(this);
 			clearState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF);
 			assert_states_valid(this);
@@ -1282,7 +1300,7 @@ void LLSpatialGroup::checkOcclusion()
 
 void LLSpatialGroup::doOcclusion(LLCamera* camera)
 {
-	if (mSpatialPartition->mOcclusionEnabled && LLPipeline::sUseOcclusion > 1)
+	if (mSpatialPartition->isOcclusionEnabled() && LLPipeline::sUseOcclusion > 1)
 	{
 		if (earlyFail(camera, this))
 		{
@@ -1309,7 +1327,7 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera)
 				glBeginQueryARB(GL_SAMPLES_PASSED_ARB, mOcclusionQuery);					
 				glVertexPointer(3, GL_FLOAT, 0, mOcclusionVerts);
 				glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8,
-							GL_UNSIGNED_BYTE, get_occlusion_indices(camera, mBounds[0]));
+							GL_UNSIGNED_BYTE, get_box_fan_indices(camera, mBounds[0]));
 				glEndQueryARB(GL_SAMPLES_PASSED_ARB);
 			}
 
@@ -1470,7 +1488,7 @@ class LLOctreeCull : public LLSpatialGroup::OctreeTraveler
 		group->checkOcclusion();
 
 		if (group->mOctreeNode->getParent() &&	//never occlusion cull the root node
-			LLPipeline::sUseOcclusion &&			//ignore occlusion if disabled
+		  	LLPipeline::sUseOcclusion &&			//ignore occlusion if disabled
 			group->isState(LLSpatialGroup::OCCLUDED))
 		{
 			gPipeline.markOccluder(group);
@@ -1594,6 +1612,86 @@ class LLOctreeCullNoFarClip : public LLOctreeCull
 	}
 };
 
+class LLOctreeCullShadow : public LLOctreeCull
+{
+public:
+	LLOctreeCullShadow(LLCamera* camera)
+		: LLOctreeCull(camera) { }
+
+	virtual S32 frustumCheck(const LLSpatialGroup* group)
+	{
+		return mCamera->AABBInFrustum(group->mBounds[0], group->mBounds[1]);
+	}
+
+	virtual S32 frustumCheckObjects(const LLSpatialGroup* group)
+	{
+		return mCamera->AABBInFrustum(group->mObjectBounds[0], group->mObjectBounds[1]);
+	}
+};
+
+class LLOctreeCullVisExtents: public LLOctreeCullShadow
+{
+public:
+	LLOctreeCullVisExtents(LLCamera* camera, LLVector3& min, LLVector3& max)
+		: LLOctreeCullShadow(camera), mMin(min), mMax(max), mEmpty(TRUE) { }
+
+	virtual bool earlyFail(LLSpatialGroup* group)
+	{
+		if (group->mOctreeNode->getParent() &&	//never occlusion cull the root node
+			LLPipeline::sUseOcclusion &&			//ignore occlusion if disabled
+			group->isState(LLSpatialGroup::OCCLUDED))
+		{
+			return true;
+		}
+		
+		return false;
+	}
+
+	virtual void processGroup(LLSpatialGroup* group)
+	{
+		if (group->mObjectBounds[1].magVecSquared() < 256.f * 256.f)
+		{ //megaprims and water edge patches be damned!
+			mEmpty = FALSE;
+			update_min_max(mMin, mMax, group->mObjectExtents[0]);
+			update_min_max(mMin, mMax, group->mObjectExtents[1]);
+		}
+	}
+
+	BOOL mEmpty;
+	LLVector3& mMin;
+	LLVector3& mMax;
+};
+
+class LLOctreeCullDetectVisible: public LLOctreeCullShadow
+{
+public:
+	LLOctreeCullDetectVisible(LLCamera* camera)
+		: LLOctreeCullShadow(camera), mResult(FALSE) { }
+
+	virtual bool earlyFail(LLSpatialGroup* group)
+	{
+		if (mResult || //already found a node, don't check any more
+			group->mOctreeNode->getParent() &&	//never occlusion cull the root node
+			LLPipeline::sUseOcclusion &&			//ignore occlusion if disabled
+			group->isState(LLSpatialGroup::OCCLUDED))
+		{
+			return true;
+		}
+		
+		return false;
+	}
+
+	virtual void processGroup(LLSpatialGroup* group)
+	{
+		if (group->isVisible())
+		{
+			mResult = TRUE;
+		}
+	}
+
+	BOOL mResult;
+};
+
 class LLOctreeSelect : public LLOctreeCull
 {
 public:
@@ -1747,6 +1845,25 @@ void LLSpatialPartition::resetVertexBuffers()
 	dirty.traverse(mOctree);
 }
 
+BOOL LLSpatialPartition::isOcclusionEnabled()
+{
+	return mOcclusionEnabled || LLPipeline::sUseOcclusion > 2;
+}
+
+BOOL LLSpatialPartition::getVisibleExtents(LLCamera& camera, LLVector3& visMin, LLVector3& visMax)
+{
+	LLOctreeCullVisExtents vis(&camera, visMin, visMax);
+	vis.traverse(mOctree);
+	return vis.mEmpty;
+}
+
+BOOL LLSpatialPartition::visibleObjectsInFrustum(LLCamera& camera)
+{
+	LLOctreeCullDetectVisible vis(&camera);
+	vis.traverse(mOctree);
+	return vis.mResult;
+}
+
 S32 LLSpatialPartition::cull(LLCamera &camera, std::vector<LLDrawable *>* results, BOOL for_select)
 {
 	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
@@ -1772,6 +1889,12 @@ S32 LLSpatialPartition::cull(LLCamera &camera, std::vector<LLDrawable *>* result
 		LLOctreeSelect selecter(&camera, results);
 		selecter.traverse(mOctree);
 	}
+	else if (LLPipeline::sShadowRender)
+	{
+		LLFastTimer ftm(LLFastTimer::FTM_FRUSTUM_CULL);
+		LLOctreeCullShadow culler(&camera);
+		culler.traverse(mOctree);
+	}
 	else if (mInfiniteFarClip || !LLPipeline::sUseFarClip)
 	{
 		LLFastTimer ftm(LLFastTimer::FTM_FRUSTUM_CULL);		
@@ -1790,14 +1913,14 @@ S32 LLSpatialPartition::cull(LLCamera &camera, std::vector<LLDrawable *>* result
 
 BOOL earlyFail(LLCamera* camera, LLSpatialGroup* group)
 {
-	const F32 vel = (LLViewerCamera::getInstance()->getVelocityStat()->getCurrent()+0.2f);
+	const F32 vel = SG_OCCLUSION_FUDGE*2.f;
 	LLVector3 c = group->mBounds[0];
-	LLVector3 r = group->mBounds[1]*SG_OCCLUSION_FUDGE + LLVector3(vel,vel,vel);
+	LLVector3 r = group->mBounds[1] + LLVector3(vel,vel,vel);
     
-	if (r.magVecSquared() > 1024.0*1024.0)
+	/*if (r.magVecSquared() > 1024.0*1024.0)
 	{
 		return TRUE;
-	}
+	}*/
 
 	LLVector3 e = camera->getOrigin();
 	
@@ -1865,21 +1988,31 @@ void pushBufferVerts(LLVertexBuffer* buffer, U32 mask)
 
 void pushBufferVerts(LLSpatialGroup* group, U32 mask)
 {
-	if (!group->mDrawMap.empty())
+	if (group->mSpatialPartition->mRenderByGroup)
 	{
-		LLDrawInfo* params = *(group->mDrawMap.begin()->second.begin());
-		LLRenderPass::applyModelMatrix(*params);
-	
-		pushBufferVerts(group->mVertexBuffer, mask);
-
-		for (LLSpatialGroup::buffer_map_t::iterator i = group->mBufferMap.begin(); i != group->mBufferMap.end(); ++i)
+		if (!group->mDrawMap.empty())
 		{
-			for (LLSpatialGroup::buffer_list_t::iterator j = i->second.begin(); j != i->second.end(); ++j)
+			LLDrawInfo* params = *(group->mDrawMap.begin()->second.begin());
+			LLRenderPass::applyModelMatrix(*params);
+		
+			pushBufferVerts(group->mVertexBuffer, mask);
+
+			for (LLSpatialGroup::buffer_map_t::iterator i = group->mBufferMap.begin(); i != group->mBufferMap.end(); ++i)
 			{
-				pushBufferVerts(*j, mask);
+				for (LLSpatialGroup::buffer_texture_map_t::iterator j = i->second.begin(); j != i->second.end(); ++j)
+				{
+					for (LLSpatialGroup::buffer_list_t::iterator k = j->second.begin(); k != j->second.end(); ++k)
+					{
+						pushBufferVerts(*k, mask);
+					}
+				}
 			}
 		}
 	}
+	else
+	{
+		drawBox(group->mBounds[0], group->mBounds[1]);
+	}
 }
 
 void pushVertsColorCoded(LLSpatialGroup* group, U32 mask)
@@ -2026,6 +2159,23 @@ void renderOctree(LLSpatialGroup* group)
 		}
 						
 		drawBoxOutline(group->mBounds[0],group->mBounds[1]);
+
+
+		//draw bounding box for draw info
+		if (group->mSpatialPartition->mRenderByGroup)
+		{
+			gGL.color4f(1.0f, 0.75f, 0.25f, 0.6f);
+			for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i)
+			{
+				for (LLSpatialGroup::drawmap_elem_t::iterator j = i->second.begin(); j != i->second.end(); ++j)
+				{
+					LLDrawInfo* draw_info = *j;
+					LLVector3 center = (draw_info->mExtents[1] + draw_info->mExtents[0])*0.5f;
+					LLVector3 size = (draw_info->mExtents[1] - draw_info->mExtents[0])*0.5f;
+					drawBoxOutline(center, size);
+				}
+			}
+		}
 	}
 	
 //	LLSpatialGroup::OctreeNode* node = group->mOctreeNode;
@@ -2046,6 +2196,7 @@ void renderVisibility(LLSpatialGroup* group, LLCamera* camera)
 	{
 		LLGLDepthTest depth_under(GL_TRUE, GL_FALSE, GL_GREATER);
 		glColor4f(0, 0.5f, 0, 0.5f);
+		gGL.color4f(0, 0.5f, 0, 0.5f);
 		pushBufferVerts(group, LLVertexBuffer::MAP_VERTEX);
 	}
 
@@ -2055,6 +2206,7 @@ void renderVisibility(LLSpatialGroup* group, LLCamera* camera)
 		if (render_objects)
 		{
 			glColor4f(0.f, 0.5f, 0.f,1.f);
+			gGL.color4f(0.f, 0.5f, 0.f, 1.f);
 			pushBufferVerts(group, LLVertexBuffer::MAP_VERTEX);
 		}
 
@@ -2063,6 +2215,7 @@ void renderVisibility(LLSpatialGroup* group, LLCamera* camera)
 		if (render_objects)
 		{
 			glColor4f(0.f, 0.75f, 0.f,0.5f);
+			gGL.color4f(0.f, 0.75f, 0.f, 0.5f);
 			pushBufferVerts(group, LLVertexBuffer::MAP_VERTEX);
 		}
 		else if (camera && group->mOcclusionVerts)
@@ -2071,60 +2224,63 @@ void renderVisibility(LLSpatialGroup* group, LLCamera* camera)
 			glVertexPointer(3, GL_FLOAT, 0, group->mOcclusionVerts);
 
 			glColor4f(1.0f, 0.f, 0.f, 0.5f);
-			glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8, GL_UNSIGNED_BYTE, get_occlusion_indices(camera, group->mBounds[0]));
+			glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8, GL_UNSIGNED_BYTE, get_box_fan_indices(camera, group->mBounds[0]));
 			glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 			
 			glColor4f(1.0f, 1.f, 1.f, 1.0f);
-			glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8, GL_UNSIGNED_BYTE, get_occlusion_indices(camera, group->mBounds[0]));
+			glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8, GL_UNSIGNED_BYTE, get_box_fan_indices(camera, group->mBounds[0]));
 			glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 		}
 	}
 }
 
-void renderBoundingBox(LLDrawable* drawable)
+void renderBoundingBox(LLDrawable* drawable, BOOL set_color = TRUE)
 {
-	if (drawable->isSpatialBridge())
-	{
-		gGL.color4f(1,0.5f,0,1);
-	}
-	else if (drawable->getVOVolume())
+	if (set_color)
 	{
-		if (drawable->isRoot())
+		if (drawable->isSpatialBridge())
 		{
-			gGL.color4f(1,1,0,1);
+			gGL.color4f(1,0.5f,0,1);
 		}
-		else
+		else if (drawable->getVOVolume())
 		{
-			gGL.color4f(0,1,0,1);
+			if (drawable->isRoot())
+			{
+				gGL.color4f(1,1,0,1);
+			}
+			else
+			{
+				gGL.color4f(0,1,0,1);
+			}
 		}
-	}
-	else if (drawable->getVObj())
-	{
-		switch (drawable->getVObj()->getPCode())
+		else if (drawable->getVObj())
 		{
-			case LLViewerObject::LL_VO_SURFACE_PATCH:
-					gGL.color4f(0,1,1,1);
-					break;
-			case LLViewerObject::LL_VO_CLOUDS:
-					gGL.color4f(0.5f,0.5f,0.5f,1.0f);
-					break;
-			case LLViewerObject::LL_VO_PART_GROUP:
+			switch (drawable->getVObj()->getPCode())
+			{
+				case LLViewerObject::LL_VO_SURFACE_PATCH:
+						gGL.color4f(0,1,1,1);
+						break;
+				case LLViewerObject::LL_VO_CLOUDS:
+						gGL.color4f(0.5f,0.5f,0.5f,1.0f);
+						break;
+				case LLViewerObject::LL_VO_PART_GROUP:
 			case LLViewerObject::LL_VO_HUD_PART_GROUP:
-					gGL.color4f(0,0,1,1);
-					break;
-			case LLViewerObject::LL_VO_WATER:
-					gGL.color4f(0,0.5f,1,1);
-					break;
-			case LL_PCODE_LEGACY_TREE:
-					gGL.color4f(0,0.5f,0,1);
-			default:
-					gGL.color4f(1,0,1,1);
-					break;
+						gGL.color4f(0,0,1,1);
+						break;
+				case LLViewerObject::LL_VO_WATER:
+						gGL.color4f(0,0.5f,1,1);
+						break;
+				case LL_PCODE_LEGACY_TREE:
+						gGL.color4f(0,0.5f,0,1);
+				default:
+						gGL.color4f(1,0,1,1);
+						break;
+			}
+		}
+		else 
+		{
+			gGL.color4f(1,0,0,1);
 		}
-	}
-	else 
-	{
-		gGL.color4f(1,0,0,1);
 	}
 
 	const LLVector3* ext;
@@ -2156,7 +2312,8 @@ void renderBoundingBox(LLDrawable* drawable)
 	if (vobj && vobj->onActiveList())
 	{
 		gGL.flush();
-		glLineWidth(4.f*(sinf(gFrameTimeSeconds*2.f)*0.25f+0.75f));
+		glLineWidth(llmax(4.f*sinf(gFrameTimeSeconds*2.f)+1.f, 1.f));
+		//glLineWidth(4.f*(sinf(gFrameTimeSeconds*2.f)*0.25f+0.75f));
 		stop_glerror();
 		drawBoxOutline(pos,size);
 		gGL.flush();
@@ -2379,8 +2536,7 @@ class LLOctreeRenderNonOccluded : public LLOctreeTraveler<LLDrawable>
 			}
 
 			//render visibility wireframe
-			if (group->mSpatialPartition->mRenderByGroup &&
-				gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION))
+			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION))
 			{
 				gGL.flush();
 				glPushMatrix();
@@ -2456,6 +2612,51 @@ class LLOctreeRenderNonOccluded : public LLOctreeTraveler<LLDrawable>
 	}
 };
 
+class LLOctreePushBBoxVerts : public LLOctreeTraveler<LLDrawable>
+{
+public:
+	LLCamera* mCamera;
+	LLOctreePushBBoxVerts(LLCamera* camera): mCamera(camera) {}
+	
+	virtual void traverse(const LLSpatialGroup::OctreeNode* node)
+	{
+		LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
+		
+		if (!mCamera || mCamera->AABBInFrustum(group->mBounds[0], group->mBounds[1]))
+		{
+			node->accept(this);
+
+			for (U32 i = 0; i < node->getChildCount(); i++)
+			{
+				traverse(node->getChild(i));
+			}
+		}
+	}
+
+	virtual void visit(const LLSpatialGroup::OctreeNode* branch)
+	{
+		LLSpatialGroup* group = (LLSpatialGroup*) branch->getListener(0);
+
+		if (group->isState(LLSpatialGroup::GEOM_DIRTY) || (mCamera && !mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1])))
+		{
+			return;
+		}
+
+		for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i)
+		{
+			LLDrawable* drawable = *i;
+						
+			renderBoundingBox(drawable, FALSE);			
+		}
+	}
+};
+
+void LLSpatialPartition::renderIntersectingBBoxes(LLCamera* camera)
+{
+	LLOctreePushBBoxVerts pusher(camera);
+	pusher.traverse(mOctree);
+}
+
 void LLSpatialPartition::renderDebug()
 {
 	if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCTREE |
@@ -2661,9 +2862,22 @@ LLDrawInfo::LLDrawInfo(U16 start, U16 end, U32 count, U32 offset,
 	mParticle(particle),
 	mPartSize(part_size),
 	mVSize(0.f),
-	mGroup(NULL)
+	mGroup(NULL),
+	mFace(NULL),
+	mDistance(0.f)
 {
 	mDebugColor = (rand() << 16) + rand();
+	if (mStart >= mVertexBuffer->getRequestedVerts() ||
+		mEnd >= mVertexBuffer->getRequestedVerts())
+	{
+		llerrs << "Invalid draw info vertex range." << llendl;
+	}
+
+	if (mOffset >= (U32) mVertexBuffer->getRequestedIndices() ||
+		mOffset + mCount > (U32) mVertexBuffer->getRequestedIndices())
+	{
+		llerrs << "Invalid draw info index range." << llendl;
+	}
 }
 
 LLDrawInfo::~LLDrawInfo()	
@@ -2672,6 +2886,11 @@ LLDrawInfo::~LLDrawInfo()
 	{
 		llerrs << "LLDrawInfo deleted illegally!" << llendl;
 	}
+
+	if (mFace)
+	{
+		mFace->setDrawInfo(NULL);
+	}
 }
 
 LLVertexBuffer* LLGeometryManager::createVertexBuffer(U32 type_mask, U32 usage)
diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h
index 2f0d80414d8062dd3e04600ba019ccfd5dd32a7d..4d67b374c818ced28d6de0eeadd5179f6f3f2122 100644
--- a/indra/newview/llspatialpartition.h
+++ b/indra/newview/llspatialpartition.h
@@ -42,6 +42,7 @@
 #include "llgltypes.h"
 #include "llcubemap.h"
 #include "lldrawpool.h"
+#include "llface.h"
 
 #include <queue>
 
@@ -55,6 +56,9 @@ class LLSpatialGroup;
 S32 AABBSphereIntersect(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &rad);
 S32 AABBSphereIntersectR2(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &radius_squared);
 
+// get index buffer for binary encoded axis vertex buffer given a box at center being viewed by given camera
+U8* get_box_fan_indices(LLCamera* camera, const LLVector3& center);
+
 class LLDrawInfo : public LLRefCount 
 {
 protected:
@@ -82,6 +86,9 @@ class LLDrawInfo : public LLRefCount
 	F32 mPartSize;
 	F32 mVSize;
 	LLSpatialGroup* mGroup;
+	LLFace* mFace; //associated face
+	F32 mDistance;
+	LLVector3 mExtents[2];
 
 	struct CompareTexture
 	{
@@ -101,6 +108,16 @@ class LLDrawInfo : public LLRefCount
 		}
 	};
 
+	struct CompareVertexBuffer
+	{ //sort by texture
+		bool operator()(const LLPointer<LLDrawInfo>& lhs, const LLPointer<LLDrawInfo>& rhs)	
+		{
+			// sort by pointer, sort NULL down to the end
+			return lhs.get() != rhs.get() 
+					&& (lhs.isNull() || (rhs.notNull() && lhs->mVertexBuffer.get() > rhs->mVertexBuffer.get()));
+		}
+	};
+
 	struct CompareTexturePtrMatrix
 	{
 		bool operator()(const LLPointer<LLDrawInfo>& lhs, const LLPointer<LLDrawInfo>& rhs)	
@@ -121,6 +138,16 @@ class LLDrawInfo : public LLRefCount
 						&& (lhs.isNull() || (rhs.notNull() && lhs->mBump > rhs->mBump));
 		}
 	};
+
+	struct CompareDistanceGreater
+	{
+		bool operator()(const LLPointer<LLDrawInfo>& lhs, const LLPointer<LLDrawInfo>& rhs) 
+		{
+			// sort by mBump value, sort NULL down to the end
+			return lhs.get() != rhs.get() 
+						&& (lhs.isNull() || (rhs.notNull() && lhs->mDistance > rhs->mDistance));
+		}
+	};
 };
 
 class LLSpatialGroup : public LLOctreeListener<LLDrawable>
@@ -136,7 +163,8 @@ class LLSpatialGroup : public LLOctreeListener<LLDrawable>
 	typedef std::vector<LLPointer<LLDrawInfo> > drawmap_elem_t; 
 	typedef std::map<U32, drawmap_elem_t > draw_map_t;	
 	typedef std::vector<LLPointer<LLVertexBuffer> > buffer_list_t;
-	typedef std::map<LLPointer<LLViewerImage>, buffer_list_t> buffer_map_t;
+	typedef std::map<LLPointer<LLViewerImage>, buffer_list_t> buffer_texture_map_t;
+	typedef std::map<U32, buffer_texture_map_t> buffer_map_t;
 
 	typedef LLOctreeListener<LLDrawable>	BaseType;
 	typedef LLOctreeListener<LLDrawable>	OctreeListener;
@@ -226,6 +254,7 @@ class LLSpatialGroup : public LLOctreeListener<LLDrawable>
 	BOOL needsUpdate();
 	BOOL changeLOD();
 	void rebuildGeom();
+	void rebuildMesh();
 
 	void dirtyGeom() { setState(GEOM_DIRTY); }
 	void dirtyMesh() { setState(MESH_DIRTY); }
@@ -286,8 +315,10 @@ class LLGeometryManager
 	std::vector<LLFace*> mFaceList;
 	virtual ~LLGeometryManager() { }
 	virtual void rebuildGeom(LLSpatialGroup* group) = 0;
+	virtual void rebuildMesh(LLSpatialGroup* group) = 0;
 	virtual void getGeometry(LLSpatialGroup* group) = 0;
 	virtual void addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32 &index_count);
+	
 	virtual LLVertexBuffer* createVertexBuffer(U32 type_mask, U32 usage);
 };
 
@@ -320,7 +351,9 @@ class LLSpatialPartition: public LLGeometryManager
 	virtual F32 calcPixelArea(LLSpatialGroup* group, LLCamera& camera);
 
 	virtual void rebuildGeom(LLSpatialGroup* group);
+	virtual void rebuildMesh(LLSpatialGroup* group);
 
+	BOOL visibleObjectsInFrustum(LLCamera& camera);
 	S32 cull(LLCamera &camera, std::vector<LLDrawable *>* results = NULL, BOOL for_select = FALSE); // Cull on arbitrary frustum
 	
 	BOOL isVisible(const LLVector3& v);
@@ -329,9 +362,12 @@ class LLSpatialPartition: public LLGeometryManager
 	virtual BOOL isBridge() { return asBridge() != NULL; }
 
 	void renderDebug();
+	void renderIntersectingBBoxes(LLCamera* camera);
 	void restoreGL();
 	void resetVertexBuffers();
-	
+	BOOL isOcclusionEnabled();
+	BOOL getVisibleExtents(LLCamera& camera, LLVector3& visMin, LLVector3& visMax);
+
 public:
 	LLSpatialGroup::OctreeNode* mOctree;
 	BOOL mOcclusionEnabled; // if TRUE, occlusion culling is performed
@@ -445,6 +481,7 @@ class LLCullResult
 	drawinfo_list_t		mRenderMap[LLRenderPass::NUM_RENDER_TYPES];
 };
 
+
 //spatial partition for water (implemented in LLVOWater.cpp)
 class LLWaterPartition : public LLSpatialPartition
 {
@@ -511,8 +548,11 @@ class LLVolumeGeometryManager: public LLGeometryManager
 public:
 	virtual ~LLVolumeGeometryManager() { }
 	virtual void rebuildGeom(LLSpatialGroup* group);
+	virtual void rebuildMesh(LLSpatialGroup* group);
 	virtual void getGeometry(LLSpatialGroup* group);
+	void genDrawInfo(LLSpatialGroup* group, U32 mask, std::vector<LLFace*>& faces, BOOL distance_sort = FALSE);
 	void registerFace(LLSpatialGroup* group, LLFace* facep, U32 type);
+
 };
 
 //spatial partition that uses volume geometry manager (implemented in LLVOVolume.cpp)
@@ -522,6 +562,7 @@ class LLVolumePartition : public LLSpatialPartition, public LLVolumeGeometryMana
 	LLVolumePartition();
 	virtual void rebuildGeom(LLSpatialGroup* group) { LLVolumeGeometryManager::rebuildGeom(group); }
 	virtual void getGeometry(LLSpatialGroup* group) { LLVolumeGeometryManager::getGeometry(group); }
+	virtual void rebuildMesh(LLSpatialGroup* group) { LLVolumeGeometryManager::rebuildMesh(group); }
 	virtual void addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32& index_count) { LLVolumeGeometryManager::addGeometryCount(group, vertex_count, index_count); }
 };
 
@@ -532,6 +573,7 @@ class LLVolumeBridge : public LLSpatialBridge, public LLVolumeGeometryManager
 	LLVolumeBridge(LLDrawable* drawable);
 	virtual void rebuildGeom(LLSpatialGroup* group) { LLVolumeGeometryManager::rebuildGeom(group); }
 	virtual void getGeometry(LLSpatialGroup* group) { LLVolumeGeometryManager::getGeometry(group); }
+	virtual void rebuildMesh(LLSpatialGroup* group) { LLVolumeGeometryManager::rebuildMesh(group); }
 	virtual void addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32& index_count) { LLVolumeGeometryManager::addGeometryCount(group, vertex_count, index_count); }
 };
 
diff --git a/indra/newview/llsprite.cpp b/indra/newview/llsprite.cpp
index a819903d80c162d3eb538064e5151d5b8ea82562..893ed222971b9c019b6e856eb3abbd6f9c01e1c8 100644
--- a/indra/newview/llsprite.cpp
+++ b/indra/newview/llsprite.cpp
@@ -195,7 +195,7 @@ void LLSprite::updateFace(LLFace &face)
 	if (face.mVertexBuffer.isNull())
 	{	
 		face.mVertexBuffer = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX | 
-												LLVertexBuffer::MAP_TEXCOORD,
+												LLVertexBuffer::MAP_TEXCOORD0,
 												GL_STREAM_DRAW_ARB);
 		face.mVertexBuffer->allocateBuffer(4, 12, TRUE);
 		face.setGeomIndex(0);
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index b4f8f6b71ecea179661f405190aadc94707e0e1f..f6e3b14ddb21ee0e49af86cb5ad611c32dc9b4a4 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -737,8 +737,6 @@ bool idle_startup()
 		LL_DEBUGS("AppInit") << "Initializing Window" << LL_ENDL;
 		
 		gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW);
-		// Push our window frontmost
-		gViewerWindow->getWindow()->show();
 
 		timeout_count = 0;
 
@@ -794,6 +792,10 @@ bool idle_startup()
 		gLoginMenuBarView->setVisible( TRUE );
 		gLoginMenuBarView->setEnabled( TRUE );
 
+		// Push our window frontmost
+		gViewerWindow->getWindow()->show();
+		display_startup();
+
 		// DEV-16927.  The following code removes errant keystrokes that happen while the window is being 
 		// first made visible.
 #ifdef _WIN32
@@ -1800,7 +1802,13 @@ bool idle_startup()
 		{
 			LL_DEBUGS("AppInit") << "Initializing sky..." << LL_ENDL;
 			// Initialize all of the viewer object classes for the first time (doing things like texture fetches.
+			LLGLState::checkStates();
+			LLGLState::checkTextureChannels();
+
 			gSky.init(initial_sun_direction);
+
+			LLGLState::checkStates();
+			LLGLState::checkTextureChannels();
 		}
 
 		LL_DEBUGS("AppInit") << "Decoding images..." << LL_ENDL;
@@ -2372,8 +2380,14 @@ bool idle_startup()
 		{
 			update_texture_fetch();
 			set_startup_status(0.60f + 0.30f * timeout_frac,
-				"Loading world...",
+				LLTrans::getString("LoginPrecaching"),
 					gAgent.mMOTD);
+			display_startup();
+			if (!LLViewerShaderMgr::sInitialized)
+			{
+				LLViewerShaderMgr::sInitialized = TRUE;
+				LLViewerShaderMgr::instance()->setShaders();
+			}
 		}
 
 		return TRUE;
diff --git a/indra/newview/llsurface.cpp b/indra/newview/llsurface.cpp
index dcb8f6d5b1d348b6459451cd3d620af441c8da98..a27f0e22540dc487560c5c7cc734da9dd1a7fde6 100644
--- a/indra/newview/llsurface.cpp
+++ b/indra/newview/llsurface.cpp
@@ -253,7 +253,7 @@ void LLSurface::createSTexture()
 		mSTexturep = new LLViewerImage(raw, FALSE);
 		mSTexturep->dontDiscard();
 		gGL.getTexUnit(0)->bind(mSTexturep.get());
-		mSTexturep->setClamp(TRUE, TRUE);
+		mSTexturep->setAddressMode(LLTexUnit::TAM_CLAMP);
 		gImageList.addImage(mSTexturep);
 	}
 }
@@ -278,7 +278,7 @@ void LLSurface::createWaterTexture()
 		mWaterTexturep = new LLViewerImage(raw, FALSE);
 		mWaterTexturep->dontDiscard();
 		gGL.getTexUnit(0)->bind(mWaterTexturep.get());
-		mWaterTexturep->setClamp(TRUE, TRUE);
+		mWaterTexturep->setAddressMode(LLTexUnit::TAM_CLAMP);
 		gImageList.addImage(mWaterTexturep);
 	}
 }
@@ -299,7 +299,7 @@ void LLSurface::initTextures()
 	{
 		createWaterTexture();
 		mWaterObjp = (LLVOWater *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_WATER, mRegionp);
-		gPipeline.addObject(mWaterObjp);
+		gPipeline.createObject(mWaterObjp);
 		LLVector3d water_pos_global = from_region_handle(mRegionp->getHandle());
 		water_pos_global += LLVector3d(128.0, 128.0, DEFAULT_WATER_HEIGHT);
 		mWaterObjp->setPositionGlobal(water_pos_global);
diff --git a/indra/newview/llsurfacepatch.cpp b/indra/newview/llsurfacepatch.cpp
index 59231b3d69411b403918e9fd9733412e44f01b2c..5fac5fd1e43f2e49889e86acefda14f442d5e3c4 100644
--- a/indra/newview/llsurfacepatch.cpp
+++ b/indra/newview/llsurfacepatch.cpp
@@ -128,7 +128,7 @@ void LLSurfacePatch::setSurface(LLSurface *surfacep)
 		mVObjp = (LLVOSurfacePatch *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_SURFACE_PATCH, mSurfacep->getRegion());
 		mVObjp->setPatch(this);
 		mVObjp->setPositionRegion(mCenterRegion);
-		gPipeline.addObject(mVObjp);
+		gPipeline.createObject(mVObjp);
 	}
 } 
 
diff --git a/indra/newview/lltexlayer.cpp b/indra/newview/lltexlayer.cpp
index 709fcd166b98c09d02934fa5f257020bf144a072..6a7ba7b7f424113f693c8bcfe1369600b7d9c6cc 100644
--- a/indra/newview/lltexlayer.cpp
+++ b/indra/newview/lltexlayer.cpp
@@ -57,10 +57,6 @@
 
 //#include "../tools/imdebug/imdebug.h"
 
-
-// SJB: We really always want to use the GL cache;
-// let GL page textures in and out of video RAM instead of trying to do so by hand.
-
 // static
 S32 LLTexLayerSetBuffer::sGLByteCount = 0;
 S32 LLTexLayerSetBuffer::sGLBumpByteCount = 0;
@@ -151,10 +147,9 @@ void LLTexLayerSetBuffer::createBumpTexture()
 
 		gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
 
-		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+		gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
 
-		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, mWidth, mHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+		LLImageGL::setManualImage(GL_TEXTURE_2D, 0, GL_RGBA8, mWidth, mHeight, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
 		stop_glerror();
 
 		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
@@ -1375,15 +1370,14 @@ BOOL LLTexLayer::render( S32 x, S32 y, S32 width, S32 height )
 				{
 					LLGLDisable alpha_test(getInfo()->mWriteAllChannels ? GL_ALPHA_TEST : 0);
 
-					BOOL old_clamps = image_gl->getClampS();
-					BOOL old_clampt = image_gl->getClampT();
+					LLTexUnit::eTextureAddressMode old_mode = image_gl->getAddressMode();
 					
 					gGL.getTexUnit(0)->bind(image_gl);
-					image_gl->setClamp(TRUE, TRUE);
+					gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
 
 					gl_rect_2d_simple_tex( width, height );
 
-					image_gl->setClamp(old_clamps, old_clampt);
+					gGL.getTexUnit(0)->setTextureAddressMode(old_mode);
 					gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 				}
 			}
@@ -1575,14 +1569,14 @@ BOOL LLTexLayer::renderAlphaMasks( S32 x, S32 y, S32 width, S32 height, LLColor4
 				{
 					LLGLSNoAlphaTest gls_no_alpha_test;
 
-					BOOL old_clamps = image_gl->getClampS();
-					BOOL old_clampt = image_gl->getClampT();					
+					LLTexUnit::eTextureAddressMode old_mode = image_gl->getAddressMode();
+					
 					gGL.getTexUnit(0)->bind(image_gl);
-					image_gl->setClamp(TRUE, TRUE);
+					gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
 
 					gl_rect_2d_simple_tex( width, height );
 
-					image_gl->setClamp(old_clamps, old_clampt);
+					gGL.getTexUnit(0)->setTextureAddressMode(old_mode);
 					gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 				}
 			}
@@ -1719,21 +1713,20 @@ BOOL LLTexLayer::renderImageRaw( U8* in_data, S32 in_width, S32 in_height, S32 i
 			internal_format = GL_ALPHA8;
 		}
 		
-		GLuint name = 0;
-		glGenTextures(1, &name );
+		U32 name = 0;
+		LLImageGL::generateTextures(1, &name );
 		stop_glerror();
 
 		gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, name);
 		stop_glerror();
 
-		glTexImage2D(
+		LLImageGL::setManualImage(
 			GL_TEXTURE_2D, 0, internal_format, 
 			in_width, in_height,
-			0, format, GL_UNSIGNED_BYTE, in_data );
+			format, GL_UNSIGNED_BYTE, in_data );
 		stop_glerror();
 
-		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+		gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
 		
 		gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
 
@@ -1741,7 +1734,7 @@ BOOL LLTexLayer::renderImageRaw( U8* in_data, S32 in_width, S32 in_height, S32 i
 
 		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 
-		glDeleteTextures(1, &name );
+		LLImageGL::deleteTextures(1, &name );
 		stop_glerror();
 	}
 	else
@@ -2016,7 +2009,7 @@ BOOL LLTexLayerParamAlpha::render( S32 x, S32 y, S32 width, S32 height )
 		if(	!mCachedProcessedImageGL ||
 			(mCachedProcessedImageGL->getWidth() != image_tga_width) ||
 			(mCachedProcessedImageGL->getHeight() != image_tga_height) ||
-			(weight_changed ))
+			(weight_changed) )
 		{
 //			llinfos << "Building Cached Alpha: " << mName << ": (" << mStaticImageRaw->getWidth() << ", " << mStaticImageRaw->getHeight() << ") " << effective_weight << llendl;
 			mCachedEffectiveWeight = effective_weight;
@@ -2028,7 +2021,6 @@ BOOL LLTexLayerParamAlpha::render( S32 x, S32 y, S32 width, S32 height )
 				// We now have something in one of our caches
 				LLTexLayerSet::sHasCaches |= mCachedProcessedImageGL ? TRUE : FALSE;
 
-
 				mCachedProcessedImageGL->setExplicitFormat( GL_ALPHA8, GL_ALPHA );
 			}
 
@@ -2047,9 +2039,8 @@ BOOL LLTexLayerParamAlpha::render( S32 x, S32 y, S32 width, S32 height )
 				{
 					mCachedProcessedImageGL->createGLTexture(0, mStaticImageRaw);
 					mNeedsCreateTexture = FALSE;
-					
 					gGL.getTexUnit(0)->bind(mCachedProcessedImageGL);
-					mCachedProcessedImageGL->setClamp(TRUE, TRUE);
+					mCachedProcessedImageGL->setAddressMode(LLTexUnit::TAM_CLAMP);
 				}
 
 				LLGLSNoAlphaTest gls_no_alpha_test;
@@ -2504,7 +2495,7 @@ LLImageGL* LLTexStaticImageList::getImageGL(const std::string& file_name, BOOL i
 			image_gl->createGLTexture(0, image_raw);
 
 			gGL.getTexUnit(0)->bind(image_gl);
-			image_gl->setClamp(TRUE, TRUE);
+			image_gl->setAddressMode(LLTexUnit::TAM_CLAMP);
 
 			mStaticImageListGL [ namekey ] = image_gl;
 			mGLBytes += (S32)image_gl->getWidth() * image_gl->getHeight() * image_gl->getComponents();
diff --git a/indra/newview/lltexlayer.h b/indra/newview/lltexlayer.h
index 97b55a3d06ff1f5f9c02db9ab1628d129ba27a35..5ab8c91f72f7e2a9408e24cde345a6926bb83c3e 100644
--- a/indra/newview/lltexlayer.h
+++ b/indra/newview/lltexlayer.h
@@ -533,7 +533,6 @@ class LLTexStaticImageList
 	S32 mTGABytes;
 };
 
-
 // Used by LLTexLayerSetBuffer for a callback.
 class LLBakedUploadData
 {
diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp
index d3f1744f2fe8d781702d38c2e12194bc19279cfd..69723f622a69ea1a52c0ce8897891161f1ffcb58 100644
--- a/indra/newview/lltexturecache.cpp
+++ b/indra/newview/lltexturecache.cpp
@@ -175,7 +175,7 @@ class LLTextureCacheLocalFileWorker : public LLTextureCacheWorker
 
 bool LLTextureCacheLocalFileWorker::doRead()
 {
-	S32 local_size = ll_apr_file_size(mFileName, mCache->getFileAPRPool());
+	S32 local_size = LLAPRFile::size(mFileName, mCache->getLocalAPRFilePool());
 
 	if (local_size > 0 && mFileName.size() > 4)
 	{
@@ -248,8 +248,9 @@ bool LLTextureCacheLocalFileWorker::doRead()
 		mDataSize = local_size;
 	}
 	mReadData = new U8[mDataSize];
-	S32 bytes_read = ll_apr_file_read_ex(mFileName, mCache->getFileAPRPool(),
-										 mReadData, mOffset, mDataSize);
+	
+	S32 bytes_read = LLAPRFile::readEx(mFileName, mReadData, mOffset, mDataSize, mCache->getLocalAPRFilePool());	
+
 	if (bytes_read != mDataSize)
 	{
 // 		llwarns << "Error reading file from local cache: " << mFileName
@@ -317,11 +318,11 @@ bool LLTextureCacheRemoteWorker::doRead()
 	{
 		std::string filename = mCache->getLocalFileName(mID);	
 		local_filename = filename + ".j2c";
-		local_size = ll_apr_file_size(local_filename, mCache->getFileAPRPool());
+		local_size = LLAPRFile::size(local_filename, mCache->getLocalAPRFilePool());
 		if (local_size == 0)
 		{
 			local_filename = filename + ".tga";
-			local_size = ll_apr_file_size(local_filename, mCache->getFileAPRPool());
+			local_size = LLAPRFile::size(local_filename, mCache->getLocalAPRFilePool());
 			if (local_size > 0)
 			{
 				mImageFormat = IMG_CODEC_TGA;
@@ -389,8 +390,8 @@ bool LLTextureCacheRemoteWorker::doRead()
 			mDataSize = local_size;
 		}
 		mReadData = new U8[mDataSize];
-		S32 bytes_read = ll_apr_file_read_ex(local_filename, mCache->getFileAPRPool(),
-											 mReadData, mOffset, mDataSize);
+		S32 bytes_read = LLAPRFile::readEx(local_filename, 
+											 mReadData, mOffset, mDataSize, mCache->getLocalAPRFilePool());
 		if (bytes_read != mDataSize)
 		{
 // 			llwarns << "Error reading file from local cache: " << local_filename
@@ -483,8 +484,8 @@ bool LLTextureCacheRemoteWorker::doRead()
 		S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset;
 		S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
 		mReadData = new U8[size];
-		S32 bytes_read = ll_apr_file_read_ex(mCache->mHeaderDataFileName, mCache->getFileAPRPool(),
-											 mReadData, offset, size);
+		S32 bytes_read = LLAPRFile::readEx(mCache->mHeaderDataFileName, 
+											 mReadData, offset, size, mCache->getLocalAPRFilePool());
 		if (bytes_read != size)
 		{
 // 			llwarns << "LLTextureCacheWorker: "  << mID
@@ -510,7 +511,7 @@ bool LLTextureCacheRemoteWorker::doRead()
 		if (mFileHandle == LLLFSThread::nullHandle())
 		{
 			std::string filename = mCache->getTextureFileName(mID);
-			S32 filesize = ll_apr_file_size(filename, mCache->getFileAPRPool());
+			S32 filesize = LLAPRFile::size(filename, mCache->getLocalAPRFilePool());
 			if (filesize > mOffset)
 			{
 				S32 datasize = TEXTURE_CACHE_ENTRY_SIZE + filesize;
@@ -569,7 +570,7 @@ bool LLTextureCacheRemoteWorker::doRead()
 		}
 #else
 		std::string filename = mCache->getTextureFileName(mID);
-		S32 filesize = ll_apr_file_size(filename, mCache->getFileAPRPool());
+		S32 filesize = LLAPRFile::size(filename, mCache->getLocalAPRFilePool());
 		S32 bytes_read = 0;
 		if (filesize > mOffset)
 		{
@@ -589,9 +590,10 @@ bool LLTextureCacheRemoteWorker::doRead()
 				delete[] mReadData;
 			}
 			mReadData = data;
-			bytes_read = ll_apr_file_read_ex(filename, mCache->getFileAPRPool(),
+			bytes_read = LLAPRFile::readEx(filename, 
 											 mReadData + data_offset,
-											 file_offset, file_size);
+											 file_offset, file_size,
+											 mCache->getLocalAPRFilePool());
 			if (bytes_read != file_size)
 			{
 // 				llwarns << "LLTextureCacheWorker: "  << mID
@@ -694,8 +696,7 @@ bool LLTextureCacheRemoteWorker::doWrite()
 		llassert_always(mOffset < TEXTURE_CACHE_ENTRY_SIZE);
 		S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset;
 		S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
-		S32 bytes_written = ll_apr_file_write_ex(mCache->mHeaderDataFileName, mCache->getFileAPRPool(),
-												 mWriteData, offset, size);
+		S32 bytes_written = LLAPRFile::writeEx(mCache->mHeaderDataFileName, mWriteData, offset, size, mCache->getLocalAPRFilePool());		
 
 		if (bytes_written <= 0)
 		{
@@ -770,9 +771,11 @@ bool LLTextureCacheRemoteWorker::doWrite()
 		if (file_size > 0 && mCache->appendToTextureEntryList(mID, file_size))
 		{
 			std::string filename = mCache->getTextureFileName(mID);
-			bytes_written = ll_apr_file_write_ex(filename, mCache->getFileAPRPool(),
+			
+			bytes_written = LLAPRFile::writeEx(filename, 
 												 mWriteData + data_offset,
-												 file_offset, file_size);
+												 file_offset, file_size,
+												 mCache->getLocalAPRFilePool());
 			if (bytes_written <= 0)
 			{
 				mDataSize = -1; // failed
@@ -793,13 +796,14 @@ bool LLTextureCacheRemoteWorker::doWrite()
 //virtual
 bool LLTextureCacheWorker::doWork(S32 param)
 {
+// *TODO reenable disabled apr_pool usage disabled due to maint-render-9 merge breakage -brad
 	//allocate a new local apr_pool
-	LLAPRPool pool ;
+//	LLAPRPool pool ;
 
 	//save the current mFileAPRPool to avoid breaking anything.
-	apr_pool_t* old_pool = mCache->getFileAPRPool() ;
+//	apr_pool_t* old_pool = mCache->getFileAPRPool() ;
 	//make mFileAPRPool to point to the local one
-	mCache->setFileAPRPool(pool.getAPRPool()) ;
+//	mCache->setFileAPRPool(pool.getAPRPool()) ;
 
 	bool res = false;
 	if (param == 0) // read
@@ -816,7 +820,7 @@ bool LLTextureCacheWorker::doWork(S32 param)
 	}
 
 	//set mFileAPRPool back, the local one will be released automatically.
-	mCache->setFileAPRPool(old_pool) ;
+//	mCache->setFileAPRPool(old_pool) ;
 
 	return res;
 }
@@ -880,20 +884,17 @@ void LLTextureCacheWorker::endWork(S32 param, bool aborted)
 
 LLTextureCache::LLTextureCache(bool threaded)
 	: LLWorkerThread("TextureCache", threaded),
-	  mWorkersMutex(getAPRPool()),
-	  mHeaderMutex(getAPRPool()),
-	  mListMutex(getAPRPool()),
-	  mFileAPRPool(NULL),
+	  mWorkersMutex(NULL),
+	  mHeaderMutex(NULL),
+	  mListMutex(NULL),
 	  mReadOnly(FALSE),
 	  mTexturesSizeTotal(0),
 	  mDoPurge(FALSE)
 {
-	apr_pool_create(&mFileAPRPool, NULL);
 }
 
 LLTextureCache::~LLTextureCache()
 {
-	apr_pool_destroy(mFileAPRPool);
 }
 
 //////////////////////////////////////////////////////////////////////////////
@@ -969,8 +970,10 @@ bool LLTextureCache::appendToTextureEntryList(const LLUUID& id, S32 bodysize)
 		{
 			llassert_always(bodysize > 0);
 			Entry* entry = new Entry(id, bodysize, time(NULL));
-			ll_apr_file_write_ex(mTexturesDirEntriesFileName, getFileAPRPool(),
-								 (U8*)entry, -1, 1*sizeof(Entry));
+
+			LLAPRFile::writeEx(mTexturesDirEntriesFileName,
+								 (U8*)entry, -1, 1*sizeof(Entry),
+								 getLocalAPRFilePool());			
 			delete entry;
 			if (iter != mTexturesSizeMap.end())
 			{
@@ -1018,8 +1021,8 @@ void LLTextureCache::purgeCache(ELLPath location)
 	{
 		setDirNames(location);
 	
-		ll_apr_file_remove(mHeaderEntriesFileName, NULL);
-		ll_apr_file_remove(mHeaderDataFileName, NULL);
+		LLAPRFile::remove(mHeaderEntriesFileName, getLocalAPRFilePool());
+		LLAPRFile::remove(mHeaderDataFileName, getLocalAPRFilePool());
 	}
 	purgeAllTextures(true);
 }
@@ -1081,15 +1084,16 @@ struct lru_data
 };
 
 // Called from either the main thread or the worker thread
-void LLTextureCache::readHeaderCache(apr_pool_t* poolp)
+void LLTextureCache::readHeaderCache()
 {
 	LLMutexLock lock(&mHeaderMutex);
 	mHeaderEntriesInfo.mVersion = 0.f;
 	mHeaderEntriesInfo.mEntries = 0;
-	if (ll_apr_file_exists(mHeaderEntriesFileName, poolp))
+	if (LLAPRFile::isExist(mHeaderEntriesFileName, getLocalAPRFilePool()))
 	{
-		ll_apr_file_read_ex(mHeaderEntriesFileName, poolp,
-							(U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo));
+		LLAPRFile::readEx(mHeaderEntriesFileName,
+							(U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo),
+							getLocalAPRFilePool());
 	}
 	if (mHeaderEntriesInfo.mVersion != sHeaderCacheVersion)
 	{
@@ -1097,8 +1101,10 @@ void LLTextureCache::readHeaderCache(apr_pool_t* poolp)
 		{
 			// Info with 0 entries
 			mHeaderEntriesInfo.mVersion = sHeaderCacheVersion;
-			ll_apr_file_write_ex(mHeaderEntriesFileName, poolp,
-								 (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo));
+
+			LLAPRFile::writeEx(mHeaderEntriesFileName, 
+								 (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo),
+								 getLocalAPRFilePool());
 		}
 	}
 	else
@@ -1107,8 +1113,11 @@ void LLTextureCache::readHeaderCache(apr_pool_t* poolp)
 		if (num_entries)
 		{
 			Entry* entries = new Entry[num_entries];
-			ll_apr_file_read_ex(mHeaderEntriesFileName, poolp,
-								(U8*)entries, sizeof(EntriesInfo), num_entries*sizeof(Entry));
+			{
+				LLAPRFile::readEx(mHeaderEntriesFileName, 
+								(U8*)entries, sizeof(EntriesInfo), num_entries*sizeof(Entry),
+								getLocalAPRFilePool());
+			}
 			typedef std::set<lru_data*, lru_data::Compare> lru_set_t;
 			lru_set_t lru;
 			for (S32 i=0; i<num_entries; i++)
@@ -1153,7 +1162,7 @@ void LLTextureCache::purgeAllTextures(bool purge_directories)
 				LLFile::rmdir(dirname);
 			}
 		}
-		ll_apr_file_remove(mTexturesDirEntriesFileName, NULL);
+		LLAPRFile::remove(mTexturesDirEntriesFileName, getLocalAPRFilePool());
 		if (purge_directories)
 		{
 			LLFile::rmdir(mTexturesDirName);
@@ -1174,7 +1183,7 @@ void LLTextureCache::purgeTextures(bool validate)
 
 	LLMutexLock lock(&mHeaderMutex);
 	
-	S32 filesize = ll_apr_file_size(mTexturesDirEntriesFileName, NULL);
+	S32 filesize = LLAPRFile::size(mTexturesDirEntriesFileName, getLocalAPRFilePool());
 	S32 num_entries = filesize / sizeof(Entry);
 	if (num_entries * (S32)sizeof(Entry) != filesize)
 	{
@@ -1188,8 +1197,9 @@ void LLTextureCache::purgeTextures(bool validate)
 	}
 	
 	Entry* entries = new Entry[num_entries];
-	S32 bytes_read = ll_apr_file_read_ex(mTexturesDirEntriesFileName, NULL,
-										 (U8*)entries, 0, num_entries*sizeof(Entry));
+	S32 bytes_read = LLAPRFile::readEx(mTexturesDirEntriesFileName, 
+										 (U8*)entries, 0, num_entries*sizeof(Entry),
+										 getLocalAPRFilePool());	
 	if (bytes_read != filesize)
 	{
 		LL_WARNS("TextureCache") << "Bad cache file (2): " << mTexturesDirEntriesFileName << " Purging." << LL_ENDL;
@@ -1248,7 +1258,7 @@ void LLTextureCache::purgeTextures(bool validate)
 			if (uuididx == validate_idx)
 			{
  				LL_DEBUGS("TextureCache") << "Validating: " << filename << "Size: " << entries[idx].mSize << LL_ENDL;
-				S32 bodysize = ll_apr_file_size(filename, NULL);
+				S32 bodysize = LLAPRFile::size(filename, getLocalAPRFilePool());
 				if (bodysize != entries[idx].mSize)
 				{
 					LL_WARNS("TextureCache") << "TEXTURE CACHE BODY HAS BAD SIZE: " << bodysize << " != " << entries[idx].mSize
@@ -1261,7 +1271,7 @@ void LLTextureCache::purgeTextures(bool validate)
 		{
 			purge_count++;
 	 		LL_DEBUGS("TextureCache") << "PURGING: " << filename << LL_ENDL;
-			ll_apr_file_remove(filename, NULL);
+			LLAPRFile::remove(filename, getLocalAPRFilePool());
 			total_size -= entries[idx].mSize;
 			entries[idx].mSize = 0;
 		}
@@ -1278,9 +1288,10 @@ void LLTextureCache::purgeTextures(bool validate)
 
 	LL_DEBUGS("TextureCache") << "TEXTURE CACHE: Writing Entries: " << num_entries << LL_ENDL;
 	
-	ll_apr_file_remove(mTexturesDirEntriesFileName, NULL);
-	ll_apr_file_write_ex(mTexturesDirEntriesFileName, NULL,
-						 (U8*)&entries[0], 0, num_entries*sizeof(Entry));
+	LLAPRFile::remove(mTexturesDirEntriesFileName, getLocalAPRFilePool());
+	LLAPRFile::writeEx(mTexturesDirEntriesFileName, 
+						 (U8*)&entries[0], 0, num_entries*sizeof(Entry),
+						 getLocalAPRFilePool());
 	
 	mTexturesSizeTotal = 0;
 	mTexturesSizeMap.clear();
@@ -1351,8 +1362,9 @@ S32 LLTextureCache::getHeaderCacheEntry(const LLUUID& id, bool touch, S32* image
 				idx = mHeaderEntriesInfo.mEntries++;
 				mHeaderIDMap[id] = idx;
 				// Update Info
-				ll_apr_file_write_ex(mHeaderEntriesFileName, getFileAPRPool(),
-									(U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo));
+				LLAPRFile::writeEx(mHeaderEntriesFileName, 
+									(U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo),
+									getLocalAPRFilePool());
 			}
 			else if (!mLRU.empty())
 			{
@@ -1377,8 +1389,9 @@ S32 LLTextureCache::getHeaderCacheEntry(const LLUUID& id, bool touch, S32* image
 				llassert_always(imagesize && *imagesize > 0);
 				Entry* entry = new Entry(id, *imagesize, time(NULL));
 				S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry);
-				ll_apr_file_write_ex(mHeaderEntriesFileName, getFileAPRPool(),
-									 (U8*)entry, offset, sizeof(Entry));
+				LLAPRFile::writeEx(mHeaderEntriesFileName, 
+									 (U8*)entry, offset, sizeof(Entry),
+									 getLocalAPRFilePool());
 				delete entry;
 			}
 			else if (imagesize)
@@ -1386,15 +1399,17 @@ S32 LLTextureCache::getHeaderCacheEntry(const LLUUID& id, bool touch, S32* image
 				// Get the image size
 				Entry entry;
 				S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry);
-				ll_apr_file_read_ex(mHeaderEntriesFileName, getFileAPRPool(),
-									(U8*)&entry, offset, sizeof(Entry));
+
+				LLAPRFile::readEx(mHeaderEntriesFileName, 
+									(U8*)&entry, offset, sizeof(Entry),
+									getLocalAPRFilePool());
 				*imagesize = entry.mSize;
 			}
 		}
 	}
 	if (retry)
 	{
-		readHeaderCache(getFileAPRPool()); // updates the lru
+		readHeaderCache(); // updates the lru
 		llassert_always(!mLRU.empty() || mHeaderEntriesInfo.mEntries < sCacheMaxEntries);
 		idx = getHeaderCacheEntry(id, touch, imagesize); // assert above ensures no inf. recursion
 	}
@@ -1468,7 +1483,7 @@ LLTextureCache::handle_t LLTextureCache::writeToCache(const LLUUID& id, U32 prio
 	{
 		// NOTE: This may cause an occasional hiccup,
 		//  but it really needs to be done on the control thread
-		//  (i.e. here)
+		//  (i.e. here)		
 		purgeTextures(false);
 		mDoPurge = FALSE;
 	}
@@ -1540,8 +1555,10 @@ bool LLTextureCache::removeHeaderCacheEntry(const LLUUID& id)
 		{
 			Entry* entry = new Entry(id, -1, time(NULL));
 			S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry);
-			ll_apr_file_write_ex(mHeaderEntriesFileName, NULL,
-								 (U8*)entry, offset, sizeof(Entry));
+
+			LLAPRFile::writeEx(mHeaderEntriesFileName,
+								 (U8*)entry, offset, sizeof(Entry),
+								 getLocalAPRFilePool());			
 			delete entry;
 			mLRU[idx] = id;
 			mHeaderIDMap.erase(id);
@@ -1558,7 +1575,7 @@ void LLTextureCache::removeFromCache(const LLUUID& id)
 	if (!mReadOnly)
 	{
 		removeHeaderCacheEntry(id);
-		ll_apr_file_remove(getTextureFileName(id), NULL);
+		LLAPRFile::remove(getTextureFileName(id), getLocalAPRFilePool());
 	}
 }
 
diff --git a/indra/newview/lltexturecache.h b/indra/newview/lltexturecache.h
index fa42b5d58e7ff108a1a3566509b511b4463e1d82..68b1458e9a80e0443802543cd4babe37114aea81 100644
--- a/indra/newview/lltexturecache.h
+++ b/indra/newview/lltexturecache.h
@@ -109,18 +109,17 @@ class LLTextureCache : public LLWorkerThread
 
 protected:
 	// Accessed by LLTextureCacheWorker
-	apr_pool_t* getFileAPRPool() { return mFileAPRPool; }
 	bool appendToTextureEntryList(const LLUUID& id, S32 size);
 	std::string getLocalFileName(const LLUUID& id);
 	std::string getTextureFileName(const LLUUID& id);
 	void addCompleted(Responder* responder, bool success);
 	
 protected:
-	void setFileAPRPool(apr_pool_t* pool) { mFileAPRPool = pool ; }
+	//void setFileAPRPool(apr_pool_t* pool) { mFileAPRPool = pool ; }
 
 private:
 	void setDirNames(ELLPath location);
-	void readHeaderCache(apr_pool_t* poolp = NULL);
+	void readHeaderCache();
 	void purgeAllTextures(bool purge_directories);
 	void purgeTextures(bool validate);
 	S32 getHeaderCacheEntry(const LLUUID& id, bool touch, S32* imagesize = NULL);
@@ -133,7 +132,6 @@ class LLTextureCache : public LLWorkerThread
 	LLMutex mWorkersMutex;
 	LLMutex mHeaderMutex;
 	LLMutex mListMutex;
-	apr_pool_t* mFileAPRPool;
 	
 	typedef std::map<handle_t, LLTextureCacheWorker*> handle_map_t;
 	handle_map_t mReaders;
diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index 3fcb9c50be5f085bbceca82fb618a0e0b0b00fdb..e9dd7921cd3e8a469461b4de1e6a7dd9deb693f0 100644
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -416,7 +416,7 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,
 	  mInLocalCache(FALSE),
 	  mRetryAttempt(0),
 	  mActiveCount(0),
-	  mWorkMutex(fetcher->getWorkerAPRPool()),
+	  mWorkMutex(NULL),
 	  mFirstPacket(0),
 	  mLastPacket(-1),
 	  mTotalPackets(0),
@@ -435,7 +435,6 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,
 
 LLTextureFetchWorker::~LLTextureFetchWorker()
 {
-	llassert_always(LLWorkerClass::sDeleteLock) ;
 // 	llinfos << "Destroy: " << mID
 // 			<< " Decoded=" << mDecodedDiscard
 // 			<< " Requested=" << mRequestedDiscard
diff --git a/indra/newview/llviewercamera.cpp b/indra/newview/llviewercamera.cpp
index 5a2230c34ceddf711b143ad0fca901d5d32a9435..f54830f39f4bf13b7ccf81340cf08db7370ba079 100644
--- a/indra/newview/llviewercamera.cpp
+++ b/indra/newview/llviewercamera.cpp
@@ -83,6 +83,21 @@ glh::matrix4f gl_perspective(GLfloat fovy, GLfloat aspect, GLfloat zNear, GLfloa
 						 0, 0, -1.f, 0);
 }
 
+glh::matrix4f gl_lookat(LLVector3 eye, LLVector3 center, LLVector3 up)
+{
+	LLVector3 f = center-eye;
+	f.normVec();
+	up.normVec();
+	LLVector3 s = f % up;
+	LLVector3 u = s % f;
+
+	return glh::matrix4f(s[0], s[1], s[2], 0,
+					  u[0], u[1], u[2], 0,
+					  -f[0], -f[1], -f[2], 0,
+					  0, 0, 0, 1);
+	
+}
+
 LLViewerCamera::LLViewerCamera() : LLCamera()
 {
 	calcProjection(getFar());
@@ -183,7 +198,7 @@ void LLViewerCamera::calcProjection(const F32 far_distance) const
 // height.
 
 //static
-void LLViewerCamera::updateFrustumPlanes(LLCamera& camera, BOOL ortho, BOOL zflip)
+void LLViewerCamera::updateFrustumPlanes(LLCamera& camera, BOOL ortho, BOOL zflip, BOOL no_hacks)
 {
 	GLint* viewport = (GLint*) gGLViewport;
 	GLdouble* model = gGLModelView;
@@ -192,7 +207,27 @@ void LLViewerCamera::updateFrustumPlanes(LLCamera& camera, BOOL ortho, BOOL zfli
 
 	LLVector3 frust[8];
 
-	if (zflip)
+	if (no_hacks)
+	{
+		gluUnProject(viewport[0],viewport[1],0,model,proj,viewport,&objX,&objY,&objZ);
+		frust[0].setVec((F32)objX,(F32)objY,(F32)objZ);
+		gluUnProject(viewport[0]+viewport[2],viewport[1],0,model,proj,viewport,&objX,&objY,&objZ);
+		frust[1].setVec((F32)objX,(F32)objY,(F32)objZ);
+		gluUnProject(viewport[0]+viewport[2],viewport[1]+viewport[3],0,model,proj,viewport,&objX,&objY,&objZ);
+		frust[2].setVec((F32)objX,(F32)objY,(F32)objZ);
+		gluUnProject(viewport[0],viewport[1]+viewport[3],0,model,proj,viewport,&objX,&objY,&objZ);
+		frust[3].setVec((F32)objX,(F32)objY,(F32)objZ);
+
+		gluUnProject(viewport[0],viewport[1],1,model,proj,viewport,&objX,&objY,&objZ);
+		frust[4].setVec((F32)objX,(F32)objY,(F32)objZ);
+		gluUnProject(viewport[0]+viewport[2],viewport[1],1,model,proj,viewport,&objX,&objY,&objZ);
+		frust[5].setVec((F32)objX,(F32)objY,(F32)objZ);
+		gluUnProject(viewport[0]+viewport[2],viewport[1]+viewport[3],1,model,proj,viewport,&objX,&objY,&objZ);
+		frust[6].setVec((F32)objX,(F32)objY,(F32)objZ);
+		gluUnProject(viewport[0],viewport[1]+viewport[3],1,model,proj,viewport,&objX,&objY,&objZ);
+		frust[7].setVec((F32)objX,(F32)objY,(F32)objZ);
+	}
+	else if (zflip)
 	{
 		gluUnProject(viewport[0],viewport[1]+viewport[3],0,model,proj,viewport,&objX,&objY,&objZ);
 		frust[0].setVec((F32)objX,(F32)objY,(F32)objZ);
@@ -232,7 +267,7 @@ void LLViewerCamera::updateFrustumPlanes(LLCamera& camera, BOOL ortho, BOOL zfli
 		
 		if (ortho)
 		{
-			LLVector3 far_shift = LLVector3(camera.getFar()*2.0f,0,0);
+			LLVector3 far_shift = camera.getAtAxis()*camera.getFar()*2.f; 
 			for (U32 i = 0; i < 4; i++)
 			{
 				frust[i+4] = frust[i] + far_shift;
@@ -369,13 +404,13 @@ void LLViewerCamera::setPerspective(BOOL for_selection,
 
 	updateFrustumPlanes(*this);
 
-	if (gSavedSettings.getBOOL("CameraOffset"))
+	/*if (gSavedSettings.getBOOL("CameraOffset"))
 	{
 		glMatrixMode(GL_PROJECTION);
 		glTranslatef(0,0,-50);
 		glRotatef(20.0,1,0,0);
 		glMatrixMode(GL_MODELVIEW);
-	}
+	}*/
 }
 
 
diff --git a/indra/newview/llviewercamera.h b/indra/newview/llviewercamera.h
index 5e21fda09dbfa42eec1b6e2751dba54bf81d5c51..6a0c42beecda541e7643946615793b9371c97be0 100644
--- a/indra/newview/llviewercamera.h
+++ b/indra/newview/llviewercamera.h
@@ -60,7 +60,7 @@ class LLViewerCamera : public LLCamera, public LLSingleton<LLViewerCamera>
 								const LLVector3 &up_direction,
 								const LLVector3 &point_of_interest);
 
-	static void updateFrustumPlanes(LLCamera& camera, BOOL ortho = FALSE, BOOL zflip = FALSE);
+	static void updateFrustumPlanes(LLCamera& camera, BOOL ortho = FALSE, BOOL zflip = FALSE, BOOL no_hacks = FALSE);
 	void setPerspective(BOOL for_selection, S32 x, S32 y_from_bot, S32 width, S32 height, BOOL limit_select_distance, F32 z_near = 0, F32 z_far = 0);
 
 	const LLMatrix4 &getProjection() const;
diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index 16a830a11090aa2c014e80a5511efec9c54aaace..1a40da9c1feeba078d7f44d6c9767dbc56698b72 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -355,19 +355,24 @@ static bool handleRenderUseFBOChanged(const LLSD& newvalue)
 	{
 		gPipeline.releaseGLBuffers();
 		gPipeline.createGLBuffers();
+		if (LLPipeline::sRenderDeferred && LLRenderTarget::sUseFBO)
+		{
+			LLViewerShaderMgr::instance()->setShaders();
+		}
 	}
 	return true;
 }
 
 static bool handleRenderUseImpostorsChanged(const LLSD& newvalue)
 {
-	LLVOAvatar::sUseImpostors = FALSE; //newvalue.asBoolean();
+	LLVOAvatar::sUseImpostors = newvalue.asBoolean();
 	return true;
 }
 
 static bool handleRenderDebugGLChanged(const LLSD& newvalue)
 {
 	gDebugGL = newvalue.asBoolean();
+	gGL.clearErrors();
 	return true;
 }
 
@@ -437,6 +442,7 @@ void settings_setup_listeners()
 	gSavedSettings.getControl("FirstPersonAvatarVisible")->getSignal()->connect(boost::bind(&handleRenderAvatarMouselookChanged, _1));
 	gSavedSettings.getControl("RenderFarClip")->getSignal()->connect(boost::bind(&handleRenderFarClipChanged, _1));
 	gSavedSettings.getControl("RenderTerrainDetail")->getSignal()->connect(boost::bind(&handleTerrainDetailChanged, _1));
+	gSavedSettings.getControl("RenderAnimateTrees")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _1));
 	gSavedSettings.getControl("RenderAvatarVP")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _1));
 	gSavedSettings.getControl("VertexShaderEnable")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _1));
 	gSavedSettings.getControl("RenderGlow")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _1));
@@ -462,6 +468,7 @@ void settings_setup_listeners()
 	gSavedSettings.getControl("RenderObjectBump")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _1));
 	gSavedSettings.getControl("RenderMaxVBOSize")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _1));
 	gSavedSettings.getControl("RenderUseFBO")->getSignal()->connect(boost::bind(&handleRenderUseFBOChanged, _1));
+	gSavedSettings.getControl("RenderDeferredNoise")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _1));
 	gSavedSettings.getControl("RenderUseImpostors")->getSignal()->connect(boost::bind(&handleRenderUseImpostorsChanged, _1));
 	gSavedSettings.getControl("RenderDebugGL")->getSignal()->connect(boost::bind(&handleRenderDebugGLChanged, _1));
 	gSavedSettings.getControl("RenderDebugPipeline")->getSignal()->connect(boost::bind(&handleRenderDebugPipelineChanged, _1));
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index 9099ddc8963f84e6e7705a64735b227111e4aa44..54c6f0a71ff2ce8f359a7d6bf8d51232e30fd97c 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -108,7 +108,7 @@ LLFrameTimer gRecentMemoryTime;
 // Rendering stuff
 void pre_show_depth_buffer();
 void post_show_depth_buffer();
-void render_ui();
+void render_ui(F32 zoom_factor = 1.f, int subfield = 0);
 void render_hud_attachments();
 void render_ui_3d();
 void render_ui_2d();
@@ -161,9 +161,9 @@ void display_startup()
 	glClear(GL_DEPTH_BUFFER_BIT);
 }
 
-
 void display_update_camera()
 {
+	llpushcallstacks ;
 	// TODO: cut draw distance down if customizing avatar?
 	// TODO: cut draw distance on per-parcel basis?
 
@@ -500,12 +500,13 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 		if (LLDynamicTexture::updateAllInstances())
 		{
 			gGL.setColorMask(true, true);
-			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+			glClear(GL_DEPTH_BUFFER_BIT);
 		}
 	}
 
 	gViewerWindow->setupViewport();
-	
+
+	gPipeline.resetFrameStats();	// Reset per-frame statistics.
 	if (!gDisconnected)
 	{
 		LLAppViewer::instance()->pingMainloopTimeout("Display:Update");
@@ -528,6 +529,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 		
 		gFrameStats.start(LLFrameStats::UPDATE_GEOM);
 		const F32 max_geom_update_time = 0.005f*10.f*gFrameIntervalSeconds; // 50 ms/second update time
+		gPipeline.createObjects(max_geom_update_time);
 		gPipeline.updateGeom(max_geom_update_time);
 		stop_glerror();
 		
@@ -557,10 +559,17 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 				&& LLFeatureManager::getInstance()->isFeatureAvailable("UseOcclusion") 
 				&& gSavedSettings.getBOOL("UseOcclusion") 
 				&& gGLManager.mHasOcclusionQuery) ? 2 : 0;
+
+		if (LLPipeline::sUseOcclusion && LLPipeline::sRenderDeferred)
+		{ //force occlusion on for all render types if doing deferred render
+			LLPipeline::sUseOcclusion = 3;
+		}
+
 		LLPipeline::sFastAlpha = gSavedSettings.getBOOL("RenderFastAlpha");
 		LLPipeline::sUseFarClip = gSavedSettings.getBOOL("RenderUseFarClip");
 		LLVOAvatar::sMaxVisible = gSavedSettings.getS32("RenderAvatarMaxVisible");
-		
+		LLPipeline::sDelayVBUpdate = gSavedSettings.getBOOL("RenderDelayVBUpdate");
+
 		S32 occlusion = LLPipeline::sUseOcclusion;
 		if (gDepthDirty)
 		{ //depth buffer is invalid, don't overwrite occlusion state
@@ -568,18 +577,25 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 		}
 		gDepthDirty = FALSE;
 
+		LLGLState::checkStates();
+		LLGLState::checkTextureChannels();
+		LLGLState::checkClientArrays();
+
 		static LLCullResult result;
 		gPipeline.updateCull(*LLViewerCamera::getInstance(), result, water_clip);
 		stop_glerror();
 
+		LLGLState::checkStates();
+		LLGLState::checkTextureChannels();
+		LLGLState::checkClientArrays();
+
 		BOOL to_texture = !for_snapshot &&
 						gPipeline.canUseVertexShaders() &&
 						LLPipeline::sRenderGlow;
 
 		LLAppViewer::instance()->pingMainloopTimeout("Display:Swap");
 		
-		// now do the swap buffer (just before rendering to framebuffer)
-		{ //swap and flush state from previous frame
+		{ 
 			{
  				LLFastTimer ftm(LLFastTimer::FTM_CLIENT_COPY);
 				LLVertexBuffer::clientCopy(0.016);
@@ -593,14 +609,29 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 
 			gGL.setColorMask(true, true);
 			glClearColor(0,0,0,0);
-			
+
+			LLGLState::checkStates();
+			LLGLState::checkTextureChannels();
+			LLGLState::checkClientArrays();
+
 			if (!for_snapshot)
 			{
+				if (gFrameCount > 1)
+				{ //for some reason, ATI 4800 series will error out if you 
+				  //try to generate a shadow before the first frame is through
+					gPipeline.generateSunShadow(*LLViewerCamera::getInstance());
+				}
+
+				LLGLState::checkStates();
+				LLGLState::checkTextureChannels();
+				LLGLState::checkClientArrays();
+
 				glh::matrix4f proj = glh_get_current_projection();
 				glh::matrix4f mod = glh_get_current_modelview();
 				glViewport(0,0,512,512);
 				LLVOAvatar::updateFreezeCounter() ;
 				LLVOAvatar::updateImpostors();
+
 				glh_set_current_projection(proj);
 				glh_set_current_modelview(mod);
 				glMatrixMode(GL_PROJECTION);
@@ -608,8 +639,13 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 				glMatrixMode(GL_MODELVIEW);
 				glLoadMatrixf(mod.m);
 				gViewerWindow->setupViewport();
+
+				LLGLState::checkStates();
+				LLGLState::checkTextureChannels();
+				LLGLState::checkClientArrays();
+
 			}
-			glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+			glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
 		}
 
 		if (!for_snapshot)
@@ -626,6 +662,8 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 		//
 		// Doing this here gives hardware occlusion queries extra time to complete
 		LLAppViewer::instance()->pingMainloopTimeout("Display:UpdateImages");
+		LLError::LLCallStacks::clear() ;
+		llpushcallstacks ;
 		gFrameStats.start(LLFrameStats::IMAGE_UPDATE);
 
 		{
@@ -640,7 +678,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 			gImageList.updateImages(max_image_decode_time);
 			stop_glerror();
 		}
-
+		llpushcallstacks ;
 		///////////////////////////////////
 		//
 		// StateSort
@@ -722,11 +760,25 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 		//	glPopMatrix();
 		//}
 
+		LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater() ? TRUE : FALSE;
+		LLPipeline::updateRenderDeferred();
+		
+		stop_glerror();
+
 		if (to_texture)
 		{
 			gGL.setColorMask(true, true);
-			gPipeline.mScreen.bindTarget();
-			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+			if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender)
+			{
+				gPipeline.mDeferredScreen.bindTarget();
+				gPipeline.mDeferredScreen.clear();
+			}
+			else
+			{
+				gPipeline.mScreen.bindTarget();
+				gPipeline.mScreen.clear();
+			}
+			
 			gGL.setColorMask(true, false);
 		}
 		
@@ -737,9 +789,15 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 		{
 
 			gGL.setColorMask(true, false);
-			LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater() ? TRUE : FALSE;
-			gPipeline.renderGeom(*LLViewerCamera::getInstance(), TRUE);
-			LLPipeline::sUnderWaterRender = FALSE;
+			if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender)
+			{
+				gPipeline.renderGeomDeferred(*LLViewerCamera::getInstance());
+			}
+			else
+			{
+				gPipeline.renderGeom(*LLViewerCamera::getInstance(), TRUE);
+			}
+			
 			gGL.setColorMask(true, true);
 
 			//store this frame's modelview matrix for use
@@ -755,8 +813,14 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 		
 		if (to_texture)
 		{
-
-			gPipeline.mScreen.flush();
+			if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender)
+			{
+				gPipeline.mDeferredScreen.flush();
+			}
+			else
+			{
+				gPipeline.mScreen.flush();
+			}
 		}
 
 		/// We copy the frame buffer straight into a texture here,
@@ -765,8 +829,14 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 		/// grasp of their full display stack just yet.
 		// gPostProcess->apply(gViewerWindow->getWindowDisplayWidth(), gViewerWindow->getWindowDisplayHeight());
 		
+		if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender)
+		{
+			gPipeline.renderDeferredLighting();
+		}
+
+		LLPipeline::sUnderWaterRender = FALSE;
+
 		LLAppViewer::instance()->pingMainloopTimeout("Display:RenderUI");
-		
 		if (!for_snapshot)
 		{
 			gFrameStats.start(LLFrameStats::RENDER_UI);
@@ -818,7 +888,10 @@ void render_hud_attachments()
 		//only render hud objects
 		U32 mask = gPipeline.getRenderTypeMask();
 		gPipeline.setRenderTypeMask(0);
-		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD);
+		if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
+		{
+			gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD);
+		}
 
 		BOOL has_ui = gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI);
 		if (has_ui)
@@ -829,16 +902,18 @@ void render_hud_attachments()
 		S32 use_occlusion = LLPipeline::sUseOcclusion;
 		LLPipeline::sUseOcclusion = 0;
 		LLPipeline::sDisableShaders = TRUE;
-
+		
 		//cull, sort, and render hud objects
 		static LLCullResult result;
 		LLSpatialGroup::sNoDelete = TRUE;
+
 		gPipeline.updateCull(hud_cam, result);
 
 		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_BUMP);
 		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_SIMPLE);
 		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_VOLUME);
 		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_ALPHA);
+		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_FULLBRIGHT);
 		
 		gPipeline.stateSort(hud_cam, result);
 
@@ -935,7 +1010,7 @@ BOOL setup_hud_matrices(const LLRect& screen_region)
 }
 
 
-void render_ui()
+void render_ui(F32 zoom_factor, int subfield)
 {
 	LLGLState::checkStates();
 	
@@ -950,7 +1025,7 @@ void render_ui()
 
 		if (to_texture)
 		{
-			gPipeline.renderBloom(gSnapshot);
+			gPipeline.renderBloom(gSnapshot, zoom_factor, subfield);
 		}
 
 		render_hud_elements();
diff --git a/indra/newview/llviewerjoint.cpp b/indra/newview/llviewerjoint.cpp
index 5a21ac68d3742db122965a2e80846db6b8f2b1a3..89490e08bf40f2f0085811791a52b773702cd972 100644
--- a/indra/newview/llviewerjoint.cpp
+++ b/indra/newview/llviewerjoint.cpp
@@ -244,6 +244,8 @@ void LLViewerJoint::setValid( BOOL valid, BOOL recursive )
 //--------------------------------------------------------------------
 U32 LLViewerJoint::render( F32 pixelArea, BOOL first_pass )
 {
+	stop_glerror();
+
 	U32 triangle_count = 0;
 
 	//----------------------------------------------------------------
@@ -261,6 +263,10 @@ U32 LLViewerJoint::render( F32 pixelArea, BOOL first_pass )
 		{
 			triangle_count += drawShape( pixelArea, first_pass );
 		}
+		else if (LLPipeline::sShadowRender)
+		{
+			triangle_count += drawShape(pixelArea, first_pass);
+		}
 		else if ( isTransparent() && !LLPipeline::sReflectionRender)
 		{
 			// Hair and Skirt
diff --git a/indra/newview/llviewerjointmesh.cpp b/indra/newview/llviewerjointmesh.cpp
index 0d5c19570ab5329360d36c93aa3b7e786a64dfe5..4cacc5c97b6d35aff8576102ea198e9f3d711572 100644
--- a/indra/newview/llviewerjointmesh.cpp
+++ b/indra/newview/llviewerjointmesh.cpp
@@ -73,7 +73,7 @@ extern BOOL gRenderForSelect;
 static LLPointer<LLVertexBuffer> sRenderBuffer = NULL;
 static const U32 sRenderMask = LLVertexBuffer::MAP_VERTEX |
 							   LLVertexBuffer::MAP_NORMAL |
-							   LLVertexBuffer::MAP_TEXCOORD;
+							   LLVertexBuffer::MAP_TEXCOORD0;
 
 
 //-----------------------------------------------------------------------------
@@ -459,14 +459,13 @@ void LLViewerJointMesh::uploadJointMatrices()
 			for (S32 axis = 0; axis < NUM_AXES; axis++)
 			{
 				F32* vector = gJointMatUnaligned[joint_num].mMatrix[axis];
-				//glProgramLocalParameter4fvARB(GL_VERTEX_PROGRAM_ARB, LL_CHARACTER_MAX_JOINTS_PER_MESH * axis + joint_num+5, (GLfloat*)vector);
 				U32 offset = LL_CHARACTER_MAX_JOINTS_PER_MESH*axis+joint_num;
 				memcpy(mat+offset*4, vector, sizeof(GLfloat)*4);
-				//glProgramLocalParameter4fvARB(GL_VERTEX_PROGRAM_ARB, LL_CHARACTER_MAX_JOINTS_PER_MESH * axis + joint_num+6, (GLfloat*)vector);
-				//cgGLSetParameterArray4f(gPipeline.mAvatarMatrix, offset, 1, vector);
 			}
 		}
+		stop_glerror();
 		glUniform4fvARB(gAvatarMatrixParam, 45, mat);
+		stop_glerror();
 	}
 }
 
@@ -536,6 +535,7 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass)
 	//----------------------------------------------------------------
 	llassert( !(mTexture.notNull() && mLayerSet) );  // mutually exclusive
 
+	LLTexUnit::eTextureAddressMode old_mode = LLTexUnit::TAM_WRAP;
 	if (mTestImageName)
 	{
 		gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mTestImageName);
@@ -565,11 +565,9 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass)
 	else
 	if ( mTexture.notNull() )
 	{
-		if (!mTexture->getClampS() || !mTexture->getClampT())
-		{
-			gGL.getTexUnit(0)->bind(mTexture.get());
-			mTexture->overrideClamp (TRUE, TRUE);
-		}
+		old_mode = mTexture->getAddressMode();
+		gGL.getTexUnit(0)->bind(mTexture.get());
+		gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
 	}
 	else
 	{
@@ -628,7 +626,7 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass)
 	if (mTexture.notNull())
 	{
 		gGL.getTexUnit(0)->bind(mTexture.get());
-		mTexture->restoreClamp();
+		gGL.getTexUnit(0)->setTextureAddressMode(old_mode);
 	}
 
 	return triangle_count;
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 417117bdf12cfeaa2847d8fcab599bcf9027114e..de16bbf8a15bf0695bb1f37f246adfb04dba8589 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -1047,6 +1047,7 @@ void init_debug_ui_menu(LLMenuGL* menu)
 	menu->appendSeparator();
 	menu->append(new LLMenuItemCheckGL("Show Time", menu_toggle_control, NULL, menu_check_control, (void*)"DebugShowTime"));
 	menu->append(new LLMenuItemCheckGL("Show Render Info", menu_toggle_control, NULL, menu_check_control, (void*)"DebugShowRenderInfo"));
+	menu->append(new LLMenuItemCheckGL("Show Matrices", menu_toggle_control, NULL, menu_check_control, (void*)"DebugShowRenderMatrices"));
 	menu->append(new LLMenuItemCheckGL("Show Color Under Cursor", menu_toggle_control, NULL, menu_check_control, (void*)"DebugShowColor"));
 	
 	menu->createJumpKeys();
@@ -1184,6 +1185,9 @@ void init_debug_rendering_menu(LLMenuGL* menu)
 	sub_menu->append(new LLMenuItemCheckGL("Octree",	&LLPipeline::toggleRenderDebug, NULL,
 													&LLPipeline::toggleRenderDebugControl,
 													(void*)LLPipeline::RENDER_DEBUG_OCTREE));
+	sub_menu->append(new LLMenuItemCheckGL("Shadow Frusta",	&LLPipeline::toggleRenderDebug, NULL,
+													&LLPipeline::toggleRenderDebugControl,
+													(void*)LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA));
 	sub_menu->append(new LLMenuItemCheckGL("Occlusion",	&LLPipeline::toggleRenderDebug, NULL,
 													&LLPipeline::toggleRenderDebugControl,
 													(void*)LLPipeline::RENDER_DEBUG_OCCLUSION));
diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp
index a6dede1e382761f393f7007486e465be75dab31d..2925916e2ac6396c7a679789ff42e3fe281951d5 100644
--- a/indra/newview/llviewermenufile.cpp
+++ b/indra/newview/llviewermenufile.cpp
@@ -788,8 +788,9 @@ void upload_new_resource(const std::string& src_filename, std::string name,
 		uuid = tid.makeAssetID(gAgent.getSecureSessionID());
 		// copy this file into the vfs for upload
 		S32 file_size;
-		apr_file_t* fp = ll_apr_file_open(filename, LL_APR_RB, &file_size);
-		if (fp)
+		LLAPRFile infile ;
+		infile.open(filename, LL_APR_RB, NULL, &file_size);
+		if (infile.getFileHandle())
 		{
 			LLVFile file(gVFS, uuid, asset_type, LLVFile::WRITE);
 
@@ -797,11 +798,10 @@ void upload_new_resource(const std::string& src_filename, std::string name,
 
 			const S32 buf_size = 65536;
 			U8 copy_buf[buf_size];
-			while ((file_size = ll_apr_file_read(fp, copy_buf, buf_size)))
+			while ((file_size = infile.read(copy_buf, buf_size)))
 			{
 				file.write(copy_buf, file_size);
 			}
-			apr_file_close(fp);
 		}
 		else
 		{
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index bd433c0c73d0e723229bc0db2fbfb99558c35dbb..e4ddbd42dd3a0f3ba3d55f55bc1e69c8347426c1 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -1406,7 +1406,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
 				}
 
 				// Setup object text
-				if (!mText)
+				if (!mText && (value & 0x4))
 				{
 					mText = (LLHUDText *)LLHUDObject::addHUDObject(LLHUDObject::LL_HUD_TEXT);
 					mText->setFont(LLFontGL::sSansSerif);
@@ -1428,7 +1428,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
 
 					setChanged(TEXTURE);
 				}
-				else
+				else if(mText.notNull())
 				{
 					mText->markDead();
 					mText = NULL;
@@ -3730,11 +3730,11 @@ S32 LLViewerObject::setTEColor(const U8 te, const LLColor4& color)
 	else if (color != tep->getColor())
 	{
 		retval = LLPrimitive::setTEColor(te, color);
-		setChanged(TEXTURE);
+		//setChanged(TEXTURE);
 		if (mDrawable.notNull() && retval)
 		{
 			// These should only happen on updates which are not the initial update.
-			gPipeline.markTextured(mDrawable);
+			dirtyMesh();
 		}
 	}
 	return retval;
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index 45ab630e354e2351afc5d2642630b5467ccc8fb2..16a3b98d1296069e7937657f769ebf476f06f29e 100644
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -131,6 +131,8 @@ class LLViewerObject : public LLPrimitive, public LLRefCount
 
 public:
 	typedef std::list<LLPointer<LLViewerObject> > child_list_t;
+	typedef std::list<LLPointer<LLViewerObject> > vobj_list_t;
+
 	typedef const child_list_t const_child_list_t;
 
 	LLViewerObject(const LLUUID &id, const LLPCode type, LLViewerRegion *regionp, BOOL is_global = FALSE);
diff --git a/indra/newview/llviewerparceloverlay.cpp b/indra/newview/llviewerparceloverlay.cpp
index b66f2c83beb7612d3c553fa2d71a77b86ea387cf..866c2a91ebb5f76e757cd61d7acd976a8c4e674f 100644
--- a/indra/newview/llviewerparceloverlay.cpp
+++ b/indra/newview/llviewerparceloverlay.cpp
@@ -74,8 +74,8 @@ LLViewerParcelOverlay::LLViewerParcelOverlay(LLViewerRegion* region, F32 region_
 	mTexture->createGLTexture(0, mImageRaw);
 	gGL.getTexUnit(0)->activate();
 	gGL.getTexUnit(0)->bind(mTexture);
-	mTexture->setClamp(TRUE, TRUE);
-	mTexture->setMipFilterNearest(TRUE);
+	mTexture->setAddressMode(LLTexUnit::TAM_CLAMP);
+	mTexture->setFilteringOption(LLTexUnit::TFO_POINT);
 
 	//
 	// Initialize the GL texture with empty data.
diff --git a/indra/newview/llviewerpartsim.cpp b/indra/newview/llviewerpartsim.cpp
index d513c021eeaec027cd51feb21ec9769eddeb1000..b74f9e9f2cd4f15dd485fc32c18ccac6a5b69fbc 100644
--- a/indra/newview/llviewerpartsim.cpp
+++ b/indra/newview/llviewerpartsim.cpp
@@ -152,7 +152,9 @@ LLViewerPartGroup::LLViewerPartGroup(const LLVector3 &center_agent, const F32 bo
 	mVOPartGroupp->setPositionAgent(getCenterAgent());
 	F32 scale = box_side * 0.5f;
 	mVOPartGroupp->setScale(LLVector3(scale,scale,scale));
-	gPipeline.addObject(mVOPartGroupp);
+	
+	//gPipeline.addObject(mVOPartGroupp);
+	gPipeline.createObject(mVOPartGroupp);
 
 	LLSpatialGroup* group = mVOPartGroupp->mDrawable->getSpatialGroup();
 
diff --git a/indra/newview/llviewerpartsource.cpp b/indra/newview/llviewerpartsource.cpp
index dfd97b8e65e6e14acabad5a5330523e0266b899b..38c75a84d1b11f253bd810d48b16941404544800 100644
--- a/indra/newview/llviewerpartsource.cpp
+++ b/indra/newview/llviewerpartsource.cpp
@@ -102,7 +102,7 @@ LLViewerPartSourceScript::LLViewerPartSourceScript(LLViewerObject *source_objp)
 	mPosAgent = mSourceObjectp->getPositionAgent();
 	mImagep = gImageList.getImageFromFile("pixiesmall.j2c");
 	gGL.getTexUnit(0)->bind(mImagep.get());
-	mImagep->setClamp(TRUE, TRUE);
+	mImagep->setAddressMode(LLTexUnit::TAM_CLAMP);
 }
 
 
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index 1c025b42c94f13608a7364b18e62d6b408effa3d..b5bd2f93af8b5480fa4f82f6dd1d388980d979cc 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -63,6 +63,8 @@ using std::pair;
 using std::make_pair;
 using std::string;
 
+BOOL				LLViewerShaderMgr::sInitialized = FALSE;
+
 LLVector4			gShinyOrigin;
 
 //object shaders
@@ -101,7 +103,23 @@ LLGLSLShader			gPostColorFilterProgram;
 LLGLSLShader			gPostNightVisionProgram;
 
 // Deferred rendering shaders
+LLGLSLShader			gDeferredImpostorProgram;
+LLGLSLShader			gDeferredWaterProgram;
 LLGLSLShader			gDeferredDiffuseProgram;
+LLGLSLShader			gDeferredBumpProgram;
+LLGLSLShader			gDeferredTerrainProgram;
+LLGLSLShader			gDeferredTreeProgram;
+LLGLSLShader			gDeferredAvatarProgram;
+LLGLSLShader			gDeferredAvatarAlphaProgram;
+LLGLSLShader			gDeferredLightProgram;
+LLGLSLShader			gDeferredMultiLightProgram;
+LLGLSLShader			gDeferredSunProgram;
+LLGLSLShader			gDeferredBlurLightProgram;
+LLGLSLShader			gDeferredSoftenProgram;
+LLGLSLShader			gDeferredShadowProgram;
+LLGLSLShader			gDeferredAvatarShadowProgram;
+LLGLSLShader			gDeferredAlphaProgram;
+LLGLSLShader			gDeferredFullbrightProgram;
 
 //current avatar shader parameter pointer
 GLint				gAvatarMatrixParam;
@@ -126,6 +144,15 @@ LLViewerShaderMgr::LLViewerShaderMgr() :
 	mShaderList.push_back(&gAvatarWaterProgram);
 	mShaderList.push_back(&gObjectShinyWaterProgram);
 	mShaderList.push_back(&gUnderWaterProgram);
+	mShaderList.push_back(&gDeferredSunProgram);
+	mShaderList.push_back(&gDeferredBlurLightProgram);
+	mShaderList.push_back(&gDeferredSoftenProgram);
+	mShaderList.push_back(&gDeferredLightProgram);
+	mShaderList.push_back(&gDeferredMultiLightProgram);
+	mShaderList.push_back(&gDeferredAlphaProgram);
+	mShaderList.push_back(&gDeferredFullbrightProgram);
+	mShaderList.push_back(&gDeferredWaterProgram);
+	mShaderList.push_back(&gDeferredAvatarAlphaProgram);
 }
 
 LLViewerShaderMgr::~LLViewerShaderMgr()
@@ -188,6 +215,18 @@ void LLViewerShaderMgr::initAttribsAndUniforms(void)
 		mReservedUniforms.push_back("gamma");
 		mReservedUniforms.push_back("scene_light_strength");
 
+		mReservedUniforms.push_back("depthMap");
+		mReservedUniforms.push_back("shadowMap0");
+		mReservedUniforms.push_back("shadowMap1");
+		mReservedUniforms.push_back("shadowMap2");
+		mReservedUniforms.push_back("shadowMap3");
+		mReservedUniforms.push_back("normalMap");
+		mReservedUniforms.push_back("positionMap");
+		mReservedUniforms.push_back("diffuseRect");
+		mReservedUniforms.push_back("specularRect");
+		mReservedUniforms.push_back("noiseMap");
+		mReservedUniforms.push_back("lightMap");
+			
 		mWLUniforms.push_back("camPosLocal");
 
 		mTerrainUniforms.reserve(5);
@@ -240,7 +279,7 @@ S32 LLViewerShaderMgr::getVertexShaderLevel(S32 type)
 
 void LLViewerShaderMgr::setShaders()
 {
-	if (!gPipeline.mInitialized)
+	if (!gPipeline.mInitialized || !sInitialized)
 	{
 		return;
 	}
@@ -254,6 +293,7 @@ void LLViewerShaderMgr::setShaders()
 	{
 		LLPipeline::sWaterReflections = gGLManager.mHasCubeMap;
 		LLPipeline::sRenderGlow = gSavedSettings.getBOOL("RenderGlow"); 
+		LLPipeline::updateRenderDeferred();
 	}
 	else
 	{
@@ -290,36 +330,16 @@ void LLViewerShaderMgr::setShaders()
 		S32 wl_class = 2;
 		S32 water_class = 2;
 		S32 deferred_class = 0;
-		if (!gSavedSettings.getBOOL("WindLightUseAtmosShaders"))
+		if (!(LLFeatureManager::getInstance()->isFeatureAvailable("WindLightUseAtmosShaders")
+			  && gSavedSettings.getBOOL("WindLightUseAtmosShaders")))
 		{
 			// user has disabled WindLight in their settings, downgrade
 			// windlight shaders to stub versions.
 			wl_class = 1;
-
-			// if class one or less, turn off more shaders
-			// since higher end cards won't see any real gain
-			// from turning off most of the shaders,
-			// but class one would
-			// TODO: Make water on class one cards color things
-			// beneath it properly
-			if(LLFeatureManager::getInstance()->getGPUClass() < GPU_CLASS_2)
-			{
-				// use lesser water and other stuff
-				light_class = 2;
-				env_class = 0;
-				obj_class = 0;
-				effect_class = 1;
-				water_class = 1;
-			}
 		}
 
-		if (gSavedSettings.getBOOL("RenderDeferred"))
+		if (LLPipeline::sRenderDeferred)
 		{
-			light_class = 1;
-			env_class = 0;
-			obj_class = 0;
-			water_class = 1;
-			effect_class = 1;
 			deferred_class = 1;
 		}
 
@@ -358,8 +378,7 @@ void LLViewerShaderMgr::setShaders()
 			loadShadersWindLight();
 			loadShadersEffects();
 			loadShadersInterface();
-			loadShadersDeferred();
-
+			
 			// Load max avatar shaders to set the max level
 			mVertexShaderLevel[SHADER_AVATAR] = 3;
 			mMaxAvatarShaderLevel = 3;
@@ -406,6 +425,11 @@ void LLViewerShaderMgr::setShaders()
 				gSavedSettings.setBOOL("RenderAvatarCloth", FALSE);
 				loadShadersAvatar(); // unloads
 			}
+
+			if (!loadShadersDeferred())
+			{
+				gSavedSettings.setBOOL("RenderDeferred", FALSE);
+			}
 #endif
 		}
 		else
@@ -511,6 +535,10 @@ BOOL LLViewerShaderMgr::loadBasicShaders()
 		sum_lights_class = 1;
 	}
 
+	// Use the feature table to mask out the max light level to use.  Also make sure it's at least 1.
+	S32 max_light_class = gSavedSettings.getS32("RenderShaderLightingMaxLevel");
+	sum_lights_class = llclamp(sum_lights_class, 1, max_light_class);
+
 	// Load the Basic Vertex Shaders at the appropriate level. 
 	// (in order of shader function call depth for reference purposes, deepest level first)
 
@@ -779,15 +807,33 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 {
 	if (mVertexShaderLevel[SHADER_DEFERRED] == 0)
 	{
+		gDeferredTreeProgram.unload();
 		gDeferredDiffuseProgram.unload();
+		gDeferredBumpProgram.unload();
+		gDeferredImpostorProgram.unload();
+		gDeferredTerrainProgram.unload();
+		gDeferredLightProgram.unload();
+		gDeferredMultiLightProgram.unload();
+		gDeferredSunProgram.unload();
+		gDeferredBlurLightProgram.unload();
+		gDeferredSoftenProgram.unload();
+		gDeferredShadowProgram.unload();
+		gDeferredAvatarShadowProgram.unload();
+		gDeferredAvatarProgram.unload();
+		gDeferredAvatarAlphaProgram.unload();
+		gDeferredAlphaProgram.unload();
+		gDeferredFullbrightProgram.unload();
+		gDeferredWaterProgram.unload();
 		return FALSE;
 	}
 
+	mVertexShaderLevel[SHADER_AVATAR] = 1;
+
 	BOOL success = TRUE;
 
 	if (success)
 	{
-		gDeferredDiffuseProgram.mName = "Deffered Diffuse Shader";
+		gDeferredDiffuseProgram.mName = "Deferred Diffuse Shader";
 		gDeferredDiffuseProgram.mShaderFiles.clear();
 		gDeferredDiffuseProgram.mShaderFiles.push_back(make_pair("deferred/diffuseV.glsl", GL_VERTEX_SHADER_ARB));
 		gDeferredDiffuseProgram.mShaderFiles.push_back(make_pair("deferred/diffuseF.glsl", GL_FRAGMENT_SHADER_ARB));
@@ -795,6 +841,187 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		success = gDeferredDiffuseProgram.createShader(NULL, NULL);
 	}
 
+	if (success)
+	{
+		gDeferredBumpProgram.mName = "Deferred Bump Shader";
+		gDeferredBumpProgram.mShaderFiles.clear();
+		gDeferredBumpProgram.mShaderFiles.push_back(make_pair("deferred/bumpV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredBumpProgram.mShaderFiles.push_back(make_pair("deferred/bumpF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredBumpProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		success = gDeferredBumpProgram.createShader(NULL, NULL);
+	}
+
+	if (success)
+	{
+		gDeferredTreeProgram.mName = "Deferred Tree Shader";
+		gDeferredTreeProgram.mShaderFiles.clear();
+		gDeferredTreeProgram.mShaderFiles.push_back(make_pair("deferred/treeV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredTreeProgram.mShaderFiles.push_back(make_pair("deferred/treeF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredTreeProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		success = gDeferredTreeProgram.createShader(NULL, NULL);
+	}
+
+	if (success)
+	{
+		gDeferredImpostorProgram.mName = "Deferred Impostor Shader";
+		gDeferredImpostorProgram.mShaderFiles.clear();
+		gDeferredImpostorProgram.mShaderFiles.push_back(make_pair("deferred/impostorV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredImpostorProgram.mShaderFiles.push_back(make_pair("deferred/impostorF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredImpostorProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		success = gDeferredImpostorProgram.createShader(NULL, NULL);
+	}
+
+	if (success)
+	{
+		gDeferredLightProgram.mName = "Deferred Light Shader";
+		gDeferredLightProgram.mShaderFiles.clear();
+		gDeferredLightProgram.mShaderFiles.push_back(make_pair("deferred/pointLightV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredLightProgram.mShaderFiles.push_back(make_pair("deferred/pointLightF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredLightProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		success = gDeferredLightProgram.createShader(NULL, NULL);
+	}
+
+	if (success)
+	{
+		gDeferredMultiLightProgram.mName = "Deferred MultiLight Shader";
+		gDeferredMultiLightProgram.mShaderFiles.clear();
+		gDeferredMultiLightProgram.mShaderFiles.push_back(make_pair("deferred/pointLightV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredMultiLightProgram.mShaderFiles.push_back(make_pair("deferred/multiPointLightF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredMultiLightProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		success = gDeferredMultiLightProgram.createShader(NULL, NULL);
+	}
+
+	if (success)
+	{
+		gDeferredSunProgram.mName = "Deferred Sun Shader";
+		gDeferredSunProgram.mShaderFiles.clear();
+		gDeferredSunProgram.mShaderFiles.push_back(make_pair("deferred/sunLightV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredSunProgram.mShaderFiles.push_back(make_pair("deferred/sunLightF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredSunProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		success = gDeferredSunProgram.createShader(NULL, NULL);
+	}
+
+	if (success)
+	{
+		gDeferredBlurLightProgram.mName = "Deferred Blur Light Shader";
+		gDeferredBlurLightProgram.mShaderFiles.clear();
+		gDeferredBlurLightProgram.mShaderFiles.push_back(make_pair("deferred/blurLightV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredBlurLightProgram.mShaderFiles.push_back(make_pair("deferred/blurLightF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredBlurLightProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		success = gDeferredBlurLightProgram.createShader(NULL, NULL);
+	}
+
+	if (success)
+	{
+		gDeferredAlphaProgram.mName = "Deferred Alpha Shader";
+		gDeferredAlphaProgram.mFeatures.calculatesLighting = true;
+		gDeferredAlphaProgram.mFeatures.calculatesAtmospherics = true;
+		gDeferredAlphaProgram.mFeatures.hasGamma = true;
+		gDeferredAlphaProgram.mFeatures.hasAtmospherics = true;
+		gDeferredAlphaProgram.mFeatures.hasLighting = true;
+		gDeferredAlphaProgram.mShaderFiles.clear();
+		gDeferredAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredAlphaProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		success = gDeferredAlphaProgram.createShader(NULL, NULL);
+	}
+
+	if (success)
+	{
+		gDeferredFullbrightProgram.mName = "Deferred Fullbright Shader";
+		gDeferredFullbrightProgram.mFeatures.calculatesAtmospherics = true;
+		gDeferredFullbrightProgram.mFeatures.hasGamma = true;
+		gDeferredFullbrightProgram.mFeatures.hasTransport = true;
+		gDeferredFullbrightProgram.mFeatures.isFullbright = true;
+		gDeferredFullbrightProgram.mShaderFiles.clear();
+		gDeferredFullbrightProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredFullbrightProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredFullbrightProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		success = gDeferredFullbrightProgram.createShader(NULL, NULL);
+	}
+
+	if (success)
+	{
+		// load water shader
+		gDeferredWaterProgram.mName = "Deferred Water Shader";
+		gDeferredWaterProgram.mFeatures.calculatesAtmospherics = true;
+		gDeferredWaterProgram.mFeatures.hasGamma = true;
+		gDeferredWaterProgram.mFeatures.hasTransport = true;
+		gDeferredWaterProgram.mShaderFiles.clear();
+		gDeferredWaterProgram.mShaderFiles.push_back(make_pair("deferred/waterV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredWaterProgram.mShaderFiles.push_back(make_pair("deferred/waterF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		success = gDeferredWaterProgram.createShader(NULL, &mWaterUniforms);
+	}
+
+	if (success)
+	{
+		gDeferredSoftenProgram.mName = "Deferred Soften Shader";
+		gDeferredSoftenProgram.mShaderFiles.clear();
+		gDeferredSoftenProgram.mShaderFiles.push_back(make_pair("deferred/softenLightV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredSoftenProgram.mShaderFiles.push_back(make_pair("deferred/softenLightF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredSoftenProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		success = gDeferredSoftenProgram.createShader(NULL, NULL);
+	}
+
+	if (success)
+	{
+		gDeferredShadowProgram.mName = "Deferred Shadow Shader";
+		gDeferredShadowProgram.mShaderFiles.clear();
+		gDeferredShadowProgram.mShaderFiles.push_back(make_pair("deferred/shadowV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredShadowProgram.mShaderFiles.push_back(make_pair("deferred/shadowF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredShadowProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		success = gDeferredShadowProgram.createShader(NULL, NULL);
+	}
+
+	if (success)
+	{
+		gDeferredAvatarShadowProgram.mName = "Deferred Avatar Shadow Shader";
+		gDeferredAvatarShadowProgram.mFeatures.hasSkinning = true;
+		gDeferredAvatarShadowProgram.mShaderFiles.clear();
+		gDeferredAvatarShadowProgram.mShaderFiles.push_back(make_pair("deferred/avatarShadowV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredAvatarShadowProgram.mShaderFiles.push_back(make_pair("deferred/avatarShadowF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredAvatarShadowProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		success = gDeferredAvatarShadowProgram.createShader(&mAvatarAttribs, &mAvatarUniforms);
+	}
+
+	if (success)
+	{
+		gTerrainProgram.mName = "Deferred Terrain Shader";
+		gDeferredTerrainProgram.mShaderFiles.clear();
+		gDeferredTerrainProgram.mShaderFiles.push_back(make_pair("deferred/terrainV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredTerrainProgram.mShaderFiles.push_back(make_pair("deferred/terrainF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredTerrainProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		success = gDeferredTerrainProgram.createShader(NULL, &mTerrainUniforms);
+	}
+
+	if (success)
+	{
+		gDeferredAvatarProgram.mName = "Avatar Shader";
+		gDeferredAvatarProgram.mFeatures.hasSkinning = true;
+		gDeferredAvatarProgram.mShaderFiles.clear();
+		gDeferredAvatarProgram.mShaderFiles.push_back(make_pair("deferred/avatarV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredAvatarProgram.mShaderFiles.push_back(make_pair("deferred/avatarF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredAvatarProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		success = gDeferredAvatarProgram.createShader(&mAvatarAttribs, &mAvatarUniforms);
+	}
+
+	if (success)
+	{
+		gDeferredAvatarAlphaProgram.mName = "Avatar Alpha Shader";
+		gDeferredAvatarAlphaProgram.mFeatures.hasSkinning = true;
+		gDeferredAvatarAlphaProgram.mFeatures.calculatesLighting = true;
+		gDeferredAvatarAlphaProgram.mFeatures.calculatesAtmospherics = true;
+		gDeferredAvatarAlphaProgram.mFeatures.hasGamma = true;
+		gDeferredAvatarAlphaProgram.mFeatures.hasAtmospherics = true;
+		gDeferredAvatarAlphaProgram.mFeatures.hasLighting = true;
+		gDeferredAvatarAlphaProgram.mShaderFiles.clear();
+		gDeferredAvatarAlphaProgram.mShaderFiles.push_back(make_pair("deferred/avatarAlphaV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredAvatarAlphaProgram.mShaderFiles.push_back(make_pair("deferred/avatarAlphaF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredAvatarAlphaProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		success = gDeferredAvatarAlphaProgram.createShader(&mAvatarAttribs, &mAvatarUniforms);
+	}
+
 	return success;
 }
 
diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h
index 4cad3a23a82aad3c06f2fd76815c048f6a8fd31c..a743966d93c951f64da693c2617c07afd0b3670c 100644
--- a/indra/newview/llviewershadermgr.h
+++ b/indra/newview/llviewershadermgr.h
@@ -38,6 +38,8 @@
 class LLViewerShaderMgr: public LLShaderMgr
 {
 public:
+	static BOOL sInitialized;
+
 	LLViewerShaderMgr();
 	/* virtual */ ~LLViewerShaderMgr();
 
@@ -109,6 +111,17 @@ class LLViewerShaderMgr: public LLShaderMgr
 		CLOUD_SCALE,
 		GAMMA,
 		SCENE_LIGHT_STRENGTH,
+		DEFERRED_DEPTH,
+		DEFERRED_SHADOW0,
+		DEFERRED_SHADOW1,
+		DEFERRED_SHADOW2,
+		DEFERRED_SHADOW3,
+		DEFERRED_NORMAL,
+		DEFERRED_POSITION,
+		DEFERRED_DIFFUSE,
+		DEFERRED_SPECULAR,
+		DEFERRED_NOISE,
+		DEFERRED_LIGHT,
 		END_RESERVED_UNIFORMS
 	} eGLSLReservedUniforms;
 
@@ -305,7 +318,23 @@ extern LLGLSLShader			gPostColorFilterProgram;
 extern LLGLSLShader			gPostNightVisionProgram;
 
 // Deferred rendering shaders
+extern LLGLSLShader			gDeferredImpostorProgram;
+extern LLGLSLShader			gDeferredWaterProgram;
 extern LLGLSLShader			gDeferredDiffuseProgram;
+extern LLGLSLShader			gDeferredBumpProgram;
+extern LLGLSLShader			gDeferredTerrainProgram;
+extern LLGLSLShader			gDeferredTreeProgram;
+extern LLGLSLShader			gDeferredLightProgram;
+extern LLGLSLShader			gDeferredMultiLightProgram;
+extern LLGLSLShader			gDeferredSunProgram;
+extern LLGLSLShader			gDeferredBlurLightProgram;
+extern LLGLSLShader			gDeferredAvatarProgram;
+extern LLGLSLShader			gDeferredSoftenProgram;
+extern LLGLSLShader			gDeferredShadowProgram;
+extern LLGLSLShader			gDeferredAvatarShadowProgram;
+extern LLGLSLShader			gDeferredAlphaProgram;
+extern LLGLSLShader			gDeferredFullbrightProgram;
+extern LLGLSLShader			gDeferredAvatarAlphaProgram;
 
 //current avatar shader parameter pointer
 extern GLint				gAvatarMatrixParam;
diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp
index 2af38548166e3596eca34446529be4fbe60c89e2..648fbd4714a66e5a9f14baa6ef883e8016fd87bf 100644
--- a/indra/newview/llviewerstats.cpp
+++ b/indra/newview/llviewerstats.cpp
@@ -351,7 +351,6 @@ void LLViewerStats::addToMessage(LLSD &body) const
 // Moving them here, but not merging them into LLViewerStats yet.
 void reset_statistics()
 {
-	gPipeline.resetFrameStats();	// Reset per-frame statistics.
 	if (LLSurface::sTextureUpdateTime)
 	{
 		LLSurface::sTexelsUpdatedPerSecStat.addValue(0.001f*(LLSurface::sTexelsUpdated / LLSurface::sTextureUpdateTime));
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index e73736bc615ac0786f90c352c6087c0c2ad99a58..cddca662205e738e063f7cedd32039983b681f4e 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -194,7 +194,7 @@
 //
 // Globals
 //
-void render_ui();
+void render_ui(F32 zoom_factor = 1.f, int subfield = 0);
 LLBottomPanel* gBottomPanel = NULL;
 
 extern BOOL gDebugClicks;
@@ -447,7 +447,7 @@ class LLDebugText
 			if (gPipeline.mBatchCount > 0)
 			{
 				addText(xpos, ypos, llformat("Batch min/max/mean: %d/%d/%d", gPipeline.mMinBatchSize, gPipeline.mMaxBatchSize, 
-					gPipeline.mMeanBatchSize));
+					gPipeline.mTrianglesDrawn/gPipeline.mBatchCount));
 
 				gPipeline.mMinBatchSize = gPipeline.mMaxBatchSize;
 				gPipeline.mMaxBatchSize = 0;
@@ -464,9 +464,46 @@ class LLDebugText
 			
 			ypos += y_inc;
 
+			addText(xpos,ypos, llformat("%d Lights visible", LLPipeline::sVisibleLightCount));
+			
+			ypos += y_inc;
+
 			LLVertexBuffer::sBindCount = LLImageGL::sBindCount = 
 				LLVertexBuffer::sSetCount = LLImageGL::sUniqueCount = 
-				gPipeline.mNumVisibleNodes = 0;
+				gPipeline.mNumVisibleNodes = LLPipeline::sVisibleLightCount = 0;
+		}
+		if (gSavedSettings.getBOOL("DebugShowRenderMatrices"))
+		{
+			addText(xpos, ypos, llformat("%.4f    .%4f    %.4f    %.4f", gGLProjection[12], gGLProjection[13], gGLProjection[14], gGLProjection[15]));
+			ypos += y_inc;
+
+			addText(xpos, ypos, llformat("%.4f    .%4f    %.4f    %.4f", gGLProjection[8], gGLProjection[9], gGLProjection[10], gGLProjection[11]));
+			ypos += y_inc;
+
+			addText(xpos, ypos, llformat("%.4f    .%4f    %.4f    %.4f", gGLProjection[4], gGLProjection[5], gGLProjection[6], gGLProjection[7]));
+			ypos += y_inc;
+
+			addText(xpos, ypos, llformat("%.4f    .%4f    %.4f    %.4f", gGLProjection[0], gGLProjection[1], gGLProjection[2], gGLProjection[3]));
+			ypos += y_inc;
+
+			addText(xpos, ypos, "Projection Matrix");
+			ypos += y_inc;
+
+
+			addText(xpos, ypos, llformat("%.4f    .%4f    %.4f    %.4f", gGLModelView[12], gGLModelView[13], gGLModelView[14], gGLModelView[15]));
+			ypos += y_inc;
+
+			addText(xpos, ypos, llformat("%.4f    .%4f    %.4f    %.4f", gGLModelView[8], gGLModelView[9], gGLModelView[10], gGLModelView[11]));
+			ypos += y_inc;
+
+			addText(xpos, ypos, llformat("%.4f    .%4f    %.4f    %.4f", gGLModelView[4], gGLModelView[5], gGLModelView[6], gGLModelView[7]));
+			ypos += y_inc;
+
+			addText(xpos, ypos, llformat("%.4f    .%4f    %.4f    %.4f", gGLModelView[0], gGLModelView[1], gGLModelView[2], gGLModelView[3]));
+			ypos += y_inc;
+
+			addText(xpos, ypos, "View Matrix");
+			ypos += y_inc;
 		}
 		if (gSavedSettings.getBOOL("DebugShowColor"))
 		{
@@ -3473,9 +3510,9 @@ void LLViewerWindow::schedulePick(LLPickInfo& pick_info)
 		LLGLState scissor_state(GL_SCISSOR_TEST);
 		scissor_state.enable();
 		glScissor(pick_info.mScreenRegion.mLeft, pick_info.mScreenRegion.mBottom, pick_info.mScreenRegion.getWidth(), pick_info.mScreenRegion.getHeight());
-	glClearColor(0.f, 0.f, 0.f, 0.f);
-	glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
-	//glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+		glClearColor(0.f, 0.f, 0.f, 0.f);
+		glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+		//glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
 	}
 	
 	// build perspective transform and picking viewport
@@ -4028,6 +4065,10 @@ void LLViewerWindow::playSnapshotAnimAndSound()
 
 BOOL LLViewerWindow::thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 preview_height, BOOL show_ui, BOOL do_rebuild, ESnapshotType type)
 {
+	return rawSnapshot(raw, preview_width, preview_height, FALSE, FALSE, show_ui, do_rebuild, type);
+	
+	// *TODO below code was broken in deferred pipeline
+	/*
 	if ((!raw) || preview_width < 10 || preview_height < 10)
 	{
 		return FALSE;
@@ -4059,7 +4100,7 @@ BOOL LLViewerWindow::thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 p
 	LLVOAvatar::updateFreezeCounter(1) ; //pause avatar updating for one frame
 	
 	S32 w = preview_width ;
-	S32 h = preview_height ;	
+	S32 h = preview_height ;
 	LLVector2 display_scale = mDisplayScale ;
 	mDisplayScale.setVec((F32)w / mWindowRect.getWidth(), (F32)h / mWindowRect.getHeight()) ;
 	LLRect window_rect = mWindowRect;
@@ -4098,7 +4139,7 @@ BOOL LLViewerWindow::thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 p
 		gltype = GL_UNSIGNED_BYTE ;
 	}
 
-	raw->resize(w, h, glpixel_length);	
+	raw->resize(w, h, glpixel_length);
 	glReadPixels(0, 0, w, h, glformat, gltype, raw->getData());
 
 	if(SNAPSHOT_TYPE_DEPTH == type)
@@ -4160,7 +4201,7 @@ BOOL LLViewerWindow::thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 p
 	
 	gSavedSettings.setS32("RenderName", render_name);	
 	
-	return TRUE;
+	return TRUE;*/
 }
 
 // Saves the image from the screen to the specified filename and path.
@@ -4210,7 +4251,7 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei
 		F32 ratio = llmin( (F32)window_width / image_width , (F32)window_height / image_height) ;
 		snapshot_width = (S32)(ratio * image_width) ;
 		snapshot_height = (S32)(ratio * image_height) ;
-		scale_factor = llmax(1.0f, 1.0f / ratio) ;	
+		scale_factor = llmax(1.0f, 1.0f / ratio) ;
 	}
 	else //the scene(window) proportion needs to be maintained.
 	{
@@ -4227,7 +4268,7 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei
 					
 					snapshot_width = image_width;
 					snapshot_height = image_height;
-					target.allocate(snapshot_width, snapshot_height, GL_RGBA, TRUE, LLTexUnit::TT_RECT_TEXTURE, TRUE);
+					target.allocate(snapshot_width, snapshot_height, GL_RGBA, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, TRUE);
 					window_width = snapshot_width;
 					window_height = snapshot_height;
 					scale_factor = 1.f;
@@ -4304,9 +4345,10 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei
 			}
 			else
 			{
-				display(do_rebuild, scale_factor, subimage_x+(subimage_y*llceil(scale_factor)), TRUE);
+				const U32 subfield = subimage_x+(subimage_y*llceil(scale_factor));
+				display(do_rebuild, scale_factor, subfield, TRUE);
 				// Required for showing the GUI in snapshots?  See DEV-16350 for details. JC
-				render_ui();
+				render_ui(scale_factor, subfield);
 			}
 
 			S32 subimage_x_offset = llclamp(buffer_x_offset - (subimage_x * window_width), 0, window_width);
@@ -4777,8 +4819,6 @@ BOOL LLViewerWindow::checkSettings()
 		}
 
 		mResDirty = false;
-		// This will force a state update the next frame.
-		mStatesDirty = true;
 	}
 		
 	BOOL is_fullscreen = mWindow->getFullscreen();
diff --git a/indra/newview/llvlcomposition.cpp b/indra/newview/llvlcomposition.cpp
index b58f1147f328f41a9f9f5b47de811edfc9c2961c..b79d7d10ff67b7d0eccf3d0ee269211ffe1a5cf9 100644
--- a/indra/newview/llvlcomposition.cpp
+++ b/indra/newview/llvlcomposition.cpp
@@ -107,6 +107,7 @@ void LLVLComposition::setDetailTextureID(S32 corner, const LLUUID& id)
 		return;
 	}
 	mDetailTextures[corner] = gImageList.getImage(id);
+	mDetailTextures[corner]->setNoDelete() ;
 	mRawImages[corner] = NULL;
 }
 
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 7e22eb40bbb2fcd6a3fde885ea48e2ea0f64a098..3757923e272e3a7ed166d559eedd54e0f80d2334 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -684,9 +684,6 @@ LLVOAvatar::LLVOAvatar(
 	mLowerMaskTexName(0),
 	mCulled( FALSE ),
 	mVisibilityRank(0),
-	mFadeTime(0.f),
-	mLastFadeTime(0.f),
-	mLastFadeDistance(1.f),
 	mTexSkinColor( NULL ),
 	mTexHairColor( NULL ),
 	mTexEyeColor( NULL ),
@@ -764,7 +761,7 @@ LLVOAvatar::LLVOAvatar(
 
 	mShadowImagep = gImageList.getImageFromFile("foot_shadow.j2c");
 	gGL.getTexUnit(0)->bind(mShadowImagep.get());
-	mShadowImagep->setClamp(TRUE, TRUE);
+	mShadowImagep->setAddressMode(LLTexUnit::TAM_CLAMP);
 	
 	mInAir = FALSE;
 
@@ -1362,11 +1359,11 @@ void LLVOAvatar::deleteCachedImages()
 		LLTexLayerSet::sHasCaches = FALSE;
 	}
 	
-	for( GLuint* namep = (GLuint*)sScratchTexNames.getFirstData(); 
+	for( LLGLuint * namep = sScratchTexNames.getFirstData(); 
 		 namep; 
-		 namep = (GLuint*)sScratchTexNames.getNextData() )
+		 namep = sScratchTexNames.getNextData() )
 	{
-		glDeleteTextures(1, namep );
+		LLImageGL::deleteTextures(1, (U32 *)namep );
 		stop_glerror();
 	}
 
@@ -2868,12 +2865,15 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update)
 		}
 	}
 
-	mDrawable->movePartition();
-	
-	//force a move if sitting on an active object
-	if (getParent() && ((LLViewerObject*) getParent())->mDrawable->isActive())
+	if (mDrawable.notNull())
 	{
-		gPipeline.markMoved(mDrawable, TRUE);
+		mDrawable->movePartition();
+		
+		//force a move if sitting on an active object
+		if (getParent() && ((LLViewerObject*) getParent())->mDrawable->isActive())
+		{
+			gPipeline.markMoved(mDrawable, TRUE);
+		}
 	}
 }
 
@@ -3576,6 +3576,10 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
 		{ //back 25% of max visible avatars are slow updating impostors
 			mUpdatePeriod = 8;
 		}
+		else if (visible && mVisibilityRank > (U32) LLVOAvatar::sMaxVisible)
+		{ //background avatars are REALLY slow updating impostors
+			mUpdatePeriod = 16;
+		}
 		else if (visible && mImpostorPixelArea <= impostor_area)
 		{  // stuff in between gets an update period based on pixel area
 			mUpdatePeriod = llclamp((S32) sqrtf(impostor_area*4.f/mImpostorPixelArea), 2, 8);
@@ -4193,7 +4197,7 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass)
 				mSkirtLOD.updateJointGeometry();
 			}
 
-			if (!mIsSelf || gAgent.needsRenderHead())
+			if (!mIsSelf || gAgent.needsRenderHead() || LLPipeline::sShadowRender)
 			{
 				mEyeLashLOD.updateJointGeometry();
 				mHeadLOD.updateJointGeometry();
@@ -4294,18 +4298,22 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass)
 	if (pass == AVATAR_RENDER_PASS_SINGLE)
 	{
 		BOOL first_pass = TRUE;
-		if (!mIsSelf || gAgent.needsRenderHead())
+		if (!LLDrawPoolAvatar::sSkipOpaque)
 		{
-			num_indices += mHeadLOD.render(mAdjustedPixelArea);
-			first_pass = FALSE;
+			if (!mIsSelf || gAgent.needsRenderHead() || LLPipeline::sShadowRender)
+			{
+				num_indices += mHeadLOD.render(mAdjustedPixelArea);
+				first_pass = FALSE;
+			}
+			num_indices += mUpperBodyLOD.render(mAdjustedPixelArea, first_pass);
+			num_indices += mLowerBodyLOD.render(mAdjustedPixelArea, FALSE);
 		}
-		num_indices += mUpperBodyLOD.render(mAdjustedPixelArea, first_pass);
-		num_indices += mLowerBodyLOD.render(mAdjustedPixelArea, FALSE);
 
+		if (!LLDrawPoolAvatar::sSkipTransparent || LLPipeline::sImpostorRender)
 		{
 			LLGLEnable blend(GL_BLEND);
 			LLGLEnable test(GL_ALPHA_TEST);
-			num_indices += renderTransparent();
+			num_indices += renderTransparent(first_pass);
 		}
 	}
 	
@@ -4318,10 +4326,9 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass)
 	return num_indices;
 }
 
-U32 LLVOAvatar::renderTransparent()
+U32 LLVOAvatar::renderTransparent(BOOL first_pass)
 {
 	U32 num_indices = 0;
-	BOOL first_pass = FALSE;
 	if( isWearingWearableType( WT_SKIRT ) )
 	{
 		gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.25f);
@@ -4330,7 +4337,7 @@ U32 LLVOAvatar::renderTransparent()
 		gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
 	}
 
-	if (!mIsSelf || gAgent.needsRenderHead())
+	if (!mIsSelf || gAgent.needsRenderHead() || LLPipeline::sShadowRender)
 	{
 		if (LLPipeline::sImpostorRender)
 		{
@@ -4402,7 +4409,7 @@ U32 LLVOAvatar::renderFootShadows()
 	}
 
 	U32 foot_mask = LLVertexBuffer::MAP_VERTEX |
-					LLVertexBuffer::MAP_TEXCOORD;
+					LLVertexBuffer::MAP_TEXCOORD0;
 
 	LLGLDepthTest test(GL_TRUE, GL_FALSE);
 	//render foot shadows
@@ -4435,23 +4442,6 @@ U32 LLVOAvatar::renderImpostor(LLColor4U color)
 	LLGLEnable test(GL_ALPHA_TEST);
 	gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.f);
 
-	F32 blend = gFrameTimeSeconds - mFadeTime;
-
-	LLGLState gl_blend(GL_BLEND, blend < 1.f ? TRUE : FALSE);
-	gGL.setSceneBlendType(LLRender::BT_ALPHA);
-
-	F32 alpha;
-	if (mVisibilityRank >= (U32) LLVOAvatar::sMaxVisible)
-	{ //fade out
-		alpha = 1.f - llmin(blend, 1.f);
-	}
-	else 
-	{ //fade in
-		alpha = llmin(blend, 1.f);
-	}
-
-	color.mV[3] = (U8) (alpha*255);
-	
 	gGL.color4ubv(color.mV);
 	gGL.getTexUnit(0)->bind(&mImpostor);
 	gGL.begin(LLRender::QUADS);
@@ -5945,6 +5935,11 @@ void LLVOAvatar::setPixelAreaAndAngle(LLAgent &agent)
 {
 	LLMemType mt(LLMemType::MTYPE_AVATAR);
 
+	if (mDrawable.isNull())
+	{
+		return;
+	}
+
 	const LLVector3* ext = mDrawable->getSpatialExtents();
 	LLVector3 center = (ext[1] + ext[0]) * 0.5f;
 	LLVector3 size = (ext[1]-ext[0])*0.5f;
@@ -6349,15 +6344,21 @@ BOOL LLVOAvatar::attachObject(LLViewerObject *viewer_object)
 //-----------------------------------------------------------------------------
 void LLVOAvatar::lazyAttach()
 {
+	std::vector<LLPointer<LLViewerObject> > still_pending;
+	
 	for (U32 i = 0; i < mPendingAttachment.size(); i++)
 	{
 		if (mPendingAttachment[i]->mDrawable)
 		{
 			attachObject(mPendingAttachment[i]);
 		}
+		else
+		{
+			still_pending.push_back(mPendingAttachment[i]);
+		}
 	}
 
-	mPendingAttachment.clear();
+	mPendingAttachment = still_pending;
 }
 
 void LLVOAvatar::resetHUDAttachments()
@@ -6957,8 +6958,7 @@ void LLVOAvatar::dumpTotalLocalTextureByteCount()
 BOOL LLVOAvatar::isVisible()
 {
 	return mDrawable.notNull()
-		&& (mDrawable->isVisible() || mIsDummy)
-		&& (mVisibilityRank < (U32) sMaxVisible || gFrameTimeSeconds - mFadeTime < 1.f); 
+		&& (mDrawable->isVisible() || mIsDummy);
 }
 
 
@@ -7133,23 +7133,21 @@ LLGLuint LLVOAvatar::getScratchTexName( LLGLenum format, U32* texture_bytes )
 
 		LLGLSUIDefault gls_ui;
 
-		GLuint name = 0;
-		glGenTextures(1, &name );
+		U32 name = 0;
+		LLImageGL::generateTextures(1, &name );
 		stop_glerror();
 
 		gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, name);
 		stop_glerror();
 
-		glTexImage2D(
+		LLImageGL::setManualImage(
 			GL_TEXTURE_2D, 0, internal_format, 
 			VOAVATAR_SCRATCH_TEX_WIDTH, VOAVATAR_SCRATCH_TEX_HEIGHT,
-			0, format, GL_UNSIGNED_BYTE, NULL );
+			format, GL_UNSIGNED_BYTE, NULL );
 		stop_glerror();
 
-		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-		glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
-		glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+		gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
+		gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
 		stop_glerror();
 
 		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
@@ -8758,20 +8756,19 @@ void LLVOAvatar::onBakedTextureMasksLoaded( BOOL success, LLViewerImage *src_vi,
 			}
 
 			U32 gl_name;
-			glGenTextures(1, (GLuint*) &gl_name );
+			LLImageGL::generateTextures(1, &gl_name );
 			stop_glerror();
 
 			gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, gl_name);
 			stop_glerror();
 
-			glTexImage2D(
+			LLImageGL::setManualImage(
 				GL_TEXTURE_2D, 0, GL_ALPHA8, 
 				aux_src->getWidth(), aux_src->getHeight(),
-				0, GL_ALPHA, GL_UNSIGNED_BYTE, aux_src->getData());
+				GL_ALPHA, GL_UNSIGNED_BYTE, aux_src->getData());
 			stop_glerror();
 
-			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+			gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
 
 			if( id == head_baked->getID() )
 			{
@@ -8783,7 +8780,7 @@ void LLVOAvatar::onBakedTextureMasksLoaded( BOOL success, LLViewerImage *src_vi,
 					self->mHeadMaskDiscard = discard_level;
 					if (self->mHeadMaskTexName)
 					{
-						glDeleteTextures(1, (GLuint*) &self->mHeadMaskTexName);
+						LLImageGL::deleteTextures(1, &self->mHeadMaskTexName);
 					}
 					self->mHeadMaskTexName = gl_name;
 				}
@@ -8803,7 +8800,7 @@ void LLVOAvatar::onBakedTextureMasksLoaded( BOOL success, LLViewerImage *src_vi,
 					self->mUpperMaskDiscard = discard_level;
 					if (self->mUpperMaskTexName)
 					{
-						glDeleteTextures(1, (GLuint*) &self->mUpperMaskTexName);
+						LLImageGL::deleteTextures(1, &self->mUpperMaskTexName);
 					}
 					self->mUpperMaskTexName = gl_name;
 				}
@@ -8823,7 +8820,7 @@ void LLVOAvatar::onBakedTextureMasksLoaded( BOOL success, LLViewerImage *src_vi,
 					self->mLowerMaskDiscard = discard_level;
 					if (self->mLowerMaskTexName)
 					{
-						glDeleteTextures(1, (GLuint*) &self->mLowerMaskTexName);
+						LLImageGL::deleteTextures(1, &self->mLowerMaskTexName);
 					}
 					self->mLowerMaskTexName = gl_name;
 				}
@@ -9010,7 +9007,9 @@ void LLVOAvatar::useBakedTexture( const LLUUID& id )
 void LLVOAvatar::dumpArchetypeXML( void* )
 {
 	LLVOAvatar* avatar = gAgent.getAvatarObject();
-	apr_file_t* file = ll_apr_file_open(gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,"new archetype.xml"), LL_APR_WB );
+	LLAPRFile outfile ;
+	outfile.open(gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,"new archetype.xml"), LL_APR_WB );
+	apr_file_t* file = outfile.getFileHandle() ;
 	if( !file )
 	{
 		return;
@@ -9053,7 +9052,6 @@ void LLVOAvatar::dumpArchetypeXML( void* )
 	}
 	apr_file_printf( file, "\t</archetype>\n" );
 	apr_file_printf( file, "\n</linden_genepool>\n" );
-	apr_file_close( file );
 }
 
 
@@ -9069,33 +9067,7 @@ void LLVOAvatar::setVisibilityRank(U32 rank)
 		return;
 	}
 
-	BOOL stale = gFrameTimeSeconds - mLastFadeTime > 10.f;
-	
-	//only raise visibility rank or trigger a fade out every 10 seconds
-	if (mVisibilityRank >= (U32) LLVOAvatar::sMaxVisible && rank < (U32) LLVOAvatar::sMaxVisible ||
-		(stale && mVisibilityRank < (U32) LLVOAvatar::sMaxVisible && rank >= (U32) LLVOAvatar::sMaxVisible))
-	{ //remember the time we became visible/invisible based on visibility rank
-		mVisibilityRank = rank;
-		mLastFadeTime = gFrameTimeSeconds;
-		mLastFadeDistance = mDrawable->mDistanceWRTCamera;
-
-		F32 blend = gFrameTimeSeconds - mFadeTime;
-		mFadeTime = gFrameTimeSeconds;
-		if (blend < 1.f)
-		{ //move the blend time back if a blend is already in progress (prevent flashes)
-			mFadeTime -= 1.f-blend;
-		}
-	}
-	else if (stale)
-	{
-		mLastFadeTime = gFrameTimeSeconds;
-		mLastFadeDistance = mDrawable->mDistanceWRTCamera;
-		mVisibilityRank = rank;
-	}
-	else
-	{
-		mVisibilityRank = llmin(mVisibilityRank, rank);
-	}
+	mVisibilityRank = rank;
 }
 
 // Assumes LLVOAvatar::sInstances has already been sorted.
@@ -10023,7 +9995,7 @@ BOOL LLVOAvatar::isImpostor() const
 
 BOOL LLVOAvatar::needsImpostorUpdate() const
 {
-	return mNeedsImpostorUpdate ;
+	return mNeedsImpostorUpdate;
 }
 
 const LLVector3& LLVOAvatar::getImpostorOffset() const
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index 81ab0fd49cf0013f6649cfe6c6b8ca6e4428b191..14f7bd6dcc2563818644019e60b2e560c0cbbba1 100644
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -263,7 +263,7 @@ class LLVOAvatar :
 	{
 		VERTEX_DATA_MASK =	(1 << LLVertexBuffer::TYPE_VERTEX) |
 							(1 << LLVertexBuffer::TYPE_NORMAL) |
-							(1 << LLVertexBuffer::TYPE_TEXCOORD) |
+							(1 << LLVertexBuffer::TYPE_TEXCOORD0) |
 							(1 << LLVertexBuffer::TYPE_WEIGHT) |
 							(1 << LLVertexBuffer::TYPE_CLOTHWEIGHT)							
 	};
@@ -306,7 +306,7 @@ class LLVOAvatar :
 	U32 renderImpostor(LLColor4U color = LLColor4U(255,255,255,255));
 	U32 renderRigid();
 	U32 renderSkinned(EAvatarRenderPass pass);
-	U32 renderTransparent();
+	U32 renderTransparent(BOOL first_pass);
 	void renderCollisionVolumes();
 	
 	/*virtual*/ BOOL lineSegmentIntersect(const LLVector3& start, const LLVector3& end,
@@ -978,9 +978,6 @@ class LLVOAvatar :
 
 	BOOL				mCulled;
 	U32					mVisibilityRank;
-	F32					mFadeTime;
-	F32					mLastFadeTime;
-	F32					mLastFadeDistance;
 	F32					mMinPixelArea; // debug
 	F32					mMaxPixelArea; // debug
 	BOOL				mHasGrey; // debug
diff --git a/indra/newview/llvoicevisualizer.cpp b/indra/newview/llvoicevisualizer.cpp
index 95c4550fdee5afc17c1c47e44b4738eaeeb74107..5606398aaf346077ac81b34f3a52db9320d258a8 100644
--- a/indra/newview/llvoicevisualizer.cpp
+++ b/indra/newview/llvoicevisualizer.cpp
@@ -149,6 +149,8 @@ LLVoiceVisualizer::LLVoiceVisualizer( const U8 type )
 		mSoundSymbol.mWaveExpansion			[i] = 1.0f;
 	}
 
+	mSoundSymbol.mTexture[0]->setFilteringOption(LLTexUnit::TFO_ANISOTROPIC);
+
 	// The first instance loads the initial state from prefs.
 	if (!sPrefsInitialized)
 	{
diff --git a/indra/newview/llvopartgroup.cpp b/indra/newview/llvopartgroup.cpp
index 322516fe5651ddc6e5cb029e7462842b38395f90..6dfe23ba98651cafdb6d80203ecd0368cc5ea91b 100644
--- a/indra/newview/llvopartgroup.cpp
+++ b/indra/newview/llvopartgroup.cpp
@@ -418,7 +418,9 @@ void LLParticlePartition::addGeometryCount(LLSpatialGroup* group, U32& vertex_co
 void LLParticlePartition::getGeometry(LLSpatialGroup* group)
 {
 	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
-	LLFastTimer ftm(LLFastTimer::FTM_REBUILD_PARTICLE_VB);
+	LLFastTimer ftm(mDrawableType == LLPipeline::RENDER_TYPE_GRASS ?
+					LLFastTimer::FTM_REBUILD_GRASS_VB :
+					LLFastTimer::FTM_REBUILD_PARTICLE_VB);
 
 	std::sort(mFaceList.begin(), mFaceList.end(), LLFace::CompareDistanceGreater());
 
@@ -438,7 +440,7 @@ void LLParticlePartition::getGeometry(LLSpatialGroup* group)
 	buffer->getVertexStrider(verticesp);
 	buffer->getNormalStrider(normalsp);
 	buffer->getColorStrider(colorsp);
-	buffer->getTexCoordStrider(texcoordsp);
+	buffer->getTexCoord0Strider(texcoordsp);
 	buffer->getIndexStrider(indicesp);
 
 	LLSpatialGroup::drawmap_elem_t& draw_vec = group->mDrawMap[mRenderPass];	
@@ -479,8 +481,12 @@ void LLParticlePartition::getGeometry(LLSpatialGroup* group)
 			U32 offset = facep->getIndicesStart();
 			U32 count = facep->getIndicesCount();
 			LLDrawInfo* info = new LLDrawInfo(start,end,count,offset,facep->getTexture(), buffer, fullbright); 
+			info->mExtents[0] = group->mObjectExtents[0];
+			info->mExtents[1] = group->mObjectExtents[1];
 			info->mVSize = vsize;
 			draw_vec.push_back(info);
+			//for alpha sorting
+			facep->setDrawInfo(info);
 		}
 	}
 
diff --git a/indra/newview/llvopartgroup.h b/indra/newview/llvopartgroup.h
index 30a3165826d3e3c886f96dbc3ffad1c22025cc9d..3dc32929920f519cb196bf71e0979b6939245599 100644
--- a/indra/newview/llvopartgroup.h
+++ b/indra/newview/llvopartgroup.h
@@ -47,7 +47,7 @@ class LLVOPartGroup : public LLAlphaObject
 	{
 		VERTEX_DATA_MASK =	(1 << LLVertexBuffer::TYPE_VERTEX) |
 							(1 << LLVertexBuffer::TYPE_NORMAL) |
-							(1 << LLVertexBuffer::TYPE_TEXCOORD) |
+							(1 << LLVertexBuffer::TYPE_TEXCOORD0) |
 							(1 << LLVertexBuffer::TYPE_COLOR)
 	};
 
diff --git a/indra/newview/llvosky.cpp b/indra/newview/llvosky.cpp
index 3ec043eb392c82b0e1108d944a79a9fa8ca04e49..c3366cad90fe5c8cfe919921a692474d0352178a 100644
--- a/indra/newview/llvosky.cpp
+++ b/indra/newview/llvosky.cpp
@@ -213,7 +213,7 @@ void LLSkyTex::init()
 	for (S32 i = 0; i < 2; ++i)
 	{
 		mImageGL[i] = new LLImageGL(FALSE);
-		mImageGL[i]->setClamp(TRUE, TRUE);
+		mImageGL[i]->setAddressMode(LLTexUnit::TAM_CLAMP);
 		mImageRaw[i] = new LLImageRaw(sResolution, sResolution, sComponents);
 		
 		initEmpty(i);
@@ -231,7 +231,7 @@ void LLSkyTex::restoreGL()
 	for (S32 i = 0; i < 2; i++)
 	{
 		mImageGL[i] = new LLImageGL(FALSE);
-		mImageGL[i]->setClamp(TRUE, TRUE);
+		mImageGL[i]->setAddressMode(LLTexUnit::TAM_CLAMP);
 	}
 }
 
@@ -290,7 +290,7 @@ void LLSkyTex::create(const F32 brightness)
 void LLSkyTex::createGLImage(S32 which)
 {	
 	mImageGL[which]->createGLTexture(0, mImageRaw[which]);
-	mImageGL[which]->setClamp(TRUE, TRUE);
+	mImageGL[which]->setAddressMode(LLTexUnit::TAM_CLAMP);
 }
 
 void LLSkyTex::bindTexture(BOOL curr)
@@ -377,11 +377,12 @@ LLVOSky::LLVOSky(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
 	mMoon.setIntensity(0.1f * SUN_INTENSITY);
 
 	mSunTexturep = gImageList.getImage(gSunTextureID, TRUE, TRUE);
-	mSunTexturep->setClamp(TRUE, TRUE);
+	mSunTexturep->setAddressMode(LLTexUnit::TAM_CLAMP);
 	mMoonTexturep = gImageList.getImage(gMoonTextureID, TRUE, TRUE);
-	mMoonTexturep->setClamp(TRUE, TRUE);
+	mMoonTexturep->setAddressMode(LLTexUnit::TAM_CLAMP);
 	mBloomTexturep = gImageList.getImage(IMG_BLOOM1);
-	mBloomTexturep->setClamp(TRUE, TRUE);
+	mBloomTexturep->setNoDelete() ;
+	mBloomTexturep->setAddressMode(LLTexUnit::TAM_CLAMP);
 
 	mHeavenlyBodyUpdated = FALSE ;
 }
@@ -447,6 +448,7 @@ void LLVOSky::initCubeMap()
 		mCubeMap = new LLCubeMap();
 		mCubeMap->init(images);
 	}
+	gGL.getTexUnit(0)->disable();
 }
 
 
@@ -471,11 +473,12 @@ void LLVOSky::restoreGL()
 		mSkyTex[i].restoreGL();
 	}
 	mSunTexturep = gImageList.getImage(gSunTextureID, TRUE, TRUE);
-	mSunTexturep->setClamp(TRUE, TRUE);
+	mSunTexturep->setAddressMode(LLTexUnit::TAM_CLAMP);
 	mMoonTexturep = gImageList.getImage(gMoonTextureID, TRUE, TRUE);
-	mMoonTexturep->setClamp(TRUE, TRUE);
+	mMoonTexturep->setAddressMode(LLTexUnit::TAM_CLAMP);
 	mBloomTexturep = gImageList.getImage(IMG_BLOOM1);
-	mBloomTexturep->setClamp(TRUE, TRUE);
+	mBloomTexturep->setNoDelete() ;
+	mBloomTexturep->setAddressMode(LLTexUnit::TAM_CLAMP);
 
 	calcAtmospherics();	
 
@@ -1153,6 +1156,7 @@ BOOL LLVOSky::updateSky()
 					images.push_back(mShinyTex[side].getImageRaw(TRUE));
 				}
 				mCubeMap->init(images);
+				gGL.getTexUnit(0)->disable();
 			}
 
 			gPipeline.markRebuild(gSky.mVOGroundp->mDrawable, LLDrawable::REBUILD_ALL, TRUE);
@@ -2024,7 +2028,7 @@ void LLVOSky::updateFog(const F32 distance)
 	const BOOL hide_clip_plane = TRUE;
 	LLColor4 target_fog(0.f, 0.2f, 0.5f, 0.f);
 
-	const F32 water_height = gAgent.getRegion()->getWaterHeight();
+	const F32 water_height = gAgent.getRegion() ? gAgent.getRegion()->getWaterHeight() : 0.f;
 	// LLWorld::getInstance()->getWaterHeight();
 	F32 camera_height = gAgent.getCameraPositionAgent().mV[2];
 
diff --git a/indra/newview/llvosurfacepatch.cpp b/indra/newview/llvosurfacepatch.cpp
index 3a90a665a8ae7286f9969cc9ca3994d016ad39d7..4980b50de4555ce10a500b63afbea3d7b18ed5ad 100644
--- a/indra/newview/llvosurfacepatch.cpp
+++ b/indra/newview/llvosurfacepatch.cpp
@@ -57,40 +57,30 @@ class LLVertexBufferTerrain : public LLVertexBuffer
 {
 public:
 	LLVertexBufferTerrain() :
-		LLVertexBuffer(MAP_VERTEX | MAP_NORMAL | MAP_TEXCOORD | MAP_TEXCOORD2 | MAP_COLOR, GL_DYNAMIC_DRAW_ARB)
+		LLVertexBuffer(MAP_VERTEX | MAP_NORMAL | MAP_TEXCOORD0 | MAP_TEXCOORD1 | MAP_COLOR, GL_DYNAMIC_DRAW_ARB)
 	{
+		//texture coordinates 2 and 3 exist, but use the same data as texture coordinate 1
+		mOffsets[TYPE_TEXCOORD3] = mOffsets[TYPE_TEXCOORD2] = mOffsets[TYPE_TEXCOORD1];
+		mTypeMask |= MAP_TEXCOORD2 | MAP_TEXCOORD3;
 	};
 
-	// virtual
+	/*// virtual
 	void setupVertexBuffer(U32 data_mask) const
 	{		
-		if (LLDrawPoolTerrain::getDetailMode() == 0)
+		if (LLDrawPoolTerrain::getDetailMode() == 0 || LLPipeline::sShadowRender)
 		{
 			LLVertexBuffer::setupVertexBuffer(data_mask);
 		}
-		else if (data_mask & LLVertexBuffer::MAP_TEXCOORD2)
+		else if (data_mask & LLVertexBuffer::MAP_TEXCOORD1)
 		{
-			U8* base = useVBOs() ? NULL : mMappedData;
-	
-			glVertexPointer(3,GL_FLOAT, mStride, (void*)(base + 0));
-			glNormalPointer(GL_FLOAT, mStride, (void*)(base + mOffsets[TYPE_NORMAL]));
-			glColorPointer(4, GL_UNSIGNED_BYTE, mStride, (void*)(base + mOffsets[TYPE_COLOR]));
-		
-			glClientActiveTextureARB(GL_TEXTURE3_ARB);
-			glTexCoordPointer(2,GL_FLOAT, mStride, (void*)(base + mOffsets[TYPE_TEXCOORD2]));
-			glClientActiveTextureARB(GL_TEXTURE2_ARB);
-			glTexCoordPointer(2,GL_FLOAT, mStride, (void*)(base + mOffsets[TYPE_TEXCOORD2]));
-			glClientActiveTextureARB(GL_TEXTURE1_ARB);
-			glTexCoordPointer(2,GL_FLOAT, mStride, (void*)(base + mOffsets[TYPE_TEXCOORD2]));
-			glClientActiveTextureARB(GL_TEXTURE0_ARB);
-			glTexCoordPointer(2,GL_FLOAT, mStride, (void*)(base + mOffsets[TYPE_TEXCOORD2]));
+			LLVertexBuffer::setupVertexBuffer(data_mask);
 		}
 		else
 		{
 			LLVertexBuffer::setupVertexBuffer(data_mask);
 		}
 		llglassertok();		
-	}
+	}*/
 };
 
 //============================================================================
@@ -1054,8 +1044,8 @@ void LLTerrainPartition::getGeometry(LLSpatialGroup* group)
 
 	llassert_always(buffer->getVertexStrider(vertices));
 	llassert_always(buffer->getNormalStrider(normals));
-	llassert_always(buffer->getTexCoordStrider(texcoords));
-	llassert_always(buffer->getTexCoord2Strider(texcoords2));
+	llassert_always(buffer->getTexCoord0Strider(texcoords));
+	llassert_always(buffer->getTexCoord1Strider(texcoords2));
 	llassert_always(buffer->getColorStrider(colors));
 	llassert_always(buffer->getIndexStrider(indices));
 
diff --git a/indra/newview/llvosurfacepatch.h b/indra/newview/llvosurfacepatch.h
index 7b0529287cee9ffd674f8f04e9ed045f856d89e5..2dd86518992d5cbd9b6d2d47fec369b0e84150dd 100644
--- a/indra/newview/llvosurfacepatch.h
+++ b/indra/newview/llvosurfacepatch.h
@@ -49,8 +49,8 @@ class LLVOSurfacePatch : public LLStaticViewerObject
 	{
 		VERTEX_DATA_MASK =	(1 << LLVertexBuffer::TYPE_VERTEX) |
 							(1 << LLVertexBuffer::TYPE_NORMAL) |
-							(1 << LLVertexBuffer::TYPE_TEXCOORD) |
-							(1 << LLVertexBuffer::TYPE_TEXCOORD2) |
+							(1 << LLVertexBuffer::TYPE_TEXCOORD0) |
+							(1 << LLVertexBuffer::TYPE_TEXCOORD1) |
 							(1 << LLVertexBuffer::TYPE_COLOR) 
 	};
 
diff --git a/indra/newview/llvotree.cpp b/indra/newview/llvotree.cpp
index 4c7b90d8a1a021f02fb977f303b9a0182581b021..3b76127eb25de27131e4ef28be6bab97702ee789 100644
--- a/indra/newview/llvotree.cpp
+++ b/indra/newview/llvotree.cpp
@@ -86,6 +86,7 @@ LLVOTree::LLVOTree(const LLUUID &id, const LLPCode pcode, LLViewerRegion *region
 	mSpecies = 0;
 	mFrameCount = 0;
 	mWind = mRegionp->mWind.getVelocity(getPositionRegion());
+	mTrunkLOD = 0;
 }
 
 
@@ -343,41 +344,69 @@ BOOL LLVOTree::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
 		return TRUE;
 	}
 	
-	F32 mass_inv; 
-
-	//  For all tree objects, update the trunk bending with the current wind 
-	//  Walk sprite list in order away from viewer 
-	if (!(mFrameCount % FRAMES_PER_WIND_UPDATE)) 
+	if (gSavedSettings.getBOOL("RenderAnimateTrees"))
 	{
-		//  If needed, Get latest wind for this tree
-		mWind = mRegionp->mWind.getVelocity(getPositionRegion());
+		F32 mass_inv; 
+
+		//  For all tree objects, update the trunk bending with the current wind 
+		//  Walk sprite list in order away from viewer 
+		if (!(mFrameCount % FRAMES_PER_WIND_UPDATE)) 
+		{
+			//  If needed, Get latest wind for this tree
+			mWind = mRegionp->mWind.getVelocity(getPositionRegion());
+		}
+		mFrameCount++;
+
+		mass_inv = 1.f/(5.f + mDepth*mBranches*0.2f);
+		mTrunkVel += (mWind * mass_inv * TREE_WIND_SENSITIVITY);		//  Pull in direction of wind
+		mTrunkVel -= (mTrunkBend * mass_inv * TREE_TRUNK_STIFFNESS);		//  Restoring force in direction of trunk 	
+		mTrunkBend += mTrunkVel;
+		mTrunkVel *= 0.99f;									//  Add damping
+
+		if (mTrunkBend.length() > 1.f)
+		{
+			mTrunkBend.normalize();
+		}
+
+		if (mTrunkVel.length() > 1.f)
+		{
+			mTrunkVel.normalize();
+		}
 	}
-	mFrameCount++;
 
-	mass_inv = 1.f/(5.f + mDepth*mBranches*0.2f);
-	mTrunkVel += (mWind * mass_inv * TREE_WIND_SENSITIVITY);		//  Pull in direction of wind
-	mTrunkVel -= (mTrunkBend * mass_inv * TREE_TRUNK_STIFFNESS);		//  Restoring force in direction of trunk 	
-	mTrunkBend += mTrunkVel;
-	mTrunkVel *= 0.99f;									//  Add damping
+	S32 trunk_LOD = 0;
+	F32 app_angle = getAppAngle()*LLVOTree::sTreeFactor;
 
-	if (mTrunkBend.length() > 1.f)
+	for (S32 j = 0; j < 4; j++)
 	{
-		mTrunkBend.normalize();
-	}
 
-	if (mTrunkVel.length() > 1.f)
+		if (app_angle > LLVOTree::sLODAngles[j])
+		{
+			trunk_LOD = j;
+			break;
+		}
+	} 
+
+	if (!gSavedSettings.getBOOL("RenderAnimateTrees"))
 	{
-		mTrunkVel.normalize();
+		if (mReferenceBuffer.isNull())
+		{
+			gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE);
+		}
+		else if (trunk_LOD != mTrunkLOD)
+		{
+			gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, FALSE);
+		}
 	}
 
+	mTrunkLOD = trunk_LOD;
+
 	return TRUE;
 }
 
-
 const F32 TREE_BLEND_MIN = 1.f;
 const F32 TREE_BLEND_RANGE = 1.f;
 
-
 void LLVOTree::render(LLAgent &agent)
 {
 }
@@ -450,338 +479,604 @@ const S32 LEAF_VERTICES = 16;
 BOOL LLVOTree::updateGeometry(LLDrawable *drawable)
 {
 	LLFastTimer ftm(LLFastTimer::FTM_UPDATE_TREE);
-	const F32 SRR3 = 0.577350269f; // sqrt(1/3)
-	const F32 SRR2 = 0.707106781f; // sqrt(1/2)
-	U32 i, j;
 
-	U32 slices = MAX_SLICES;
+	if (mReferenceBuffer.isNull() || mDrawable->getFace(0)->mVertexBuffer.isNull())
+	{
+		const F32 SRR3 = 0.577350269f; // sqrt(1/3)
+		const F32 SRR2 = 0.707106781f; // sqrt(1/2)
+		U32 i, j;
+
+		U32 slices = MAX_SLICES;
+
+		S32 max_indices = LEAF_INDICES;
+		S32 max_vertices = LEAF_VERTICES;
+		S32 lod;
+
+		LLFace *face = drawable->getFace(0);
+
+		face->mCenterAgent = getPositionAgent();
+		face->mCenterLocal = face->mCenterAgent;
+
+		for (lod = 0; lod < 4; lod++)
+		{
+			slices = sLODSlices[lod];
+			sLODVertexOffset[lod] = max_vertices;
+			sLODVertexCount[lod] = slices*slices;
+			sLODIndexOffset[lod] = max_indices;
+			sLODIndexCount[lod] = (slices-1)*(slices-1)*6;
+			max_indices += sLODIndexCount[lod];
+			max_vertices += sLODVertexCount[lod];
+		}
+
+		mReferenceBuffer = new LLVertexBuffer(LLDrawPoolTree::VERTEX_DATA_MASK, gSavedSettings.getBOOL("RenderAnimateTrees") ? GL_STATIC_DRAW_ARB : 0);
+		mReferenceBuffer->allocateBuffer(max_vertices, max_indices, TRUE);
+
+		LLStrider<LLVector3> vertices;
+		LLStrider<LLVector3> normals;
+		LLStrider<LLVector2> tex_coords;
+		LLStrider<U16> indicesp;
+
+		mReferenceBuffer->getVertexStrider(vertices);
+		mReferenceBuffer->getNormalStrider(normals);
+		mReferenceBuffer->getTexCoord0Strider(tex_coords);
+		mReferenceBuffer->getIndexStrider(indicesp);
+				
+		S32 vertex_count = 0;
+		S32 index_count = 0;
+		
+		// First leaf
+		*(normals++) =		LLVector3(-SRR2, -SRR2, 0.f);
+		*(tex_coords++) =	LLVector2(LEAF_LEFT, LEAF_BOTTOM);
+		*(vertices++) =		LLVector3(-0.5f*LEAF_WIDTH, 0.f, 0.f);
+		vertex_count++;
+
+		*(normals++) =		LLVector3(SRR3, -SRR3, SRR3);
+		*(tex_coords++) =	LLVector2(LEAF_RIGHT, LEAF_TOP);
+		*(vertices++) =		LLVector3(0.5f*LEAF_WIDTH, 0.f, 1.f);
+		vertex_count++;
+
+		*(normals++) =		LLVector3(-SRR3, -SRR3, SRR3);
+		*(tex_coords++) =	LLVector2(LEAF_LEFT, LEAF_TOP);
+		*(vertices++) =		LLVector3(-0.5f*LEAF_WIDTH, 0.f, 1.f);
+		vertex_count++;
+
+		*(normals++) =		LLVector3(SRR2, -SRR2, 0.f);
+		*(tex_coords++) =	LLVector2(LEAF_RIGHT, LEAF_BOTTOM);
+		*(vertices++) =		LLVector3(0.5f*LEAF_WIDTH, 0.f, 0.f);
+		vertex_count++;
+
+
+		*(indicesp++) = 0;
+		index_count++;
+		*(indicesp++) = 1;
+		index_count++;
+		*(indicesp++) = 2;
+		index_count++;
+
+		*(indicesp++) = 0;
+		index_count++;
+		*(indicesp++) = 3;
+		index_count++;
+		*(indicesp++) = 1;
+		index_count++;
+
+		// Same leaf, inverse winding/normals
+		*(normals++) =		LLVector3(-SRR2, SRR2, 0.f);
+		*(tex_coords++) =	LLVector2(LEAF_LEFT, LEAF_BOTTOM);
+		*(vertices++) =		LLVector3(-0.5f*LEAF_WIDTH, 0.f, 0.f);
+		vertex_count++;
+
+		*(normals++) =		LLVector3(SRR3, SRR3, SRR3);
+		*(tex_coords++) =	LLVector2(LEAF_RIGHT, LEAF_TOP);
+		*(vertices++) =		LLVector3(0.5f*LEAF_WIDTH, 0.f, 1.f);
+		vertex_count++;
+
+		*(normals++) =		LLVector3(-SRR3, SRR3, SRR3);
+		*(tex_coords++) =	LLVector2(LEAF_LEFT, LEAF_TOP);
+		*(vertices++) =		LLVector3(-0.5f*LEAF_WIDTH, 0.f, 1.f);
+		vertex_count++;
+
+		*(normals++) =		LLVector3(SRR2, SRR2, 0.f);
+		*(tex_coords++) =	LLVector2(LEAF_RIGHT, LEAF_BOTTOM);
+		*(vertices++) =		LLVector3(0.5f*LEAF_WIDTH, 0.f, 0.f);
+		vertex_count++;
+
+		*(indicesp++) = 4;
+		index_count++;
+		*(indicesp++) = 6;
+		index_count++;
+		*(indicesp++) = 5;
+		index_count++;
+
+		*(indicesp++) = 4;
+		index_count++;
+		*(indicesp++) = 5;
+		index_count++;
+		*(indicesp++) = 7;
+		index_count++;
+
+
+		// next leaf
+		*(normals++) =		LLVector3(SRR2, -SRR2, 0.f);
+		*(tex_coords++) =	LLVector2(LEAF_LEFT, LEAF_BOTTOM);
+		*(vertices++) =		LLVector3(0.f, -0.5f*LEAF_WIDTH, 0.f);
+		vertex_count++;
+
+		*(normals++) =		LLVector3(SRR3, SRR3, SRR3);
+		*(tex_coords++) =	LLVector2(LEAF_RIGHT, LEAF_TOP);
+		*(vertices++) =		LLVector3(0.f, 0.5f*LEAF_WIDTH, 1.f);
+		vertex_count++;
+
+		*(normals++) =		LLVector3(SRR3, -SRR3, SRR3);
+		*(tex_coords++) =	LLVector2(LEAF_LEFT, LEAF_TOP);
+		*(vertices++) =		LLVector3(0.f, -0.5f*LEAF_WIDTH, 1.f);
+		vertex_count++;
+
+		*(normals++) =		LLVector3(SRR2, SRR2, 0.f);
+		*(tex_coords++) =	LLVector2(LEAF_RIGHT, LEAF_BOTTOM);
+		*(vertices++) =		LLVector3(0.f, 0.5f*LEAF_WIDTH, 0.f);
+		vertex_count++;
+
+		*(indicesp++) = 8;
+		index_count++;
+		*(indicesp++) = 9;
+		index_count++;
+		*(indicesp++) = 10;
+		index_count++;
+
+		*(indicesp++) = 8;
+		index_count++;
+		*(indicesp++) = 11;
+		index_count++;
+		*(indicesp++) = 9;
+		index_count++;
+
+
+		// other side of same leaf
+		*(normals++) =		LLVector3(-SRR2, -SRR2, 0.f);
+		*(tex_coords++) =	LLVector2(LEAF_LEFT, LEAF_BOTTOM);
+		*(vertices++) =		LLVector3(0.f, -0.5f*LEAF_WIDTH, 0.f);
+		vertex_count++;
+
+		*(normals++) =		LLVector3(-SRR3, SRR3, SRR3);
+		*(tex_coords++) =	LLVector2(LEAF_RIGHT, LEAF_TOP);
+		*(vertices++) =		LLVector3(0.f, 0.5f*LEAF_WIDTH, 1.f);
+		vertex_count++;
+
+		*(normals++) =		LLVector3(-SRR3, -SRR3, SRR3);
+		*(tex_coords++) =	LLVector2(LEAF_LEFT, LEAF_TOP);
+		*(vertices++) =		LLVector3(0.f, -0.5f*LEAF_WIDTH, 1.f);
+		vertex_count++;
+
+		*(normals++) =		LLVector3(-SRR2, SRR2, 0.f);
+		*(tex_coords++) =	LLVector2(LEAF_RIGHT, LEAF_BOTTOM);
+		*(vertices++) =		LLVector3(0.f, 0.5f*LEAF_WIDTH, 0.f);
+		vertex_count++;
+
+		*(indicesp++) = 12;
+		index_count++;
+		*(indicesp++) = 14;
+		index_count++;
+		*(indicesp++) = 13;
+		index_count++;
+
+		*(indicesp++) = 12;
+		index_count++;
+		*(indicesp++) = 13;
+		index_count++;
+		*(indicesp++) = 15;
+		index_count++;
+
+		// Generate geometry for the cylinders
+
+		// Different LOD's
+
+		// Generate the vertices
+		// Generate the indices
+
+		for (lod = 0; lod < 4; lod++)
+		{
+			slices = sLODSlices[lod];
+			F32 base_radius = 0.65f;
+			F32 top_radius = base_radius * sSpeciesTable[mSpecies]->mTaper;
+			//llinfos << "Species " << ((U32) mSpecies) << ", taper = " << sSpeciesTable[mSpecies].mTaper << llendl;
+			//llinfos << "Droop " << mDroop << ", branchlength: " << mBranchLength << llendl;
+			F32 angle = 0;
+			F32 angle_inc = 360.f/(slices-1);
+			F32 z = 0.f;
+			F32 z_inc = 1.f;
+			if (slices > 3)
+			{
+				z_inc = 1.f/(slices - 3);
+			}
+			F32 radius = base_radius;
+
+			F32 x1,y1;
+			F32 noise_scale = sSpeciesTable[mSpecies]->mNoiseMag;
+			LLVector3 nvec;
+
+			const F32 cap_nudge = 0.1f;			// Height to 'peak' the caps on top/bottom of branch
+
+			const S32 fractal_depth = 5;
+			F32 nvec_scale = 1.f * sSpeciesTable[mSpecies]->mNoiseScale;
+			F32 nvec_scalez = 4.f * sSpeciesTable[mSpecies]->mNoiseScale;
+
+			F32 tex_z_repeat = sSpeciesTable[mSpecies]->mRepeatTrunkZ;
+
+			F32 start_radius;
+			F32 nangle = 0;
+			F32 height = 1.f;
+			F32 r0;
+
+			for (i = 0; i < slices; i++)
+			{
+				if (i == 0) 
+				{
+					z = - cap_nudge;
+					r0 = 0.0;
+				}
+				else if (i == (slices - 1))
+				{
+					z = 1.f + cap_nudge;//((i - 2) * z_inc) + cap_nudge;
+					r0 = 0.0;
+				}
+				else  
+				{
+					z = (i - 1) * z_inc;
+					r0 = base_radius + (top_radius - base_radius)*z;
+				}
 
-	S32 max_indices = LEAF_INDICES;
-	S32 max_vertices = LEAF_VERTICES;
-	S32 lod;
+				for (j = 0; j < slices; j++)
+				{
+					if (slices - 1 == j)
+					{
+						angle = 0.f;
+					}
+					else
+					{
+						angle =  j*angle_inc;
+					}
+				
+					nangle = angle;
+					
+					x1 = cos(angle * DEG_TO_RAD);
+					y1 = sin(angle * DEG_TO_RAD);
+					LLVector2 tc;
+					// This isn't totally accurate.  Should compute based on slope as well.
+					start_radius = r0 * (1.f + 1.2f*fabs(z - 0.66f*height)/height);
+					nvec.set(	cos(nangle * DEG_TO_RAD)*start_radius*nvec_scale, 
+								sin(nangle * DEG_TO_RAD)*start_radius*nvec_scale, 
+								z*nvec_scalez); 
+					// First and last slice at 0 radius (to bring in top/bottom of structure)
+					radius = start_radius + turbulence3((F32*)&nvec.mV, (F32)fractal_depth)*noise_scale;
+
+					if (slices - 1 == j)
+					{
+						// Not 0.5 for slight slop factor to avoid edges on leaves
+						tc = LLVector2(0.490f, (1.f - z/2.f)*tex_z_repeat);
+					}
+					else
+					{
+						tc = LLVector2((angle/360.f)*0.5f, (1.f - z/2.f)*tex_z_repeat);
+					}
+
+					*(vertices++) =		LLVector3(x1*radius, y1*radius, z);
+					*(normals++) =		LLVector3(x1, y1, 0.f);
+					*(tex_coords++) = tc;
+					vertex_count++;
+				}
+			}
 
-	LLFace *face = drawable->getFace(0);
+			for (i = 0; i < (slices - 1); i++)
+			{
+				for (j = 0; j < (slices - 1); j++)
+				{
+					S32 x1_offset = j+1;
+					if ((j+1) == slices)
+					{
+						x1_offset = 0;
+					}
+					// Generate the matching quads
+					*(indicesp) = j + (i*slices) + sLODVertexOffset[lod];
+					llassert(*(indicesp) < (U32)max_vertices);
+					indicesp++;
+					index_count++;
+					*(indicesp) = x1_offset + ((i+1)*slices) + sLODVertexOffset[lod];
+					llassert(*(indicesp) < (U32)max_vertices);
+					indicesp++;
+					index_count++;
+					*(indicesp) = j + ((i+1)*slices) + sLODVertexOffset[lod];
+					llassert(*(indicesp) < (U32)max_vertices);
+					indicesp++;
+					index_count++;
+
+					*(indicesp) = j + (i*slices) + sLODVertexOffset[lod];
+					llassert(*(indicesp) < (U32)max_vertices);
+					indicesp++;
+					index_count++;
+					*(indicesp) = x1_offset + (i*slices) + sLODVertexOffset[lod];
+					llassert(*(indicesp) < (U32)max_vertices);
+					indicesp++;
+					index_count++;
+					*(indicesp) = x1_offset + ((i+1)*slices) + sLODVertexOffset[lod];
+					llassert(*(indicesp) < (U32)max_vertices);
+					indicesp++;
+					index_count++;
+				}
+			}
+			slices /= 2; 
+		}
 
-	face->mCenterAgent = getPositionAgent();
-	face->mCenterLocal = face->mCenterAgent;
+		mReferenceBuffer->setBuffer(0);
+		llassert(vertex_count == max_vertices);
+		llassert(index_count == max_indices);
+	}
 
-	for (lod = 0; lod < 4; lod++)
+	if (gSavedSettings.getBOOL("RenderAnimateTrees"))
+	{
+		mDrawable->getFace(0)->mVertexBuffer = mReferenceBuffer;
+	}
+	else
 	{
-		slices = sLODSlices[lod];
-		sLODVertexOffset[lod] = max_vertices;
-		sLODVertexCount[lod] = slices*slices;
-		sLODIndexOffset[lod] = max_indices;
-		sLODIndexCount[lod] = (slices-1)*(slices-1)*6;
-		max_indices += sLODIndexCount[lod];
-		max_vertices += sLODVertexCount[lod];
+		//generate tree mesh
+		updateMesh();
 	}
+	
+	return TRUE;
+}
 
+void LLVOTree::updateMesh()
+{
+	LLMatrix4 matrix;
+	
+	// Translate to tree base  HACK - adjustment in Z plants tree underground
+	const LLVector3 &pos_agent = getPositionAgent();
+	//glTranslatef(pos_agent.mV[VX], pos_agent.mV[VY], pos_agent.mV[VZ] - 0.1f);
+	LLMatrix4 trans_mat;
+	trans_mat.setTranslation(pos_agent.mV[VX], pos_agent.mV[VY], pos_agent.mV[VZ] - 0.1f);
+	trans_mat *= matrix;
+	
+	// Rotate to tree position and bend for current trunk/wind
+	// Note that trunk stiffness controls the amount of bend at the trunk as 
+	// opposed to the crown of the tree
+	// 
+	const F32 TRUNK_STIFF = 22.f;
+	
+	LLQuaternion rot = 
+		LLQuaternion(mTrunkBend.magVec()*TRUNK_STIFF*DEG_TO_RAD, LLVector4(mTrunkBend.mV[VX], mTrunkBend.mV[VY], 0)) *
+		LLQuaternion(90.f*DEG_TO_RAD, LLVector4(0,0,1)) *
+		getRotation();
+
+	LLMatrix4 rot_mat(rot);
+	rot_mat *= trans_mat;
+
+	F32 radius = getScale().magVec()*0.05f;
+	LLMatrix4 scale_mat;
+	scale_mat.mMatrix[0][0] = 
+		scale_mat.mMatrix[1][1] =
+		scale_mat.mMatrix[2][2] = radius;
+
+	scale_mat *= rot_mat;
+
+//	const F32 THRESH_ANGLE_FOR_BILLBOARD = 15.f;
+//	const F32 BLEND_RANGE_FOR_BILLBOARD = 3.f;
+
+	F32 droop = mDroop + 25.f*(1.f - mTrunkBend.magVec());
+	
+	S32 stop_depth = 0;
+	F32 alpha = 1.0;
+	
+
+	U32 vert_count = 0;
+	U32 index_count = 0;
+	
+	calcNumVerts(vert_count, index_count, mTrunkLOD, stop_depth, mDepth, mTrunkDepth, mBranches);
+
+	LLFace* facep = mDrawable->getFace(0);
+	facep->mVertexBuffer = new LLVertexBuffer(LLDrawPoolTree::VERTEX_DATA_MASK, GL_STATIC_DRAW_ARB);
+	facep->mVertexBuffer->allocateBuffer(vert_count, index_count, TRUE);
+	
 	LLStrider<LLVector3> vertices;
 	LLStrider<LLVector3> normals;
 	LLStrider<LLVector2> tex_coords;
-	LLStrider<U16> indicesp;
-
-	face->setSize(max_vertices, max_indices);
+	LLStrider<U16> indices;
+	U16 idx_offset = 0;
 
-	face->mVertexBuffer = new LLVertexBuffer(LLDrawPoolTree::VERTEX_DATA_MASK, GL_STATIC_DRAW_ARB);
-	face->mVertexBuffer->allocateBuffer(max_vertices, max_indices, TRUE);
-	face->setGeomIndex(0);
-	face->setIndicesIndex(0);
+	facep->mVertexBuffer->getVertexStrider(vertices);
+	facep->mVertexBuffer->getNormalStrider(normals);
+	facep->mVertexBuffer->getTexCoord0Strider(tex_coords);
+	facep->mVertexBuffer->getIndexStrider(indices);
 
-	face->getGeometry(vertices, normals, tex_coords, indicesp);
+	genBranchPipeline(vertices, normals, tex_coords, indices, idx_offset, scale_mat, mTrunkLOD, stop_depth, mDepth, mTrunkDepth, 1.0, mTwist, droop, mBranches, alpha);
 	
+	mReferenceBuffer->setBuffer(0);
+	facep->mVertexBuffer->setBuffer(0);
+
+}
 
-	S32 vertex_count = 0;
-	S32 index_count = 0;
+void LLVOTree::appendMesh(LLStrider<LLVector3>& vertices, 
+						 LLStrider<LLVector3>& normals, 
+						 LLStrider<LLVector2>& tex_coords, 
+						 LLStrider<U16>& indices,
+						 U16& cur_idx,
+						 LLMatrix4& matrix,
+						 LLMatrix4& norm_mat,
+						 S32 vert_start,
+						 S32 vert_count,
+						 S32 index_count,
+						 S32 index_offset)
+{
+	LLStrider<LLVector3> v;
+	LLStrider<LLVector3> n;
+	LLStrider<LLVector2> t;
+	LLStrider<U16> idx;
+
+	mReferenceBuffer->getVertexStrider(v);
+	mReferenceBuffer->getNormalStrider(n);
+	mReferenceBuffer->getTexCoord0Strider(t);
+	mReferenceBuffer->getIndexStrider(idx);
 	
-	// First leaf
-	*(normals++) =		LLVector3(-SRR2, -SRR2, 0.f);
-	*(tex_coords++) =	LLVector2(LEAF_LEFT, LEAF_BOTTOM);
-	*(vertices++) =		LLVector3(-0.5f*LEAF_WIDTH, 0.f, 0.f);
-	vertex_count++;
-
-	*(normals++) =		LLVector3(SRR3, -SRR3, SRR3);
-	*(tex_coords++) =	LLVector2(LEAF_RIGHT, LEAF_TOP);
-	*(vertices++) =		LLVector3(0.5f*LEAF_WIDTH, 0.f, 1.f);
-	vertex_count++;
-
-	*(normals++) =		LLVector3(-SRR3, -SRR3, SRR3);
-	*(tex_coords++) =	LLVector2(LEAF_LEFT, LEAF_TOP);
-	*(vertices++) =		LLVector3(-0.5f*LEAF_WIDTH, 0.f, 1.f);
-	vertex_count++;
-
-	*(normals++) =		LLVector3(SRR2, -SRR2, 0.f);
-	*(tex_coords++) =	LLVector2(LEAF_RIGHT, LEAF_BOTTOM);
-	*(vertices++) =		LLVector3(0.5f*LEAF_WIDTH, 0.f, 0.f);
-	vertex_count++;
-
-
-	*(indicesp++) = 0;
-	index_count++;
-	*(indicesp++) = 1;
-	index_count++;
-	*(indicesp++) = 2;
-	index_count++;
-
-	*(indicesp++) = 0;
-	index_count++;
-	*(indicesp++) = 3;
-	index_count++;
-	*(indicesp++) = 1;
-	index_count++;
-
-	// Same leaf, inverse winding/normals
-	*(normals++) =		LLVector3(-SRR2, SRR2, 0.f);
-	*(tex_coords++) =	LLVector2(LEAF_LEFT, LEAF_BOTTOM);
-	*(vertices++) =		LLVector3(-0.5f*LEAF_WIDTH, 0.f, 0.f);
-	vertex_count++;
-
-	*(normals++) =		LLVector3(SRR3, SRR3, SRR3);
-	*(tex_coords++) =	LLVector2(LEAF_RIGHT, LEAF_TOP);
-	*(vertices++) =		LLVector3(0.5f*LEAF_WIDTH, 0.f, 1.f);
-	vertex_count++;
-
-	*(normals++) =		LLVector3(-SRR3, SRR3, SRR3);
-	*(tex_coords++) =	LLVector2(LEAF_LEFT, LEAF_TOP);
-	*(vertices++) =		LLVector3(-0.5f*LEAF_WIDTH, 0.f, 1.f);
-	vertex_count++;
-
-	*(normals++) =		LLVector3(SRR2, SRR2, 0.f);
-	*(tex_coords++) =	LLVector2(LEAF_RIGHT, LEAF_BOTTOM);
-	*(vertices++) =		LLVector3(0.5f*LEAF_WIDTH, 0.f, 0.f);
-	vertex_count++;
-
-	*(indicesp++) = 4;
-	index_count++;
-	*(indicesp++) = 6;
-	index_count++;
-	*(indicesp++) = 5;
-	index_count++;
-
-	*(indicesp++) = 4;
-	index_count++;
-	*(indicesp++) = 5;
-	index_count++;
-	*(indicesp++) = 7;
-	index_count++;
-
-
-	// next leaf
-	*(normals++) =		LLVector3(SRR2, -SRR2, 0.f);
-	*(tex_coords++) =	LLVector2(LEAF_LEFT, LEAF_BOTTOM);
-	*(vertices++) =		LLVector3(0.f, -0.5f*LEAF_WIDTH, 0.f);
-	vertex_count++;
-
-	*(normals++) =		LLVector3(SRR3, SRR3, SRR3);
-	*(tex_coords++) =	LLVector2(LEAF_RIGHT, LEAF_TOP);
-	*(vertices++) =		LLVector3(0.f, 0.5f*LEAF_WIDTH, 1.f);
-	vertex_count++;
-
-	*(normals++) =		LLVector3(SRR3, -SRR3, SRR3);
-	*(tex_coords++) =	LLVector2(LEAF_LEFT, LEAF_TOP);
-	*(vertices++) =		LLVector3(0.f, -0.5f*LEAF_WIDTH, 1.f);
-	vertex_count++;
-
-	*(normals++) =		LLVector3(SRR2, SRR2, 0.f);
-	*(tex_coords++) =	LLVector2(LEAF_RIGHT, LEAF_BOTTOM);
-	*(vertices++) =		LLVector3(0.f, 0.5f*LEAF_WIDTH, 0.f);
-	vertex_count++;
-
-	*(indicesp++) = 8;
-	index_count++;
-	*(indicesp++) = 9;
-	index_count++;
-	*(indicesp++) = 10;
-	index_count++;
-
-	*(indicesp++) = 8;
-	index_count++;
-	*(indicesp++) = 11;
-	index_count++;
-	*(indicesp++) = 9;
-	index_count++;
-
-
-	// other side of same leaf
-	*(normals++) =		LLVector3(-SRR2, -SRR2, 0.f);
-	*(tex_coords++) =	LLVector2(LEAF_LEFT, LEAF_BOTTOM);
-	*(vertices++) =		LLVector3(0.f, -0.5f*LEAF_WIDTH, 0.f);
-	vertex_count++;
-
-	*(normals++) =		LLVector3(-SRR3, SRR3, SRR3);
-	*(tex_coords++) =	LLVector2(LEAF_RIGHT, LEAF_TOP);
-	*(vertices++) =		LLVector3(0.f, 0.5f*LEAF_WIDTH, 1.f);
-	vertex_count++;
-
-	*(normals++) =		LLVector3(-SRR3, -SRR3, SRR3);
-	*(tex_coords++) =	LLVector2(LEAF_LEFT, LEAF_TOP);
-	*(vertices++) =		LLVector3(0.f, -0.5f*LEAF_WIDTH, 1.f);
-	vertex_count++;
-
-	*(normals++) =		LLVector3(-SRR2, SRR2, 0.f);
-	*(tex_coords++) =	LLVector2(LEAF_RIGHT, LEAF_BOTTOM);
-	*(vertices++) =		LLVector3(0.f, 0.5f*LEAF_WIDTH, 0.f);
-	vertex_count++;
-
-	*(indicesp++) = 12;
-	index_count++;
-	*(indicesp++) = 14;
-	index_count++;
-	*(indicesp++) = 13;
-	index_count++;
-
-	*(indicesp++) = 12;
-	index_count++;
-	*(indicesp++) = 13;
-	index_count++;
-	*(indicesp++) = 15;
-	index_count++;
-
-	// Generate geometry for the cylinders
-
-	// Different LOD's
-
-	// Generate the vertices
-	// Generate the indices
-
-	for (lod = 0; lod < 4; lod++)
+	//copy/transform vertices into mesh - check
+	for (S32 i = 0; i < vert_count; i++)
+	{ 
+		U16 index = vert_start + i;
+		*vertices++ = v[index] * matrix;
+		LLVector3 norm = n[index] * norm_mat;
+		norm.normalize();
+		*normals++ = norm;
+		*tex_coords++ = t[index];
+	}
+
+	//copy offset indices into mesh - check
+	for (S32 i = 0; i < index_count; i++)
 	{
-		slices = sLODSlices[lod];
-		F32 base_radius = 0.65f;
-		F32 top_radius = base_radius * sSpeciesTable[mSpecies]->mTaper;
-		//llinfos << "Species " << ((U32) mSpecies) << ", taper = " << sSpeciesTable[mSpecies].mTaper << llendl;
-		//llinfos << "Droop " << mDroop << ", branchlength: " << mBranchLength << llendl;
-		F32 angle = 0;
-		F32 angle_inc = 360.f/(slices-1);
-		F32 z = 0.f;
-		F32 z_inc = 1.f;
-		if (slices > 3)
+		U16 index = index_offset + i;
+		if (idx[index] >= vert_start + vert_count ||
+			idx[index] < vert_start)
 		{
-			z_inc = 1.f/(slices - 3);
+			llerrs << "WTF?" << llendl;
 		}
-		F32 radius = base_radius;
-
-		F32 x1,y1;
-		F32 noise_scale = sSpeciesTable[mSpecies]->mNoiseMag;
-		LLVector3 nvec;
-
-		const F32 cap_nudge = 0.1f;			// Height to 'peak' the caps on top/bottom of branch
-
-		const S32 fractal_depth = 5;
-		F32 nvec_scale = 1.f * sSpeciesTable[mSpecies]->mNoiseScale;
-		F32 nvec_scalez = 4.f * sSpeciesTable[mSpecies]->mNoiseScale;
+		*indices++ = idx[index]-vert_start+cur_idx;
+	}
 
-		F32 tex_z_repeat = sSpeciesTable[mSpecies]->mRepeatTrunkZ;
+	//increment index offset - check
+	cur_idx += vert_count;
+}
+								 
+
+void LLVOTree::genBranchPipeline(LLStrider<LLVector3>& vertices, 
+								 LLStrider<LLVector3>& normals, 
+								 LLStrider<LLVector2>& tex_coords, 
+								 LLStrider<U16>& indices,
+								 U16& index_offset,
+								 LLMatrix4& matrix, 
+								 S32 trunk_LOD, 
+								 S32 stop_level, 
+								 U16 depth, 
+								 U16 trunk_depth,  
+								 F32 scale, 
+								 F32 twist, 
+								 F32 droop,  
+								 F32 branches, 
+								 F32 alpha)
+{
+	//
+	//  Generates a tree mesh by recursing, generating branches and then a 'leaf' texture.
+	
+	static F32 constant_twist;
+	static F32 width = 0;
 
-		F32 start_radius;
-		F32 nangle = 0;
-		F32 height = 1.f;
-		F32 r0;
+	F32 length = ((trunk_depth || (scale == 1.f))? mTrunkLength:mBranchLength);
+	F32 aspect = ((trunk_depth || (scale == 1.f))? mTrunkAspect:mBranchAspect);
+	
+	constant_twist = 360.f/branches;
 
-		for (i = 0; i < slices; i++)
+	if (stop_level >= 0)
+	{
+		if (depth > stop_level)
 		{
-			if (i == 0) 
 			{
-				z = - cap_nudge;
-				r0 = 0.0;
+				llassert(sLODIndexCount[trunk_LOD] > 0);
+				width = scale * length * aspect;
+				LLMatrix4 scale_mat;
+				scale_mat.mMatrix[0][0] = width;
+				scale_mat.mMatrix[1][1] = width;
+				scale_mat.mMatrix[2][2] = scale*length;
+				scale_mat *= matrix;
+
+				glh::matrix4f norm((F32*) scale_mat.mMatrix);
+				LLMatrix4 norm_mat = LLMatrix4(norm.inverse().transpose().m);
+
+				norm_mat.invert();
+				appendMesh(vertices, normals, tex_coords, indices, index_offset, scale_mat, norm_mat, 
+							sLODVertexOffset[trunk_LOD], sLODVertexCount[trunk_LOD], sLODIndexCount[trunk_LOD], sLODIndexOffset[trunk_LOD]);
 			}
-			else if (i == (slices - 1))
+			
+			// Recurse to create more branches
+			for (S32 i=0; i < (S32)branches; i++) 
 			{
-				z = 1.f + cap_nudge;//((i - 2) * z_inc) + cap_nudge;
-				r0 = 0.0;
+				LLMatrix4 trans_mat;
+				trans_mat.setTranslation(0,0,scale*length);
+				trans_mat *= matrix;
+
+				LLQuaternion rot = 
+					LLQuaternion(20.f*DEG_TO_RAD, LLVector4(0.f, 0.f, 1.f)) *
+					LLQuaternion(droop*DEG_TO_RAD, LLVector4(0.f, 1.f, 0.f)) *
+					LLQuaternion(((constant_twist + ((i%2==0)?twist:-twist))*i)*DEG_TO_RAD, LLVector4(0.f, 0.f, 1.f));
+				
+				LLMatrix4 rot_mat(rot);
+				rot_mat *= trans_mat;
+
+				genBranchPipeline(vertices, normals, tex_coords, indices, index_offset, rot_mat, trunk_LOD, stop_level, depth - 1, 0, scale*mScaleStep, twist, droop, branches, alpha);
 			}
-			else  
+			//  Recurse to continue trunk
+			if (trunk_depth)
 			{
-				z = (i - 1) * z_inc;
-				r0 = base_radius + (top_radius - base_radius)*z;
-			}
+				LLMatrix4 trans_mat;
+				trans_mat.setTranslation(0,0,scale*length);
+				trans_mat *= matrix;
 
-			for (j = 0; j < slices; j++)
+				LLMatrix4 rot_mat(70.5f*DEG_TO_RAD, LLVector4(0,0,1));
+				rot_mat *= trans_mat; // rotate a bit around Z when ascending 
+				genBranchPipeline(vertices, normals, tex_coords, indices, index_offset, rot_mat, trunk_LOD, stop_level, depth, trunk_depth-1, scale*mScaleStep, twist, droop, branches, alpha);
+			}
+		}
+		else
+		{
+			//
+			//  Append leaves as two 90 deg crossed quads with leaf textures
+			//
 			{
-				if (slices - 1 == j)
-				{
-					angle = 0.f;
-				}
-				else
-				{
-					angle =  j*angle_inc;
-				}
-			
-				nangle = angle;
-				
-				x1 = cos(angle * DEG_TO_RAD);
-				y1 = sin(angle * DEG_TO_RAD);
-				LLVector2 tc;
-				// This isn't totally accurate.  Should compute based on slope as well.
-				start_radius = r0 * (1.f + 1.2f*fabs(z - 0.66f*height)/height);
-				nvec.set(	cos(nangle * DEG_TO_RAD)*start_radius*nvec_scale, 
-							sin(nangle * DEG_TO_RAD)*start_radius*nvec_scale, 
-							z*nvec_scalez); 
-				// First and last slice at 0 radius (to bring in top/bottom of structure)
-				radius = start_radius + turbulence3((F32*)&nvec.mV, (F32)fractal_depth)*noise_scale;
-
-				if (slices - 1 == j)
-				{
-					// Not 0.5 for slight slop factor to avoid edges on leaves
-					tc = LLVector2(0.490f, (1.f - z/2.f)*tex_z_repeat);
-				}
-				else
-				{
-					tc = LLVector2((angle/360.f)*0.5f, (1.f - z/2.f)*tex_z_repeat);
-				}
+				LLMatrix4 scale_mat;
+				scale_mat.mMatrix[0][0] = 
+					scale_mat.mMatrix[1][1] =
+					scale_mat.mMatrix[2][2] = scale*mLeafScale;
 
-				*(vertices++) =		LLVector3(x1*radius, y1*radius, z);
-				*(normals++) =		LLVector3(x1, y1, 0.f);
-				*(tex_coords++) = tc;
-				vertex_count++;
+				scale_mat *= matrix;
+
+				glh::matrix4f norm((F32*) scale_mat.mMatrix);
+				LLMatrix4 norm_mat = LLMatrix4(norm.inverse().transpose().m);
+
+				appendMesh(vertices, normals, tex_coords, indices, index_offset, scale_mat, norm_mat, 0, LEAF_VERTICES, LEAF_INDICES, 0);	
 			}
 		}
+	}
+}
+
 
-		for (i = 0; i < (slices - 1); i++)
+
+void LLVOTree::calcNumVerts(U32& vert_count, U32& index_count, S32 trunk_LOD, S32 stop_level, U16 depth, U16 trunk_depth, F32 branches)
+{
+	if (stop_level >= 0)
+	{
+		if (depth > stop_level)
 		{
-			for (j = 0; j < (slices - 1); j++)
+			index_count += sLODIndexCount[trunk_LOD];
+			vert_count += sLODVertexCount[trunk_LOD];
+
+			// Recurse to create more branches
+			for (S32 i=0; i < (S32)branches; i++) 
 			{
-				S32 x1_offset = j+1;
-				if ((j+1) == slices)
-				{
-					x1_offset = 0;
-				}
-				// Generate the matching quads
-				*(indicesp) = j + (i*slices) + sLODVertexOffset[lod];
-				llassert(*(indicesp) < (U32)max_vertices);
-				indicesp++;
-				index_count++;
-				*(indicesp) = x1_offset + ((i+1)*slices) + sLODVertexOffset[lod];
-				llassert(*(indicesp) < (U32)max_vertices);
-				indicesp++;
-				index_count++;
-				*(indicesp) = j + ((i+1)*slices) + sLODVertexOffset[lod];
-				llassert(*(indicesp) < (U32)max_vertices);
-				indicesp++;
-				index_count++;
-
-				*(indicesp) = j + (i*slices) + sLODVertexOffset[lod];
-				llassert(*(indicesp) < (U32)max_vertices);
-				indicesp++;
-				index_count++;
-				*(indicesp) = x1_offset + (i*slices) + sLODVertexOffset[lod];
-				llassert(*(indicesp) < (U32)max_vertices);
-				indicesp++;
-				index_count++;
-				*(indicesp) = x1_offset + ((i+1)*slices) + sLODVertexOffset[lod];
-				llassert(*(indicesp) < (U32)max_vertices);
-				indicesp++;
-				index_count++;
+				calcNumVerts(vert_count, index_count, trunk_LOD, stop_level, depth - 1, 0, branches);
 			}
+			
+			//  Recurse to continue trunk
+			if (trunk_depth)
+			{
+				calcNumVerts(vert_count, index_count, trunk_LOD, stop_level, depth, trunk_depth-1, branches);
+			}
+		}
+		else
+		{
+			index_count += LEAF_INDICES;
+			vert_count += LEAF_VERTICES;
 		}
-		slices /= 2; 
 	}
-
-	face->mVertexBuffer->setBuffer(0);
-	llassert(vertex_count == max_vertices);
-	llassert(index_count == max_indices);
-
-	return TRUE;
+	else
+	{
+		index_count += LEAF_INDICES;
+		vert_count += LEAF_VERTICES;
+	}
 }
 
 U32 LLVOTree::drawBranchPipeline(LLMatrix4& matrix, U16* indicesp, S32 trunk_LOD, S32 stop_level, U16 depth, U16 trunk_depth,  F32 scale, F32 twist, F32 droop,  F32 branches, F32 alpha)
diff --git a/indra/newview/llvotree.h b/indra/newview/llvotree.h
index 7e81dc3e0811337d32049377454a481ea42f7204..473f1c340ec84379592fbda74d3bcb0db7a1556e 100644
--- a/indra/newview/llvotree.h
+++ b/indra/newview/llvotree.h
@@ -51,7 +51,7 @@ class LLVOTree : public LLViewerObject
 	{
 		VERTEX_DATA_MASK =	(1 << LLVertexBuffer::TYPE_VERTEX) |
 							(1 << LLVertexBuffer::TYPE_NORMAL) |
-							(1 << LLVertexBuffer::TYPE_TEXCOORD)
+							(1 << LLVertexBuffer::TYPE_TEXCOORD0)
 	};
 
 	LLVOTree(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp);
@@ -79,6 +79,38 @@ class LLVOTree : public LLViewerObject
 
 	void updateRadius();
 
+	void calcNumVerts(U32& vert_count, U32& index_count, S32 trunk_LOD, S32 stop_level, U16 depth, U16 trunk_depth, F32 branches);
+
+	void updateMesh();
+
+	void appendMesh(LLStrider<LLVector3>& vertices, 
+						 LLStrider<LLVector3>& normals, 
+						 LLStrider<LLVector2>& tex_coords, 
+						 LLStrider<U16>& indices,
+						 U16& idx_offset,
+						 LLMatrix4& matrix,
+						 LLMatrix4& norm_mat,
+						 S32 vertex_offset,
+						 S32 vertex_count,
+						 S32 index_count,
+						 S32 index_offset);
+
+	void genBranchPipeline(LLStrider<LLVector3>& vertices, 
+								 LLStrider<LLVector3>& normals, 
+								 LLStrider<LLVector2>& tex_coords, 
+								 LLStrider<U16>& indices,
+								 U16& index_offset,
+								 LLMatrix4& matrix, 
+								 S32 trunk_LOD, 
+								 S32 stop_level, 
+								 U16 depth, 
+								 U16 trunk_depth,  
+								 F32 scale, 
+								 F32 twist, 
+								 F32 droop,  
+								 F32 branches, 
+								 F32 alpha);
+
 	U32 drawBranchPipeline(LLMatrix4& matrix, U16* indicesp, S32 trunk_LOD, S32 stop_level, U16 depth, U16 trunk_depth,  F32 scale, F32 twist, F32 droop,  F32 branches, F32 alpha);
  
 
@@ -127,6 +159,7 @@ class LLVOTree : public LLViewerObject
 	LLVector3		mTrunkVel;		// 
 	LLVector3		mWind;
 
+	LLPointer<LLVertexBuffer> mReferenceBuffer; //reference geometry for generating tree mesh
 	LLPointer<LLViewerImage> mTreeImagep;	// Pointer to proper tree image
 
 	U8				mSpecies;		// Species of tree
@@ -138,7 +171,7 @@ class LLVOTree : public LLViewerObject
 	U8				mDepth;			// Number of recursions to tips of branches
 	F32				mScaleStep;		// Multiplier for scale at each recursion level
 	U8				mTrunkDepth;
-
+	U32				mTrunkLOD;
 	F32				mLeafScale;		// Scales leaf texture when rendering 
 
 	F32				mBillboardScale;	//  How big to draw the billboard?
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 9023147a7da45093766765e2ebaddcea853f34de..9e051a6470b95492aef3178a3d81a5ebbf36ed98 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -409,7 +409,7 @@ BOOL LLVOVolume::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
 void LLVOVolume::updateTextures(LLAgent &agent)
 {
 	const F32 TEXTURE_AREA_REFRESH_TIME = 5.f; // seconds
-	if (mTextureUpdateTimer.getElapsedTimeF32() > TEXTURE_AREA_REFRESH_TIME)
+	if (mDrawable.notNull() && mTextureUpdateTimer.getElapsedTimeF32() > TEXTURE_AREA_REFRESH_TIME)
 	{
 		if (mDrawable->isVisible())
 		{
@@ -468,17 +468,6 @@ void LLVOVolume::updateTextures()
 
 		F32 old_size = face->getVirtualSize();
 
-		if (face->getPoolType() == LLDrawPool::POOL_ALPHA)
-		{
-			
-			if (LLPipeline::sFastAlpha &&
-				vsize < MIN_ALPHA_SIZE && old_size > MIN_ALPHA_SIZE ||
-				vsize > MIN_ALPHA_SIZE && old_size < MIN_ALPHA_SIZE)
-			{
-				gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_COLOR, FALSE);
-			}
-		}
-
 		if (face->mTextureMatrix != NULL)
 		{
 			if (vsize < MIN_TEX_ANIM_SIZE && old_size > MIN_TEX_ANIM_SIZE ||
@@ -1283,10 +1272,12 @@ S32 LLVOVolume::setTEColor(const U8 te, const LLColor3& color)
 S32 LLVOVolume::setTEColor(const U8 te, const LLColor4& color)
 {
 	S32 res = LLViewerObject::setTEColor(te, color);
-	if (res)
+	if (res && mDrawable.notNull())
 	{
-		gPipeline.markTextured(mDrawable);
-		mFaceMappingChanged = TRUE;
+		//gPipeline.markTextured(mDrawable);
+		mDrawable->setState(LLDrawable::REBUILD_COLOR);
+		dirtyMesh();
+		//mFaceMappingChanged = TRUE;
 	}
 	return  res;
 }
@@ -1392,11 +1383,11 @@ S32 LLVOVolume::setTEScaleT(const U8 te, const F32 t)
 
 void LLVOVolume::updateTEData()
 {
-	if (mDrawable.notNull())
+	/*if (mDrawable.notNull())
 	{
 		mFaceMappingChanged = TRUE;
 		gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_MATERIAL, TRUE);
-	}
+	}*/
 }
 
 //----------------------------------------------------------------------------
@@ -1824,7 +1815,9 @@ F32 LLVOVolume::getBinRadius()
 		{
 			LLFace* face = mDrawable->getFace(i);
 			if (face->getPoolType() == LLDrawPool::POOL_ALPHA &&
-				(!LLPipeline::sFastAlpha || face->getVirtualSize() > MIN_ALPHA_SIZE))
+				(!LLPipeline::sFastAlpha || 
+				face->getFaceColor().mV[3] != 1.f ||
+				!face->getTexture()->getIsAlphaMask()))
 			{
 				alpha_wrap = TRUE;
 				break;
@@ -1849,14 +1842,20 @@ F32 LLVOVolume::getBinRadius()
 	}
 	else if (mDrawable->isStatic())
 	{
-		if (mDrawable->getRadius() < 2.0f)
+		/*if (mDrawable->getRadius() < 2.0f)
 		{
 			radius = 16.f;
 		}
 		else
 		{
 			radius = llmax(mDrawable->getRadius(), 32.f);
-		}
+		}*/
+
+		radius = (((S32) mDrawable->getRadius())/2+1)*8;
+	}
+	else if (mDrawable->getVObj()->isAttachment())
+	{
+		radius = (((S32) (mDrawable->getRadius()*4)+1))*2;
 	}
 	else
 	{
@@ -2128,6 +2127,11 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 		glow = (U8) (facep->getTextureEntry()->getGlow() * 255);
 	}
 
+	if (facep->mVertexBuffer.isNull())
+	{
+		llerrs << "WTF?" << llendl;
+	}
+
 	if (idx >= 0 && 
 		draw_vec[idx]->mVertexBuffer == facep->mVertexBuffer &&
 		draw_vec[idx]->mEnd == facep->getGeomIndex()-1 &&
@@ -2146,6 +2150,8 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 		draw_vec[idx]->mEnd += facep->getGeomCount();
 		draw_vec[idx]->mVSize = llmax(draw_vec[idx]->mVSize, facep->getVirtualSize());
 		validate_draw_info(*draw_vec[idx]);
+		update_min_max(draw_vec[idx]->mExtents[0], draw_vec[idx]->mExtents[1], facep->mExtents[0]);
+		update_min_max(draw_vec[idx]->mExtents[0], draw_vec[idx]->mExtents[1], facep->mExtents[1]);
 	}
 	else
 	{
@@ -2161,6 +2167,12 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 		draw_info->mTextureMatrix = tex_mat;
 		draw_info->mModelMatrix = model_mat;
 		draw_info->mGlowColor.setVec(0,0,0,glow);
+		if (type == LLRenderPass::PASS_ALPHA)
+		{ //for alpha sorting
+			facep->setDrawInfo(draw_info);
+		}
+		draw_info->mExtents[0] = facep->mExtents[0];
+		draw_info->mExtents[1] = facep->mExtents[1];
 		validate_draw_info(*draw_info);
 	}
 }
@@ -2184,89 +2196,15 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 
 	group->mLastUpdateViewAngle = group->mViewAngle;
 
-	if (!group->isState(LLSpatialGroup::GEOM_DIRTY |
-						LLSpatialGroup::ALPHA_DIRTY))
+	if (!group->isState(LLSpatialGroup::GEOM_DIRTY | LLSpatialGroup::ALPHA_DIRTY))
 	{
-		if (group->isState(LLSpatialGroup::MESH_DIRTY))
+		if (group->isState(LLSpatialGroup::MESH_DIRTY) && !LLPipeline::sDelayVBUpdate)
 		{
-			S32 num_mapped_veretx_buffer = LLVertexBuffer::sMappedCount ;
-
-			group->mBuilt = 1.f;
 			LLFastTimer ftm(LLFastTimer::FTM_REBUILD_VBO);	
-
 			LLFastTimer ftm2(LLFastTimer::FTM_REBUILD_VOLUME_VB);
-
-			for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter)
-			{
-				LLDrawable* drawablep = *drawable_iter;
-
-				if (drawablep->isDead() || drawablep->isState(LLDrawable::FORCE_INVISIBLE) )
-				{
-					continue;
-				}
-
-				if (drawablep->isState(LLDrawable::REBUILD_ALL))
-				{
-					LLVOVolume* vobj = drawablep->getVOVolume();
-					vobj->preRebuild();
-					LLVolume* volume = vobj->getVolume();
-					for (S32 i = 0; i < drawablep->getNumFaces(); ++i)
-					{
-						LLFace* face = drawablep->getFace(i);
-						if (face && face->mVertexBuffer.notNull())
-						{
-							face->getGeometryVolume(*volume, face->getTEOffset(), 
-								vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), face->getGeomIndex());
-						}
-					}
-
-					drawablep->clearState(LLDrawable::REBUILD_ALL);
-				}
-			}
-			
-			//unmap all the buffers
-			for (LLSpatialGroup::buffer_map_t::iterator i = group->mBufferMap.begin(); i != group->mBufferMap.end(); ++i)
-			{
-				LLSpatialGroup::buffer_list_t& list = i->second;
-				for (LLSpatialGroup::buffer_list_t::iterator j = list.begin(); j != list.end(); ++j)
-				{
-					LLVertexBuffer* buffer = *j;
-					if (buffer->isLocked())
-					{
-						buffer->setBuffer(0);
-					}
-				}
-			}
-			
-			// don't forget alpha
-			if(	group != NULL && 
-				!group->mVertexBuffer.isNull() && 
-				group->mVertexBuffer->isLocked())
-			{
-				group->mVertexBuffer->setBuffer(0);
-			}
-
-			//if not all buffers are unmapped
-			if(num_mapped_veretx_buffer != LLVertexBuffer::sMappedCount) 
-			{
-				llwarns << "Not all mapped vertex buffers are unmapped!" << llendl ; 
-				for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter)
-				{
-					LLDrawable* drawablep = *drawable_iter;
-					for (S32 i = 0; i < drawablep->getNumFaces(); ++i)
-					{
-						LLFace* face = drawablep->getFace(i);
-						if (face && face->mVertexBuffer.notNull() && face->mVertexBuffer->isLocked())
-						{
-							face->mVertexBuffer->setBuffer(0) ;
-						}
-					}
-				} 
-			}
-
-			group->clearState(LLSpatialGroup::MESH_DIRTY);
+		
+			rebuildMesh(group);
 		}
-
 		return;
 	}
 
@@ -2279,15 +2217,20 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 
 	mFaceList.clear();
 
+	std::vector<LLFace*> fullbright_faces;
+	std::vector<LLFace*> bump_faces;
+	std::vector<LLFace*> simple_faces;
+
 	std::vector<LLFace*> alpha_faces;
-	U32 vertex_count = 0;
-	U32 index_count = 0;
 	U32 useage = group->mSpatialPartition->mBufferUsage;
 
 	U32 max_vertices = (gSavedSettings.getS32("RenderMaxVBOSize")*1024)/LLVertexBuffer::calcStride(group->mSpatialPartition->mVertexDataMask);
+	U32 max_total = (gSavedSettings.getS32("RenderMaxNodeSize")*1024)/LLVertexBuffer::calcStride(group->mSpatialPartition->mVertexDataMask);
 	max_vertices = llmin(max_vertices, (U32) 65535);
 
-	//get all the faces into a list, putting alpha faces in their own list
+	U32 cur_total = 0;
+
+	//get all the faces into a list
 	for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter)
 	{
 		LLDrawable* drawablep = *drawable_iter;
@@ -2313,6 +2256,16 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 			//sum up face verts and indices
 			drawablep->updateFaceSize(i);
 			LLFace* facep = drawablep->getFace(i);
+
+			if (cur_total > max_total)
+			{
+				facep->mVertexBuffer = NULL;
+				facep->mLastVertexBuffer = NULL;
+				continue;
+			}
+
+			cur_total += facep->getGeomCount();
+
 			if (facep->hasGeometry() && facep->mPixelArea > FORCE_CULL_AREA)
 			{
 				const LLTextureEntry* te = facep->getTextureEntry();
@@ -2349,36 +2302,14 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 
 				if (type == LLDrawPool::POOL_ALPHA)
 				{
-					BOOL alpha_opt = LLPipeline::sFastAlpha && gPipeline.canUseWindLightShadersOnObjects() && facep->getVirtualSize() < MIN_ALPHA_SIZE;
-
-					const LLColor4& col = facep->getTextureEntry()->getColor();
-
-					if (alpha_opt)
-					{ //if we're applying the alpha optimization, only blend faces that have alpha (0.15, 0.5]
-					  //for faces with alpha (0.5, 1.0], render with an alpha mask
-					  //for faces with alpha [0.0, 0.15], don't render
-						if (col.mV[3] > 0.5f)
-						{
-							mFaceList.push_back(facep);
-						}
-						else if (col.mV[3] > 0.15f)
-						{
-							vertex_count += facep->getGeomCount();
-							index_count += facep->getIndicesCount();
-							alpha_faces.push_back(facep);
-						}
-						else
-						{	//face has no renderable geometry
-							facep->mVertexBuffer = NULL;
-							facep->mLastVertexBuffer = NULL;
-							//don't alpha wrap drawables that have only tiny tiny alpha faces
-							facep->setPoolType(LLDrawPool::POOL_SIMPLE);
-						}
+					if (LLPipeline::sFastAlpha &&
+						(te->getColor().mV[VW] == 1.0f) &&
+						facep->getTexture()->getIsAlphaMask())
+					{ //can be treated as alpha mask
+						simple_faces.push_back(facep);
 					}
 					else
 					{
-						vertex_count += facep->getGeomCount();
-						index_count += facep->getIndicesCount();
 						alpha_faces.push_back(facep);
 					}
 				}
@@ -2388,124 +2319,300 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 					{
 						facep->mLastUpdateTime = gFrameTimeSeconds;
 					}
-					mFaceList.push_back(facep);
+
+					if (gPipeline.canUseWindLightShadersOnObjects()
+						&& LLPipeline::sRenderBump)
+					{
+						if (te->getBumpmap())
+						{ //needs normal + binormal
+							bump_faces.push_back(facep);
+						}
+						else if (te->getShiny() || !te->getFullbright())
+						{ //needs normal
+							simple_faces.push_back(facep);
+						}
+						else 
+						{ //doesn't need normal
+							fullbright_faces.push_back(facep);
+						}
+					}
+					else
+					{
+						if (te->getBumpmap() && LLPipeline::sRenderBump)
+						{ //needs normal + binormal
+							bump_faces.push_back(facep);
+						}
+						else if (te->getShiny() && LLPipeline::sRenderBump ||
+							!te->getFullbright())
+						{ //needs normal
+							simple_faces.push_back(facep);
+						}
+						else 
+						{ //doesn't need normal
+							fullbright_faces.push_back(facep);
+						}
+					}
 				}
 			}
 			else
 			{	//face has no renderable geometry
 				facep->mVertexBuffer = NULL;
 				facep->mLastVertexBuffer = NULL;
-				//don't alpha wrap drawables that have only tiny tiny alpha faces
-				facep->setPoolType(LLDrawPool::POOL_SIMPLE);
 			}		
 		}
 	}
 
-	U16 alpha_vertex_count = vertex_count > 65535 ? 65535 : vertex_count;
-	U32 alpha_index_count = index_count;
-
 	group->mBufferUsage = useage;
 
 	//PROCESS NON-ALPHA FACES
+	U32 simple_mask = LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR;
+	U32 alpha_mask = simple_mask | 0x80000000; //hack to give alpha verts their own VBO
+	U32 bump_mask = LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR;
+	U32 fullbright_mask = LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR;
+
+	if (LLPipeline::sRenderDeferred)
 	{
-		//sort faces by things that break batches
-		std::sort(mFaceList.begin(), mFaceList.end(), LLFace::CompareBatchBreaker());
-					
-		std::vector<LLFace*>::iterator face_iter = mFaceList.begin();
-		
-		LLSpatialGroup::buffer_map_t buffer_map;
+		bump_mask |= LLVertexBuffer::MAP_BINORMAL;
+	}
 
-		LLViewerImage* last_tex = NULL;
-		U32 buffer_index = 0;
+	genDrawInfo(group, simple_mask, simple_faces);
+	genDrawInfo(group, bump_mask, bump_faces);
+	genDrawInfo(group, fullbright_mask, fullbright_faces);
+	genDrawInfo(group, alpha_mask, alpha_faces, TRUE);
 
-		while (face_iter != mFaceList.end())
+	if (!LLPipeline::sDelayVBUpdate)
+	{
+		//drawables have been rebuilt, clear rebuild status
+		for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter)
 		{
-			//pull off next face
-			LLFace* facep = *face_iter;
-			LLViewerImage* tex = facep->getTexture();
+			LLDrawable* drawablep = *drawable_iter;
+			drawablep->clearState(LLDrawable::REBUILD_ALL);
+		}
+	}
 
-			if (last_tex == tex)
-			{
-				buffer_index++;
-			}
-			else
+	group->mLastUpdateTime = gFrameTimeSeconds;
+	group->mBuilt = 1.f;
+	group->clearState(LLSpatialGroup::GEOM_DIRTY | LLSpatialGroup::ALPHA_DIRTY);
+
+	if (LLPipeline::sDelayVBUpdate)
+	{
+		group->setState(LLSpatialGroup::MESH_DIRTY);
+	}
+
+	mFaceList.clear();
+}
+
+void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
+{
+	if (group->isState(LLSpatialGroup::MESH_DIRTY))
+	{
+		S32 num_mapped_veretx_buffer = LLVertexBuffer::sMappedCount ;
+
+		group->mBuilt = 1.f;
+		
+		for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter)
+		{
+			LLDrawable* drawablep = *drawable_iter;
+
+			if (drawablep->isDead() || drawablep->isState(LLDrawable::FORCE_INVISIBLE) )
 			{
-				last_tex = tex;
-				buffer_index = 0;
+				continue;
 			}
 
-			U32 index_count = facep->getIndicesCount();
-			U32 geom_count = facep->getGeomCount();
-
-			//sum up vertices needed for this texture
-			std::vector<LLFace*>::iterator i = face_iter;
-			++i;
-			
-			while (i != mFaceList.end() && 
-				(LLPipeline::sTextureBindTest || (*i)->getTexture() == tex))
+			if (drawablep->isState(LLDrawable::REBUILD_ALL))
 			{
-				facep = *i;
-				
-				if (geom_count + facep->getGeomCount() > max_vertices)
-				{ //cut vertex buffers on geom count too big
-					break;
+				LLVOVolume* vobj = drawablep->getVOVolume();
+				vobj->preRebuild();
+				LLVolume* volume = vobj->getVolume();
+				for (S32 i = 0; i < drawablep->getNumFaces(); ++i)
+				{
+					LLFace* face = drawablep->getFace(i);
+					if (face && face->mVertexBuffer.notNull())
+					{
+						face->getGeometryVolume(*volume, face->getTEOffset(), 
+							vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), face->getGeomIndex());
+					}
 				}
 
-				++i;
-				index_count += facep->getIndicesCount();
-				geom_count += facep->getGeomCount();
+				drawablep->clearState(LLDrawable::REBUILD_ALL);
 			}
+		}
 		
-			//create/delete/resize vertex buffer if needed
-			LLVertexBuffer* buffer = NULL;
-			LLSpatialGroup::buffer_map_t::iterator found_iter = group->mBufferMap.find(tex);
-			if (found_iter != group->mBufferMap.end())
+		//unmap all the buffers
+		for (LLSpatialGroup::buffer_map_t::iterator i = group->mBufferMap.begin(); i != group->mBufferMap.end(); ++i)
+		{
+			LLSpatialGroup::buffer_texture_map_t& map = i->second;
+			for (LLSpatialGroup::buffer_texture_map_t::iterator j = map.begin(); j != map.end(); ++j)
 			{
-				if (buffer_index < found_iter->second.size())
+				LLSpatialGroup::buffer_list_t& list = j->second;
+				for (LLSpatialGroup::buffer_list_t::iterator k = list.begin(); k != list.end(); ++k)
 				{
-					buffer = found_iter->second[buffer_index];
+					LLVertexBuffer* buffer = *k;
+					if (buffer->isLocked())
+					{
+						buffer->setBuffer(0);
+					}
 				}
 			}
-							
-			if (!buffer)
-			{ //create new buffer if needed
+		}
+		
+		// don't forget alpha
+		if(	group != NULL && 
+			!group->mVertexBuffer.isNull() && 
+			group->mVertexBuffer->isLocked())
+		{
+			group->mVertexBuffer->setBuffer(0);
+		}
+
+		//if not all buffers are unmapped
+		if(num_mapped_veretx_buffer != LLVertexBuffer::sMappedCount) 
+		{
+			llwarns << "Not all mapped vertex buffers are unmapped!" << llendl ; 
+			for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter)
+			{
+				LLDrawable* drawablep = *drawable_iter;
+				for (S32 i = 0; i < drawablep->getNumFaces(); ++i)
+				{
+					LLFace* face = drawablep->getFace(i);
+					if (face && face->mVertexBuffer.notNull() && face->mVertexBuffer->isLocked())
+					{
+						face->mVertexBuffer->setBuffer(0) ;
+					}
+				}
+			} 
+		}
+
+		group->clearState(LLSpatialGroup::MESH_DIRTY);
+	}
+}
+
+void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::vector<LLFace*>& faces, BOOL distance_sort)
+{
+	//calculate maximum number of vertices to store in a single buffer
+	U32 max_vertices = (gSavedSettings.getS32("RenderMaxVBOSize")*1024)/LLVertexBuffer::calcStride(group->mSpatialPartition->mVertexDataMask);
+	max_vertices = llmin(max_vertices, (U32) 65535);
+
+	if (!distance_sort)
+	{
+		//sort faces by things that break batches
+		std::sort(faces.begin(), faces.end(), LLFace::CompareBatchBreaker());
+	}
+	else
+	{
+		//sort faces by distance
+		std::sort(faces.begin(), faces.end(), LLFace::CompareDistanceGreater());
+	}
+				
+	std::vector<LLFace*>::iterator face_iter = faces.begin();
+	
+	LLSpatialGroup::buffer_map_t buffer_map;
+
+	LLViewerImage* last_tex = NULL;
+	S32 buffer_index = 0;
+
+	if (distance_sort)
+	{
+		buffer_index = -1;
+	}
+
+	while (face_iter != faces.end())
+	{
+		//pull off next face
+		LLFace* facep = *face_iter;
+		LLViewerImage* tex = facep->getTexture();
+
+		if (distance_sort)
+		{
+			tex = NULL;
+		}
+
+		if (last_tex == tex)
+		{
+			buffer_index++;
+		}
+		else
+		{
+			last_tex = tex;
+			buffer_index = 0;
+		}
+
+		U32 index_count = facep->getIndicesCount();
+		U32 geom_count = facep->getGeomCount();
+
+		//sum up vertices needed for this texture
+		std::vector<LLFace*>::iterator i = face_iter;
+		++i;
+		
+		while (i != faces.end() && 
+			(LLPipeline::sTextureBindTest || (distance_sort || (*i)->getTexture() == tex)))
+		{
+			facep = *i;
+			
+			if (geom_count + facep->getGeomCount() > max_vertices)
+			{ //cut vertex buffers on geom count too big
+				break;
+			}
+
+			++i;
+			index_count += facep->getIndicesCount();
+			geom_count += facep->getGeomCount();
+		}
+	
+		//create/delete/resize vertex buffer if needed
+		LLVertexBuffer* buffer = NULL;
+		LLSpatialGroup::buffer_texture_map_t::iterator found_iter = group->mBufferMap[mask].find(tex);
+		
+		if (found_iter != group->mBufferMap[mask].end())
+		{
+			if ((U32) buffer_index < found_iter->second.size())
+			{
+				buffer = found_iter->second[buffer_index];
+			}
+		}
+						
+		if (!buffer)
+		{ //create new buffer if needed
+			buffer = createVertexBuffer(mask, 
+											group->mBufferUsage);
+			buffer->allocateBuffer(geom_count, index_count, TRUE);
+		}
+		else 
+		{
+			if (LLVertexBuffer::sEnableVBOs && buffer->getUsage() != group->mBufferUsage)
+			{
 				buffer = createVertexBuffer(group->mSpatialPartition->mVertexDataMask, 
-												group->mBufferUsage);
+											group->mBufferUsage);
 				buffer->allocateBuffer(geom_count, index_count, TRUE);
 			}
-			else 
+			else
 			{
-				if (LLVertexBuffer::sEnableVBOs && buffer->getUsage() != group->mBufferUsage)
-				{
-					buffer = createVertexBuffer(group->mSpatialPartition->mVertexDataMask, 
-												group->mBufferUsage);
-					buffer->allocateBuffer(geom_count, index_count, TRUE);
-				}
-				else
-				{
-					buffer->resizeBuffer(geom_count, index_count);
-				}
+				buffer->resizeBuffer(geom_count, index_count);
 			}
+		}
 
-			buffer_map[tex].push_back(buffer);
+		buffer_map[mask][tex].push_back(buffer);
 
-			//add face geometry
+		//add face geometry
 
-			U32 indices_index = 0;
-			U16 index_offset = 0;
+		U32 indices_index = 0;
+		U16 index_offset = 0;
 
-			while (face_iter < i)
+		while (face_iter < i)
+		{
+			facep = *face_iter;
+			facep->mIndicesIndex = indices_index;
+			facep->mGeomIndex = index_offset;
+			facep->mVertexBuffer = buffer;
 			{
-				facep = *face_iter;
-				LLDrawable* drawablep = facep->getDrawable();
-				LLVOVolume* vobj = drawablep->getVOVolume();
-				LLVolume* volume = vobj->getVolume();
-
-				U32 te_idx = facep->getTEOffset();
-				facep->mIndicesIndex = indices_index;
-				facep->mGeomIndex = index_offset;
-				facep->mVertexBuffer = buffer;
+				facep->updateRebuildFlags();
+				if (!LLPipeline::sDelayVBUpdate)
 				{
+					LLDrawable* drawablep = facep->getDrawable();
+					LLVOVolume* vobj = drawablep->getVOVolume();
+					LLVolume* volume = vobj->getVolume();
+
+					U32 te_idx = facep->getTEOffset();
+
 					if (facep->getGeometryVolume(*volume, te_idx, 
 						vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), index_offset))
 					{
@@ -2513,168 +2620,130 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 							facep->getIndicesStart(), facep->getIndicesCount());
 					}
 				}
+			}
 
-				index_offset += facep->getGeomCount();
-				indices_index += facep->mIndicesCount;
-
-				BOOL force_simple = facep->mPixelArea < FORCE_SIMPLE_RENDER_AREA;
-				BOOL fullbright = facep->isState(LLFace::FULLBRIGHT);
-				const LLTextureEntry* te = facep->getTextureEntry();
+			index_offset += facep->getGeomCount();
+			indices_index += facep->mIndicesCount;
 
-				BOOL is_alpha = facep->getPoolType() == LLDrawPool::POOL_ALPHA ? TRUE : FALSE;
+			BOOL force_simple = facep->mPixelArea < FORCE_SIMPLE_RENDER_AREA;
+			BOOL fullbright = facep->isState(LLFace::FULLBRIGHT);
+			const LLTextureEntry* te = facep->getTextureEntry();
 
-				if (!is_alpha 
-					&& gPipeline.canUseWindLightShadersOnObjects()
-					&& LLPipeline::sRenderBump 
-					&& te->getShiny())
+			BOOL is_alpha = facep->getPoolType() == LLDrawPool::POOL_ALPHA ? TRUE : FALSE;
+		
+			if (is_alpha)
+			{
+				// can we safely treat this as an alpha mask?
+				if (LLPipeline::sFastAlpha &&
+				    (te->getColor().mV[VW] == 1.0f) &&
+				    facep->getTexture()->getIsAlphaMask())
 				{
-					if (tex->getPrimaryFormat() == GL_ALPHA)
+					if (te->getFullbright())
 					{
-						registerFace(group, facep, LLRenderPass::PASS_INVISI_SHINY);
-						registerFace(group, facep, LLRenderPass::PASS_INVISIBLE);
-					}
-					else if (fullbright)
-					{						
-						registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT_SHINY);
+						registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK);
 					}
 					else
 					{
-						registerFace(group, facep, LLRenderPass::PASS_SHINY);
+						registerFace(group, facep, LLRenderPass::PASS_ALPHA_MASK);
 					}
 				}
 				else
 				{
-					if (!is_alpha && tex->getPrimaryFormat() == GL_ALPHA)
+					registerFace(group, facep, LLRenderPass::PASS_ALPHA);
+				}
+
+				if (LLPipeline::sRenderDeferred)
+				{
+					registerFace(group, facep, LLRenderPass::PASS_ALPHA_SHADOW);
+				}
+			}
+			else if (gPipeline.canUseVertexShaders()
+				&& LLPipeline::sRenderBump 
+				&& te->getShiny())
+			{
+				if (tex->getPrimaryFormat() == GL_ALPHA)
+				{
+					registerFace(group, facep, LLRenderPass::PASS_INVISI_SHINY);
+					registerFace(group, facep, LLRenderPass::PASS_INVISIBLE);
+				}
+				else if (LLPipeline::sRenderDeferred)
+				{
+					if (te->getBumpmap())
 					{
-						registerFace(group, facep, LLRenderPass::PASS_INVISIBLE);
+						registerFace(group, facep, LLRenderPass::PASS_BUMP);
 					}
-					else if (fullbright)
+					else if (te->getFullbright())
 					{
-						registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT);
+						registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT_SHINY);
 					}
 					else
 					{
 						registerFace(group, facep, LLRenderPass::PASS_SIMPLE);
 					}
-					
-					if (!is_alpha && te->getShiny())
-					{
-						registerFace(group, facep, LLRenderPass::PASS_SHINY);
-					}
 				}
-				
-				if (!is_alpha)
+				else if (fullbright)
+				{						
+					registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT_SHINY);
+				}
+				else
 				{
-					facep->setPoolType(LLDrawPool::POOL_SIMPLE);
-					
-					if (!force_simple && te->getBumpmap())
+					registerFace(group, facep, LLRenderPass::PASS_SHINY);
+				}
+			}
+			else
+			{
+				if (!is_alpha && tex->getPrimaryFormat() == GL_ALPHA)
+				{
+					registerFace(group, facep, LLRenderPass::PASS_INVISIBLE);
+				}
+				else if (fullbright)
+				{
+					registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT);
+				}
+				else
+				{
+					if (LLPipeline::sRenderDeferred && te->getBumpmap())
 					{
 						registerFace(group, facep, LLRenderPass::PASS_BUMP);
 					}
+					else
+					{
+						registerFace(group, facep, LLRenderPass::PASS_SIMPLE);
+					}
 				}
-
-				if (LLPipeline::sRenderGlow && te->getGlow() > 0.f)
+				
+				if (!is_alpha && te->getShiny())
 				{
-					registerFace(group, facep, LLRenderPass::PASS_GLOW);
+					registerFace(group, facep, LLRenderPass::PASS_SHINY);
 				}
-							
-				++face_iter;
-			}
-
-			buffer->setBuffer(0);
-		}
-
-		group->mBufferMap.clear();
-		for (LLSpatialGroup::buffer_map_t::iterator i = buffer_map.begin(); i != buffer_map.end(); ++i)
-		{
-			group->mBufferMap[i->first] = i->second;
-		}
-	}
-
-	//PROCESS ALPHA FACES
-	if (!alpha_faces.empty())
-	{
-		//sort alpha faces by distance
-		std::sort(alpha_faces.begin(), alpha_faces.end(), LLFace::CompareDistanceGreater());
-
-		//store alpha faces in root vertex buffer
-		if (group->mVertexBuffer.isNull() || (LLVertexBuffer::sEnableVBOs && group->mBufferUsage != group->mVertexBuffer->getUsage()))
-		{
-			group->mVertexBuffer = createVertexBuffer(group->mSpatialPartition->mVertexDataMask, 
-													  group->mBufferUsage);
-			group->mVertexBuffer->allocateBuffer(alpha_vertex_count, alpha_index_count, true);
-			stop_glerror();
-		}
-		else
-		{
-			group->mVertexBuffer->resizeBuffer(alpha_vertex_count, alpha_index_count);
-			stop_glerror();
-		}
-
-		//get vertex buffer striders
-		LLVertexBuffer* buffer = group->mVertexBuffer;
-
-		U32 index_offset = 0;
-		U32 indices_index = 0;
-
-		for (std::vector<LLFace*>::iterator i = alpha_faces.begin(); i != alpha_faces.end(); ++i)
-		{
-			LLFace* facep = *i;
-
-			if (facep->mGeomCount + index_offset > 65535)
-			{ //cut off alpha nodes at 64k vertices
-				facep->mVertexBuffer = NULL ;
-				facep->mLastVertexBuffer = NULL ;
-				continue ;
 			}
-
-			LLDrawable* drawablep = facep->getDrawable();
-			LLVOVolume* vobj = drawablep->getVOVolume();
-			LLVolume* volume = vobj->getVolume();
-
-			U32 te_idx = facep->getTEOffset();
-			facep->mIndicesIndex = indices_index;
-			facep->mGeomIndex = index_offset;
-			facep->mVertexBuffer = group->mVertexBuffer;
-			if (facep->getGeometryVolume(*volume, te_idx, 
-										vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), 
-										index_offset))
+			
+			if (!is_alpha && !LLPipeline::sRenderDeferred)
 			{
-				buffer->markDirty(facep->getGeomIndex(), facep->getGeomCount(), 
-					facep->getIndicesStart(), facep->getIndicesCount());
+				facep->setPoolType(LLDrawPool::POOL_SIMPLE);
+				
+				if (!force_simple && te->getBumpmap())
+				{
+					registerFace(group, facep, LLRenderPass::PASS_BUMP);
+				}
 			}
 
-			index_offset += facep->getGeomCount();
-			indices_index += facep->mIndicesCount;
-
-			registerFace(group, facep, LLRenderPass::PASS_ALPHA);
-
-			if (LLPipeline::sRenderGlow && facep->getTextureEntry()->getGlow() > 0.f)
+			if (LLPipeline::sRenderGlow && te->getGlow() > 0.f)
 			{
 				registerFace(group, facep, LLRenderPass::PASS_GLOW);
-			}				
+			}
+						
+			++face_iter;
 		}
 
 		buffer->setBuffer(0);
 	}
-	else
-	{
-		group->mVertexBuffer = NULL;
-	}
 
-	//drawables have been rebuilt, clear rebuild status
-	for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter)
+	group->mBufferMap[mask].clear();
+	for (LLSpatialGroup::buffer_texture_map_t::iterator i = buffer_map[mask].begin(); i != buffer_map[mask].end(); ++i)
 	{
-		LLDrawable* drawablep = *drawable_iter;
-		drawablep->clearState(LLDrawable::REBUILD_ALL);
+		group->mBufferMap[mask][i->first] = i->second;
 	}
-
-	group->mLastUpdateTime = gFrameTimeSeconds;
-	group->mBuilt = 1.f;
-	group->clearState(LLSpatialGroup::GEOM_DIRTY |
-						LLSpatialGroup::ALPHA_DIRTY | LLSpatialGroup::MESH_DIRTY);
-
-	mFaceList.clear();
 }
 
 void LLGeometryManager::addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32 &index_count)
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h
index 50f754b8826ad2ea2e10c3651785c9851a240aad..155775510e17129c859b1b44b217df016ab3a6a5 100644
--- a/indra/newview/llvovolume.h
+++ b/indra/newview/llvovolume.h
@@ -84,8 +84,8 @@ class LLVOVolume : public LLViewerObject
 	{
 		VERTEX_DATA_MASK =	(1 << LLVertexBuffer::TYPE_VERTEX) |
 							(1 << LLVertexBuffer::TYPE_NORMAL) |
-							(1 << LLVertexBuffer::TYPE_TEXCOORD) |
-							(1 << LLVertexBuffer::TYPE_TEXCOORD2) |
+							(1 << LLVertexBuffer::TYPE_TEXCOORD0) |
+							(1 << LLVertexBuffer::TYPE_TEXCOORD1) |
 							(1 << LLVertexBuffer::TYPE_COLOR)
 	};
 
diff --git a/indra/newview/llvowater.h b/indra/newview/llvowater.h
index 8ea47387c8dafe75f8ed9326a75d47421fdc7882..cdda48f6f283fddeac97ff57a2aed78cf3dba371 100644
--- a/indra/newview/llvowater.h
+++ b/indra/newview/llvowater.h
@@ -52,7 +52,7 @@ class LLVOWater : public LLStaticViewerObject
 	{
 		VERTEX_DATA_MASK =	(1 << LLVertexBuffer::TYPE_VERTEX) |
 							(1 << LLVertexBuffer::TYPE_NORMAL) |
-							(1 << LLVertexBuffer::TYPE_TEXCOORD) 
+							(1 << LLVertexBuffer::TYPE_TEXCOORD0) 
 	};
 
 	LLVOWater(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp);
diff --git a/indra/newview/llvowlsky.cpp b/indra/newview/llvowlsky.cpp
index 635989e3af58db8f2dc2217c280e13d183ffbfc6..abd25e6598aefc84819c1ccdc66461713da27480 100644
--- a/indra/newview/llvowlsky.cpp
+++ b/indra/newview/llvowlsky.cpp
@@ -320,7 +320,7 @@ BOOL LLVOWLSky::updateGeometry(LLDrawable * drawable)
 		mFanVerts->allocateBuffer(getFanNumVerts(), getFanNumIndices(), TRUE);
 
 		BOOL success = mFanVerts->getVertexStrider(vertices)
-			&& mFanVerts->getTexCoordStrider(texCoords)
+			&& mFanVerts->getTexCoord0Strider(texCoords)
 			&& mFanVerts->getIndexStrider(indices);
 
 		if(!success) 
@@ -380,7 +380,7 @@ BOOL LLVOWLSky::updateGeometry(LLDrawable * drawable)
 
 			// lock the buffer
 			BOOL success = segment->getVertexStrider(vertices)
-				&& segment->getTexCoordStrider(texCoords)
+				&& segment->getTexCoord0Strider(texCoords)
 				&& segment->getIndexStrider(indices);
 
 			if(!success) 
diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp
index 4239996017f002e09fea06248a899ae92d1fc293..f11ef97b55bd111cf82df04a8dd1917314f9d23d 100644
--- a/indra/newview/llworld.cpp
+++ b/indra/newview/llworld.cpp
@@ -111,7 +111,7 @@ LLWorld::LLWorld() :
 	
 	mDefaultWaterTexturep = new LLViewerImage(raw, FALSE);
 	gGL.getTexUnit(0)->bind(mDefaultWaterTexturep.get());
-	mDefaultWaterTexturep->setClamp(TRUE, TRUE);
+	mDefaultWaterTexturep->setAddressMode(LLTexUnit::TAM_CLAMP);
 
 }
 
@@ -872,7 +872,7 @@ void LLWorld::updateWaterObjects()
 													 y + rwidth/2,
 													 256.f+DEFAULT_WATER_HEIGHT));
 				waterp->setScale(LLVector3((F32)rwidth, (F32)rwidth, 512.f));
-				gPipeline.addObject(waterp);
+				gPipeline.createObject(waterp);
 				mHoleWaterObjects.push_back(waterp);
 			}
 		}
@@ -923,7 +923,7 @@ void LLWorld::updateWaterObjects()
 			waterp = mEdgeWaterObjects[dir];
 			waterp->setUseTexture(FALSE);
 			waterp->setIsEdgePatch(TRUE);
-			gPipeline.addObject(waterp);
+			gPipeline.createObject(waterp);
 		}
 
 		waterp->setRegion(gAgent.getRegion());
diff --git a/indra/newview/llworldmap.cpp b/indra/newview/llworldmap.cpp
index 4d46ff19cc889d0419a8d0617f6d166e0217f63b..c9a3bd2112a23c13537858a3abf12301b85e66a1 100644
--- a/indra/newview/llworldmap.cpp
+++ b/indra/newview/llworldmap.cpp
@@ -506,9 +506,9 @@ void LLWorldMap::processMapLayerReply(LLMessageSystem* msg, void**)
 		new_layer.LayerDefined = TRUE;
 		msg->getUUIDFast(_PREHASH_LayerData, _PREHASH_ImageID, new_layer.LayerImageID, block);
 		new_layer.LayerImage = gImageList.getImage(new_layer.LayerImageID, MIPMAP_TRUE, FALSE);
-		
+
 		gGL.getTexUnit(0)->bind(new_layer.LayerImage.get());
-		new_layer.LayerImage->setClamp(TRUE, TRUE);
+		new_layer.LayerImage->setAddressMode(LLTexUnit::TAM_CLAMP);
 		
 		U32 left, right, top, bottom;
 		msg->getU32Fast(_PREHASH_LayerData, _PREHASH_Left, left, block);
@@ -618,10 +618,11 @@ void LLWorldMap::processMapBlockReply(LLMessageSystem* msg, void**)
 			siminfo->mRegionFlags = region_flags;
 			siminfo->mWaterHeight = (F32) water_height;
 			siminfo->mMapImageID[agent_flags] = image_id;
+
 #ifdef IMMEDIATE_IMAGE_LOAD
 			siminfo->mCurrentImage = gImageList.getImage(siminfo->mMapImageID[LLWorldMap::getInstance()->mCurrentMap], MIPMAP_TRUE, FALSE);
 			gGL.getTexUnit(0)->bind(siminfo->mCurrentImage.get());
-			siminfo->mCurrentImage->setClamp(TRUE, TRUE);
+			siminfo->mCurrentImage->setAddressMode(LLTexUnit::TAM_CLAMP);
 #endif
 			
 			if (siminfo->mMapImageID[2].notNull())
diff --git a/indra/newview/llworldmapview.cpp b/indra/newview/llworldmapview.cpp
index 1cf8755e6266a45dfcb07e0fa93b6829edc2bf62..db36fa0ffeeda50f531c68de724992b9758953d3 100644
--- a/indra/newview/llworldmapview.cpp
+++ b/indra/newview/llworldmapview.cpp
@@ -511,7 +511,7 @@ void LLWorldMapView::draw()
 			{
 				textures_requested_this_tick++;
 				info->mCurrentImage = gImageList.getImage(info->mMapImageID[LLWorldMap::getInstance()->mCurrentMap], MIPMAP_TRUE, FALSE);
-				info->mCurrentImage->setClamp(TRUE, TRUE);
+                info->mCurrentImage->setAddressMode(LLTexUnit::TAM_CLAMP);
 				simimage = info->mCurrentImage;
 				gGL.getTexUnit(0)->bind(simimage);
 			}
@@ -524,7 +524,7 @@ void LLWorldMapView::draw()
 			{
 				textures_requested_this_tick++;
 				info->mOverlayImage = gImageList.getImage(info->mMapImageID[2], MIPMAP_TRUE, FALSE);
-				info->mOverlayImage->setClamp(TRUE, TRUE);
+				info->mOverlayImage->setAddressMode(LLTexUnit::TAM_CLAMP);
 				overlayimage = info->mOverlayImage;
 				gGL.getTexUnit(0)->bind(overlayimage);
 			}
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 62e337b2d1c1f7732793b3f8d612f5c66cd6dd87..3a5e41e3cafc5843c0ade6f90b51de131161cd27 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -139,21 +139,22 @@ LLPipeline gPipeline;
 const LLMatrix4* gGLLastMatrix = NULL;
 
 //----------------------------------------
-
 std::string gPoolNames[] = 
 {
 	// Correspond to LLDrawpool enum render type
 	"NONE",
 	"POOL_SIMPLE",
-	"POOL_TERRAIN",	
+	"POOL_TERRAIN",
+	"POOL_BUMP",
 	"POOL_TREE",
 	"POOL_SKY",
 	"POOL_WL_SKY",
 	"POOL_GROUND",
-	"POOL_BUMP",
 	"POOL_INVISIBLE",
 	"POOL_AVATAR",
 	"POOL_WATER",
+	"POOL_GRASS",
+	"POOL_FULLBRIGHT",
 	"POOL_GLOW",
 	"POOL_ALPHA",
 };
@@ -232,10 +233,12 @@ BOOL	LLPipeline::sRenderSoundBeacons = FALSE;
 BOOL	LLPipeline::sRenderBeacons = FALSE;
 BOOL	LLPipeline::sRenderHighlight = TRUE;
 S32		LLPipeline::sUseOcclusion = 0;
+BOOL	LLPipeline::sDelayVBUpdate = TRUE;
 BOOL	LLPipeline::sFastAlpha = TRUE;
 BOOL	LLPipeline::sDisableShaders = FALSE;
 BOOL	LLPipeline::sRenderBump = TRUE;
 BOOL	LLPipeline::sUseFarClip = TRUE;
+BOOL	LLPipeline::sShadowRender = FALSE;
 BOOL	LLPipeline::sSkipUpdate = FALSE;
 BOOL	LLPipeline::sWaterReflections = FALSE;
 BOOL	LLPipeline::sRenderGlow = FALSE;
@@ -246,6 +249,8 @@ BOOL	LLPipeline::sTextureBindTest = FALSE;
 BOOL	LLPipeline::sRenderFrameTest = FALSE;
 BOOL	LLPipeline::sRenderAttachedLights = TRUE;
 BOOL	LLPipeline::sRenderAttachedParticles = TRUE;
+BOOL	LLPipeline::sRenderDeferred = FALSE;
+S32		LLPipeline::sVisibleLightCount = 0;
 
 static LLCullResult* sCull = NULL;
 
@@ -261,6 +266,13 @@ static const U32 gl_cube_face[] =
 
 void validate_framebuffer_object();
 
+void addDeferredAttachments(LLRenderTarget& target)
+{
+	target.addColorAttachment(GL_RGBA16F_ARB); //specular
+	target.addColorAttachment(GL_RGBA16F_ARB); //normal+z	
+	target.addColorAttachment(GL_RGBA16F_ARB); //position
+}
+
 LLPipeline::LLPipeline() :
 	mBackfaceCull(FALSE),
 	mBatchCount(0),
@@ -276,9 +288,6 @@ LLPipeline::LLPipeline() :
 	mGeometryChanges(0),
 	mNumVisibleFaces(0),
 
-	mCubeBuffer(NULL),
-	mCubeFrameBuffer(0),
-	mCubeDepth(0),
 	mInitialized(FALSE),
 	mVertexShadersEnabled(FALSE),
 	mVertexShadersLoaded(0),
@@ -293,6 +302,7 @@ LLPipeline::LLPipeline() :
 	mWaterPool(NULL),
 	mGroundPool(NULL),
 	mSimplePool(NULL),
+	mFullbrightPool(NULL),
 	mInvisiblePool(NULL),
 	mGlowPool(NULL),
 	mBumpPool(NULL),
@@ -301,8 +311,7 @@ LLPipeline::LLPipeline() :
 	mLightMovingMask(0),
 	mLightingDetail(0)
 {
-	mBlurCubeBuffer[0] = mBlurCubeBuffer[1] = mBlurCubeBuffer[2] = 0;
-	mBlurCubeTexture[0] = mBlurCubeTexture[1] = mBlurCubeTexture[2] = 0;
+	mNoiseMap = 0;
 }
 
 void LLPipeline::init()
@@ -321,6 +330,8 @@ void LLPipeline::init()
 	//create render pass pools
 	getPool(LLDrawPool::POOL_ALPHA);
 	getPool(LLDrawPool::POOL_SIMPLE);
+	getPool(LLDrawPool::POOL_GRASS);
+	getPool(LLDrawPool::POOL_FULLBRIGHT);
 	getPool(LLDrawPool::POOL_INVISIBLE);
 	getPool(LLDrawPool::POOL_BUMP);
 	getPool(LLDrawPool::POOL_GLOW);
@@ -405,6 +416,8 @@ void LLPipeline::cleanup()
 	mGroundPool = NULL;
 	delete mSimplePool;
 	mSimplePool = NULL;
+	delete mFullbrightPool;
+	mFullbrightPool = NULL;
 	delete mInvisiblePool;
 	mInvisiblePool = NULL;
 	delete mGlowPool;
@@ -456,52 +469,103 @@ void LLPipeline::resizeScreenTexture()
 		GLuint resY = gViewerWindow->getWindowDisplayHeight();
 	
 		U32 res_mod = gSavedSettings.getU32("RenderResolutionDivisor");
-		if (res_mod > 1)
+		if (res_mod > 1 && res_mod < resX && res_mod < resY)
 		{
 			resX /= res_mod;
 			resY /= res_mod;
 		}
-	
-		mScreen.release();
-		mScreen.allocate(resX, resY, GL_RGBA, TRUE, LLTexUnit::TT_RECT_TEXTURE);		
+
+		allocateScreenBuffer(resX,resY);
 
 		llinfos << "RESIZED SCREEN TEXTURE: " << resX << "x" << resY << llendl;
 	}
 }
 
-
-void LLPipeline::releaseGLBuffers()
+void LLPipeline::allocateScreenBuffer(U32 resX, U32 resY)
 {
-	assertInitialized();
-	
-	if (mCubeBuffer)
+	U32 samples = gSavedSettings.getU32("RenderFSAASamples");
+	if (LLPipeline::sRenderDeferred)
 	{
-		mCubeBuffer = NULL;
+		//allocate deferred rendering color buffers
+		mDeferredScreen.allocate(resX, resY, GL_RGBA16F_ARB, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE);
+		addDeferredAttachments(mDeferredScreen);
+		mScreen.allocate(resX, resY, GL_RGBA16F_ARB, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE);		
+		
+		for (U32 i = 0; i < 2; i++)
+		{
+			mDeferredLight[i].allocate(resX, resY, GL_RGB, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE);
+		}
 	}
-
-	if (mCubeFrameBuffer)
+	else
 	{
-		glDeleteFramebuffersEXT(1, &mCubeFrameBuffer);
-		glDeleteRenderbuffersEXT(1, &mCubeDepth);
-		mCubeDepth = mCubeFrameBuffer = 0;
+		mScreen.allocate(resX, resY, GL_RGBA, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE);		
 	}
+	
 
-	if (mBlurCubeBuffer[0])
+	if (gGLManager.mHasFramebufferMultisample && samples > 1)
 	{
-		glDeleteFramebuffersEXT(3, mBlurCubeBuffer);
-		mBlurCubeBuffer[0] = mBlurCubeBuffer[1] = mBlurCubeBuffer[2] = 0;
+		if (LLPipeline::sRenderDeferred)
+		{
+			mSampleBuffer.allocate(resX,resY,GL_RGBA16F_ARB,TRUE,TRUE,LLTexUnit::TT_RECT_TEXTURE,FALSE,samples);
+			addDeferredAttachments(mSampleBuffer);
+			mDeferredScreen.setSampleBuffer(&mSampleBuffer);
+		}
+		else
+		{
+			mSampleBuffer.allocate(resX,resY,GL_RGBA,TRUE,TRUE,LLTexUnit::TT_RECT_TEXTURE,FALSE,samples);
+		}
+
+		mScreen.setSampleBuffer(&mSampleBuffer);
+		stop_glerror();
+	}
+	else if (LLPipeline::sRenderDeferred)
+	{ //share depth buffer between deferred targets
+		mDeferredScreen.shareDepthBuffer(mScreen);
+		for (U32 i = 0; i < 2; i++)
+		{
+			mDeferredScreen.shareDepthBuffer(mDeferredLight[i]);
+		}
 	}
 
-	if (mBlurCubeTexture[0])
+	gGL.getTexUnit(0)->disable();
+
+	stop_glerror();
+
+}
+
+//static
+void LLPipeline::updateRenderDeferred()
+{
+	BOOL deferred = (gSavedSettings.getBOOL("RenderDeferred") && 
+		LLRenderTarget::sUseFBO &&
+		gSavedSettings.getBOOL("VertexShaderEnable") && 
+		gSavedSettings.getBOOL("RenderAvatarVP") &&
+		gSavedSettings.getBOOL("WindLightUseAtmosShaders")) ? TRUE : FALSE;
+	
+	sRenderDeferred = deferred;			
+}
+
+void LLPipeline::releaseGLBuffers()
+{
+	assertInitialized();
+	
+	if (mNoiseMap)
 	{
-		glDeleteTextures(3, mBlurCubeTexture);
-		mBlurCubeTexture[0] = mBlurCubeTexture[1] = mBlurCubeTexture[2] = 0;
+		LLImageGL::deleteTextures(1, &mNoiseMap);
+		mNoiseMap = 0;
 	}
 
 	mWaterRef.release();
 	mWaterDis.release();
 	mScreen.release();
-
+	mSampleBuffer.releaseSampleBuffer();
+	mDeferredScreen.release();
+	
+	
+	for (U32 i = 0; i < 4; i++)
+	{
+		mSunShadow[i].release();
+	}
 	for (U32 i = 0; i < 3; i++)
 	{
 		mGlow[i].release();
@@ -514,72 +578,17 @@ void LLPipeline::createGLBuffers()
 {
 	assertInitialized();
 
+	updateRenderDeferred();
+
 	if (LLPipeline::sWaterReflections)
 	{ //water reflection texture
 		U32 res = (U32) gSavedSettings.getS32("RenderWaterRefResolution");
 			
-		mWaterRef.allocate(res,res,GL_RGBA,TRUE);
-		mWaterDis.allocate(res,res,GL_RGBA,TRUE);
-
-#if 0 //cube map buffers (keep for future work)
-		{
-			//reflection map generation buffers
-			if (mCubeFrameBuffer == 0)
-			{
-				glGenFramebuffersEXT(1, &mCubeFrameBuffer);
-				glGenRenderbuffersEXT(1, &mCubeDepth);
-
-				U32 res = REFLECTION_MAP_RES;
-
-				glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, mCubeDepth);
-						
-				glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT,GL_DEPTH_COMPONENT,res,res);
-							
-				glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
-			}
-
-			if (mCubeBuffer.isNull())
-			{
-				res = 128;
-				mCubeBuffer = new LLCubeMap();
-				mCubeBuffer->initGL();
-				mCubeBuffer->setReflection();
-					
-				for (U32 i = 0; i < 6; i++)
-				{
-					glTexImage2D(gl_cube_face[i], 0, GL_RGBA, res, res, 0, GL_RGBA, GL_FLOAT, NULL); 
-				}
-			}
-
-			if (mBlurCubeBuffer[0] == 0)
-			{
-				glGenFramebuffersEXT(3, mBlurCubeBuffer);
-			}
-
-			if (mBlurCubeTexture[0] == 0)
-			{
-				glGenTextures(3, mBlurCubeTexture);
-			}
-
-			res = (U32) gSavedSettings.getS32("RenderReflectionRes");
-
-			for (U32 j = 0; j < 3; j++)
-			{
-				gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_CUBE_MAP, mBlurCubeTexture[j]);
-				glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-				glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-				glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-				glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-					
-				for (U32 i = 0; i < 6; i++)
-				{
-					glTexImage2D(gl_cube_face[i], 0, GL_RGBA, res, res, 0, GL_RGBA, GL_FLOAT, NULL); 
-				}
-			}
-		}
-#endif
+		mWaterRef.allocate(res,res,GL_RGBA,TRUE,FALSE);
+		mWaterDis.allocate(res,res,GL_RGBA,TRUE,FALSE);
 	}
 
+
 	stop_glerror();
 
 	if (LLPipeline::sRenderGlow)
@@ -589,14 +598,41 @@ void LLPipeline::createGLBuffers()
 
 		for (U32 i = 0; i < 3; i++)
 		{
-			mGlow[i].allocate(512,glow_res,GL_RGBA,FALSE);
+			mGlow[i].allocate(512,glow_res,GL_RGBA,FALSE,FALSE);
 		}
-		
+	}
 
-		GLuint resX = gViewerWindow->getWindowDisplayWidth();
-		GLuint resY = gViewerWindow->getWindowDisplayHeight();
+	GLuint resX = gViewerWindow->getWindowDisplayWidth();
+	GLuint resY = gViewerWindow->getWindowDisplayHeight();
 	
-		mScreen.allocate(resX, resY, GL_RGBA, TRUE, LLTexUnit::TT_RECT_TEXTURE);
+	allocateScreenBuffer(resX,resY);
+
+	if (sRenderDeferred)
+	{
+		mSunShadow[0].allocate(1024,1024, 0, TRUE, FALSE);
+		mSunShadow[1].allocate(1024,1024, 0, TRUE, FALSE);
+		mSunShadow[2].allocate(1024,1024, 0, TRUE, FALSE);
+		mSunShadow[3].allocate(1024,1024, 0, TRUE, FALSE);
+		
+		if (!mNoiseMap)
+		{
+			const U32 noiseRes = 128;
+			LLVector3 noise[noiseRes*noiseRes];
+
+			F32 scaler = gSavedSettings.getF32("RenderDeferredNoise")/100.f;
+			for (U32 i = 0; i < noiseRes*noiseRes; ++i)
+			{
+				noise[i] = LLVector3(ll_frand()-0.5f, ll_frand()-0.5f, 0.f);
+				noise[i].normVec();
+				noise[i].mV[2] = ll_frand()*scaler+1.f-scaler/2.f;
+			}
+
+			LLImageGL::generateTextures(1, &mNoiseMap);
+			
+			gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mNoiseMap);
+			LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_RGB16F_ARB, noiseRes, noiseRes, GL_RGB, GL_FLOAT, noise);
+			gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+		}
 	}
 }
 
@@ -627,7 +663,8 @@ void LLPipeline::restoreGL()
 
 BOOL LLPipeline::canUseVertexShaders()
 {
-	if (!gGLManager.mHasVertexShader ||
+	if (sDisableShaders ||
+		!gGLManager.mHasVertexShader ||
 		!gGLManager.mHasFragmentShader ||
 		!LLFeatureManager::getInstance()->isFeatureAvailable("VertexShaderEnable") ||
 		(assertInitialized() && mVertexShadersLoaded != 1) )
@@ -785,6 +822,14 @@ LLDrawPool *LLPipeline::findPool(const U32 type, LLViewerImage *tex0)
 		poolp = mSimplePool;
 		break;
 
+	case LLDrawPool::POOL_GRASS:
+		poolp = mGrassPool;
+		break;
+
+	case LLDrawPool::POOL_FULLBRIGHT:
+		poolp = mFullbrightPool;
+		break;
+
 	case LLDrawPool::POOL_INVISIBLE:
 		poolp = mInvisiblePool;
 		break;
@@ -964,19 +1009,61 @@ void LLPipeline::unlinkDrawable(LLDrawable *drawable)
 
 U32 LLPipeline::addObject(LLViewerObject *vobj)
 {
-	LLMemType mt(LLMemType::MTYPE_DRAWABLE);
 	if (gNoRender)
 	{
 		return 0;
 	}
 
+	if (gSavedSettings.getBOOL("RenderDelayCreation"))
+	{
+		mCreateQ.push_back(vobj);
+	}
+	else
+	{
+		createObject(vobj);
+	}
+
+	return 1;
+}
+
+void LLPipeline::createObjects(F32 max_dtime)
+{
+	LLFastTimer ftm(LLFastTimer::FTM_GEO_UPDATE);
+	LLMemType mt(LLMemType::MTYPE_DRAWABLE);
+
+	LLTimer update_timer;
+
+	while (!mCreateQ.empty() && update_timer.getElapsedTimeF32() < max_dtime)
+	{
+		LLViewerObject* vobj = mCreateQ.front();
+		if (!vobj->isDead())
+		{
+			createObject(vobj);
+		}
+		mCreateQ.pop_front();
+	}
+	
+	//for (LLViewerObject::vobj_list_t::iterator iter = mCreateQ.begin(); iter != mCreateQ.end(); ++iter)
+	//{
+	//	createObject(*iter);
+	//}
+
+	//mCreateQ.clear();
+}
+
+void LLPipeline::createObject(LLViewerObject* vobj)
+{
 	LLDrawable* drawablep = vobj->mDrawable;
 
 	if (!drawablep)
 	{
 		drawablep = vobj->createDrawable(this);
 	}
-	
+	else
+	{
+		llerrs << "Redundant drawable creation!" << llendl;
+	}
+		
 	llassert(drawablep);
 
 	if (vobj->getParent())
@@ -990,7 +1077,14 @@ U32 LLPipeline::addObject(LLViewerObject *vobj)
 
 	markRebuild(drawablep, LLDrawable::REBUILD_ALL, TRUE);
 
-	return 1;
+	if (drawablep->getVOVolume() && gSavedSettings.getBOOL("RenderAnimateRes"))
+	{
+		// fun animated res
+		drawablep->updateXform(TRUE);
+		drawablep->clearState(LLDrawable::MOVE_UNDAMPED);
+		drawablep->setScale(LLVector3(0,0,0));
+		drawablep->makeActive();
+	}
 }
 
 
@@ -1195,6 +1289,65 @@ void LLPipeline::grabReferences(LLCullResult& result)
 	sCull = &result;
 }
 
+BOOL LLPipeline::visibleObjectsInFrustum(LLCamera& camera)
+{
+	for (LLWorld::region_list_t::iterator iter = LLWorld::getInstance()->getRegionList().begin(); 
+			iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+	{
+		LLViewerRegion* region = *iter;
+
+		for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
+		{
+			LLSpatialPartition* part = region->getSpatialPartition(i);
+			if (part)
+			{
+				if (hasRenderType(part->mDrawableType))
+				{
+					if (part->visibleObjectsInFrustum(camera))
+					{
+						return TRUE;
+					}
+				}
+			}
+		}
+	}
+
+	return FALSE;
+}
+
+BOOL LLPipeline::getVisibleExtents(LLCamera& camera, LLVector3& min, LLVector3& max)
+{
+	min = LLVector3(F32_MAX, F32_MAX, F32_MAX);
+	max = LLVector3(-F32_MAX, -F32_MAX, -F32_MAX);
+
+
+	BOOL res = TRUE;
+
+	for (LLWorld::region_list_t::iterator iter = LLWorld::getInstance()->getRegionList().begin(); 
+			iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+	{
+		LLViewerRegion* region = *iter;
+
+		for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
+		{
+			LLSpatialPartition* part = region->getSpatialPartition(i);
+			if (part)
+			{
+				if (hasRenderType(part->mDrawableType))
+				{
+					if (!part->getVisibleExtents(camera, min, max))
+					{
+						res = FALSE;
+					}
+				}
+			}
+		}
+	}
+
+	return res;
+}
+
+
 void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_clip)
 {
 	LLFastTimer t(LLFastTimer::FTM_CULL);
@@ -1207,6 +1360,7 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl
 	BOOL to_texture =	LLPipeline::sUseOcclusion > 1 &&
 						!hasRenderType(LLPipeline::RENDER_TYPE_HUD) && 
 						!sReflectionRender &&
+						!sShadowRender &&
 						gPipeline.canUseVertexShaders() &&
 						sRenderGlow;
 
@@ -1217,6 +1371,7 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl
 
 	glPushMatrix();
 	gGLLastMatrix = NULL;
+	//glLoadMatrixd(gGLModelView);
 	glLoadMatrixd(gGLLastModelView);
 
 	LLVertexBuffer::unbind();
@@ -1224,7 +1379,11 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl
 	LLGLDisable test(GL_ALPHA_TEST);
 	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 
-	gGL.setColorMask(false, false);
+	if (sUseOcclusion > 1)
+	{
+		gGL.setColorMask(false, false);
+	}
+
 	LLGLDepthTest depth(GL_TRUE, GL_FALSE);
 
 	for (LLWorld::region_list_t::iterator iter = LLWorld::getInstance()->getRegionList().begin(); 
@@ -1282,13 +1441,17 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl
 		sCull->pushDrawable(gSky.mVOGroundp->mDrawable);
 	}
 	
-	gGL.setColorMask(true, false);
+	
 	glPopMatrix();
 
+	if (sUseOcclusion > 1)
+	{
+		gGL.setColorMask(true, false);
+	}
+
 	if (to_texture)
 	{
 		mScreen.flush();
-		LLRenderTarget::unbindTarget();
 	}
 	else if (LLPipeline::sUseOcclusion > 1)
 	{
@@ -1357,6 +1520,7 @@ void LLPipeline::markOccluder(LLSpatialGroup* group)
 void LLPipeline::doOcclusion(LLCamera& camera)
 {
 	LLVertexBuffer::unbind();
+
 	if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION))
 	{
 		gGL.setColorMask(true, false, false, false);
@@ -1525,7 +1689,7 @@ void LLPipeline::markMoved(LLDrawable *drawablep, BOOL damped_motion)
 
 	if (!drawablep)
 	{
-		llerrs << "Sending null drawable to moved list!" << llendl;
+		//llerrs << "Sending null drawable to moved list!" << llendl;
 		return;
 	}
 	
@@ -1595,8 +1759,8 @@ void LLPipeline::shiftObjects(const LLVector3 &offset)
 	assertInitialized();
 
 	glClear(GL_DEPTH_BUFFER_BIT);
-	gDepthDirty = FALSE;
-
+	gDepthDirty = TRUE;
+		
 	for (LLDrawable::drawable_vector_t::iterator iter = mShiftList.begin();
 		 iter != mShiftList.end(); iter++)
 	{
@@ -1772,6 +1936,7 @@ void LLPipeline::stateSort(LLSpatialGroup* group, LLCamera& camera)
 			stateSort(drawablep, camera);
 		}
 	}
+
 }
 
 void LLPipeline::stateSort(LLSpatialBridge* bridge, LLCamera& camera)
@@ -2045,6 +2210,22 @@ void LLPipeline::postSort(LLCamera& camera)
 	}
 	LLSpatialGroup::sNoDelete = TRUE;
 
+
+	const S32 bin_count = 1024*8;
+		
+	static LLCullResult::drawinfo_list_t alpha_bins[bin_count];
+	static U32 bin_size[bin_count];
+
+	//clear one bin per frame to avoid memory bloat
+	static S32 clear_idx = 0;
+	clear_idx = (1+clear_idx)%bin_count;
+	alpha_bins[clear_idx].clear();
+
+	for (U32 j = 0; j < bin_count; j++)
+	{
+		bin_size[j] = 0;
+	}
+
 	//build render map
 	for (LLCullResult::sg_list_t::iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i)
 	{
@@ -2064,7 +2245,7 @@ void LLPipeline::postSort(LLCamera& camera)
 				sCull->pushDrawInfo(j->first, *k);
 			}
 		}
-		
+
 		LLSpatialGroup::draw_map_t::iterator alpha = group->mDrawMap.find(LLRenderPass::PASS_ALPHA);
 		
 		if (alpha != group->mDrawMap.end())
@@ -2090,28 +2271,26 @@ void LLPipeline::postSort(LLCamera& camera)
 		}
 	}
 		
+	if (!sShadowRender)
 	{
 		//sort by texture or bump map
 		for (U32 i = 0; i < LLRenderPass::NUM_RENDER_TYPES; ++i)
 		{
-			//if (!mRenderMap[i].empty())
+			if (i == LLRenderPass::PASS_BUMP)
 			{
-				if (i == LLRenderPass::PASS_BUMP)
-				{
-					std::sort(sCull->beginRenderMap(i), sCull->endRenderMap(i), LLDrawInfo::CompareBump());
-				}
-				else 
-				{
-					std::sort(sCull->beginRenderMap(i), sCull->endRenderMap(i), LLDrawInfo::CompareTexturePtrMatrix());
-				}
+				std::sort(sCull->beginRenderMap(i), sCull->endRenderMap(i), LLDrawInfo::CompareBump());
 			}
+			else 
+			{
+				std::sort(sCull->beginRenderMap(i), sCull->endRenderMap(i), LLDrawInfo::CompareTexturePtrMatrix());
+			}	
 		}
 
 		std::sort(sCull->beginAlphaGroups(), sCull->endAlphaGroups(), LLSpatialGroup::CompareDepthGreater());
 	}
-
+	
 	// only render if the flag is set. The flag is only set if we are in edit mode or the toggle is set in the menus
-	if (gSavedSettings.getBOOL("BeaconAlwaysOn"))
+	if (gSavedSettings.getBOOL("BeaconAlwaysOn") && !sShadowRender)
 	{
 		if (sRenderScriptedTouchBeacons)
 		{
@@ -2164,23 +2343,26 @@ void LLPipeline::postSort(LLCamera& camera)
 		LLFloaterTelehub::addBeacons();
 	}
 
-	mSelectedFaces.clear();
-	
-	// Draw face highlights for selected faces.
-	if (LLSelectMgr::getInstance()->getTEMode())
+	if (!sShadowRender)
 	{
-		struct f : public LLSelectedTEFunctor
+		mSelectedFaces.clear();
+		
+		// Draw face highlights for selected faces.
+		if (LLSelectMgr::getInstance()->getTEMode())
 		{
-			virtual bool apply(LLViewerObject* object, S32 te)
+			struct f : public LLSelectedTEFunctor
 			{
-				if (object->mDrawable)
+				virtual bool apply(LLViewerObject* object, S32 te)
 				{
-					gPipeline.mSelectedFaces.push_back(object->mDrawable->getFace(te));
+					if (object->mDrawable)
+					{
+						gPipeline.mSelectedFaces.push_back(object->mDrawable->getFace(te));
+					}
+					return true;
 				}
-				return true;
-			}
-		} func;
-		LLSelectMgr::getInstance()->getSelection()->applyToTEs(&func);
+			} func;
+			LLSelectMgr::getInstance()->getSelection()->applyToTEs(&func);
+		}
 	}
 
 	LLSpatialGroup::sNoDelete = FALSE;
@@ -2328,8 +2510,6 @@ void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate)
 	stop_glerror();
 	gFrameStats.start(LLFrameStats::RENDER_SYNC);
 
-	glEnableClientState(GL_VERTEX_ARRAY);
-
 	LLVertexBuffer::unbind();
 
 	// Do verification of GL state
@@ -2379,7 +2559,7 @@ void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate)
 	}
 
 	gGL.getTexUnit(0)->bind(LLViewerImage::sDefaultImagep);
-	LLViewerImage::sDefaultImagep->setClamp(FALSE, FALSE);
+	LLViewerImage::sDefaultImagep->setAddressMode(LLTexUnit::TAM_WRAP);
 	
 	//////////////////////////////////////////////
 	//
@@ -2387,37 +2567,39 @@ void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate)
 	//
 	//	
 	stop_glerror();
-	BOOL occlude = sUseOcclusion > 1;
 	
-	U32 cur_type = 0;
-
 	LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderDrawPools");
 	
-	if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_PICKING))
-	{
 		LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderForSelect");
-		gObjectList.renderObjectsForSelect(camera, gViewerWindow->getVirtualWindowRect());
+		LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderDeferred");
+	for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
+	{
+		LLDrawPool *poolp = *iter;
+		if (hasRenderType(poolp->getType()))
+		{
+			poolp->prerender();
+		}
 	}
-	else if (gSavedSettings.getBOOL("RenderDeferred"))
+
+	if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_PICKING))
 	{
-		LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderDeferred");
-		renderGeomDeferred();
+		gObjectList.renderObjectsForSelect(camera, gViewerWindow->getVirtualWindowRect());
 	}
 	else
 	{
-		for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
+		LLFastTimer t(LLFastTimer::FTM_POOLS);
+		
+		// HACK: don't calculate local lights if we're rendering the HUD!
+		//    Removing this check will cause bad flickering when there are 
+		//    HUD elements being rendered AND the user is in flycam mode  -nyx
+		if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
 		{
-			LLDrawPool *poolp = *iter;
-			if (hasRenderType(poolp->getType()))
-			{
-				poolp->prerender();
-			}
+			calcNearbyLights(camera);
+			setupHWLights(NULL);
 		}
 
-
-		LLFastTimer t(LLFastTimer::FTM_POOLS);
-		calcNearbyLights(camera);
-		setupHWLights(NULL);
+		BOOL occlude = sUseOcclusion > 1;
+		U32 cur_type = 0;
 
 		pool_set_t::iterator iter1 = mPools.begin();
 		while ( iter1 != mPools.end() )
@@ -2426,7 +2608,7 @@ void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate)
 			
 			cur_type = poolp->getType();
 
-			if (occlude && cur_type > LLDrawPool::POOL_AVATAR)
+			if (occlude && cur_type >= LLDrawPool::POOL_GRASS)
 			{
 				occlude = FALSE;
 				gGLLastMatrix = NULL;
@@ -2444,6 +2626,7 @@ void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate)
 			
 				for( S32 i = 0; i < poolp->getNumPasses(); i++ )
 				{
+					LLVertexBuffer::unbind();
 					poolp->beginRenderPass(i);
 					for (iter2 = iter1; iter2 != mPools.end(); iter2++)
 					{
@@ -2487,25 +2670,29 @@ void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate)
 			iter1 = iter2;
 			stop_glerror();
 		}
-	}
 	
 	LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderDrawPoolsEnd");
 
+	LLVertexBuffer::unbind();
+		
+		gGLLastMatrix = NULL;
+		glLoadMatrixd(gGLModelView);
+
+		if (occlude)
+		{
+			occlude = FALSE;
+			gGLLastMatrix = NULL;
+			glLoadMatrixd(gGLModelView);
+			doOcclusion(camera);
+		}
+	}
+
 	LLVertexBuffer::unbind();
 	LLGLState::checkStates();
 	LLGLState::checkTextureChannels();
 	LLGLState::checkClientArrays();
 
-	gGLLastMatrix = NULL;
-	glLoadMatrixd(gGLModelView);
-
-	if (occlude)
-	{
-		occlude = FALSE;
-		gGLLastMatrix = NULL;
-		glLoadMatrixd(gGLModelView);
-		doOcclusion(camera);
-	}
+	
 
 	stop_glerror();
 		
@@ -2530,7 +2717,7 @@ void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate)
 
 	LLVertexBuffer::unbind();
 	
-	if (!LLPipeline::sReflectionRender && gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
+	if (!LLPipeline::sReflectionRender && !LLPipeline::sRenderDeferred && gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
 	{
 		// Render debugging beacons.
 		gObjectList.renderObjectBeacons();
@@ -2557,13 +2744,283 @@ void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate)
 	LLGLState::checkClientArrays();
 }
 
-void LLPipeline::renderGeomDeferred()
+void LLPipeline::renderGeomDeferred(LLCamera& camera)
+{
+	LLFastTimer t(LLFastTimer::FTM_RENDER_GEOMETRY);
+
+	LLFastTimer t2(LLFastTimer::FTM_POOLS);
+
+	LLGLEnable cull(GL_CULL_FACE);
+
+	LLGLEnable stencil(GL_STENCIL_TEST);
+	glStencilFunc(GL_ALWAYS, 1, 0xFFFFFFFF);
+	stop_glerror();
+	glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
+	stop_glerror();
+
+	for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
+	{
+		LLDrawPool *poolp = *iter;
+		if (hasRenderType(poolp->getType()))
+		{
+			poolp->prerender();
+		}
+	}
+
+	LLGLEnable multisample(GL_MULTISAMPLE_ARB);
+
+	LLVertexBuffer::unbind();
+
+	LLGLState::checkStates();
+	LLGLState::checkTextureChannels();
+	LLGLState::checkClientArrays();
+
+	U32 cur_type = 0;
+
+	gGL.setColorMask(true, true);
+	
+	pool_set_t::iterator iter1 = mPools.begin();
+
+	while ( iter1 != mPools.end() )
+	{
+		LLDrawPool *poolp = *iter1;
+		
+		cur_type = poolp->getType();
+
+		pool_set_t::iterator iter2 = iter1;
+		if (hasRenderType(poolp->getType()) && poolp->getNumDeferredPasses() > 0)
+		{
+			LLFastTimer t(LLFastTimer::FTM_POOLRENDER);
+
+			gGLLastMatrix = NULL;
+			glLoadMatrixd(gGLModelView);
+		
+			for( S32 i = 0; i < poolp->getNumDeferredPasses(); i++ )
+			{
+				LLVertexBuffer::unbind();
+				poolp->beginDeferredPass(i);
+				for (iter2 = iter1; iter2 != mPools.end(); iter2++)
+				{
+					LLDrawPool *p = *iter2;
+					if (p->getType() != cur_type)
+					{
+						break;
+					}
+										
+					p->renderDeferred(i);
+				}
+				poolp->endDeferredPass(i);
+				LLVertexBuffer::unbind();
+
+				GLint depth;
+				glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &depth);
+				if (depth > 3)
+				{
+					llerrs << "GL matrix stack corrupted!" << llendl;
+				}
+				LLGLState::checkStates();
+				LLGLState::checkTextureChannels();
+				LLGLState::checkClientArrays();
+			}
+		}
+		else
+		{
+			// Skip all pools of this type
+			for (iter2 = iter1; iter2 != mPools.end(); iter2++)
+			{
+				LLDrawPool *p = *iter2;
+				if (p->getType() != cur_type)
+				{
+					break;
+				}
+			}
+		}
+		iter1 = iter2;
+		stop_glerror();
+	}
+
+	gGLLastMatrix = NULL;
+	glLoadMatrixd(gGLModelView);
+
+	gGL.setColorMask(true, false);
+}
+
+void LLPipeline::renderGeomPostDeferred(LLCamera& camera)
+{
+	LLFastTimer t(LLFastTimer::FTM_POOLS);
+	U32 cur_type = 0;
+
+	LLGLEnable cull(GL_CULL_FACE);
+
+	LLGLEnable multisample(GL_MULTISAMPLE_ARB);
+
+	calcNearbyLights(camera);
+	setupHWLights(NULL);
+
+	gGL.setColorMask(true, false);
+
+	pool_set_t::iterator iter1 = mPools.begin();
+	BOOL occlude = LLPipeline::sUseOcclusion > 1;
+
+	while ( iter1 != mPools.end() )
+	{
+		LLDrawPool *poolp = *iter1;
+		
+		cur_type = poolp->getType();
+
+		if (occlude && cur_type >= LLDrawPool::POOL_GRASS)
+		{
+			occlude = FALSE;
+			gGLLastMatrix = NULL;
+			glLoadMatrixd(gGLModelView);
+			doOcclusion(camera);
+			gGL.setColorMask(true, false);
+		}
+
+		pool_set_t::iterator iter2 = iter1;
+		if (hasRenderType(poolp->getType()) && poolp->getNumPostDeferredPasses() > 0)
+		{
+			LLFastTimer t(LLFastTimer::FTM_POOLRENDER);
+
+			gGLLastMatrix = NULL;
+			glLoadMatrixd(gGLModelView);
+		
+			for( S32 i = 0; i < poolp->getNumPostDeferredPasses(); i++ )
+			{
+				LLVertexBuffer::unbind();
+				poolp->beginPostDeferredPass(i);
+				for (iter2 = iter1; iter2 != mPools.end(); iter2++)
+				{
+					LLDrawPool *p = *iter2;
+					if (p->getType() != cur_type)
+					{
+						break;
+					}
+										
+					p->renderPostDeferred(i);
+				}
+				poolp->endPostDeferredPass(i);
+				LLVertexBuffer::unbind();
+
+				GLint depth;
+				glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &depth);
+				if (depth > 3)
+				{
+					llerrs << "GL matrix stack corrupted!" << llendl;
+				}
+				LLGLState::checkStates();
+				LLGLState::checkTextureChannels();
+				LLGLState::checkClientArrays();
+			}
+		}
+		else
+		{
+			// Skip all pools of this type
+			for (iter2 = iter1; iter2 != mPools.end(); iter2++)
+			{
+				LLDrawPool *p = *iter2;
+				if (p->getType() != cur_type)
+				{
+					break;
+				}
+			}
+		}
+		iter1 = iter2;
+		stop_glerror();
+	}
+
+	gGLLastMatrix = NULL;
+	glLoadMatrixd(gGLModelView);
+
+	renderHighlights();
+	mHighlightFaces.clear();
+
+	renderDebug();
+
+	LLVertexBuffer::unbind();
+
+	if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
+	{
+		// Render debugging beacons.
+		gObjectList.renderObjectBeacons();
+		LLHUDObject::renderAll();
+		gObjectList.resetObjectBeacons();
+	}
+
+	if (occlude)
+	{
+		occlude = FALSE;
+		gGLLastMatrix = NULL;
+		glLoadMatrixd(gGLModelView);
+		doOcclusion(camera);
+	}
+}
+
+void LLPipeline::renderGeomShadow(LLCamera& camera)
 {
-	gDeferredDiffuseProgram.bind();
-	gPipeline.renderObjects(LLRenderPass::PASS_SIMPLE, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_NORMAL, TRUE);
-	gDeferredDiffuseProgram.unbind();
+	U32 cur_type = 0;
+	
+	LLGLEnable cull(GL_CULL_FACE);
+
+	LLVertexBuffer::unbind();
+
+	pool_set_t::iterator iter1 = mPools.begin();
+	
+	while ( iter1 != mPools.end() )
+	{
+		LLDrawPool *poolp = *iter1;
+		
+		cur_type = poolp->getType();
+
+		pool_set_t::iterator iter2 = iter1;
+		if (hasRenderType(poolp->getType()) && poolp->getNumShadowPasses() > 0)
+		{
+			gGLLastMatrix = NULL;
+			glLoadMatrixd(gGLModelView);
+		
+			for( S32 i = 0; i < poolp->getNumShadowPasses(); i++ )
+			{
+				LLVertexBuffer::unbind();
+				poolp->beginShadowPass(i);
+				for (iter2 = iter1; iter2 != mPools.end(); iter2++)
+				{
+					LLDrawPool *p = *iter2;
+					if (p->getType() != cur_type)
+					{
+						break;
+					}
+										
+					p->renderShadow(i);
+				}
+				poolp->endShadowPass(i);
+				LLVertexBuffer::unbind();
+
+				LLGLState::checkStates();
+				LLGLState::checkTextureChannels();
+				LLGLState::checkClientArrays();
+			}
+		}
+		else
+		{
+			// Skip all pools of this type
+			for (iter2 = iter1; iter2 != mPools.end(); iter2++)
+			{
+				LLDrawPool *p = *iter2;
+				if (p->getType() != cur_type)
+				{
+					break;
+				}
+			}
+		}
+		iter1 = iter2;
+		stop_glerror();
+	}
+
+	gGLLastMatrix = NULL;
+	glLoadMatrixd(gGLModelView);
 }
 
+
 void LLPipeline::addTrianglesDrawn(S32 count)
 {
 	assertInitialized();
@@ -2621,6 +3078,99 @@ void LLPipeline::renderDebug()
 		}
 	}
 
+	if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
+	{
+		gGL.color4f(1,1,1,1);
+		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+				
+		F32 col[] =
+		{
+			1,1,0,
+			0,1,1,
+			1,0,1,
+			1,1,1,
+			1,0,0,
+			0,1,0,
+			0,0,1,
+			0,0,0
+		};
+
+		for (U32 i = 0; i < 8; i++)
+		{
+			gGL.color3fv(col+i*3);	
+
+			gGL.begin(LLRender::LINES);
+
+			LLVector3* frust = mShadowCamera[i].mAgentFrustum;
+
+			gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[1].mV);
+			gGL.vertex3fv(frust[1].mV); gGL.vertex3fv(frust[2].mV);
+			gGL.vertex3fv(frust[2].mV); gGL.vertex3fv(frust[3].mV);
+			gGL.vertex3fv(frust[3].mV); gGL.vertex3fv(frust[0].mV);
+
+			gGL.vertex3fv(frust[4].mV); gGL.vertex3fv(frust[5].mV);
+			gGL.vertex3fv(frust[5].mV); gGL.vertex3fv(frust[6].mV);
+			gGL.vertex3fv(frust[6].mV); gGL.vertex3fv(frust[7].mV);
+			gGL.vertex3fv(frust[7].mV); gGL.vertex3fv(frust[4].mV);
+
+			gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[4].mV);
+			gGL.vertex3fv(frust[1].mV); gGL.vertex3fv(frust[5].mV);
+			gGL.vertex3fv(frust[2].mV); gGL.vertex3fv(frust[6].mV);
+			gGL.vertex3fv(frust[3].mV); gGL.vertex3fv(frust[7].mV);
+			
+			if (i < 4)
+			{
+				LLVector3* ext = mShadowExtents[i];
+				
+				LLVector3 box[] =
+				{
+					LLVector3(ext[0][0], ext[0][1], ext[0][2]),
+					LLVector3(ext[1][0], ext[0][1], ext[0][2]),
+					LLVector3(ext[1][0], ext[1][1], ext[0][2]),
+					LLVector3(ext[0][0], ext[1][1], ext[0][2]),
+					LLVector3(ext[0][0], ext[0][1], ext[1][2]),
+					LLVector3(ext[1][0], ext[0][1], ext[1][2]),
+					LLVector3(ext[1][0], ext[1][1], ext[1][2]),
+					LLVector3(ext[0][0], ext[1][1], ext[1][2]),
+				};
+					
+				gGL.vertex3fv(box[0].mV); gGL.vertex3fv(box[1].mV);
+				gGL.vertex3fv(box[1].mV); gGL.vertex3fv(box[2].mV);
+				gGL.vertex3fv(box[2].mV); gGL.vertex3fv(box[3].mV);
+				gGL.vertex3fv(box[3].mV); gGL.vertex3fv(box[0].mV);
+
+				gGL.vertex3fv(box[4].mV); gGL.vertex3fv(box[5].mV);
+				gGL.vertex3fv(box[5].mV); gGL.vertex3fv(box[6].mV);
+				gGL.vertex3fv(box[6].mV); gGL.vertex3fv(box[7].mV);
+				gGL.vertex3fv(box[7].mV); gGL.vertex3fv(box[4].mV);
+
+				gGL.vertex3fv(box[0].mV); gGL.vertex3fv(box[4].mV);
+				gGL.vertex3fv(box[1].mV); gGL.vertex3fv(box[5].mV);
+				gGL.vertex3fv(box[2].mV); gGL.vertex3fv(box[6].mV);
+				gGL.vertex3fv(box[3].mV); gGL.vertex3fv(box[7].mV);
+			}
+
+			gGL.end();
+			
+			for (LLWorld::region_list_t::iterator iter = LLWorld::getInstance()->getRegionList().begin(); 
+					iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+			{
+				LLViewerRegion* region = *iter;
+				for (U32 j = 0; j < LLViewerRegion::NUM_PARTITIONS; j++)
+				{
+					LLSpatialPartition* part = region->getSpatialPartition(j);
+					if (part)
+					{
+						if (hasRenderType(part->mDrawableType))
+						{
+							part->renderIntersectingBBoxes(&mShadowCamera[i]);
+						}
+					}
+				}
+			}
+		}
+	}
+
 	if (mRenderDebugMask & RENDER_DEBUG_COMPOSITION)
 	{
 		// Debug composition layers
@@ -2653,6 +3203,7 @@ void LLPipeline::renderDebug()
 			gGL.end();
 		}
 	}
+
 	gGL.flush();
 }
 
@@ -2735,7 +3286,7 @@ void LLPipeline::renderForSelect(std::set<LLViewerObject*>& objects, BOOL render
 	gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_ALPHA, LLTexUnit::TBS_VERT_ALPHA);
 
 	U32 prim_mask = LLVertexBuffer::MAP_VERTEX | 
-					LLVertexBuffer::MAP_TEXCOORD;
+					LLVertexBuffer::MAP_TEXCOORD0;
 
 	for (std::set<LLViewerObject*>::iterator i = objects.begin(); i != objects.end(); ++i)
 	{
@@ -2891,6 +3442,30 @@ void LLPipeline::addToQuickLookup( LLDrawPool* new_poolp )
 		}
 		break;
 
+	case LLDrawPool::POOL_GRASS:
+		if (mGrassPool)
+		{
+			llassert(0);
+			llwarns << "Ignoring duplicate grass pool." << llendl;
+		}
+		else
+		{
+			mGrassPool = (LLRenderPass*) new_poolp;
+		}
+		break;
+
+	case LLDrawPool::POOL_FULLBRIGHT:
+		if (mFullbrightPool)
+		{
+			llassert(0);
+			llwarns << "Ignoring duplicate simple pool." << llendl;
+		}
+		else
+		{
+			mFullbrightPool = (LLRenderPass*) new_poolp;
+		}
+		break;
+
 	case LLDrawPool::POOL_INVISIBLE:
 		if (mInvisiblePool)
 		{
@@ -3024,6 +3599,16 @@ void LLPipeline::removeFromQuickLookup( LLDrawPool* poolp )
 		mSimplePool = NULL;
 		break;
 
+	case LLDrawPool::POOL_GRASS:
+		llassert(mGrassPool == poolp);
+		mGrassPool = NULL;
+		break;
+
+	case LLDrawPool::POOL_FULLBRIGHT:
+		llassert(mFullbrightPool == poolp);
+		mFullbrightPool = NULL;
+		break;
+
 	case LLDrawPool::POOL_INVISIBLE:
 		llassert(mInvisiblePool == poolp);
 		mInvisiblePool = NULL;
@@ -3117,7 +3702,7 @@ void LLPipeline::setupAvatarLights(BOOL for_edit)
 
 	if (for_edit)
 	{
-		LLColor4 diffuse(0.8f, 0.8f, 0.8f, 0.f);
+		LLColor4 diffuse(1.f, 1.f, 1.f, 0.f);
 		LLVector4 light_pos_cam(-8.f, 0.25f, 10.f, 0.f);  // w==0 => directional light
 		LLMatrix4 camera_mat = LLViewerCamera::getInstance()->getModelview();
 		LLMatrix4 camera_rot(camera_mat.getMat3());
@@ -3288,8 +3873,12 @@ void LLPipeline::calcNearbyLights(LLCamera& camera)
 			{
 				continue;
 			}
-			new_nearby_lights.insert(Light(drawable, dist, 0.f));
-			if (new_nearby_lights.size() > (U32)MAX_LOCAL_LIGHTS)
+			if (!sRenderAttachedLights && light && light->isAttachment())
+			{
+				continue;
+			}
+			new_nearby_lights.insert(Light(drawable, dist, 0.f));
+			if (new_nearby_lights.size() > (U32)MAX_LOCAL_LIGHTS)
 			{
 				new_nearby_lights.erase(--new_nearby_lights.end());
 				const Light& last = *new_nearby_lights.rbegin();
@@ -4282,11 +4871,11 @@ void LLPipeline::resetVertexBuffers()
 void LLPipeline::renderObjects(U32 type, U32 mask, BOOL texture)
 {
 	assertInitialized();
+	glLoadMatrixd(gGLModelView);
 	gGLLastMatrix = NULL;
-	glLoadMatrixd(gGLLastModelView);
-	mSimplePool->renderGroups(type, mask, texture);
-	gGLLastMatrix = NULL;
-	glLoadMatrixd(gGLLastModelView);
+	mSimplePool->pushBatches(type, mask);
+	glLoadMatrixd(gGLModelView);
+	gGLLastMatrix = NULL;		
 }
 
 void LLPipeline::setUseVBO(BOOL use_vbo)
@@ -4334,191 +4923,6 @@ void apply_cube_face_rotation(U32 face)
 		break;
 	}
 }
-void LLPipeline::generateReflectionMap(LLCubeMap* cube_map, LLCamera& cube_cam)
-{
-	LLGLState::checkStates();
-	LLGLState::checkTextureChannels();
-	LLGLState::checkClientArrays();
-
-	assertInitialized();
-
-	//render dynamic cube map
-	U32 type_mask = gPipeline.getRenderTypeMask();
-	S32 use_occlusion = LLPipeline::sUseOcclusion;
-	LLPipeline::sUseOcclusion = 0;
-	LLPipeline::sSkipUpdate = TRUE;
-	U32 res = REFLECTION_MAP_RES;
-
-	LLPipeline::sReflectionRender = TRUE;
-
-	gGL.getTexUnit(cube_map->getStage())->bind(cube_map);
-	gGL.getTexUnit(0)->activate();
-	GLint width;
-	glGetTexLevelParameteriv(GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, 0, GL_TEXTURE_WIDTH, &width);
-	if (width != res)
-	{
-		cube_map->setReflection();
-		
-		for (U32 i = 0; i < 6; i++)
-		{
-			glTexImage2D(gl_cube_face[i], 0, GL_RGBA, res, res, 0, GL_RGBA, GL_FLOAT, NULL); 
-		}
-	}
-	gGL.getTexUnit(cube_map->getStage())->unbind(LLTexUnit::TT_CUBE_MAP);
-	gGL.getTexUnit(cube_map->getStage())->disable();
-	gGL.getTexUnit(0)->activate();
-	gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
-
-	BOOL toggle_ui = gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI);
-	if (toggle_ui)
-	{
-		gPipeline.toggleRenderDebugFeature((void*) LLPipeline::RENDER_DEBUG_FEATURE_UI);
-	}
-	
-	U32 cube_mask = (1 << LLPipeline::RENDER_TYPE_SIMPLE) |
-					(1 << LLPipeline::RENDER_TYPE_WATER) |
-					//(1 << LLPipeline::RENDER_TYPE_BUMP) |
-					(1 << LLPipeline::RENDER_TYPE_ALPHA) |
-					(1 << LLPipeline::RENDER_TYPE_TREE) |
-					//(1 << LLPipeline::RENDER_TYPE_PARTICLES) |
-					(1 << LLPipeline::RENDER_TYPE_CLOUDS) |
-					//(1 << LLPipeline::RENDER_TYPE_STARS) |
-					//(1 << LLPipeline::RENDER_TYPE_AVATAR) |
-					(1 << LLPipeline::RENDER_TYPE_GLOW) |
-					(1 << LLPipeline::RENDER_TYPE_GRASS) |
-					(1 << LLPipeline::RENDER_TYPE_VOLUME) |
-					(1 << LLPipeline::RENDER_TYPE_TERRAIN) |
-					(1 << LLPipeline::RENDER_TYPE_SKY) |
-					(1 << LLPipeline::RENDER_TYPE_WL_SKY) |
-					(1 << LLPipeline::RENDER_TYPE_GROUND);
-	
-	LLDrawPoolWater::sSkipScreenCopy = TRUE;
-	LLPipeline::sSkipUpdate = TRUE;
-	cube_mask = cube_mask & type_mask;
-	gPipeline.setRenderTypeMask(cube_mask);
-
-	glMatrixMode(GL_PROJECTION);
-	glPushMatrix();
-	glMatrixMode(GL_MODELVIEW);
-	glPushMatrix();
-
-	glViewport(0,0,res,res);
-	
-	glClearColor(0,0,0,0);			
-	
-	LLVector3 origin = cube_cam.getOrigin();
-
-	gPipeline.calcNearbyLights(cube_cam);
-
-	stop_glerror();
-	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mCubeFrameBuffer);
-	glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
-										GL_RENDERBUFFER_EXT, mCubeDepth);		
-	stop_glerror();
-
-	for (S32 i = 0; i < 6; i++)
-	{
-		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mCubeFrameBuffer);
-		glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
-									gl_cube_face[i], cube_map->getGLName(), 0);
-		validate_framebuffer_object();
-		glMatrixMode(GL_PROJECTION);
-		glLoadIdentity();
-		gluPerspective(90.f, 1.f, 0.1f, 1024.f);
-		glMatrixMode(GL_MODELVIEW);
-		glLoadIdentity();
-		
-		apply_cube_face_rotation(i);
-
-		glTranslatef(-origin.mV[0], -origin.mV[1], -origin.mV[2]);
-		cube_cam.setOrigin(origin);
-		LLViewerCamera::updateFrustumPlanes(cube_cam);
-		cube_cam.setOrigin(LLViewerCamera::getInstance()->getOrigin());
-		static LLCullResult result;
-		gPipeline.updateCull(cube_cam, result);
-		gPipeline.stateSort(cube_cam, result);
-		
-		glClearColor(0,0,0,0);
-		gGL.setColorMask(true, true);
-		glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
-		gGL.setColorMask(true, false);
-		stop_glerror();
-		gPipeline.renderGeom(cube_cam);
-	}
-
-	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
-
-	cube_cam.setOrigin(origin);
-	gShinyOrigin.setVec(cube_cam.getOrigin(), cube_cam.getFar()*2.f);
-	glMatrixMode(GL_PROJECTION);
-	glPopMatrix();
-	glMatrixMode(GL_MODELVIEW);
-	glPopMatrix();
-
-	gViewerWindow->setupViewport();
-
-	gPipeline.setRenderTypeMask(type_mask);
-	LLPipeline::sUseOcclusion = use_occlusion;
-	LLPipeline::sSkipUpdate = FALSE;
-
-	if (toggle_ui)
-	{
-		gPipeline.toggleRenderDebugFeature((void*)LLPipeline::RENDER_DEBUG_FEATURE_UI);
-	}
-	LLDrawPoolWater::sSkipScreenCopy = FALSE;
-	LLPipeline::sSkipUpdate = FALSE;
-	LLPipeline::sReflectionRender = FALSE;
-
-	LLGLState::checkStates();
-	LLGLState::checkTextureChannels();
-	LLGLState::checkClientArrays();
-}
-
-//send cube map vertices and texture coordinates
-void render_cube_map()
-{
-	U16 idx[36];
-
-	idx[0] = 1; idx[1] = 0; idx[2] = 2; //front
-	idx[3] = 3; idx[4] = 2; idx[5] = 0;
-
-	idx[6] = 4; idx[7] = 5; idx[8] = 1; //top
-	idx[9] = 0; idx[10] = 1; idx[11] = 5; 
-
-	idx[12] = 5; idx[13] = 4; idx[14] = 6; //back
-	idx[15] = 7; idx[16] = 6; idx[17] = 4;
-
-	idx[18] = 6; idx[19] = 7; idx[20] = 3; //bottom
-	idx[21] = 2; idx[22] = 3; idx[23] = 7;
-
-	idx[24] = 0; idx[25] = 5; idx[26] = 3; //left
-	idx[27] = 6; idx[28] = 3; idx[29] = 5;
-
-	idx[30] = 4; idx[31] = 1; idx[32] = 7; //right
-	idx[33] = 2; idx[34] = 7; idx[35] = 1;
-
-	LLVector3 vert[8];
-	LLVector3 r = LLVector3(1,1,1);
-
-	vert[0] = r.scaledVec(LLVector3(-1,1,1)); //   0 - left top front
-	vert[1] = r.scaledVec(LLVector3(1,1,1));  //   1 - right top front
-	vert[2] = r.scaledVec(LLVector3(1,-1,1)); //   2 - right bottom front
-	vert[3] = r.scaledVec(LLVector3(-1,-1,1)); //  3 - left bottom front
-
-	vert[4] = r.scaledVec(LLVector3(1,1,-1)); //  4 - left top back
-	vert[5] = r.scaledVec(LLVector3(-1,1,-1)); //   5 - right top back
-	vert[6] = r.scaledVec(LLVector3(-1,-1,-1)); //  6 - right bottom back
-	vert[7] = r.scaledVec(LLVector3(1,-1,-1)); // 7 -left bottom back
-
-	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-	glTexCoordPointer(3, GL_FLOAT, 0, vert);
-	glVertexPointer(3, GL_FLOAT, 0, vert);
-
-	glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_SHORT, (GLushort*) idx);
-
-	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-}
 
 void validate_framebuffer_object()
 {                                                           
@@ -4547,132 +4951,12 @@ void validate_framebuffer_object()
 	}
 }
 
-void LLPipeline::blurReflectionMap(LLCubeMap* cube_in, LLCubeMap* cube_out)
-{
-	LLGLState::checkStates();
-	LLGLState::checkTextureChannels();
-	LLGLState::checkClientArrays();
-
-	assertInitialized();
-
-	U32 res = (U32) gSavedSettings.getS32("RenderReflectionRes");
-	enableLightsFullbright(LLColor4::white);
-	LLGLDepthTest depth(GL_FALSE);
-	gGL.setColorMask(true, true);
-	glMatrixMode(GL_PROJECTION);
-	glPushMatrix();
-	glLoadIdentity();
-	gluPerspective(90.f+45.f/res, 1.f, 0.1f, 1024.f);
-	glMatrixMode(GL_MODELVIEW);
-	glPushMatrix();
-
-	cube_out->enableTexture(0);
-	gGL.getTexUnit(cube_out->getStage())->bind(cube_out);
-	gGL.getTexUnit(0)->activate();
-	GLint width;
-	glGetTexLevelParameteriv(GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, 0, GL_TEXTURE_WIDTH, &width);
-	if (width != res)
-	{
-		cube_out->setReflection();
-		
-		for (U32 i = 0; i < 6; i++)
-		{
-			glTexImage2D(gl_cube_face[i], 0, GL_RGBA, res, res, 0, GL_RGBA, GL_FLOAT, NULL); 
-		}
-	}
-	gGL.getTexUnit(cube_out->getStage())->unbind(LLTexUnit::TT_CUBE_MAP);
-	gGL.getTexUnit(0)->activate();
-	glViewport(0, 0, res, res);
-	LLGLEnable blend(GL_BLEND);
-	
-	S32 kernel = 2;
-	F32 step = 90.f/res;
-	F32 alpha = 1.f / ((kernel*2)+1);
-
-	gGL.color4f(alpha,alpha,alpha,alpha*1.25f);
-	
-	LLVector3 axis[] = 
-	{
-		LLVector3(1,0,0),
-		LLVector3(0,1,0),
-		LLVector3(0,0,1)
-	};
-
-	stop_glerror();
-	glViewport(0,0,res, res);
-	gGL.setSceneBlendType(LLRender::BT_ADD);
-	cube_in->enableTexture(0);
-	//3-axis blur
-	for (U32 j = 0; j < 3; j++)
-	{
-		stop_glerror();
-
-		if (j == 0)
-		{
-			gGL.getTexUnit(cube_in->getStage())->bind(cube_in);
-		}
-		else
-		{
-			gGL.getTexUnit(cube_in->getStage())->bindManual(LLTexUnit::TT_CUBE_MAP, mBlurCubeTexture[j-1]);
-		}
-		gGL.getTexUnit(0)->activate();
-
-		stop_glerror();
-
-		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mBlurCubeBuffer[j]);
-		stop_glerror();
-
-		for (U32 i = 0; i < 6; i++)
-		{
-			stop_glerror();
-			glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, 
-								GL_COLOR_ATTACHMENT0_EXT,
-								gl_cube_face[i], 
-								j < 2 ? mBlurCubeTexture[j] : cube_out->getGLName(), 0);
-			validate_framebuffer_object();
-			gGL.setColorMask(true, true);
-			glClear(GL_COLOR_BUFFER_BIT);
-			glLoadIdentity();
-			apply_cube_face_rotation(i);
-			for (S32 x = -kernel; x <= kernel; ++x)
-			{
-				glPushMatrix();
-				glRotatef(x*step, axis[j].mV[0], axis[j].mV[1], axis[j].mV[2]);
-				render_cube_map();
-				glPopMatrix();
-			}
-			stop_glerror();
-		}	
-	}
-
-	stop_glerror();
-
-	gGL.getTexUnit(cube_in->getStage())->unbind(LLTexUnit::TT_CUBE_MAP);
-	
-	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
-	gGL.setColorMask(true, false);
-	glMatrixMode(GL_PROJECTION);
-	glPopMatrix();
-	glMatrixMode(GL_MODELVIEW);
-	glPopMatrix();
-
-	gGL.getTexUnit(cube_in->getStage())->disable();
-	gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
-	gViewerWindow->setupViewport();
-	gGL.setSceneBlendType(LLRender::BT_ALPHA);
-
-	LLGLState::checkStates();
-	LLGLState::checkTextureChannels();
-	LLGLState::checkClientArrays();
-}
-
 void LLPipeline::bindScreenToTexture() 
 {
 	
 }
 
-void LLPipeline::renderBloom(BOOL for_snapshot)
+void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield)
 {
 	if (!(gPipeline.canUseVertexShaders() &&
 		sRenderGlow))
@@ -4694,8 +4978,8 @@ void LLPipeline::renderBloom(BOOL for_snapshot)
 	U32 res_mod = gSavedSettings.getU32("RenderResolutionDivisor");
 
 	LLVector2 tc1(0,0);
-	LLVector2 tc2((F32) gViewerWindow->getWindowDisplayWidth(),
-					(F32) gViewerWindow->getWindowDisplayHeight());
+	LLVector2 tc2((F32) gViewerWindow->getWindowDisplayWidth()*2,
+				  (F32) gViewerWindow->getWindowDisplayHeight()*2);
 
 	if (res_mod > 1)
 	{
@@ -4732,9 +5016,22 @@ void LLPipeline::renderBloom(BOOL for_snapshot)
 			//glStencilFunc(GL_NOTEQUAL, 255, 0xFFFFFFFF);
 			//glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
 			//LLGLDisable blend(GL_BLEND);
+
+			// If the snapshot is constructed from tiles, calculate which
+			// tile we're in.
+			const S32 num_horizontal_tiles = llceil(zoom_factor);
+			const LLVector2 tile(subfield % num_horizontal_tiles,
+								 (S32)(subfield / num_horizontal_tiles));
+			llassert(zoom_factor > 0.0); // Non-zero, non-negative.
+			const F32 tile_size = 1.0/zoom_factor;
+			
+			tc1 = tile*tile_size; // Top left texture coordinates
+			tc2 = (tile+LLVector2(1,1))*tile_size; // Bottom right texture coordinates
+			
 			LLGLEnable blend(GL_BLEND);
 			gGL.setSceneBlendType(LLRender::BT_ADD);
-			tc2.setVec(1,1);				
+			
+				
 			gGL.begin(LLRender::TRIANGLE_STRIP);
 			gGL.color4f(1,1,1,1);
 			gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
@@ -4748,6 +5045,7 @@ void LLPipeline::renderBloom(BOOL for_snapshot)
 			
 			gGL.texCoord2f(tc2.mV[0], tc2.mV[1]);
 			gGL.vertex2f(1,1);
+
 			gGL.end();
 
 			gGL.flush();
@@ -4771,7 +5069,7 @@ void LLPipeline::renderBloom(BOOL for_snapshot)
 		}
 		
 		gGlowExtractProgram.bind();
-		F32 minLum = llclamp(gSavedSettings.getF32("RenderGlowMinLuminance"), 0.0f, 1.0f);
+		F32 minLum = llmax(gSavedSettings.getF32("RenderGlowMinLuminance"), 0.0f);
 		F32 maxAlpha = gSavedSettings.getF32("RenderGlowMaxExtractAlpha");		
 		F32 warmthAmount = gSavedSettings.getF32("RenderGlowWarmthAmount");	
 		LLVector3 lumWeights = gSavedSettings.getVector3("RenderGlowLumWeights");
@@ -4798,13 +5096,11 @@ void LLPipeline::renderBloom(BOOL for_snapshot)
 		gGL.vertex2f(-1,-1);
 		
 		gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
-		gGL.vertex2f(-1,1);
+		gGL.vertex2f(-1,3);
 		
 		gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
-		gGL.vertex2f(1,-1);
+		gGL.vertex2f(3,-1);
 		
-		gGL.texCoord2f(tc2.mV[0], tc2.mV[1]);
-		gGL.vertex2f(1,1);
 		gGL.end();
 		
 		gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
@@ -4813,7 +5109,7 @@ void LLPipeline::renderBloom(BOOL for_snapshot)
 	}
 
 	tc1.setVec(0,0);
-	tc2.setVec(1,1);
+	tc2.setVec(2,2);
 
 
 
@@ -4867,13 +5163,11 @@ void LLPipeline::renderBloom(BOOL for_snapshot)
 		gGL.vertex2f(-1,-1);
 		
 		gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
-		gGL.vertex2f(-1,1);
+		gGL.vertex2f(-1,3);
 		
 		gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
-		gGL.vertex2f(1,-1);
+		gGL.vertex2f(3,-1);
 		
-		gGL.texCoord2f(tc2.mV[0], tc2.mV[1]);
-		gGL.vertex2f(1,1);
 		gGL.end();
 		
 		mGlow[i%2].flush();
@@ -4889,81 +5183,12 @@ void LLPipeline::renderBloom(BOOL for_snapshot)
 
 	gViewerWindow->setupViewport();
 
-	/*mGlow[1].bindTexture();
-	{
-		LLGLEnable stencil(GL_STENCIL_TEST);
-		glStencilFunc(GL_NOTEQUAL, 255, 0xFFFFFFFF);
-		glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
-		LLGLDisable blend(GL_BLEND);
-			
-		gGL.begin(LLVertexBuffer::TRIANGLE_STRIP);
-		gGL.color4f(1,1,1,1);
-		gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
-		gGL.vertex2f(-1,-1);
-		
-		gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
-		gGL.vertex2f(-1,1);
-		
-		gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
-		gGL.vertex2f(1,-1);
-		
-		gGL.texCoord2f(tc2.mV[0], tc2.mV[1]);
-		gGL.vertex2f(1,1);
-		gGL.end();
-
-		gGL.flush();
-	}
-
-	if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_GLOW))
-	{
-		tc2.setVec((F32) gViewerWindow->getWindowDisplayWidth(),
-				(F32) gViewerWindow->getWindowDisplayHeight());
-
-		if (res_mod > 1)
-		{
-			tc2 /= (F32) res_mod;
-		}
-
-		LLGLEnable blend(GL_BLEND);
-		gGL.blendFunc(GL_ONE, GL_ONE);
-
-		gGL.getTexUnit(0)->disable();
-		gGL.getTexUnit(0)->enable(LLTexUnit::TT_RECT_TEXTURE);
-		mScreen.bindTexture();
-		
-		gGL.begin(LLVertexBuffer::TRIANGLE_STRIP);
-		gGL.color4f(1,1,1,1);
-		gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
-		gGL.vertex2f(-1,-1);
-		
-		gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
-		gGL.vertex2f(-1,1);
-		
-		gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
-		gGL.vertex2f(1,-1);
-		
-		gGL.texCoord2f(tc2.mV[0], tc2.mV[1]);
-		gGL.vertex2f(1,1);
-		gGL.end();
-
-		gGL.flush();
-		
-		gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
-
-		gGL.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-	}*/
 	gGL.flush();
 	
 	{
 		LLVertexBuffer::unbind();
 
-		F32 uv0[] = 
-		{
-				tc1.mV[0], tc1.mV[1],
-				tc1.mV[0], tc2.mV[1],
-				tc2.mV[0], tc1.mV[1],
-				tc2.mV[0], tc2.mV[1]
-		};
+		
 		
 		tc2.setVec((F32) gViewerWindow->getWindowDisplayWidth(),
 			(F32) gViewerWindow->getWindowDisplayHeight());
@@ -4973,55 +5198,56 @@ void LLPipeline::renderBloom(BOOL for_snapshot)
 			tc2 /= (F32) res_mod;
 		}
 
-		F32 uv1[] = 
-		{
-				tc1.mV[0], tc1.mV[1],
-				tc1.mV[0], tc2.mV[1],
-				tc2.mV[0], tc1.mV[1],
-				tc2.mV[0], tc2.mV[1]
-		};
+		U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TEXCOORD1;
+		LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(mask, 0);
+		buff->allocateBuffer(3,0,TRUE);
 
-		F32 v[] = 
-		{
-			-1,-1,
-			-1,1,
-			1,-1,
-			1,1
-		};
+		LLStrider<LLVector3> v;
+		LLStrider<LLVector2> uv1;
+		LLStrider<LLVector2> uv2;
+
+		buff->getVertexStrider(v);
+		buff->getTexCoord0Strider(uv1);
+		buff->getTexCoord1Strider(uv2);
+		
+		uv1[0] = LLVector2(0, 0);
+		uv1[1] = LLVector2(0, 2);
+		uv1[2] = LLVector2(2, 0);
 		
+		uv2[0] = LLVector2(0, 0);
+		uv2[1] = LLVector2(0, tc2.mV[1]*2.f);
+		uv2[2] = LLVector2(tc2.mV[0]*2.f, 0);
+		
+		v[0] = LLVector3(-1,-1,0);
+		v[1] = LLVector3(-1,3,0);
+		v[2] = LLVector3(3,-1,0);
+				
+		buff->setBuffer(0);
+
 		LLGLDisable blend(GL_BLEND);
 
 		//tex unit 0
 		gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_COLOR);
 	
 		gGL.getTexUnit(0)->bind(&mGlow[1]);
-		glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-		glTexCoordPointer(2, GL_FLOAT, 0, uv0);
 		gGL.getTexUnit(1)->activate();
 		gGL.getTexUnit(1)->enable(LLTexUnit::TT_RECT_TEXTURE);
 		
 		//tex unit 1
 		gGL.getTexUnit(1)->setTextureColorBlend(LLTexUnit::TBO_ADD, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_PREV_COLOR);
 		
-		glClientActiveTextureARB(GL_TEXTURE1_ARB);
-		glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-		glTexCoordPointer(2, GL_FLOAT, 0, uv1);
-
-		glVertexPointer(2, GL_FLOAT, 0, v);
-		
 		gGL.getTexUnit(1)->bind(&mScreen);
 		gGL.getTexUnit(1)->activate();
 		
 		LLGLEnable multisample(GL_MULTISAMPLE_ARB);
-		glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+		
+		buff->setBuffer(mask);
+		buff->drawArrays(LLRender::TRIANGLE_STRIP, 0, 3);
 		
 		gGL.getTexUnit(1)->disable();
-		glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 		gGL.getTexUnit(1)->setTextureBlendType(LLTexUnit::TB_MULT);
 
-		glClientActiveTextureARB(GL_TEXTURE0_ARB);
 		gGL.getTexUnit(0)->activate();
-		glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 		gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
 	}
 	
@@ -5038,35 +5264,555 @@ void LLPipeline::renderBloom(BOOL for_snapshot)
 
 }
 
-inline float sgn(float a)
+void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index)
 {
-    if (a > 0.0F) return (1.0F);
-    if (a < 0.0F) return (-1.0F);
-    return (0.0F);
-}
+	shader.bind();
+	S32 channel = 0;
+	channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_DIFFUSE, LLTexUnit::TT_RECT_TEXTURE);
+	if (channel > -1)
+	{
+		mDeferredScreen.bindTexture(0,channel);
+		//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+		//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+	}
 
-void LLPipeline::generateWaterReflection(LLCamera& camera_in)
-{
-	if (LLPipeline::sWaterReflections && assertInitialized() && LLDrawPoolWater::sNeedsReflectionUpdate)
+	channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_SPECULAR, LLTexUnit::TT_RECT_TEXTURE);
+	if (channel > -1)
 	{
-		LLVertexBuffer::unbind();
+		mDeferredScreen.bindTexture(1, channel);
+	}
 
-		LLGLState::checkStates();
-		LLGLState::checkTextureChannels();
-		LLGLState::checkClientArrays();
+	channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_NORMAL, LLTexUnit::TT_RECT_TEXTURE);
+	if (channel > -1)
+	{
+		mDeferredScreen.bindTexture(2, channel);
+	}
 
-		LLCamera camera = camera_in;
-		camera.setFar(camera.getFar()*0.87654321f);
-		LLPipeline::sReflectionRender = TRUE;
-		S32 occlusion = LLPipeline::sUseOcclusion;
-		LLPipeline::sUseOcclusion = llmin(occlusion, 1);
-		U32 type_mask = gPipeline.mRenderTypeMask;
+	channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_POSITION, LLTexUnit::TT_RECT_TEXTURE);
+	if (channel > -1)
+	{
+		mDeferredScreen.bindTexture(3, channel);
+	}
 
-		glh::matrix4f projection = glh_get_current_projection();
-		glh::matrix4f mat;
+	channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_DEPTH, LLTexUnit::TT_RECT_TEXTURE);
+	if (channel > -1)
+	{
+		gGL.getTexUnit(channel)->bind(&mDeferredScreen, TRUE);
+	}
 
-		stop_glerror();
-		LLPlane plane;
+	channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_NOISE);
+	if (channel > -1)
+	{
+		gGL.getTexUnit(channel)->bindManual(LLTexUnit::TT_TEXTURE, mNoiseMap);
+	}
+
+	stop_glerror();
+
+	channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_LIGHT, LLTexUnit::TT_RECT_TEXTURE);
+	if (channel > -1)
+	{
+		mDeferredLight[light_index].bindTexture(0, channel);
+	}
+
+	stop_glerror();
+
+	for (U32 i = 0; i < 4; i++)
+	{
+		channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_SHADOW0+i);
+		stop_glerror();
+		if (channel > -1)
+		{
+			stop_glerror();
+			gGL.getTexUnit(channel)->bind(&mSunShadow[i], TRUE);
+			gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
+			stop_glerror();
+			
+			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);
+			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
+			stop_glerror();
+		}
+	}
+
+	stop_glerror();
+
+	F32 mat[64];
+	for (U32 i = 0; i < 16; i++)
+	{
+		mat[i] = mSunShadowMatrix[0].m[i];
+		mat[i+16] = mSunShadowMatrix[1].m[i];
+		mat[i+32] = mSunShadowMatrix[2].m[i];
+		mat[i+48] = mSunShadowMatrix[3].m[i];
+	}
+
+	shader.uniformMatrix4fv("shadow_matrix[0]", 4, FALSE, mat);
+	shader.uniformMatrix4fv("shadow_matrix", 4, FALSE, mat);
+
+	stop_glerror();
+
+	channel = shader.enableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP);
+	if (channel > -1)
+	{
+		LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
+		if (cube_map)
+		{
+			cube_map->enable(channel);
+			cube_map->bind();
+			F64* m = gGLModelView;
+
+			
+			F32 mat[] = { m[0], m[1], m[2],
+						  m[4], m[5], m[6],
+						  m[8], m[9], m[10] };
+		
+			shader.uniform3fv("env_mat[0]", 3, mat);
+			shader.uniform3fv("env_mat", 3, mat);
+		}
+	}
+
+	shader.uniform4fv("shadow_clip", 1, mSunClipPlanes.mV);
+	shader.uniform1f("sun_wash", gSavedSettings.getF32("RenderDeferredSunWash"));
+	shader.uniform1f("shadow_noise", gSavedSettings.getF32("RenderShadowNoise"));
+	shader.uniform1f("blur_size", gSavedSettings.getF32("RenderShadowBlurSize"));
+
+	shader.uniform1f("ssao_radius", gSavedSettings.getF32("RenderSSAOScale"));
+	shader.uniform1f("ssao_max_radius", gSavedSettings.getU32("RenderSSAOMaxScale"));
+
+	F32 ssao_factor = gSavedSettings.getF32("RenderSSAOFactor");
+	shader.uniform1f("ssao_factor", ssao_factor);
+	shader.uniform1f("ssao_factor_inv", 1.0/ssao_factor);
+
+	LLVector3 ssao_effect = gSavedSettings.getVector3("RenderSSAOEffect");
+	F32 matrix_diag = (ssao_effect[0] + 2.0*ssao_effect[1])/3.0;
+	F32 matrix_nondiag = (ssao_effect[0] - ssao_effect[1])/3.0;
+	// This matrix scales (proj of color onto <1/rt(3),1/rt(3),1/rt(3)>) by
+	// value factor, and scales remainder by saturation factor
+	F32 ssao_effect_mat[] = {	matrix_diag, matrix_nondiag, matrix_nondiag,
+								matrix_nondiag, matrix_diag, matrix_nondiag,
+								matrix_nondiag, matrix_nondiag, matrix_diag};
+	shader.uniformMatrix3fv("ssao_effect_mat", 1, GL_FALSE, ssao_effect_mat);
+
+	shader.uniform2f("screen_res", mDeferredScreen.getWidth(), mDeferredScreen.getHeight());
+	shader.uniform1f("near_clip", LLViewerCamera::getInstance()->getNear()*2.f);
+	shader.uniform1f("alpha_soften", gSavedSettings.getF32("RenderDeferredAlphaSoften"));
+}
+
+void LLPipeline::renderDeferredLighting()
+{
+	if (!sCull)
+	{
+		return;
+	}
+
+	LLGLEnable multisample(GL_MULTISAMPLE_ARB);
+
+	if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
+	{
+		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD);
+	}
+
+	//ati doesn't seem to love actually using the stencil buffer on FBO's
+	LLGLEnable stencil(GL_STENCIL_TEST);
+	glStencilFunc(GL_EQUAL, 1, 0xFFFFFFFF);
+	glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+
+	gGL.setColorMask(true, true);
+
+	mDeferredLight[0].bindTarget();
+
+	//mDeferredLight[0].copyContents(mDeferredScreen, 0, 0, mDeferredScreen.getWidth(), mDeferredScreen.getHeight(),
+	//					0, 0, mDeferredLight[0].getWidth(), mDeferredLight[0].getHeight(), GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);	
+	
+	//draw a cube around every light
+	LLVertexBuffer::unbind();
+
+	glBlendFunc(GL_ONE, GL_ONE);
+	LLGLEnable cull(GL_CULL_FACE);
+	LLGLEnable blend(GL_BLEND);
+
+	glh::matrix4f mat = glh_copy_matrix(gGLModelView);
+
+	F32 vert[] = 
+	{
+		-1,1,
+		-1,-3,
+		3,1,
+	};
+
+	bindDeferredShader(gDeferredSunProgram);
+
+	glh::matrix4f inv_trans = glh_get_current_modelview().inverse().transpose();
+
+	const U32 slice = 32;
+	F32 offset[slice*3];
+	for (U32 i = 0; i < 4; i++)
+	{
+		for (U32 j = 0; j < 8; j++)
+		{
+			glh::vec3f v;
+			v.set_value(sinf(6.284f/8*j), cosf(6.284f/8*j), -(F32) i);
+			v.normalize();
+			inv_trans.mult_matrix_vec(v);
+			v.normalize();
+			offset[(i*8+j)*3+0] = v.v[0];
+			offset[(i*8+j)*3+1] = v.v[2];
+			offset[(i*8+j)*3+2] = v.v[1];
+		}
+	}
+
+	gDeferredSunProgram.uniform3fv("offset", slice, offset);
+	gDeferredSunProgram.uniform2f("screenRes", mDeferredLight[0].getWidth(), mDeferredLight[0].getHeight());
+
+	setupHWLights(NULL); //to set mSunDir;
+
+	glPushMatrix();
+	glLoadIdentity();
+	glMatrixMode(GL_PROJECTION);
+	glPushMatrix();
+	glLoadIdentity();
+
+	LLVector4 dir(mSunDir, 0.f);
+
+	glh::vec4f tc(dir.mV);
+	mat.mult_matrix_vec(tc);
+	glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], 0);
+	glColor3f(1,1,1);
+
+	glVertexPointer(2, GL_FLOAT, 0, vert);
+	{
+		LLGLDisable blend(GL_BLEND);
+		LLGLDepthTest depth(GL_FALSE);
+		stop_glerror();
+		glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
+		stop_glerror();
+	}
+	
+	unbindDeferredShader(gDeferredSunProgram);
+
+	mDeferredLight[0].flush();
+
+	//blur lightmap
+	mDeferredLight[1].bindTarget();
+
+	//mDeferredLight[1].copyContents(mDeferredScreen, 0, 0, mDeferredScreen.getWidth(), mDeferredScreen.getHeight(),
+	//					0, 0, mDeferredLight[0].getWidth(), mDeferredLight[0].getHeight(), GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);	
+	
+	bindDeferredShader(gDeferredBlurLightProgram);
+
+	LLVector3 gauss[32]; // xweight, yweight, offset
+
+	LLVector3 go = gSavedSettings.getVector3("RenderShadowGaussian");
+	U32 kern_length = llclamp(gSavedSettings.getU32("RenderShadowBlurSamples"), (U32) 1, (U32) 16)*2 - 1;
+	F32 blur_size = gSavedSettings.getF32("RenderShadowBlurSize");
+
+	// sample symmetrically with the middle sample falling exactly on 0.0
+	F32 x = -(kern_length/2.0f) + 0.5f;
+
+	for (U32 i = 0; i < kern_length; i++)
+	{
+		gauss[i].mV[0] = llgaussian(x, go.mV[0]);
+		gauss[i].mV[1] = llgaussian(x, go.mV[1]);
+		gauss[i].mV[2] = x;
+		x += 1.f;
+	}
+	/* swap the x=0 position to the start of gauss[] so we can
+	   treat it specially as an optimization. */
+	LLVector3 swap;
+	swap = gauss[kern_length/2];
+	gauss[kern_length/2] = gauss[0];
+	gauss[0] = swap;
+	llassert(gauss[0].mV[2] == 0.0f);
+
+	gDeferredBlurLightProgram.uniform2f("delta", 1.f, 0.f);
+	gDeferredBlurLightProgram.uniform3fv("kern[0]", kern_length, gauss[0].mV);
+	gDeferredBlurLightProgram.uniform3fv("kern", kern_length, gauss[0].mV);
+	gDeferredBlurLightProgram.uniform1i("kern_length", kern_length);
+	gDeferredBlurLightProgram.uniform1f("kern_scale", blur_size * (kern_length/2.f - 0.5f));
+
+	{
+		LLGLDisable blend(GL_BLEND);
+		LLGLDepthTest depth(GL_FALSE);
+		stop_glerror();
+		glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
+		stop_glerror();
+	}
+	
+	mDeferredLight[1].flush();
+	unbindDeferredShader(gDeferredBlurLightProgram);
+
+	bindDeferredShader(gDeferredBlurLightProgram, 1);
+	mDeferredLight[0].bindTarget();
+
+	gDeferredBlurLightProgram.uniform2f("delta", 0.f, 1.f);
+	gDeferredBlurLightProgram.uniform3fv("kern[0]", kern_length, gauss[0].mV);
+	gDeferredBlurLightProgram.uniform3fv("kern", kern_length, gauss[0].mV);
+	gDeferredBlurLightProgram.uniform1i("kern_length", kern_length);
+	gDeferredBlurLightProgram.uniform1f("kern_scale", blur_size * (kern_length/2.f - 0.5f));
+
+	{
+		LLGLDisable blend(GL_BLEND);
+		LLGLDepthTest depth(GL_FALSE);
+		stop_glerror();
+		glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+		stop_glerror();
+	}
+	mDeferredLight[0].flush();
+	unbindDeferredShader(gDeferredBlurLightProgram);
+
+	stop_glerror();
+	glPopMatrix();
+	stop_glerror();
+	glMatrixMode(GL_MODELVIEW);
+	stop_glerror();
+	glPopMatrix();
+	stop_glerror();
+
+	//copy depth and stencil from deferred screen
+	//mScreen.copyContents(mDeferredScreen, 0, 0, mDeferredScreen.getWidth(), mDeferredScreen.getHeight(),
+	//					0, 0, mScreen.getWidth(), mScreen.getHeight(), GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
+
+	mScreen.bindTarget();
+	mScreen.clear(GL_COLOR_BUFFER_BIT);
+		
+	bindDeferredShader(gDeferredSoftenProgram);	
+	{
+		LLGLDepthTest depth(GL_FALSE);
+		LLGLDisable blend(GL_BLEND);
+		LLGLDisable test(GL_ALPHA_TEST);
+
+		//full screen blit
+		glPushMatrix();
+		glLoadIdentity();
+		glMatrixMode(GL_PROJECTION);
+		glPushMatrix();
+		glLoadIdentity();
+
+		glVertexPointer(2, GL_FLOAT, 0, vert);
+		
+		glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
+		
+		glPopMatrix();
+		glMatrixMode(GL_MODELVIEW);
+		glPopMatrix();
+	}
+
+	unbindDeferredShader(gDeferredSoftenProgram);
+
+	bindDeferredShader(gDeferredLightProgram);
+
+	std::list<LLVector4> fullscreen_lights;
+	std::list<LLVector4> light_colors;
+
+	F32 v[24];
+	glVertexPointer(3, GL_FLOAT, 0, v);
+	{
+		LLGLDepthTest depth(GL_TRUE, GL_FALSE);
+		for (LLDrawable::drawable_set_t::iterator iter = mLights.begin(); iter != mLights.end(); ++iter)
+		{
+			LLDrawable* drawablep = *iter;
+			
+			LLVOVolume* volume = drawablep->getVOVolume();
+			if (!volume)
+			{
+				continue;
+			}
+
+			LLVector3 center = drawablep->getPositionAgent();
+			F32* c = center.mV;
+			F32 s = volume->getLightRadius()*1.5f;
+
+			if (LLViewerCamera::getInstance()->AABBInFrustumNoFarClip(center, LLVector3(s,s,s)) == 0)
+			{
+				continue;
+			}
+
+			sVisibleLightCount++;
+			glh::vec3f tc(c);
+			mat.mult_matrix_vec(tc);
+			
+			LLColor3 col = volume->getLightColor();
+			col *= volume->getLightIntensity();
+
+			//vertex positions are encoded so the 3 bits of their vertex index 
+			//correspond to their axis facing, with bit position 3,2,1 matching
+			//axis facing x,y,z, bit set meaning positive facing, bit clear 
+			//meaning negative facing
+			v[0] = c[0]-s; v[1]  = c[1]-s; v[2]  = c[2]-s;  // 0 - 0000 
+			v[3] = c[0]-s; v[4]  = c[1]-s; v[5]  = c[2]+s;  // 1 - 0001
+			v[6] = c[0]-s; v[7]  = c[1]+s; v[8]  = c[2]-s;  // 2 - 0010
+			v[9] = c[0]-s; v[10] = c[1]+s; v[11] = c[2]+s;  // 3 - 0011
+																							   
+			v[12] = c[0]+s; v[13] = c[1]-s; v[14] = c[2]-s; // 4 - 0100
+			v[15] = c[0]+s; v[16] = c[1]-s; v[17] = c[2]+s; // 5 - 0101
+			v[18] = c[0]+s; v[19] = c[1]+s; v[20] = c[2]-s; // 6 - 0110
+			v[21] = c[0]+s; v[22] = c[1]+s; v[23] = c[2]+s; // 7 - 0111
+
+			if (LLViewerCamera::getInstance()->getOrigin().mV[0] > c[0] + s + 0.2f ||
+				LLViewerCamera::getInstance()->getOrigin().mV[0] < c[0] - s - 0.2f ||
+				LLViewerCamera::getInstance()->getOrigin().mV[1] > c[1] + s + 0.2f ||
+				LLViewerCamera::getInstance()->getOrigin().mV[1] < c[1] - s - 0.2f ||
+				LLViewerCamera::getInstance()->getOrigin().mV[2] > c[2] + s + 0.2f ||
+				LLViewerCamera::getInstance()->getOrigin().mV[2] < c[2] - s - 0.2f)
+			{ //draw box if camera is outside box
+				glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], s*s);
+				glColor4f(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f);
+				glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8,
+					GL_UNSIGNED_BYTE, get_box_fan_indices(LLViewerCamera::getInstance(), center));
+			}
+			else
+			{	
+				fullscreen_lights.push_back(LLVector4(tc.v[0], tc.v[1], tc.v[2], s*s));
+				light_colors.push_back(LLVector4(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f));
+			}
+		}
+	}
+
+	unbindDeferredShader(gDeferredLightProgram);
+
+	if (!fullscreen_lights.empty())
+	{
+		bindDeferredShader(gDeferredMultiLightProgram);
+		LLGLDepthTest depth(GL_FALSE);
+
+		//full screen blit
+		glPushMatrix();
+		glLoadIdentity();
+		glMatrixMode(GL_PROJECTION);
+		glPushMatrix();
+		glLoadIdentity();
+
+		U32 count = 0;
+
+		LLVector4 light[16];
+		LLVector4 col[16];
+
+		glVertexPointer(2, GL_FLOAT, 0, vert);
+
+		while (!fullscreen_lights.empty())
+		{
+			light[count] = fullscreen_lights.front();
+			fullscreen_lights.pop_front();
+			col[count] = light_colors.front();
+			light_colors.pop_front();
+
+			count++;
+			if (count == 16 || fullscreen_lights.empty())
+			{
+				gDeferredMultiLightProgram.uniform1i("light_count", count);
+				gDeferredMultiLightProgram.uniform4fv("light[0]", count, (GLfloat*) light);
+				gDeferredMultiLightProgram.uniform4fv("light", count, (GLfloat*) light);
+				gDeferredMultiLightProgram.uniform4fv("light_col[0]", count, (GLfloat*) col);
+				gDeferredMultiLightProgram.uniform4fv("light_col", count, (GLfloat*) col);
+				count = 0;
+				glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
+			}
+		}
+		
+		
+		glPopMatrix();
+		glMatrixMode(GL_MODELVIEW);
+		glPopMatrix();
+
+		unbindDeferredShader(gDeferredMultiLightProgram);
+	}
+	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+	{ //render non-deferred geometry
+		LLGLDisable blend(GL_BLEND);
+		LLGLDisable stencil(GL_STENCIL_TEST);
+
+		U32 render_mask = mRenderTypeMask;
+		mRenderTypeMask =	mRenderTypeMask & 
+							((1 << LLPipeline::RENDER_TYPE_SKY) |
+							(1 << LLPipeline::RENDER_TYPE_CLOUDS) |
+							(1 << LLPipeline::RENDER_TYPE_WL_SKY) |
+							(1 << LLPipeline::RENDER_TYPE_ALPHA) |
+							(1 << LLPipeline::RENDER_TYPE_AVATAR) |
+							(1 << LLPipeline::RENDER_TYPE_WATER) |
+							(1 << LLPipeline::RENDER_TYPE_FULLBRIGHT) |
+							(1 << LLPipeline::RENDER_TYPE_VOLUME) |
+							(1 << LLPipeline::RENDER_TYPE_GLOW) |
+							(1 << LLPipeline::RENDER_TYPE_BUMP));
+		
+		renderGeomPostDeferred(*LLViewerCamera::getInstance());
+		mRenderTypeMask = render_mask;
+	}
+
+	mScreen.flush();
+						
+}
+
+void LLPipeline::unbindDeferredShader(LLGLSLShader &shader)
+{
+	stop_glerror();
+	shader.disableTexture(LLViewerShaderMgr::DEFERRED_POSITION, LLTexUnit::TT_RECT_TEXTURE);
+	shader.disableTexture(LLViewerShaderMgr::DEFERRED_NORMAL, LLTexUnit::TT_RECT_TEXTURE);
+	shader.disableTexture(LLViewerShaderMgr::DEFERRED_DIFFUSE, LLTexUnit::TT_RECT_TEXTURE);
+	shader.disableTexture(LLViewerShaderMgr::DEFERRED_SPECULAR, LLTexUnit::TT_RECT_TEXTURE);
+	shader.disableTexture(LLViewerShaderMgr::DEFERRED_DEPTH, LLTexUnit::TT_RECT_TEXTURE);
+	shader.disableTexture(LLViewerShaderMgr::DEFERRED_LIGHT, LLTexUnit::TT_RECT_TEXTURE);
+	for (U32 i = 0; i < 4; i++)
+	{
+		if (shader.disableTexture(LLViewerShaderMgr::DEFERRED_SHADOW0+i) > -1)
+		{
+			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
+		}
+	}
+	shader.disableTexture(LLViewerShaderMgr::DEFERRED_NOISE);
+
+	S32 channel = shader.disableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP);
+	if (channel > -1)
+	{
+		LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
+		if (cube_map)
+		{
+			cube_map->disable();
+		}
+	}
+	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+	gGL.getTexUnit(0)->activate();
+	shader.unbind();
+}
+
+inline float sgn(float a)
+{
+    if (a > 0.0F) return (1.0F);
+    if (a < 0.0F) return (-1.0F);
+    return (0.0F);
+}
+
+void LLPipeline::generateWaterReflection(LLCamera& camera_in)
+{
+	if (LLPipeline::sWaterReflections && assertInitialized() && LLDrawPoolWater::sNeedsReflectionUpdate)
+	{
+		LLVOAvatar* agent = gAgent.getAvatarObject();
+		if (gAgent.getCameraAnimating() || gAgent.getCameraMode() != CAMERA_MODE_MOUSELOOK)
+		{
+			agent = NULL;
+		}
+
+		if (agent)
+		{
+			agent->updateAttachmentVisibility(CAMERA_MODE_THIRD_PERSON);
+		}
+		LLVertexBuffer::unbind();
+
+		LLGLState::checkStates();
+		LLGLState::checkTextureChannels();
+		LLGLState::checkClientArrays();
+
+		LLCamera camera = camera_in;
+		camera.setFar(camera.getFar()*0.87654321f);
+		LLPipeline::sReflectionRender = TRUE;
+		S32 occlusion = LLPipeline::sUseOcclusion;
+		LLPipeline::sUseOcclusion = llmin(occlusion, 1);
+		
+		U32 type_mask = gPipeline.mRenderTypeMask;
+
+		glh::matrix4f projection = glh_get_current_projection();
+		glh::matrix4f mat;
+
+		stop_glerror();
+		LLPlane plane;
 
 		F32 height = gAgent.getRegion()->getWaterHeight(); 
 		F32 to_clip = fabsf(camera.getOrigin().mV[2]-height);
@@ -5127,15 +5873,15 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 			//initial sky pass (no user clip plane)
 			{ //mask out everything but the sky
 				U32 tmp = mRenderTypeMask;
-				mRenderTypeMask &= ((1 << LLPipeline::RENDER_TYPE_SKY) |
-									(1 << LLPipeline::RENDER_TYPE_CLOUDS) |
+				mRenderTypeMask = tmp & ((1 << LLPipeline::RENDER_TYPE_SKY) |
 									(1 << LLPipeline::RENDER_TYPE_WL_SKY));
-
 				static LLCullResult result;
 				updateCull(camera, result);
 				stateSort(camera, result);
+				mRenderTypeMask = tmp & ((1 << LLPipeline::RENDER_TYPE_SKY) |
+									(1 << LLPipeline::RENDER_TYPE_CLOUDS) |
+									(1 << LLPipeline::RENDER_TYPE_WL_SKY));
 				renderGeom(camera, TRUE);
-
 				mRenderTypeMask = tmp;
 			}
 
@@ -5227,6 +5973,7 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 		last_update = LLDrawPoolWater::sNeedsReflectionUpdate && LLDrawPoolWater::sNeedsDistortionUpdate;
 
 		LLRenderTarget::unbindTarget();
+
 		LLPipeline::sReflectionRender = FALSE;
 
 		if (!LLRenderTarget::sUseFBO)
@@ -5245,7 +5992,422 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 		LLGLState::checkStates();
 		LLGLState::checkTextureChannels();
 		LLGLState::checkClientArrays();
+
+		if (agent)
+		{
+			agent->updateAttachmentVisibility(gAgent.getCameraMode());
+		}
+	}
+}
+
+glh::matrix4f look(const LLVector3 pos, const LLVector3 dir, const LLVector3 up)
+{
+	glh::matrix4f ret;
+
+	LLVector3 dirN;
+	LLVector3 upN;
+	LLVector3 lftN;
+
+	lftN = dir % up;
+	lftN.normVec();
+	
+	upN = lftN % dir;
+	upN.normVec();
+	
+	dirN = dir;
+	dirN.normVec();
+	
+
+	ret.m[ 0] = lftN[0];
+	ret.m[ 1] = upN[0];
+	ret.m[ 2] = -dirN[0];
+	ret.m[ 3] = 0.f;
+
+	ret.m[ 4] = lftN[1];
+	ret.m[ 5] = upN[1];
+	ret.m[ 6] = -dirN[1];
+	ret.m[ 7] = 0.f;
+
+	ret.m[ 8] = lftN[2];
+	ret.m[ 9] = upN[2];
+	ret.m[10] = -dirN[2];
+	ret.m[11] = 0.f;
+
+	ret.m[12] = -(lftN*pos);
+	ret.m[13] = -(upN*pos);
+	ret.m[14] = dirN*pos;
+	ret.m[15] = 1.f;
+
+	return ret;
+}
+
+glh::matrix4f scale_translate_to_fit(const LLVector3 min, const LLVector3 max)
+{
+	glh::matrix4f ret;
+	ret.m[ 0] = 2/(max[0]-min[0]);
+	ret.m[ 4] = 0;
+	ret.m[ 8] = 0;
+	ret.m[12] = -(max[0]+min[0])/(max[0]-min[0]);
+
+	ret.m[ 1] = 0;
+	ret.m[ 5] = 2/(max[1]-min[1]);
+	ret.m[ 9] = 0;
+	ret.m[13] = -(max[1]+min[1])/(max[1]-min[1]);
+
+	ret.m[ 2] = 0;
+	ret.m[ 6] = 0;
+	ret.m[10] = 2/(max[2]-min[2]);
+	ret.m[14] = -(max[2]+min[2])/(max[2]-min[2]);
+
+	ret.m[ 3] = 0;
+	ret.m[ 7] = 0;
+	ret.m[11] = 0;
+	ret.m[15] = 1;
+
+	return ret;
+}
+
+void LLPipeline::generateSunShadow(LLCamera& camera)
+{
+
+	if (!sRenderDeferred)
+	{
+		return;
+	}
+
+	//temporary hack to disable shadows but keep local lights
+	static BOOL clear = TRUE;
+	BOOL gen_shadow = gSavedSettings.getBOOL("RenderDeferredSunShadow");
+	if (!gen_shadow)
+	{
+		if (clear)
+		{
+			clear = FALSE;
+			for (U32 i = 0; i < 4; i++)
+			{
+				mSunShadow[i].bindTarget();
+				mSunShadow[i].clear();
+				mSunShadow[i].flush();
+			}
+		}
+		return;
+	}
+	clear = TRUE;
+
+	gGL.setColorMask(false, false);
+
+	//get sun view matrix
+	
+	F32 range = 128.f;
+
+	//store current projection/modelview matrix
+	glh::matrix4f saved_proj = glh_get_current_projection();
+	glh::matrix4f saved_view = glh_get_current_modelview();
+	glh::matrix4f inv_view = saved_view.inverse();
+
+	glh::matrix4f view[4];
+	glh::matrix4f proj[4];
+	LLVector3 up;
+
+	//clip contains parallel split distances for 3 splits
+	LLVector3 clip = gSavedSettings.getVector3("RenderShadowClipPlanes");
+
+	//far clip on last split is minimum of camera view distance and 128
+	mSunClipPlanes = LLVector4(clip, clip.mV[2] * clip.mV[2]/clip.mV[1]);
+
+	const LLPickInfo& pick_info = gViewerWindow->getLastPick();
+
+	if (!pick_info.mPosGlobal.isExactlyZero())
+	{ //squish nearest frustum based on alt-zoom (tighten up nearest frustum when focusing on tiny object
+		F32 focus_dist = (F32) (pick_info.mPosGlobal + LLVector3d(pick_info.mObjectOffset) - gAgent.getPosGlobalFromAgent(LLViewerCamera::getInstance()->getOrigin())).magVec();
+		mSunClipPlanes.mV[0] = llclamp(focus_dist*focus_dist, 2.f, mSunClipPlanes.mV[0]);
+	}
+		
+	// convenience array of 4 near clip plane distances
+	F32 dist[] = { 0.1f, mSunClipPlanes.mV[0], mSunClipPlanes.mV[1], mSunClipPlanes.mV[2], mSunClipPlanes.mV[3] };
+
+	//currently used for amount to extrude frusta corners for constructing shadow frusta
+	LLVector3 n = gSavedSettings.getVector3("RenderShadowNearDist");
+	F32 nearDist[] = { n.mV[0], n.mV[1], n.mV[2], n.mV[2] };
+
+	for (S32 j = 0; j < 4; j++)
+	{
+		//restore render matrices
+		glh_set_current_modelview(saved_view);
+		glh_set_current_projection(saved_proj);
+
+		//get center of far clip plane (for point of interest later)
+		LLVector3 center = camera.getOrigin() + camera.getAtAxis() * range;
+
+		LLVector3 eye = camera.getOrigin();
+
+		//camera used for shadow cull/render
+		LLCamera shadow_cam;
+		
+	    // perspective shadow map
+		glh::vec3f p[16];		//point cloud to be contained by shadow projection (light camera space)
+		glh::vec3f wp[16];		//point cloud to be contained by shadow projection (world space)
+		
+		LLVector3 lightDir = -mSunDir;
+		glh::vec3f light_dir(lightDir.mV);
+
+		//create light space camera matrix
+		LLVector3 at;
+		F32 dl = camera.getLeftAxis() * lightDir;
+		F32 du = camera.getUpAxis() * lightDir;
+
+		//choose an at axis such that up will be most aligned with lightDir
+		if (dl*dl < du*du)
+		{
+			at = lightDir%camera.getLeftAxis();
+		}
+		else
+		{
+			at = lightDir%camera.getUpAxis();
+		}
+
+		if (at * camera.getAtAxis() < 0)
+		{
+			at = -at;
+		}
+		
+		LLVector3 left = lightDir%at;
+		up = left%lightDir;
+		up.normVec();
+
+		//create world space camera frustum for this split
+		shadow_cam = camera;
+		shadow_cam.setFar(16.f);
+	
+		LLViewerCamera::updateFrustumPlanes(shadow_cam);
+
+		LLVector3* frust = shadow_cam.mAgentFrustum;
+
+		LLVector3 pn = shadow_cam.getAtAxis();
+		
+		LLVector3 frust_center;
+		
+		LLVector3 min, max;
+
+		//construct 8 corners of split frustum section
+		for (U32 i = 0; i < 4; i++)
+		{
+			LLVector3 delta = frust[i+4]-eye;
+			delta.normVec();
+			F32 dp = delta*pn;
+			frust[i] = eye + (delta*dist[j])/dp;
+			frust[i+4] = eye + (delta*dist[j+1])/dp;
+			frust_center += frust[i] + frust[i+4];
+		}
+
+		//get frustum center
+		frust_center /= 8.f;
+						
+		shadow_cam.calcAgentFrustumPlanes(frust);
+
+		
+		if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
+		{
+			mShadowCamera[j] = shadow_cam;
+		}
+
+		if (gPipeline.getVisibleExtents(shadow_cam, min, max))
+		{
+			//no possible shadow receivers
+			if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
+			{
+				mShadowExtents[j][0] = LLVector3();
+				mShadowExtents[j][1] = LLVector3();
+				mShadowCamera[j+4] = shadow_cam;
+			}
+
+			continue;
+		}
+
+		if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
+		{
+			mShadowExtents[j][0] = min;
+			mShadowExtents[j][1] = max;
+		}
+				
+		view[j] = look(frust_center-lightDir*nearDist[j], lightDir, up);
+		F32 shadow_dist = nearDist[j];
+
+		for (U32 i = 0; i < 8; i++)
+		{
+			//points in worldspace (wp) and light camera space (p)
+			//that must be included in shadow generation
+			wp[i] = glh::vec3f(frust[i].mV);
+			wp[i+8] = wp[i] - light_dir*shadow_dist;
+			view[j].mult_matrix_vec(wp[i], p[i]);
+			view[j].mult_matrix_vec(wp[i+8], p[i+8]);
+		}
+	
+		min = LLVector3(p[0].v);
+		max = LLVector3(p[0].v);
+
+		LLVector3 fmin = min;
+		LLVector3 fmax = max;
+
+		for (U32 i = 1; i < 16; i++)
+		{ //find camera space AABB of frustum in light camera space
+			update_min_max(min, max, LLVector3(p[i].v));
+			if (i < 8)
+			{
+				update_min_max(fmin, fmax, LLVector3(p[i].v));
+			}
+		}
+
+		//generate perspective matrix that contains frustum
+		//proj[j] = matrix_perspective(min, max);
+		proj[j] = gl_ortho(min.mV[0], max.mV[0],
+							min.mV[1], max.mV[1],
+							-max.mV[2], -min.mV[2]);
+						
+		shadow_cam.setFar(128.f);
+		shadow_cam.setOriginAndLookAt(eye, up, center);
+
+		glh_set_current_modelview(view[j]);
+		glh_set_current_projection(proj[j]);
+
+		LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE);
+
+		proj[j] = gl_ortho(fmin.mV[0], fmax.mV[0],
+						   fmin.mV[1], fmax.mV[1],
+						   -fmax.mV[2], -fmin.mV[2]);
+
+		//translate and scale to from [-1, 1] to [0, 1]
+		glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f,
+						0.f, 0.5f, 0.f, 0.5f,
+						0.f, 0.f, 0.5f, 0.5f,
+						0.f, 0.f, 0.f, 1.f);
+
+		glh_set_current_modelview(view[j]);
+		glh_set_current_projection(proj[j]);
+
+		mSunShadowMatrix[j] = trans*proj[j]*view[j]*inv_view;
+		
+		U32 type_mask = mRenderTypeMask;
+		mRenderTypeMask = type_mask & ((1<<LLPipeline::RENDER_TYPE_SIMPLE) |
+									   (1<<LLPipeline::RENDER_TYPE_ALPHA) |
+									   (1<<LLPipeline::RENDER_TYPE_GRASS) |
+									   (1<<LLPipeline::RENDER_TYPE_FULLBRIGHT) |
+									   (1<<LLPipeline::RENDER_TYPE_BUMP) |
+									   (1<<LLPipeline::RENDER_TYPE_VOLUME) |
+									   (1<<LLPipeline::RENDER_TYPE_AVATAR) |
+									   (1<<LLPipeline::RENDER_TYPE_TREE) | 
+									   (1<<LLPipeline::RENDER_TYPE_TERRAIN) |
+									   0);
+
+		//clip out geometry on the same side of water as the camera
+		static LLCullResult result;
+		S32 occlude = LLPipeline::sUseOcclusion;
+		LLPipeline::sUseOcclusion = 1;
+		LLPipeline::sShadowRender = TRUE;
+		//hack to prevent LOD updates from using sun camera origin
+		shadow_cam.setOrigin(camera.getOrigin());
+		updateCull(shadow_cam, result);
+		stateSort(shadow_cam, result);
+		
+		if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
+		{
+			LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE);
+			mShadowCamera[j+4] = shadow_cam;
+		}
+
+		LLFastTimer t(LLFastTimer::FTM_SHADOW_RENDER);
+
+		stop_glerror();
+
+		mSunShadow[j].bindTarget();
+		mSunShadow[j].getViewport(gGLViewport);
+
+		{
+			LLGLDepthTest depth(GL_TRUE);
+			mSunShadow[j].clear();
+		}
+
+		U32 types[] = { LLRenderPass::PASS_SIMPLE, LLRenderPass::PASS_FULLBRIGHT, LLRenderPass::PASS_SHINY, LLRenderPass::PASS_BUMP };
+		LLGLEnable cull(GL_CULL_FACE);
+
+		//generate sun shadow map
+		glMatrixMode(GL_PROJECTION);
+		glPushMatrix();
+		glLoadMatrixf(proj[j].m);
+		glMatrixMode(GL_MODELVIEW);
+		glPushMatrix();
+		glLoadMatrixf(view[j].m);
+
+		stop_glerror();
+		gGLLastMatrix = NULL;
+
+		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+				
+		glColor4f(1,1,1,1);
+		
+		glCullFace(GL_FRONT);
+
+		stop_glerror();
+
+		gGL.setColorMask(false, false);
+
+		gDeferredShadowProgram.bind();
+		{
+			LLFastTimer ftm(LLFastTimer::FTM_SHADOW_SIMPLE);
+			LLGLDisable test(GL_ALPHA_TEST);
+			gGL.getTexUnit(0)->disable();
+			for (U32 i = 0; i < sizeof(types)/sizeof(U32); ++i)
+			{
+				renderObjects(types[i], LLVertexBuffer::MAP_VERTEX, FALSE);
+			}
+			gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
+		}
+		
+		{
+			LLFastTimer ftm(LLFastTimer::FTM_SHADOW_ALPHA);
+			LLGLEnable test(GL_ALPHA_TEST);
+			gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.6f);
+			renderObjects(LLRenderPass::PASS_ALPHA_SHADOW, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR, TRUE);
+			glColor4f(1,1,1,1);
+			renderObjects(LLRenderPass::PASS_GRASS, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, TRUE);
+			gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
+		}
+		
+		gDeferredShadowProgram.unbind();
+
+		renderGeomShadow(shadow_cam);
+
+		gGL.setColorMask(true, true);
+
+		glCullFace(GL_BACK);
+		LLPipeline::sUseOcclusion = occlude;
+		LLPipeline::sShadowRender = FALSE;
+		mRenderTypeMask = type_mask;
+		
+		glMatrixMode(GL_PROJECTION);
+		glPopMatrix();
+		glMatrixMode(GL_MODELVIEW);
+		glPopMatrix();
+		gGLLastMatrix = NULL;
+
+		mSunShadow[j].flush();
+	}
+
+	if (!gSavedSettings.getBOOL("CameraOffset"))
+	{
+		glh_set_current_modelview(saved_view);
+		glh_set_current_projection(saved_proj);
 	}
+	else
+	{
+		glh_set_current_modelview(view[1]);
+		glh_set_current_projection(proj[1]);
+		glLoadMatrixf(view[1].m);
+		glMatrixMode(GL_PROJECTION);
+		glLoadMatrixf(proj[1].m);
+		glMatrixMode(GL_MODELVIEW);
+	}
+	gGL.setColorMask(true, false);
 }
 
 void LLPipeline::renderGroups(LLRenderPass* pass, U32 type, U32 mask, BOOL texture)
@@ -5265,6 +6427,10 @@ void LLPipeline::renderGroups(LLRenderPass* pass, U32 type, U32 mask, BOOL textu
 
 void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 {
+	LLGLState::checkStates();
+	LLGLState::checkTextureChannels();
+	LLGLState::checkClientArrays();
+
 	static LLCullResult result;
 	result.clear();
 	grabReferences(result);
@@ -5290,6 +6456,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 				(1<<LLPipeline::RENDER_TYPE_BUMP) |
 				(1<<LLPipeline::RENDER_TYPE_GRASS) |
 				(1<<LLPipeline::RENDER_TYPE_SIMPLE) |
+				(1<<LLPipeline::RENDER_TYPE_FULLBRIGHT) |
 				(1<<LLPipeline::RENDER_TYPE_ALPHA) | 
 				(1<<LLPipeline::RENDER_TYPE_INVISIBLE);
 	}
@@ -5300,7 +6467,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 
 	S32 occlusion = sUseOcclusion;
 	sUseOcclusion = 0;
-	sReflectionRender = TRUE;
+	sReflectionRender = sRenderDeferred ? FALSE : TRUE;
 	sImpostorRender = TRUE;
 
 	markVisible(avatar->mDrawable, *LLViewerCamera::getInstance());
@@ -5377,10 +6544,17 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 	if (!avatar->mImpostor.isComplete() || resX != avatar->mImpostor.getWidth() ||
 		resY != avatar->mImpostor.getHeight())
 	{
-		avatar->mImpostor.allocate(resX,resY,GL_RGBA,TRUE);
+		if (LLPipeline::sRenderDeferred)
+		{
+			avatar->mImpostor.allocate(resX,resY,GL_RGBA16F_ARB,TRUE,TRUE);
+			addDeferredAttachments(avatar->mImpostor);
+		}
+		else
+		{
+			avatar->mImpostor.allocate(resX,resY,GL_RGBA,TRUE,TRUE);
+		}
 		gGL.getTexUnit(0)->bind(&avatar->mImpostor);
-		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+		gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
 		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 	}
 
@@ -5388,8 +6562,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 		LLGLEnable scissor(GL_SCISSOR_TEST);
 		glScissor(0, 0, resX, resY);
 		avatar->mImpostor.bindTarget();
-		avatar->mImpostor.getViewport(gGLViewport);
-		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+		avatar->mImpostor.clear();
 	}
 	
 	LLGLEnable stencil(GL_STENCIL_TEST);
@@ -5397,11 +6570,20 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 	glStencilFunc(GL_ALWAYS, 1, 0xFFFFFFFF);
 	glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
 
-	renderGeom(camera);
+	if (LLPipeline::sRenderDeferred)
+	{
+		stop_glerror();
+		renderGeomDeferred(camera);
+	}
+	else
+	{
+		renderGeom(camera);
+	}
 	
 	glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
 	glStencilFunc(GL_EQUAL, 1, 0xFFFFFF);
 
+	if (!sRenderDeferred || muted)
 	{
 		LLVector3 left = camera.getLeftAxis()*tdim.mV[0]*2.f;
 		LLVector3 up = camera.getUpAxis()*tdim.mV[1]*2.f;
@@ -5432,7 +6614,6 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 		gGL.end();
 		gGL.flush();
 
-
 		gGL.setSceneBlendType(LLRender::BT_ALPHA);
 	}
 
@@ -5454,6 +6635,11 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 
 	avatar->mNeedsImpostorUpdate = FALSE;
 	avatar->cacheImpostorValues();
+
+	LLVertexBuffer::unbind();
+	LLGLState::checkStates();
+	LLGLState::checkTextureChannels();
+	LLGLState::checkClientArrays();
 }
 
 BOOL LLPipeline::hasRenderBatches(const U32 type) const
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index 5ab38317532fad9cc70c32822976b9a29e6cdadd..e8673c7d4c34518a69ebe97bd289041aabf35adf 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -57,6 +57,7 @@ class LLRenderFunc;
 class LLCubeMap;
 class LLCullResult;
 class LLVOAvatar;
+class LLGLSLShader;
 
 typedef enum e_avatar_skinning_method
 {
@@ -75,6 +76,7 @@ glh::matrix4f glh_get_current_projection();
 void glh_set_current_projection(glh::matrix4f& mat);
 glh::matrix4f gl_ortho(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat znear, GLfloat zfar);
 glh::matrix4f gl_perspective(GLfloat fovy, GLfloat aspect, GLfloat zNear, GLfloat zFar);
+glh::matrix4f gl_lookat(LLVector3 eye, LLVector3 center, LLVector3 up);
 
 class LLPipeline
 {
@@ -88,14 +90,13 @@ class LLPipeline
 	void resizeScreenTexture();
 	void releaseGLBuffers();
 	void createGLBuffers();
+	void allocateScreenBuffer(U32 resX, U32 resY);
 
 	void resetVertexBuffers(LLDrawable* drawable);
 	void setUseVBO(BOOL use_vbo);
 	void generateImpostor(LLVOAvatar* avatar);
-	void generateReflectionMap(LLCubeMap* cube_map, LLCamera& camera);
-	void blurReflectionMap(LLCubeMap* cube_in, LLCubeMap* cube_out);
 	void bindScreenToTexture();
-	void renderBloom(BOOL for_snapshot);
+	void renderBloom(BOOL for_snapshot, F32 zoom_factor = 1.f, int subfield = 0);
 
 	void init();
 	void cleanup();
@@ -176,7 +177,11 @@ class LLPipeline
 	void updateMoveNormalAsync(LLDrawable* drawablep);
 	void updateMovedList(LLDrawable::drawable_vector_t& move_list);
 	void updateMove();
+	BOOL visibleObjectsInFrustum(LLCamera& camera);
+	BOOL getVisibleExtents(LLCamera& camera, LLVector3 &min, LLVector3& max);
 	void updateCull(LLCamera& camera, LLCullResult& result, S32 water_clip = 0);  //if water_clip is 0, ignore water plane, 1, cull to above plane, -1, cull to below plane
+	void createObjects(F32 max_dtime);
+	void createObject(LLViewerObject* vobj);
 	void updateGeom(F32 max_dtime);
 
 	//calculate pixel area of given box from vantage point of given camera
@@ -195,9 +200,15 @@ class LLPipeline
 	void grabReferences(LLCullResult& result);
 
 	void renderGeom(LLCamera& camera, BOOL forceVBOUpdate = FALSE);
-	void renderGeomDeferred();
-
+	void renderGeomDeferred(LLCamera& camera);
+	void renderGeomPostDeferred(LLCamera& camera);
+	void renderGeomShadow(LLCamera& camera);
+	void bindDeferredShader(LLGLSLShader& shader, U32 light_index = 0);
+	void unbindDeferredShader(LLGLSLShader& shader);
+	void renderDeferredLighting();
+	
 	void generateWaterReflection(LLCamera& camera);
+	void generateSunShadow(LLCamera& camera);
 	void renderHighlights();
 	void renderDebug();
 
@@ -230,7 +241,7 @@ class LLPipeline
 	LLCullResult::drawinfo_list_t::iterator endRenderMap(U32 type);
 	LLCullResult::sg_list_t::iterator beginAlphaGroups();
 	LLCullResult::sg_list_t::iterator endAlphaGroups();
-
+	
 	void addTrianglesDrawn(S32 count);
 	BOOL hasRenderType(const U32 type) const				{ return (type && (mRenderTypeMask & (1<<type))) ? TRUE : FALSE; }
 	BOOL hasRenderDebugFeatureMask(const U32 mask) const	{ return (mRenderDebugFeatureMask & mask) ? TRUE : FALSE; }
@@ -276,6 +287,8 @@ class LLPipeline
 	static void toggleRenderHighlights(void* data);
 	static BOOL getRenderHighlights(void* data);
 
+	static void updateRenderDeferred();
+
 private:
 	void unloadShaders();
 	void addToQuickLookup( LLDrawPool* new_poolp );
@@ -295,6 +308,8 @@ class LLPipeline
 		RENDER_TYPE_GROUND		= LLDrawPool::POOL_GROUND,	
 		RENDER_TYPE_TERRAIN		= LLDrawPool::POOL_TERRAIN,
 		RENDER_TYPE_SIMPLE		= LLDrawPool::POOL_SIMPLE,
+		RENDER_TYPE_GRASS		= LLDrawPool::POOL_GRASS,
+		RENDER_TYPE_FULLBRIGHT	= LLDrawPool::POOL_FULLBRIGHT,
 		RENDER_TYPE_BUMP		= LLDrawPool::POOL_BUMP,
 		RENDER_TYPE_AVATAR		= LLDrawPool::POOL_AVATAR,
 		RENDER_TYPE_TREE		= LLDrawPool::POOL_TREE,
@@ -306,7 +321,6 @@ class LLPipeline
 		// Following are object types (only used in drawable mRenderType)
 		RENDER_TYPE_HUD = LLDrawPool::NUM_POOL_TYPES,
 		RENDER_TYPE_VOLUME,
-		RENDER_TYPE_GRASS,
 		RENDER_TYPE_PARTICLES,
 		RENDER_TYPE_CLOUDS,
 	};
@@ -326,24 +340,26 @@ class LLPipeline
 
 	enum LLRenderDebugMask
 	{
-		RENDER_DEBUG_COMPOSITION		= 0x000020,
-		RENDER_DEBUG_VERIFY				= 0x000080,
-		RENDER_DEBUG_BBOXES				= 0x000200,
-		RENDER_DEBUG_OCTREE				= 0x000400,
-		RENDER_DEBUG_PICKING			= 0x000800,
-		RENDER_DEBUG_OCCLUSION			= 0x001000,
-		RENDER_DEBUG_POINTS				= 0x002000,
-		RENDER_DEBUG_TEXTURE_PRIORITY	= 0x004000,
-		RENDER_DEBUG_TEXTURE_AREA		= 0x008000,
-		RENDER_DEBUG_FACE_AREA			= 0x010000,
-		RENDER_DEBUG_PARTICLES			= 0x020000,
-		RENDER_DEBUG_GLOW				= 0x040000,
-		RENDER_DEBUG_TEXTURE_ANIM		= 0x080000,
-		RENDER_DEBUG_LIGHTS				= 0x100000,
-		RENDER_DEBUG_BATCH_SIZE			= 0x200000,
-		RENDER_DEBUG_RAYCAST            = 0x400000,
-		RENDER_DEBUG_SHAME				= 0x800000,
-		RENDER_DEBUG_SCULPTED           = 0x1000000
+		RENDER_DEBUG_COMPOSITION		= 0x0000001,
+		RENDER_DEBUG_VERIFY				= 0x0000002,
+		RENDER_DEBUG_BBOXES				= 0x0000004,
+		RENDER_DEBUG_OCTREE				= 0x0000008,
+		RENDER_DEBUG_PICKING			= 0x0000010,
+		RENDER_DEBUG_OCCLUSION			= 0x0000020,
+		RENDER_DEBUG_POINTS				= 0x0000040,
+		RENDER_DEBUG_TEXTURE_PRIORITY	= 0x0000080,
+		RENDER_DEBUG_TEXTURE_AREA		= 0x0000100,
+		RENDER_DEBUG_FACE_AREA			= 0x0000200,
+		RENDER_DEBUG_PARTICLES			= 0x0000400,
+		RENDER_DEBUG_GLOW				= 0x0000800,
+		RENDER_DEBUG_TEXTURE_ANIM		= 0x0001000,
+		RENDER_DEBUG_LIGHTS				= 0x0002000,
+		RENDER_DEBUG_BATCH_SIZE			= 0x0004000,
+		RENDER_DEBUG_ALPHA_BINS			= 0x0008000,
+		RENDER_DEBUG_RAYCAST            = 0x0010000,
+		RENDER_DEBUG_SHAME				= 0x0020000,
+		RENDER_DEBUG_SHADOW_FRUSTA		= 0x0040000,
+		RENDER_DEBUG_SCULPTED           = 0x0080000,
 	};
 
 public:
@@ -376,11 +392,13 @@ class LLPipeline
 
 	static BOOL				sShowHUDAttachments;
 	static S32				sUseOcclusion;  // 0 = no occlusion, 1 = read only, 2 = read/write
+	static BOOL				sDelayVBUpdate;
 	static BOOL				sFastAlpha;
 	static BOOL				sDisableShaders; // if TRUE, rendering will be done without shaders
 	static BOOL				sRenderBump;
 	static BOOL				sUseFBO;
 	static BOOL				sUseFarClip;
+	static BOOL				sShadowRender;
 	static BOOL				sSkipUpdate; //skip lod updates
 	static BOOL				sWaterReflections;
 	static BOOL				sDynamicLOD;
@@ -393,10 +411,22 @@ class LLPipeline
 	static BOOL				sRenderFrameTest;
 	static BOOL				sRenderAttachedLights;
 	static BOOL				sRenderAttachedParticles;
-	
+	static BOOL				sRenderDeferred;
+	static S32				sVisibleLightCount;
+
 	//screen texture
 	LLRenderTarget			mScreen;
-	
+	LLRenderTarget			mDeferredScreen;
+	LLRenderTarget			mDeferredLight[2];
+	LLMultisampleBuffer		mSampleBuffer;
+
+	//sun shadow map
+	LLRenderTarget			mSunShadow[4];
+	LLCamera				mShadowCamera[8];
+	LLVector3				mShadowExtents[4][2];
+	glh::matrix4f			mSunShadowMatrix[4];
+	LLVector4				mSunClipPlanes;
+
 	LLVector2				mScreenScale;
 
 	//water reflection texture
@@ -408,20 +438,9 @@ class LLPipeline
 	//texture for making the glow
 	LLRenderTarget				mGlow[3];
 
-	//dynamic cube map scratch space
-	LLPointer<LLCubeMap>	mCubeBuffer;
-
-	//cube map anti-aliasing buffers
-	GLuint					mBlurCubeBuffer[3];
-	GLuint					mBlurCubeTexture[3];
+	//noise map
+	U32					mNoiseMap;
 
-	//frambuffer object for rendering dynamic cube maps
-	GLuint					mCubeFrameBuffer;
-	
-	//depth buffer object for rendering dynamic cube maps
-	GLuint					mCubeDepth;
-
-	
 	LLColor4				mSunDiffuse;
 	LLVector3				mSunDir;
 
@@ -481,6 +500,7 @@ class LLPipeline
 	//
 	LLDrawable::drawable_list_t 	mBuildQ1; // priority
 	LLDrawable::drawable_list_t 	mBuildQ2; // non-priority
+	LLViewerObject::vobj_list_t		mCreateQ;
 		
 	LLDrawable::drawable_set_t		mActiveQ;
 	
@@ -525,6 +545,8 @@ class LLPipeline
 	LLDrawPool*					mWaterPool;
 	LLDrawPool*					mGroundPool;
 	LLRenderPass*				mSimplePool;
+	LLRenderPass*				mGrassPool;
+	LLRenderPass*				mFullbrightPool;
 	LLDrawPool*					mInvisiblePool;
 	LLDrawPool*					mGlowPool;
 	LLDrawPool*					mBumpPool;
diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py
index f249f53105d54bca392728f98bcff699182d7a7e..249787ad8dcfc1826d76e071b389ce50cb796451 100755
--- a/indra/newview/viewer_manifest.py
+++ b/indra/newview/viewer_manifest.py
@@ -260,6 +260,12 @@ def construct(self):
                 "../win_updater/relwithdebinfo/windows-updater.exe"),
                   dst="updater.exe")
 
+        # For google-perftools tcmalloc allocator.
+        #if self.prefix(src="../../libraries/i686-win32/lib/release", dst=""):
+        #        self.path("libtcmalloc_minimal.dll")
+        #        self.end_prefix()
+
+
     def nsi_file_commands(self, install=True):
         def wpath(path):
             if path.endswith('/') or path.endswith(os.path.sep):
diff --git a/indra/test/CMakeLists.txt b/indra/test/CMakeLists.txt
index 3490ad6f6840404be15cd4101cbe60f3c4a1d8c6..01c291be7bc276b6e3ed2940cf5a21dd508ec6a6 100644
--- a/indra/test/CMakeLists.txt
+++ b/indra/test/CMakeLists.txt
@@ -118,8 +118,8 @@ target_link_libraries(test
 if (WINDOWS)
   set_target_properties(test
           PROPERTIES 
-          LINK_FLAGS "/NODEFAULTLIB:MSVCRT"
-          LINK_FLAGS_DEBUG "/NODEFAULTLIB:LIBCMT"
+          LINK_FLAGS "/NODEFAULTLIB:LIBCMT"
+          LINK_FLAGS_DEBUG "/NODEFAULTLIB:\"LIBCMT;LIBCMTD;MSVCRT\""
           )
 endif (WINDOWS)
 
diff --git a/indra/win_crash_logger/CMakeLists.txt b/indra/win_crash_logger/CMakeLists.txt
index d15377a26be3dfe9141fbf1e85be612cfabde806..27022680b861e9d8eb5e5b43742da74e3784a250 100644
--- a/indra/win_crash_logger/CMakeLists.txt
+++ b/indra/win_crash_logger/CMakeLists.txt
@@ -72,12 +72,17 @@ target_link_libraries(windows-crash-logger
     ${LLCOMMON_LIBRARIES}
     ${WINDOWS_LIBRARIES}
     ${DXGUID_LIBRARY}
+    user32
+    gdi32
+    ole32
+    oleaut32
+    Wldap32
     )
     
 if (WINDOWS)
     set_target_properties(windows-crash-logger
         PROPERTIES 
-        LINK_FLAGS "/NODEFAULTLIB:MSVCRT"
-        LINK_FLAGS_DEBUG "/NODEFAULTLIB:LIBCMT /NODEFAULTLIB:MSVCRTD"
+        LINK_FLAGS "/NODEFAULTLIB:LIBCMT"
+        LINK_FLAGS_DEBUG "/NODEFAULTLIB:\"LIBCMT;LIBCMTD;MSVCRT\""
         )
 endif (WINDOWS)
diff --git a/indra/win_updater/CMakeLists.txt b/indra/win_updater/CMakeLists.txt
index 6379d7c59bc6e11f9924816a895238a590d4785d..dedb7cfcc72ef1dd10cbf264657a0158fe214ba1 100644
--- a/indra/win_updater/CMakeLists.txt
+++ b/indra/win_updater/CMakeLists.txt
@@ -21,10 +21,15 @@ list(APPEND win_updater_SOURCE_FILES ${win_updater_HEADER_FILES})
 
 add_executable(windows-updater WIN32 ${win_updater_SOURCE_FILES})
 
-target_link_libraries(windows-updater wininet)
+target_link_libraries(windows-updater
+    wininet
+    user32
+    gdi32
+    shell32
+    )
 
 set_target_properties(windows-updater
     PROPERTIES
-    LINK_FLAGS "/NODEFAULTLIB:MSVCRT"
-    LINK_FLAGS_DEBUG "/NODEFAULTLIB:\"LIBCMT;MSVCRTD\""
+    LINK_FLAGS "/NODEFAULTLIB:LIBCMT"
+    LINK_FLAGS_DEBUG "/NODEFAULTLIB:\"LIBCMT;LIBCMTD;MSVCRT\""
     )
diff --git a/install.xml b/install.xml
index ad559a0e9064301db0620b27fd788eea8c0c6426..5870612653a7337510caf3f7eb3ee594b44b5fd3 100644
--- a/install.xml
+++ b/install.xml
@@ -127,9 +127,9 @@
           <key>windows</key>
           <map>
             <key>md5sum</key>
-            <string>352c46f39773b9415f8a9bf868c4c305</string>
+            <string>b9d23a69a25fdeed96dcc3bf696b6514</string>
             <key>url</key>
-            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/apr_suite-1.2.8-windows-20080618.tar.bz2</uri>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/apr_suite-1.2.12-windows-20080806.tar.bz2</uri>
           </map>
         </map>
       </map>
@@ -174,9 +174,9 @@
           <key>windows</key>
           <map>
             <key>md5sum</key>
-            <string>085a62de4c264d6a3718ad789aacd297</string>
+            <string>6a53b02a07527de680f1336e20f74f08</string>
             <key>url</key>
-            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/ares-1.3.0-windows-20080618.tar.bz2</uri>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/ares-1.4.0-windows-20080723.tar.bz2</uri>
           </map>
         </map>
       </map>
@@ -230,9 +230,9 @@
           <key>windows</key>
           <map>
             <key>md5sum</key>
-            <string>6f03592f4db4c177c7b255520283f547</string>
+            <string>d2b2ad9b46b9981c2a6be7c912bd17b4</string>
             <key>url</key>
-            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/boost-1.32.0-windows-20080613.tar.bz2</uri>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/boost-1.34.1-windows-20080723.tar.bz2</uri>
           </map>
         </map>
       </map>
@@ -277,9 +277,9 @@
           <key>windows</key>
           <map>
             <key>md5sum</key>
-            <string>fb42c5b40e34b043cee236aa216b141e</string>
+            <string>d391c33898a5dbc7e7537bf0d9cda36e</string>
             <key>url</key>
-            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/curl-7.16.0-windows-20080613.tar.bz2</uri>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/curl-7.18.1-windows-20080723.tar.bz2</uri>
           </map>
         </map>
       </map>
@@ -372,9 +372,9 @@
           <key>windows</key>
           <map>
             <key>md5sum</key>
-            <string>abd100b16dbe4621019a229af0411f5d</string>
+            <string>cca5ca3759f645d4a124d4b96df7f717</string>
             <key>url</key>
-            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/expat-1.95.8-windows-20080617.tar.bz2</uri>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/expat-1.95.8-windows-20080715.tar.bz2</uri>
           </map>
         </map>
       </map>
@@ -481,9 +481,9 @@
           <key>windows</key>
           <map>
             <key>md5sum</key>
-            <string>b22d33d86567561eb116aa2ccd024d88</string>
+            <string>688944a961e16c2a89f81b60b2ff3acf</string>
             <key>url</key>
-            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/freetype-2.1.5-windows-20080613.tar.bz2</uri>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/freetype-2.1.5-windows-20080822.tar.bz2</uri>
           </map>
         </map>
       </map>
@@ -730,9 +730,9 @@
           <key>windows</key>
           <map>
             <key>md5sum</key>
-            <string>475ab2d2f4b769834bd3f35562b8c445</string>
+            <string>e40d2df9aaefb3bd57289fe96766353a</string>
             <key>url</key>
-            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/jpeglib-6b-windows-20080613.tar.bz2</uri>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/jpeglib-6b-windows-20080723.tar.bz2</uri>
           </map>
         </map>
       </map>
@@ -817,9 +817,9 @@
           <key>windows</key>
           <map>
             <key>md5sum</key>
-            <string>87af253b1d76437290355e8e20029377</string>
+            <string>c4cf53deda9148549e6534a98b56e866</string>
             <key>url</key>
-            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/kdu-binaries-5.2.1-windows-20080617.tar.bz2</uri>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/kdu-binaries-4.2-windows-20080723.tar.bz2</uri>
           </map>
         </map>
       </map>
@@ -912,9 +912,9 @@ anguage Infrstructure (CLI) international standard</string>
           <key>windows</key>
           <map>
             <key>md5sum</key>
-            <string>96ad03239a2b1d50584dcaf66162e03e</string>
+            <string>230b6113158994c516ea742fb9e163c3</string>
             <key>url</key>
-            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/libpng-1.2.18-windows-20080613.tar.bz2</uri>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/libpng-1.2.29-windows-20080723.tar.bz2</uri>
           </map>
         </map>
       </map>
@@ -1010,9 +1010,9 @@ anguage Infrstructure (CLI) international standard</string>
           <key>windows</key>
           <map>
             <key>md5sum</key>
-            <string>42cb780c595d25881b4967292a4a0f40</string>
+            <string>3fd03d7bbd0efceddce1e158eb454fc9</string>
             <key>url</key>
-            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/llmozlib-windows-20080828.tar.bz2</uri>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/llmozlib-windows-20090123.tar.bz2</uri>
           </map>
         </map>
       </map>
@@ -1072,9 +1072,9 @@ anguage Infrstructure (CLI) international standard</string>
           <key>windows</key>
           <map>
             <key>md5sum</key>
-            <string>813e8621ca3cd5a720f709620927070f</string>
+            <string>98bac06680dca907e783d8dd4aa9edde</string>
             <key>url</key>
-            <uri>scp:install-packages.lindenlab.com:/local/www/install-packages/doc/mysql-windows-20080611.tar.bz2</uri>
+            <uri>scp:install-packages.lindenlab.com:/local/www/install-packages/doc/mysql-windows-20080804.tar.bz2</uri>
           </map>
         </map>
       </map>
@@ -1112,9 +1112,9 @@ anguage Infrstructure (CLI) international standard</string>
           <key>windows</key>
           <map>
             <key>md5sum</key>
-            <string>03cbdf59996f468f907f11cb9c64f93f</string>
+            <string>8ac100b5b711231b06be891c91cb68f3</string>
             <key>url</key>
-            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/ndofdev-windows-20080618.tar.bz2</uri>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/ndofdev-windows-20080723.tar.bz2</uri>
           </map>
         </map>
       </map>
@@ -1159,9 +1159,9 @@ anguage Infrstructure (CLI) international standard</string>
           <key>windows</key>
           <map>
             <key>md5sum</key>
-            <string>9667525f28adb4ad54bbc883b14324ac</string>
+            <string>9bf1fea65e66b2cd3075e6ffd7eb57ad</string>
             <key>url</key>
-            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/ogg-vorbis-1.03-1.1.2-windows-20080613.tar.bz2</uri>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/ogg-vorbis-1.1.3-1.2.0-windows-20080723.tar.bz2</uri>
           </map>
         </map>
       </map>
@@ -1202,9 +1202,9 @@ anguage Infrstructure (CLI) international standard</string>
           <key>windows</key>
           <map>
             <key>md5sum</key>
-            <string>8a75180cae12d268071c090abb031ba5</string>
+            <string>dd85209081b832e836de6e1538541d89</string>
             <key>url</key>
-            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/openSSL-0.9.7c-windows-20080613.tar.bz2</uri>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/openSSL-0.9.8j-windows-20090129.tar.bz2</uri>
           </map>
         </map>
       </map>
@@ -1289,9 +1289,9 @@ anguage Infrstructure (CLI) international standard</string>
           <key>windows</key>
           <map>
             <key>md5sum</key>
-            <string>33ceb9232a59c0399ef4d239373c3e42</string>
+            <string>48650448e3d9c8d3a97fd0169b22892c</string>
             <key>url</key>
-            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/openjpeg-1.2-windows-20080613.tar.bz2</uri>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/openjpeg-1.2-windows-20080723.tar.bz2</uri>
           </map>
         </map>
       </map>
@@ -1471,9 +1471,9 @@ anguage Infrstructure (CLI) international standard</string>
           <key>windows</key>
           <map>
             <key>md5sum</key>
-            <string>ef96676498fef5c2bd1a1de0144163e2</string>
+            <string>789988ea1fd8615137f843fbbe5b6bfa</string>
             <key>url</key>
-            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/xmlrpc-epi-0.51-windows-20080613.tar.bz2</uri>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/xmlrpc-epi-0.51-windows-20080723.tar.bz2</uri>
           </map>
         </map>
       </map>
@@ -1518,9 +1518,9 @@ anguage Infrstructure (CLI) international standard</string>
           <key>windows</key>
           <map>
             <key>md5sum</key>
-            <string>bebeba689d2a8d19cfde150582a4f85a</string>
+            <string>9ad657cc5146fef77ffa8dd1c069018f</string>
             <key>url</key>
-            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/zlib-1.1.4-windows-20080618.tar.bz2</uri>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/zlib-1.2.3-windows-20080723.tar.bz2</uri>
           </map>
         </map>
       </map>