Newer
Older
/**
* @file llgl.cpp
* @brief LLGL implementation
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* 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 "llstacktrace.h"
#include "llglslshader.h"
#if LL_WINDOWS
#include "lldxhardware.h"
#endif
#ifdef _DEBUG
//#define GL_STATE_VERIFY
#endif
#if LL_SDL
#include <SDL.h>
#endif
BOOL gDebugSession = FALSE;
BOOL gHeadlessClient = FALSE;
BOOL gGLDebugLoggingEnabled = TRUE;
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");
andreykproductengine
committed
llofstream gFailLog;
#ifndef APIENTRY
#define APIENTRY
#endif
void APIENTRY gl_debug_callback(GLenum source,
GLenum type,
GLuint id,
GLenum severity,
GLsizei length,
const GLchar* message,
GLvoid* userParam)
{
if (gGLDebugLoggingEnabled)
{
if (severity == GL_DEBUG_SEVERITY_HIGH)
{
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)
{
LL_ERRS() << "Halting on GL Error" << LL_ENDL;
}
}
}
David Parks
committed
void parse_glsl_version(S32& major, S32& minor);
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
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;
std::list<LLGLUpdate*> LLGLUpdate::sGLQ;
LLGLManager gGLManager;
LLGLManager::LLGLManager() :
mInited(FALSE),
mIsDisabled(FALSE),
mHasMultitexture(FALSE),
David Parks
committed
mHasATIMemInfo(FALSE),
mHasAMDAssociations(FALSE),
mHasNVXMemInfo(FALSE),
mNumTextureUnits(1),
mHasMipMapGeneration(FALSE),
mHasCompressedTextures(FALSE),
mHasFramebufferObject(FALSE),
David Parks
committed
mMaxSamples(0),
David Parks
committed
mHasSync(FALSE),
mHasVertexArrayObject(FALSE),
mHasMapBufferRange(FALSE),
mHasPBuffer(FALSE),
mHasShaderObjects(FALSE),
mHasVertexShader(FALSE),
mHasFragmentShader(FALSE),
mNumTextureImageUnits(0),
David Parks
committed
mHasTimerQuery(FALSE),
mHasOcclusionQuery2(FALSE),
David Parks
committed
mHasTextureMultisample(FALSE),
David Parks
committed
mHasTransformFeedback(FALSE),
David Parks
committed
mMaxSampleMaskWords(0),
mMaxColorTextureSamples(0),
mMaxDepthTextureSamples(0),
mMaxIntegerSamples(0),
mHasAnisotropic(FALSE),
mHasARBEnvCombine(FALSE),
mHasCubeMap(FALSE),
mHasDebugOutput(FALSE),
mHasTextureSwizzle(false),
mIsATI(FALSE),
mIsNVIDIA(FALSE),
mIsIntel(FALSE),
mIsGF2or4MX(FALSE),
mIsGF3(FALSE),
mIsGFFX(FALSE),
mATIOffsetVerticalLines(FALSE),
mATIOldDriver(FALSE),
Graham Madarasz
committed
#if LL_DARWIN
mIsMobileGF(FALSE),
#endif
mHasRequirements(TRUE),
mHasSeparateSpecularColor(FALSE),
mDriverVersionMajor(1),
mDriverVersionMinor(0),
mDriverVersionRelease(0),
mGLVersion(1.0f),
David Parks
committed
mGLSLVersionMajor(0),
mGLSLVersionMinor(0),
mVRAM(0),
mGLMaxVertexRange(0),
mGLMaxIndexRange(0)
{
}
//---------------------------------------------------------------------
// Global initialization for GL
//---------------------------------------------------------------------
if (!epoxy_has_wgl_extension(dc, "WGL_ARB_pixel_format"))
{
LL_WARNS("RenderInit") << "No ARB pixel format extensions" << LL_ENDL;
}
if (epoxy_has_wgl_extension(dc, "WGL_ARB_create_context"))
{
//GLH_EXT_NAME(wglCreateContextAttribsARB) = (PFNWGLCREATECONTEXTATTRIBSARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglCreateContextAttribsARB");
}
else
{
LL_WARNS("RenderInit") << "No ARB create context extensions" << LL_ENDL;
}
// For retreiving information per AMD adapter,
// because we can't trust curently selected/default one when there are multiple
mHasAMDAssociations = epoxy_has_wgl_extension(dc, "WGL_AMD_gpu_association");
if (mHasAMDAssociations)
{
//GLH_EXT_NAME(wglGetGPUIDsAMD) = (PFNWGLGETGPUIDSAMDPROC)GLH_EXT_GET_PROC_ADDRESS("wglGetGPUIDsAMD");
//GLH_EXT_NAME(wglGetGPUInfoAMD) = (PFNWGLGETGPUINFOAMDPROC)GLH_EXT_GET_PROC_ADDRESS("wglGetGPUInfoAMD");
if (epoxy_has_wgl_extension(dc, "WGL_EXT_swap_control"))
//GLH_EXT_NAME(wglSwapIntervalEXT) = (PFNWGLSWAPINTERVALEXTPROC)GLH_EXT_GET_PROC_ADDRESS("wglSwapIntervalEXT");
if( !epoxy_has_wgl_extension(dc, "WGL_ARB_pbuffer") )
{
LL_WARNS("RenderInit") << "No ARB WGL PBuffer extensions" << LL_ENDL;
}
if( !epoxy_has_wgl_extension(dc, "WGL_ARB_render_texture") )
{
LL_WARNS("RenderInit") << "No ARB WGL render texture extensions" << LL_ENDL;
}
mHasPBuffer = epoxy_has_wgl_extension(dc, "WGL_ARB_pbuffer") &&
epoxy_has_wgl_extension(dc, "WGL_ARB_render_texture") &&
epoxy_has_wgl_extension(dc, "WGL_ARB_pixel_format");
// 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;
}
stop_glerror();
// Extract video card strings and convert to upper case to
// work around driver-to-driver variation in capitalization.
mGLVendor = ll_safe_string((const char *)glGetString(GL_VENDOR));
LLStringUtil::toUpper(mGLVendor);
mGLRenderer = ll_safe_string((const char *)glGetString(GL_RENDERER));
LLStringUtil::toUpper(mGLRenderer);
parse_gl_version( &mDriverVersionMajor,
&mDriverVersionMinor,
&mDriverVersionRelease,
&mDriverVersionVendorString,
&mGLVersionString);
mGLVersion = mDriverVersionMajor + mDriverVersionMinor * .1f;
David Parks
committed
David Parks
committed
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
David Parks
committed
}
if (mGLVersion >= 2.1f && LLImageGL::sCompressTextures)
{ //use texture compression
David Parks
committed
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 ")
{
mGLVendorShort = "ATI";
Don Kjer
committed
// *TODO: Fix this?
mIsATI = TRUE;
#if LL_WINDOWS && !LL_MESA_HEADLESS
if (mDriverVersionRelease < 3842)
{
mATIOffsetVerticalLines = TRUE;
}
#endif // LL_WINDOWS
#if (LL_WINDOWS || LL_LINUX) && !LL_MESA_HEADLESS
// count any pre OpenGL 3.0 implementation as an old driver
if (mGLVersion < 3.f)
{
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;
}
Graham Madarasz
committed
#if LL_DARWIN
else if ((mGLRenderer.find("9400M") != std::string::npos)
Graham Linden
committed
|| (mGLRenderer.find("9600M") != std::string::npos)
|| (mGLRenderer.find("9800M") != std::string::npos))
Graham Madarasz
committed
{
mIsMobileGF = TRUE;
}
#endif
}
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";
}
stop_glerror();
// This is called here because it depends on the setting of mIsGF2or4MX, and sets up mHasMultitexture.
initExtensions();
stop_glerror();
if (mVRAM == 0)
{
S32 old_vram = mVRAM;
David Parks
committed
#if LL_WINDOWS
if (mHasAMDAssociations)
{
GLuint gl_gpus_count = wglGetGPUIDsAMD(0, 0);
if (gl_gpus_count > 0)
{
GLuint* ids = new GLuint[gl_gpus_count];
wglGetGPUIDsAMD(gl_gpus_count, ids);
David Parks
committed
GLuint mem_mb = 0;
for (U32 i = 0; i < gl_gpus_count; i++)
{
wglGetGPUInfoAMD(ids[i],
WGL_GPU_RAM_AMD,
GL_UNSIGNED_INT,
sizeof(GLuint),
&mem_mb);
if (mVRAM < mem_mb)
{
// basically pick the best AMD and trust driver/OS to know to switch
mVRAM = mem_mb;
}
}
LL_WARNS("RenderInit") << "VRAM Detected (AMDAssociations):" << mVRAM << LL_ENDL;
if (mHasATIMemInfo && mVRAM == 0)
David Parks
committed
{ //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;
LL_WARNS("RenderInit") << "VRAM Detected (ATIMemInfo):" << mVRAM << LL_ENDL;
David Parks
committed
}
if (mHasNVXMemInfo && mVRAM == 0)
{
S32 dedicated_memory;
glGetIntegerv(GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX, &dedicated_memory);
mVRAM = dedicated_memory/1024;
LL_WARNS("RenderInit") << "VRAM Detected (NVXMemInfo):" << mVRAM << LL_ENDL;
}
David Parks
committed
David Parks
committed
if (mVRAM < 256)
{
// Something likely went wrong using the above extensions
// try WMI first and fall back to old method (from dxdiag) if all else fails
// Function will check all GPUs WMI knows of and will pick up the one with most
// memory. We need to check all GPUs because system can switch active GPU to
// weaker one, to preserve power when not under load.
S32 mem = LLDXHardware::getMBVideoMemoryViaDXGI();
if (mem != 0)
{
mVRAM = mem;
LL_WARNS("RenderInit") << "VRAM Detected (WMI):" << mVRAM<< LL_ENDL;
}
#endif
if (mVRAM < 256 && old_vram > 0)
{
// fall back to old method
// Note: on Windows value will be from LLDXHardware.
// Either received via dxdiag or via WMI by id from dxdiag.
David Parks
committed
mVRAM = old_vram;
}
else
{
LL_INFOS("RenderInit") << "Detected VRAM from GL: " << mVRAM << LL_ENDL;
}
David Parks
committed
}
{
LL_INFOS("RenderInit") << "Using VRAM value from OS: " << mVRAM << LL_ENDL;
David Parks
committed
}
stop_glerror();
if (mHasFragmentShader)
{
GLint num_tex_image_units;
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &num_tex_image_units);
mNumTextureImageUnits = llmin(num_tex_image_units, 32);
}
LL_INFOS() << "NUM TEX IMAGE UNITS: " << mNumTextureImageUnits << LL_ENDL;
if (LLRender::sGLCoreProfile)
{
David Parks
committed
mNumTextureUnits = llmin(mNumTextureImageUnits, MAX_GL_TEXTURE_UNITS);
}
else if (mHasMultitexture)
glGetIntegerv(GL_MAX_TEXTURE_UNITS, &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;
}
stop_glerror();
David Parks
committed
if (mHasTextureMultisample)
{
glGetIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES, &mMaxColorTextureSamples);
glGetIntegerv(GL_MAX_DEPTH_TEXTURE_SAMPLES, &mMaxDepthTextureSamples);
glGetIntegerv(GL_MAX_INTEGER_SAMPLES, &mMaxIntegerSamples);
glGetIntegerv(GL_MAX_SAMPLE_MASK_WORDS, &mMaxSampleMaskWords);
}
stop_glerror();
if (mHasDebugOutput && gDebugGL)
{ //setup debug output callback
glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW, 0, NULL, GL_TRUE);
glDebugMessageCallback((GLDEBUGPROC) gl_debug_callback, NULL);
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
}
stop_glerror();
//HACK always disable texture multisample, use FXAA instead
mHasTextureMultisample = FALSE;
David Parks
committed
#if LL_WINDOWS
if (mIsATI)
{ //using multisample textures on ATI results in black screen for some reason
mHasTextureMultisample = FALSE;
}
Graham Madarasz (Graham)
committed
David Parks
committed
if (mIsIntel && mGLVersion <= 3.f)
{ //never try to use framebuffer objects on older intel drivers (crashy)
mHasFramebufferObject = FALSE;
}
Graham Madarasz (Graham)
committed
#endif
David Parks
committed
if (mHasFramebufferObject)
{
glGetIntegerv(GL_MAX_SAMPLES, &mMaxSamples);
}
stop_glerror();
stop_glerror();
stop_glerror();
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"] = ll_safe_string((const char *)glGetString(GL_VENDOR));
info["GLInfo"]["GLRenderer"] = ll_safe_string((const char *)glGetString(GL_RENDERER));
info["GLInfo"]["GLVersion"] = ll_safe_string((const char *)glGetString(GL_VERSION));
#if !LL_DARWIN
if (mGLVersion >= 3.0f && glGetStringi) {
std::vector<std::string> gl_extension_str_vec;
GLint n, i;
glGetIntegerv(GL_NUM_EXTENSIONS, &n);
for (i = 0; i < n; i++) {
std::string exten = ll_safe_string((const char *) glGetStringi(GL_EXTENSIONS, i));
if (!exten.empty())
info["GLInfo"]["GLExtensions"].append(exten);
}
} else
#endif
{
std::string all_exts = ll_safe_string((const char *) glGetString(GL_EXTENSIONS));
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");
}
#if !LL_MESA_HEADLESS
#if !LL_DARWIN
if (mGLVersion >= 3.0f && glGetStringi) {
std::stringstream gl_extension_strstrm;
GLint n, i;
glGetIntegerv(GL_NUM_EXTENSIONS, &n);
for (i = 0; i < n; i++) {
std::string exten = ll_safe_string((const char *) glGetStringi(GL_EXTENSIONS, i));
if (!exten.empty() && i != n)
gl_extension_strstrm << exten << "\n";
}
info_str += std::string("GL_EXTENSIONS:\n") + gl_extension_strstrm.str() + std::string("\n");
} else
{
std::string all_exts = ll_safe_string((const char *) glGetString(GL_EXTENSIONS));
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: " << ll_safe_string((const char *)glGetString(GL_VENDOR)) << LL_ENDL;
LL_INFOS("RenderInit") << "GL_RENDERER: " << ll_safe_string((const char *)glGetString(GL_RENDERER)) << LL_ENDL;
LL_INFOS("RenderInit") << "GL_VERSION: " << ll_safe_string((const char *)glGetString(GL_VERSION)) << LL_ENDL;
#if !LL_DARWIN
if (mGLVersion >= 3.0f && glGetStringi) {
std::stringstream gl_extension_strstrm;
GLint n, i;
glGetIntegerv(GL_NUM_EXTENSIONS, &n);
for (i = 0; i < n; i++) {
std::string exten = ll_safe_string((const char *) glGetStringi(GL_EXTENSIONS, i));
if (!exten.empty() && i != n)
gl_extension_strstrm << exten << "\n";
}
LL_INFOS("RenderInit") << "GL_EXTENSIONS:\n" << gl_extension_strstrm.str() << LL_ENDL;
}
else
#endif
{
std::string all_exts = ll_safe_string((const char *) glGetString(GL_EXTENSIONS));
LLStringUtil::replaceChar(all_exts, ' ', '\n');
LL_INFOS("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
Merov Linden
committed
# ifdef GL_ARB_multitexture
mHasMultitexture = TRUE;
# else
mHasMultitexture = FALSE;
# endif // GL_ARB_multitexture
Merov Linden
committed
# ifdef GL_ARB_texture_env_combine
mHasARBEnvCombine = TRUE;
# else
mHasARBEnvCombine = FALSE;
# endif // GL_ARB_texture_env_combine
Merov Linden
committed
# ifdef GL_ARB_texture_compression
mHasCompressedTextures = TRUE;
# else
mHasCompressedTextures = FALSE;
# endif // GL_ARB_texture_compression
Merov Linden
committed
# ifdef GL_ARB_vertex_buffer_object
mHasVertexBufferObject = TRUE;
# else
mHasVertexBufferObject = FALSE;
# endif // GL_ARB_vertex_buffer_object
Merov Linden
committed
# ifdef GL_EXT_framebuffer_object
mHasFramebufferObject = TRUE;
# else
mHasFramebufferObject = FALSE;
# endif // GL_EXT_framebuffer_object
Merov Linden
committed
# ifdef GL_ARB_draw_buffers
mHasDrawBuffers = TRUE;
#else
mHasDrawBuffers = FALSE;
# endif // GL_ARB_draw_buffers
Merov Linden
committed
# 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 = mGLVersion >= 1.3f || epoxy_has_gl_extension("GL_ARB_multitexture");
mHasATIMemInfo = epoxy_has_gl_extension("GL_ATI_meminfo"); //Basic AMD method, also see mHasAMDAssociations
mHasNVXMemInfo = epoxy_has_gl_extension("GL_NVX_gpu_memory_info");
mHasSeparateSpecularColor = mGLVersion >= 1.2f || epoxy_has_gl_extension("GL_EXT_separate_specular_color");
mHasAnisotropic = mGLVersion >= 4.6f || epoxy_has_gl_extension("GL_EXT_texture_filter_anisotropic");
mHasCubeMap = mGLVersion >= 1.3f || epoxy_has_gl_extension("GL_ARB_texture_cube_map");
mHasARBEnvCombine = mGLVersion >= 1.3f || epoxy_has_gl_extension("GL_ARB_texture_env_combine");
mHasCompressedTextures = mGLVersion >= 1.3f || epoxy_has_gl_extension("GL_ARB_texture_compression");
mHasOcclusionQuery = mGLVersion >= 1.5f || epoxy_has_gl_extension("GL_ARB_occlusion_query");
mHasTimerQuery = mGLVersion >= 3.3f || epoxy_has_gl_extension("GL_ARB_timer_query");
mHasOcclusionQuery2 = mGLVersion >= 3.3f || epoxy_has_gl_extension("GL_ARB_occlusion_query2");
mHasVertexBufferObject = mGLVersion >= 1.5f || epoxy_has_gl_extension("GL_ARB_vertex_buffer_object");
mHasVertexArrayObject = mGLVersion >= 3.0f || epoxy_has_gl_extension("GL_ARB_vertex_array_object");
mHasSync = mGLVersion >= 3.2f || epoxy_has_gl_extension("GL_ARB_sync");
mHasMapBufferRange = mGLVersion >= 3.0f || epoxy_has_gl_extension("GL_ARB_map_buffer_range");
mHasFlushBufferRange = epoxy_has_gl_extension("GL_APPLE_flush_buffer_range");
mHasDepthClamp = mGLVersion >= 3.2f || (epoxy_has_gl_extension("GL_ARB_depth_clamp") || epoxy_has_gl_extension("GL_NV_depth_clamp"));
// mask out FBO support when packed_depth_stencil isn't there 'cause we need it for LLRenderTarget -Brad
#ifdef GL_ARB_framebuffer_object
mHasFramebufferObject = mGLVersion >= 3.0f || epoxy_has_gl_extension("GL_ARB_framebuffer_object");
#else
mHasFramebufferObject = mGLVersion >= 3.0f || (epoxy_has_gl_extension("GL_EXT_framebuffer_object") &&
epoxy_has_gl_extension("GL_EXT_framebuffer_blit") &&
epoxy_has_gl_extension("GL_EXT_framebuffer_multisample") &&
epoxy_has_gl_extension("GL_EXT_packed_depth_stencil"));
#endif
#ifdef GL_EXT_texture_sRGB
mHassRGBTexture = mGLVersion >= 2.1f || epoxy_has_gl_extension("GL_EXT_texture_sRGB");
#endif
#ifdef GL_ARB_framebuffer_sRGB
mHassRGBFramebuffer = mGLVersion >= 3.0f || epoxy_has_gl_extension("GL_ARB_framebuffer_sRGB");
#else
mHassRGBFramebuffer = mGLVersion >= 3.0f || epoxy_has_gl_extension("GL_EXT_framebuffer_sRGB");
#endif
#ifdef GL_EXT_texture_sRGB_decode
mHasTexturesRGBDecode = epoxy_has_gl_extension("GL_EXT_texture_sRGB_decode");
#else
mHasTexturesRGBDecode = epoxy_has_gl_extension("GL_ARB_texture_sRGB_decode");
#endif
mHasMipMapGeneration = mHasFramebufferObject || mGLVersion >= 1.4f;
mHasDrawBuffers = mGLVersion >= 2.0f || epoxy_has_gl_extension("GL_ARB_draw_buffers");
mHasBlendFuncSeparate = mGLVersion >= 1.4f || epoxy_has_gl_extension("GL_EXT_blend_func_separate");
mHasTextureRectangle = mGLVersion >= 3.1f || epoxy_has_gl_extension("GL_ARB_texture_rectangle");
mHasTextureMultisample = mGLVersion >= 3.2f || epoxy_has_gl_extension("GL_ARB_texture_multisample");
mHasDebugOutput = mGLVersion >= 4.3f || epoxy_has_gl_extension("GL_ARB_debug_output");
mHasTransformFeedback = mGLVersion >= 4.0f ? TRUE : FALSE;
mHasPointParameters = !mIsATI && (mGLVersion >= 1.4f || epoxy_has_gl_extension("GL_ARB_point_parameters"));
mHasShaderObjects = mGLVersion >= 2.0f || (epoxy_has_gl_extension("GL_ARB_shader_objects") && (LLRender::sGLCoreProfile || epoxy_has_gl_extension("GL_ARB_shading_language_100")));
mHasVertexShader = mGLVersion >= 2.0f || (epoxy_has_gl_extension("GL_ARB_vertex_program") && epoxy_has_gl_extension("GL_ARB_vertex_shader")
&& (LLRender::sGLCoreProfile || epoxy_has_gl_extension("GL_ARB_shading_language_100")));
mHasFragmentShader = mGLVersion >= 2.0f || (epoxy_has_gl_extension("GL_ARB_fragment_shader") && (LLRender::sGLCoreProfile || epoxy_has_gl_extension("GL_ARB_shading_language_100")));
mHasTextureSwizzle = mGLVersion >= 3.3f || epoxy_has_gl_extension("GL_ARB_texture_swizzle");
#if LL_LINUX || LL_SOLARIS
LL_INFOS() << "initExtensions() checking shell variables to adjust features..." << LL_ENDL;
// 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.
{
//mHasMultitexture = FALSE; // NEEDED!
Merov Linden
committed
mHasDepthClamp = FALSE;
mHasARBEnvCombine = FALSE;
mHasCompressedTextures = FALSE;
mHasVertexBufferObject = FALSE;
mHasFramebufferObject = FALSE;
mHasDrawBuffers = FALSE;
mHasMipMapGeneration = FALSE;
mHasSeparateSpecularColor = FALSE;
mHasAnisotropic = FALSE;
mHasCubeMap = FALSE;
mHasOcclusionQuery = FALSE;
mHasPointParameters = FALSE;
mHasShaderObjects = FALSE;
mHasVertexShader = FALSE;
mHasFragmentShader = FALSE;
mHasTextureSwizzle = 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;
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
David Parks
committed
if (strchr(blacklist,'s')) mHasTextureRectangle = FALSE;
if (strchr(blacklist,'t')) mHasBlendFuncSeparate = FALSE;//S
if (strchr(blacklist,'u')) mHasDepthClamp = FALSE;
#endif // LL_LINUX || LL_SOLARIS
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
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;
// }
// Misc
glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, (GLint*) &mGLMaxVertexRange);
glGetIntegerv(GL_MAX_ELEMENTS_INDICES, (GLint*) &mGLMaxIndexRange);
glGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint*) &mGLMaxTextureSize);