Commits

davep  committed d19ccd3 Merge

merge

  • Participants
  • Parent commits acfb078, 824543e

Comments (0)

Files changed (323)

 3d75c836d178c7c7e788f256afe195f6cab764a2 3.2.7-beta1
 89980333c99dbaf1787fe20784f1d8849e9b5d4f 3.2.8-start
 16f8e2915f3f2e4d732fb3125daf229cb0fd1875 DRTVWR-114_3.2.8-beta1
+37dd400ad721e2a89ee820ffc1e7e433c68f3ca2 3.2.9-start
 16f8e2915f3f2e4d732fb3125daf229cb0fd1875 3.2.8-beta1
 987425b1acf4752379b2e1eb20944b4b35d67a85 DRTVWR-115_3.2.8-beta2
 987425b1acf4752379b2e1eb20944b4b35d67a85 3.2.8-beta2
 51b2fd52e36aab8f670e0874e7e1472434ec4b4a DRTVWR-113_3.2.8-release
 51b2fd52e36aab8f670e0874e7e1472434ec4b4a 3.2.8-release
-37dd400ad721e2a89ee820ffc1e7e433c68f3ca2 3.2.9-start
 e9c82fca5ae6fb8a8af29012d78fb194a29323f3 DRTVWR-117_3.2.9-beta1
 e9c82fca5ae6fb8a8af29012d78fb194a29323f3 3.2.9-beta1
 a01ef9bed28627f4ca543fbc1d70c79cc297a90f DRTVWR-118_3.2.9-beta2

File indra/linux_updater/linux_updater.cpp

 		else if ((!strcmp(argv[i], "--image-dir")) && (++i < argc))
 		{
 			app_state->image_dir = argv[i];
-			app_state->image_dir_iter = new LLDirIterator(argv[i], "/*.jpg");
+			app_state->image_dir_iter = new LLDirIterator(argv[i], "*.jpg");
 		}
 		else if ((!strcmp(argv[i], "--dest")) && (++i < argc))
 		{

File indra/llcharacter/llcharacter.h

 
 	virtual void addDebugText( const std::string& text ) = 0;
 
-	virtual const LLUUID&	getID() = 0;
+	virtual const LLUUID&	getID() const = 0;
 	//-------------------------------------------------------------------------
 	// End Interface
 	//-------------------------------------------------------------------------

File indra/llmessage/llcurl.cpp

 	  mErrorCount(0),
 	  mState(STATE_READY),
 	  mDead(FALSE),
+	  mValid(TRUE),
 	  mMutexp(NULL),
 	  mDeletionMutexp(NULL),
 	  mEasyMutexp(NULL)
 
 LLCurl::Multi::~Multi()
 {
-	cleanup() ;	
+	cleanup(true) ;	
+	
+	delete mDeletionMutexp ;
+	mDeletionMutexp = NULL ;	
 }
 
-void LLCurl::Multi::cleanup()
+void LLCurl::Multi::cleanup(bool deleted)
 {
 	if(!mCurlMultiHandle)
 	{
 		return ; //nothing to clean.
 	}
+	llassert_always(deleted || !mValid) ;
 
+	LLMutexLock lock(mDeletionMutexp);
+	
 	// Clean up active
 	for(easy_active_list_t::iterator iter = mEasyActiveList.begin();
 		iter != mEasyActiveList.end(); ++iter)
 	{
 		Easy* easy = *iter;
 		check_curl_multi_code(curl_multi_remove_handle(mCurlMultiHandle, easy->getCurlHandle()));
+
+		if(deleted)
+		{
+			easy->mResponder = NULL ; //avoid triggering mResponder.
+		}
 		delete easy;
 	}
 	mEasyActiveList.clear();
 
 	check_curl_multi_code(LLCurl::deleteMultiHandle(mCurlMultiHandle));
 	mCurlMultiHandle = NULL ;
-
+	
 	delete mMutexp ;
 	mMutexp = NULL ;
-	delete mDeletionMutexp ;
-	mDeletionMutexp = NULL ;
 	delete mEasyMutexp ;
 	mEasyMutexp = NULL ;
-	
+
 	mQueued = 0 ;
 	mState = STATE_COMPLETED;
 	
 
 void LLCurl::Multi::markDead()
 {
-	LLMutexLock lock(mDeletionMutexp) ;
+	{
+		LLMutexLock lock(mDeletionMutexp) ;
 	
-	mDead = TRUE ;
-	LLCurl::getCurlThread()->setPriority(mHandle, LLQueuedThread::PRIORITY_URGENT) ; 
+		if(mCurlMultiHandle != NULL)
+		{
+			mDead = TRUE ;
+			LLCurl::getCurlThread()->setPriority(mHandle, LLQueuedThread::PRIORITY_URGENT) ; 
+
+			return;
+		}
+	}
+	
+	//not valid, delete it.
+	delete this;	
 }
 
 void LLCurl::Multi::setState(LLCurl::Multi::ePerformState state)
 		setState(STATE_COMPLETED) ;		
 		mIdleTimer.reset() ;
 	}
-	else if(mIdleTimer.getElapsedTimeF32() > mIdleTimeOut) //idle for too long, remove it.
+	else if(!mValid && mIdleTimer.getElapsedTimeF32() > mIdleTimeOut) //idle for too long, remove it.
 	{
 		dead = true ;
 	}
+	else if(mValid && mIdleTimer.getElapsedTimeF32() > mIdleTimeOut - 1.f) //idle for too long, mark it invalid.
+	{
+		mValid = FALSE ;
+	}
 
 	return dead ;
 }
 		return ;
 	}
 
-	if(multi->isValid())
-	{
-		multi->markDead() ;
-	}
-	else
-	{
-		deleteMulti(multi) ;
-	}
+	multi->markDead() ;
 }
 
 //private
 void LLCurlThread::cleanupMulti(LLCurl::Multi* multi) 
 {
 	multi->cleanup() ;
+	if(multi->isDead()) //check if marked dead during cleaning up.
+	{
+		deleteMulti(multi) ;
+	}
 }
 
 //------------------------------------------------------------

File indra/llmessage/llcurl.h

 	ePerformState getState() ;
 	
 	bool isCompleted() ;
-	bool isValid() {return mCurlMultiHandle != NULL ;}
+	bool isValid() {return mCurlMultiHandle != NULL && mValid;}
 	bool isDead() {return mDead;}
 
 	bool waitToComplete() ;
 	
 private:
 	void easyFree(LLCurl::Easy*);
-	void cleanup() ;
+	void cleanup(bool deleted = false) ;
 	
 	CURLM* mCurlMultiHandle;
 
 	ePerformState mState;
 
 	BOOL mDead ;
+	BOOL mValid ;
 	LLMutex* mMutexp ;
 	LLMutex* mDeletionMutexp ;
 	LLMutex* mEasyMutexp ;

File indra/llrender/llgl.cpp

 	llwarns << "Severity: " << std::hex << severity << llendl;
 	llwarns << "Message: " << message << llendl;
 	llwarns << "-----------------------" << llendl;
+	if (severity == GL_DEBUG_SEVERITY_HIGH_ARB)
+	{
+		llerrs << "Halting on GL Error" << llendl;
+	}
 }
 #endif
 
+void parse_glsl_version(S32& major, S32& minor);
+
 void ll_init_fail_log(std::string filename)
 {
 	gFailLog.open(filename.c_str());
 PFNGLGETUNIFORMFVARBPROC glGetUniformfvARB = NULL;
 PFNGLGETUNIFORMIVARBPROC glGetUniformivARB = NULL;
 PFNGLGETSHADERSOURCEARBPROC glGetShaderSourceARB = NULL;
+PFNGLVERTEXATTRIBIPOINTERPROC glVertexAttribIPointer = NULL;
 
 #if LL_WINDOWS
 PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = NULL;
 	mDriverVersionMinor(0),
 	mDriverVersionRelease(0),
 	mGLVersion(1.0f),
-		
+	mGLSLVersionMajor(0),
+	mGLSLVersionMinor(0),		
 	mVRAM(0),
 	mGLMaxVertexRange(0),
 	mGLMaxIndexRange(0)
 
 	mGLVersion = mDriverVersionMajor + mDriverVersionMinor * .1f;
 
+	if (mGLVersion >= 2.f)
+	{
+		parse_glsl_version(mGLSLVersionMajor, mGLSLVersionMinor);
+
+#if LL_DARWIN
+		//never use GLSL greater than 1.20 on OSX
+		if (mGLSLVersionMajor > 1 || mGLSLVersionMinor >= 30)
+		{
+			mGLSLVersionMajor = 1;
+			mGLSLVersionMinor = 20;
+		}
+#endif
+	}
+
+	if (mGLVersion >= 2.1f && LLImageGL::sCompressTextures)
+	{ //use texture compression
+		glHint(GL_TEXTURE_COMPRESSION_HINT, GL_NICEST);
+	}
+	else
+	{ //GL version is < 3.0, always disable texture compression
+		LLImageGL::sCompressTextures = false;
+	}
+	
 	// Trailing space necessary to keep "nVidia Corpor_ati_on" cards
 	// from being recognized as ATI.
 	if (mGLVendor.substr(0,4) == "ATI ")
 #endif // LL_WINDOWS
 
 #if (LL_WINDOWS || LL_LINUX) && !LL_MESA_HEADLESS
-		// release 7277 is a point at which we verify that ATI OpenGL
-		// drivers get pretty stable with SL, ~Catalyst 8.2,
-		// for both Win32 and Linux.
-		if (mDriverVersionRelease < 7277 &&
-		    mDriverVersionRelease != 0) // 0 == Undetectable driver version - these get to pretend to be new ATI drivers, though that decision may be revisited.
+		// count any pre OpenGL 3.0 implementation as an old driver
+		if (mGLVersion < 3.f) 
 		{
 			mATIOldDriver = TRUE;
 		}
 	}
 #endif
 
+	if (mIsIntel)
+	{ //never try to use framebuffer objects on intel (crashy)
+		mHasFramebufferObject = FALSE;
+	}
+
 	if (mHasFramebufferObject)
 	{
 		glGetIntegerv(GL_MAX_SAMPLES, &mMaxSamples);
 		glVertexAttrib4uivARB = (PFNGLVERTEXATTRIB4UIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4uivARB");
 		glVertexAttrib4usvARB = (PFNGLVERTEXATTRIB4USVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4usvARB");
 		glVertexAttribPointerARB = (PFNGLVERTEXATTRIBPOINTERARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttribPointerARB");
+		glVertexAttribIPointer = (PFNGLVERTEXATTRIBIPOINTERPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttribIPointer");
 		glEnableVertexAttribArrayARB = (PFNGLENABLEVERTEXATTRIBARRAYARBPROC) GLH_EXT_GET_PROC_ADDRESS("glEnableVertexAttribArrayARB");
 		glDisableVertexAttribArrayARB = (PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDisableVertexAttribArrayARB");
 		glProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramStringARB");
 	}
 }
 
+
+void parse_glsl_version(S32& major, S32& minor)
+{
+	// GL_SHADING_LANGUAGE_VERSION returns a null-terminated string with the format: 
+	// <major>.<minor>[.<release>] [<vendor specific>]
+
+	const char* version = (const char*) glGetString(GL_SHADING_LANGUAGE_VERSION);
+	major = 0;
+	minor = 0;
+	
+	if( !version )
+	{
+		return;
+	}
+
+	std::string ver_copy( version );
+	S32 len = (S32)strlen( version );	/* Flawfinder: ignore */
+	S32 i = 0;
+	S32 start;
+	// Find the major version
+	start = i;
+	for( ; i < len; i++ )
+	{
+		if( '.' == version[i] )
+		{
+			break;
+		}
+	}
+	std::string major_str = ver_copy.substr(start,i-start);
+	LLStringUtil::convertToS32(major_str, major);
+
+	if( '.' == version[i] )
+	{
+		i++;
+	}
+
+	// Find the minor version
+	start = i;
+	for( ; i < len; i++ )
+	{
+		if( ('.' == version[i]) || isspace(version[i]) )
+		{
+			break;
+		}
+	}
+	std::string minor_str = ver_copy.substr(start,i-start);
+	LLStringUtil::convertToS32(minor_str, minor);
+}
+
 LLGLUserClipPlane::LLGLUserClipPlane(const LLPlane& p, const glh::matrix4f& modelview, const glh::matrix4f& projection, bool apply)
 {
 	mApply = apply;

File indra/llrender/llgl.h

 	S32 mDriverVersionMinor;
 	S32 mDriverVersionRelease;
 	F32 mGLVersion; // e.g = 1.4
+	S32 mGLSLVersionMajor;
+	S32 mGLSLVersionMinor;
 	std::string mDriverVersionVendorString;
 
 	S32 mVRAM; // VRAM in MB

File indra/llrender/llglheaders.h

 extern PFNGLVERTEXATTRIB4UIVARBPROC glVertexAttrib4uivARB;
 extern PFNGLVERTEXATTRIB4USVARBPROC glVertexAttrib4usvARB;
 extern PFNGLVERTEXATTRIBPOINTERARBPROC glVertexAttribPointerARB;
+extern PFNGLVERTEXATTRIBIPOINTERPROC glVertexAttribIPointer;
 extern PFNGLENABLEVERTEXATTRIBARRAYARBPROC glEnableVertexAttribArrayARB;
 extern PFNGLDISABLEVERTEXATTRIBARRAYARBPROC glDisableVertexAttribArrayARB;
 extern PFNGLPROGRAMSTRINGARBPROC glProgramStringARB;
 extern PFNGLVERTEXATTRIB4UIVARBPROC glVertexAttrib4uivARB;
 extern PFNGLVERTEXATTRIB4USVARBPROC glVertexAttrib4usvARB;
 extern PFNGLVERTEXATTRIBPOINTERARBPROC glVertexAttribPointerARB;
+extern PFNGLVERTEXATTRIBIPOINTERPROC glVertexAttribIPointer;
 extern PFNGLENABLEVERTEXATTRIBARRAYARBPROC glEnableVertexAttribArrayARB;
 extern PFNGLDISABLEVERTEXATTRIBARRAYARBPROC glDisableVertexAttribArrayARB;
 extern PFNGLPROGRAMSTRINGARBPROC glProgramStringARB;
 extern PFNGLVERTEXATTRIB4UIVARBPROC glVertexAttrib4uivARB;
 extern PFNGLVERTEXATTRIB4USVARBPROC glVertexAttrib4usvARB;
 extern PFNGLVERTEXATTRIBPOINTERARBPROC glVertexAttribPointerARB;
+extern PFNGLVERTEXATTRIBIPOINTERPROC glVertexAttribIPointer;
 extern PFNGLENABLEVERTEXATTRIBARRAYARBPROC glEnableVertexAttribArrayARB;
 extern PFNGLDISABLEVERTEXATTRIBARRAYARBPROC glDisableVertexAttribArrayARB;
 extern PFNGLPROGRAMSTRINGARBPROC glProgramStringARB;

File indra/llrender/llglslshader.cpp

 }
 
 LLShaderFeatures::LLShaderFeatures()
-: calculatesLighting(false), isShiny(false), isFullbright(false), hasWaterFog(false),
-hasTransport(false), hasSkinning(false), hasObjectSkinning(false), hasAtmospherics(false), isSpecular(false),
-hasGamma(false), hasLighting(false), isAlphaLighting(false), calculatesAtmospherics(false), mIndexedTextureChannels(0), disableTextureIndex(false),
-hasAlphaMask(false)
+	: atmosphericHelpers(false)
+	, calculatesLighting(false)
+	, calculatesAtmospherics(false)
+	, hasLighting(false)
+	, isAlphaLighting(false)
+	, isShiny(false)
+	, isFullbright(false)
+	, isSpecular(false)
+	, hasWaterFog(false)
+	, hasTransport(false)
+	, hasSkinning(false)
+	, hasObjectSkinning(false)
+	, hasAtmospherics(false)
+	, hasGamma(false)
+	, mIndexedTextureChannels(0)
+	, disableTextureIndex(false)
+	, hasAlphaMask(false)
 {
 }
 
 		glGetAttachedObjectsARB(mProgramObject, 1024, &count, obj);
 		for (GLsizei i = 0; i < count; i++)
 		{
-			glDeleteObjectARB(obj[i]);
+#if !LL_DARWIN
+			if (glIsProgramARB(obj[i]))
+#endif
+			{
+				glDeleteObjectARB(obj[i]);
+			}
 		}
 
 		glDeleteObjectARB(mProgramObject);
 		return FALSE;
 	}
 
-	if (gGLManager.mGLVersion < 3.1f)
-	{ //attachShaderFeatures may have set the number of indexed texture channels, so set to 1 again
+	if (gGLManager.mGLSLVersionMajor < 2 && gGLManager.mGLSLVersionMinor < 3)
+	{ //indexed texture rendering requires GLSL 1.3 or later
+		//attachShaderFeatures may have set the number of indexed texture channels, so set to 1 again
 		mFeatures.mIndexedTextureChannels = llmin(mFeatures.mIndexedTextureChannels, 1);
 	}
 

File indra/llrender/llglslshader.h

 class LLShaderFeatures
 {
 public:
+	bool atmosphericHelpers;
 	bool calculatesLighting;
 	bool calculatesAtmospherics;
 	bool hasLighting; // implies no transport (it's possible to have neither though)

File indra/llrender/llimagegl.cpp

 F32 LLImageGL::sLastFrameTime			= 0.f;
 BOOL LLImageGL::sAllowReadBackRaw       = FALSE ;
 LLImageGL* LLImageGL::sDefaultGLTexture = NULL ;
+bool LLImageGL::sCompressTextures = false;
 
 std::set<LLImageGL*> LLImageGL::sImageList;
 
 	mDiscardLevelInAtlas = -1 ;
 	mTexelsInAtlas = 0 ;
 	mTexelsInGLTexture = 0 ;
+
+	mAllowCompression = true;
 	
 	mTarget = GL_TEXTURE_2D;
 	mBindTarget = LLTexUnit::TT_TEXTURE;
 						stop_glerror();
 					}
 						
-					LLImageGL::setManualImage(mTarget, gl_level, mFormatInternal, w, h, mFormatPrimary, GL_UNSIGNED_BYTE, (GLvoid*)data_in);
+					LLImageGL::setManualImage(mTarget, gl_level, mFormatInternal, w, h, mFormatPrimary, GL_UNSIGNED_BYTE, (GLvoid*)data_in, mAllowCompression);
 					if (gl_level == 0)
 					{
 						analyzeAlpha(data_in, w, h);
 					LLImageGL::setManualImage(mTarget, 0, mFormatInternal,
 								 w, h, 
 								 mFormatPrimary, mFormatType,
-								 data_in);
+								 data_in, mAllowCompression);
 					analyzeAlpha(data_in, w, h);
 					stop_glerror();
 
 							stop_glerror();
 						}
 
-						LLImageGL::setManualImage(mTarget, m, mFormatInternal, w, h, mFormatPrimary, mFormatType, cur_mip_data);
+						LLImageGL::setManualImage(mTarget, m, mFormatInternal, w, h, mFormatPrimary, mFormatType, cur_mip_data, mAllowCompression);
 						if (m == 0)
 						{
 							analyzeAlpha(data_in, w, h);
 			}
 
 			LLImageGL::setManualImage(mTarget, 0, mFormatInternal, w, h,
-						 mFormatPrimary, mFormatType, (GLvoid *)data_in);
+						 mFormatPrimary, mFormatType, (GLvoid *)data_in, mAllowCompression);
 			analyzeAlpha(data_in, w, h);
 			
 			updatePickMask(w, h, data_in);
 }
 
 // static
-void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels)
+void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels, bool allow_compression)
 {
 	bool use_scratch = false;
 	U32* scratch = NULL;
 		}
 	}
 
+	if (LLImageGL::sCompressTextures && allow_compression)
+	{
+		switch (intformat)
+		{
+			case GL_RGB: 
+			case GL_RGB8:
+				intformat = GL_COMPRESSED_RGB; 
+				break;
+			case GL_RGBA:
+			case GL_RGBA8:
+				intformat = GL_COMPRESSED_RGBA; 
+				break;
+			case GL_LUMINANCE:
+			case GL_LUMINANCE8:
+				intformat = GL_COMPRESSED_LUMINANCE;
+				break;
+			case GL_LUMINANCE_ALPHA:
+			case GL_LUMINANCE8_ALPHA8:
+				intformat = GL_COMPRESSED_LUMINANCE_ALPHA;
+				break;
+			case GL_ALPHA:
+			case GL_ALPHA8:
+				intformat = GL_COMPRESSED_ALPHA;
+				break;
+			default:
+				llwarns << "Could not compress format: " << std::hex << intformat << llendl;
+				break;
+		}
+	}
+
 	stop_glerror();
 	glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, use_scratch ? scratch : pixels);
 	stop_glerror();

File indra/llrender/llimagegl.h

 	
 	void setSize(S32 width, S32 height, S32 ncomponents);
 	void setComponents(S32 ncomponents) { mComponents = (S8)ncomponents ;}
+	void setAllowCompression(bool allow) { mAllowCompression = allow; }
 
 	// 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, bool immediate = false);
-	static void setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels);
+	static void setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels, bool allow_compression = true);
 
 	BOOL createGLTexture() ;
 	BOOL createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0, BOOL to_create = TRUE, 
 	U32      mTexelsInAtlas ;
 	U32      mTexelsInGLTexture;
 
+	bool mAllowCompression;
+
 protected:
 	LLGLenum mTarget;		// Normally GL_TEXTURE2D, sometimes something else (ex. cube maps)
 	LLTexUnit::eTextureType mBindTarget;	// Normally TT_TEXTURE, sometimes something else (ex. cube maps)
 	static BOOL sGlobalUseAnisotropic;
 	static LLImageGL* sDefaultGLTexture ;	
 	static BOOL sAutomatedTest;
-
+	static bool sCompressTextures;			//use GL texture compression
 #if DEBUG_MISS
 	BOOL mMissed; // Missed on last bind?
 	BOOL getMissed() const { return mMissed; };

File indra/llrender/llrendertarget.cpp

 
 	{
 		clear_glerror();
-		LLImageGL::setManualImage(LLTexUnit::getInternalType(mUsage), 0, color_fmt, mResX, mResY, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+		LLImageGL::setManualImage(LLTexUnit::getInternalType(mUsage), 0, color_fmt, mResX, mResY, GL_RGBA, GL_UNSIGNED_BYTE, NULL, false);
 		if (glGetError() != GL_NO_ERROR)
 		{
 			llwarns << "Could not allocate color buffer for render target." << llendl;
 		U32 internal_type = LLTexUnit::getInternalType(mUsage);
 		stop_glerror();
 		clear_glerror();
-		LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT24, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
+		LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT24, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL, false);
 		gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
 	}
 

File indra/llrender/llshadermgr.cpp

 		}
 	}
 
-	if (features->calculatesLighting)
+	if (features->calculatesLighting || features->atmosphericHelpers)
 	{
 		if (!shader->attachObject("windlight/atmosphericsHelpersV.glsl"))
 		{
 			return FALSE;
 		}
+	}
 		
+	if (features->calculatesLighting)
+	{
 		if (features->isSpecular)
 		{
 			if (!shader->attachObject("lighting/lightFuncSpecularV.glsl"))
 	GLcharARB* text[4096];
 	GLuint count = 0;
 
-	F32 version = gGLManager.mGLVersion;
+	S32 major_version = gGLManager.mGLSLVersionMajor;
+	S32 minor_version = gGLManager.mGLSLVersionMinor;
+	
+	if (major_version == 1 && minor_version < 30)
+	{
+		if (minor_version < 10)
+		{
+			//should NEVER get here -- if major version is 1 and minor version is less than 10, 
+			// viewer should never attempt to use shaders, continuing will result in undefined behavior
+			llerrs << "Unsupported GLSL Version." << llendl;
+		}
 
-//hack to never use GLSL > 1.20 on OSX
-#if LL_DARWIN
-	version = llmin(version, 2.9f);
-#endif
-
-	if (version < 2.1f)
-	{
-		text[count++] = strdup("#version 110\n");
-		text[count++] = strdup("#define ATTRIBUTE attribute\n");
-		text[count++] = strdup("#define VARYING varying\n");
-	}
-	else if (version < 3.3f)
-	{
-		//set version to 1.20
-		text[count++] = strdup("#version 120\n");
-		text[count++] = strdup("#define FXAA_GLSL_120 1\n");
-		text[count++] = strdup("#define FXAA_FAST_PIXEL_OFFSET 0\n");
-		text[count++] = strdup("#define ATTRIBUTE attribute\n");
-		text[count++] = strdup("#define VARYING varying\n");
+		if (minor_version <= 19)
+		{
+			text[count++] = strdup("#version 110\n");
+			text[count++] = strdup("#define ATTRIBUTE attribute\n");
+			text[count++] = strdup("#define VARYING varying\n");
+			text[count++] = strdup("#define VARYING_FLAT varying\n");
+		}
+		else if (minor_version <= 29)
+		{
+			//set version to 1.20
+			text[count++] = strdup("#version 120\n");
+			text[count++] = strdup("#define FXAA_GLSL_120 1\n");
+			text[count++] = strdup("#define FXAA_FAST_PIXEL_OFFSET 0\n");
+			text[count++] = strdup("#define ATTRIBUTE attribute\n");
+			text[count++] = strdup("#define VARYING varying\n");
+			text[count++] = strdup("#define VARYING_FLAT varying\n");
+		}
 	}
 	else
 	{  
-		if (version < 4.f)
+		if (major_version < 4)
 		{
 			//set version to 1.30
 			text[count++] = strdup("#version 130\n");
+
+			//some implementations of GLSL 1.30 require integer precision be explicitly declared
+			text[count++] = strdup("precision mediump int;\n");
+			text[count++] = strdup("precision highp float;\n");
 		}
 		else
 		{ //set version to 400
 		{ //"varying" state is "out" in a vertex program, "in" in a fragment program 
 			// ("varying" is deprecated after version 1.20)
 			text[count++] = strdup("#define VARYING out\n");
+			text[count++] = strdup("#define VARYING_FLAT flat out\n");
 		}
 		else
 		{
 			text[count++] = strdup("#define VARYING in\n");
+			text[count++] = strdup("#define VARYING_FLAT flat in\n");
 		}
 
 		//backwards compatibility with legacy texture lookup syntax
+		text[count++] = strdup("#define texture2D texture\n");
 		text[count++] = strdup("#define textureCube texture\n");
 		text[count++] = strdup("#define texture2DLod textureLod\n");
 		text[count++] = strdup("#define	shadow2D(a,b) vec2(texture(a,b))\n");
+
+		if (major_version > 1 || minor_version >= 40)
+		{ //GLSL 1.40 replaces texture2DRect et al with texture
+			text[count++] = strdup("#define texture2DRect texture\n");
+			text[count++] = strdup("#define shadow2DRect(a,b) vec2(texture(a,b))\n");
+		}
 	}
 
 	//copy preprocessor definitions into buffer
 		.
 		uniform sampler2D texN;
 		
-		VARYING float vary_texture_index;
+		VARYING_FLAT ivec4 vary_texture_index;
+
+		vec4 ret = vec4(1,0,1,1);
 
 		vec4 diffuseLookup(vec2 texcoord)
 		{
-			switch (int(vary_texture_index+0.25))
+			switch (vary_texture_index.r))
 			{
-				case 0: return texture2D(tex0, texcoord);
-				case 1: return texture2D(tex1, texcoord);
-				case 2: return texture2D(tex2, texcoord);
+				case 0: ret = texture2D(tex0, texcoord); break;
+				case 1: ret = texture2D(tex1, texcoord); break;
+				case 2: ret = texture2D(tex2, texcoord); break;
 				.
 				.
 				.
-				case N: return texture2D(texN, texcoord);
+				case N: return texture2D(texN, texcoord); break;
 			}
 
-			return vec4(0,0,0,0);
+			return ret;
 		}
 		*/
 
 
 		if (texture_index_channels > 1)
 		{
-			text[count++] = strdup("VARYING float vary_texture_index;\n");
+			text[count++] = strdup("VARYING_FLAT ivec4 vary_texture_index;\n");
 		}
 
 		text[count++] = strdup("vec4 diffuseLookup(vec2 texcoord)\n");
 			text[count++] = strdup("return texture2D(tex0, texcoord);\n");
 			text[count++] = strdup("}\n");
 		}
-		else if (gGLManager.mGLVersion >= 3.f)
-		{ 
-			text[count++] = strdup("\tswitch (int(vary_texture_index+0.25))\n");
+		else if (major_version > 1 || minor_version >= 30)
+		{  //switches are supported in GLSL 1.30 and later
+			text[count++] = strdup("\tvec4 ret = vec4(1,0,1,1);\n");
+			text[count++] = strdup("\tswitch (vary_texture_index.r)\n");
 			text[count++] = strdup("\t{\n");
 		
 			//switch body
 			for (S32 i = 0; i < texture_index_channels; ++i)
 			{
-				std::string case_str = llformat("\t\tcase %d: return texture2D(tex%d, texcoord);\n", i, i);
+				std::string case_str = llformat("\t\tcase %d: ret = texture2D(tex%d, texcoord); break;\n", i, i);
 				text[count++] = strdup(case_str.c_str());
 			}
 
 			text[count++] = strdup("\t}\n");
-			text[count++] = strdup("\treturn vec4(1,0,1,1);\n");
+			text[count++] = strdup("\treturn ret;\n");
 			text[count++] = strdup("}\n");
 		}
 		else
-		{
-			//switches aren't supported, make block that looks like:
-			/*
-				int ti = int(vary_texture_index+0.25);
-				if (ti == 0) return texture2D(tex0, texcoord);
-				if (ti == 1) return texture2D(tex1, texcoord);
-				.
-				.
-				.
-				if (ti == N) return texture2D(texN, texcoord);
-			*/
-				
-			text[count++] = strdup("int ti = int(vary_texture_index+0.25);\n");
-			for (S32 i = 0; i < texture_index_channels; ++i)
-			{
-				std::string if_str = llformat("if (ti == %d) return texture2D(tex%d, texcoord);\n", i, i);
-				text[count++] = strdup(if_str.c_str());
-			}
-
-			text[count++] = strdup("\treturn vec4(1,0,1,1);\n");
-			text[count++] = strdup("}\n");
-		}			
+		{ //should never get here.  Indexed texture rendering requires GLSL 1.30 or later 
+			// (for passing integers between vertex and fragment shaders)
+			llerrs << "Indexed texture rendering requires GLSL 1.30 or later." << llendl;
+		}
 	}
 
 	//copy file into memory
 	mReservedUniforms.push_back("magnification");
 	mReservedUniforms.push_back("max_cof");
 	mReservedUniforms.push_back("res_scale");
+	mReservedUniforms.push_back("dof_width");
+	mReservedUniforms.push_back("dof_height");
 
 	mReservedUniforms.push_back("depthMap");
 	mReservedUniforms.push_back("shadowMap0");

File indra/llrender/llshadermgr.h

 		DOF_MAGNIFICATION,
 		DOF_MAX_COF,
 		DOF_RES_SCALE,
+		DOF_WIDTH,
+		DOF_HEIGHT,
 
 		DEFERRED_DEPTH,
 		DEFERRED_SHADOW0,

File indra/llrender/llvertexbuffer.cpp

 #include "llglslshader.h"
 #include "llmemory.h"
 
+#define LL_VBO_POOLING 0
+
 //Next Highest Power Of Two
 //helper function, returns first number > v that is a power of 2, or v if v is already a power of 2
 U32 nhpo2(U32 v)
 	return r;
 }
 
+//which power of 2 is i?
+//assumes i is a power of 2 > 0
+U32 wpo2(U32 i)
+{
+	llassert(i > 0);
+	llassert(nhpo2(i) == i);
+
+	U32 r = 0;
+
+	while (i >>= 1) ++r;
+
+	return r;
+}
+
+
+const U32 LL_VBO_BLOCK_SIZE = 2048;
+
+U32 vbo_block_size(U32 size)
+{ //what block size will fit size?
+	U32 mod = size % LL_VBO_BLOCK_SIZE;
+	return mod == 0 ? size : size + (LL_VBO_BLOCK_SIZE-mod);
+}
+
+U32 vbo_block_index(U32 size)
+{
+	return vbo_block_size(size)/LL_VBO_BLOCK_SIZE;
+}
+
+
 
 //============================================================================
 
 //static
-LLVBOPool LLVertexBuffer::sStreamVBOPool;
-LLVBOPool LLVertexBuffer::sDynamicVBOPool;
-LLVBOPool LLVertexBuffer::sStreamIBOPool;
-LLVBOPool LLVertexBuffer::sDynamicIBOPool;
+LLVBOPool LLVertexBuffer::sStreamVBOPool(GL_STREAM_DRAW_ARB, GL_ARRAY_BUFFER_ARB);
+LLVBOPool LLVertexBuffer::sDynamicVBOPool(GL_DYNAMIC_DRAW_ARB, GL_ARRAY_BUFFER_ARB);
+LLVBOPool LLVertexBuffer::sStreamIBOPool(GL_STREAM_DRAW_ARB, GL_ELEMENT_ARRAY_BUFFER_ARB);
+LLVBOPool LLVertexBuffer::sDynamicIBOPool(GL_DYNAMIC_DRAW_ARB, GL_ELEMENT_ARRAY_BUFFER_ARB);
+
 U32 LLVBOPool::sBytesPooled = 0;
+U32 LLVBOPool::sIndexBytesPooled = 0;
+U32 LLVertexBuffer::sAllocatedIndexBytes = 0;
+U32 LLVertexBuffer::sIndexCount = 0;
 
-LLPrivateMemoryPool* LLVertexBuffer::sPrivatePoolp = NULL ;
+LLPrivateMemoryPool* LLVertexBuffer::sPrivatePoolp = NULL;
 U32 LLVertexBuffer::sBindCount = 0;
 U32 LLVertexBuffer::sSetCount = 0;
 S32 LLVertexBuffer::sCount = 0;
 S32 LLVertexBuffer::sGLCount = 0;
 S32 LLVertexBuffer::sMappedCount = 0;
-BOOL LLVertexBuffer::sDisableVBOMapping = FALSE ;
-BOOL LLVertexBuffer::sEnableVBOs = TRUE;
+bool LLVertexBuffer::sDisableVBOMapping = false;
+bool LLVertexBuffer::sEnableVBOs = true;
 U32 LLVertexBuffer::sGLRenderBuffer = 0;
 U32 LLVertexBuffer::sGLRenderArray = 0;
 U32 LLVertexBuffer::sGLRenderIndices = 0;
 U32 LLVertexBuffer::sLastMask = 0;
-BOOL LLVertexBuffer::sVBOActive = FALSE;
-BOOL LLVertexBuffer::sIBOActive = FALSE;
+bool LLVertexBuffer::sVBOActive = false;
+bool LLVertexBuffer::sIBOActive = false;
 U32 LLVertexBuffer::sAllocatedBytes = 0;
-BOOL LLVertexBuffer::sMapped = FALSE;
-BOOL LLVertexBuffer::sUseStreamDraw = TRUE;
-BOOL LLVertexBuffer::sUseVAO = FALSE;
-BOOL LLVertexBuffer::sPreferStreamDraw = FALSE;
+U32 LLVertexBuffer::sVertexCount = 0;
+bool LLVertexBuffer::sMapped = false;
+bool LLVertexBuffer::sUseStreamDraw = true;
+bool LLVertexBuffer::sUseVAO = false;
+bool LLVertexBuffer::sPreferStreamDraw = false;
 
 const U32 FENCE_WAIT_TIME_NANOSECONDS = 10000;  //1 ms
 
 };
 
 
-//which power of 2 is i?
-//assumes i is a power of 2 > 0
-U32 wpo2(U32 i)
-{
-	llassert(i > 0);
-	llassert(nhpo2(i) == i);
-
-	U32 r = 0;
-
-	while (i >>= 1) ++r;
-
-	return r;
-}
-
 volatile U8* LLVBOPool::allocate(U32& name, U32 size)
 {
-	llassert(nhpo2(size) == size);
+	llassert(vbo_block_size(size) == size);
+	
+	volatile U8* ret = NULL;
 
-	U32 i = wpo2(size);
+#if LL_VBO_POOLING
+
+	U32 i = vbo_block_index(size);
 
 	if (mFreeList.size() <= i)
 	{
 		mFreeList.resize(i+1);
 	}
 
-	volatile U8* ret = NULL;
-
 	if (mFreeList[i].empty())
 	{
 		//make a new buffer
 		glGenBuffersARB(1, &name);
 		glBindBufferARB(mType, name);
-		LLVertexBuffer::sAllocatedBytes += size;
+
+		if (mType == GL_ARRAY_BUFFER_ARB)
+		{
+			LLVertexBuffer::sAllocatedBytes += size;
+		}
+		else
+		{
+			LLVertexBuffer::sAllocatedIndexBytes += size;
+		}
 
 		if (LLVertexBuffer::sDisableVBOMapping || mUsage != GL_DYNAMIC_DRAW_ARB)
 		{
 		name = mFreeList[i].front().mGLName;
 		ret = mFreeList[i].front().mClientData;
 
-		sBytesPooled -= size;
+		if (mType == GL_ARRAY_BUFFER_ARB)
+		{
+			sBytesPooled -= size;
+		}
+		else
+		{
+			sIndexBytesPooled -= size;
+		}
 
 		mFreeList[i].pop_front();
 	}
+#else //no pooling
+
+	glGenBuffersARB(1, &name);
+	glBindBufferARB(mType, name);
+
+	if (mType == GL_ARRAY_BUFFER_ARB)
+	{
+		LLVertexBuffer::sAllocatedBytes += size;
+	}
+	else
+	{
+		LLVertexBuffer::sAllocatedIndexBytes += size;
+	}
+
+	if (LLVertexBuffer::sDisableVBOMapping || mUsage != GL_DYNAMIC_DRAW_ARB)
+	{
+		glBufferDataARB(mType, size, 0, mUsage);
+		ret = (U8*) ll_aligned_malloc_16(size);
+	}
+	else
+	{ //always use a true hint of static draw when allocating non-client-backed buffers
+		glBufferDataARB(mType, size, 0, GL_STATIC_DRAW_ARB);
+	}
+
+	glBindBufferARB(mType, 0);
+
+#endif
 
 	return ret;
 }
 
 void LLVBOPool::release(U32 name, volatile U8* buffer, U32 size)
 {
-	llassert(nhpo2(size) == size);
+	llassert(vbo_block_size(size) == size);
 
-	U32 i = wpo2(size);
+#if LL_VBO_POOLING
+
+	U32 i = vbo_block_index(size);
 
 	llassert(mFreeList.size() > i);
 
 	Record rec;
 	rec.mGLName = name;
 	rec.mClientData = buffer;
-
-	sBytesPooled += size;
 	
-	if (!LLVertexBuffer::sDisableVBOMapping && mUsage == GL_DYNAMIC_DRAW_ARB)
+	if (buffer == NULL)
 	{
 		glDeleteBuffersARB(1, &rec.mGLName);
 	}
 	else
 	{
+		if (mType == GL_ARRAY_BUFFER_ARB)
+		{
+			sBytesPooled += size;
+		}
+		else
+		{
+			sIndexBytesPooled += size;
+		}
 		mFreeList[i].push_back(rec);
 	}
+#else //no pooling
+	glDeleteBuffersARB(1, &name);
+	ll_aligned_free_16((U8*) buffer);
+
+	if (mType == GL_ARRAY_BUFFER_ARB)
+	{
+		LLVertexBuffer::sAllocatedBytes -= size;
+	}
+	else
+	{
+		LLVertexBuffer::sAllocatedIndexBytes -= size;
+	}
+#endif
 }
 
 void LLVBOPool::cleanup()
 
 			l.pop_front();
 
-			LLVertexBuffer::sAllocatedBytes -= size;
-			sBytesPooled -= size;
+			if (mType == GL_ARRAY_BUFFER_ARB)
+			{
+				sBytesPooled -= size;
+				LLVertexBuffer::sAllocatedBytes -= size;
+			}
+			else
+			{
+				sIndexBytesPooled -= size;
+				LLVertexBuffer::sAllocatedIndexBytes -= size;
+			}
 		}
 
 		size *= 2;
 {
 	if (sLastMask != data_mask)
 	{
-		BOOL error = FALSE;
+		bool error = false;
+
+		if (gGLManager.mGLSLVersionMajor < 2 && gGLManager.mGLSLVersionMinor < 30)
+		{
+			//make sure texture index is disabled
+			data_mask = data_mask & ~MAP_TEXTURE_INDEX;
+		}
 
 		if (LLGLSLShader::sNoFixedFunction)
 		{
 						{
 							if (gDebugSession)
 							{
-								error = TRUE;
+								error = true;
 								gFailLog << "Bad client state! " << array[i] << " disabled." << std::endl;
 							}
 							else
 					{ //needs to be disabled, make sure it was (DEBUG TEMPORARY)
 						if (gDebugSession)
 						{
-							error = TRUE;
+							error = true;
 							gFailLog << "Bad client state! " << array[i] << " enabled." << std::endl;
 						}
 						else
 
 	U32 count = pos.size();
 	llassert_always(norm.size() >= pos.size());
-	llassert_always(count > 0) ;
+	llassert_always(count > 0);
 
 	unbind();
 	
 void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const
 {
 	validateRange(start, end, count, indices_offset);
-	mMappable = FALSE;
+	mMappable = false;
 	gGL.syncMatrices();
 
 	llassert(mNumVerts >= 0);
 void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const
 {
 	llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
-	mMappable = FALSE;
+	mMappable = false;
 	gGL.syncMatrices();
 
 	llassert(mNumIndices >= 0);
 void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const
 {
 	llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
-	mMappable = FALSE;
+	mMappable = false;
 	gGL.syncMatrices();
 	
 	llassert(mNumVerts >= 0);
 //static
 void LLVertexBuffer::initClass(bool use_vbo, bool no_vbo_mapping)
 {
-	sEnableVBOs = use_vbo && gGLManager.mHasVertexBufferObject ;
-	sDisableVBOMapping = sEnableVBOs && no_vbo_mapping ;
+	sEnableVBOs = use_vbo && gGLManager.mHasVertexBufferObject;
+	sDisableVBOMapping = sEnableVBOs && no_vbo_mapping;
 
-	if(!sPrivatePoolp)
+	if (!sPrivatePoolp)
 	{ 
-		sPrivatePoolp = LLPrivateMemoryPoolManager::getInstance()->newPool(LLPrivateMemoryPool::STATIC) ;
+		sPrivatePoolp = LLPrivateMemoryPoolManager::getInstance()->newPool(LLPrivateMemoryPool::STATIC);
 	}
-
-	sStreamVBOPool.mType = GL_ARRAY_BUFFER_ARB;
-	sStreamVBOPool.mUsage= GL_STREAM_DRAW_ARB;
-	sStreamIBOPool.mType = GL_ELEMENT_ARRAY_BUFFER_ARB;
-	sStreamIBOPool.mUsage= GL_STREAM_DRAW_ARB;
-
-	sDynamicVBOPool.mType = GL_ARRAY_BUFFER_ARB;
-	sDynamicVBOPool.mUsage= GL_DYNAMIC_DRAW_ARB;
-	sDynamicIBOPool.mType = GL_ELEMENT_ARRAY_BUFFER_ARB;
-	sDynamicIBOPool.mUsage= GL_DYNAMIC_DRAW_ARB;
 }
 
 //static 
 #endif
 		sGLRenderArray = 0;
 		sGLRenderIndices = 0;
-		sIBOActive = FALSE;
+		sIBOActive = false;
 	}
 
 	if (sVBOActive)
 	{
 		glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
-		sVBOActive = FALSE;
+		sVBOActive = false;
 	}
 	if (sIBOActive)
 	{
 		glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
-		sIBOActive = FALSE;
+		sIBOActive = false;
 	}
 
 	sGLRenderBuffer = 0;
 
 	if(sPrivatePoolp)
 	{
-		LLPrivateMemoryPoolManager::getInstance()->deletePool(sPrivatePoolp) ;
-		sPrivatePoolp = NULL ;
+		LLPrivateMemoryPoolManager::getInstance()->deletePool(sPrivatePoolp);
+		sPrivatePoolp = NULL;
 	}
 }
 
 //----------------------------------------------------------------------------
 
+S32 LLVertexBuffer::determineUsage(S32 usage)
+{
+	S32 ret_usage = usage;
+
+	if (!sEnableVBOs)
+	{
+		ret_usage = 0;
+	}
+	
+	if (ret_usage == GL_STREAM_DRAW_ARB && !sUseStreamDraw)
+	{
+		ret_usage = 0;
+	}
+	
+	if (ret_usage == GL_DYNAMIC_DRAW_ARB && sPreferStreamDraw)
+	{
+		ret_usage = GL_STREAM_DRAW_ARB;
+	}
+	
+	if (ret_usage == 0 && LLRender::sGLCoreProfile)
+	{ //MUST use VBOs for all rendering
+		ret_usage = GL_STREAM_DRAW_ARB;
+	}
+	
+	if (ret_usage && ret_usage != GL_STREAM_DRAW_ARB)
+	{ //only stream_draw and dynamic_draw are supported when using VBOs, dynamic draw is the default
+		if (sDisableVBOMapping)
+		{ //always use stream draw if VBO mapping is disabled
+			ret_usage = GL_STREAM_DRAW_ARB;
+		}
+		else
+		{
+			ret_usage = GL_DYNAMIC_DRAW_ARB;
+		}
+	}
+	
+	return ret_usage;
+}
+
 LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) :
 	LLRefCount(),
 
 	mNumVerts(0),
 	mNumIndices(0),
-	mUsage(usage),
+	mAlignedOffset(0),
+	mAlignedIndexOffset(0),
+	mSize(0),
+	mIndicesSize(0),
+	mTypeMask(typemask),
+	mUsage(LLVertexBuffer::determineUsage(usage)),
 	mGLBuffer(0),
+	mGLIndices(0),
 	mGLArray(0),
-	mGLIndices(0), 
 	mMappedData(NULL),
-	mMappedIndexData(NULL), 
-	mVertexLocked(FALSE),
-	mIndexLocked(FALSE),
-	mFinal(FALSE),
-	mEmpty(TRUE),
+	mMappedIndexData(NULL),
+	mMappedDataUsingVBOs(false),
+	mMappedIndexDataUsingVBOs(false),
+	mVertexLocked(false),
+	mIndexLocked(false),
+	mFinal(false),
+	mEmpty(true),
+	mMappable(false),
 	mFence(NULL)
 {
 	LLMemType mt2(LLMemType::MTYPE_VERTEX_CONSTRUCTOR);
-	mFence = NULL;
-	if (!sEnableVBOs)
-	{
-		mUsage = 0 ; 
-	}
 
-	if (mUsage == GL_STREAM_DRAW_ARB && !sUseStreamDraw)
-	{
-		mUsage = 0;
-	}
-	
-	if (mUsage == GL_DYNAMIC_DRAW_ARB && sPreferStreamDraw)
-	{
-		mUsage = GL_STREAM_DRAW_ARB;
-	}
-
-	if (mUsage == 0 && LLRender::sGLCoreProfile)
-	{ //MUST use VBOs for all rendering
-		mUsage = GL_STREAM_DRAW_ARB;
-	}
-
-	if (mUsage && mUsage != GL_STREAM_DRAW_ARB)
-	{ //only stream_draw and dynamic_draw are supported when using VBOs, dynamic draw is the default
-		if (sDisableVBOMapping)
-		{ //always use stream draw if VBO mapping is disabled
-			mUsage = GL_STREAM_DRAW_ARB;
-		}
-		else
-		{
-			mUsage = GL_DYNAMIC_DRAW_ARB;
-		}
-	}
-	
-
-	if (mUsage == GL_DYNAMIC_DRAW_ARB && !sDisableVBOMapping)
-	{
-		mMappable = TRUE;
-	}
-	else
-	{
-		mMappable = FALSE;
-	}
+	mMappable = (mUsage == GL_DYNAMIC_DRAW_ARB && !sDisableVBOMapping);
 
 	//zero out offsets
 	for (U32 i = 0; i < TYPE_MAX; i++)
 		mOffsets[i] = 0;
 	}
 
-	mTypeMask = typemask;
-	mSize = 0;
-	mIndicesSize = 0;
-	mAlignedOffset = 0;
-	mAlignedIndexOffset = 0;
-
 	sCount++;
 }
 
 	
 	mFence = NULL;
 
-	llassert_always(!mMappedData && !mMappedIndexData) ;
+	sVertexCount -= mNumVerts;
+	sIndexCount -= mNumIndices;
+
+	llassert_always(!mMappedData && !mMappedIndexData);
 };
 
 void LLVertexBuffer::placeFence() const
 
 void LLVertexBuffer::genBuffer(U32 size)
 {
-	mSize = nhpo2(size);
+	mSize = vbo_block_size(size);
 
 	if (mUsage == GL_STREAM_DRAW_ARB)
 	{
 
 void LLVertexBuffer::genIndices(U32 size)
 {
-	mIndicesSize = nhpo2(size);
+	mIndicesSize = vbo_block_size(size);
 
 	if (mUsage == GL_STREAM_DRAW_ARB)
 	{
 		return;
 	}
 
-	mEmpty = TRUE;
+	mEmpty = true;
 
-	if (useVBOs())
+	mMappedDataUsingVBOs = useVBOs();
+	
+	if (mMappedDataUsingVBOs)
 	{
 		genBuffer(size);
 	}
 		return;
 	}
 
-	mEmpty = TRUE;
+	mEmpty = true;
 
 	//pad by 16 bytes for aligned copies
 	size += 16;
 
-	if (useVBOs())
+	mMappedIndexDataUsingVBOs = useVBOs();
+
+	if (mMappedIndexDataUsingVBOs)
 	{
 		//pad by another 16 bytes for VBO pointer adjustment
 		size += 16;
 	LLMemType mt2(LLMemType::MTYPE_VERTEX_DESTROY_BUFFER);
 	if (mGLBuffer)
 	{
-		if (useVBOs())
+		if (mMappedDataUsingVBOs)
 		{
 			releaseBuffer();
 		}
 		else
 		{
-			FREE_MEM(sPrivatePoolp, (void*) mMappedData) ;
+			FREE_MEM(sPrivatePoolp, (void*) mMappedData);
 			mMappedData = NULL;
-			mEmpty = TRUE;
+			mEmpty = true;
 		}
 	}
 	
 	LLMemType mt2(LLMemType::MTYPE_VERTEX_DESTROY_INDICES);
 	if (mGLIndices)
 	{
-		if (useVBOs())
+		if (mMappedIndexDataUsingVBOs)
 		{
 			releaseIndices();
 		}
 		else
 		{
-			FREE_MEM(sPrivatePoolp, (void*) mMappedIndexData) ;
+			FREE_MEM(sPrivatePoolp, (void*) mMappedIndexData);
 			mMappedIndexData = NULL;
-			mEmpty = TRUE;
+			mEmpty = true;
 		}
 	}
 
 		createGLBuffer(needed_size);
 	}
 
+	sVertexCount -= mNumVerts;
 	mNumVerts = nverts;
+	sVertexCount += mNumVerts;
 }
 
 void LLVertexBuffer::updateNumIndices(S32 nindices)
 		createGLIndices(needed_size);
 	}
 
+	sIndexCount -= mNumIndices;
 	mNumIndices = nindices;
+	sIndexCount += mNumIndices;
 }
 
 void LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create)
 		1, //TYPE_WEIGHT,
 		4, //TYPE_WEIGHT4,
 		4, //TYPE_CLOTHWEIGHT,
-		1, //TYPE_TEXTURE_INDEX
+		4, //TYPE_TEXTURE_INDEX
 	};
 
 	U32 attrib_type[] =
 		GL_FLOAT, //TYPE_WEIGHT,
 		GL_FLOAT, //TYPE_WEIGHT4,
 		GL_FLOAT, //TYPE_CLOTHWEIGHT,
-		GL_FLOAT, //TYPE_TEXTURE_INDEX
+		GL_UNSIGNED_BYTE, //TYPE_TEXTURE_INDEX
+	};
+
+	bool attrib_integer[] = 
+	{
+		false, //TYPE_VERTEX,
+		false, //TYPE_NORMAL,
+		false, //TYPE_TEXCOORD0,
+		false, //TYPE_TEXCOORD1,
+		false, //TYPE_TEXCOORD2,
+		false, //TYPE_TEXCOORD3,
+		false, //TYPE_COLOR,
+		false, //TYPE_EMISSIVE,
+		false, //TYPE_BINORMAL,
+		false, //TYPE_WEIGHT,
+		false, //TYPE_WEIGHT4,
+		false, //TYPE_CLOTHWEIGHT,
+		true, //TYPE_TEXTURE_INDEX
 	};
 
 	U32 attrib_normalized[] =
 		if (mTypeMask & (1 << i))
 		{
 			glEnableVertexAttribArrayARB(i);
-			glVertexAttribPointerARB(i, attrib_size[i], attrib_type[i], attrib_normalized[i], sTypeSize[i], (void*) mOffsets[i]); 
+
+			if (attrib_integer[i])
+			{
+#if !LL_DARWIN
+				//glVertexattribIPointer requires GLSL 1.30 or later
+				if (gGLManager.mGLSLVersionMajor > 1 || gGLManager.mGLSLVersionMinor >= 30)
+				{
+					glVertexAttribIPointer(i, attrib_size[i], attrib_type[i], sTypeSize[i], (void*) mOffsets[i]); 
+				}
+#endif
+			}
+			else
+			{
+				glVertexAttribPointerARB(i, attrib_size[i], attrib_type[i], attrib_normalized[i], sTypeSize[i], (void*) mOffsets[i]); 
+			}
 		}
 		else
 		{
 	}
 }
 
-BOOL LLVertexBuffer::useVBOs() const
+bool LLVertexBuffer::useVBOs() const
 {
 	//it's generally ineffective to use VBO for things that are streaming on apple
-		
-	if (!mUsage)
-	{
-		return FALSE;
-	}
-
-	return TRUE;
+	return (mUsage != 0);
 }
 
 //----------------------------------------------------------------------------
 		if (!mVertexLocked)
 		{
 			LLMemType mt_v(LLMemType::MTYPE_VERTEX_MAP_BUFFER_VERTICES);
-			mVertexLocked = TRUE;
+			mVertexLocked = true;
 			sMappedCount++;
 			stop_glerror();	
 
 			{
 				log_glerror();
 
-			//check the availability of memory
-			LLMemory::logMemoryInfo(TRUE) ; 
+				//check the availability of memory
+				LLMemory::logMemoryInfo(true);
 			
 				if(mMappable)
 				{			
 					//--------------------
 					//print out more debug info before crash
-					llinfos << "vertex buffer size: (num verts : num indices) = " << getNumVerts() << " : " << getNumIndices() << llendl ;
-					GLint size ;
-					glGetBufferParameterivARB(GL_ARRAY_BUFFER_ARB, GL_BUFFER_SIZE_ARB, &size) ;
-					llinfos << "GL_ARRAY_BUFFER_ARB size is " << size << llendl ;
+					llinfos << "vertex buffer size: (num verts : num indices) = " << getNumVerts() << " : " << getNumIndices() << llendl;
+					GLint size;
+					glGetBufferParameterivARB(GL_ARRAY_BUFFER_ARB, GL_BUFFER_SIZE_ARB, &size);
+					llinfos << "GL_ARRAY_BUFFER_ARB size is " << size << llendl;
 					//--------------------