From e7830b39f01d9f9c82e9e2029634dffb8386b24e Mon Sep 17 00:00:00 2001
From: Dave Parks <davep@lindenlab.com>
Date: Fri, 3 Dec 2021 15:07:31 +0000
Subject: [PATCH] SL-16436 and SL-16327 Fix for RenderDebugGL test failures and
 fix for grey textures

---
 indra/llrender/llgl.cpp                       |  44 +-
 indra/llrender/llimagegl.cpp                  |  34 +-
 indra/llrender/llimagegl.h                    |  10 +-
 indra/llrender/llrender.cpp                   |   6 +-
 indra/newview/CMakeLists.txt                  |   4 -
 .../class1/deferred/avatarAlphaShadowF.glsl   |   4 +-
 .../class1/deferred/avatarAlphaShadowV.glsl   |   3 -
 indra/newview/lldrawable.h                    |   5 +-
 indra/newview/lldrawpooltree.cpp              |  10 +-
 indra/newview/llface.h                        |   1 -
 indra/newview/llglsandbox.cpp                 |  15 +
 indra/newview/llspatialpartition.cpp          | 130 +-----
 indra/newview/llspatialpartition.h            |  40 +-
 indra/newview/lltextureatlas.cpp              | 416 ------------------
 indra/newview/lltextureatlas.h                |  90 ----
 indra/newview/lltextureatlasmanager.cpp       | 268 -----------
 indra/newview/lltextureatlasmanager.h         | 105 -----
 indra/newview/llviewertexture.cpp             |  71 +--
 indra/newview/llvovolume.cpp                  |  11 +-
 indra/newview/pipeline.cpp                    |  28 +-
 indra/newview/pipeline.h                      |   3 +
 21 files changed, 166 insertions(+), 1132 deletions(-)
 delete mode 100644 indra/newview/lltextureatlas.cpp
 delete mode 100644 indra/newview/lltextureatlas.h
 delete mode 100644 indra/newview/lltextureatlasmanager.cpp
 delete mode 100644 indra/newview/lltextureatlasmanager.h

diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index 58183adfce8..f24bf6ec782 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -88,24 +88,32 @@ void APIENTRY gl_debug_callback(GLenum source,
 {
 	if (gGLDebugLoggingEnabled)
 	{
-	if (severity == GL_DEBUG_SEVERITY_HIGH_ARB)
-	{
-		LL_WARNS() << "----- GL ERROR --------" << LL_ENDL;
-	}
-	else
-	{
-		LL_WARNS() << "----- GL WARNING -------" << LL_ENDL;
-	}
-	LL_WARNS() << "Type: " << std::hex << type << LL_ENDL;
-	LL_WARNS() << "ID: " << std::hex << id << LL_ENDL;
-	LL_WARNS() << "Severity: " << std::hex << severity << LL_ENDL;
-	LL_WARNS() << "Message: " << message << LL_ENDL;
-	LL_WARNS() << "-----------------------" << LL_ENDL;
-	if (severity == GL_DEBUG_SEVERITY_HIGH_ARB)
-	{
-		LL_ERRS() << "Halting on GL Error" << LL_ENDL;
-	}
-}
+
+        if (severity != GL_DEBUG_SEVERITY_HIGH_ARB &&
+            severity != GL_DEBUG_SEVERITY_MEDIUM_ARB &&
+            severity != GL_DEBUG_SEVERITY_LOW_ARB)
+        { //suppress out-of-spec messages sent by nvidia driver (mostly vertexbuffer hints)
+            return;
+        }
+
+	    if (severity == GL_DEBUG_SEVERITY_HIGH_ARB)
+	    {
+		    LL_WARNS() << "----- GL ERROR --------" << LL_ENDL;
+	    }
+	    else
+	    {
+		    LL_WARNS() << "----- GL WARNING -------" << LL_ENDL;
+	    }
+	    LL_WARNS() << "Type: " << std::hex << type << LL_ENDL;
+	    LL_WARNS() << "ID: " << std::hex << id << LL_ENDL;
+	    LL_WARNS() << "Severity: " << std::hex << severity << LL_ENDL;
+	    LL_WARNS() << "Message: " << message << LL_ENDL;
+	    LL_WARNS() << "-----------------------" << LL_ENDL;
+	    if (severity == GL_DEBUG_SEVERITY_HIGH_ARB)
+	    {
+		    LL_ERRS() << "Halting on GL Error" << LL_ENDL;
+	    }
+    }
 }
 #endif
 
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index 894eb8c7730..d3af27272b2 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -41,6 +41,10 @@
 #include "llrender.h"
 #include "llwindow.h"
 
+#if !LL_IMAGEGL_THREAD_CHECK
+#define checkActiveThread()
+#endif
+
 //----------------------------------------------------------------------------
 const F32 MIN_TEXTURE_LIFETIME = 10.f;
 
@@ -437,6 +441,10 @@ LLImageGL::~LLImageGL()
 
 void LLImageGL::init(BOOL usemipmaps)
 {
+#if LL_IMAGEGL_THREAD_CHECK
+    mActiveThread = LLThread::currentID();
+#endif
+
 	// keep these members in the same order as declared in llimagehl.h
 	// so that it is obvious by visual inspection if we forgot to
 	// init a field.
@@ -1317,6 +1325,8 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt
 BOOL LLImageGL::createGLTexture()
 {
     LL_PROFILE_ZONE_SCOPED;
+    checkActiveThread();
+
 	if (gGLManager.mIsDisabled)
 	{
 		LL_WARNS() << "Trying to create a texture while GL is disabled!" << LL_ENDL;
@@ -1349,6 +1359,8 @@ BOOL LLImageGL::createGLTexture()
 BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename/*=0*/, BOOL to_create, S32 category)
 {
     LL_PROFILE_ZONE_SCOPED;
+    checkActiveThread();
+
 	if (gGLManager.mIsDisabled)
 	{
 		LL_WARNS() << "Trying to create a texture while GL is disabled!" << LL_ENDL;
@@ -1462,6 +1474,8 @@ 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)
 {
     LL_PROFILE_ZONE_SCOPED;
+    checkActiveThread();
+
     llassert(data_in);
     stop_glerror();
 
@@ -1576,6 +1590,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_
     // mark this as bound at this point, so we don't throw it out immediately
     mLastBindTime = sLastFrameTime;
 
+    checkActiveThread();
     return TRUE;
 }
 
@@ -1690,18 +1705,10 @@ BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compre
 	return TRUE ;
 }
 
-void LLImageGL::deleteDeadTextures()
-{
-	bool reset = false;
-
-	if (reset)
-	{
-		gGL.getTexUnit(0)->activate();
-	}
-}
-		
 void LLImageGL::destroyGLTexture()
 {
+    checkActiveThread();
+
 	if (mTexName != 0)
 	{
 		if(mTextureMemory != S32Bytes(0))
@@ -1720,6 +1727,7 @@ void LLImageGL::destroyGLTexture()
 //force to invalidate the gl texture, most likely a sculpty texture
 void LLImageGL::forceToInvalidateGLTexture()
 {
+    checkActiveThread();
 	if (mTexName != 0)
 	{
 		destroyGLTexture();
@@ -2196,6 +2204,12 @@ void LLImageGL::resetCurTexSizebar()
 	sCurTexPickSize = -1 ;
 }
 //----------------------------------------------------------------------------
+#if LL_IMAGEGL_THREAD_CHECK
+void LLImageGL::checkActiveThread()
+{
+    llassert(mActiveThread == LLThread::currentID());
+}
+#endif
 
 //----------------------------------------------------------------------------
 
diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h
index ae773bb3625..28996a554a4 100644
--- a/indra/llrender/llimagegl.h
+++ b/indra/llrender/llimagegl.h
@@ -40,7 +40,8 @@
 #include "threadpool.h"
 #include "workqueue.h"
 
-class LLTextureAtlas ;
+#define LL_IMAGEGL_THREAD_CHECK 0 //set to 1 to enable thread debugging for ImageGL
+
 class LLWindow;
 
 #define BYTES_TO_MEGA_BYTES(x) ((x) >> 20)
@@ -54,7 +55,6 @@ class LLImageGL : public LLRefCount
 	// These 2 functions replace glGenTextures() and glDeleteTextures()
 	static void generateTextures(S32 numTextures, U32 *textures);
 	static void deleteTextures(S32 numTextures, const U32 *textures);
-	static void deleteDeadTextures();
 
 	// Size calculation
 	static S32 dataFormatBits(S32 dataformat);
@@ -189,6 +189,12 @@ class LLImageGL : public LLRefCount
 	BOOL preAddToAtlas(S32 discard_level, const LLImageRaw* raw_image);
 	void postAddToAtlas() ;	
 
+#if LL_IMAGEGL_THREAD_CHECK
+    // thread debugging
+    std::thread::id mActiveThread;
+    void checkActiveThread();
+#endif
+
 public:
 	// Various GL/Rendering options
 	S32Bytes mTextureMemory;
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index 235f8a8eb0b..8b4f250894f 100644
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -181,7 +181,11 @@ void LLTexUnit::bindFast(LLTexture* texture)
     mCurrTexture = gl_tex->getTexName();
     if (!mCurrTexture)
     {
-        mCurrTexture = LLImageGL::sDefaultGLTexture->getTexName();
+        LL_PROFILE_ZONE_NAMED("MISSING TEXTURE");
+        //if deleted, will re-generate it immediately
+        texture->forceImmediateUpdate();
+        gl_tex->forceUpdateBindStats();
+        texture->bindDefaultImage(mIndex);
     }
     glBindTexture(sGLTextureType[gl_tex->getTarget()], mCurrTexture);
     mHasMipMaps = gl_tex->mHasMipMaps;
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 4a7f17f15bf..8157d1566a9 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -590,8 +590,6 @@ set(viewer_SOURCE_FILES
     llsyswellwindow.cpp
     llteleporthistory.cpp
     llteleporthistorystorage.cpp
-    lltextureatlas.cpp
-    lltextureatlasmanager.cpp
     lltexturecache.cpp
     lltexturectrl.cpp
     lltexturefetch.cpp
@@ -1219,8 +1217,6 @@ set(viewer_HEADER_FILES
     lltable.h
     llteleporthistory.h
     llteleporthistorystorage.h
-    lltextureatlas.h
-    lltextureatlasmanager.h
     lltexturecache.h
     lltexturectrl.h
     lltexturefetch.h
diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaShadowF.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaShadowF.glsl
index ef49b6f4e82..1b16e4eb09e 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaShadowF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaShadowF.glsl
@@ -40,11 +40,11 @@ VARYING vec4 post_pos;
 VARYING float pos_w;
 VARYING float target_pos_x;
 VARYING vec2 vary_texcoord0;
-VARYING vec4 vertex_color;
+uniform vec4 color;
 
 void main() 
 {
-	float alpha = texture2D(diffuseMap, vary_texcoord0.xy).a * vertex_color.a;
+	float alpha = texture2D(diffuseMap, vary_texcoord0.xy).a * color.a;
 
 	if (alpha < 0.05) // treat as totally transparent
 	{
diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaShadowV.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaShadowV.glsl
index d1d7ece6feb..1c5b142ebd1 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaShadowV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaShadowV.glsl
@@ -30,7 +30,6 @@ uniform float shadow_target_width;
 mat4 getSkinnedTransform();
 void passTextureIndex();
 
-ATTRIBUTE vec4 diffuse_color;
 ATTRIBUTE vec3 position;
 ATTRIBUTE vec3 normal;
 ATTRIBUTE vec2 texcoord0;
@@ -41,7 +40,6 @@ VARYING vec4 post_pos;
 VARYING float pos_w;
 VARYING float target_pos_x;
 VARYING vec2 vary_texcoord0;
-VARYING vec4 vertex_color;
 
 void main()
 {
@@ -68,7 +66,6 @@ void main()
 
 	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
 
-	vertex_color = diffuse_color;
 #if !DEPTH_CLAMP
 	post_pos = pos;
 
diff --git a/indra/newview/lldrawable.h b/indra/newview/lldrawable.h
index 6002e3e0dda..9a9f6cf7c24 100644
--- a/indra/newview/lldrawable.h
+++ b/indra/newview/lldrawable.h
@@ -64,6 +64,8 @@ class LLDrawable
 {
     LL_ALIGN_NEW;
 public:
+    typedef std::vector<LLFace*> face_list_t;
+
 	LLDrawable(const LLDrawable& rhs) 
         : LLViewerOctreeEntryData(rhs)
 	{
@@ -129,6 +131,7 @@ class LLDrawable
 	
 	inline LLFace*      getFace(const S32 i) const;
 	inline S32			getNumFaces()      	 const;
+    face_list_t& getFaces() { return mFaces; }
 
 	//void                removeFace(const S32 i); // SJB: Avoid using this, it's slow
 	LLFace*				addFace(LLFacePool *poolp, LLViewerTexture *texturep);
@@ -297,8 +300,6 @@ class LLDrawable
 	static F32 sCurPixelAngle; //current pixels per radian
 
 private:
-	typedef std::vector<LLFace*> face_list_t;
-	
 	U32				mState;
 	S32				mRenderType;
 	LLPointer<LLViewerObject> mVObjp;
diff --git a/indra/newview/lldrawpooltree.cpp b/indra/newview/lldrawpooltree.cpp
index ac957f1cbdd..facfb235c91 100644
--- a/indra/newview/lldrawpooltree.cpp
+++ b/indra/newview/lldrawpooltree.cpp
@@ -92,8 +92,9 @@ void LLDrawPoolTree::render(S32 pass)
 
 	LLGLState test(GL_ALPHA_TEST, 0);
 
-	gGL.getTexUnit(sDiffTex)->bind(mTexturep);
-				
+	gGL.getTexUnit(sDiffTex)->bindFast(mTexturep);
+    gPipeline.touchTexture(mTexturep, 1024.f * 1024.f); // <=== keep Linden tree textures at full res
+
 	for (std::vector<LLFace*>::iterator iter = mDrawFace.begin();
 		 iter != mDrawFace.end(); iter++)
 	{
@@ -116,9 +117,8 @@ void LLDrawPoolTree::render(S32 pass)
 				gPipeline.mMatrixOpCount++;
 			}
 
-			buff->setBuffer(LLDrawPoolTree::VERTEX_DATA_MASK);
-			buff->drawRange(LLRender::TRIANGLES, 0, buff->getNumVerts()-1, buff->getNumIndices(), 0); 
-			gPipeline.addTrianglesDrawn(buff->getNumIndices());
+			buff->setBufferFast(LLDrawPoolTree::VERTEX_DATA_MASK);
+			buff->drawRangeFast(LLRender::TRIANGLES, 0, buff->getNumVerts()-1, buff->getNumIndices(), 0); 
 		}
 	}
 }
diff --git a/indra/newview/llface.h b/indra/newview/llface.h
index c533edede42..79f50f22736 100644
--- a/indra/newview/llface.h
+++ b/indra/newview/llface.h
@@ -47,7 +47,6 @@ class LLTextureEntry;
 class LLVertexProgram;
 class LLViewerTexture;
 class LLGeometryManager;
-class LLTextureAtlasSlot;
 class LLDrawInfo;
 class LLMeshSkinInfo;
 
diff --git a/indra/newview/llglsandbox.cpp b/indra/newview/llglsandbox.cpp
index a135ef0814e..0b5064c77d4 100644
--- a/indra/newview/llglsandbox.cpp
+++ b/indra/newview/llglsandbox.cpp
@@ -1115,6 +1115,14 @@ F32 gpu_benchmark()
 	// ensure matched pair of bind() and unbind() calls
 	ShaderBinder binder(gBenchmarkProgram);
 
+    U32 glarray = 0;
+
+    if (LLRender::sGLCoreProfile)
+    {
+        glGenVertexArrays(1, &glarray);
+        glBindVertexArray(glarray);
+    }
+
 	buff->setBuffer(LLVertexBuffer::MAP_VERTEX);
 	glFinish();
 
@@ -1147,6 +1155,13 @@ F32 gpu_benchmark()
 		}
 	}
 
+    if (LLRender::sGLCoreProfile)
+    {
+        glBindVertexArray(0);
+        glDeleteVertexArrays(1, &glarray);
+    }
+
+
 	std::sort(results.begin(), results.end());
 
 	F32 gbps = results[results.size()/2];
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index 25d6106361d..48e9f3726fb 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -51,7 +51,6 @@
 #include "llphysicsshapebuilderutil.h"
 #include "llvoavatar.h"
 #include "llvolumemgr.h"
-#include "lltextureatlas.h"
 #include "llviewershadermgr.h"
 #include "llcontrolavatar.h"
 
@@ -128,129 +127,6 @@ LLSpatialGroup::~LLSpatialGroup()
 	sNodeCount--;
 
 	clearDrawMap();
-	clearAtlasList() ;
-}
-
-BOOL LLSpatialGroup::hasAtlas(LLTextureAtlas* atlasp)
-{
-	S8 type = atlasp->getComponents() - 1 ;
-	for(std::list<LLTextureAtlas*>::iterator iter = mAtlasList[type].begin(); iter != mAtlasList[type].end() ; ++iter)
-	{
-		if(atlasp == *iter)
-		{
-			return TRUE ;
-		}
-	}
-	return FALSE ;
-}
-
-void LLSpatialGroup::addAtlas(LLTextureAtlas* atlasp, S8 recursive_level) 
-{		
-	if(!hasAtlas(atlasp))
-	{
-		mAtlasList[atlasp->getComponents() - 1].push_back(atlasp) ;
-		atlasp->addSpatialGroup(this) ;
-	}
-	
-	--recursive_level;
-	if(recursive_level)//levels propagating up.
-	{
-		LLSpatialGroup* parent = getParent() ;
-		if(parent)
-		{
-			parent->addAtlas(atlasp, recursive_level) ;
-		}
-	}	
-}
-
-void LLSpatialGroup::removeAtlas(LLTextureAtlas* atlasp, BOOL remove_group, S8 recursive_level) 
-{
-	mAtlasList[atlasp->getComponents() - 1].remove(atlasp) ;
-	if(remove_group)
-	{
-		atlasp->removeSpatialGroup(this) ;
-	}
-
-	--recursive_level;
-	if(recursive_level)//levels propagating up.
-	{
-		LLSpatialGroup* parent = getParent() ;
-		if(parent)
-		{
-			parent->removeAtlas(atlasp, recursive_level) ;
-		}
-	}	
-}
-
-void LLSpatialGroup::clearAtlasList() 
-{
-	std::list<LLTextureAtlas*>::iterator iter ;
-	for(S8 i = 0 ; i < 4 ; i++)
-	{
-		if(mAtlasList[i].size() > 0)
-		{
-			for(iter = mAtlasList[i].begin(); iter != mAtlasList[i].end() ; ++iter)
-			{
-				((LLTextureAtlas*)*iter)->removeSpatialGroup(this) ;			
-			}
-			mAtlasList[i].clear() ;
-		}
-	}
-}
-
-LLTextureAtlas* LLSpatialGroup::getAtlas(S8 ncomponents, S8 to_be_reserved, S8 recursive_level)
-{
-	S8 type = ncomponents - 1 ;
-	if(mAtlasList[type].size() > 0)
-	{
-		for(std::list<LLTextureAtlas*>::iterator iter = mAtlasList[type].begin(); iter != mAtlasList[type].end() ; ++iter)
-		{
-			if(!((LLTextureAtlas*)*iter)->isFull(to_be_reserved))
-			{
-				return *iter ;
-			}
-		}
-	}
-
-	--recursive_level;
-	if(recursive_level)
-	{
-		LLSpatialGroup* parent = getParent() ;
-		if(parent)
-		{
-			return parent->getAtlas(ncomponents, to_be_reserved, recursive_level) ;
-		}
-	}
-	return NULL ;
-}
-
-void LLSpatialGroup::setCurUpdatingSlot(LLTextureAtlasSlot* slotp) 
-{ 
-	mCurUpdatingSlotp = slotp;
-
-	//if(!hasAtlas(mCurUpdatingSlotp->getAtlas()))
-	//{
-	//	addAtlas(mCurUpdatingSlotp->getAtlas()) ;
-	//}
-}
-
-LLTextureAtlasSlot* LLSpatialGroup::getCurUpdatingSlot(LLViewerTexture* imagep, S8 recursive_level) 
-{ 
-	if(gFrameCount && mCurUpdatingTime == gFrameCount && mCurUpdatingTexture == imagep)
-	{
-		return mCurUpdatingSlotp ;
-	}
-
-	//--recursive_level ;
-	//if(recursive_level)
-	//{
-	//	LLSpatialGroup* parent = getParent() ;
-	//	if(parent)
-	//	{
-	//		return parent->getCurUpdatingSlot(imagep, recursive_level) ;
-	//	}
-	//}
-	return NULL ;
 }
 
 void LLSpatialGroup::clearDrawMap()
@@ -665,11 +541,7 @@ LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) : LLO
 	mDistance(0.f),
 	mDepth(0.f),
 	mLastUpdateDistance(-1.f), 
-	mLastUpdateTime(gFrameTimeSeconds),
-	mAtlasList(4),
-	mCurUpdatingTime(0),
-	mCurUpdatingSlotp(NULL),
-	mCurUpdatingTexture (NULL)
+	mLastUpdateTime(gFrameTimeSeconds)
 {
 	ll_assert_aligned(this,16);
 	
diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h
index 5fca516f192..58d821353a7 100644
--- a/indra/newview/llspatialpartition.h
+++ b/indra/newview/llspatialpartition.h
@@ -50,8 +50,6 @@ class LLViewerOctreePartition;
 class LLSpatialPartition;
 class LLSpatialBridge;
 class LLSpatialGroup;
-class LLTextureAtlas;
-class LLTextureAtlasSlot;
 class LLViewerRegion;
 
 void pushVerts(LLFace* face, U32 mask);
@@ -91,6 +89,10 @@ class LLDrawInfo : public LLRefCount
 	LLPointer<LLViewerTexture>     mTexture;
 	std::vector<LLPointer<LLViewerTexture> > mTextureList;
 
+    // virtual size of mTexture and mTextureList textures
+    // used to update the decode priority of textures in this DrawInfo
+    std::vector<F32> mTextureListVSize;
+
 	S32 mDebugColor;
 	const LLMatrix4* mTextureMatrix;
 	const LLMatrix4* mModelMatrix;
@@ -304,49 +306,15 @@ class LLSpatialGroup : public LLOcclusionCullingGroup
 	virtual void handleDestruction(const TreeNode* node);
 	virtual void handleChildAddition(const OctreeNode* parent, OctreeNode* child);
 
-//-------------------
-//for atlas use
-//-------------------
-	//atlas	
-	void setCurUpdatingTime(U32 t) {mCurUpdatingTime = t ;}
-	U32  getCurUpdatingTime() const { return mCurUpdatingTime ;}
-	
-	void setCurUpdatingSlot(LLTextureAtlasSlot* slotp) ;
-	LLTextureAtlasSlot* getCurUpdatingSlot(LLViewerTexture* imagep, S8 recursive_level = 3) ;
-
-	void setCurUpdatingTexture(LLViewerTexture* tex){ mCurUpdatingTexture = tex ;}
-	LLViewerTexture* getCurUpdatingTexture() const { return mCurUpdatingTexture ;}
-	
-	BOOL hasAtlas(LLTextureAtlas* atlasp) ;
-	LLTextureAtlas* getAtlas(S8 ncomponents, S8 to_be_reserved, S8 recursive_level = 3) ;
-	void addAtlas(LLTextureAtlas* atlasp, S8 recursive_level = 3) ;
-	void removeAtlas(LLTextureAtlas* atlasp, BOOL remove_group = TRUE, S8 recursive_level = 3) ;
-	void clearAtlasList() ;
-
 public:
-
 	LL_ALIGN_16(LLVector4a mViewAngle);
 	LL_ALIGN_16(LLVector4a mLastUpdateViewAngle);
 
 	F32 mObjectBoxSize; //cached mObjectBounds[1].getLength3()
-		
-private:
-	U32                     mCurUpdatingTime ;
-	//do not make the below two to use LLPointer
-	//because mCurUpdatingTime invalidates them automatically.
-	LLTextureAtlasSlot* mCurUpdatingSlotp ;
-	LLViewerTexture*          mCurUpdatingTexture ;
-
-	std::vector< std::list<LLTextureAtlas*> > mAtlasList ; 
-//-------------------
-//end for atlas use
-//-------------------
 
 protected:
 	virtual ~LLSpatialGroup();
 
-	static S32 sLODSeed;
-
 public:
 	bridge_list_t mBridgeList;
 	buffer_map_t mBufferMap; //used by volume buffers to attempt to reuse vertex buffers
diff --git a/indra/newview/lltextureatlas.cpp b/indra/newview/lltextureatlas.cpp
deleted file mode 100644
index 1c8e4f796e0..00000000000
--- a/indra/newview/lltextureatlas.cpp
+++ /dev/null
@@ -1,416 +0,0 @@
-/** 
- * @file lltextureatlas.cpp
- * @brief LLTextureAtlas class implementation.
- *
- * $LicenseInfo:firstyear=2002&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-#include "llviewerprecompiledheaders.h"
-#include "linden_common.h"
-#include "llerror.h"
-#include "llimage.h"
-#include "llmath.h"
-#include "llgl.h"
-#include "llrender.h"
-#include "lltextureatlas.h"
-
-//-------------------
-S16 LLTextureAtlas::sMaxSubTextureSize = 64 ;
-S16 LLTextureAtlas::sSlotSize = 32 ;
-
-#ifndef DEBUG_ATLAS
-#define DEBUG_ATLAS 0
-#endif
-
-#ifndef DEBUG_USAGE_BITS
-#define DEBUG_USAGE_BITS 0
-#endif
-//**************************************************************************************************************
-LLTextureAtlas::LLTextureAtlas(U8 ncomponents, S16 atlas_dim) : 
-    LLViewerTexture(atlas_dim * sSlotSize, atlas_dim * sSlotSize, ncomponents, TRUE),
-	mAtlasDim(atlas_dim),
-	mNumSlotsReserved(0),
-	mMaxSlotsInAtlas(atlas_dim * atlas_dim)
-{
-	generateEmptyUsageBits() ;
-
-	//generate an empty texture
-	generateGLTexture() ;
-	LLPointer<LLImageRaw> image_raw = new LLImageRaw(mFullWidth, mFullHeight, mComponents);
-	createGLTexture(0, image_raw, 0);
-	image_raw = NULL;
-}
-
-LLTextureAtlas::~LLTextureAtlas() 
-{
-	if(mSpatialGroupList.size() > 0)
-	{
-		LL_ERRS() << "Not clean up the spatial groups!" << LL_ENDL ;
-	}
-	releaseUsageBits() ;
-}
-
-//virtual 
-S8 LLTextureAtlas::getType() const
-{
-	return 0; //LLViewerTexture::ATLAS_TEXTURE ;
-}
-
-void LLTextureAtlas::getTexCoordOffset(S16 col, S16 row, F32& xoffset, F32& yoffset)
-{
-	xoffset = (F32)col / mAtlasDim ;
-	yoffset = (F32)row / mAtlasDim ;	
-}
-
-void LLTextureAtlas::getTexCoordScale(S32 w, S32 h, F32& xscale, F32& yscale)
-{
-	xscale = (F32)w / (mAtlasDim * sSlotSize) ;
-	yscale = (F32)h / (mAtlasDim * sSlotSize) ;	
-}
-
-//insert a texture piece into the atlas
-LLGLuint LLTextureAtlas::insertSubTexture(LLImageGL* source_gl_tex, S32 discard_level, const LLImageRaw* raw_image, S16 slot_col, S16 slot_row)
-{
-	if(!getTexName())
-	{
-		return 0 ;
-	}
-
-	S32 w = raw_image->getWidth() ;
-	S32 h = raw_image->getHeight() ;
-	if(w < 8 || w > sMaxSubTextureSize || h < 8 || h > sMaxSubTextureSize)
-	{
-		//size overflow
-		return 0 ;
-	}
-
-	BOOL res = gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, getTexName());
-	if (!res) 
-	{
-		LL_ERRS() << "bindTexture failed" << LL_ENDL;
-	}
-	
-	GLint xoffset = sSlotSize * slot_col ;
-	GLint yoffset = sSlotSize * slot_row ;
-
-	if(!source_gl_tex->preAddToAtlas(discard_level, raw_image))
-	{
-		return 0 ;
-	}
-
-	glTexSubImage2D(GL_TEXTURE_2D, 0, xoffset, yoffset, w, h,
-						mGLTexturep->getPrimaryFormat(), mGLTexturep->getFormatType(), raw_image->getData());
-	
-	source_gl_tex->postAddToAtlas() ;
-	return getTexName();
-}
-	
-//release a sub-texture slot from the atlas
-void LLTextureAtlas::releaseSlot(S16 slot_col, S16 slot_row, S8 slot_width)
-{
-	unmarkUsageBits(slot_width, slot_col, slot_row) ;
-	mNumSlotsReserved -= slot_width * slot_width ;
-}
-
-BOOL LLTextureAtlas::isEmpty() const 
-{
-	return !mNumSlotsReserved ;
-}
-	
-BOOL LLTextureAtlas::isFull(S8 to_be_reserved) const 
-{
-	return mNumSlotsReserved + to_be_reserved > mMaxSlotsInAtlas ;
-}
-F32  LLTextureAtlas::getFullness() const 
-{
-	return (F32)mNumSlotsReserved / mMaxSlotsInAtlas ;
-}
-
-void LLTextureAtlas::addSpatialGroup(LLSpatialGroup* groupp) 
-{
-	if(groupp && !hasSpatialGroup(groupp))
-	{
-		mSpatialGroupList.push_back(groupp);
-	}
-}
-
-void LLTextureAtlas::removeSpatialGroup(LLSpatialGroup* groupp) 
-{
-	if(groupp)
-	{
-		mSpatialGroupList.remove(groupp);
-	}
-}
-
-void LLTextureAtlas::clearSpatialGroup() 
-{
-	mSpatialGroupList.clear();
-}
-void LLTextureAtlas::removeLastSpatialGroup() 
-{
-	mSpatialGroupList.pop_back() ;
-}
-
-LLSpatialGroup* LLTextureAtlas::getLastSpatialGroup() 
-{
-	if(mSpatialGroupList.size() > 0)
-	{
-		return mSpatialGroupList.back() ;
-	}
-	return NULL ;
-}
-
-BOOL LLTextureAtlas::hasSpatialGroup(LLSpatialGroup* groupp) 
-{
-	for(std::list<LLSpatialGroup*>::iterator iter = mSpatialGroupList.begin(); iter != mSpatialGroupList.end() ; ++iter)
-	{
-		if(*iter == groupp)
-		{
-			return TRUE ;
-		}
-	}
-	return FALSE ;
-}
-
-//--------------------------------------------------------------------------------------
-//private
-void LLTextureAtlas::generateEmptyUsageBits()
-{
-	S32 col_len = (mAtlasDim + 7) >> 3 ;
-	mUsageBits = new U8*[mAtlasDim] ;
-	*mUsageBits = new U8[mAtlasDim * col_len] ;
-
-	mUsageBits[0] = *mUsageBits ;
-	for(S32 i = 1 ; i < mAtlasDim ; i++)
-	{
-	   mUsageBits[i] = mUsageBits[i-1] + col_len ;
-
-	   for(S32 j = 0 ; j < col_len ; j++)
-	   {
-		   //init by 0 for all bits.
-		   mUsageBits[i][j] = 0 ;
-	   }
-	}
-
-	//do not forget mUsageBits[0]!
-	for(S32 j = 0 ; j < col_len ; j++)
-	{
-		//init by 0 for all bits.
-		mUsageBits[0][j] = 0 ;
-	}
-
-	mTestBits = NULL ;
-#if DEBUG_USAGE_BITS
-	//------------
-	//test
-	mTestBits = new U8*[mAtlasDim] ;
-	*mTestBits = new U8[mAtlasDim * mAtlasDim] ;
-	mTestBits[0] = *mTestBits ;
-	for(S32 i = 1 ; i < mAtlasDim ; i++)
-	{
-	   mTestBits[i] = mTestBits[i-1] + mAtlasDim ;
-
-	   for(S32 j = 0 ; j < mAtlasDim ; j++)
-	   {
-		   //init by 0 for all bits.
-		   mTestBits[i][j] = 0 ;
-	   }
-	}
-
-	for(S32 j = 0 ; j < mAtlasDim ; j++)
-	{
-		//init by 0 for all bits.
-		mTestBits[0][j] = 0 ;
-	}
-#endif
-}
-
-void LLTextureAtlas::releaseUsageBits()
-{
-   if(mUsageBits)
-   {
-       delete[] *mUsageBits ;
-       delete[] mUsageBits ;
-   }
-   mUsageBits = NULL ;
-
-   //test
-   if( mTestBits)
-   {
-	   delete[] *mTestBits;
-	   delete[]  mTestBits;
-   }
-    mTestBits = NULL ;
-}
-
-void LLTextureAtlas::markUsageBits(S8 bits_len, U8 mask, S16 col, S16 row)
-{
-	S16 x = col >> 3 ;
-	
-	for(S8 i = 0 ; i < bits_len ; i++)
-	{
-		mUsageBits[row + i][x] |= mask ;
-	}
-
-#if DEBUG_USAGE_BITS
-	//test
-	for(S8 i = row ; i < row + bits_len ; i++)
-	{
-		for(S8 j = col ; j < col + bits_len ; j++)
-		{
-			mTestBits[i][j] = 1 ;
-		}
-	}
-#endif
-}
-
-void LLTextureAtlas::unmarkUsageBits(S8 bits_len, S16 col, S16 row)
-{
-	S16 x = col >> 3 ;
-	U8  mask = 1 ;
-	for(S8 i = 1 ; i < bits_len ; i++)
-	{
-		mask |= (1 << i) ;
-	}
-	mask <<= (col & 7) ;
-	mask = ~mask ;
-	
-	for(S8 i = 0 ; i < bits_len ; i++)
-	{
-		mUsageBits[row + i][x] &= mask ;
-	}
-
-#if DEBUG_USAGE_BITS
-	//test
-	for(S8 i = row ; i < row + bits_len ; i++)
-	{
-		for(S8 j = col ; j < col + bits_len ; j++)
-		{
-			mTestBits[i][j] = 0 ;
-		}
-	}
-#endif
-}
-
-//return true if any of bits in the range marked.
-BOOL LLTextureAtlas::areUsageBitsMarked(S8 bits_len, U8 mask, S16 col, S16 row)
-{
-	BOOL ret = FALSE ;	
-	S16 x = col >> 3 ;
-	
-	for(S8 i = 0 ; i < bits_len ; i++)
-	{
-		if(mUsageBits[row + i][x] & mask)
-		{
-			ret = TRUE ;
-			break ;
-			//return TRUE ;
-		}
-	}
-
-#if DEBUG_USAGE_BITS
-	//test
-	BOOL ret2 = FALSE ;
-	for(S8 i = row ; i < row + bits_len ; i++)
-	{
-		for(S8 j = col ; j < col + bits_len ; j++)
-		{
-			if(mTestBits[i][j])
-			{
-				ret2 = TRUE ;
-			}
-		}
-	}
-
-	if(ret != ret2)
-	{
-		LL_ERRS() << "bits map corrupted." << LL_ENDL ;
-	}
-#endif
-	return ret ;//FALSE ;
-}
-
-//----------------------------------------------------------------------
-//
-//index order: Z order, i.e.: 
-// |-----|-----|-----|-----|
-// |  10 |  11 | 14  | 15  |
-// |-----|-----|-----|-----|
-// |   8 |   9 | 12  | 13  |
-// |-----|-----|-----|-----|
-// |   2 |   3 |   6 |   7 |
-// |-----|-----|-----|-----|
-// |   0 |   1 |   4 |   5 |
-// |-----|-----|-----|-----|
-void LLTextureAtlas::getPositionFromIndex(S16 index, S16& col, S16& row)
-{
-	col = 0 ;
-	row = 0 ;
-
-	S16 index_copy = index ;
-	for(S16 i = 0 ; index_copy && i < 16 ; i += 2)
-	{
-		col |= ((index & (1 << i)) >> i) << (i >> 1) ;
-		row |= ((index & (1 << (i + 1))) >> (i + 1)) << (i >> 1) ;
-		index_copy >>= 2 ;
-	}
-}
-void LLTextureAtlas::getIndexFromPosition(S16 col, S16 row, S16& index)
-{
-	index = 0 ;
-	S16 col_copy = col ;
-	S16 row_copy = row ;
-	for(S16 i = 0 ; (col_copy || row_copy) && i < 16 ; i++)
-	{
-		index |= ((col & 1 << i) << i) | ((row & 1 << i) << ( i + 1)) ;
-		col_copy >>= 1 ;
-		row_copy >>= 1 ;
-	}
-}
-//----------------------------------------------------------------------
-//return TRUE if succeeds.
-BOOL LLTextureAtlas::getNextAvailableSlot(S8 bits_len, S16& col, S16& row)
-{
-    S16 index_step = bits_len * bits_len ;
-
-    U8 mask = 1 ;
-	for(S8 i = 1 ; i < bits_len ; i++)
-	{
-		mask |= (1 << i) ;
-	}	
-   
-	U8 cur_mask ;
-	for(S16 index = 0 ; index < mMaxSlotsInAtlas ; index += index_step)
-    {
-		getPositionFromIndex(index, col, row) ;
-		
-		cur_mask = mask << (col & 7) ;
-		if(!areUsageBitsMarked(bits_len, cur_mask, col, row))
-		{
-			markUsageBits(bits_len, cur_mask, col, row) ;
-			mNumSlotsReserved += bits_len * bits_len ;
-			
-			return TRUE ;
-		}
-    }
-
-   return FALSE ;
-}
diff --git a/indra/newview/lltextureatlas.h b/indra/newview/lltextureatlas.h
deleted file mode 100644
index 6b36eb7fe41..00000000000
--- a/indra/newview/lltextureatlas.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/** 
- * @file lltextureatlas.h
- * @brief LLTextureAtlas base class.
- *
- * $LicenseInfo:firstyear=2002&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-
-#ifndef LL_TEXTUREATLAS_H
-#define LL_TEXTUREATLAS_H
-
-#include "llviewertexture.h"
-class LLSpatialGroup ;
-
-class LLTextureAtlas : public LLViewerTexture
-{
-protected:
-	/*virtual*/ ~LLTextureAtlas() ;
-
-public:
-	LLTextureAtlas(U8 ncomponents, S16 atlas_dim = 16) ;	
-
-	/*virtual*/ S8 getType() const;
-
-	LLGLuint insertSubTexture(LLImageGL* source_gl_tex, S32 discard_level, const LLImageRaw* raw_image, S16 slot_col, S16 slot_row) ;
-	void releaseSlot(S16 slot_col, S16 slot_row, S8 slot_width);
-
-	BOOL getNextAvailableSlot(S8 bits_len, S16& col, S16& row) ;
-	void getTexCoordOffset(S16 col, S16 row, F32& xoffset, F32& yOffset) ;
-	void getTexCoordScale(S32 w, S32 h, F32& xscale, F32& yscale) ;
-
-	BOOL isEmpty() const ;
-	BOOL isFull(S8 to_be_reserved = 1) const ;
-	F32  getFullness() const ;
-
-	void addSpatialGroup(LLSpatialGroup* groupp) ;
-	void removeSpatialGroup(LLSpatialGroup* groupp) ;
-	LLSpatialGroup* getLastSpatialGroup() ;
-	void removeLastSpatialGroup() ;
-	BOOL hasSpatialGroup(LLSpatialGroup* groupp) ;
-	void clearSpatialGroup() ;
-	std::list<LLSpatialGroup*>* getSpatialGroupList() {return &mSpatialGroupList;}
-private:
-	void generateEmptyUsageBits() ;
-	void releaseUsageBits() ;
-
-	void markUsageBits(S8 bits_len, U8 mask, S16 col, S16 row) ;
-	void unmarkUsageBits(S8 bits_len, S16 col, S16 row) ;
-
-	void getPositionFromIndex(S16 index, S16& col, S16& row) ;
-	void getIndexFromPosition(S16 col, S16 row, S16& index) ;
-	BOOL areUsageBitsMarked(S8 bits_len, U8 mask, S16 col, S16 row) ;
-
-private:	
-	S16 mAtlasDim ; //number of slots per edge, i.e, there are "mAtlasDim * mAtlasDim" total slots in the atlas. 
-	S16 mNumSlotsReserved ;
-	S16 mMaxSlotsInAtlas ;
-	U8  **mUsageBits ;	
-	std::list<LLSpatialGroup*> mSpatialGroupList ;
-
-public:
-	//debug use only
-	U8  **mTestBits ;
-
-public:
-	static S16 sMaxSubTextureSize ;
-	static S16 sSlotSize ;
-};
-
-#endif
-
diff --git a/indra/newview/lltextureatlasmanager.cpp b/indra/newview/lltextureatlasmanager.cpp
deleted file mode 100644
index ca9d6da4db1..00000000000
--- a/indra/newview/lltextureatlasmanager.cpp
+++ /dev/null
@@ -1,268 +0,0 @@
-/** 
- * @file lltextureatlasmanager.cpp
- * @brief LLTextureAtlasManager class implementation.
- *
- * $LicenseInfo:firstyear=2002&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-#include "llviewerprecompiledheaders.h"
-#include "linden_common.h"
-#include "llerror.h"
-#include "llmath.h"
-#include "lltextureatlas.h"
-#include "lltextureatlasmanager.h"
-#include "llspatialpartition.h"
-
-const S8 MAX_NUM_EMPTY_ATLAS = 2 ;
-const F32 MIN_ATLAS_FULLNESS = 0.6f ;
-
-//*********************************************************************************************
-//implementation of class LLTextureAtlasInfo
-//*********************************************************************************************
-LLTextureAtlasSlot::LLTextureAtlasSlot(LLTextureAtlas* atlasp, LLSpatialGroup* groupp, S16 col, S16 row, F32 xoffset, F32 yoffset, S8 slot_width) : 
-	mAtlasp(atlasp),
-	mGroupp(groupp),
-	mCol(col),
-	mRow(row),
-	mReservedSlotWidth(slot_width),
-	mValid(FALSE),
-	mUpdatedTime(0),
-	mTexCoordOffset(xoffset, yoffset),
-	mTexCoordScale(1.f, 1.f)
-{
-	llassert_always(mAtlasp || mGroupp || mReservedSlotWidth) ;
-}
-
-LLTextureAtlasSlot::~LLTextureAtlasSlot()
-{
-	if(mAtlasp)
-	{
-		mAtlasp->releaseSlot(mCol, mRow, mReservedSlotWidth) ;
-		if(mAtlasp->isEmpty())
-		{
-			LLTextureAtlasManager::getInstance()->releaseAtlas(mAtlasp) ;
-		}
-		mAtlasp = NULL ;
-	}
-}
-
-//void LLTextureAtlasSlot::setAtlas(LLTextureAtlas* atlasp) 
-//{
-//	mAtlasp = atlasp ;
-//}
-//void LLTextureAtlasSlot::setSlotPos(S16 col, S16 row) 
-//{
-//	mCol = col ;
-//	mRow = row ;
-//}
-//void LLTextureAtlasSlot::setSlotWidth(S8 width) 
-//{
-//	//slot is a square with each edge length a power-of-two number
-//	mReservedSlotWidth = width ;
-//}
-//void LLTextureAtlasSlot::setTexCoordOffset(F32 xoffset, F32 yoffset) 
-//{
-//	mTexCoordOffset.mV[0] = xoffset ;
-//	mTexCoordOffset.mV[1] = yoffset ;
-//}
-
-void LLTextureAtlasSlot::setSpatialGroup(LLSpatialGroup* groupp) 
-{
-	mGroupp = groupp ;
-}
-void LLTextureAtlasSlot::setTexCoordScale(F32 xscale, F32 yscale) 
-{
-	mTexCoordScale.mV[0] = xscale ;
-	mTexCoordScale.mV[1] = yscale ;
-}
-//*********************************************************************************************
-//END of implementation of class LLTextureAtlasInfo
-//*********************************************************************************************
-
-//*********************************************************************************************
-//implementation of class LLTextureAtlasManager
-//*********************************************************************************************
-LLTextureAtlasManager::LLTextureAtlasManager() :
-	mAtlasMap(4),
-	mEmptyAtlasMap(4) 
-{
-}
-
-LLTextureAtlasManager::~LLTextureAtlasManager()
-{
-	for(S32 i = 0 ; i < 4 ; i++)
-	{
-		for(ll_texture_atlas_list_t::iterator j = mAtlasMap[i].begin() ; j != mAtlasMap[i].end() ; ++j)
-		{
-			*j = NULL ;
-		}
-		for(ll_texture_atlas_list_t::iterator j = mEmptyAtlasMap[i].begin() ; j != mEmptyAtlasMap[i].end() ; ++j)
-		{
-			*j = NULL ;
-		}
-
-		mAtlasMap[i].clear() ;
-		mEmptyAtlasMap[i].clear() ;
-	}
-	mAtlasMap.clear() ;
-	mEmptyAtlasMap.clear() ;
-}
-
-//return TRUE if qualified
-BOOL LLTextureAtlasManager::canAddToAtlas(S32 w, S32 h, S8 ncomponents, LLGLenum target) 
-{
-	if(ncomponents < 1 || ncomponents > 4)
-	{
-		return FALSE ;
-	}
-	//only support GL_TEXTURE_2D
-	if(GL_TEXTURE_2D != target)
-	{
-		return FALSE ;
-	}
-	//real image size overflows
-	if(w < 8 || w > LLTextureAtlas::sMaxSubTextureSize || h < 8 || h > LLTextureAtlas::sMaxSubTextureSize)
-	{
-		return FALSE ;
-	}
-
-	//if non-power-of-two number
-	if((w & (w - 1)) || (h & (h - 1)))
-	{
-		return FALSE ;
-	}
-
-	return TRUE ;
-}
-
-void LLTextureAtlasManager::releaseAtlas(LLTextureAtlas* atlasp)
-{	
-	LLSpatialGroup* groupp = atlasp->getLastSpatialGroup() ;
-	while(groupp)
-	{
-		groupp->removeAtlas(atlasp, FALSE) ;
-		atlasp->removeLastSpatialGroup() ;
-
-		groupp = atlasp->getLastSpatialGroup() ;
-	}
-
-	S8 type = atlasp->getComponents() - 1 ;	
-	//insert to the empty list
-	if(mEmptyAtlasMap[type].size() < MAX_NUM_EMPTY_ATLAS)
-	{					
-		mEmptyAtlasMap[type].push_back(atlasp) ;
-	}
-		
-	//delete the atlasp
-	mAtlasMap[type].remove(atlasp) ;
-}
-
-//
-//this function reserves an appropriate slot from atlas pool for an image.
-//return non-NULL if succeeds.
-//Note:
-//1, this function does not check if the image this slot assigned for qualifies for atlas or not, 
-//       call LLTextureAtlasManager::canAddToAtlas(...) to do the check before calling this function.
-//2, this function also dose not check if the image is already in atlas. It always assigns a new slot anyway.
-//3, this function tries to group sub-textures from same spatial group into ONE atlas to improve render batching.
-//
-LLPointer<LLTextureAtlasSlot> LLTextureAtlasManager::reserveAtlasSlot(S32 sub_texture_size, S8 ncomponents, 
-																		  LLSpatialGroup* groupp, LLViewerTexture* imagep)
-{
-	if(!groupp)
-	{
-		//do not insert to atlas if does not have a group.
-		return NULL ;
-	}
-
-	//bits_len must <= 8 and is a power of two number, i.e.: must be one of these numbers: 1, 2, 4, 8.
-	if(sub_texture_size > LLTextureAtlas::sMaxSubTextureSize)
-	{
-		sub_texture_size = LLTextureAtlas::sMaxSubTextureSize ;
-	}
-	S8 bits_len = sub_texture_size / LLTextureAtlas::sSlotSize ;
-	if(bits_len < 1)
-	{
-	   bits_len = 1 ;
-	}
-		
-	S16 col = -1, row = -1;
-	S8 total_bits = bits_len * bits_len ;
-
-	//insert to the atlas reserved by the same spatial group
-	LLPointer<LLTextureAtlas> atlasp = groupp->getAtlas(ncomponents, total_bits) ;
-	if(atlasp.notNull())
-	{
-		if(!atlasp->getNextAvailableSlot(bits_len, col, row))
-		{
-			//failed
-			atlasp = NULL ;
-		}		
-	}
-
-   //search an atlas to fit for 'size'
-	if(!atlasp)
-	{
-		S8 atlas_index = ncomponents - 1 ;
-		ll_texture_atlas_list_t::iterator iter = mAtlasMap[atlas_index].begin() ;
-		for(; iter != mAtlasMap[atlas_index].end(); ++iter) 
-		{
-			LLTextureAtlas* cur = (LLTextureAtlas*)*iter ;
-			if(cur->getFullness() < MIN_ATLAS_FULLNESS)//this atlas is empty enough for this group to insert more sub-textures later if necessary.
-			{
-				if(cur->getNextAvailableSlot(bits_len, col, row))
-				{
-					atlasp = cur ;
-					groupp->addAtlas(atlasp) ;				
-					break ;
-				}
-			}
-		}
-	}
-
-	//create a new atlas if necessary
-	if(!atlasp)
-	{
-		if(mEmptyAtlasMap[ncomponents - 1].size() > 0)
-		{
-			//there is an empty one
-			atlasp = mEmptyAtlasMap[ncomponents - 1].back() ;
-			mEmptyAtlasMap[ncomponents - 1].pop_back() ;
-		}
-		else
-		{
-			atlasp = new LLTextureAtlas(ncomponents, 16) ;
-		}
-		mAtlasMap[ncomponents - 1].push_back(atlasp) ;
-		atlasp->getNextAvailableSlot(bits_len, col, row) ;		
-		groupp->addAtlas(atlasp) ;
-	}
-
-	F32 xoffset, yoffset ;
-	atlasp->getTexCoordOffset(col, row, xoffset, yoffset) ;
-	LLPointer<LLTextureAtlasSlot> slot_infop = new LLTextureAtlasSlot(atlasp, groupp, col, row, xoffset, yoffset, bits_len) ;
-	
-	return slot_infop ;
-}
-
-//*********************************************************************************************
-//END of implementation of class LLTextureAtlasManager
-//*********************************************************************************************
diff --git a/indra/newview/lltextureatlasmanager.h b/indra/newview/lltextureatlasmanager.h
deleted file mode 100644
index 1b8df708c62..00000000000
--- a/indra/newview/lltextureatlasmanager.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/** 
- * @file lltextureatlasmanager.h
- * @brief LLTextureAtlasManager base class.
- *
- * $LicenseInfo:firstyear=2002&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-
-#ifndef LL_TEXTUREATLASMANAGER_H
-#define LL_TEXTUREATLASMANAGER_H
-
-#include "llmemory.h"
-
-class LLSpatialGroup ;
-class LLViewerTexture ;
-
-//just use it as a structure.
-class LLTextureAtlasSlot : public LLRefCount
-{
-public:
-	LLTextureAtlasSlot(LLTextureAtlas* atlasp, LLSpatialGroup* groupp, S16 col, S16 row, F32 xoffset, F32 yoffset, S8 slot_width) ;
-
-protected:
-	virtual ~LLTextureAtlasSlot();
-	
-public:
-
-	//
-	//do not allow to change those values
-	//
-	//void setAtlas(LLTextureAtlas* atlasp) ;	
-	//void setSlotPos(S16 col, S16 row) ;
-	//void setSlotWidth(S8 width) ;
-	//void setTexCoordOffset(F32 xoffser, F32 yoffset) ;
-	//
-
-	void setSpatialGroup(LLSpatialGroup* groupp) ;
-	void setTexCoordScale(F32 xscale, F32 yscale) ;
-	void setValid() {mValid = TRUE ;}
-
-	LLTextureAtlas* getAtlas()const {return mAtlasp;}
-	LLSpatialGroup* getSpatialGroup() const {return mGroupp ;} 
-	S16             getSlotCol()const {return mCol;}
-	S16             getSlotRow()const {return mRow;}
-	S8              getSlotWidth()const{return mReservedSlotWidth;}
-	BOOL            isValid()const { return mValid;}
-	const LLVector2*      getTexCoordOffset()const {return &mTexCoordOffset;}
-	const LLVector2*      getTexCoordScale() const {return &mTexCoordScale;}
-
-	void setUpdatedTime(U32 t) {mUpdatedTime = t;}
-	U32  getUpdatedTime()const {return mUpdatedTime;}
-
-private:
-	LLTextureAtlas* mAtlasp;
-	S16             mCol ;//col of the slot
-	S16             mRow ;//row of the slot
-	S8              mReservedSlotWidth ; //slot is a square with each edge length a power-of-two number	
-	LLSpatialGroup* mGroupp ;
-	BOOL            mValid ;
-
-	LLVector2       mTexCoordOffset ;
-	LLVector2       mTexCoordScale ;
-
-	U32             mUpdatedTime ;	
-} ;
-
-class LLTextureAtlasManager : public LLSingleton<LLTextureAtlasManager>
-{
-	LLSINGLETON(LLTextureAtlasManager);
-	~LLTextureAtlasManager();
-	typedef std::list<LLPointer<LLTextureAtlas> > ll_texture_atlas_list_t ;
-
-public:
-
-	LLPointer<LLTextureAtlasSlot> reserveAtlasSlot(S32 sub_texture_size, S8 ncomponents, 
-		LLSpatialGroup* groupp, LLViewerTexture* imagep) ;
-	void releaseAtlas(LLTextureAtlas* atlasp);
-
-	BOOL canAddToAtlas(S32 w, S32 h, S8 ncomponents, LLGLenum target) ;
-
-private:	
-	std::vector<ll_texture_atlas_list_t> mAtlasMap ;
-	std::vector<ll_texture_atlas_list_t> mEmptyAtlasMap ; //delay some empty atlases deletion to avoid possible creation of new atlas immediately.
-};
-
-#endif
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index f932acd48ce..37ed2e9f208 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -1476,6 +1476,10 @@ void LLViewerFetchedTexture::addToCreateTexture()
 BOOL LLViewerFetchedTexture::preCreateTexture(S32 usename/*= 0*/)
 {
     LL_PROFILE_ZONE_SCOPED;
+#if LL_IMAGEGL_THREAD_CHECK
+    mGLTexturep->checkActiveThread();
+#endif
+
     if (!mNeedsCreateTexture)
     {
         destroyRawImage();
@@ -1603,6 +1607,9 @@ void LLViewerFetchedTexture::postCreateTexture()
     {
         return;
     }
+#if LL_IMAGEGL_THREAD_CHECK
+    mGLTexturep->checkActiveThread();
+#endif
 
     notifyAboutCreatingTexture();
 
@@ -1619,36 +1626,45 @@ void LLViewerFetchedTexture::postCreateTexture()
 
 void LLViewerFetchedTexture::scheduleCreateTexture()
 {
-    ref();
-    mNeedsCreateTexture = TRUE;
-    if (preCreateTexture())
+    if (!mNeedsCreateTexture)
     {
+        ref();
         mNeedsCreateTexture = TRUE;
-#if LL_WINDOWS //flip to 0 to revert to single-threaded OpenGL texture uploads
-        auto mainq = mMainQueue.lock();
-        if (mainq)
+        if (preCreateTexture())
         {
-            mainq->postTo(
-                mImageQueue,
-                // work to be done on LLImageGL worker thread
-                [this]()
-                {
-                    //actually create the texture on a background thread
-                    createTexture();
-                },
-                // callback to be run on main thread
-                [this]()
-                {
-                    //finalize on main thread
-                    postCreateTexture();
-                    unref();
-                });
-        }
-        else
+            mNeedsCreateTexture = TRUE;
+#if LL_WINDOWS //flip to 0 to revert to single-threaded OpenGL texture uploads
+            auto mainq = mMainQueue.lock();
+            if (mainq)
+            {
+                mainq->postTo(
+                    mImageQueue,
+                    // work to be done on LLImageGL worker thread
+                    [this]()
+                    {
+#if LL_IMAGEGL_THREAD_CHECK
+                        mGLTexturep->mActiveThread = LLThread::currentID();
 #endif
-        {
-            gTextureList.mCreateTextureList.insert(this);
-            unref();
+                        //actually create the texture on a background thread
+                        createTexture();
+                    },
+                    // callback to be run on main thread
+                        [this]()
+                    {
+#if LL_IMAGEGL_THREAD_CHECK
+                        mGLTexturep->mActiveThread = LLThread::currentID();
+#endif
+                        //finalize on main thread
+                        postCreateTexture();
+                        unref();
+                    });
+            }
+            else
+#endif
+            {
+                gTextureList.mCreateTextureList.insert(this);
+                unref();
+            }
         }
     }
 }
@@ -2967,7 +2983,8 @@ void LLViewerFetchedTexture::destroyRawImage()
 void LLViewerFetchedTexture::switchToCachedImage()
 {
     LL_PROFILE_ZONE_SCOPED;
-	if(mCachedRawImage.notNull())
+	if(mCachedRawImage.notNull() && 
+        !mNeedsCreateTexture) // <--- texture creation is pending, don't step on it
 	{
 		mRawImage = mCachedRawImage;
 						
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 2f554bc9b89..4e7eb4df5d6 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -5189,6 +5189,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 		}
 	}
 
+    F32 vsize = facep->getVirtualSize(); //TODO -- adjust by texture scale?
 
 	if (index < FACE_DO_NOT_BATCH_TEXTURES && idx >= 0)
 	{
@@ -5202,10 +5203,12 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 			{
 				batchable = true;
 				draw_vec[idx]->mTextureList[index] = tex;
+                draw_vec[idx]->mTextureListVSize[index] = vsize;
 			}
 			else if (draw_vec[idx]->mTextureList[index] == tex)
 			{ //this face's texture index can be used with this batch
 				batchable = true;
+                draw_vec[idx]->mTextureListVSize[index] = llmax(vsize, draw_vec[idx]->mTextureListVSize[index]);
 			}
 		}
 		else
@@ -5236,12 +5239,14 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 	{
 		draw_vec[idx]->mCount += facep->getIndicesCount();
 		draw_vec[idx]->mEnd += facep->getGeomCount();
-		draw_vec[idx]->mVSize = llmax(draw_vec[idx]->mVSize, facep->getVirtualSize());
+		draw_vec[idx]->mVSize = llmax(draw_vec[idx]->mVSize, vsize);
 
 		if (index < FACE_DO_NOT_BATCH_TEXTURES && index >= draw_vec[idx]->mTextureList.size())
 		{
 			draw_vec[idx]->mTextureList.resize(index+1);
 			draw_vec[idx]->mTextureList[index] = tex;
+            draw_vec[idx]->mTextureListVSize.resize(index + 1);
+            draw_vec[idx]->mTextureListVSize[index] = vsize;
 		}
 		draw_vec[idx]->validate();
 		update_min_max(draw_vec[idx]->mExtents[0], draw_vec[idx]->mExtents[1], facep->mExtents[0]);
@@ -5256,7 +5261,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 		LLPointer<LLDrawInfo> draw_info = new LLDrawInfo(start,end,count,offset, tex, 
 			facep->getVertexBuffer(), selected, fullbright, bump);
 		draw_info->mGroup = group;
-		draw_info->mVSize = facep->getVirtualSize();
+		draw_info->mVSize = vsize;
 		draw_vec.push_back(draw_info);
 		draw_info->mTextureMatrix = tex_mat;
 		draw_info->mModelMatrix = model_mat;
@@ -5331,6 +5336,8 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 		{ //initialize texture list for texture batching
 			draw_info->mTextureList.resize(index+1);
 			draw_info->mTextureList[index] = tex;
+            draw_info->mTextureListVSize.resize(index + 1);
+            draw_info->mTextureListVSize[index] = vsize;
 		}
 		draw_info->validate();
 	}
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index c122b4f43e6..df676b30fc2 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -3711,25 +3711,31 @@ void renderSoundHighlights(LLDrawable* drawablep)
 }
 }
 
-void LLPipeline::touchTextures(LLDrawInfo* info)
+void LLPipeline::touchTexture(LLViewerTexture* tex, F32 vsize)
 {
-    LL_PROFILE_ZONE_SCOPED;
-    for (auto& tex : info->mTextureList)
+    if (tex)
     {
-        if (tex.notNull())
+        LLImageGL* gl_tex = tex->getGLTexture();
+        if (gl_tex && gl_tex->updateBindStats(gl_tex->mTextureMemory))
         {
-            LLImageGL* gl_tex = tex->getGLTexture();
-            if (gl_tex && gl_tex->updateBindStats(gl_tex->mTextureMemory))
-            {
-                tex->setActive();
-            }
+            tex->setActive();
+            tex->addTextureStats(vsize);
         }
     }
 
-    if (info->mTexture.notNull())
+
+}
+void LLPipeline::touchTextures(LLDrawInfo* info)
+{
+    LL_PROFILE_ZONE_SCOPED;
+    for (int i = 0; i < info->mTextureList.size(); ++i)
     {
-        info->mTexture->addTextureStats(info->mVSize);
+        touchTexture(info->mTextureList[i], info->mTextureListVSize[i]);
     }
+
+    touchTexture(info->mTexture, info->mVSize);
+    touchTexture(info->mSpecularMap, info->mVSize);
+    touchTexture(info->mNormalMap, info->mVSize);
 }
 
 void LLPipeline::postSort(LLCamera& camera)
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index 3ac3e3ce011..794d806d0cf 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -260,8 +260,11 @@ class LLPipeline
 	void stateSort(LLSpatialBridge* bridge, LLCamera& camera, BOOL fov_changed = FALSE);
 	void stateSort(LLDrawable* drawablep, LLCamera& camera);
 	void postSort(LLCamera& camera);
+    
     //update stats for textures in given DrawInfo
     void touchTextures(LLDrawInfo* info);
+    void touchTexture(LLViewerTexture* tex, F32 vsize);
+
 	void forAllVisibleDrawables(void (*func)(LLDrawable*));
 
     void renderObjects(U32 type, U32 mask, bool texture = true, bool batch_texture = false, bool rigged = false);
-- 
GitLab