Skip to content
Snippets Groups Projects
llgl.cpp 69.6 KiB
Newer Older
  • Learn to ignore specific revisions
  • /** 
     * @file llgl.cpp
     * @brief LLGL implementation
     *
    
     * $LicenseInfo:firstyear=2001&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$
     */
    
    // This file sets some global GL parameters, and implements some 
    // useful functions for GL operations.
    
    #define GLH_EXT_SINGLE_FILE
    
    #include "linden_common.h"
    
    #include "boost/tokenizer.hpp"
    
    #include "llsys.h"
    
    #include "llgl.h"
    #include "llrender.h"
    
    #include "llerror.h"
    
    #include "llerrorcontrol.h"
    
    #include "llquaternion.h"
    #include "llmath.h"
    #include "m4math.h"
    #include "llstring.h"
    
    #include "llmemtype.h"
    #include "llstacktrace.h"
    
    
    #include "llglheaders.h"
    
    #ifdef _DEBUG
    //#define GL_STATE_VERIFY
    #endif
    
    
    BOOL gDebugGL = FALSE;
    BOOL gClothRipple = FALSE;
    
    BOOL gHeadlessClient = FALSE;
    
    BOOL gGLActive = FALSE;
    
    
    static const std::string HEADLESS_VENDOR_STRING("Linden Lab");
    static const std::string HEADLESS_RENDERER_STRING("Headless");
    static const std::string HEADLESS_VERSION_STRING("1.0");
    
    
    std::ofstream gFailLog;
    
    void ll_init_fail_log(std::string filename)
    {
    	gFailLog.open(filename.c_str());
    }
    
    
    void ll_fail(std::string msg)
    {
    	
    	if (gDebugSession)
    	{
    		std::vector<std::string> lines;
    
    		gFailLog << LLError::utcTime() << " " << msg << std::endl;
    
    		gFailLog << "Stack Trace:" << std::endl;
    
    		ll_get_stack_trace(lines);
    		
    		for(size_t i = 0; i < lines.size(); ++i)
    		{
    			gFailLog << lines[i] << std::endl;
    		}
    
    		gFailLog << "End of Stack Trace." << std::endl << std::endl;
    
    		gFailLog.flush();
    	}
    };
    
    void ll_close_fail_log()
    {
    	gFailLog.close();
    }
    
    
    LLMatrix4 gGLObliqueProjectionInverse;
    
    
    #define LL_GL_NAME_POOLING 0
    
    
    std::list<LLGLUpdate*> LLGLUpdate::sGLQ;
    
    #if (LL_WINDOWS || LL_LINUX || LL_SOLARIS)  && !LL_MESA_HEADLESS
    
    // ATI prototypes
    // vertex blending prototypes
    PFNGLWEIGHTPOINTERARBPROC			glWeightPointerARB = NULL;
    PFNGLVERTEXBLENDARBPROC				glVertexBlendARB = NULL;
    PFNGLWEIGHTFVARBPROC				glWeightfvARB = NULL;
    
    // Vertex buffer object prototypes
    PFNGLBINDBUFFERARBPROC				glBindBufferARB = NULL;
    PFNGLDELETEBUFFERSARBPROC			glDeleteBuffersARB = NULL;
    PFNGLGENBUFFERSARBPROC				glGenBuffersARB = NULL;
    PFNGLISBUFFERARBPROC				glIsBufferARB = NULL;
    PFNGLBUFFERDATAARBPROC				glBufferDataARB = NULL;
    PFNGLBUFFERSUBDATAARBPROC			glBufferSubDataARB = NULL;
    PFNGLGETBUFFERSUBDATAARBPROC		glGetBufferSubDataARB = NULL;
    PFNGLMAPBUFFERARBPROC				glMapBufferARB = NULL;
    PFNGLUNMAPBUFFERARBPROC				glUnmapBufferARB = NULL;
    PFNGLGETBUFFERPARAMETERIVARBPROC	glGetBufferParameterivARB = NULL;
    PFNGLGETBUFFERPOINTERVARBPROC		glGetBufferPointervARB = NULL;
    
    // vertex object prototypes
    PFNGLNEWOBJECTBUFFERATIPROC			glNewObjectBufferATI = NULL;
    PFNGLISOBJECTBUFFERATIPROC			glIsObjectBufferATI = NULL;
    PFNGLUPDATEOBJECTBUFFERATIPROC		glUpdateObjectBufferATI = NULL;
    PFNGLGETOBJECTBUFFERFVATIPROC		glGetObjectBufferfvATI = NULL;
    PFNGLGETOBJECTBUFFERIVATIPROC		glGetObjectBufferivATI = NULL;
    PFNGLFREEOBJECTBUFFERATIPROC		glFreeObjectBufferATI = NULL;
    PFNGLARRAYOBJECTATIPROC				glArrayObjectATI = NULL;
    PFNGLVERTEXATTRIBARRAYOBJECTATIPROC	glVertexAttribArrayObjectATI = NULL;
    PFNGLGETARRAYOBJECTFVATIPROC		glGetArrayObjectfvATI = NULL;
    PFNGLGETARRAYOBJECTIVATIPROC		glGetArrayObjectivATI = NULL;
    PFNGLVARIANTARRAYOBJECTATIPROC		glVariantObjectArrayATI = NULL;
    PFNGLGETVARIANTARRAYOBJECTFVATIPROC	glGetVariantArrayObjectfvATI = NULL;
    PFNGLGETVARIANTARRAYOBJECTIVATIPROC	glGetVariantArrayObjectivATI = NULL;
    
    // GL_ARB_occlusion_query
    PFNGLGENQUERIESARBPROC glGenQueriesARB = NULL;
    PFNGLDELETEQUERIESARBPROC glDeleteQueriesARB = NULL;
    PFNGLISQUERYARBPROC glIsQueryARB = NULL;
    PFNGLBEGINQUERYARBPROC glBeginQueryARB = NULL;
    PFNGLENDQUERYARBPROC glEndQueryARB = NULL;
    PFNGLGETQUERYIVARBPROC glGetQueryivARB = NULL;
    PFNGLGETQUERYOBJECTIVARBPROC glGetQueryObjectivARB = NULL;
    PFNGLGETQUERYOBJECTUIVARBPROC glGetQueryObjectuivARB = NULL;
    
    // GL_ARB_point_parameters
    PFNGLPOINTPARAMETERFARBPROC glPointParameterfARB = NULL;
    PFNGLPOINTPARAMETERFVARBPROC glPointParameterfvARB = NULL;
    
    
    PFNGLISRENDERBUFFERPROC glIsRenderbuffer = NULL;
    PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer = NULL;
    PFNGLDELETERENDERBUFFERSPROC glDeleteRenderbuffers = NULL;
    PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers = NULL;
    PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage = NULL;
    PFNGLGETRENDERBUFFERPARAMETERIVPROC glGetRenderbufferParameteriv = NULL;
    PFNGLISFRAMEBUFFERPROC glIsFramebuffer = NULL;
    PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer = NULL;
    PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers = NULL;
    PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers = NULL;
    PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus = NULL;
    PFNGLFRAMEBUFFERTEXTURE1DPROC glFramebufferTexture1D = NULL;
    PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D = NULL;
    PFNGLFRAMEBUFFERTEXTURE3DPROC glFramebufferTexture3D = NULL;
    PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer = NULL;
    PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glGetFramebufferAttachmentParameteriv = NULL;
    PFNGLGENERATEMIPMAPPROC glGenerateMipmap = NULL;
    PFNGLBLITFRAMEBUFFERPROC glBlitFramebuffer = NULL;
    PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glRenderbufferStorageMultisample = NULL;
    PFNGLFRAMEBUFFERTEXTURELAYERPROC glFramebufferTextureLayer = NULL;
    
    // GL_EXT_blend_func_separate
    PFNGLBLENDFUNCSEPARATEEXTPROC glBlendFuncSeparateEXT = NULL;
    
    
    // GL_ARB_draw_buffers
    PFNGLDRAWBUFFERSARBPROC glDrawBuffersARB = NULL;
    
    
    //shader object prototypes
    PFNGLDELETEOBJECTARBPROC glDeleteObjectARB = NULL;
    PFNGLGETHANDLEARBPROC glGetHandleARB = NULL;
    PFNGLDETACHOBJECTARBPROC glDetachObjectARB = NULL;
    PFNGLCREATESHADEROBJECTARBPROC glCreateShaderObjectARB = NULL;
    PFNGLSHADERSOURCEARBPROC glShaderSourceARB = NULL;
    PFNGLCOMPILESHADERARBPROC glCompileShaderARB = NULL;
    PFNGLCREATEPROGRAMOBJECTARBPROC glCreateProgramObjectARB = NULL;
    PFNGLATTACHOBJECTARBPROC glAttachObjectARB = NULL;
    PFNGLLINKPROGRAMARBPROC glLinkProgramARB = NULL;
    PFNGLUSEPROGRAMOBJECTARBPROC glUseProgramObjectARB = NULL;
    PFNGLVALIDATEPROGRAMARBPROC glValidateProgramARB = NULL;
    PFNGLUNIFORM1FARBPROC glUniform1fARB = NULL;
    PFNGLUNIFORM2FARBPROC glUniform2fARB = NULL;
    PFNGLUNIFORM3FARBPROC glUniform3fARB = NULL;
    PFNGLUNIFORM4FARBPROC glUniform4fARB = NULL;
    PFNGLUNIFORM1IARBPROC glUniform1iARB = NULL;
    PFNGLUNIFORM2IARBPROC glUniform2iARB = NULL;
    PFNGLUNIFORM3IARBPROC glUniform3iARB = NULL;
    PFNGLUNIFORM4IARBPROC glUniform4iARB = NULL;
    PFNGLUNIFORM1FVARBPROC glUniform1fvARB = NULL;
    PFNGLUNIFORM2FVARBPROC glUniform2fvARB = NULL;
    PFNGLUNIFORM3FVARBPROC glUniform3fvARB = NULL;
    PFNGLUNIFORM4FVARBPROC glUniform4fvARB = NULL;
    PFNGLUNIFORM1IVARBPROC glUniform1ivARB = NULL;
    PFNGLUNIFORM2IVARBPROC glUniform2ivARB = NULL;
    PFNGLUNIFORM3IVARBPROC glUniform3ivARB = NULL;
    PFNGLUNIFORM4IVARBPROC glUniform4ivARB = NULL;
    PFNGLUNIFORMMATRIX2FVARBPROC glUniformMatrix2fvARB = NULL;
    PFNGLUNIFORMMATRIX3FVARBPROC glUniformMatrix3fvARB = NULL;
    PFNGLUNIFORMMATRIX4FVARBPROC glUniformMatrix4fvARB = NULL;
    PFNGLGETOBJECTPARAMETERFVARBPROC glGetObjectParameterfvARB = NULL;
    PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameterivARB = NULL;
    PFNGLGETINFOLOGARBPROC glGetInfoLogARB = NULL;
    PFNGLGETATTACHEDOBJECTSARBPROC glGetAttachedObjectsARB = NULL;
    PFNGLGETUNIFORMLOCATIONARBPROC glGetUniformLocationARB = NULL;
    PFNGLGETACTIVEUNIFORMARBPROC glGetActiveUniformARB = NULL;
    PFNGLGETUNIFORMFVARBPROC glGetUniformfvARB = NULL;
    PFNGLGETUNIFORMIVARBPROC glGetUniformivARB = NULL;
    PFNGLGETSHADERSOURCEARBPROC glGetShaderSourceARB = NULL;
    
    // vertex shader prototypes
    
    #if LL_LINUX || LL_SOLARIS
    
    PFNGLVERTEXATTRIB1DARBPROC glVertexAttrib1dARB = NULL;
    PFNGLVERTEXATTRIB1DVARBPROC glVertexAttrib1dvARB = NULL;
    PFNGLVERTEXATTRIB1FARBPROC glVertexAttrib1fARB = NULL;
    PFNGLVERTEXATTRIB1FVARBPROC glVertexAttrib1fvARB = NULL;
    PFNGLVERTEXATTRIB1SARBPROC glVertexAttrib1sARB = NULL;
    PFNGLVERTEXATTRIB1SVARBPROC glVertexAttrib1svARB = NULL;
    PFNGLVERTEXATTRIB2DARBPROC glVertexAttrib2dARB = NULL;
    PFNGLVERTEXATTRIB2DVARBPROC glVertexAttrib2dvARB = NULL;
    PFNGLVERTEXATTRIB2FARBPROC glVertexAttrib2fARB = NULL;
    PFNGLVERTEXATTRIB2FVARBPROC glVertexAttrib2fvARB = NULL;
    PFNGLVERTEXATTRIB2SARBPROC glVertexAttrib2sARB = NULL;
    PFNGLVERTEXATTRIB2SVARBPROC glVertexAttrib2svARB = NULL;
    PFNGLVERTEXATTRIB3DARBPROC glVertexAttrib3dARB = NULL;
    PFNGLVERTEXATTRIB3DVARBPROC glVertexAttrib3dvARB = NULL;
    PFNGLVERTEXATTRIB3FARBPROC glVertexAttrib3fARB = NULL;
    PFNGLVERTEXATTRIB3FVARBPROC glVertexAttrib3fvARB = NULL;
    PFNGLVERTEXATTRIB3SARBPROC glVertexAttrib3sARB = NULL;
    PFNGLVERTEXATTRIB3SVARBPROC glVertexAttrib3svARB = NULL;
    
    #endif // LL_LINUX || LL_SOLARIS
    
    PFNGLVERTEXATTRIB4NBVARBPROC glVertexAttrib4nbvARB = NULL;
    PFNGLVERTEXATTRIB4NIVARBPROC glVertexAttrib4nivARB = NULL;
    PFNGLVERTEXATTRIB4NSVARBPROC glVertexAttrib4nsvARB = NULL;
    PFNGLVERTEXATTRIB4NUBARBPROC glVertexAttrib4nubARB = NULL;
    PFNGLVERTEXATTRIB4NUBVARBPROC glVertexAttrib4nubvARB = NULL;
    PFNGLVERTEXATTRIB4NUIVARBPROC glVertexAttrib4nuivARB = NULL;
    PFNGLVERTEXATTRIB4NUSVARBPROC glVertexAttrib4nusvARB = NULL;
    
    #if LL_LINUX  || LL_SOLARIS
    
    PFNGLVERTEXATTRIB4BVARBPROC glVertexAttrib4bvARB = NULL;
    PFNGLVERTEXATTRIB4DARBPROC glVertexAttrib4dARB = NULL;
    PFNGLVERTEXATTRIB4DVARBPROC glVertexAttrib4dvARB = NULL;
    PFNGLVERTEXATTRIB4FARBPROC glVertexAttrib4fARB = NULL;
    PFNGLVERTEXATTRIB4FVARBPROC glVertexAttrib4fvARB = NULL;
    PFNGLVERTEXATTRIB4IVARBPROC glVertexAttrib4ivARB = NULL;
    PFNGLVERTEXATTRIB4SARBPROC glVertexAttrib4sARB = NULL;
    PFNGLVERTEXATTRIB4SVARBPROC glVertexAttrib4svARB = NULL;
    PFNGLVERTEXATTRIB4UBVARBPROC glVertexAttrib4ubvARB = NULL;
    PFNGLVERTEXATTRIB4UIVARBPROC glVertexAttrib4uivARB = NULL;
    PFNGLVERTEXATTRIB4USVARBPROC glVertexAttrib4usvARB = NULL;
    PFNGLVERTEXATTRIBPOINTERARBPROC glVertexAttribPointerARB = NULL;
    PFNGLENABLEVERTEXATTRIBARRAYARBPROC glEnableVertexAttribArrayARB = NULL;
    PFNGLDISABLEVERTEXATTRIBARRAYARBPROC glDisableVertexAttribArrayARB = NULL;
    PFNGLPROGRAMSTRINGARBPROC glProgramStringARB = NULL;
    PFNGLBINDPROGRAMARBPROC glBindProgramARB = NULL;
    PFNGLDELETEPROGRAMSARBPROC glDeleteProgramsARB = NULL;
    PFNGLGENPROGRAMSARBPROC glGenProgramsARB = NULL;
    PFNGLPROGRAMENVPARAMETER4DARBPROC glProgramEnvParameter4dARB = NULL;
    PFNGLPROGRAMENVPARAMETER4DVARBPROC glProgramEnvParameter4dvARB = NULL;
    PFNGLPROGRAMENVPARAMETER4FARBPROC glProgramEnvParameter4fARB = NULL;
    PFNGLPROGRAMENVPARAMETER4FVARBPROC glProgramEnvParameter4fvARB = NULL;
    PFNGLPROGRAMLOCALPARAMETER4DARBPROC glProgramLocalParameter4dARB = NULL;
    PFNGLPROGRAMLOCALPARAMETER4DVARBPROC glProgramLocalParameter4dvARB = NULL;
    PFNGLPROGRAMLOCALPARAMETER4FARBPROC glProgramLocalParameter4fARB = NULL;
    PFNGLPROGRAMLOCALPARAMETER4FVARBPROC glProgramLocalParameter4fvARB = NULL;
    PFNGLGETPROGRAMENVPARAMETERDVARBPROC glGetProgramEnvParameterdvARB = NULL;
    PFNGLGETPROGRAMENVPARAMETERFVARBPROC glGetProgramEnvParameterfvARB = NULL;
    PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC glGetProgramLocalParameterdvARB = NULL;
    PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC glGetProgramLocalParameterfvARB = NULL;
    PFNGLGETPROGRAMIVARBPROC glGetProgramivARB = NULL;
    PFNGLGETPROGRAMSTRINGARBPROC glGetProgramStringARB = NULL;
    PFNGLGETVERTEXATTRIBDVARBPROC glGetVertexAttribdvARB = NULL;
    PFNGLGETVERTEXATTRIBFVARBPROC glGetVertexAttribfvARB = NULL;
    PFNGLGETVERTEXATTRIBIVARBPROC glGetVertexAttribivARB = NULL;
    PFNGLGETVERTEXATTRIBPOINTERVARBPROC glGetVertexAttribPointervARB = NULL;
    PFNGLISPROGRAMARBPROC glIsProgramARB = NULL;
    
    #endif // LL_LINUX || LL_SOLARIS
    
    PFNGLBINDATTRIBLOCATIONARBPROC glBindAttribLocationARB = NULL;
    PFNGLGETACTIVEATTRIBARBPROC glGetActiveAttribARB = NULL;
    PFNGLGETATTRIBLOCATIONARBPROC glGetAttribLocationARB = NULL;
    
    #if LL_WINDOWS
    PFNWGLSWAPINTERVALEXTPROC			wglSwapIntervalEXT = NULL;
    #endif
    
    
    #if LL_LINUX_NV_GL_HEADERS
    // linux nvidia headers.  these define these differently to mesa's.  ugh.
    PFNGLACTIVETEXTUREARBPROC glActiveTextureARB = NULL;
    PFNGLCLIENTACTIVETEXTUREARBPROC glClientActiveTextureARB = NULL;
    PFNGLDRAWRANGEELEMENTSPROC glDrawRangeElements = NULL;
    #endif // LL_LINUX_NV_GL_HEADERS
    
    #endif
    
    LLGLManager gGLManager;
    
    LLGLManager::LLGLManager() :
    	mInited(FALSE),
    	mIsDisabled(FALSE),
    
    	mHasMultitexture(FALSE),
    
    	mNumTextureUnits(1),
    	mHasMipMapGeneration(FALSE),
    	mHasCompressedTextures(FALSE),
    	mHasFramebufferObject(FALSE),
    
    	mHasBlendFuncSeparate(FALSE),
    
    
    	mHasVertexBufferObject(FALSE),
    	mHasPBuffer(FALSE),
    	mHasShaderObjects(FALSE),
    	mHasVertexShader(FALSE),
    	mHasFragmentShader(FALSE),
    	mHasOcclusionQuery(FALSE),
    
    	mHasPointParameters(FALSE),
    
    Tofu Linden's avatar
    Tofu Linden committed
    	mHasDrawBuffers(FALSE),
    	mHasTextureRectangle(FALSE),
    
    
    	mHasAnisotropic(FALSE),
    	mHasARBEnvCombine(FALSE),
    	mHasCubeMap(FALSE),
    
    	mIsATI(FALSE),
    	mIsNVIDIA(FALSE),
    	mIsIntel(FALSE),
    	mIsGF2or4MX(FALSE),
    	mIsGF3(FALSE),
    	mIsGFFX(FALSE),
    	mATIOffsetVerticalLines(FALSE),
    
    
    	mHasRequirements(TRUE),
    
    	mHasSeparateSpecularColor(FALSE),
    
    
    	mDebugGPU(FALSE),
    
    
    	mDriverVersionMajor(1),
    	mDriverVersionMinor(0),
    	mDriverVersionRelease(0),
    	mGLVersion(1.0f),
    		
    	mVRAM(0),
    	mGLMaxVertexRange(0),
    	mGLMaxIndexRange(0)
    {
    }
    
    //---------------------------------------------------------------------
    // Global initialization for GL
    //---------------------------------------------------------------------
    void LLGLManager::initWGL()
    {
    	mHasPBuffer = FALSE;
    #if LL_WINDOWS && !LL_MESA_HEADLESS
    	if (!glh_init_extensions("WGL_ARB_pixel_format"))
    	{
    		LL_WARNS("RenderInit") << "No ARB pixel format extensions" << LL_ENDL;
    	}
    
    	if (ExtensionExists("WGL_EXT_swap_control", gGLHExts.mSysExts))
    	{
            GLH_EXT_NAME(wglSwapIntervalEXT) = (PFNWGLSWAPINTERVALEXTPROC)GLH_EXT_GET_PROC_ADDRESS("wglSwapIntervalEXT");
    	}
    
    	if( !glh_init_extensions("WGL_ARB_pbuffer") )
    	{
    		LL_WARNS("RenderInit") << "No ARB WGL PBuffer extensions" << LL_ENDL;
    	}
    
    	if( !glh_init_extensions("WGL_ARB_render_texture") )
    	{
    		LL_WARNS("RenderInit") << "No ARB WGL render texture extensions" << LL_ENDL;
    	}
    
    	mHasPBuffer = ExtensionExists("WGL_ARB_pbuffer", gGLHExts.mSysExts) &&
    					ExtensionExists("WGL_ARB_render_texture", gGLHExts.mSysExts) &&
    					ExtensionExists("WGL_ARB_pixel_format", gGLHExts.mSysExts);
    #endif
    }
    
    // return false if unable (or unwilling due to old drivers) to init GL
    bool LLGLManager::initGL()
    {
    	if (mInited)
    	{
    		LL_ERRS("RenderInit") << "Calling init on LLGLManager after already initialized!" << LL_ENDL;
    	}
    
    	GLint alpha_bits;
    	glGetIntegerv( GL_ALPHA_BITS, &alpha_bits );
    	if( 8 != alpha_bits )
    	{
    		LL_WARNS("RenderInit") << "Frame buffer has less than 8 bits of alpha.  Avatar texture compositing will fail." << LL_ENDL;
    	}
    
    	// Extract video card strings and convert to upper case to
    	// work around driver-to-driver variation in capitalization.
    	mGLVendor = std::string((const char *)glGetString(GL_VENDOR));
    	LLStringUtil::toUpper(mGLVendor);
    
    	mGLRenderer = std::string((const char *)glGetString(GL_RENDERER));
    	LLStringUtil::toUpper(mGLRenderer);
    
    	parse_gl_version( &mDriverVersionMajor, 
    		&mDriverVersionMinor, 
    		&mDriverVersionRelease, 
    		&mDriverVersionVendorString );
    
    	mGLVersion = mDriverVersionMajor + mDriverVersionMinor * .1f;
    	
    	// Trailing space necessary to keep "nVidia Corpor_ati_on" cards
    	// from being recognized as ATI.
    	if (mGLVendor.substr(0,4) == "ATI ")
    	{
    		mGLVendorShort = "ATI";
    		BOOL mobile = FALSE;
    		if (mGLRenderer.find("MOBILITY") != std::string::npos)
    		{
    			mobile = TRUE;
    		}
    		mIsATI = TRUE;
    
    #if LL_WINDOWS && !LL_MESA_HEADLESS
    		if (mDriverVersionRelease < 3842)
    		{
    			mATIOffsetVerticalLines = TRUE;
    		}
    #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.
    		{
    			mATIOldDriver = TRUE;
    		}
    #endif // (LL_WINDOWS || LL_LINUX) && !LL_MESA_HEADLESS
    
    	}
    	else if (mGLVendor.find("NVIDIA ") != std::string::npos)
    	{
    		mGLVendorShort = "NVIDIA";
    		mIsNVIDIA = TRUE;
    		if (   mGLRenderer.find("GEFORCE4 MX") != std::string::npos
    			|| mGLRenderer.find("GEFORCE2") != std::string::npos
    			|| mGLRenderer.find("GEFORCE 2") != std::string::npos
    			|| mGLRenderer.find("GEFORCE4 460 GO") != std::string::npos
    			|| mGLRenderer.find("GEFORCE4 440 GO") != std::string::npos
    			|| mGLRenderer.find("GEFORCE4 420 GO") != std::string::npos)
    		{
    			mIsGF2or4MX = TRUE;
    		}
    		else if (mGLRenderer.find("GEFORCE FX") != std::string::npos
    				 || mGLRenderer.find("QUADRO FX") != std::string::npos
    				 || mGLRenderer.find("NV34") != std::string::npos)
    		{
    			mIsGFFX = TRUE;
    		}
    		else if(mGLRenderer.find("GEFORCE3") != std::string::npos)
    		{
    			mIsGF3 = TRUE;
    		}
    
    	}
    	else if (mGLVendor.find("INTEL") != std::string::npos
    #if LL_LINUX
    		 // The Mesa-based drivers put this in the Renderer string,
    		 // not the Vendor string.
    		 || mGLRenderer.find("INTEL") != std::string::npos
    #endif //LL_LINUX
    		 )
    	{
    		mGLVendorShort = "INTEL";
    		mIsIntel = TRUE;
    	}
    	else
    	{
    		mGLVendorShort = "MISC";
    	}
    	
    	// This is called here because it depends on the setting of mIsGF2or4MX, and sets up mHasMultitexture.
    	initExtensions();
    
    
    	if (mHasATIMemInfo)
    	{ //ask the gl how much vram is free at startup and attempt to use no more than half of that
    		S32 meminfo[4];
    		glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, meminfo);
    
    		mVRAM = meminfo[0]/1024;
    	}
    
    	else if (mHasNVXMemInfo)
    	{
    		S32 dedicated_memory;
    		glGetIntegerv(GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX, &dedicated_memory);
    		mVRAM = dedicated_memory/1024;
    	}
    
    	if (mHasMultitexture)
    	{
    		GLint num_tex_units;		
    		glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &num_tex_units);
    		mNumTextureUnits = llmin(num_tex_units, (GLint)MAX_GL_TEXTURE_UNITS);
    		if (mIsIntel)
    		{
    			mNumTextureUnits = llmin(mNumTextureUnits, 2);
    		}
    	}
    	else
    	{
    		mHasRequirements = FALSE;
    
    		// We don't support cards that don't support the GL_ARB_multitexture extension
    		LL_WARNS("RenderInit") << "GL Drivers do not support GL_ARB_multitexture" << LL_ENDL;
    		return false;
    	}
    	
    
    	setToDebugGPU();
    
    
    	initGLStates();
    	return true;
    }
    
    
    void LLGLManager::setToDebugGPU()
    {
    	//"MOBILE INTEL(R) 965 EXPRESS CHIP", 
    	if (mGLRenderer.find("INTEL") != std::string::npos && mGLRenderer.find("965") != std::string::npos)
    	{
    		mDebugGPU = TRUE ;
    	}
    
    	return ;
    }
    
    
    void LLGLManager::getGLInfo(LLSD& info)
    {
    
    	if (gHeadlessClient)
    	{
    		info["GLInfo"]["GLVendor"] = HEADLESS_VENDOR_STRING;
    		info["GLInfo"]["GLRenderer"] = HEADLESS_RENDERER_STRING;
    		info["GLInfo"]["GLVersion"] = HEADLESS_VERSION_STRING;
    		return;
    	}
    	else
    	{
    		info["GLInfo"]["GLVendor"] = std::string((const char *)glGetString(GL_VENDOR));
    		info["GLInfo"]["GLRenderer"] = std::string((const char *)glGetString(GL_RENDERER));
    		info["GLInfo"]["GLVersion"] = std::string((const char *)glGetString(GL_VERSION));
    	}
    
    
    #if !LL_MESA_HEADLESS
    	std::string all_exts = ll_safe_string((const char *)gGLHExts.mSysExts);
    	boost::char_separator<char> sep(" ");
    	boost::tokenizer<boost::char_separator<char> > tok(all_exts, sep);
    	for(boost::tokenizer<boost::char_separator<char> >::iterator i = tok.begin(); i != tok.end(); ++i)
    	{
    		info["GLInfo"]["GLExtensions"].append(*i);
    	}
    #endif
    }
    
    std::string LLGLManager::getGLInfoString()
    {
    	std::string info_str;
    
    
    	if (gHeadlessClient)
    	{
    		info_str += std::string("GL_VENDOR      ") + HEADLESS_VENDOR_STRING + std::string("\n");
    		info_str += std::string("GL_RENDERER    ") + HEADLESS_RENDERER_STRING + std::string("\n");
    		info_str += std::string("GL_VERSION     ") + HEADLESS_VERSION_STRING + std::string("\n");
    	}
    	else
    	{
    		info_str += std::string("GL_VENDOR      ") + ll_safe_string((const char *)glGetString(GL_VENDOR)) + std::string("\n");
    		info_str += std::string("GL_RENDERER    ") + ll_safe_string((const char *)glGetString(GL_RENDERER)) + std::string("\n");
    		info_str += std::string("GL_VERSION     ") + ll_safe_string((const char *)glGetString(GL_VERSION)) + std::string("\n");
    	}
    
    	std::string all_exts= ll_safe_string(((const char *)gGLHExts.mSysExts));
    
    	LLStringUtil::replaceChar(all_exts, ' ', '\n');
    	info_str += std::string("GL_EXTENSIONS:\n") + all_exts + std::string("\n");
    #endif
    	
    	return info_str;
    }
    
    void LLGLManager::printGLInfoString()
    {
    
    	if (gHeadlessClient)
    	{
    		LL_INFOS("RenderInit") << "GL_VENDOR:     " << HEADLESS_VENDOR_STRING << LL_ENDL;
    		LL_INFOS("RenderInit") << "GL_RENDERER:   " << HEADLESS_RENDERER_STRING << LL_ENDL;
    		LL_INFOS("RenderInit") << "GL_VERSION:    " << HEADLESS_VERSION_STRING << LL_ENDL;
    	}
    	else
    	{
    		LL_INFOS("RenderInit") << "GL_VENDOR:     " << ((const char *)glGetString(GL_VENDOR)) << LL_ENDL;
    		LL_INFOS("RenderInit") << "GL_RENDERER:   " << ((const char *)glGetString(GL_RENDERER)) << LL_ENDL;
    		LL_INFOS("RenderInit") << "GL_VERSION:    " << ((const char *)glGetString(GL_VERSION)) << LL_ENDL;
    	}
    
    
    #if !LL_MESA_HEADLESS
    
    	std::string all_exts= ll_safe_string(((const char *)gGLHExts.mSysExts));
    
    	LLStringUtil::replaceChar(all_exts, ' ', '\n');
    	LL_DEBUGS("RenderInit") << "GL_EXTENSIONS:\n" << all_exts << LL_ENDL;
    #endif
    }
    
    std::string LLGLManager::getRawGLString()
    {
    	std::string gl_string;
    
    	if (gHeadlessClient)
    	{
    		gl_string = HEADLESS_VENDOR_STRING + " " + HEADLESS_RENDERER_STRING;
    	}
    	else
    	{
    		gl_string = ll_safe_string((char*)glGetString(GL_VENDOR)) + " " + ll_safe_string((char*)glGetString(GL_RENDERER));
    	}
    
    	return gl_string;
    }
    
    void LLGLManager::shutdownGL()
    {
    	if (mInited)
    	{
    		glFinish();
    		stop_glerror();
    		mInited = FALSE;
    	}
    }
    
    // these are used to turn software blending on. They appear in the Debug/Avatar menu
    // presence of vertex skinning/blending or vertex programs will set these to FALSE by default.
    
    void LLGLManager::initExtensions()
    {
    #if LL_MESA_HEADLESS
    
    	mHasMultitexture = TRUE;
    # else
    	mHasMultitexture = FALSE;
    
    # endif // GL_ARB_multitexture
    
    	mHasARBEnvCombine = TRUE;	
    # else
    	mHasARBEnvCombine = FALSE;
    
    # endif // GL_ARB_texture_env_combine
    
    	mHasCompressedTextures = TRUE;
    # else
    	mHasCompressedTextures = FALSE;
    
    # endif // GL_ARB_texture_compression
    
    	mHasVertexBufferObject = TRUE;
    # else
    	mHasVertexBufferObject = FALSE;
    
    # endif // GL_ARB_vertex_buffer_object
    
    	mHasFramebufferObject = TRUE;
    # else
    	mHasFramebufferObject = FALSE;
    
    # endif // GL_EXT_framebuffer_object
    
    	mHasDrawBuffers = TRUE;
    #else
    	mHasDrawBuffers = FALSE;
    
    # endif // GL_ARB_draw_buffers
    
    # if defined(GL_NV_depth_clamp) || defined(GL_ARB_depth_clamp)
    	mHasDepthClamp = TRUE;
    #else
    	mHasDepthClamp = FALSE;
    
    #endif // defined(GL_NV_depth_clamp) || defined(GL_ARB_depth_clamp)
    
    # if GL_EXT_blend_func_separate
    	mHasBlendFuncSeparate = TRUE;
    #else
    	mHasBlendFuncSeparate = FALSE;
    
    # endif // GL_EXT_blend_func_separate
    
    	mHasMipMapGeneration = FALSE;
    	mHasSeparateSpecularColor = FALSE;
    	mHasAnisotropic = FALSE;
    	mHasCubeMap = FALSE;
    	mHasOcclusionQuery = FALSE;
    	mHasPointParameters = FALSE;
    	mHasShaderObjects = FALSE;
    	mHasVertexShader = FALSE;
    	mHasFragmentShader = FALSE;
    
    	mHasTextureRectangle = FALSE;
    
    #else // LL_MESA_HEADLESS
    	mHasMultitexture = glh_init_extensions("GL_ARB_multitexture");
    
    	mHasATIMemInfo = ExtensionExists("GL_ATI_meminfo", gGLHExts.mSysExts);
    
    	mHasNVXMemInfo = ExtensionExists("GL_NVX_gpu_memory_info", gGLHExts.mSysExts);
    
    	mHasMipMapGeneration = glh_init_extensions("GL_SGIS_generate_mipmap");
    	mHasSeparateSpecularColor = glh_init_extensions("GL_EXT_separate_specular_color");
    	mHasAnisotropic = glh_init_extensions("GL_EXT_texture_filter_anisotropic");
    	glh_init_extensions("GL_ARB_texture_cube_map");
    	mHasCubeMap = ExtensionExists("GL_ARB_texture_cube_map", gGLHExts.mSysExts);
    	mHasARBEnvCombine = ExtensionExists("GL_ARB_texture_env_combine", gGLHExts.mSysExts);
    	mHasCompressedTextures = glh_init_extensions("GL_ARB_texture_compression");
    	mHasOcclusionQuery = ExtensionExists("GL_ARB_occlusion_query", gGLHExts.mSysExts);
    
    	mHasOcclusionQuery2 = ExtensionExists("GL_ARB_occlusion_query2", gGLHExts.mSysExts);
    
    	mHasVertexBufferObject = ExtensionExists("GL_ARB_vertex_buffer_object", gGLHExts.mSysExts);
    
    	mHasDepthClamp = ExtensionExists("GL_ARB_depth_clamp", gGLHExts.mSysExts) || ExtensionExists("GL_NV_depth_clamp", gGLHExts.mSysExts);
    
    	// mask out FBO support when packed_depth_stencil isn't there 'cause we need it for LLRenderTarget -Brad
    
    	mHasFramebufferObject = ExtensionExists("GL_ARB_framebuffer_object", gGLHExts.mSysExts);
    
    #else
    	mHasFramebufferObject = ExtensionExists("GL_EXT_framebuffer_object", gGLHExts.mSysExts) &&
    							ExtensionExists("GL_EXT_framebuffer_blit", gGLHExts.mSysExts) &&
    							ExtensionExists("GL_EXT_framebuffer_multisample", gGLHExts.mSysExts) &&
    							ExtensionExists("GL_EXT_packed_depth_stencil", gGLHExts.mSysExts);
    #endif
    	
    
    	mHasDrawBuffers = ExtensionExists("GL_ARB_draw_buffers", gGLHExts.mSysExts);
    
    	mHasBlendFuncSeparate = ExtensionExists("GL_EXT_blend_func_separate", gGLHExts.mSysExts);
    
    	mHasTextureRectangle = ExtensionExists("GL_ARB_texture_rectangle", gGLHExts.mSysExts);
    
    #if !LL_DARWIN
    	mHasPointParameters = !mIsATI && ExtensionExists("GL_ARB_point_parameters", gGLHExts.mSysExts);
    #endif
    	mHasShaderObjects = ExtensionExists("GL_ARB_shader_objects", gGLHExts.mSysExts) && ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts);
    	mHasVertexShader = ExtensionExists("GL_ARB_vertex_program", gGLHExts.mSysExts) && ExtensionExists("GL_ARB_vertex_shader", gGLHExts.mSysExts)
    						&& ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts);
    	mHasFragmentShader = ExtensionExists("GL_ARB_fragment_shader", gGLHExts.mSysExts) && ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts);
    #endif
    
    
    #if LL_LINUX || LL_SOLARIS
    	llinfos << "initExtensions() checking shell variables to adjust features..." << llendl;
    
    	// Our extension support for the Linux Client is very young with some
    	// potential driver gotchas, so offer a semi-secret way to turn it off.
    
    Tofu Linden's avatar
    Tofu Linden committed
    	if (getenv("LL_GL_NOEXT"))
    
    	{
    		//mHasMultitexture = FALSE; // NEEDED!
    
    		mHasARBEnvCombine = FALSE;
    		mHasCompressedTextures = FALSE;
    		mHasVertexBufferObject = FALSE;
    		mHasFramebufferObject = FALSE;
    
    		mHasBlendFuncSeparate = FALSE;
    
    		mHasMipMapGeneration = FALSE;
    		mHasSeparateSpecularColor = FALSE;
    		mHasAnisotropic = FALSE;
    		mHasCubeMap = FALSE;
    		mHasOcclusionQuery = FALSE;
    		mHasPointParameters = FALSE;
    		mHasShaderObjects = FALSE;
    		mHasVertexShader = FALSE;
    		mHasFragmentShader = FALSE;
    		LL_WARNS("RenderInit") << "GL extension support DISABLED via LL_GL_NOEXT" << LL_ENDL;
    	}
    	else if (getenv("LL_GL_BASICEXT"))	/* Flawfinder: ignore */
    	{
    		// This switch attempts to turn off all support for exotic
    		// extensions which I believe correspond to fatal driver
    		// bug reports.  This should be the default until we get a
    		// proper blacklist/whitelist on Linux.
    		mHasMipMapGeneration = FALSE;
    		mHasAnisotropic = FALSE;
    		//mHasCubeMap = FALSE; // apparently fatal on Intel 915 & similar
    		//mHasOcclusionQuery = FALSE; // source of many ATI system hangs
    		mHasShaderObjects = FALSE;
    		mHasVertexShader = FALSE;
    		mHasFragmentShader = FALSE;
    
    		mHasBlendFuncSeparate = FALSE;
    
    		LL_WARNS("RenderInit") << "GL extension support forced to SIMPLE level via LL_GL_BASICEXT" << LL_ENDL;
    	}
    	if (getenv("LL_GL_BLACKLIST"))	/* Flawfinder: ignore */
    	{
    		// This lets advanced troubleshooters disable specific
    		// GL extensions to isolate problems with their hardware.
    		// SL-28126
    		const char *const blacklist = getenv("LL_GL_BLACKLIST");	/* Flawfinder: ignore */
    		LL_WARNS("RenderInit") << "GL extension support partially disabled via LL_GL_BLACKLIST: " << blacklist << LL_ENDL;
    		if (strchr(blacklist,'a')) mHasARBEnvCombine = FALSE;
    		if (strchr(blacklist,'b')) mHasCompressedTextures = FALSE;
    		if (strchr(blacklist,'c')) mHasVertexBufferObject = FALSE;
    		if (strchr(blacklist,'d')) mHasMipMapGeneration = FALSE;//S
    // 		if (strchr(blacklist,'f')) mHasNVVertexArrayRange = FALSE;//S
    // 		if (strchr(blacklist,'g')) mHasNVFence = FALSE;//S
    		if (strchr(blacklist,'h')) mHasSeparateSpecularColor = FALSE;
    		if (strchr(blacklist,'i')) mHasAnisotropic = FALSE;//S
    		if (strchr(blacklist,'j')) mHasCubeMap = FALSE;//S
    // 		if (strchr(blacklist,'k')) mHasATIVAO = FALSE;//S
    		if (strchr(blacklist,'l')) mHasOcclusionQuery = FALSE;
    		if (strchr(blacklist,'m')) mHasShaderObjects = FALSE;//S
    		if (strchr(blacklist,'n')) mHasVertexShader = FALSE;//S
    		if (strchr(blacklist,'o')) mHasFragmentShader = FALSE;//S
    		if (strchr(blacklist,'p')) mHasPointParameters = FALSE;//S
    		if (strchr(blacklist,'q')) mHasFramebufferObject = FALSE;//S
    
    		if (strchr(blacklist,'r')) mHasDrawBuffers = FALSE;//S
    
    		if (strchr(blacklist,'s')) mHasTextureRectangle = FALSE;
    		if (strchr(blacklist,'t')) mHasBlendFuncSeparate = FALSE;//S
    		if (strchr(blacklist,'u')) mHasDepthClamp = FALSE;
    
    #endif // LL_LINUX || LL_SOLARIS
    
    	
    	if (!mHasMultitexture)
    	{
    		LL_INFOS("RenderInit") << "Couldn't initialize multitexturing" << LL_ENDL;
    	}
    	if (!mHasMipMapGeneration)
    	{
    		LL_INFOS("RenderInit") << "Couldn't initialize mipmap generation" << LL_ENDL;
    	}
    	if (!mHasARBEnvCombine)
    	{
    		LL_INFOS("RenderInit") << "Couldn't initialize GL_ARB_texture_env_combine" << LL_ENDL;
    	}
    	if (!mHasSeparateSpecularColor)
    	{
    		LL_INFOS("RenderInit") << "Couldn't initialize separate specular color" << LL_ENDL;
    	}
    	if (!mHasAnisotropic)
    	{
    		LL_INFOS("RenderInit") << "Couldn't initialize anisotropic filtering" << LL_ENDL;
    	}
    	if (!mHasCompressedTextures)
    	{
    		LL_INFOS("RenderInit") << "Couldn't initialize GL_ARB_texture_compression" << LL_ENDL;
    	}
    	if (!mHasOcclusionQuery)
    	{
    		LL_INFOS("RenderInit") << "Couldn't initialize GL_ARB_occlusion_query" << LL_ENDL;
    	}
    
    	if (!mHasOcclusionQuery2)
    	{
    		LL_INFOS("RenderInit") << "Couldn't initialize GL_ARB_occlusion_query2" << LL_ENDL;
    	}
    
    	if (!mHasPointParameters)
    	{
    		LL_INFOS("RenderInit") << "Couldn't initialize GL_ARB_point_parameters" << LL_ENDL;
    	}
    	if (!mHasShaderObjects)
    	{
    		LL_INFOS("RenderInit") << "Couldn't initialize GL_ARB_shader_objects" << LL_ENDL;
    	}
    	if (!mHasVertexShader)
    	{
    		LL_INFOS("RenderInit") << "Couldn't initialize GL_ARB_vertex_shader" << LL_ENDL;
    	}
    	if (!mHasFragmentShader)
    	{
    		LL_INFOS("RenderInit") << "Couldn't initialize GL_ARB_fragment_shader" << LL_ENDL;
    	}
    
    	if (!mHasBlendFuncSeparate)
    	{
    		LL_INFOS("RenderInit") << "Couldn't initialize GL_EXT_blend_func_separate" << LL_ENDL;
    	}
    	if (!mHasDrawBuffers)
    	{
    		LL_INFOS("RenderInit") << "Couldn't initialize GL_ARB_draw_buffers" << LL_ENDL;
    	}
    
    
    	// Disable certain things due to known bugs
    	if (mIsIntel && mHasMipMapGeneration)
    	{
    		LL_INFOS("RenderInit") << "Disabling mip-map generation for Intel GPUs" << LL_ENDL;
    		mHasMipMapGeneration = FALSE;
    	}
    	if (mIsATI && mHasMipMapGeneration)
    	{
    		LL_INFOS("RenderInit") << "Disabling mip-map generation for ATI GPUs (performance opt)" << LL_ENDL;
    		mHasMipMapGeneration = FALSE;
    	}
    	
    	// Misc
    	glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, (GLint*) &mGLMaxVertexRange);
    	glGetIntegerv(GL_MAX_ELEMENTS_INDICES, (GLint*) &mGLMaxIndexRange);
    	
    
    #if (LL_WINDOWS || LL_LINUX || LL_SOLARIS) && !LL_MESA_HEADLESS
    
    	LL_DEBUGS("RenderInit") << "GL Probe: Getting symbols" << LL_ENDL;
    	if (mHasVertexBufferObject)
    	{
    		glBindBufferARB = (PFNGLBINDBUFFERARBPROC)GLH_EXT_GET_PROC_ADDRESS("glBindBufferARB");
    		if (glBindBufferARB)
    		{
    			glDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC)GLH_EXT_GET_PROC_ADDRESS("glDeleteBuffersARB");
    			glGenBuffersARB = (PFNGLGENBUFFERSARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGenBuffersARB");
    			glIsBufferARB = (PFNGLISBUFFERARBPROC)GLH_EXT_GET_PROC_ADDRESS("glIsBufferARB");
    			glBufferDataARB = (PFNGLBUFFERDATAARBPROC)GLH_EXT_GET_PROC_ADDRESS("glBufferDataARB");
    			glBufferSubDataARB = (PFNGLBUFFERSUBDATAARBPROC)GLH_EXT_GET_PROC_ADDRESS("glBufferSubDataARB");
    			glGetBufferSubDataARB = (PFNGLGETBUFFERSUBDATAARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetBufferSubDataARB");
    			glMapBufferARB = (PFNGLMAPBUFFERARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMapBufferARB");
    			glUnmapBufferARB = (PFNGLUNMAPBUFFERARBPROC)GLH_EXT_GET_PROC_ADDRESS("glUnmapBufferARB");
    			glGetBufferParameterivARB = (PFNGLGETBUFFERPARAMETERIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetBufferParameterivARB");
    			glGetBufferPointervARB = (PFNGLGETBUFFERPOINTERVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetBufferPointervARB");
    		}
    		else
    		{
    			mHasVertexBufferObject = FALSE;
    		}
    	}
    	if (mHasFramebufferObject)
    	{
    
    		llinfos << "initExtensions() FramebufferObject-related procs..." << llendl;
    
    		glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC) GLH_EXT_GET_PROC_ADDRESS("glIsRenderbuffer");
    		glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC) GLH_EXT_GET_PROC_ADDRESS("glBindRenderbuffer");
    		glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteRenderbuffers");
    		glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC) GLH_EXT_GET_PROC_ADDRESS("glGenRenderbuffers");
    		glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC) GLH_EXT_GET_PROC_ADDRESS("glRenderbufferStorage");
    		glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC) GLH_EXT_GET_PROC_ADDRESS("glGetRenderbufferParameteriv");
    		glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC) GLH_EXT_GET_PROC_ADDRESS("glIsFramebuffer");
    		glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC) GLH_EXT_GET_PROC_ADDRESS("glBindFramebuffer");
    		glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteFramebuffers");
    		glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC) GLH_EXT_GET_PROC_ADDRESS("glGenFramebuffers");
    		glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC) GLH_EXT_GET_PROC_ADDRESS("glCheckFramebufferStatus");
    		glFramebufferTexture1D = (PFNGLFRAMEBUFFERTEXTURE1DPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferTexture1D");
    		glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferTexture2D");
    		glFramebufferTexture3D = (PFNGLFRAMEBUFFERTEXTURE3DPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferTexture3D");
    		glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferRenderbuffer");
    		glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) GLH_EXT_GET_PROC_ADDRESS("glGetFramebufferAttachmentParameteriv");
    		glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC) GLH_EXT_GET_PROC_ADDRESS("glGenerateMipmap");
    		glBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC) GLH_EXT_GET_PROC_ADDRESS("glBlitFramebuffer");
    		glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC) GLH_EXT_GET_PROC_ADDRESS("glRenderbufferStorageMultisample");
    		glFramebufferTextureLayer = (PFNGLFRAMEBUFFERTEXTURELAYERPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferTextureLayer");
    
    	}
    	if (mHasDrawBuffers)
    	{
    		glDrawBuffersARB = (PFNGLDRAWBUFFERSARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDrawBuffersARB");
    	}
    
    	if (mHasBlendFuncSeparate)
    	{
    		glBlendFuncSeparateEXT = (PFNGLBLENDFUNCSEPARATEEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glBlendFuncSeparateEXT");
    	}
    
    #if (!LL_LINUX && !LL_SOLARIS) || LL_LINUX_NV_GL_HEADERS
    	// This is expected to be a static symbol on Linux GL implementations, except if we use the nvidia headers - bah
    
    	glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC)GLH_EXT_GET_PROC_ADDRESS("glDrawRangeElements");
    	if (!glDrawRangeElements)
    	{
    		mGLMaxVertexRange = 0;
    		mGLMaxIndexRange = 0;
    	}
    
    #endif // !LL_LINUX || LL_LINUX_NV_GL_HEADERS
    #if LL_LINUX_NV_GL_HEADERS
    	// nvidia headers are critically different from mesa-esque
     	glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC)GLH_EXT_GET_PROC_ADDRESS("glActiveTextureARB");
     	glClientActiveTextureARB = (PFNGLCLIENTACTIVETEXTUREARBPROC)GLH_EXT_GET_PROC_ADDRESS("glClientActiveTextureARB");
    #endif // LL_LINUX_NV_GL_HEADERS
    
    	if (mHasOcclusionQuery)
    	{
    
    		llinfos << "initExtensions() OcclusionQuery-related procs..." << llendl;
    
    		glGenQueriesARB = (PFNGLGENQUERIESARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGenQueriesARB");
    		glDeleteQueriesARB = (PFNGLDELETEQUERIESARBPROC)GLH_EXT_GET_PROC_ADDRESS("glDeleteQueriesARB");
    		glIsQueryARB = (PFNGLISQUERYARBPROC)GLH_EXT_GET_PROC_ADDRESS("glIsQueryARB");
    		glBeginQueryARB = (PFNGLBEGINQUERYARBPROC)GLH_EXT_GET_PROC_ADDRESS("glBeginQueryARB");
    		glEndQueryARB = (PFNGLENDQUERYARBPROC)GLH_EXT_GET_PROC_ADDRESS("glEndQueryARB");
    		glGetQueryivARB = (PFNGLGETQUERYIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetQueryivARB");
    		glGetQueryObjectivARB = (PFNGLGETQUERYOBJECTIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetQueryObjectivARB");
    		glGetQueryObjectuivARB = (PFNGLGETQUERYOBJECTUIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetQueryObjectuivARB");
    	}
    	if (mHasPointParameters)
    	{
    
    		llinfos << "initExtensions() PointParameters-related procs..." << llendl;
    
    		glPointParameterfARB = (PFNGLPOINTPARAMETERFARBPROC)GLH_EXT_GET_PROC_ADDRESS("glPointParameterfARB");
    		glPointParameterfvARB = (PFNGLPOINTPARAMETERFVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glPointParameterfvARB");
    	}
    	if (mHasShaderObjects)
    	{
    		glDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteObjectARB");
    		glGetHandleARB = (PFNGLGETHANDLEARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetHandleARB");
    		glDetachObjectARB = (PFNGLDETACHOBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDetachObjectARB");
    		glCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glCreateShaderObjectARB");
    		glShaderSourceARB = (PFNGLSHADERSOURCEARBPROC) GLH_EXT_GET_PROC_ADDRESS("glShaderSourceARB");
    		glCompileShaderARB = (PFNGLCOMPILESHADERARBPROC) GLH_EXT_GET_PROC_ADDRESS("glCompileShaderARB");
    		glCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glCreateProgramObjectARB");
    		glAttachObjectARB = (PFNGLATTACHOBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glAttachObjectARB");
    		glLinkProgramARB = (PFNGLLINKPROGRAMARBPROC) GLH_EXT_GET_PROC_ADDRESS("glLinkProgramARB");
    		glUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUseProgramObjectARB");
    		glValidateProgramARB = (PFNGLVALIDATEPROGRAMARBPROC) GLH_EXT_GET_PROC_ADDRESS("glValidateProgramARB");
    		glUniform1fARB = (PFNGLUNIFORM1FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform1fARB");
    		glUniform2fARB = (PFNGLUNIFORM2FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform2fARB");
    		glUniform3fARB = (PFNGLUNIFORM3FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform3fARB");
    		glUniform4fARB = (PFNGLUNIFORM4FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform4fARB");
    		glUniform1iARB = (PFNGLUNIFORM1IARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform1iARB");
    		glUniform2iARB = (PFNGLUNIFORM2IARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform2iARB");
    		glUniform3iARB = (PFNGLUNIFORM3IARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform3iARB");
    		glUniform4iARB = (PFNGLUNIFORM4IARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform4iARB");
    		glUniform1fvARB = (PFNGLUNIFORM1FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform1fvARB");