diff options
Diffstat (limited to 'indra/llrender')
-rw-r--r-- | indra/llrender/CMakeLists.txt | 34 | ||||
-rw-r--r-- | indra/llrender/llcubemap.cpp | 532 | ||||
-rw-r--r-- | indra/llrender/llcubemap.h | 89 | ||||
-rw-r--r-- | indra/llrender/llgl.cpp | 1726 | ||||
-rw-r--r-- | indra/llrender/llgl.h | 377 | ||||
-rw-r--r-- | indra/llrender/llglheaders.h | 588 | ||||
-rw-r--r-- | indra/llrender/llglslshader.cpp | 823 | ||||
-rw-r--r-- | indra/llrender/llglslshader.h | 139 | ||||
-rw-r--r-- | indra/llrender/llglstates.h | 302 | ||||
-rw-r--r-- | indra/llrender/llgltypes.h | 44 | ||||
-rw-r--r-- | indra/llrender/llpostprocess.cpp | 574 | ||||
-rw-r--r-- | indra/llrender/llpostprocess.h | 268 | ||||
-rw-r--r-- | indra/llrender/llrender.cpp | 6 | ||||
-rw-r--r-- | indra/llrender/llrender.h | 5 | ||||
-rw-r--r-- | indra/llrender/llrendersphere.cpp | 159 | ||||
-rw-r--r-- | indra/llrender/llrendersphere.h | 34 | ||||
-rw-r--r-- | indra/llrender/llshadermgr.cpp | 513 | ||||
-rw-r--r-- | indra/llrender/llshadermgr.h | 75 | ||||
-rw-r--r-- | indra/llrender/llvertexbuffer.h | 1 |
19 files changed, 6288 insertions, 1 deletions
diff --git a/indra/llrender/CMakeLists.txt b/indra/llrender/CMakeLists.txt index 2dba8ef60d..76858d9839 100644 --- a/indra/llrender/CMakeLists.txt +++ b/indra/llrender/CMakeLists.txt @@ -20,24 +20,38 @@ include_directories( ) set(llrender_SOURCE_FILES + llcubemap.cpp llfont.cpp llfontgl.cpp llgldbg.cpp + llglslshader.cpp llimagegl.cpp + llpostprocess.cpp llrender.cpp + llrendersphere.cpp llrendertarget.cpp + llshadermgr.cpp llvertexbuffer.cpp ) set(llrender_HEADER_FILES CMakeLists.txt + llcubemap.h llfontgl.h llfont.h + llgl.h llgldbg.h + llglheaders.h + llglslshader.h + llglstates.h + llgltypes.h llimagegl.h + llpostprocess.h llrender.h + llrendersphere.h llrendertarget.h + llshadermgr.h llvertexbuffer.h ) @@ -46,4 +60,24 @@ set_source_files_properties(${llrender_HEADER_FILES} list(APPEND llrender_SOURCE_FILES ${llrender_HEADER_FILES}) +if (SERVER AND NOT WINDOWS AND NOT DARWIN) + copy_server_sources( + llgl + ) + + + set_source_files_properties( + ${server_SOURCE_FILES} + PROPERTIES + COMPILE_FLAGS "-DLL_MESA=1 -DLL_MESA_HEADLESS=1" + ) + add_library (llrenderheadless + ${llrender_SOURCE_FILES} + ${server_SOURCE_FILES} + ) +else (SERVER AND NOT WINDOWS AND NOT DARWIN) + list(APPEND llrender_SOURCE_FILES + llgl.cpp + ) +endif (SERVER AND NOT WINDOWS AND NOT DARWIN) add_library (llrender ${llrender_SOURCE_FILES}) diff --git a/indra/llrender/llcubemap.cpp b/indra/llrender/llcubemap.cpp new file mode 100644 index 0000000000..f19992eeab --- /dev/null +++ b/indra/llrender/llcubemap.cpp @@ -0,0 +1,532 @@ +/** + * @file llcubemap.cpp + * @brief LLCubeMap class implementation + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2007, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ +#include "linden_common.h" + +#include "llworkerthread.h" + +#include "llcubemap.h" + +#include "v4coloru.h" +#include "v3math.h" +#include "v3dmath.h" +#include "m3math.h" +#include "m4math.h" +#include "llcamera.h" + +#include "llrender.h" + +#include "llglheaders.h" + +const F32 epsilon = 1e-7f; +const U16 RESOLUTION = 64; + +#if LL_DARWIN +// mipmap generation on cubemap textures seems to be broken on the Mac for at least some cards. +// Since the cubemap is small (64x64 per face) and doesn't have any fine detail, turning off mipmaps is a usable workaround. +const BOOL use_cube_mipmaps = FALSE; +#else +const BOOL use_cube_mipmaps = FALSE; //current build works best without cube mipmaps +#endif + +bool LLCubeMap::sUseCubeMaps = true; + +LLCubeMap::LLCubeMap() + : mTextureStage(0), + mTextureCoordStage(0), + mMatrixStage(0) +{ +} + +LLCubeMap::~LLCubeMap() +{ +} + +void LLCubeMap::initGL() +{ + llassert(gGLManager.mInited); + + if (gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps) + { + mTargets[0] = GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB; + mTargets[1] = GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB; + mTargets[2] = GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB; + mTargets[3] = GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB; + mTargets[4] = GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB; + mTargets[5] = GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB; + + // Not initialized, do stuff. + if (mImages[0].isNull()) + { + GLuint texname = 0; + + glGenTextures(1, &texname); + + for (int i = 0; i < 6; i++) + { + mImages[i] = new LLImageGL(64, 64, 4, (use_cube_mipmaps? TRUE : FALSE)); + mImages[i]->setTarget(mTargets[i], GL_TEXTURE_CUBE_MAP_ARB); + mRawImages[i] = new LLImageRaw(64, 64, 4); + mImages[i]->createGLTexture(0, mRawImages[i], texname); + + glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, texname); + mImages[i]->setClampCubemap (TRUE, TRUE, TRUE); + stop_glerror(); + } + } + disable(); + } + else + { + llwarns << "Using cube map without extension!" << llendl + } +} + +void LLCubeMap::initRawData(const std::vector<LLPointer<LLImageRaw> >& rawimages) +{ + bool flip_x[6] = { false, true, false, false, true, false }; + bool flip_y[6] = { true, true, true, false, true, true }; + bool transpose[6] = { false, false, false, false, true, true }; + + // Yes, I know that this is inefficient! - djs 08/08/02 + for (int i = 0; i < 6; i++) + { + const U8 *sd = rawimages[i]->getData(); + U8 *td = mRawImages[i]->getData(); + + S32 offset = 0; + S32 sx, sy, so; + for (int y = 0; y < 64; y++) + { + for (int x = 0; x < 64; x++) + { + sx = x; + sy = y; + if (flip_y[i]) + { + sy = 63 - y; + } + if (flip_x[i]) + { + sx = 63 - x; + } + if (transpose[i]) + { + S32 temp = sx; + sx = sy; + sy = temp; + } + + so = 64*sy + sx; + so *= 4; + *(td + offset++) = *(sd + so++); + *(td + offset++) = *(sd + so++); + *(td + offset++) = *(sd + so++); + *(td + offset++) = *(sd + so++); + } + } + } +} + +void LLCubeMap::initGLData() +{ + for (int i = 0; i < 6; i++) + { + mImages[i]->setSubImage(mRawImages[i], 0, 0, 64, 64); + } +} + +void LLCubeMap::init(const std::vector<LLPointer<LLImageRaw> >& rawimages) +{ + if (!gGLManager.mIsDisabled) + { + initGL(); + initRawData(rawimages); + initGLData(); + } +} + +GLuint LLCubeMap::getGLName() +{ + return mImages[0]->getTexName(); +} + +void LLCubeMap::bind() +{ + if (gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps) + { + // We assume that if they have cube mapping, they have multitexturing. + if (mTextureStage > 0) + { + gGL.getTexUnit(mTextureStage)->activate(); + } + glEnable(GL_TEXTURE_CUBE_MAP_ARB); + glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, mImages[0]->getTexName()); + + mImages[0]->setMipFilterNearest (FALSE, FALSE); + if (mTextureStage > 0) + { + gGL.getTexUnit(0)->activate(); + } + } + else + { + llwarns << "Using cube map without extension!" << llendl + } +} + +void LLCubeMap::enable(S32 stage) +{ + enableTexture(stage); + enableTextureCoords(stage); +} + +void LLCubeMap::enableTexture(S32 stage) +{ + mTextureStage = stage; + if (gGLManager.mHasCubeMap && stage >= 0 && LLCubeMap::sUseCubeMaps) + { + if (stage > 0) + { + gGL.getTexUnit(stage)->activate(); + } + + glEnable(GL_TEXTURE_CUBE_MAP_ARB); + + if (stage > 0) + { + gGL.getTexUnit(0)->activate(); + } + } +} + +void LLCubeMap::enableTextureCoords(S32 stage) +{ + mTextureCoordStage = stage; + if (gGLManager.mHasCubeMap && stage >= 0 && LLCubeMap::sUseCubeMaps) + { + if (stage > 0) + { + gGL.getTexUnit(stage)->activate(); + } + + glEnable(GL_TEXTURE_GEN_R); + glEnable(GL_TEXTURE_GEN_S); + glEnable(GL_TEXTURE_GEN_T); + + glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP); + glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP); + glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP); + + if (stage > 0) + { + gGL.getTexUnit(0)->activate(); + } + } +} + +void LLCubeMap::disable(void) +{ + disableTexture(); + disableTextureCoords(); +} + +void LLCubeMap::disableTexture(void) +{ + if (gGLManager.mHasCubeMap && mTextureStage >= 0 && LLCubeMap::sUseCubeMaps) + { + if (mTextureStage > 0) + { + gGL.getTexUnit(mTextureStage)->activate(); + } + glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, 0); + glDisable(GL_TEXTURE_CUBE_MAP_ARB); + if (mTextureStage > 0) + { + gGL.getTexUnit(0)->activate(); + } + } +} + +void LLCubeMap::disableTextureCoords(void) +{ + if (gGLManager.mHasCubeMap && mTextureCoordStage >= 0 && LLCubeMap::sUseCubeMaps) + { + if (mTextureCoordStage > 0) + { + gGL.getTexUnit(mTextureCoordStage)->activate(); + } + glDisable(GL_TEXTURE_GEN_S); + glDisable(GL_TEXTURE_GEN_T); + glDisable(GL_TEXTURE_GEN_R); + if (mTextureCoordStage > 0) + { + gGL.getTexUnit(0)->activate(); + } + } +} + +void LLCubeMap::setMatrix(S32 stage) +{ + mMatrixStage = stage; + + if (stage > 0) + { + gGL.getTexUnit(stage)->activate(); + } + + LLVector3 x(LLVector3d(gGLModelView+0)); + LLVector3 y(LLVector3d(gGLModelView+4)); + LLVector3 z(LLVector3d(gGLModelView+8)); + + LLMatrix3 mat3; + mat3.setRows(x,y,z); + LLMatrix4 trans(mat3); + trans.transpose(); + + glMatrixMode(GL_TEXTURE); + glPushMatrix(); + glLoadMatrixf((F32 *)trans.mMatrix); + glMatrixMode(GL_MODELVIEW); + + if (stage > 0) + { + gGL.getTexUnit(0)->activate(); + } +} + +void LLCubeMap::restoreMatrix() +{ + if (mMatrixStage > 0) + { + gGL.getTexUnit(mMatrixStage)->activate(); + } + glMatrixMode(GL_TEXTURE); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + + if (mMatrixStage > 0) + { + gGL.getTexUnit(0)->activate(); + } +} + +void LLCubeMap::setReflection (void) +{ + glBindTexture (GL_TEXTURE_CUBE_MAP_ARB, getGLName()); + mImages[0]->setMipFilterNearest (FALSE, FALSE); + mImages[0]->setClampCubemap (TRUE, TRUE); +} + +LLVector3 LLCubeMap::map(U8 side, U16 v_val, U16 h_val) const +{ + LLVector3 dir; + + const U8 curr_coef = side >> 1; // 0/1 = X axis, 2/3 = Y, 4/5 = Z + const S8 side_dir = (((side & 1) << 1) - 1); // even = -1, odd = 1 + const U8 i_coef = (curr_coef + 1) % 3; + const U8 j_coef = (i_coef + 1) % 3; + + dir.mV[curr_coef] = side_dir; + + switch (side) + { + case 0: // negative X + dir.mV[i_coef] = -F32((v_val<<1) + 1) / RESOLUTION + 1; + dir.mV[j_coef] = F32((h_val<<1) + 1) / RESOLUTION - 1; + break; + case 1: // positive X + dir.mV[i_coef] = -F32((v_val<<1) + 1) / RESOLUTION + 1; + dir.mV[j_coef] = -F32((h_val<<1) + 1) / RESOLUTION + 1; + break; + case 2: // negative Y + dir.mV[i_coef] = -F32((v_val<<1) + 1) / RESOLUTION + 1; + dir.mV[j_coef] = F32((h_val<<1) + 1) / RESOLUTION - 1; + break; + case 3: // positive Y + dir.mV[i_coef] = F32((v_val<<1) + 1) / RESOLUTION - 1; + dir.mV[j_coef] = F32((h_val<<1) + 1) / RESOLUTION - 1; + break; + case 4: // negative Z + dir.mV[i_coef] = -F32((h_val<<1) + 1) / RESOLUTION + 1; + dir.mV[j_coef] = -F32((v_val<<1) + 1) / RESOLUTION + 1; + break; + case 5: // positive Z + dir.mV[i_coef] = -F32((h_val<<1) + 1) / RESOLUTION + 1; + dir.mV[j_coef] = F32((v_val<<1) + 1) / RESOLUTION - 1; + break; + default: + dir.mV[i_coef] = F32((v_val<<1) + 1) / RESOLUTION - 1; + dir.mV[j_coef] = F32((h_val<<1) + 1) / RESOLUTION - 1; + } + + dir.normVec(); + return dir; +} + + +BOOL LLCubeMap::project(F32& v_val, F32& h_val, BOOL& outside, + U8 side, const LLVector3& dir) const +{ + const U8 curr_coef = side >> 1; // 0/1 = X axis, 2/3 = Y, 4/5 = Z + const S8 side_dir = (((side & 1) << 1) - 1); // even = -1, odd = 1 + const U8 i_coef = (curr_coef + 1) % 3; + const U8 j_coef = (i_coef + 1) % 3; + + outside = TRUE; + if (side_dir * dir.mV[curr_coef] < 0) + return FALSE; + + LLVector3 ray; + + F32 norm_val = fabs(dir.mV[curr_coef]); + + if (norm_val < epsilon) + norm_val = 1e-5f; + + ray.mV[curr_coef] = side_dir; + ray.mV[i_coef] = dir.mV[i_coef] / norm_val; + ray.mV[j_coef] = dir.mV[j_coef] / norm_val; + + + const F32 i_val = (ray.mV[i_coef] + 1) * 0.5f * RESOLUTION; + const F32 j_val = (ray.mV[j_coef] + 1) * 0.5f * RESOLUTION; + + switch (side) + { + case 0: // negative X + v_val = RESOLUTION - i_val; + h_val = j_val; + break; + case 1: // positive X + v_val = RESOLUTION - i_val; + h_val = RESOLUTION - j_val; + break; + case 2: // negative Y + v_val = RESOLUTION - i_val; + h_val = j_val; + break; + case 3: // positive Y + v_val = i_val; + h_val = j_val; + break; + case 4: // negative Z + v_val = RESOLUTION - j_val; + h_val = RESOLUTION - i_val; + break; + case 5: // positive Z + v_val = RESOLUTION - j_val; + h_val = i_val; + break; + default: + v_val = i_val; + h_val = j_val; + } + + outside = ((v_val < 0) || (v_val > RESOLUTION) || + (h_val < 0) || (h_val > RESOLUTION)); + + return TRUE; +} + +BOOL LLCubeMap::project(F32& v_min, F32& v_max, F32& h_min, F32& h_max, + U8 side, LLVector3 dir[4]) const +{ + v_min = h_min = RESOLUTION; + v_max = h_max = 0; + + BOOL fully_outside = TRUE; + for (U8 vtx = 0; vtx < 4; ++vtx) + { + F32 v_val, h_val; + BOOL outside; + BOOL consider = project(v_val, h_val, outside, side, dir[vtx]); + if (!outside) + fully_outside = FALSE; + if (consider) + { + if (v_val < v_min) v_min = v_val; + if (v_val > v_max) v_max = v_val; + if (h_val < h_min) h_min = h_val; + if (h_val > h_max) h_max = h_val; + } + } + + v_min = llmax(0.0f, v_min); + v_max = llmin(RESOLUTION - epsilon, v_max); + h_min = llmax(0.0f, h_min); + h_max = llmin(RESOLUTION - epsilon, h_max); + + return !fully_outside; +} + + +void LLCubeMap::paintIn(LLVector3 dir[4], const LLColor4U& col) +{ + F32 v_min, v_max, h_min, h_max; + LLVector3 center = dir[0] + dir[1] + dir[2] + dir[3]; + center.normVec(); + + for (U8 side = 0; side < 6; ++side) + { + if (!project(v_min, v_max, h_min, h_max, side, dir)) + continue; + + U8 *td = mRawImages[side]->getData(); + + U16 v_minu = (U16) v_min; + U16 v_maxu = (U16) (ceil(v_max) + 0.5); + U16 h_minu = (U16) h_min; + U16 h_maxu = (U16) (ceil(h_max) + 0.5); + + for (U16 v = v_minu; v < v_maxu; ++v) + for (U16 h = h_minu; h < h_maxu; ++h) + //for (U16 v = 0; v < RESOLUTION; ++v) + // for (U16 h = 0; h < RESOLUTION; ++h) + { + const LLVector3 ray = map(side, v, h); + if (ray * center > 0.999) + { + const U32 offset = (RESOLUTION * v + h) * 4; + for (U8 cc = 0; cc < 3; ++cc) + td[offset + cc] = U8((td[offset + cc] + col.mV[cc]) * 0.5); + } + } + mImages[side]->setSubImage(mRawImages[side], 0, 0, 64, 64); + } +} + +void LLCubeMap::destroyGL() +{ + for (S32 i = 0; i < 6; i++) + { + mImages[i] = NULL; + } +} diff --git a/indra/llrender/llcubemap.h b/indra/llrender/llcubemap.h new file mode 100644 index 0000000000..c273ab40ec --- /dev/null +++ b/indra/llrender/llcubemap.h @@ -0,0 +1,89 @@ +/** + * @file llcubemap.h + * @brief LLCubeMap class definition + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2007, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLCUBEMAP_H +#define LL_LLCUBEMAP_H + +#include "llgl.h" + +#include <vector> + +class LLVector3; + +// Environment map hack! +class LLCubeMap : public LLRefCount +{ +public: + LLCubeMap(); + void init(const std::vector<LLPointer<LLImageRaw> >& rawimages); + void initGL(); + void initRawData(const std::vector<LLPointer<LLImageRaw> >& rawimages); + void initGLData(); + + void bind(); + void enable(S32 stage); + + void enableTexture(S32 stage); + void enableTextureCoords(S32 stage); + + void disable(void); + void disableTexture(void); + void disableTextureCoords(void); + void setMatrix(S32 stage); + void restoreMatrix(); + void setReflection (void); + + void finishPaint(); + + GLuint getGLName(); + + LLVector3 map(U8 side, U16 v_val, U16 h_val) const; + BOOL project(F32& v_val, F32& h_val, BOOL& outside, + U8 side, const LLVector3& dir) const; + BOOL project(F32& v_min, F32& v_max, F32& h_min, F32& h_max, + U8 side, LLVector3 dir[4]) const; + void paintIn(LLVector3 dir[4], const LLColor4U& col); + void destroyGL(); + +public: + static bool sUseCubeMaps; + +protected: + ~LLCubeMap(); + LLGLenum mTargets[6]; + LLPointer<LLImageGL> mImages[6]; + LLPointer<LLImageRaw> mRawImages[6]; + S32 mTextureStage; + S32 mTextureCoordStage; + S32 mMatrixStage; +}; + +#endif diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp new file mode 100644 index 0000000000..8c63122cb8 --- /dev/null +++ b/indra/llrender/llgl.cpp @@ -0,0 +1,1726 @@ +/** + * @file llgl.cpp + * @brief LLGL implementation + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2007, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/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 "llquaternion.h" +#include "llmath.h" +#include "m4math.h" +#include "llstring.h" + +#include "llglheaders.h" + +#ifdef _DEBUG +//#define GL_STATE_VERIFY +#endif + +BOOL gDebugGL = FALSE; +BOOL gClothRipple = FALSE; +BOOL gNoRender = FALSE; +LLMatrix4 gGLObliqueProjectionInverse; + +LLGLNamePool::pool_list_t LLGLNamePool::sInstances; + +#if (LL_WINDOWS || LL_LINUX) && !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; + +// GL_EXT_framebuffer_object +PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT = NULL; +PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT = NULL; +PFNGLDELETERENDERBUFFERSEXTPROC glDeleteRenderbuffersEXT = NULL; +PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffersEXT = NULL; +PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorageEXT = NULL; +PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glGetRenderbufferParameterivEXT = NULL; +PFNGLISFRAMEBUFFEREXTPROC glIsFramebufferEXT = NULL; +PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT = NULL; +PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT = NULL; +PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT = NULL; +PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT = NULL; +PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glFramebufferTexture1DEXT = NULL; +PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT = NULL; +PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glFramebufferTexture3DEXT = NULL; +PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT = NULL; +PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glGetFramebufferAttachmentParameterivEXT = NULL; +PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT = 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 +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 +PFNGLVERTEXATTRIB4NBVARBPROC glVertexAttrib4nbvARB = NULL; +PFNGLVERTEXATTRIB4NIVARBPROC glVertexAttrib4nivARB = NULL; +PFNGLVERTEXATTRIB4NSVARBPROC glVertexAttrib4nsvARB = NULL; +PFNGLVERTEXATTRIB4NUBARBPROC glVertexAttrib4nubARB = NULL; +PFNGLVERTEXATTRIB4NUBVARBPROC glVertexAttrib4nubvARB = NULL; +PFNGLVERTEXATTRIB4NUIVARBPROC glVertexAttrib4nuivARB = NULL; +PFNGLVERTEXATTRIB4NUSVARBPROC glVertexAttrib4nusvARB = NULL; +#if LL_LINUX +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 +PFNGLBINDATTRIBLOCATIONARBPROC glBindAttribLocationARB = NULL; +PFNGLGETACTIVEATTRIBARBPROC glGetActiveAttribARB = NULL; +PFNGLGETATTRIBLOCATIONARBPROC glGetAttribLocationARB = NULL; + +#if LL_WINDOWS +PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL; +#endif + +#if LL_LINUX +PFNGLCOLORTABLEEXTPROC glColorTableEXT = NULL; +#endif // LL_LINUX + +#endif + +LLGLManager gGLManager; + +LLGLManager::LLGLManager() : + mInited(FALSE), + mIsDisabled(FALSE), + + mHasMultitexture(FALSE), + mNumTextureUnits(1), + mHasMipMapGeneration(FALSE), + mHasPalettedTextures(FALSE), + mHasCompressedTextures(FALSE), + mHasFramebufferObject(FALSE), + + mHasVertexBufferObject(FALSE), + mHasPBuffer(FALSE), + mHasShaderObjects(FALSE), + mHasVertexShader(FALSE), + mHasFragmentShader(FALSE), + mHasOcclusionQuery(FALSE), + mHasPointParameters(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), + + 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 + } + 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 (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; + } + + + initGLStates(); + return true; +} + +void LLGLManager::getGLInfo(LLSD& info) +{ + 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; + std::string all_exts, line; + + 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 + all_exts = (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() +{ + std::string info_str; + std::string all_exts, line; + + 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 + all_exts = std::string(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; + 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. + +extern LLCPUInfo gSysCPU; + +void LLGLManager::initExtensions() +{ +#if LL_MESA_HEADLESS +# if GL_ARB_multitexture + mHasMultitexture = TRUE; +# else + mHasMultitexture = FALSE; +# endif +# if GL_ARB_texture_env_combine + mHasARBEnvCombine = TRUE; +# else + mHasARBEnvCombine = FALSE; +# endif +# if GL_ARB_texture_compression + mHasCompressedTextures = TRUE; +# else + mHasCompressedTextures = FALSE; +# endif +# if GL_ARB_vertex_buffer_object + mHasVertexBufferObject = TRUE; +# else + mHasVertexBufferObject = FALSE; +# endif +# if GL_EXT_framebuffer_object + mHasFramebufferObject = TRUE; +# else + mHasFramebufferObject = FALSE; +# endif + mHasMipMapGeneration = FALSE; + mHasPalettedTextures = FALSE; + mHasSeparateSpecularColor = FALSE; + mHasAnisotropic = FALSE; + mHasCubeMap = FALSE; + mHasOcclusionQuery = FALSE; + mHasPointParameters = FALSE; + mHasShaderObjects = FALSE; + mHasVertexShader = FALSE; + mHasFragmentShader = FALSE; +#else // LL_MESA_HEADLESS + mHasMultitexture = glh_init_extensions("GL_ARB_multitexture"); + mHasMipMapGeneration = glh_init_extensions("GL_SGIS_generate_mipmap"); + mHasPalettedTextures = glh_init_extension("GL_EXT_paletted_texture"); + 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); + mHasVertexBufferObject = ExtensionExists("GL_ARB_vertex_buffer_object", gGLHExts.mSysExts); + // mask out FBO support when packed_depth_stencil isn't there 'cause we need it for LLRenderTarget -Brad + mHasFramebufferObject = ExtensionExists("GL_EXT_framebuffer_object", gGLHExts.mSysExts) + && ExtensionExists("GL_EXT_packed_depth_stencil", gGLHExts.mSysExts); +#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 + // 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. + if (getenv("LL_GL_NOEXT")) /* Flawfinder: ignore */ + { + //mHasMultitexture = FALSE; // NEEDED! + mHasARBEnvCombine = FALSE; + mHasCompressedTextures = FALSE; + mHasVertexBufferObject = FALSE; + mHasFramebufferObject = FALSE; + mHasMipMapGeneration = FALSE; + mHasPalettedTextures = 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; + mHasPalettedTextures = 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,'e')) mHasPalettedTextures = 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 + } +#endif // LL_LINUX + +#if LL_DARWIN || LL_LINUX + // MBW -- 12/4/2003 -- Using paletted textures causes a bunch of avatar rendering problems on the Mac. + // Not sure if this is due to driver problems or incorrect use of the extension, but I'm disabling it for now. + // Tofu - 2006-10-03 -- Same problem on Linux. + mHasPalettedTextures = false; +#endif + + 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 (!mHasPalettedTextures) + { + LL_INFOS("RenderInit") << "Couldn't initialize GL_EXT_paletted_texture" << 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 (!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; + } + + // 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_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) + { + glIsRenderbufferEXT = (PFNGLISRENDERBUFFEREXTPROC) GLH_EXT_GET_PROC_ADDRESS("glIsRenderbufferEXT"); + glBindRenderbufferEXT = (PFNGLBINDRENDERBUFFEREXTPROC) GLH_EXT_GET_PROC_ADDRESS("glBindRenderbufferEXT"); + glDeleteRenderbuffersEXT = (PFNGLDELETERENDERBUFFERSEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteRenderbuffersEXT"); + glGenRenderbuffersEXT = (PFNGLGENRENDERBUFFERSEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glGenRenderbuffersEXT"); + glRenderbufferStorageEXT = (PFNGLRENDERBUFFERSTORAGEEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glRenderbufferStorageEXT"); + glGetRenderbufferParameterivEXT = (PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glGetRenderbufferParameterivEXT"); + glIsFramebufferEXT = (PFNGLISFRAMEBUFFEREXTPROC) GLH_EXT_GET_PROC_ADDRESS("glIsFramebufferEXT"); + glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC) GLH_EXT_GET_PROC_ADDRESS("glBindFramebufferEXT"); + glDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteFramebuffersEXT"); + glGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glGenFramebuffersEXT"); + glCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glCheckFramebufferStatusEXT"); + glFramebufferTexture1DEXT = (PFNGLFRAMEBUFFERTEXTURE1DEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferTexture1DEXT"); + glFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferTexture2DEXT"); + glFramebufferTexture3DEXT = (PFNGLFRAMEBUFFERTEXTURE3DEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferTexture3DEXT"); + glFramebufferRenderbufferEXT = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferRenderbufferEXT"); + glGetFramebufferAttachmentParameterivEXT = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glGetFramebufferAttachmentParameterivEXT"); + glGenerateMipmapEXT = (PFNGLGENERATEMIPMAPEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glGenerateMipmapEXT"); + } +#if !LL_LINUX + // This is expected to be a static symbol on Linux GL implementations + glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC)GLH_EXT_GET_PROC_ADDRESS("glDrawRangeElements"); + if (!glDrawRangeElements) + { + mGLMaxVertexRange = 0; + mGLMaxIndexRange = 0; + } +#endif // !LL_LINUX +#if LL_LINUX + // On Linux we need to get glColorTableEXT dynamically. + if (mHasPalettedTextures) + { + glColorTableEXT = (PFNGLCOLORTABLEEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glColorTableEXT"); + } +#endif // LL_LINUX + if (mHasOcclusionQuery) + { + 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) + { + 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"); + glUniform2fvARB = (PFNGLUNIFORM2FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform2fvARB"); + glUniform3fvARB = (PFNGLUNIFORM3FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform3fvARB"); + glUniform4fvARB = (PFNGLUNIFORM4FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform4fvARB"); + glUniform1ivARB = (PFNGLUNIFORM1IVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform1ivARB"); + glUniform2ivARB = (PFNGLUNIFORM2IVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform2ivARB"); + glUniform3ivARB = (PFNGLUNIFORM3IVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform3ivARB"); + glUniform4ivARB = (PFNGLUNIFORM4IVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform4ivARB"); + glUniformMatrix2fvARB = (PFNGLUNIFORMMATRIX2FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniformMatrix2fvARB"); + glUniformMatrix3fvARB = (PFNGLUNIFORMMATRIX3FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniformMatrix3fvARB"); + glUniformMatrix4fvARB = (PFNGLUNIFORMMATRIX4FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniformMatrix4fvARB"); + glGetObjectParameterfvARB = (PFNGLGETOBJECTPARAMETERFVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetObjectParameterfvARB"); + glGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetObjectParameterivARB"); + glGetInfoLogARB = (PFNGLGETINFOLOGARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetInfoLogARB"); + glGetAttachedObjectsARB = (PFNGLGETATTACHEDOBJECTSARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetAttachedObjectsARB"); + glGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetUniformLocationARB"); + glGetActiveUniformARB = (PFNGLGETACTIVEUNIFORMARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetActiveUniformARB"); + glGetUniformfvARB = (PFNGLGETUNIFORMFVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetUniformfvARB"); + glGetUniformivARB = (PFNGLGETUNIFORMIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetUniformivARB"); + glGetShaderSourceARB = (PFNGLGETSHADERSOURCEARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetShaderSourceARB"); + } + if (mHasVertexShader) + { + glGetAttribLocationARB = (PFNGLGETATTRIBLOCATIONARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetAttribLocationARB"); + glBindAttribLocationARB = (PFNGLBINDATTRIBLOCATIONARBPROC) GLH_EXT_GET_PROC_ADDRESS("glBindAttribLocationARB"); + glGetActiveAttribARB = (PFNGLGETACTIVEATTRIBARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetActiveAttribARB"); + glVertexAttrib1dARB = (PFNGLVERTEXATTRIB1DARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1dARB"); + glVertexAttrib1dvARB = (PFNGLVERTEXATTRIB1DVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1dvARB"); + glVertexAttrib1fARB = (PFNGLVERTEXATTRIB1FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1fARB"); + glVertexAttrib1fvARB = (PFNGLVERTEXATTRIB1FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1fvARB"); + glVertexAttrib1sARB = (PFNGLVERTEXATTRIB1SARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1sARB"); + glVertexAttrib1svARB = (PFNGLVERTEXATTRIB1SVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1svARB"); + glVertexAttrib2dARB = (PFNGLVERTEXATTRIB2DARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2dARB"); + glVertexAttrib2dvARB = (PFNGLVERTEXATTRIB2DVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2dvARB"); + glVertexAttrib2fARB = (PFNGLVERTEXATTRIB2FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2fARB"); + glVertexAttrib2fvARB = (PFNGLVERTEXATTRIB2FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2fvARB"); + glVertexAttrib2sARB = (PFNGLVERTEXATTRIB2SARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2sARB"); + glVertexAttrib2svARB = (PFNGLVERTEXATTRIB2SVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2svARB"); + glVertexAttrib3dARB = (PFNGLVERTEXATTRIB3DARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3dARB"); + glVertexAttrib3dvARB = (PFNGLVERTEXATTRIB3DVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3dvARB"); + glVertexAttrib3fARB = (PFNGLVERTEXATTRIB3FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3fARB"); + glVertexAttrib3fvARB = (PFNGLVERTEXATTRIB3FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3fvARB"); + glVertexAttrib3sARB = (PFNGLVERTEXATTRIB3SARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3sARB"); + glVertexAttrib3svARB = (PFNGLVERTEXATTRIB3SVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3svARB"); + glVertexAttrib4nbvARB = (PFNGLVERTEXATTRIB4NBVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nbvARB"); + glVertexAttrib4nivARB = (PFNGLVERTEXATTRIB4NIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nivARB"); + glVertexAttrib4nsvARB = (PFNGLVERTEXATTRIB4NSVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nsvARB"); + glVertexAttrib4nubARB = (PFNGLVERTEXATTRIB4NUBARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nubARB"); + glVertexAttrib4nubvARB = (PFNGLVERTEXATTRIB4NUBVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nubvARB"); + glVertexAttrib4nuivARB = (PFNGLVERTEXATTRIB4NUIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nuivARB"); + glVertexAttrib4nusvARB = (PFNGLVERTEXATTRIB4NUSVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nusvARB"); + glVertexAttrib4bvARB = (PFNGLVERTEXATTRIB4BVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4bvARB"); + glVertexAttrib4dARB = (PFNGLVERTEXATTRIB4DARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4dARB"); + glVertexAttrib4dvARB = (PFNGLVERTEXATTRIB4DVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4dvARB"); + glVertexAttrib4fARB = (PFNGLVERTEXATTRIB4FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4fARB"); + glVertexAttrib4fvARB = (PFNGLVERTEXATTRIB4FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4fvARB"); + glVertexAttrib4ivARB = (PFNGLVERTEXATTRIB4IVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4ivARB"); + glVertexAttrib4sARB = (PFNGLVERTEXATTRIB4SARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4sARB"); + glVertexAttrib4svARB = (PFNGLVERTEXATTRIB4SVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4svARB"); + glVertexAttrib4ubvARB = (PFNGLVERTEXATTRIB4UBVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4ubvARB"); + glVertexAttrib4uivARB = (PFNGLVERTEXATTRIB4UIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4uivARB"); + glVertexAttrib4usvARB = (PFNGLVERTEXATTRIB4USVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4usvARB"); + glVertexAttribPointerARB = (PFNGLVERTEXATTRIBPOINTERARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttribPointerARB"); + glEnableVertexAttribArrayARB = (PFNGLENABLEVERTEXATTRIBARRAYARBPROC) GLH_EXT_GET_PROC_ADDRESS("glEnableVertexAttribArrayARB"); + glDisableVertexAttribArrayARB = (PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDisableVertexAttribArrayARB"); + glProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramStringARB"); + glBindProgramARB = (PFNGLBINDPROGRAMARBPROC) GLH_EXT_GET_PROC_ADDRESS("glBindProgramARB"); + glDeleteProgramsARB = (PFNGLDELETEPROGRAMSARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteProgramsARB"); + glGenProgramsARB = (PFNGLGENPROGRAMSARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGenProgramsARB"); + glProgramEnvParameter4dARB = (PFNGLPROGRAMENVPARAMETER4DARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4dARB"); + glProgramEnvParameter4dvARB = (PFNGLPROGRAMENVPARAMETER4DVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4dvARB"); + glProgramEnvParameter4fARB = (PFNGLPROGRAMENVPARAMETER4FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4fARB"); + glProgramEnvParameter4fvARB = (PFNGLPROGRAMENVPARAMETER4FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4fvARB"); + glProgramLocalParameter4dARB = (PFNGLPROGRAMLOCALPARAMETER4DARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4dARB"); + glProgramLocalParameter4dvARB = (PFNGLPROGRAMLOCALPARAMETER4DVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4dvARB"); + glProgramLocalParameter4fARB = (PFNGLPROGRAMLOCALPARAMETER4FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4fARB"); + glProgramLocalParameter4fvARB = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4fvARB"); + glGetProgramEnvParameterdvARB = (PFNGLGETPROGRAMENVPARAMETERDVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetProgramEnvParameterdvARB"); + glGetProgramEnvParameterfvARB = (PFNGLGETPROGRAMENVPARAMETERFVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetProgramEnvParameterfvARB"); + glGetProgramLocalParameterdvARB = (PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetProgramLocalParameterdvARB"); + glGetProgramLocalParameterfvARB = (PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetProgramLocalParameterfvARB"); + glGetProgramivARB = (PFNGLGETPROGRAMIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetProgramivARB"); + glGetProgramStringARB = (PFNGLGETPROGRAMSTRINGARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetProgramStringARB"); + glGetVertexAttribdvARB = (PFNGLGETVERTEXATTRIBDVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribdvARB"); + glGetVertexAttribfvARB = (PFNGLGETVERTEXATTRIBFVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribfvARB"); + glGetVertexAttribivARB = (PFNGLGETVERTEXATTRIBIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribivARB"); + glGetVertexAttribPointervARB = (PFNGLGETVERTEXATTRIBPOINTERVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glgetVertexAttribPointervARB"); + glIsProgramARB = (PFNGLISPROGRAMARBPROC) GLH_EXT_GET_PROC_ADDRESS("glIsProgramARB"); + } + LL_DEBUGS("RenderInit") << "GL Probe: Got symbols" << LL_ENDL; +#endif + + mInited = TRUE; +} + +void rotate_quat(LLQuaternion& rotation) +{ + F32 angle_radians, x, y, z; + rotation.getAngleAxis(&angle_radians, &x, &y, &z); + glRotatef(angle_radians * RAD_TO_DEG, x, y, z); +} + +void flush_glerror() +{ + glGetError(); +} + +void assert_glerror() +{ + if (gNoRender || !gDebugGL) + { + return; + } + if (!gGLManager.mInited) + { + LL_ERRS("RenderInit") << "GL not initialized" << LL_ENDL; + } + // Create or update texture to be used with this data + GLenum error; + error = glGetError(); + BOOL quit = FALSE; + while (error) + { + quit = TRUE; +#ifndef LL_LINUX // *FIX: ! This should be an error for linux as well. + GLubyte const * gl_error_msg = gluErrorString(error); + if (NULL != gl_error_msg) + { + LL_WARNS("RenderState") << "GL Error:" << gl_error_msg << LL_ENDL; + } + else + { + // gluErrorString returns NULL for some extensions' error codes. + // you'll probably have to grep for the number in glext.h. + LL_WARNS("RenderState") << "GL Error: UNKNOWN 0x" << std::hex << error << LL_ENDL; + } + error = glGetError(); +#endif + } + + if (quit) + { + llerrs << "One or more unhandled GL errors." << llendl; + } +} + +void clear_glerror() +{ + // Create or update texture to be used with this data + GLenum error; + error = glGetError(); +} + +/////////////////////////////////////////////////////////////// +// +// LLGLState +// + +// Static members +std::map<LLGLenum, LLGLboolean> LLGLState::sStateMap; + +GLboolean LLGLDepthTest::sDepthEnabled = GL_FALSE; // OpenGL default +GLenum LLGLDepthTest::sDepthFunc = GL_LESS; // OpenGL default +GLboolean LLGLDepthTest::sWriteEnabled = GL_TRUE; // OpenGL default + +//static +void LLGLState::initClass() +{ + sStateMap[GL_DITHER] = GL_TRUE; + sStateMap[GL_TEXTURE_2D] = GL_TRUE; +} + +//static +void LLGLState::restoreGL() +{ + sStateMap.clear(); + initClass(); +} + +//static +// Really shouldn't be needed, but seems we sometimes do. +void LLGLState::resetTextureStates() +{ + gGL.flush(); + GLint maxTextureUnits; + + glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &maxTextureUnits); + for (S32 j = maxTextureUnits-1; j >=0; j--) + { + gGL.getTexUnit(j)->activate(); + glClientActiveTextureARB(GL_TEXTURE0_ARB+j); + j == 0 ? glEnable(GL_TEXTURE_2D) : glDisable(GL_TEXTURE_2D); + } +} + +void LLGLState::dumpStates() +{ + LL_INFOS("RenderState") << "GL States:" << LL_ENDL; + for (std::map<LLGLenum, LLGLboolean>::iterator iter = sStateMap.begin(); + iter != sStateMap.end(); ++iter) + { + LL_INFOS("RenderState") << llformat(" 0x%04x : %s",(S32)iter->first,iter->second?"TRUE":"FALSE") << LL_ENDL; + } +} + +void LLGLState::checkStates() +{ + if (!gDebugGL) + { + return; + } + + stop_glerror(); + + GLint activeTexture; + glGetIntegerv(GL_ACTIVE_TEXTURE_ARB, &activeTexture); + + if (activeTexture != GL_TEXTURE0_ARB) + { + LL_GL_ERRS << "Texture channel corrupted. " << LL_ENDL; + } + + GLint src; + GLint dst; + glGetIntegerv(GL_BLEND_SRC, &src); + glGetIntegerv(GL_BLEND_DST, &dst); + + if (src != GL_SRC_ALPHA || dst != GL_ONE_MINUS_SRC_ALPHA) + { + LL_GL_ERRS << "Blend function corrupted: " << std::hex << src << " " << std::hex << dst << LL_ENDL; + } + + for (std::map<LLGLenum, LLGLboolean>::iterator iter = sStateMap.begin(); + iter != sStateMap.end(); ++iter) + { + LLGLenum state = iter->first; + LLGLboolean cur_state = iter->second; + LLGLboolean gl_state = glIsEnabled(state); + if(cur_state != gl_state) + { + dumpStates(); + LL_GL_ERRS << llformat("LLGLState error. State: 0x%04x",state) << LL_ENDL; + } + } + + stop_glerror(); +} + +void LLGLState::checkTextureChannels() +{ + if (!gDebugGL) + { + return; + } + + GLint activeTexture; + glGetIntegerv(GL_ACTIVE_TEXTURE_ARB, &activeTexture); + + BOOL error = FALSE; + + if (activeTexture != GL_TEXTURE0_ARB) + { + error = TRUE; + LL_WARNS("RenderState") << "Active texture channel corrupted. " << LL_ENDL; + } + else if (!glIsEnabled(GL_TEXTURE_2D)) + { + error = TRUE; + LL_WARNS("RenderState") << "GL_TEXTURE_2D not enabled on texture channel 0." << LL_ENDL; + } + else + { + GLint tex_env_mode = 0; + + glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &tex_env_mode); + if (tex_env_mode != GL_MODULATE) + { + error = TRUE; + LL_WARNS("RenderState") << "GL_TEXTURE_ENV_MODE invalid: " << std::hex << tex_env_mode << LL_ENDL; + } + } + + GLint maxTextureUnits; + glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &maxTextureUnits); + + static const char* label[] = + { + "GL_TEXTURE_2D", + "GL_TEXTURE_COORD_ARRAY", + "GL_TEXTURE_1D", + "GL_TEXTURE_CUBE_MAP_ARB", + "GL_TEXTURE_GEN_S", + "GL_TEXTURE_GEN_T", + "GL_TEXTURE_GEN_Q", + "GL_TEXTURE_GEN_R" + }; + + static GLint value[] = + { + GL_TEXTURE_2D, + GL_TEXTURE_COORD_ARRAY, + GL_TEXTURE_1D, + GL_TEXTURE_CUBE_MAP_ARB, + GL_TEXTURE_GEN_S, + GL_TEXTURE_GEN_T, + GL_TEXTURE_GEN_Q, + GL_TEXTURE_GEN_R + }; + + GLint stackDepth = 0; + LLMatrix4 identity; + LLMatrix4 matrix; + + for (GLint i = 0; i < maxTextureUnits; i++) + { + gGL.getTexUnit(i)->activate(); + glClientActiveTextureARB(GL_TEXTURE0_ARB+i); + + glGetIntegerv(GL_TEXTURE_STACK_DEPTH, &stackDepth); + + if (stackDepth != 1) + { + error = TRUE; + LL_WARNS("RenderState") << "Texture matrix stack corrupted." << LL_ENDL; + } + + glGetFloatv(GL_TEXTURE_MATRIX, (GLfloat*) matrix.mMatrix); + + if (matrix != identity) + { + error = TRUE; + LL_WARNS("RenderState") << "Texture matrix in channel " << i << " corrupt." << LL_ENDL; + } + + for (S32 j = (i == 0 ? 1 : 0); j < 8; j++) + { + if (glIsEnabled(value[j])) + { + error = TRUE; + LL_WARNS("RenderState") << "Texture channel " << i << " still has " << label[j] << " enabled." << LL_ENDL; + } + } + } + + gGL.getTexUnit(0)->activate(); + glClientActiveTextureARB(GL_TEXTURE0_ARB); + + if (error) + { + LL_GL_ERRS << "GL texture state corruption detected." << LL_ENDL; + } +} + +void LLGLState::checkClientArrays(U32 data_mask) +{ + if (!gDebugGL) + { + return; + } + + stop_glerror(); + BOOL error = FALSE; + + GLint active_texture; + glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE_ARB, &active_texture); + + if (active_texture != GL_TEXTURE0_ARB) + { + llwarns << "Client active texture corrupted: " << active_texture << llendl; + error = TRUE; + } + + glGetIntegerv(GL_ACTIVE_TEXTURE_ARB, &active_texture); + if (active_texture != GL_TEXTURE0_ARB) + { + llwarns << "Active texture corrupted: " << active_texture << llendl; + error = TRUE; + } + + static const char* label[] = + { + "GL_VERTEX_ARRAY", + "GL_NORMAL_ARRAY", + "GL_COLOR_ARRAY", + "GL_TEXTURE_COORD_ARRAY" + }; + + static GLint value[] = + { + GL_VERTEX_ARRAY, + GL_NORMAL_ARRAY, + GL_COLOR_ARRAY, + GL_TEXTURE_COORD_ARRAY + }; + + U32 mask[] = + { //copied from llvertexbuffer.h + 0x0001, //MAP_VERTEX, + 0x0002, //MAP_NORMAL, + 0x0010, //MAP_COLOR, + 0x0004, //MAP_TEXCOORD + }; + + + for (S32 j = 0; j < 4; j++) + { + if (glIsEnabled(value[j])) + { + if (!(mask[j] & data_mask)) + { + error = TRUE; + LL_WARNS("RenderState") << "GL still has " << label[j] << " enabled." << LL_ENDL; + } + } + else + { + if (mask[j] & data_mask) + { + error = TRUE; + LL_WARNS("RenderState") << "GL does not have " << label[j] << " enabled." << LL_ENDL; + } + } + } + + glClientActiveTextureARB(GL_TEXTURE1_ARB); + gGL.getTexUnit(1)->activate(); + if (glIsEnabled(GL_TEXTURE_COORD_ARRAY)) + { + if (!(data_mask & 0x0008)) + { + error = TRUE; + LL_WARNS("RenderState") << "GL still has GL_TEXTURE_COORD_ARRAY enabled on channel 1." << LL_ENDL; + } + } + else + { + if (data_mask & 0x0008) + { + error = TRUE; + LL_WARNS("RenderState") << "GL does not have GL_TEXTURE_COORD_ARRAY enabled on channel 1." << LL_ENDL; + } + } + + if (glIsEnabled(GL_TEXTURE_2D)) + { + if (!(data_mask & 0x0008)) + { + error = TRUE; + LL_WARNS("RenderState") << "GL still has GL_TEXTURE_2D enabled on channel 1." << LL_ENDL; + } + } + else + { + if (data_mask & 0x0008) + { + error = TRUE; + LL_WARNS("RenderState") << "GL does not have GL_TEXTURE_2D enabled on channel 1." << LL_ENDL; + } + } + + glClientActiveTextureARB(GL_TEXTURE0_ARB); + gGL.getTexUnit(0)->activate(); + + if (error) + { + LL_GL_ERRS << "GL client array corruption detected." << LL_ENDL; + } +} + +/////////////////////////////////////////////////////////////////////// + +LLGLState::LLGLState(LLGLenum state, S32 enabled) : + mState(state), mWasEnabled(FALSE), mIsEnabled(FALSE) +{ + stop_glerror(); + if (state) + { + mWasEnabled = sStateMap[state]; + llassert(mWasEnabled == glIsEnabled(state)); + setEnabled(enabled); + stop_glerror(); + } +} + +void LLGLState::setEnabled(S32 enabled) +{ + if (!mState) + { + return; + } + if (enabled == CURRENT_STATE) + { + enabled = sStateMap[mState] == GL_TRUE ? TRUE : FALSE; + } + else if (enabled == TRUE && sStateMap[mState] != GL_TRUE) + { + gGL.flush(); + glEnable(mState); + sStateMap[mState] = GL_TRUE; + } + else if (enabled == FALSE && sStateMap[mState] != GL_FALSE) + { + gGL.flush(); + glDisable(mState); + sStateMap[mState] = GL_FALSE; + } + mIsEnabled = enabled; +} + +LLGLState::~LLGLState() +{ + stop_glerror(); + if (mState) + { + if (gDebugGL) + { + llassert_always(sStateMap[mState] == glIsEnabled(mState)); + } + + if (mIsEnabled != mWasEnabled) + { + gGL.flush(); + if (mWasEnabled) + { + glEnable(mState); + sStateMap[mState] = GL_TRUE; + } + else + { + glDisable(mState); + sStateMap[mState] = GL_FALSE; + } + } + } + stop_glerror(); +} + +//////////////////////////////////////////////////////////////////////////////// + +void LLGLManager::initGLStates() +{ + //gl states moved to classes in llglstates.h + LLGLState::initClass(); +} + +//////////////////////////////////////////////////////////////////////////////// + +void enable_vertex_weighting(const S32 index) +{ +#if GL_ARB_vertex_program + if (index > 0) glEnableVertexAttribArrayARB(index); // vertex weights +#endif +} + +void disable_vertex_weighting(const S32 index) +{ +#if GL_ARB_vertex_program + if (index > 0) glDisableVertexAttribArrayARB(index); // vertex weights +#endif +} + +void enable_binormals(const S32 index) +{ +#if GL_ARB_vertex_program + if (index > 0) + { + glEnableVertexAttribArrayARB(index); // binormals + } +#endif +} + +void disable_binormals(const S32 index) +{ +#if GL_ARB_vertex_program + if (index > 0) + { + glDisableVertexAttribArrayARB(index); // binormals + } +#endif +} + + +void enable_cloth_weights(const S32 index) +{ +#if GL_ARB_vertex_program + if (index > 0) glEnableVertexAttribArrayARB(index); +#endif +} + +void disable_cloth_weights(const S32 index) +{ +#if GL_ARB_vertex_program + if (index > 0) glDisableVertexAttribArrayARB(index); +#endif +} + +void set_vertex_weights(const S32 index, const U32 stride, const F32 *weights) +{ +#if GL_ARB_vertex_program + if (index > 0) glVertexAttribPointerARB(index, 1, GL_FLOAT, FALSE, stride, weights); + stop_glerror(); +#endif +} + +void set_vertex_clothing_weights(const S32 index, const U32 stride, const LLVector4 *weights) +{ +#if GL_ARB_vertex_program + if (index > 0) glVertexAttribPointerARB(index, 4, GL_FLOAT, TRUE, stride, weights); + stop_glerror(); +#endif +} + +void set_binormals(const S32 index, const U32 stride,const LLVector3 *binormals) +{ +#if GL_ARB_vertex_program + if (index > 0) glVertexAttribPointerARB(index, 3, GL_FLOAT, FALSE, stride, binormals); + stop_glerror(); +#endif +} + + +void set_palette(U8 *palette_data) +{ + if (gGLManager.mHasPalettedTextures) + { + glColorTableEXT(GL_TEXTURE_2D, GL_RGBA8, 256, GL_RGBA, GL_UNSIGNED_BYTE, palette_data); + } +} + + +void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor_specific ) +{ + // GL_VERSION returns a null-terminated string with the format: + // <major>.<minor>[.<release>] [<vendor specific>] + + const char* version = (const char*) glGetString(GL_VERSION); + *major = 0; + *minor = 0; + *release = 0; + vendor_specific->assign(""); + + 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); + + // Find the release number (optional) + if( '.' == version[i] ) + { + i++; + + start = i; + for( ; i < len; i++ ) + { + if( isspace(version[i]) ) + { + break; + } + } + + std::string release_str = ver_copy.substr(start,i-start); + LLStringUtil::convertToS32(release_str, *release); + } + + // Skip over any white space + while( version[i] && isspace( version[i] ) ) + { + i++; + } + + // Copy the vendor-specific string (optional) + if( version[i] ) + { + vendor_specific->assign( version + i ); + } +} + +LLGLUserClipPlane::LLGLUserClipPlane(const LLPlane& p, const glh::matrix4f& modelview, const glh::matrix4f& projection) +{ + mModelview = modelview; + mProjection = projection; + + setPlane(p.mV[0], p.mV[1], p.mV[2], p.mV[3]); +} + +void LLGLUserClipPlane::setPlane(F32 a, F32 b, F32 c, F32 d) +{ + glh::matrix4f& P = mProjection; + glh::matrix4f& M = mModelview; + + glh::matrix4f invtrans_MVP = (P * M).inverse().transpose(); + glh::vec4f oplane(a,b,c,d); + glh::vec4f cplane; + invtrans_MVP.mult_matrix_vec(oplane, cplane); + + cplane /= fabs(cplane[2]); // normalize such that depth is not scaled + cplane[3] -= 1; + + if(cplane[2] < 0) + cplane *= -1; + + glh::matrix4f suffix; + suffix.set_row(2, cplane); + glh::matrix4f newP = suffix * P; + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadMatrixf(newP.m); + gGLObliqueProjectionInverse = LLMatrix4(newP.inverse().transpose().m); + glMatrixMode(GL_MODELVIEW); +} + +LLGLUserClipPlane::~LLGLUserClipPlane() +{ + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); +} + +LLGLNamePool::LLGLNamePool() +{ +} + +void LLGLNamePool::registerPool(LLGLNamePool* pool) +{ + pool_list_t::iterator iter = std::find(sInstances.begin(), sInstances.end(), pool); + if (iter == sInstances.end()) + { + sInstances.push_back(pool); + } +} + +LLGLNamePool::~LLGLNamePool() +{ + pool_list_t::iterator iter = std::find(sInstances.begin(), sInstances.end(), this); + if (iter != sInstances.end()) + { + sInstances.erase(iter); + } +} + +void LLGLNamePool::upkeep() +{ + std::sort(mNameList.begin(), mNameList.end(), CompareUsed()); +} + +void LLGLNamePool::cleanup() +{ + for (name_list_t::iterator iter = mNameList.begin(); iter != mNameList.end(); ++iter) + { + releaseName(iter->name); + } + + mNameList.clear(); +} + +GLuint LLGLNamePool::allocate() +{ + for (name_list_t::iterator iter = mNameList.begin(); iter != mNameList.end(); ++iter) + { + if (!iter->used) + { + iter->used = TRUE; + return iter->name; + } + } + + NameEntry entry; + entry.name = allocateName(); + entry.used = TRUE; + mNameList.push_back(entry); + + return entry.name; +} + +void LLGLNamePool::release(GLuint name) +{ + for (name_list_t::iterator iter = mNameList.begin(); iter != mNameList.end(); ++iter) + { + if (iter->name == name) + { + iter->used = FALSE; + return; + } + } +} + +//static +void LLGLNamePool::upkeepPools() +{ + for (pool_list_t::iterator iter = sInstances.begin(); iter != sInstances.end(); ++iter) + { + LLGLNamePool* pool = *iter; + pool->upkeep(); + } +} + +//static +void LLGLNamePool::cleanupPools() +{ + for (pool_list_t::iterator iter = sInstances.begin(); iter != sInstances.end(); ++iter) + { + LLGLNamePool* pool = *iter; + pool->cleanup(); + } +} + +LLGLDepthTest::LLGLDepthTest(GLboolean depth_enabled, GLboolean write_enabled, GLenum depth_func) +: mPrevDepthEnabled(sDepthEnabled), mPrevDepthFunc(sDepthFunc), mPrevWriteEnabled(sWriteEnabled) +{ + if (depth_enabled != sDepthEnabled) + { + gGL.flush(); + if (depth_enabled) glEnable(GL_DEPTH_TEST); + else glDisable(GL_DEPTH_TEST); + sDepthEnabled = depth_enabled; + } + if (depth_func != sDepthFunc) + { + gGL.flush(); + glDepthFunc(depth_func); + sDepthFunc = depth_func; + } + if (write_enabled != sWriteEnabled) + { + gGL.flush(); + glDepthMask(write_enabled); + sWriteEnabled = write_enabled; + } +} + +LLGLDepthTest::~LLGLDepthTest() +{ + if (sDepthEnabled != mPrevDepthEnabled ) + { + gGL.flush(); + if (mPrevDepthEnabled) glEnable(GL_DEPTH_TEST); + else glDisable(GL_DEPTH_TEST); + sDepthEnabled = mPrevDepthEnabled; + } + if (sDepthFunc != mPrevDepthFunc) + { + gGL.flush(); + glDepthFunc(mPrevDepthFunc); + sDepthFunc = mPrevDepthFunc; + } + if (sWriteEnabled != mPrevWriteEnabled ) + { + gGL.flush(); + glDepthMask(mPrevWriteEnabled); + sWriteEnabled = mPrevWriteEnabled; + } +} + +LLGLClampToFarClip::LLGLClampToFarClip(glh::matrix4f P) +{ + for (U32 i = 0; i < 4; i++) + { + P.element(2, i) = P.element(3, i) * 0.99999f; + } + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadMatrixf(P.m); + glMatrixMode(GL_MODELVIEW); +} + +LLGLClampToFarClip::~LLGLClampToFarClip() +{ + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); +} + diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h new file mode 100644 index 0000000000..e9b4c7929e --- /dev/null +++ b/indra/llrender/llgl.h @@ -0,0 +1,377 @@ +/** + * @file llgl.h + * @brief LLGL definition + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2007, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLGL_H +#define LL_LLGL_H + +// This file contains various stuff for handling gl extensions and other gl related stuff. + +#include <string> +#include <map> + +#include "llerror.h" +#include "v4color.h" +#include "llstring.h" +#include "stdtypes.h" +#include "v4math.h" +#include "llplane.h" +#include "llgltypes.h" + +#include "llglheaders.h" +#include "glh/glh_linear.h" + +extern BOOL gDebugGL; + +#define LL_GL_ERRS LL_ERRS("RenderState") + +class LLSD; + +// Manage GL extensions... +class LLGLManager +{ +public: + LLGLManager(); + + bool initGL(); + void shutdownGL(); + + void initWGL(); // Initializes stupid WGL extensions + + std::string getRawGLString(); // For sending to simulator + + BOOL mInited; + BOOL mIsDisabled; + + // Extensions used by everyone + BOOL mHasMultitexture; + S32 mNumTextureUnits; + BOOL mHasMipMapGeneration; + BOOL mHasPalettedTextures; + BOOL mHasCompressedTextures; + BOOL mHasFramebufferObject; + + // ARB Extensions + BOOL mHasVertexBufferObject; + BOOL mHasPBuffer; + BOOL mHasShaderObjects; + BOOL mHasVertexShader; + BOOL mHasFragmentShader; + BOOL mHasOcclusionQuery; + BOOL mHasPointParameters; + + // Other extensions. + BOOL mHasAnisotropic; + BOOL mHasARBEnvCombine; + BOOL mHasCubeMap; + + // Vendor-specific extensions + BOOL mIsATI; + BOOL mIsNVIDIA; + BOOL mIsIntel; + BOOL mIsGF2or4MX; + BOOL mIsGF3; + BOOL mIsGFFX; + BOOL mATIOffsetVerticalLines; + + // Whether this version of GL is good enough for SL to use + BOOL mHasRequirements; + + // Misc extensions + BOOL mHasSeparateSpecularColor; + + S32 mDriverVersionMajor; + S32 mDriverVersionMinor; + S32 mDriverVersionRelease; + F32 mGLVersion; // e.g = 1.4 + std::string mDriverVersionVendorString; + + S32 mVRAM; // VRAM in MB + S32 mGLMaxVertexRange; + S32 mGLMaxIndexRange; + + void getPixelFormat(); // Get the best pixel format + + std::string getGLInfoString(); + void printGLInfoString(); + void getGLInfo(LLSD& info); + + // In ALL CAPS + std::string mGLVendor; + std::string mGLVendorShort; + + // In ALL CAPS + std::string mGLRenderer; + +private: + void initExtensions(); + void initGLStates(); + void initGLImages(); +}; + +extern LLGLManager gGLManager; + +class LLQuaternion; +class LLMatrix4; + +void rotate_quat(LLQuaternion& rotation); + +void flush_glerror(); // Flush GL errors when we know we're handling them correctly. + +void assert_glerror(); + +void clear_glerror(); + +//#if LL_DEBUG +# define stop_glerror() assert_glerror() +# define llglassertok() assert_glerror() +//#else +//# define stop_glerror() +//# define llglassertok() +//#endif + +#define llglassertok_always() assert_glerror() + +//////////////////////// +// +// Note: U32's are GLEnum's... +// + +// This is a class for GL state management + +/* + GL STATE MANAGEMENT DESCRIPTION + + LLGLState and its two subclasses, LLGLEnable and LLGLDisable, manage the current + enable/disable states of the GL to prevent redundant setting of state within a + render path or the accidental corruption of what state the next path expects. + + Essentially, wherever you would call glEnable set a state and then + subsequently reset it by calling glDisable (or vice versa), make an instance of + LLGLEnable with the state you want to set, and assume it will be restored to its + original state when that instance of LLGLEnable is destroyed. It is good practice + to exploit stack frame controls for optimal setting/unsetting and readability of + code. In llglstates.h, there are a collection of helper classes that define groups + of enables/disables that can cause multiple states to be set with the creation of + one instance. + + Sample usage: + + //disable lighting for rendering hud objects + //INCORRECT USAGE + LLGLEnable lighting(GL_LIGHTING); + renderHUD(); + LLGLDisable lighting(GL_LIGHTING); + + //CORRECT USAGE + { + LLGLEnable lighting(GL_LIGHTING); + renderHUD(); + } + + If a state is to be set on a conditional, the following mechanism + is useful: + + { + LLGLEnable lighting(light_hud ? GL_LIGHTING : 0); + renderHUD(); + } + + A LLGLState initialized with a parameter of 0 does nothing. + + LLGLState works by maintaining a map of the current GL states, and ignoring redundant + enables/disables. If a redundant call is attempted, it becomes a noop, otherwise, + it is set in the constructor and reset in the destructor. + + For debugging GL state corruption, running with debug enabled will trigger asserts + if the existing GL state does not match the expected GL state. + +*/ +class LLGLState +{ +public: + static void initClass(); + static void restoreGL(); + + static void resetTextureStates(); + static void dumpStates(); + static void checkStates(); + static void checkTextureChannels(); + static void checkClientArrays(U32 data_mask = 0x0001); + +protected: + static std::map<LLGLenum, LLGLboolean> sStateMap; + +public: + enum { CURRENT_STATE = -2 }; + LLGLState(LLGLenum state, S32 enabled = CURRENT_STATE); + ~LLGLState(); + void setEnabled(S32 enabled); + void enable() { setEnabled(TRUE); } + void disable() { setEnabled(FALSE); } +protected: + LLGLenum mState; + BOOL mWasEnabled; + BOOL mIsEnabled; +}; + +// New LLGLState class wrappers that don't depend on actual GL flags. +class LLGLEnableBlending : public LLGLState +{ +public: + LLGLEnableBlending(bool enable); +}; + +class LLGLEnableAlphaReject : public LLGLState +{ +public: + LLGLEnableAlphaReject(bool enable); +}; + +/// TODO: Being deprecated. +class LLGLEnable : public LLGLState +{ +public: + LLGLEnable(LLGLenum state) : LLGLState(state, TRUE) {} +}; + +/// TODO: Being deprecated. +class LLGLDisable : public LLGLState +{ +public: + LLGLDisable(LLGLenum state) : LLGLState(state, FALSE) {} +}; + +/* + Store and modify projection matrix to create an oblique + projection that clips to the specified plane. Oblique + projections alter values in the depth buffer, so this + class should not be used mid-renderpass. + + Restores projection matrix on destruction. + GL_MODELVIEW_MATRIX is active whenever program execution + leaves this class. + Does not stack. + Caches inverse of projection matrix used in gGLObliqueProjectionInverse +*/ +class LLGLUserClipPlane +{ +public: + + LLGLUserClipPlane(const LLPlane& plane, const glh::matrix4f& modelview, const glh::matrix4f& projection); + ~LLGLUserClipPlane(); + + void setPlane(F32 a, F32 b, F32 c, F32 d); + +private: + glh::matrix4f mProjection; + glh::matrix4f mModelview; +}; + +/* + Modify and load projection matrix to push depth values to far clip plane. + + Restores projection matrix on destruction. + GL_MODELVIEW_MATRIX is active whenever program execution + leaves this class. + Does not stack. +*/ +class LLGLClampToFarClip +{ +public: + LLGLClampToFarClip(glh::matrix4f projection); + ~LLGLClampToFarClip(); +}; + +/* + Generic pooling scheme for things which use GL names (used for occlusion queries and vertex buffer objects). + Prevents thrashing of GL name caches by avoiding calls to glGenFoo and glDeleteFoo. +*/ +class LLGLNamePool +{ +public: + typedef struct + { + GLuint name; + BOOL used; + } NameEntry; + + struct CompareUsed + { + bool operator()(const NameEntry& lhs, const NameEntry& rhs) + { + return lhs.used < rhs.used; //FALSE entries first + } + }; + + typedef std::vector<NameEntry> name_list_t; + name_list_t mNameList; + + LLGLNamePool(); + virtual ~LLGLNamePool(); + + void upkeep(); + void cleanup(); + + GLuint allocate(); + void release(GLuint name); + + static void registerPool(LLGLNamePool* pool); + static void upkeepPools(); + static void cleanupPools(); + +protected: + typedef std::vector<LLGLNamePool*> pool_list_t; + static pool_list_t sInstances; + + virtual GLuint allocateName() = 0; + virtual void releaseName(GLuint name) = 0; +}; + +extern LLMatrix4 gGLObliqueProjectionInverse; + +#include "llglstates.h" + +void init_glstates(); +void enable_vertex_weighting(const S32 index); +void disable_vertex_weighting(const S32 index); +void enable_binormals(const S32 index); +void disable_binormals(const S32 index); +void enable_cloth_weights(const S32 index); +void disable_cloth_weights(const S32 index); +void set_vertex_weights(const S32 index, const U32 stride, const F32 *weights); +void set_vertex_clothing_weights(const S32 index, const U32 stride, const LLVector4 *weights); +void set_binormals(const S32 index, const U32 stride, const LLVector3 *binormals); +void set_palette(U8* palette_data); +void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor_specific ); + +extern BOOL gClothRipple; +extern BOOL gNoRender; +#endif // LL_LLGL_H diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h new file mode 100644 index 0000000000..01578245ac --- /dev/null +++ b/indra/llrender/llglheaders.h @@ -0,0 +1,588 @@ +/** + * @file llglheaders.h + * @brief LLGL definitions + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2007, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLGLHEADERS_H +#define LL_LLGLHEADERS_H + +#if LL_MESA +//---------------------------------------------------------------------------- +// MESA headers +// quotes so we get libraries/.../GL/ version +#define GL_GLEXT_PROTOTYPES +#include "GL/gl.h" +#include "GL/glext.h" +#include "GL/glu.h" + +// The __APPLE__ kludge is to make glh_extensions.h not symbol-clash horribly +# define __APPLE__ +# include "GL/glh_extensions.h" +# undef __APPLE__ + +#elif LL_LINUX +//---------------------------------------------------------------------------- +// Linux, MESA headers, but not necessarily assuming MESA runtime. +// quotes so we get libraries/.../GL/ version +#include "GL/gl.h" +#include "GL/glext.h" +#include "GL/glu.h" + + +#if LL_LINUX && !LL_MESA_HEADLESS +// The __APPLE__ kludge is to make glh_extensions.h not symbol-clash horribly +# define __APPLE__ +# include "GL/glh_extensions.h" +# undef __APPLE__ + +/* Although SDL very likely ends up calling glXGetProcAddress() itself, + if we use SDL_GL_GetProcAddress() then we get bogus addresses back on + some systems. Weird. */ +/*# include "SDL/SDL.h" + # define GLH_EXT_GET_PROC_ADDRESS(p) SDL_GL_GetProcAddress(p) */ +#define GLX_GLXEXT_PROTOTYPES 1 +# include "GL/glx.h" +# include "GL/glxext.h" +// Use glXGetProcAddressARB instead of glXGetProcAddress - the ARB symbol +// is considered 'legacy' but works on more machines. +# define GLH_EXT_GET_PROC_ADDRESS(p) glXGetProcAddressARB((const GLubyte*)(p)) +// Whee, the X headers define 'Status'. Undefine to avoid confusion. +#undef Status +#endif // LL_LINUX && !LL_MESA_HEADLESS + + +// GL_ARB_vertex_buffer_object +extern PFNGLBINDBUFFERARBPROC glBindBufferARB; +extern PFNGLDELETEBUFFERSARBPROC glDeleteBuffersARB; +extern PFNGLGENBUFFERSARBPROC glGenBuffersARB; +extern PFNGLISBUFFERARBPROC glIsBufferARB; +extern PFNGLBUFFERDATAARBPROC glBufferDataARB; +extern PFNGLBUFFERSUBDATAARBPROC glBufferSubDataARB; +extern PFNGLGETBUFFERSUBDATAARBPROC glGetBufferSubDataARB; +extern PFNGLMAPBUFFERARBPROC glMapBufferARB; +extern PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB; +extern PFNGLGETBUFFERPARAMETERIVARBPROC glGetBufferParameterivARB; +extern PFNGLGETBUFFERPOINTERVARBPROC glGetBufferPointervARB; + +// GL_ATI_vertex_array_object +extern PFNGLNEWOBJECTBUFFERATIPROC glNewObjectBufferATI; +extern PFNGLISOBJECTBUFFERATIPROC glIsObjectBufferATI; +extern PFNGLUPDATEOBJECTBUFFERATIPROC glUpdateObjectBufferATI; +extern PFNGLGETOBJECTBUFFERFVATIPROC glGetObjectBufferfvATI; +extern PFNGLGETOBJECTBUFFERIVATIPROC glGetObjectBufferivATI; +extern PFNGLFREEOBJECTBUFFERATIPROC glFreeObjectBufferATI; +extern PFNGLARRAYOBJECTATIPROC glArrayObjectATI; +extern PFNGLVERTEXATTRIBARRAYOBJECTATIPROC glVertexAttribArrayObjectATI; +extern PFNGLGETARRAYOBJECTFVATIPROC glGetArrayObjectfvATI; +extern PFNGLGETARRAYOBJECTIVATIPROC glGetArrayObjectivATI; +extern PFNGLVARIANTARRAYOBJECTATIPROC glVariantObjectArrayATI; +extern PFNGLGETVARIANTARRAYOBJECTFVATIPROC glGetVariantArrayObjectfvATI; +extern PFNGLGETVARIANTARRAYOBJECTIVATIPROC glGetVariantArrayObjectivATI; + +// GL_ARB_occlusion_query +extern PFNGLGENQUERIESARBPROC glGenQueriesARB; +extern PFNGLDELETEQUERIESARBPROC glDeleteQueriesARB; +extern PFNGLISQUERYARBPROC glIsQueryARB; +extern PFNGLBEGINQUERYARBPROC glBeginQueryARB; +extern PFNGLENDQUERYARBPROC glEndQueryARB; +extern PFNGLGETQUERYIVARBPROC glGetQueryivARB; +extern PFNGLGETQUERYOBJECTIVARBPROC glGetQueryObjectivARB; +extern PFNGLGETQUERYOBJECTUIVARBPROC glGetQueryObjectuivARB; + +// GL_ARB_point_parameters +extern PFNGLPOINTPARAMETERFARBPROC glPointParameterfARB; +extern PFNGLPOINTPARAMETERFVARBPROC glPointParameterfvARB; + +// GL_ARB_shader_objects +extern PFNGLDELETEOBJECTARBPROC glDeleteObjectARB; +extern PFNGLGETHANDLEARBPROC glGetHandleARB; +extern PFNGLDETACHOBJECTARBPROC glDetachObjectARB; +extern PFNGLCREATESHADEROBJECTARBPROC glCreateShaderObjectARB; +extern PFNGLSHADERSOURCEARBPROC glShaderSourceARB; +extern PFNGLCOMPILESHADERARBPROC glCompileShaderARB; +extern PFNGLCREATEPROGRAMOBJECTARBPROC glCreateProgramObjectARB; +extern PFNGLATTACHOBJECTARBPROC glAttachObjectARB; +extern PFNGLLINKPROGRAMARBPROC glLinkProgramARB; +extern PFNGLUSEPROGRAMOBJECTARBPROC glUseProgramObjectARB; +extern PFNGLVALIDATEPROGRAMARBPROC glValidateProgramARB; +extern PFNGLUNIFORM1FARBPROC glUniform1fARB; +extern PFNGLUNIFORM2FARBPROC glUniform2fARB; +extern PFNGLUNIFORM3FARBPROC glUniform3fARB; +extern PFNGLUNIFORM4FARBPROC glUniform4fARB; +extern PFNGLUNIFORM1IARBPROC glUniform1iARB; +extern PFNGLUNIFORM2IARBPROC glUniform2iARB; +extern PFNGLUNIFORM3IARBPROC glUniform3iARB; +extern PFNGLUNIFORM4IARBPROC glUniform4iARB; +extern PFNGLUNIFORM1FVARBPROC glUniform1fvARB; +extern PFNGLUNIFORM2FVARBPROC glUniform2fvARB; +extern PFNGLUNIFORM3FVARBPROC glUniform3fvARB; +extern PFNGLUNIFORM4FVARBPROC glUniform4fvARB; +extern PFNGLUNIFORM1IVARBPROC glUniform1ivARB; +extern PFNGLUNIFORM2IVARBPROC glUniform2ivARB; +extern PFNGLUNIFORM3IVARBPROC glUniform3ivARB; +extern PFNGLUNIFORM4IVARBPROC glUniform4ivARB; +extern PFNGLUNIFORMMATRIX2FVARBPROC glUniformMatrix2fvARB; +extern PFNGLUNIFORMMATRIX3FVARBPROC glUniformMatrix3fvARB; +extern PFNGLUNIFORMMATRIX4FVARBPROC glUniformMatrix4fvARB; +extern PFNGLGETOBJECTPARAMETERFVARBPROC glGetObjectParameterfvARB; +extern PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameterivARB; +extern PFNGLGETINFOLOGARBPROC glGetInfoLogARB; +extern PFNGLGETATTACHEDOBJECTSARBPROC glGetAttachedObjectsARB; +extern PFNGLGETUNIFORMLOCATIONARBPROC glGetUniformLocationARB; +extern PFNGLGETACTIVEUNIFORMARBPROC glGetActiveUniformARB; +extern PFNGLGETUNIFORMFVARBPROC glGetUniformfvARB; +extern PFNGLGETUNIFORMIVARBPROC glGetUniformivARB; +extern PFNGLGETSHADERSOURCEARBPROC glGetShaderSourceARB; + +// GL_ARB_vertex_shader +extern PFNGLVERTEXATTRIB1DARBPROC glVertexAttrib1dARB; +extern PFNGLVERTEXATTRIB1DVARBPROC glVertexAttrib1dvARB; +extern PFNGLVERTEXATTRIB1FARBPROC glVertexAttrib1fARB; +extern PFNGLVERTEXATTRIB1FVARBPROC glVertexAttrib1fvARB; +extern PFNGLVERTEXATTRIB1SARBPROC glVertexAttrib1sARB; +extern PFNGLVERTEXATTRIB1SVARBPROC glVertexAttrib1svARB; +extern PFNGLVERTEXATTRIB2DARBPROC glVertexAttrib2dARB; +extern PFNGLVERTEXATTRIB2DVARBPROC glVertexAttrib2dvARB; +extern PFNGLVERTEXATTRIB2FARBPROC glVertexAttrib2fARB; +extern PFNGLVERTEXATTRIB2FVARBPROC glVertexAttrib2fvARB; +extern PFNGLVERTEXATTRIB2SARBPROC glVertexAttrib2sARB; +extern PFNGLVERTEXATTRIB2SVARBPROC glVertexAttrib2svARB; +extern PFNGLVERTEXATTRIB3DARBPROC glVertexAttrib3dARB; +extern PFNGLVERTEXATTRIB3DVARBPROC glVertexAttrib3dvARB; +extern PFNGLVERTEXATTRIB3FARBPROC glVertexAttrib3fARB; +extern PFNGLVERTEXATTRIB3FVARBPROC glVertexAttrib3fvARB; +extern PFNGLVERTEXATTRIB3SARBPROC glVertexAttrib3sARB; +extern PFNGLVERTEXATTRIB3SVARBPROC glVertexAttrib3svARB; +extern PFNGLVERTEXATTRIB4NBVARBPROC glVertexAttrib4nbvARB; +extern PFNGLVERTEXATTRIB4NIVARBPROC glVertexAttrib4nivARB; +extern PFNGLVERTEXATTRIB4NSVARBPROC glVertexAttrib4nsvARB; +extern PFNGLVERTEXATTRIB4NUBARBPROC glVertexAttrib4nubARB; +extern PFNGLVERTEXATTRIB4NUBVARBPROC glVertexAttrib4nubvARB; +extern PFNGLVERTEXATTRIB4NUIVARBPROC glVertexAttrib4nuivARB; +extern PFNGLVERTEXATTRIB4NUSVARBPROC glVertexAttrib4nusvARB; +extern PFNGLVERTEXATTRIB4BVARBPROC glVertexAttrib4bvARB; +extern PFNGLVERTEXATTRIB4DARBPROC glVertexAttrib4dARB; +extern PFNGLVERTEXATTRIB4DVARBPROC glVertexAttrib4dvARB; +extern PFNGLVERTEXATTRIB4FARBPROC glVertexAttrib4fARB; +extern PFNGLVERTEXATTRIB4FVARBPROC glVertexAttrib4fvARB; +extern PFNGLVERTEXATTRIB4IVARBPROC glVertexAttrib4ivARB; +extern PFNGLVERTEXATTRIB4SARBPROC glVertexAttrib4sARB; +extern PFNGLVERTEXATTRIB4SVARBPROC glVertexAttrib4svARB; +extern PFNGLVERTEXATTRIB4UBVARBPROC glVertexAttrib4ubvARB; +extern PFNGLVERTEXATTRIB4UIVARBPROC glVertexAttrib4uivARB; +extern PFNGLVERTEXATTRIB4USVARBPROC glVertexAttrib4usvARB; +extern PFNGLVERTEXATTRIBPOINTERARBPROC glVertexAttribPointerARB; +extern PFNGLENABLEVERTEXATTRIBARRAYARBPROC glEnableVertexAttribArrayARB; +extern PFNGLDISABLEVERTEXATTRIBARRAYARBPROC glDisableVertexAttribArrayARB; +extern PFNGLPROGRAMSTRINGARBPROC glProgramStringARB; +extern PFNGLBINDPROGRAMARBPROC glBindProgramARB; +extern PFNGLDELETEPROGRAMSARBPROC glDeleteProgramsARB; +extern PFNGLGENPROGRAMSARBPROC glGenProgramsARB; +extern PFNGLPROGRAMENVPARAMETER4DARBPROC glProgramEnvParameter4dARB; +extern PFNGLPROGRAMENVPARAMETER4DVARBPROC glProgramEnvParameter4dvARB; +extern PFNGLPROGRAMENVPARAMETER4FARBPROC glProgramEnvParameter4fARB; +extern PFNGLPROGRAMENVPARAMETER4FVARBPROC glProgramEnvParameter4fvARB; +extern PFNGLPROGRAMLOCALPARAMETER4DARBPROC glProgramLocalParameter4dARB; +extern PFNGLPROGRAMLOCALPARAMETER4DVARBPROC glProgramLocalParameter4dvARB; +extern PFNGLPROGRAMLOCALPARAMETER4FARBPROC glProgramLocalParameter4fARB; +extern PFNGLPROGRAMLOCALPARAMETER4FVARBPROC glProgramLocalParameter4fvARB; +extern PFNGLGETPROGRAMENVPARAMETERDVARBPROC glGetProgramEnvParameterdvARB; +extern PFNGLGETPROGRAMENVPARAMETERFVARBPROC glGetProgramEnvParameterfvARB; +extern PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC glGetProgramLocalParameterdvARB; +extern PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC glGetProgramLocalParameterfvARB; +extern PFNGLGETPROGRAMIVARBPROC glGetProgramivARB; +extern PFNGLGETPROGRAMSTRINGARBPROC glGetProgramStringARB; +extern PFNGLGETVERTEXATTRIBDVARBPROC glGetVertexAttribdvARB; +extern PFNGLGETVERTEXATTRIBFVARBPROC glGetVertexAttribfvARB; +extern PFNGLGETVERTEXATTRIBIVARBPROC glGetVertexAttribivARB; +extern PFNGLGETVERTEXATTRIBPOINTERVARBPROC glGetVertexAttribPointervARB; +extern PFNGLISPROGRAMARBPROC glIsProgramARB; +extern PFNGLBINDATTRIBLOCATIONARBPROC glBindAttribLocationARB; +extern PFNGLGETACTIVEATTRIBARBPROC glGetActiveAttribARB; +extern PFNGLGETATTRIBLOCATIONARBPROC glGetAttribLocationARB; + +extern PFNGLCOMPRESSEDTEXIMAGE2DARBPROC glCompressedTexImage2DARB; +extern PFNGLGETCOMPRESSEDTEXIMAGEARBPROC glGetCompressedTexImageARB; + +extern PFNGLCOLORTABLEEXTPROC glColorTableEXT; + +//GL_EXT_framebuffer_object +extern PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT; +extern PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT; +extern PFNGLDELETERENDERBUFFERSEXTPROC glDeleteRenderbuffersEXT; +extern PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffersEXT; +extern PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorageEXT; +extern PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glGetRenderbufferParameterivEXT; +extern PFNGLISFRAMEBUFFEREXTPROC glIsFramebufferEXT; +extern PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT; +extern PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT; +extern PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT; +extern PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT; +extern PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glFramebufferTexture1DEXT; +extern PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT; +extern PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glFramebufferTexture3DEXT; +extern PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT; +extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glGetFramebufferAttachmentParameterivEXT; +extern PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT; + + +#elif LL_WINDOWS + +// windows gl headers depend on things like APIENTRY, so include windows. +#define WIN32_LEAN_AND_MEAN +#include <winsock2.h> +#include <windows.h> + +//---------------------------------------------------------------------------- +#include <GL/gl.h> +#include <GL/glu.h> + +// quotes so we get libraries/.../GL/ version +#include "GL/glext.h" +#include "GL/glh_extensions.h" + + +// GL_ARB_vertex_buffer_object +extern PFNGLBINDBUFFERARBPROC glBindBufferARB; +extern PFNGLDELETEBUFFERSARBPROC glDeleteBuffersARB; +extern PFNGLGENBUFFERSARBPROC glGenBuffersARB; +extern PFNGLISBUFFERARBPROC glIsBufferARB; +extern PFNGLBUFFERDATAARBPROC glBufferDataARB; +extern PFNGLBUFFERSUBDATAARBPROC glBufferSubDataARB; +extern PFNGLGETBUFFERSUBDATAARBPROC glGetBufferSubDataARB; +extern PFNGLMAPBUFFERARBPROC glMapBufferARB; +extern PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB; +extern PFNGLGETBUFFERPARAMETERIVARBPROC glGetBufferParameterivARB; +extern PFNGLGETBUFFERPOINTERVARBPROC glGetBufferPointervARB; + +// GL_ATI_vertex_array_object +extern PFNGLNEWOBJECTBUFFERATIPROC glNewObjectBufferATI; +extern PFNGLISOBJECTBUFFERATIPROC glIsObjectBufferATI; +extern PFNGLUPDATEOBJECTBUFFERATIPROC glUpdateObjectBufferATI; +extern PFNGLGETOBJECTBUFFERFVATIPROC glGetObjectBufferfvATI; +extern PFNGLGETOBJECTBUFFERIVATIPROC glGetObjectBufferivATI; +extern PFNGLFREEOBJECTBUFFERATIPROC glFreeObjectBufferATI; +extern PFNGLARRAYOBJECTATIPROC glArrayObjectATI; +extern PFNGLVERTEXATTRIBARRAYOBJECTATIPROC glVertexAttribArrayObjectATI; +extern PFNGLGETARRAYOBJECTFVATIPROC glGetArrayObjectfvATI; +extern PFNGLGETARRAYOBJECTIVATIPROC glGetArrayObjectivATI; +extern PFNGLVARIANTARRAYOBJECTATIPROC glVariantObjectArrayATI; +extern PFNGLGETVARIANTARRAYOBJECTFVATIPROC glGetVariantArrayObjectfvATI; +extern PFNGLGETVARIANTARRAYOBJECTIVATIPROC glGetVariantArrayObjectivATI; + +extern PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT; + +// GL_ARB_occlusion_query +extern PFNGLGENQUERIESARBPROC glGenQueriesARB; +extern PFNGLDELETEQUERIESARBPROC glDeleteQueriesARB; +extern PFNGLISQUERYARBPROC glIsQueryARB; +extern PFNGLBEGINQUERYARBPROC glBeginQueryARB; +extern PFNGLENDQUERYARBPROC glEndQueryARB; +extern PFNGLGETQUERYIVARBPROC glGetQueryivARB; +extern PFNGLGETQUERYOBJECTIVARBPROC glGetQueryObjectivARB; +extern PFNGLGETQUERYOBJECTUIVARBPROC glGetQueryObjectuivARB; + +// GL_ARB_point_parameters +extern PFNGLPOINTPARAMETERFARBPROC glPointParameterfARB; +extern PFNGLPOINTPARAMETERFVARBPROC glPointParameterfvARB; + +// GL_ARB_shader_objects +extern PFNGLDELETEOBJECTARBPROC glDeleteObjectARB; +extern PFNGLGETHANDLEARBPROC glGetHandleARB; +extern PFNGLDETACHOBJECTARBPROC glDetachObjectARB; +extern PFNGLCREATESHADEROBJECTARBPROC glCreateShaderObjectARB; +extern PFNGLSHADERSOURCEARBPROC glShaderSourceARB; +extern PFNGLCOMPILESHADERARBPROC glCompileShaderARB; +extern PFNGLCREATEPROGRAMOBJECTARBPROC glCreateProgramObjectARB; +extern PFNGLATTACHOBJECTARBPROC glAttachObjectARB; +extern PFNGLLINKPROGRAMARBPROC glLinkProgramARB; +extern PFNGLUSEPROGRAMOBJECTARBPROC glUseProgramObjectARB; +extern PFNGLVALIDATEPROGRAMARBPROC glValidateProgramARB; +extern PFNGLUNIFORM1FARBPROC glUniform1fARB; +extern PFNGLUNIFORM2FARBPROC glUniform2fARB; +extern PFNGLUNIFORM3FARBPROC glUniform3fARB; +extern PFNGLUNIFORM4FARBPROC glUniform4fARB; +extern PFNGLUNIFORM1IARBPROC glUniform1iARB; +extern PFNGLUNIFORM2IARBPROC glUniform2iARB; +extern PFNGLUNIFORM3IARBPROC glUniform3iARB; +extern PFNGLUNIFORM4IARBPROC glUniform4iARB; +extern PFNGLUNIFORM1FVARBPROC glUniform1fvARB; +extern PFNGLUNIFORM2FVARBPROC glUniform2fvARB; +extern PFNGLUNIFORM3FVARBPROC glUniform3fvARB; +extern PFNGLUNIFORM4FVARBPROC glUniform4fvARB; +extern PFNGLUNIFORM1IVARBPROC glUniform1ivARB; +extern PFNGLUNIFORM2IVARBPROC glUniform2ivARB; +extern PFNGLUNIFORM3IVARBPROC glUniform3ivARB; +extern PFNGLUNIFORM4IVARBPROC glUniform4ivARB; +extern PFNGLUNIFORMMATRIX2FVARBPROC glUniformMatrix2fvARB; +extern PFNGLUNIFORMMATRIX3FVARBPROC glUniformMatrix3fvARB; +extern PFNGLUNIFORMMATRIX4FVARBPROC glUniformMatrix4fvARB; +extern PFNGLGETOBJECTPARAMETERFVARBPROC glGetObjectParameterfvARB; +extern PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameterivARB; +extern PFNGLGETINFOLOGARBPROC glGetInfoLogARB; +extern PFNGLGETATTACHEDOBJECTSARBPROC glGetAttachedObjectsARB; +extern PFNGLGETUNIFORMLOCATIONARBPROC glGetUniformLocationARB; +extern PFNGLGETACTIVEUNIFORMARBPROC glGetActiveUniformARB; +extern PFNGLGETUNIFORMFVARBPROC glGetUniformfvARB; +extern PFNGLGETUNIFORMIVARBPROC glGetUniformivARB; +extern PFNGLGETSHADERSOURCEARBPROC glGetShaderSourceARB; + +// GL_ARB_vertex_shader +extern PFNGLVERTEXATTRIB1DARBPROC glVertexAttrib1dARB; +extern PFNGLVERTEXATTRIB1DVARBPROC glVertexAttrib1dvARB; +extern PFNGLVERTEXATTRIB1FARBPROC glVertexAttrib1fARB; +extern PFNGLVERTEXATTRIB1FVARBPROC glVertexAttrib1fvARB; +extern PFNGLVERTEXATTRIB1SARBPROC glVertexAttrib1sARB; +extern PFNGLVERTEXATTRIB1SVARBPROC glVertexAttrib1svARB; +extern PFNGLVERTEXATTRIB2DARBPROC glVertexAttrib2dARB; +extern PFNGLVERTEXATTRIB2DVARBPROC glVertexAttrib2dvARB; +extern PFNGLVERTEXATTRIB2FARBPROC glVertexAttrib2fARB; +extern PFNGLVERTEXATTRIB2FVARBPROC glVertexAttrib2fvARB; +extern PFNGLVERTEXATTRIB2SARBPROC glVertexAttrib2sARB; +extern PFNGLVERTEXATTRIB2SVARBPROC glVertexAttrib2svARB; +extern PFNGLVERTEXATTRIB3DARBPROC glVertexAttrib3dARB; +extern PFNGLVERTEXATTRIB3DVARBPROC glVertexAttrib3dvARB; +extern PFNGLVERTEXATTRIB3FARBPROC glVertexAttrib3fARB; +extern PFNGLVERTEXATTRIB3FVARBPROC glVertexAttrib3fvARB; +extern PFNGLVERTEXATTRIB3SARBPROC glVertexAttrib3sARB; +extern PFNGLVERTEXATTRIB3SVARBPROC glVertexAttrib3svARB; +extern PFNGLVERTEXATTRIB4NBVARBPROC glVertexAttrib4nbvARB; +extern PFNGLVERTEXATTRIB4NIVARBPROC glVertexAttrib4nivARB; +extern PFNGLVERTEXATTRIB4NSVARBPROC glVertexAttrib4nsvARB; +extern PFNGLVERTEXATTRIB4NUBARBPROC glVertexAttrib4nubARB; +extern PFNGLVERTEXATTRIB4NUBVARBPROC glVertexAttrib4nubvARB; +extern PFNGLVERTEXATTRIB4NUIVARBPROC glVertexAttrib4nuivARB; +extern PFNGLVERTEXATTRIB4NUSVARBPROC glVertexAttrib4nusvARB; +extern PFNGLVERTEXATTRIB4BVARBPROC glVertexAttrib4bvARB; +extern PFNGLVERTEXATTRIB4DARBPROC glVertexAttrib4dARB; +extern PFNGLVERTEXATTRIB4DVARBPROC glVertexAttrib4dvARB; +extern PFNGLVERTEXATTRIB4FARBPROC glVertexAttrib4fARB; +extern PFNGLVERTEXATTRIB4FVARBPROC glVertexAttrib4fvARB; +extern PFNGLVERTEXATTRIB4IVARBPROC glVertexAttrib4ivARB; +extern PFNGLVERTEXATTRIB4SARBPROC glVertexAttrib4sARB; +extern PFNGLVERTEXATTRIB4SVARBPROC glVertexAttrib4svARB; +extern PFNGLVERTEXATTRIB4UBVARBPROC glVertexAttrib4ubvARB; +extern PFNGLVERTEXATTRIB4UIVARBPROC glVertexAttrib4uivARB; +extern PFNGLVERTEXATTRIB4USVARBPROC glVertexAttrib4usvARB; +extern PFNGLVERTEXATTRIBPOINTERARBPROC glVertexAttribPointerARB; +extern PFNGLENABLEVERTEXATTRIBARRAYARBPROC glEnableVertexAttribArrayARB; +extern PFNGLDISABLEVERTEXATTRIBARRAYARBPROC glDisableVertexAttribArrayARB; +extern PFNGLPROGRAMSTRINGARBPROC glProgramStringARB; +extern PFNGLBINDPROGRAMARBPROC glBindProgramARB; +extern PFNGLDELETEPROGRAMSARBPROC glDeleteProgramsARB; +extern PFNGLGENPROGRAMSARBPROC glGenProgramsARB; +extern PFNGLPROGRAMENVPARAMETER4DARBPROC glProgramEnvParameter4dARB; +extern PFNGLPROGRAMENVPARAMETER4DVARBPROC glProgramEnvParameter4dvARB; +extern PFNGLPROGRAMENVPARAMETER4FARBPROC glProgramEnvParameter4fARB; +extern PFNGLPROGRAMENVPARAMETER4FVARBPROC glProgramEnvParameter4fvARB; +extern PFNGLPROGRAMLOCALPARAMETER4DARBPROC glProgramLocalParameter4dARB; +extern PFNGLPROGRAMLOCALPARAMETER4DVARBPROC glProgramLocalParameter4dvARB; +extern PFNGLPROGRAMLOCALPARAMETER4FARBPROC glProgramLocalParameter4fARB; +extern PFNGLPROGRAMLOCALPARAMETER4FVARBPROC glProgramLocalParameter4fvARB; +extern PFNGLGETPROGRAMENVPARAMETERDVARBPROC glGetProgramEnvParameterdvARB; +extern PFNGLGETPROGRAMENVPARAMETERFVARBPROC glGetProgramEnvParameterfvARB; +extern PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC glGetProgramLocalParameterdvARB; +extern PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC glGetProgramLocalParameterfvARB; +extern PFNGLGETPROGRAMIVARBPROC glGetProgramivARB; +extern PFNGLGETPROGRAMSTRINGARBPROC glGetProgramStringARB; +extern PFNGLGETVERTEXATTRIBDVARBPROC glGetVertexAttribdvARB; +extern PFNGLGETVERTEXATTRIBFVARBPROC glGetVertexAttribfvARB; +extern PFNGLGETVERTEXATTRIBIVARBPROC glGetVertexAttribivARB; +extern PFNGLGETVERTEXATTRIBPOINTERVARBPROC glGetVertexAttribPointervARB; +extern PFNGLISPROGRAMARBPROC glIsProgramARB; +extern PFNGLBINDATTRIBLOCATIONARBPROC glBindAttribLocationARB; +extern PFNGLGETACTIVEATTRIBARBPROC glGetActiveAttribARB; +extern PFNGLGETATTRIBLOCATIONARBPROC glGetAttribLocationARB; + +//GL_EXT_framebuffer_object +extern PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT; +extern PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT; +extern PFNGLDELETERENDERBUFFERSEXTPROC glDeleteRenderbuffersEXT; +extern PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffersEXT; +extern PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorageEXT; +extern PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glGetRenderbufferParameterivEXT; +extern PFNGLISFRAMEBUFFEREXTPROC glIsFramebufferEXT; +extern PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT; +extern PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT; +extern PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT; +extern PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT; +extern PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glFramebufferTexture1DEXT; +extern PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT; +extern PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glFramebufferTexture3DEXT; +extern PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT; +extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glGetFramebufferAttachmentParameterivEXT; +extern PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT; + + +#elif LL_DARWIN +//---------------------------------------------------------------------------- +// LL_DARWIN + +#include <OpenGL/gl.h> +#include <OpenGL/glu.h> + +#define GL_EXT_separate_specular_color 1 +#include <OpenGL/glext.h> + +#include "GL/glh_extensions.h" + +// These symbols don't exist on 10.3.9, so they have to be declared weak. Redeclaring them here fixes the problem. +// Note that they also must not be called on 10.3.9. This should be taken care of by a runtime check for the existence of the GL extension. +#include <AvailabilityMacros.h> + +// GL_EXT_framebuffer_object +extern GLboolean glIsRenderbufferEXT(GLuint renderbuffer) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +extern void glBindRenderbufferEXT(GLenum target, GLuint renderbuffer) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +extern void glDeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +extern void glGenRenderbuffersEXT(GLsizei n, GLuint *renderbuffers) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +extern void glRenderbufferStorageEXT(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +extern void glGetRenderbufferParameterivEXT(GLenum target, GLenum pname, GLint *params) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +extern GLboolean glIsFramebufferEXT(GLuint framebuffer) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +extern void glBindFramebufferEXT(GLenum target, GLuint framebuffer) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +extern void glDeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +extern void glGenFramebuffersEXT(GLsizei n, GLuint *framebuffers) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +extern GLenum glCheckFramebufferStatusEXT(GLenum target) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +extern void glFramebufferTexture1DEXT(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +extern void glFramebufferTexture2DEXT(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +extern void glFramebufferTexture3DEXT(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +extern void glFramebufferRenderbufferEXT(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +extern void glGetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, GLenum pname, GLint *params) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +extern void glGenerateMipmapEXT(GLenum target) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; + + +#ifdef __cplusplus +extern "C" { +#endif +// +// Define vertex buffer object headers on Mac +// +#ifndef GL_ARB_vertex_buffer_object +#define GL_BUFFER_SIZE_ARB 0x8764 +#define GL_BUFFER_USAGE_ARB 0x8765 +#define GL_ARRAY_BUFFER_ARB 0x8892 +#define GL_ELEMENT_ARRAY_BUFFER_ARB 0x8893 +#define GL_ARRAY_BUFFER_BINDING_ARB 0x8894 +#define GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB 0x8895 +#define GL_VERTEX_ARRAY_BUFFER_BINDING_ARB 0x8896 +#define GL_NORMAL_ARRAY_BUFFER_BINDING_ARB 0x8897 +#define GL_COLOR_ARRAY_BUFFER_BINDING_ARB 0x8898 +#define GL_INDEX_ARRAY_BUFFER_BINDING_ARB 0x8899 +#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB 0x889A +#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB 0x889B +#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB 0x889C +#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB 0x889D +#define GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB 0x889E +#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB 0x889F +#define GL_READ_ONLY_ARB 0x88B8 +#define GL_WRITE_ONLY_ARB 0x88B9 +#define GL_READ_WRITE_ARB 0x88BA +#define GL_BUFFER_ACCESS_ARB 0x88BB +#define GL_BUFFER_MAPPED_ARB 0x88BC +#define GL_BUFFER_MAP_POINTER_ARB 0x88BD +#define GL_STREAM_DRAW_ARB 0x88E0 +#define GL_STREAM_READ_ARB 0x88E1 +#define GL_STREAM_COPY_ARB 0x88E2 +#define GL_STATIC_DRAW_ARB 0x88E4 +#define GL_STATIC_READ_ARB 0x88E5 +#define GL_STATIC_COPY_ARB 0x88E6 +#define GL_DYNAMIC_DRAW_ARB 0x88E8 +#define GL_DYNAMIC_READ_ARB 0x88E9 +#define GL_DYNAMIC_COPY_ARB 0x88EA +#endif + + + +#ifndef GL_ARB_vertex_buffer_object +/* GL types for handling large vertex buffer objects */ +typedef intptr_t GLintptrARB; +typedef intptr_t GLsizeiptrARB; +#endif + + +#ifndef GL_ARB_vertex_buffer_object +#define GL_ARB_vertex_buffer_object 1 +#ifdef GL_GLEXT_FUNCTION_POINTERS +typedef void (* glBindBufferARBProcPtr) (GLenum target, GLuint buffer); +typedef void (* glDeleteBufferARBProcPtr) (GLsizei n, const GLuint *buffers); +typedef void (* glGenBuffersARBProcPtr) (GLsizei n, GLuint *buffers); +typedef GLboolean (* glIsBufferARBProcPtr) (GLuint buffer); +typedef void (* glBufferDataARBProcPtr) (GLenum target, GLsizeiptrARB size, const GLvoid *data, GLenum usage); +typedef void (* glBufferSubDataARBProcPtr) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid *data); +typedef void (* glGetBufferSubDataARBProcPtr) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid *data); +typedef GLvoid* (* glMapBufferARBProcPtr) (GLenum target, GLenum access); /* Flawfinder: ignore */ +typedef GLboolean (* glUnmapBufferARBProcPtr) (GLenum target); +typedef void (* glGetBufferParameterivARBProcPtr) (GLenum target, GLenum pname, GLint *params); +typedef void (* glGetBufferPointervARBProcPtr) (GLenum target, GLenum pname, GLvoid* *params); +#else +extern void glBindBufferARB (GLenum, GLuint); +extern void glDeleteBuffersARB (GLsizei, const GLuint *); +extern void glGenBuffersARB (GLsizei, GLuint *); +extern GLboolean glIsBufferARB (GLuint); +extern void glBufferDataARB (GLenum, GLsizeiptrARB, const GLvoid *, GLenum); +extern void glBufferSubDataARB (GLenum, GLintptrARB, GLsizeiptrARB, const GLvoid *); +extern void glGetBufferSubDataARB (GLenum, GLintptrARB, GLsizeiptrARB, GLvoid *); +extern GLvoid* glMapBufferARB (GLenum, GLenum); +extern GLboolean glUnmapBufferARB (GLenum); +extern void glGetBufferParameterivARB (GLenum, GLenum, GLint *); +extern void glGetBufferPointervARB (GLenum, GLenum, GLvoid* *); +#endif /* GL_GLEXT_FUNCTION_POINTERS */ +#endif + +// May be needed for DARWIN... +// #ifndef GL_ARB_compressed_tex_image +// #define GL_ARB_compressed_tex_image 1 +// #ifdef GL_GLEXT_FUNCTION_POINTERS +// typedef void (* glCompressedTexImage1D) (GLenum, GLint, GLenum, GLsizei, GLint, GLsizei, const GLvoid*); +// typedef void (* glCompressedTexImage2D) (GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const GLvoid*); +// typedef void (* glCompressedTexImage3D) (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLsizei, const GLvoid*); +// typedef void (* glCompressedTexSubImage1D) (GLenum, GLint, GLint, GLsizei, GLenum, GLsizei, const GLvoid*); +// typedef void (* glCompressedTexSubImage2D) (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid*); +// typedef void (* glCompressedTexSubImage3D) (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid*); +// typedef void (* glGetCompressedTexImage) (GLenum, GLint, GLvoid*); +// #else +// extern void glCompressedTexImage1D (GLenum, GLint, GLenum, GLsizei, GLint, GLsizei, const GLvoid*); +// extern void glCompressedTexImage2D (GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const GLvoid*); +// extern void glCompressedTexImage3D (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLsizei, const GLvoid*); +// extern void glCompressedTexSubImage1D (GLenum, GLint, GLint, GLsizei, GLenum, GLsizei, const GLvoid*); +// extern void glCompressedTexSubImage2D (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid*); +// extern void glCompressedTexSubImage3D (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid*); +// extern void glGetCompressedTexImage (GLenum, GLint, GLvoid*); +// #endif /* GL_GLEXT_FUNCTION_POINTERS */ +// #endif + +#ifdef __cplusplus +} +#endif + +#include <AGL/gl.h> + +#endif // LL_MESA / LL_WINDOWS / LL_DARWIN + + +#endif // LL_LLGLHEADERS_H diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp new file mode 100644 index 0000000000..7b03944918 --- /dev/null +++ b/indra/llrender/llglslshader.cpp @@ -0,0 +1,823 @@ +/** + * @file llglslshader.cpp + * @brief GLSL helper functions and state. + * + * $LicenseInfo:firstyear=2005&license=viewergpl$ + * + * Copyright (c) 2005-2007, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llglslshader.h" + +#include "llshadermgr.h" +#include "llfile.h" +#include "llrender.h" + +#if LL_DARWIN +#include "OpenGL/OpenGL.h" +#endif + +#ifdef LL_RELEASE_FOR_DOWNLOAD +#define UNIFORM_ERRS LL_WARNS_ONCE("Shader") +#else +#define UNIFORM_ERRS LL_ERRS("Shader") +#endif + +// Lots of STL stuff in here, using namespace std to keep things more readable +using std::vector; +using std::pair; +using std::make_pair; +using std::string; + +BOOL shouldChange(const LLVector4& v1, const LLVector4& v2) +{ + return v1 != v2; +} + +LLShaderFeatures::LLShaderFeatures() +: calculatesLighting(false), isShiny(false), isFullbright(false), hasWaterFog(false), +hasTransport(false), hasSkinning(false), hasAtmospherics(false), isSpecular(false), +hasGamma(false), hasLighting(false), calculatesAtmospherics(false) +{ +} + +//=============================== +// LLGLSL Shader implementation +//=============================== +LLGLSLShader::LLGLSLShader() +: mProgramObject(0), mShaderLevel(0), mShaderGroup(SG_DEFAULT) +{ +} + +void LLGLSLShader::unload() +{ + stop_glerror(); + mAttribute.clear(); + mTexture.clear(); + mUniform.clear(); + mShaderFiles.clear(); + + if (mProgramObject) + { + GLhandleARB obj[1024]; + GLsizei count; + + glGetAttachedObjectsARB(mProgramObject, 1024, &count, obj); + for (GLsizei i = 0; i < count; i++) + { + glDeleteObjectARB(obj[i]); + } + + glDeleteObjectARB(mProgramObject); + + mProgramObject = 0; + } + + //hack to make apple not complain + glGetError(); + + stop_glerror(); +} + +BOOL LLGLSLShader::createShader(vector<string> * attributes, + vector<string> * uniforms) +{ + llassert_always(!mShaderFiles.empty()); + BOOL success = TRUE; + + // Create program + mProgramObject = glCreateProgramObjectARB(); + + // Attach existing objects + if (!LLShaderMgr::instance()->attachShaderFeatures(this)) + { + return FALSE; + } + + vector< pair<string,GLenum> >::iterator fileIter = mShaderFiles.begin(); + for ( ; fileIter != mShaderFiles.end(); fileIter++ ) + { + GLhandleARB shaderhandle = LLShaderMgr::instance()->loadShaderFile((*fileIter).first, mShaderLevel, (*fileIter).second); + LL_DEBUGS("ShaderLoading") << "SHADER FILE: " << (*fileIter).first << " mShaderLevel=" << mShaderLevel << LL_ENDL; + if (mShaderLevel > 0) + { + attachObject(shaderhandle); + } + else + { + success = FALSE; + } + } + + // Map attributes and uniforms + if (success) + { + success = mapAttributes(attributes); + } + if (success) + { + success = mapUniforms(uniforms); + } + if( !success ) + { + LL_WARNS("ShaderLoading") << "Failed to link shader: " << mName << LL_ENDL; + + // Try again using a lower shader level; + if (mShaderLevel > 0) + { + LL_WARNS("ShaderLoading") << "Failed to link using shader level " << mShaderLevel << " trying again using shader level " << (mShaderLevel - 1) << LL_ENDL; + mShaderLevel--; + return createShader(attributes,uniforms); + } + } + return success; +} + +BOOL LLGLSLShader::attachObject(std::string object) +{ + if (LLShaderMgr::instance()->mShaderObjects.count(object) > 0) + { + stop_glerror(); + glAttachObjectARB(mProgramObject, LLShaderMgr::instance()->mShaderObjects[object]); + stop_glerror(); + return TRUE; + } + else + { + LL_WARNS("ShaderLoading") << "Attempting to attach shader object that hasn't been compiled: " << object << LL_ENDL; + return FALSE; + } +} + +void LLGLSLShader::attachObject(GLhandleARB object) +{ + if (object != 0) + { + stop_glerror(); + glAttachObjectARB(mProgramObject, object); + stop_glerror(); + } + else + { + LL_WARNS("ShaderLoading") << "Attempting to attach non existing shader object. " << LL_ENDL; + } +} + +void LLGLSLShader::attachObjects(GLhandleARB* objects, S32 count) +{ + for (S32 i = 0; i < count; i++) + { + attachObject(objects[i]); + } +} + +BOOL LLGLSLShader::mapAttributes(const vector<string> * attributes) +{ + //link the program + BOOL res = link(); + + mAttribute.clear(); + U32 numAttributes = (attributes == NULL) ? 0 : attributes->size(); + mAttribute.resize(LLShaderMgr::instance()->mReservedAttribs.size() + numAttributes, -1); + + if (res) + { //read back channel locations + + //read back reserved channels first + for (U32 i = 0; i < (S32) LLShaderMgr::instance()->mReservedAttribs.size(); i++) + { + const char* name = LLShaderMgr::instance()->mReservedAttribs[i].c_str(); + S32 index = glGetAttribLocationARB(mProgramObject, (const GLcharARB *)name); + if (index != -1) + { + mAttribute[i] = index; + LL_DEBUGS("ShaderLoading") << "Attribute " << name << " assigned to channel " << index << LL_ENDL; + } + } + if (attributes != NULL) + { + for (U32 i = 0; i < numAttributes; i++) + { + const char* name = (*attributes)[i].c_str(); + S32 index = glGetAttribLocationARB(mProgramObject, name); + if (index != -1) + { + mAttribute[LLShaderMgr::instance()->mReservedAttribs.size() + i] = index; + LL_DEBUGS("ShaderLoading") << "Attribute " << name << " assigned to channel " << index << LL_ENDL; + } + } + } + + return TRUE; + } + + return FALSE; +} + +void LLGLSLShader::mapUniform(GLint index, const vector<string> * uniforms) +{ + if (index == -1) + { + return; + } + + GLenum type; + GLsizei length; + GLint size; + char name[1024]; /* Flawfinder: ignore */ + name[0] = 0; + + glGetActiveUniformARB(mProgramObject, index, 1024, &length, &size, &type, (GLcharARB *)name); + S32 location = glGetUniformLocationARB(mProgramObject, name); + if (location != -1) + { + mUniformMap[name] = location; + LL_DEBUGS("ShaderLoading") << "Uniform " << name << " is at location " << location << LL_ENDL; + + //find the index of this uniform + for (S32 i = 0; i < (S32) LLShaderMgr::instance()->mReservedUniforms.size(); i++) + { + if ( (mUniform[i] == -1) + && (LLShaderMgr::instance()->mReservedUniforms[i].compare(0, length, name, LLShaderMgr::instance()->mReservedUniforms[i].length()) == 0)) + { + //found it + mUniform[i] = location; + mTexture[i] = mapUniformTextureChannel(location, type); + return; + } + } + + if (uniforms != NULL) + { + for (U32 i = 0; i < uniforms->size(); i++) + { + if ( (mUniform[i+LLShaderMgr::instance()->mReservedUniforms.size()] == -1) + && ((*uniforms)[i].compare(0, length, name, (*uniforms)[i].length()) == 0)) + { + //found it + mUniform[i+LLShaderMgr::instance()->mReservedUniforms.size()] = location; + mTexture[i+LLShaderMgr::instance()->mReservedUniforms.size()] = mapUniformTextureChannel(location, type); + return; + } + } + } + } + } + +GLint LLGLSLShader::mapUniformTextureChannel(GLint location, GLenum type) +{ + if (type >= GL_SAMPLER_1D_ARB && type <= GL_SAMPLER_2D_RECT_SHADOW_ARB) + { //this here is a texture + glUniform1iARB(location, mActiveTextureChannels); + LL_DEBUGS("ShaderLoading") << "Assigned to texture channel " << mActiveTextureChannels << LL_ENDL; + return mActiveTextureChannels++; + } + return -1; +} + +BOOL LLGLSLShader::mapUniforms(const vector<string> * uniforms) +{ + BOOL res = TRUE; + + mActiveTextureChannels = 0; + mUniform.clear(); + mUniformMap.clear(); + mTexture.clear(); + mValue.clear(); + //initialize arrays + U32 numUniforms = (uniforms == NULL) ? 0 : uniforms->size(); + mUniform.resize(numUniforms + LLShaderMgr::instance()->mReservedUniforms.size(), -1); + mTexture.resize(numUniforms + LLShaderMgr::instance()->mReservedUniforms.size(), -1); + + bind(); + + //get the number of active uniforms + GLint activeCount; + glGetObjectParameterivARB(mProgramObject, GL_OBJECT_ACTIVE_UNIFORMS_ARB, &activeCount); + + for (S32 i = 0; i < activeCount; i++) + { + mapUniform(i, uniforms); + } + + unbind(); + + return res; +} + +BOOL LLGLSLShader::link(BOOL suppress_errors) +{ + return LLShaderMgr::instance()->linkProgramObject(mProgramObject, suppress_errors); +} + +void LLGLSLShader::bind() +{ + if (gGLManager.mHasShaderObjects) + { + glUseProgramObjectARB(mProgramObject); + + if (mUniformsDirty) + { + LLShaderMgr::instance()->updateShaderUniforms(this); + mUniformsDirty = FALSE; + } + } +} + +void LLGLSLShader::unbind() +{ + if (gGLManager.mHasShaderObjects) + { + for (U32 i = 0; i < mAttribute.size(); ++i) + { + vertexAttrib4f(i, 0,0,0,1); + } + glUseProgramObjectARB(0); + } +} + +void LLGLSLShader::bindNoShader(void) +{ + glUseProgramObjectARB(0); +} + +S32 LLGLSLShader::enableTexture(S32 uniform, S32 mode) +{ + if (uniform < 0 || uniform >= (S32)mTexture.size()) + { + UNIFORM_ERRS << "Uniform out of range: " << uniform << LL_ENDL; + return -1; + } + S32 index = mTexture[uniform]; + if (index != -1) + { + gGL.getTexUnit(index)->activate(); + glEnable(mode); + } + return index; +} + +S32 LLGLSLShader::disableTexture(S32 uniform, S32 mode) +{ + if (uniform < 0 || uniform >= (S32)mTexture.size()) + { + UNIFORM_ERRS << "Uniform out of range: " << uniform << LL_ENDL; + return -1; + } + S32 index = mTexture[uniform]; + if (index != -1) + { + gGL.getTexUnit(index)->activate(); + glDisable(mode); + } + return index; +} + +void LLGLSLShader::uniform1f(U32 index, GLfloat x) +{ + if (mProgramObject > 0) + { + if (mUniform.size() <= index) + { + UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL; + return; + } + + if (mUniform[index] >= 0) + { + std::map<GLint, LLVector4>::iterator iter = mValue.find(mUniform[index]); + if (iter == mValue.end() || iter->second.mV[0] != x) + { + glUniform1fARB(mUniform[index], x); + mValue[mUniform[index]] = LLVector4(x,0.f,0.f,0.f); + } + } + } +} + +void LLGLSLShader::uniform2f(U32 index, GLfloat x, GLfloat y) +{ + if (mProgramObject > 0) + { + if (mUniform.size() <= index) + { + UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL; + return; + } + + if (mUniform[index] >= 0) + { + std::map<GLint, LLVector4>::iterator iter = mValue.find(mUniform[index]); + LLVector4 vec(x,y,0.f,0.f); + if (iter == mValue.end() || shouldChange(iter->second,vec)) + { + glUniform2fARB(mUniform[index], x, y); + mValue[mUniform[index]] = vec; + } + } + } +} + +void LLGLSLShader::uniform3f(U32 index, GLfloat x, GLfloat y, GLfloat z) +{ + if (mProgramObject > 0) + { + if (mUniform.size() <= index) + { + UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL; + return; + } + + if (mUniform[index] >= 0) + { + std::map<GLint, LLVector4>::iterator iter = mValue.find(mUniform[index]); + LLVector4 vec(x,y,z,0.f); + if (iter == mValue.end() || shouldChange(iter->second,vec)) + { + glUniform3fARB(mUniform[index], x, y, z); + mValue[mUniform[index]] = vec; + } + } + } +} + +void LLGLSLShader::uniform4f(U32 index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + if (mProgramObject > 0) + { + if (mUniform.size() <= index) + { + UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL; + return; + } + + if (mUniform[index] >= 0) + { + std::map<GLint, LLVector4>::iterator iter = mValue.find(mUniform[index]); + LLVector4 vec(x,y,z,w); + if (iter == mValue.end() || shouldChange(iter->second,vec)) + { + glUniform4fARB(mUniform[index], x, y, z, w); + mValue[mUniform[index]] = vec; + } + } + } +} + +void LLGLSLShader::uniform1fv(U32 index, U32 count, const GLfloat* v) +{ + if (mProgramObject > 0) + { + if (mUniform.size() <= index) + { + UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL; + return; + } + + if (mUniform[index] >= 0) + { + std::map<GLint, LLVector4>::iterator iter = mValue.find(mUniform[index]); + LLVector4 vec(v[0],0.f,0.f,0.f); + if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1) + { + glUniform1fvARB(mUniform[index], count, v); + mValue[mUniform[index]] = vec; + } + } + } +} + +void LLGLSLShader::uniform2fv(U32 index, U32 count, const GLfloat* v) +{ + if (mProgramObject > 0) + { + if (mUniform.size() <= index) + { + UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL; + return; + } + + if (mUniform[index] >= 0) + { + std::map<GLint, LLVector4>::iterator iter = mValue.find(mUniform[index]); + LLVector4 vec(v[0],v[1],0.f,0.f); + if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1) + { + glUniform2fvARB(mUniform[index], count, v); + mValue[mUniform[index]] = vec; + } + } + } +} + +void LLGLSLShader::uniform3fv(U32 index, U32 count, const GLfloat* v) +{ + if (mProgramObject > 0) + { + if (mUniform.size() <= index) + { + UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL; + return; + } + + if (mUniform[index] >= 0) + { + std::map<GLint, LLVector4>::iterator iter = mValue.find(mUniform[index]); + LLVector4 vec(v[0],v[1],v[2],0.f); + if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1) + { + glUniform3fvARB(mUniform[index], count, v); + mValue[mUniform[index]] = vec; + } + } + } +} + +void LLGLSLShader::uniform4fv(U32 index, U32 count, const GLfloat* v) +{ + if (mProgramObject > 0) + { + if (mUniform.size() <= index) + { + UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL; + return; + } + + if (mUniform[index] >= 0) + { + std::map<GLint, LLVector4>::iterator iter = mValue.find(mUniform[index]); + LLVector4 vec(v[0],v[1],v[2],v[3]); + if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1) + { + glUniform4fvARB(mUniform[index], count, v); + mValue[mUniform[index]] = vec; + } + } + } +} + +void LLGLSLShader::uniformMatrix2fv(U32 index, U32 count, GLboolean transpose, const GLfloat *v) +{ + if (mProgramObject > 0) + { + if (mUniform.size() <= index) + { + UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL; + return; + } + + if (mUniform[index] >= 0) + { + glUniformMatrix2fvARB(mUniform[index], count, transpose, v); + } + } +} + +void LLGLSLShader::uniformMatrix3fv(U32 index, U32 count, GLboolean transpose, const GLfloat *v) +{ + if (mProgramObject > 0) + { + if (mUniform.size() <= index) + { + UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL; + return; + } + + if (mUniform[index] >= 0) + { + glUniformMatrix3fvARB(mUniform[index], count, transpose, v); + } + } +} + +void LLGLSLShader::uniformMatrix4fv(U32 index, U32 count, GLboolean transpose, const GLfloat *v) +{ + if (mProgramObject > 0) + { + if (mUniform.size() <= index) + { + UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL; + return; + } + + if (mUniform[index] >= 0) + { + glUniformMatrix4fvARB(mUniform[index], count, transpose, v); + } + } +} + +GLint LLGLSLShader::getUniformLocation(const string& uniform) +{ + if (mProgramObject > 0) + { + std::map<string, GLint>::iterator iter = mUniformMap.find(uniform); + if (iter != mUniformMap.end()) + { + llassert(iter->second == glGetUniformLocationARB(mProgramObject, uniform.c_str())); + return iter->second; + } + } + + return -1; +} + +void LLGLSLShader::uniform1f(const string& uniform, GLfloat v) +{ + GLint location = getUniformLocation(uniform); + + if (location >= 0) + { + std::map<GLint, LLVector4>::iterator iter = mValue.find(location); + LLVector4 vec(v,0.f,0.f,0.f); + if (iter == mValue.end() || shouldChange(iter->second,vec)) + { + glUniform1fARB(location, v); + mValue[location] = vec; + } + } +} + +void LLGLSLShader::uniform2f(const string& uniform, GLfloat x, GLfloat y) +{ + GLint location = getUniformLocation(uniform); + + if (location >= 0) + { + std::map<GLint, LLVector4>::iterator iter = mValue.find(location); + LLVector4 vec(x,y,0.f,0.f); + if (iter == mValue.end() || shouldChange(iter->second,vec)) + { + glUniform2fARB(location, x,y); + mValue[location] = vec; + } + } + +} + +void LLGLSLShader::uniform3f(const string& uniform, GLfloat x, GLfloat y, GLfloat z) +{ + GLint location = getUniformLocation(uniform); + + if (location >= 0) + { + std::map<GLint, LLVector4>::iterator iter = mValue.find(location); + LLVector4 vec(x,y,z,0.f); + if (iter == mValue.end() || shouldChange(iter->second,vec)) + { + glUniform3fARB(location, x,y,z); + mValue[location] = vec; + } + } +} + +void LLGLSLShader::uniform4f(const string& uniform, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + GLint location = getUniformLocation(uniform); + + if (location >= 0) + { + std::map<GLint, LLVector4>::iterator iter = mValue.find(location); + LLVector4 vec(x,y,z,w); + if (iter == mValue.end() || shouldChange(iter->second,vec)) + { + glUniform4fARB(location, x,y,z,w); + mValue[location] = vec; + } + } +} + +void LLGLSLShader::uniform1fv(const string& uniform, U32 count, const GLfloat* v) +{ + GLint location = getUniformLocation(uniform); + + if (location >= 0) + { + std::map<GLint, LLVector4>::iterator iter = mValue.find(location); + LLVector4 vec(v[0],0.f,0.f,0.f); + if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1) + { + glUniform1fvARB(location, count, v); + mValue[location] = vec; + } + } +} + +void LLGLSLShader::uniform2fv(const string& uniform, U32 count, const GLfloat* v) +{ + GLint location = getUniformLocation(uniform); + + if (location >= 0) + { + std::map<GLint, LLVector4>::iterator iter = mValue.find(location); + LLVector4 vec(v[0],v[1],0.f,0.f); + if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1) + { + glUniform2fvARB(location, count, v); + mValue[location] = vec; + } + } +} + +void LLGLSLShader::uniform3fv(const string& uniform, U32 count, const GLfloat* v) +{ + GLint location = getUniformLocation(uniform); + + if (location >= 0) + { + std::map<GLint, LLVector4>::iterator iter = mValue.find(location); + LLVector4 vec(v[0],v[1],v[2],0.f); + if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1) + { + glUniform3fvARB(location, count, v); + mValue[location] = vec; + } + } +} + +void LLGLSLShader::uniform4fv(const string& uniform, U32 count, const GLfloat* v) +{ + GLint location = getUniformLocation(uniform); + + if (location >= 0) + { + LLVector4 vec(v); + std::map<GLint, LLVector4>::iterator iter = mValue.find(location); + if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1) + { + glUniform4fvARB(location, count, v); + mValue[location] = vec; + } + } +} + +void LLGLSLShader::uniformMatrix2fv(const string& uniform, U32 count, GLboolean transpose, const GLfloat* v) +{ + GLint location = getUniformLocation(uniform); + + if (location >= 0) + { + glUniformMatrix2fvARB(location, count, transpose, v); + } +} + +void LLGLSLShader::uniformMatrix3fv(const string& uniform, U32 count, GLboolean transpose, const GLfloat* v) +{ + GLint location = getUniformLocation(uniform); + + if (location >= 0) + { + glUniformMatrix3fvARB(location, count, transpose, v); + } +} + +void LLGLSLShader::uniformMatrix4fv(const string& uniform, U32 count, GLboolean transpose, const GLfloat* v) +{ + GLint location = getUniformLocation(uniform); + + if (location >= 0) + { + glUniformMatrix4fvARB(location, count, transpose, v); + } +} + + +void LLGLSLShader::vertexAttrib4f(U32 index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + if (mAttribute[index] > 0) + { + glVertexAttrib4fARB(mAttribute[index], x, y, z, w); + } +} + +void LLGLSLShader::vertexAttrib4fv(U32 index, GLfloat* v) +{ + if (mAttribute[index] > 0) + { + glVertexAttrib4fvARB(mAttribute[index], v); + } +} diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h new file mode 100644 index 0000000000..c78188ba87 --- /dev/null +++ b/indra/llrender/llglslshader.h @@ -0,0 +1,139 @@ +/** + * @file llglslshader.h + * @brief GLSL shader wrappers + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2007, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLGLSLSHADER_H +#define LL_LLGLSLSHADER_H + +#include "llgl.h" + +class LLShaderFeatures +{ +public: + bool calculatesLighting; + bool calculatesAtmospherics; + bool hasLighting; // implies no transport (it's possible to have neither though) + bool isShiny; + bool isFullbright; // implies no lighting + bool isSpecular; + bool hasWaterFog; // implies no gamma + bool hasTransport; // implies no lighting (it's possible to have neither though) + bool hasSkinning; + bool hasAtmospherics; + bool hasGamma; + + // char numLights; + + LLShaderFeatures(); +}; + +class LLGLSLShader +{ +public: + + enum + { + SG_DEFAULT = 0, + SG_SKY, + SG_WATER + }; + + LLGLSLShader(); + + void unload(); + BOOL createShader(std::vector<std::string> * attributes, + std::vector<std::string> * uniforms); + BOOL attachObject(std::string object); + void attachObject(GLhandleARB object); + void attachObjects(GLhandleARB* objects = NULL, S32 count = 0); + BOOL mapAttributes(const std::vector<std::string> * attributes); + BOOL mapUniforms(const std::vector<std::string> * uniforms); + void mapUniform(GLint index, const std::vector<std::string> * uniforms); + void uniform1f(U32 index, GLfloat v); + void uniform2f(U32 index, GLfloat x, GLfloat y); + void uniform3f(U32 index, GLfloat x, GLfloat y, GLfloat z); + void uniform4f(U32 index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void uniform1fv(U32 index, U32 count, const GLfloat* v); + void uniform2fv(U32 index, U32 count, const GLfloat* v); + void uniform3fv(U32 index, U32 count, const GLfloat* v); + void uniform4fv(U32 index, U32 count, const GLfloat* v); + void uniform1f(const std::string& uniform, GLfloat v); + void uniform2f(const std::string& uniform, GLfloat x, GLfloat y); + void uniform3f(const std::string& uniform, GLfloat x, GLfloat y, GLfloat z); + void uniform4f(const std::string& uniform, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void uniform1fv(const std::string& uniform, U32 count, const GLfloat* v); + void uniform2fv(const std::string& uniform, U32 count, const GLfloat* v); + void uniform3fv(const std::string& uniform, U32 count, const GLfloat* v); + void uniform4fv(const std::string& uniform, U32 count, const GLfloat* v); + void uniformMatrix2fv(U32 index, U32 count, GLboolean transpose, const GLfloat *v); + void uniformMatrix3fv(U32 index, U32 count, GLboolean transpose, const GLfloat *v); + void uniformMatrix4fv(U32 index, U32 count, GLboolean transpose, const GLfloat *v); + void uniformMatrix2fv(const std::string& uniform, U32 count, GLboolean transpose, const GLfloat *v); + void uniformMatrix3fv(const std::string& uniform, U32 count, GLboolean transpose, const GLfloat *v); + void uniformMatrix4fv(const std::string& uniform, U32 count, GLboolean transpose, const GLfloat *v); + + void vertexAttrib4f(U32 index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void vertexAttrib4fv(U32 index, GLfloat* v); + + GLint getUniformLocation(const std::string& uniform); + + GLint mapUniformTextureChannel(GLint location, GLenum type); + + + //enable/disable texture channel for specified uniform + //if given texture uniform is active in the shader, + //the corresponding channel will be active upon return + //returns channel texture is enabled in from [0-MAX) + S32 enableTexture(S32 uniform, S32 mode = GL_TEXTURE_2D); + S32 disableTexture(S32 uniform, S32 mode = GL_TEXTURE_2D); + + BOOL link(BOOL suppress_errors = FALSE); + void bind(); + void unbind(); + + // Unbinds any previously bound shader by explicitly binding no shader. + static void bindNoShader(void); + + GLhandleARB mProgramObject; + std::vector<GLint> mAttribute; //lookup table of attribute enum to attribute channel + std::vector<GLint> mUniform; //lookup table of uniform enum to uniform location + std::map<std::string, GLint> mUniformMap; //lookup map of uniform name to uniform location + std::map<GLint, LLVector4> mValue; //lookup map of uniform location to last known value + std::vector<GLint> mTexture; + S32 mActiveTextureChannels; + S32 mShaderLevel; + S32 mShaderGroup; + BOOL mUniformsDirty; + LLShaderFeatures mFeatures; + std::vector< std::pair< std::string, GLenum > > mShaderFiles; + std::string mName; +}; + +#endif diff --git a/indra/llrender/llglstates.h b/indra/llrender/llglstates.h new file mode 100644 index 0000000000..907e4ee2e6 --- /dev/null +++ b/indra/llrender/llglstates.h @@ -0,0 +1,302 @@ +/** + * @file llglstates.h + * @brief LLGL states definitions + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2007, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +//THIS HEADER SHOULD ONLY BE INCLUDED FROM llgl.h +#ifndef LL_LLGLSTATES_H +#define LL_LLGLSTATES_H + +#include "llimagegl.h" + +//---------------------------------------------------------------------------- + +class LLGLDepthTest +{ + // Enabled by default +public: + LLGLDepthTest(GLboolean depth_enabled, GLboolean write_enabled = GL_TRUE, GLenum depth_func = GL_LEQUAL); + + ~LLGLDepthTest(); + + GLboolean mPrevDepthEnabled; + GLenum mPrevDepthFunc; + GLboolean mPrevWriteEnabled; +private: + static GLboolean sDepthEnabled; // defaults to GL_FALSE + static GLenum sDepthFunc; // defaults to GL_LESS + static GLboolean sWriteEnabled; // defaults to GL_TRUE +}; + +//---------------------------------------------------------------------------- + +class LLGLSDefault +{ +protected: + LLGLEnable mColorMaterial; + LLGLDisable mAlphaTest, mBlend, mCullFace, mDither, mFog, + mLineSmooth, mLineStipple, mNormalize, mPolygonSmooth, + mTextureGenQ, mTextureGenR, mTextureGenS, mTextureGenT, + mGLMultisample; +public: + LLGLSDefault() + : + // Enable + mColorMaterial(GL_COLOR_MATERIAL), + // Disable + mAlphaTest(GL_ALPHA_TEST), + mBlend(GL_BLEND), + mCullFace(GL_CULL_FACE), + mDither(GL_DITHER), + mFog(GL_FOG), + mLineSmooth(GL_LINE_SMOOTH), + mLineStipple(GL_LINE_STIPPLE), + mNormalize(GL_NORMALIZE), + mPolygonSmooth(GL_POLYGON_SMOOTH), + mTextureGenQ(GL_TEXTURE_GEN_Q), + mTextureGenR(GL_TEXTURE_GEN_R), + mTextureGenS(GL_TEXTURE_GEN_S), + mTextureGenT(GL_TEXTURE_GEN_T), + mGLMultisample(GL_MULTISAMPLE_ARB) + { } +}; + +class LLGLSNoTexture +{ +public: + LLGLSNoTexture() + { LLImageGL::unbindTexture(0); } +}; + +class LLGLSObjectSelect +{ +protected: + LLGLDisable mBlend, mFog, mAlphaTest; + LLGLEnable mCullFace; +public: + LLGLSObjectSelect() + : mBlend(GL_BLEND), mFog(GL_FOG), + mAlphaTest(GL_ALPHA_TEST), + mCullFace(GL_CULL_FACE) + { LLImageGL::unbindTexture(0); } +}; + +class LLGLSObjectSelectAlpha +{ +protected: + LLGLEnable mAlphaTest; +public: + LLGLSObjectSelectAlpha() + : mAlphaTest(GL_ALPHA_TEST) + {} +}; + +//---------------------------------------------------------------------------- + +class LLGLSUIDefault +{ +protected: + LLGLEnable mBlend, mAlphaTest; + LLGLDisable mCullFace; + LLGLDepthTest mDepthTest; +public: + LLGLSUIDefault() + : mBlend(GL_BLEND), mAlphaTest(GL_ALPHA_TEST), + mCullFace(GL_CULL_FACE), + mDepthTest(GL_FALSE, GL_TRUE, GL_LEQUAL) + {} +}; + +class LLGLSNoAlphaTest // : public LLGLSUIDefault +{ +protected: + LLGLDisable mAlphaTest; +public: + LLGLSNoAlphaTest() + : mAlphaTest(GL_ALPHA_TEST) + {} +}; + +class LLGLSNoTextureNoAlphaTest // : public LLGLSUIDefault +{ +protected: + LLGLDisable mAlphaTest; +public: + LLGLSNoTextureNoAlphaTest() + : mAlphaTest(GL_ALPHA_TEST) + + { LLImageGL::unbindTexture(0); } +}; + +//---------------------------------------------------------------------------- + +class LLGLSFog +{ +protected: + LLGLEnable mFog; +public: + LLGLSFog() + : mFog(GL_FOG) + {} +}; + +class LLGLSNoFog +{ +protected: + LLGLDisable mFog; +public: + LLGLSNoFog() + : mFog(GL_FOG) + {} +}; + +//---------------------------------------------------------------------------- + +class LLGLSPipeline +{ +protected: + LLGLEnable mCullFace; + LLGLDepthTest mDepthTest; +public: + LLGLSPipeline() + : mCullFace(GL_CULL_FACE), + mDepthTest(GL_TRUE, GL_TRUE, GL_LEQUAL) + { } +}; + +class LLGLSPipelineAlpha // : public LLGLSPipeline +{ +protected: + LLGLEnable mBlend, mAlphaTest; +public: + LLGLSPipelineAlpha() + : mBlend(GL_BLEND), + mAlphaTest(GL_ALPHA_TEST) + { } +}; + +class LLGLSPipelineEmbossBump +{ +protected: + LLGLDisable mFog; +public: + LLGLSPipelineEmbossBump() + : mFog(GL_FOG) + { } +}; + +class LLGLSPipelineSelection +{ +protected: + LLGLDisable mCullFace; +public: + LLGLSPipelineSelection() + : mCullFace(GL_CULL_FACE) + {} +}; + +class LLGLSPipelineAvatar +{ +protected: + LLGLEnable mNormalize; +public: + LLGLSPipelineAvatar() + : mNormalize(GL_NORMALIZE) + {} +}; + +class LLGLSPipelineSkyBox +{ +protected: + LLGLDisable mAlphaTest, mCullFace, mFog; +public: + LLGLSPipelineSkyBox() + : mAlphaTest(GL_ALPHA_TEST), mCullFace(GL_CULL_FACE), mFog(GL_FOG) + { } +}; + +class LLGLSTracker +{ +protected: + LLGLEnable mCullFace, mBlend, mAlphaTest; +public: + LLGLSTracker() : + mCullFace(GL_CULL_FACE), + mBlend(GL_BLEND), + mAlphaTest(GL_ALPHA_TEST) + + { LLImageGL::unbindTexture(0); } +}; + +//---------------------------------------------------------------------------- + +class LLGLSSpecular +{ +public: + LLGLSSpecular(const LLColor4& color, F32 shininess) + { + if (shininess > 0.0f) + { + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, color.mV); + S32 shiny = (S32)(shininess*128.f); + shiny = llclamp(shiny,0,128); + glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, shiny); + } + } + ~LLGLSSpecular() + { + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, LLColor4(0.f,0.f,0.f,0.f).mV); + glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 0); + } +}; + +//---------------------------------------------------------------------------- + + +class LLGLSBlendFunc : public LLGLSPipeline { +protected: + GLint mSavedSrc, mSavedDst; + LLGLEnable mBlend; + +public: + LLGLSBlendFunc(GLenum srcFunc, GLenum dstFunc) : + mBlend(GL_BLEND) + { + glGetIntegerv(GL_BLEND_SRC, &mSavedSrc); + glGetIntegerv(GL_BLEND_DST, &mSavedDst); + glBlendFunc(srcFunc, dstFunc); + } + + ~LLGLSBlendFunc(void) { + glBlendFunc(mSavedSrc, mSavedDst); + } +}; + + +#endif diff --git a/indra/llrender/llgltypes.h b/indra/llrender/llgltypes.h new file mode 100644 index 0000000000..42050cf90f --- /dev/null +++ b/indra/llrender/llgltypes.h @@ -0,0 +1,44 @@ +/** + * @file llgltypes.h + * @brief LLGL definition + * + * $LicenseInfo:firstyear=2006&license=viewergpl$ + * + * Copyright (c) 2006-2007, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LLGLTYPES_H +#define LLGLTYPES_H + +#define MAX_GL_TEXTURE_UNITS 16 + +typedef U32 LLGLenum; +typedef U32 LLGLuint; +typedef S32 LLGLint; +typedef F32 LLGLfloat; +typedef F64 LLGLdouble; +typedef U8 LLGLboolean; + +#endif diff --git a/indra/llrender/llpostprocess.cpp b/indra/llrender/llpostprocess.cpp new file mode 100644 index 0000000000..7c14b57fff --- /dev/null +++ b/indra/llrender/llpostprocess.cpp @@ -0,0 +1,574 @@ +/** + * @file llpostprocess.cpp + * @brief LLPostProcess class implementation + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2007-2007, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llpostprocess.h" +#include "llglslshader.h" +#include "llsdserialize.h" +#include "llrender.h" + + +LLPostProcess * gPostProcess = NULL; + + +static const unsigned int NOISE_SIZE = 512; + +/// CALCULATING LUMINANCE (Using NTSC lum weights) +/// http://en.wikipedia.org/wiki/Luma_%28video%29 +static const float LUMINANCE_R = 0.299f; +static const float LUMINANCE_G = 0.587f; +static const float LUMINANCE_B = 0.114f; + +static const char * const XML_FILENAME = "postprocesseffects.xml"; + +LLPostProcess::LLPostProcess(void) : + sceneRenderTexture(0), noiseTexture(0), + tempBloomTexture(0), + initialized(false), + mAllEffects(LLSD::emptyMap()), + screenW(1), screenH(1) +{ + /* Do nothing. Needs to be updated to use our current shader system, and to work with the move into llrender. + std::string pathName(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight", XML_FILENAME)); + LL_DEBUGS2("AppInit", "Shaders") << "Loading PostProcess Effects settings from " << pathName << LL_ENDL; + + llifstream effectsXML(pathName); + + if (effectsXML) + { + LLPointer<LLSDParser> parser = new LLSDXMLParser(); + + parser->parse(effectsXML, mAllEffects, LLSDSerialize::SIZE_UNLIMITED); + } + + if (!mAllEffects.has("default")) + { + LLSD & defaultEffect = (mAllEffects["default"] = LLSD::emptyMap()); + + defaultEffect["enable_night_vision"] = LLSD::Boolean(false); + defaultEffect["enable_bloom"] = LLSD::Boolean(false); + defaultEffect["enable_color_filter"] = LLSD::Boolean(false); + + /// NVG Defaults + defaultEffect["brightness_multiplier"] = 3.0; + defaultEffect["noise_size"] = 25.0; + defaultEffect["noise_strength"] = 0.4; + + // TODO BTest potentially add this to tweaks? + noiseTextureScale = 1.0f; + + /// Bloom Defaults + defaultEffect["extract_low"] = 0.95; + defaultEffect["extract_high"] = 1.0; + defaultEffect["bloom_width"] = 2.25; + defaultEffect["bloom_strength"] = 1.5; + + /// Color Filter Defaults + defaultEffect["brightness"] = 1.0; + defaultEffect["contrast"] = 1.0; + defaultEffect["saturation"] = 1.0; + + LLSD& contrastBase = (defaultEffect["contrast_base"] = LLSD::emptyArray()); + contrastBase.append(1.0); + contrastBase.append(1.0); + contrastBase.append(1.0); + contrastBase.append(0.5); + } + + setSelectedEffect("default"); + */ +} + +LLPostProcess::~LLPostProcess(void) +{ + glDeleteTextures(1, &sceneRenderTexture); + glDeleteTextures(1, &noiseTexture); + glDeleteTextures(1, &tempBloomTexture); +} + +// static +void LLPostProcess::initClass(void) +{ + //this will cause system to crash at second time login + //if first time login fails due to network connection --- bao + //***llassert_always(gPostProcess == NULL); + //replaced by the following line: + if(gPostProcess) + return ; + + + gPostProcess = new LLPostProcess(); +} + +// static +void LLPostProcess::cleanupClass() +{ + delete gPostProcess; + gPostProcess = NULL; +} + +void LLPostProcess::setSelectedEffect(std::string const & effectName) +{ + mSelectedEffectName = effectName; + static_cast<LLSD &>(tweaks) = mAllEffects[effectName]; +} + +void LLPostProcess::saveEffect(std::string const & effectName) +{ + /* Do nothing. Needs to be updated to use our current shader system, and to work with the move into llrender. + mAllEffects[effectName] = tweaks; + + std::string pathName(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight", XML_FILENAME)); + //llinfos << "Saving PostProcess Effects settings to " << pathName << llendl; + + llofstream effectsXML(pathName); + + LLPointer<LLSDFormatter> formatter = new LLSDXMLFormatter(); + + formatter->format(mAllEffects, effectsXML); + */ +} + +void LLPostProcess::apply(unsigned int width, unsigned int height) +{ + if (!initialized || width != screenW || height != screenH){ + initialize(width, height); + } + if (shadersEnabled()){ + doEffects(); + } +} + +void LLPostProcess::initialize(unsigned int width, unsigned int height) +{ + screenW = width; + screenH = height; + createTexture(sceneRenderTexture, screenW, screenH); + initialized = true; + + checkError(); + createNightVisionShader(); + createBloomShader(); + createColorFilterShader(); + checkError(); +} + +inline bool LLPostProcess::shadersEnabled(void) +{ + return (tweaks.useColorFilter().asBoolean() || + tweaks.useNightVisionShader().asBoolean() || + tweaks.useBloomShader().asBoolean() ); + +} + +void LLPostProcess::applyShaders(void) +{ + if (tweaks.useColorFilter()){ + applyColorFilterShader(); + checkError(); + } + if (tweaks.useNightVisionShader()){ + /// If any of the above shaders have been called update the frame buffer; + if (tweaks.useColorFilter()){ + copyFrameBuffer(sceneRenderTexture, screenW, screenH); + } + applyNightVisionShader(); + checkError(); + } + if (tweaks.useBloomShader()){ + /// If any of the above shaders have been called update the frame buffer; + if (tweaks.useColorFilter().asBoolean() || tweaks.useNightVisionShader().asBoolean()){ + copyFrameBuffer(sceneRenderTexture, screenW, screenH); + } + applyBloomShader(); + checkError(); + } +} + +void LLPostProcess::applyColorFilterShader(void) +{ + /* Do nothing. Needs to be updated to use our current shader system, and to work with the move into llrender. + gPostColorFilterProgram.bind(); + + gGL.getTexUnit(0)->activate(); + glEnable(GL_TEXTURE_RECTANGLE_ARB); + + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, sceneRenderTexture); + + getShaderUniforms(colorFilterUniforms, gPostColorFilterProgram.mProgramObject); + glUniform1iARB(colorFilterUniforms["RenderTexture"], 0); + glUniform1fARB(colorFilterUniforms["brightness"], tweaks.getBrightness()); + glUniform1fARB(colorFilterUniforms["contrast"], tweaks.getContrast()); + float baseI = (tweaks.getContrastBaseR() + tweaks.getContrastBaseG() + tweaks.getContrastBaseB()) / 3.0f; + baseI = tweaks.getContrastBaseIntensity() / ((baseI < 0.001f) ? 0.001f : baseI); + float baseR = tweaks.getContrastBaseR() * baseI; + float baseG = tweaks.getContrastBaseG() * baseI; + float baseB = tweaks.getContrastBaseB() * baseI; + glUniform3fARB(colorFilterUniforms["contrastBase"], baseR, baseG, baseB); + glUniform1fARB(colorFilterUniforms["saturation"], tweaks.getSaturation()); + glUniform3fARB(colorFilterUniforms["lumWeights"], LUMINANCE_R, LUMINANCE_G, LUMINANCE_B); + + LLGLEnable blend(GL_BLEND); + gGL.setSceneBlendType(LLRender::BT_REPLACE); + LLGLDepthTest depth(GL_FALSE); + + /// Draw a screen space quad + drawOrthoQuad(screenW, screenH, QUAD_NORMAL); + gPostColorFilterProgram.unbind(); + */ +} + +void LLPostProcess::createColorFilterShader(void) +{ + /// Define uniform names + colorFilterUniforms["RenderTexture"] = 0; + colorFilterUniforms["brightness"] = 0; + colorFilterUniforms["contrast"] = 0; + colorFilterUniforms["contrastBase"] = 0; + colorFilterUniforms["saturation"] = 0; + colorFilterUniforms["lumWeights"] = 0; +} + +void LLPostProcess::applyNightVisionShader(void) +{ + /* Do nothing. Needs to be updated to use our current shader system, and to work with the move into llrender. + gPostNightVisionProgram.bind(); + + gGL.getTexUnit(0)->activate(); + glEnable(GL_TEXTURE_RECTANGLE_ARB); + + getShaderUniforms(nightVisionUniforms, gPostNightVisionProgram.mProgramObject); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, sceneRenderTexture); + glUniform1iARB(nightVisionUniforms["RenderTexture"], 0); + + gGL.getTexUnit(1)->activate(); + glEnable(GL_TEXTURE_2D); + + glBindTexture(GL_TEXTURE_2D, noiseTexture); + glUniform1iARB(nightVisionUniforms["NoiseTexture"], 1); + + + glUniform1fARB(nightVisionUniforms["brightMult"], tweaks.getBrightMult()); + glUniform1fARB(nightVisionUniforms["noiseStrength"], tweaks.getNoiseStrength()); + noiseTextureScale = 0.01f + ((101.f - tweaks.getNoiseSize()) / 100.f); + noiseTextureScale *= (screenH / NOISE_SIZE); + + + glUniform3fARB(nightVisionUniforms["lumWeights"], LUMINANCE_R, LUMINANCE_G, LUMINANCE_B); + + LLGLEnable blend(GL_BLEND); + gGL.setSceneBlendType(LLRender::BT_REPLACE); + LLGLDepthTest depth(GL_FALSE); + + /// Draw a screen space quad + drawOrthoQuad(screenW, screenH, QUAD_NOISE); + gPostNightVisionProgram.unbind(); + gGL.getTexUnit(0)->activate(); + */ +} + +void LLPostProcess::createNightVisionShader(void) +{ + /// Define uniform names + nightVisionUniforms["RenderTexture"] = 0; + nightVisionUniforms["NoiseTexture"] = 0; + nightVisionUniforms["brightMult"] = 0; + nightVisionUniforms["noiseStrength"] = 0; + nightVisionUniforms["lumWeights"] = 0; + + createNoiseTexture(noiseTexture); +} + +void LLPostProcess::applyBloomShader(void) +{ + +} + +void LLPostProcess::createBloomShader(void) +{ + createTexture(tempBloomTexture, unsigned(screenW * 0.5), unsigned(screenH * 0.5)); + + /// Create Bloom Extract Shader + bloomExtractUniforms["RenderTexture"] = 0; + bloomExtractUniforms["extractLow"] = 0; + bloomExtractUniforms["extractHigh"] = 0; + bloomExtractUniforms["lumWeights"] = 0; + + /// Create Bloom Blur Shader + bloomBlurUniforms["RenderTexture"] = 0; + bloomBlurUniforms["bloomStrength"] = 0; + bloomBlurUniforms["texelSize"] = 0; + bloomBlurUniforms["blurDirection"] = 0; + bloomBlurUniforms["blurWidth"] = 0; +} + +void LLPostProcess::getShaderUniforms(glslUniforms & uniforms, GLhandleARB & prog) +{ + /// Find uniform locations and insert into map + std::map<const char *, GLuint>::iterator i; + for (i = uniforms.begin(); i != uniforms.end(); ++i){ + i->second = glGetUniformLocationARB(prog, i->first); + } +} + +void LLPostProcess::doEffects(void) +{ + /// Save GL State + glPushAttrib(GL_ALL_ATTRIB_BITS); + glPushClientAttrib(GL_ALL_ATTRIB_BITS); + + /// Copy the screen buffer to the render texture + copyFrameBuffer(sceneRenderTexture, screenW, screenH); + + /// Clear the frame buffer. + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + + /// Change to an orthogonal view + viewOrthogonal(screenW, screenH); + + checkError(); + applyShaders(); + + LLGLSLShader::bindNoShader(); + checkError(); + + /// Change to a perspective view + viewPerspective(); + + /// Reset GL State + glPopClientAttrib(); + glPopAttrib(); + checkError(); +} + +void LLPostProcess::copyFrameBuffer(GLuint & texture, unsigned int width, unsigned int height) +{ + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture); + glCopyTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, 0, 0, width, height, 0); +} + +void LLPostProcess::drawOrthoQuad(unsigned int width, unsigned int height, QuadType type) +{ +#if 0 + float noiseX = 0.f; + float noiseY = 0.f; + float screenRatio = 1.0f; + + if (type == QUAD_NOISE){ + noiseX = ((float) rand() / (float) RAND_MAX); + noiseY = ((float) rand() / (float) RAND_MAX); + screenRatio = (float) width / (float) height; + } + + + glBegin(GL_QUADS); + if (type != QUAD_BLOOM_EXTRACT){ + glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 0.f, (GLfloat) height); + } else { + glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 0.f, (GLfloat) height * 2.0f); + } + if (type == QUAD_NOISE){ + glMultiTexCoord2fARB(GL_TEXTURE1_ARB, + noiseX, + noiseTextureScale + noiseY); + } else if (type == QUAD_BLOOM_COMBINE){ + glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 0.f, (GLfloat) height * 0.5f); + } + glVertex2f(0.f, (GLfloat) screenH - height); + + if (type != QUAD_BLOOM_EXTRACT){ + glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 0.f, 0.f); + } else { + glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 0.f, 0.f); + } + if (type == QUAD_NOISE){ + glMultiTexCoord2fARB(GL_TEXTURE1_ARB, + noiseX, + noiseY); + } else if (type == QUAD_BLOOM_COMBINE){ + glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 0.f, 0.f); + } + glVertex2f(0.f, (GLfloat) height + (screenH - height)); + + + if (type != QUAD_BLOOM_EXTRACT){ + glMultiTexCoord2fARB(GL_TEXTURE0_ARB, (GLfloat) width, 0.f); + } else { + glMultiTexCoord2fARB(GL_TEXTURE0_ARB, (GLfloat) width * 2.0f, 0.f); + } + if (type == QUAD_NOISE){ + glMultiTexCoord2fARB(GL_TEXTURE1_ARB, + screenRatio * noiseTextureScale + noiseX, + noiseY); + } else if (type == QUAD_BLOOM_COMBINE){ + glMultiTexCoord2fARB(GL_TEXTURE1_ARB, (GLfloat) width * 0.5f, 0.f); + } + glVertex2f((GLfloat) width, (GLfloat) height + (screenH - height)); + + + if (type != QUAD_BLOOM_EXTRACT){ + glMultiTexCoord2fARB(GL_TEXTURE0_ARB, (GLfloat) width, (GLfloat) height); + } else { + glMultiTexCoord2fARB(GL_TEXTURE0_ARB, (GLfloat) width * 2.0f, (GLfloat) height * 2.0f); + } + if (type == QUAD_NOISE){ + glMultiTexCoord2fARB(GL_TEXTURE1_ARB, + screenRatio * noiseTextureScale + noiseX, + noiseTextureScale + noiseY); + } else if (type == QUAD_BLOOM_COMBINE){ + glMultiTexCoord2fARB(GL_TEXTURE1_ARB, (GLfloat) width * 0.5f, (GLfloat) height * 0.5f); + } + glVertex2f((GLfloat) width, (GLfloat) screenH - height); + glEnd(); +#endif +} + +void LLPostProcess::viewOrthogonal(unsigned int width, unsigned int height) +{ + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glOrtho( 0.f, (GLdouble) width , (GLdouble) height , 0.f, -1.f, 1.f ); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); +} + +void LLPostProcess::viewPerspective(void) +{ + glMatrixMode( GL_PROJECTION ); + glPopMatrix(); + glMatrixMode( GL_MODELVIEW ); + glPopMatrix(); +} + +void LLPostProcess::changeOrthogonal(unsigned int width, unsigned int height) +{ + viewPerspective(); + viewOrthogonal(width, height); +} + +void LLPostProcess::createTexture(GLuint & texture, unsigned int width, unsigned int height) +{ + if (texture != 0){ + glDeleteTextures(1, &texture); + } + + std::vector<GLubyte> data(width * height * 4, 0); + + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture); + glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, width, height, 0, + GL_RGBA, GL_UNSIGNED_BYTE, &data[0]); + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MIN_FILTER,GL_LINEAR); + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MAG_FILTER,GL_LINEAR); + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); +} + +void LLPostProcess::createNoiseTexture(GLuint & texture) +{ + if (texture != 0){ + glDeleteTextures(1, &texture); + } + glGenTextures(1, &texture); + + std::vector<GLubyte> buffer(NOISE_SIZE * NOISE_SIZE); + for (unsigned int i = 0; i < NOISE_SIZE; i++){ + for (unsigned int k = 0; k < NOISE_SIZE; k++){ + buffer[(i * NOISE_SIZE) + k] = (GLubyte)((double) rand() / ((double) RAND_MAX + 1.f) * 255.f); + } + } + glBindTexture(GL_TEXTURE_2D, texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, NOISE_SIZE, NOISE_SIZE, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &buffer[0]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); +} + +bool LLPostProcess::checkError(void) +{ + GLenum glErr; + bool retCode = false; + + glErr = glGetError(); + while (glErr != GL_NO_ERROR) + { + // shaderErrorLog << (const char *) gluErrorString(glErr) << std::endl; + char const * err_str_raw = (const char *) gluErrorString(glErr); + + if(err_str_raw == NULL) + { + std::ostringstream err_builder; + err_builder << "unknown error number " << glErr; + mShaderErrorString = err_builder.str(); + } + else + { + mShaderErrorString = err_str_raw; + } + + retCode = true; + glErr = glGetError(); + } + return retCode; +} + +void LLPostProcess::checkShaderError(GLhandleARB shader) +{ + GLint infologLength = 0; + GLint charsWritten = 0; + GLchar *infoLog; + + checkError(); // Check for OpenGL errors + + glGetObjectParameterivARB(shader, GL_OBJECT_INFO_LOG_LENGTH_ARB, &infologLength); + + checkError(); // Check for OpenGL errors + + if (infologLength > 0) + { + infoLog = (GLchar *)malloc(infologLength); + if (infoLog == NULL) + { + /// Could not allocate infolog buffer + return; + } + glGetInfoLogARB(shader, infologLength, &charsWritten, infoLog); + // shaderErrorLog << (char *) infoLog << std::endl; + mShaderErrorString = (char *) infoLog; + free(infoLog); + } + checkError(); // Check for OpenGL errors +} diff --git a/indra/llrender/llpostprocess.h b/indra/llrender/llpostprocess.h new file mode 100644 index 0000000000..b31333a28b --- /dev/null +++ b/indra/llrender/llpostprocess.h @@ -0,0 +1,268 @@ +/** + * @file llpostprocess.h + * @brief LLPostProcess class definition + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2007-2007, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_POSTPROCESS_H +#define LL_POSTPROCESS_H + +#include <map> +#include <fstream> +#include "llgl.h" +#include "llglheaders.h" + +class LLPostProcess +{ +public: + + typedef enum _QuadType { + QUAD_NORMAL, + QUAD_NOISE, + QUAD_BLOOM_EXTRACT, + QUAD_BLOOM_COMBINE + } QuadType; + + /// GLSL Shader Encapsulation Struct + typedef std::map<const char *, GLuint> glslUniforms; + + struct PostProcessTweaks : public LLSD { + inline PostProcessTweaks() : LLSD(LLSD::emptyMap()) + { + } + + inline LLSD & brightMult() { + return (*this)["brightness_multiplier"]; + } + + inline LLSD & noiseStrength() { + return (*this)["noise_strength"]; + } + + inline LLSD & noiseSize() { + return (*this)["noise_size"]; + } + + inline LLSD & extractLow() { + return (*this)["extract_low"]; + } + + inline LLSD & extractHigh() { + return (*this)["extract_high"]; + } + + inline LLSD & bloomWidth() { + return (*this)["bloom_width"]; + } + + inline LLSD & bloomStrength() { + return (*this)["bloom_strength"]; + } + + inline LLSD & brightness() { + return (*this)["brightness"]; + } + + inline LLSD & contrast() { + return (*this)["contrast"]; + } + + inline LLSD & contrastBaseR() { + return (*this)["contrast_base"][0]; + } + + inline LLSD & contrastBaseG() { + return (*this)["contrast_base"][1]; + } + + inline LLSD & contrastBaseB() { + return (*this)["contrast_base"][2]; + } + + inline LLSD & contrastBaseIntensity() { + return (*this)["contrast_base"][3]; + } + + inline LLSD & saturation() { + return (*this)["saturation"]; + } + + inline LLSD & useNightVisionShader() { + return (*this)["enable_night_vision"]; + } + + inline LLSD & useBloomShader() { + return (*this)["enable_bloom"]; + } + + inline LLSD & useColorFilter() { + return (*this)["enable_color_filter"]; + } + + + inline F32 getBrightMult() const { + return F32((*this)["brightness_multiplier"].asReal()); + } + + inline F32 getNoiseStrength() const { + return F32((*this)["noise_strength"].asReal()); + } + + inline F32 getNoiseSize() const { + return F32((*this)["noise_size"].asReal()); + } + + inline F32 getExtractLow() const { + return F32((*this)["extract_low"].asReal()); + } + + inline F32 getExtractHigh() const { + return F32((*this)["extract_high"].asReal()); + } + + inline F32 getBloomWidth() const { + return F32((*this)["bloom_width"].asReal()); + } + + inline F32 getBloomStrength() const { + return F32((*this)["bloom_strength"].asReal()); + } + + inline F32 getBrightness() const { + return F32((*this)["brightness"].asReal()); + } + + inline F32 getContrast() const { + return F32((*this)["contrast"].asReal()); + } + + inline F32 getContrastBaseR() const { + return F32((*this)["contrast_base"][0].asReal()); + } + + inline F32 getContrastBaseG() const { + return F32((*this)["contrast_base"][1].asReal()); + } + + inline F32 getContrastBaseB() const { + return F32((*this)["contrast_base"][2].asReal()); + } + + inline F32 getContrastBaseIntensity() const { + return F32((*this)["contrast_base"][3].asReal()); + } + + inline F32 getSaturation() const { + return F32((*this)["saturation"].asReal()); + } + + }; + + GLuint sceneRenderTexture; + GLuint noiseTexture; + GLuint tempBloomTexture; + bool initialized; + PostProcessTweaks tweaks; + + // the map of all availible effects + LLSD mAllEffects; + +public: + LLPostProcess(void); + + ~LLPostProcess(void); + + void apply(unsigned int width, unsigned int height); + + /// Perform global initialization for this class. + static void initClass(void); + + // Cleanup of global data that's only inited once per class. + static void cleanupClass(); + + void setSelectedEffect(std::string const & effectName); + + inline std::string const & getSelectedEffect(void) const { + return mSelectedEffectName; + } + + void saveEffect(std::string const & effectName); + +private: + /// read in from file + std::string mShaderErrorString; + unsigned int screenW; + unsigned int screenH; + + float noiseTextureScale; + + /// Shader Uniforms + glslUniforms nightVisionUniforms; + glslUniforms bloomExtractUniforms; + glslUniforms bloomBlurUniforms; + glslUniforms colorFilterUniforms; + + // the name of currently selected effect in mAllEffects + // invariant: tweaks == mAllEffects[mSelectedEffectName] + std::string mSelectedEffectName; + + /// General functions + void initialize(unsigned int width, unsigned int height); + void doEffects(void); + void applyShaders(void); + bool shadersEnabled(void); + + /// Night Vision Functions + void createNightVisionShader(void); + void applyNightVisionShader(void); + + /// Bloom Functions + void createBloomShader(void); + void applyBloomShader(void); + + /// Color Filter Functions + void createColorFilterShader(void); + void applyColorFilterShader(void); + + /// OpenGL Helper Functions + void getShaderUniforms(glslUniforms & uniforms, GLhandleARB & prog); + void createTexture(GLuint & texture, unsigned int width, unsigned int height); + void copyFrameBuffer(GLuint & texture, unsigned int width, unsigned int height); + void createNoiseTexture(GLuint & texture); + bool checkError(void); + void checkShaderError(GLhandleARB shader); + void drawOrthoQuad(unsigned int width, unsigned int height, QuadType type); + void viewOrthogonal(unsigned int width, unsigned int height); + void changeOrthogonal(unsigned int width, unsigned int height); + void viewPerspective(void); +}; + +extern LLPostProcess * gPostProcess; + + +#endif // LL_POSTPROCESS_H diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp index 1168155f8b..fc911de46b 100644 --- a/indra/llrender/llrender.cpp +++ b/indra/llrender/llrender.cpp @@ -36,6 +36,12 @@ LLRender gGL; +// Handy copies of last good GL matrices +F64 gGLModelView[16]; +F64 gGLLastModelView[16]; +F64 gGLProjection[16]; +S32 gGLViewport[4]; + static const U32 LL_NUM_TEXTURE_LAYERS = 8; static GLenum sGLCompareFunc[] = diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h index 2fa3237ef9..a0a492bc73 100644 --- a/indra/llrender/llrender.h +++ b/indra/llrender/llrender.h @@ -232,7 +232,10 @@ private: std::vector<LLTexUnit*> mTexUnits; }; - +extern F64 gGLModelView[16]; +extern F64 gGLLastModelView[16]; +extern F64 gGLProjection[16]; +extern S32 gGLViewport[4]; extern LLRender gGL; diff --git a/indra/llrender/llrendersphere.cpp b/indra/llrender/llrendersphere.cpp new file mode 100644 index 0000000000..296fa77184 --- /dev/null +++ b/indra/llrender/llrendersphere.cpp @@ -0,0 +1,159 @@ +/** + * @file llrendersphere.cpp + * @brief implementation of the LLRenderSphere class. + * + * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc. + * $License$ + */ + +// Sphere creates a set of display lists that can then be called to create +// a lit sphere at different LOD levels. You only need one instance of sphere +// per viewer - then call the appropriate list. + +#include "linden_common.h" + +#include "llrendersphere.h" +#include "llerror.h" + +#include "llglheaders.h" + +GLUquadricObj *gQuadObj2 = NULL; +LLRenderSphere gSphere; + +void drawSolidSphere(GLdouble radius, GLint slices, GLint stacks); + +void drawSolidSphere(GLdouble radius, GLint slices, GLint stacks) +{ + if (!gQuadObj2) + { + gQuadObj2 = gluNewQuadric(); + if (!gQuadObj2) + { + llwarns << "drawSolidSphere couldn't allocate quadric" << llendl; + return; + } + } + + gluQuadricDrawStyle(gQuadObj2, GLU_FILL); + gluQuadricNormals(gQuadObj2, GLU_SMOOTH); + // If we ever changed/used the texture or orientation state + // of quadObj, we'd need to change it to the defaults here + // with gluQuadricTexture and/or gluQuadricOrientation. + gluQuadricTexture(gQuadObj2, GL_TRUE); + gluSphere(gQuadObj2, radius, slices, stacks); +} + + +// lat = 0 is Z-axis +// lon = 0, lat = 90 at X-axis +void lat2xyz(LLVector3 * result, F32 lat, F32 lon) +{ + // Convert a latitude and longitude to x,y,z on a normal sphere and return it in result + F32 r; + result->mV[VX] = (F32) (cos(lon * DEG_TO_RAD) * sin(lat * DEG_TO_RAD)); + result->mV[VY] = (F32) (sin(lon * DEG_TO_RAD) * sin(lat * DEG_TO_RAD)); + r = (F32) pow(result->mV[VX] * result->mV[VX] + result->mV[VY] * result->mV[VY], 0.5f); + if (r == 1.0f) + { + result->mV[VZ] = 0.0f; + } + else + { + result->mV[VZ] = (F32) pow(1 - r*r, 0.5f); + if (lat > 90.01) + { + result->mV[VZ] *= -1.0; + } + } +} + +void lat2xyz_rad(LLVector3 * result, F32 lat, F32 lon) +{ + // Convert a latitude and longitude to x,y,z on a normal sphere and return it in result + F32 r; + result->mV[VX] = (F32) (cos(lon) * sin(lat)); + result->mV[VY] = (F32) (sin(lon) * sin(lat)); + r = (F32) pow(result->mV[VX] * result->mV[VX] + result->mV[VY] * result->mV[VY], 0.5f); + if (r == 1.0f) + result->mV[VZ] = 0.0f; + else + { + result->mV[VZ] = (F32) pow(1 - r*r, 0.5f); + if (lat > F_PI_BY_TWO) result->mV[VZ] *= -1.0; + } +} + +// A couple thoughts on sphere drawing: +// 1) You need more slices than stacks, but little less than 2:1 +// 2) At low LOD, setting stacks to an odd number avoids a "band" around the equator, making things look smoother +void LLRenderSphere::prerender() +{ + // Create a series of display lists for different LODs + mDList[0] = glGenLists(1); + glNewList(mDList[0], GL_COMPILE); + drawSolidSphere(1.0, 30, 20); + glEndList(); + + mDList[1] = glGenLists(1); + glNewList(mDList[1], GL_COMPILE); + drawSolidSphere(1.0, 20, 15); + glEndList(); + + mDList[2] = glGenLists(1); + glNewList(mDList[2], GL_COMPILE); + drawSolidSphere(1.0, 12, 8); + glEndList(); + + mDList[3] = glGenLists(1); + glNewList(mDList[3], GL_COMPILE); + drawSolidSphere(1.0, 8, 5); + glEndList(); +} + +void LLRenderSphere::cleanupGL() +{ + for (S32 detail = 0; detail < 4; detail++) + { + glDeleteLists(mDList[detail], 1); + mDList[detail] = 0; + } + + if (gQuadObj2) + { + gluDeleteQuadric(gQuadObj2); + gQuadObj2 = NULL; + } +} + +// Constants here are empirically derived from my eyeballs, JNC +// +// The toughest adjustment is the cutoff for the lowest LOD +// Maybe we should have more LODs at the low end? +void LLRenderSphere::render(F32 pixel_area) +{ + S32 level_of_detail; + + if (pixel_area > 10000.f) + { + level_of_detail = 0; + } + else if (pixel_area > 800.f) + { + level_of_detail = 1; + } + else if (pixel_area > 100.f) + { + level_of_detail = 2; + } + else + { + level_of_detail = 3; + } + glCallList(mDList[level_of_detail]); +} + + +void LLRenderSphere::render() +{ + glCallList(mDList[0]); +} diff --git a/indra/llrender/llrendersphere.h b/indra/llrender/llrendersphere.h new file mode 100644 index 0000000000..3e58f6fb31 --- /dev/null +++ b/indra/llrender/llrendersphere.h @@ -0,0 +1,34 @@ +/** + * @file llrendersphere.h + * @brief interface for the LLRenderSphere class. + * + * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc. + * $License$ + */ + +#ifndef LL_LLRENDERSPHERE_H +#define LL_LLRENDERSPHERE_H + +#include "llmath.h" +#include "v3math.h" +#include "v4math.h" +#include "m3math.h" +#include "m4math.h" +#include "v4color.h" +#include "llgl.h" + +void lat2xyz(LLVector3 * result, F32 lat, F32 lon); // utility routine + +class LLRenderSphere +{ +public: + LLGLuint mDList[5]; + + void prerender(); + void cleanupGL(); + void render(F32 pixel_area); // of a box of size 1.0 at that position + void render(); // render at highest LOD +}; + +extern LLRenderSphere gSphere; +#endif diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp new file mode 100644 index 0000000000..3bdc36c677 --- /dev/null +++ b/indra/llrender/llshadermgr.cpp @@ -0,0 +1,513 @@ +/** + * @file llshadermgr.cpp + * @brief Shader manager implementation. + * + * $LicenseInfo:firstyear=2005&license=viewergpl$ + * + * Copyright (c) 2005-2007, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llshadermgr.h" + +#include "llfile.h" +#include "llrender.h" + +#if LL_DARWIN +#include "OpenGL/OpenGL.h" +#endif + +#ifdef LL_RELEASE_FOR_DOWNLOAD +#define UNIFORM_ERRS LL_WARNS_ONCE("Shader") +#else +#define UNIFORM_ERRS LL_ERRS("Shader") +#endif + +// Lots of STL stuff in here, using namespace std to keep things more readable +using std::vector; +using std::pair; +using std::make_pair; +using std::string; + +LLShaderMgr * LLShaderMgr::sInstance = NULL; + +LLShaderMgr::LLShaderMgr() +{ +} + + +LLShaderMgr::~LLShaderMgr() +{ +} + +// static +LLShaderMgr * LLShaderMgr::instance() +{ + if(NULL == sInstance) + { + LL_ERRS("Shaders") << "LLShaderMgr should already have been instantiated by the application!" << LL_ENDL; + } + + return sInstance; +} + +BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) +{ + llassert_always(shader != NULL); + LLShaderFeatures *features = & shader->mFeatures; + + ////////////////////////////////////// + // Attach Vertex Shader Features First + ////////////////////////////////////// + + // NOTE order of shader object attaching is VERY IMPORTANT!!! + if (features->calculatesAtmospherics) + { + if (!shader->attachObject("windlight/atmosphericsVarsV.glsl")) + { + return FALSE; + } + } + + if (features->calculatesLighting) + { + if (!shader->attachObject("windlight/atmosphericsHelpersV.glsl")) + { + return FALSE; + } + + if (features->isSpecular) + { + if (!shader->attachObject("lighting/lightFuncSpecularV.glsl")) + { + return FALSE; + } + + if (!shader->attachObject("lighting/sumLightsSpecularV.glsl")) + { + return FALSE; + } + + if (!shader->attachObject("lighting/lightSpecularV.glsl")) + { + return FALSE; + } + } + else + { + if (!shader->attachObject("lighting/lightFuncV.glsl")) + { + return FALSE; + } + + if (!shader->attachObject("lighting/sumLightsV.glsl")) + { + return FALSE; + } + + if (!shader->attachObject("lighting/lightV.glsl")) + { + return FALSE; + } + } + } + + // NOTE order of shader object attaching is VERY IMPORTANT!!! + if (features->calculatesAtmospherics) + { + if (!shader->attachObject("windlight/atmosphericsV.glsl")) + { + return FALSE; + } + } + + if (features->hasSkinning) + { + if (!shader->attachObject("avatar/avatarSkinV.glsl")) + { + return FALSE; + } + } + + /////////////////////////////////////// + // Attach Fragment Shader Features Next + /////////////////////////////////////// + + if(features->calculatesAtmospherics) + { + if (!shader->attachObject("windlight/atmosphericsVarsF.glsl")) + { + return FALSE; + } + } + + // NOTE order of shader object attaching is VERY IMPORTANT!!! + if (features->hasGamma) + { + if (!shader->attachObject("windlight/gammaF.glsl")) + { + return FALSE; + } + } + + if (features->hasAtmospherics) + { + if (!shader->attachObject("windlight/atmosphericsF.glsl")) + { + return FALSE; + } + } + + if (features->hasTransport) + { + if (!shader->attachObject("windlight/transportF.glsl")) + { + return FALSE; + } + + // Test hasFullbright and hasShiny and attach fullbright and + // fullbright shiny atmos transport if we split them out. + } + + // NOTE order of shader object attaching is VERY IMPORTANT!!! + if (features->hasWaterFog) + { + if (!shader->attachObject("environment/waterFogF.glsl")) + { + return FALSE; + } + } + + if (features->hasLighting) + { + + if (features->hasWaterFog) + { + if (!shader->attachObject("lighting/lightWaterF.glsl")) + { + return FALSE; + } + } + + else + { + if (!shader->attachObject("lighting/lightF.glsl")) + { + return FALSE; + } + } + } + + // NOTE order of shader object attaching is VERY IMPORTANT!!! + else if (features->isFullbright) + { + + if (features->hasWaterFog) + { + if (!shader->attachObject("lighting/lightFullbrightWaterF.glsl")) + { + return FALSE; + } + } + + else if (features->isShiny) + { + if (!shader->attachObject("lighting/lightFullbrightShinyF.glsl")) + { + return FALSE; + } + } + + else + { + if (!shader->attachObject("lighting/lightFullbrightF.glsl")) + { + return FALSE; + } + } + } + + // NOTE order of shader object attaching is VERY IMPORTANT!!! + else if (features->isShiny) + { + + if (features->hasWaterFog) + { + if (!shader->attachObject("lighting/lightShinyWaterF.glsl")) + { + return FALSE; + } + } + + else + { + if (!shader->attachObject("lighting/lightShinyF.glsl")) + { + return FALSE; + } + } + } + return TRUE; +} + +//============================================================================ +// Load Shader + +static std::string get_object_log(GLhandleARB ret) +{ + std::string res; + + //get log length + GLint length; + glGetObjectParameterivARB(ret, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length); + if (length > 0) + { + //the log could be any size, so allocate appropriately + GLcharARB* log = new GLcharARB[length]; + glGetInfoLogARB(ret, length, &length, log); + res = std::string((char *)log); + delete[] log; + } + return res; +} + +void LLShaderMgr::dumpObjectLog(GLhandleARB ret, BOOL warns) +{ + std::string log = get_object_log(ret); + if ( log.length() > 0 ) + { + if (warns) + { + LL_WARNS("ShaderLoading") << log << LL_ENDL; + } + else + { + LL_DEBUGS("ShaderLoading") << log << LL_ENDL; + } +} +} + +GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type) +{ + GLenum error; + error = glGetError(); + if (error != GL_NO_ERROR) + { + LL_WARNS("ShaderLoading") << "GL ERROR entering loadShaderFile(): " << error << LL_ENDL; + } + + LL_DEBUGS("ShaderLoading") << "Loading shader file: " << filename << " class " << shader_level << LL_ENDL; + + if (filename.empty()) + { + return 0; + } + + + //read in from file + LLFILE* file = NULL; + + S32 try_gpu_class = shader_level; + S32 gpu_class; + + //find the most relevant file + for (gpu_class = try_gpu_class; gpu_class > 0; gpu_class--) + { //search from the current gpu class down to class 1 to find the most relevant shader + std::stringstream fname; + fname << getShaderDirPrefix(); + fname << gpu_class << "/" << filename; + + LL_DEBUGS("ShaderLoading") << "Looking in " << fname.str() << LL_ENDL; + file = LLFile::fopen(fname.str(), "r"); /* Flawfinder: ignore */ + if (file) + { + LL_INFOS("ShaderLoading") << "Loading file: shaders/class" << gpu_class << "/" << filename << " (Want class " << gpu_class << ")" << LL_ENDL; + break; // done + } + } + + if (file == NULL) + { + LL_WARNS("ShaderLoading") << "GLSL Shader file not found: " << filename << LL_ENDL; + return 0; + } + + //we can't have any lines longer than 1024 characters + //or any shaders longer than 1024 lines... deal - DaveP + GLcharARB buff[1024]; + GLcharARB* text[1024]; + GLuint count = 0; + + + //copy file into memory + while(fgets((char *)buff, 1024, file) != NULL && count < (sizeof(buff)/sizeof(buff[0]))) + { + text[count++] = (GLcharARB *)strdup((char *)buff); + } + fclose(file); + + //create shader object + GLhandleARB ret = glCreateShaderObjectARB(type); + error = glGetError(); + if (error != GL_NO_ERROR) + { + LL_WARNS("ShaderLoading") << "GL ERROR in glCreateShaderObjectARB: " << error << LL_ENDL; + } + else + { + //load source + glShaderSourceARB(ret, count, (const GLcharARB**) text, NULL); + error = glGetError(); + if (error != GL_NO_ERROR) + { + LL_WARNS("ShaderLoading") << "GL ERROR in glShaderSourceARB: " << error << LL_ENDL; + } + else + { + //compile source + glCompileShaderARB(ret); + error = glGetError(); + if (error != GL_NO_ERROR) + { + LL_WARNS("ShaderLoading") << "GL ERROR in glCompileShaderARB: " << error << LL_ENDL; + } + } + } + //free memory + for (GLuint i = 0; i < count; i++) + { + free(text[i]); + } + if (error == GL_NO_ERROR) + { + //check for errors + GLint success = GL_TRUE; + glGetObjectParameterivARB(ret, GL_OBJECT_COMPILE_STATUS_ARB, &success); + error = glGetError(); + if (error != GL_NO_ERROR || success == GL_FALSE) + { + //an error occured, print log + LL_WARNS("ShaderLoading") << "GLSL Compilation Error: (" << error << ") in " << filename << LL_ENDL; + dumpObjectLog(ret); + ret = 0; + } + } + else + { + ret = 0; + } + stop_glerror(); + + //successfully loaded, save results + if (ret) + { + // Add shader file to map + mShaderObjects[filename] = ret; + shader_level = try_gpu_class; + } + else + { + if (shader_level > 1) + { + shader_level--; + return loadShaderFile(filename,shader_level,type); + } + LL_WARNS("ShaderLoading") << "Failed to load " << filename << LL_ENDL; + } + return ret; +} + +BOOL LLShaderMgr::linkProgramObject(GLhandleARB obj, BOOL suppress_errors) +{ + //check for errors + glLinkProgramARB(obj); + GLint success = GL_TRUE; + glGetObjectParameterivARB(obj, GL_OBJECT_LINK_STATUS_ARB, &success); + if (!suppress_errors && success == GL_FALSE) + { + //an error occured, print log + LL_WARNS("ShaderLoading") << "GLSL Linker Error:" << LL_ENDL; + } + +// NOTE: Removing LL_DARWIN block as it doesn't seem to actually give the correct answer, +// but want it for reference once I move it. +#if 0 + // Force an evaluation of the gl state so the driver can tell if the shader will run in hardware or software + // per Apple's suggestion + glBegin(gGL.mMode); + glEnd(); + + // Query whether the shader can or cannot run in hardware + // http://developer.apple.com/qa/qa2007/qa1502.html + long vertexGPUProcessing; + CGLContextObj ctx = CGLGetCurrentContext(); + CGLGetParameter (ctx, kCGLCPGPUVertexProcessing, &vertexGPUProcessing); + long fragmentGPUProcessing; + CGLGetParameter (ctx, kCGLCPGPUFragmentProcessing, &fragmentGPUProcessing); + if (!fragmentGPUProcessing || !vertexGPUProcessing) + { + LL_WARNS("ShaderLoading") << "GLSL Linker: Running in Software:" << LL_ENDL; + success = GL_FALSE; + suppress_errors = FALSE; + } + +#else + std::string log = get_object_log(obj); + LLStringUtil::toLower(log); + if (log.find("software") != std::string::npos) + { + LL_WARNS("ShaderLoading") << "GLSL Linker: Running in Software:" << LL_ENDL; + success = GL_FALSE; + suppress_errors = FALSE; + } +#endif + if (!suppress_errors) + { + dumpObjectLog(obj, !success); + } + + return success; +} + +BOOL LLShaderMgr::validateProgramObject(GLhandleARB obj) +{ + //check program validity against current GL + glValidateProgramARB(obj); + GLint success = GL_TRUE; + glGetObjectParameterivARB(obj, GL_OBJECT_VALIDATE_STATUS_ARB, &success); + if (success == GL_FALSE) + { + LL_WARNS("ShaderLoading") << "GLSL program not valid: " << LL_ENDL; + dumpObjectLog(obj); + } + else + { + dumpObjectLog(obj, FALSE); + } + + return success; +} + diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h new file mode 100644 index 0000000000..09b9ca812e --- /dev/null +++ b/indra/llrender/llshadermgr.h @@ -0,0 +1,75 @@ +/** + * @file llshadermgr.h + * @brief Shader Manager + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2008, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_SHADERMGR_H +#define LL_SHADERMGR_H + +#include "llgl.h" +#include "llglslshader.h" + +class LLShaderMgr +{ +public: + LLShaderMgr(); + virtual ~LLShaderMgr(); + + // singleton pattern implementation + static LLShaderMgr * instance(); + + BOOL attachShaderFeatures(LLGLSLShader * shader); + void dumpObjectLog(GLhandleARB ret, BOOL warns = TRUE); + BOOL linkProgramObject(GLhandleARB obj, BOOL suppress_errors = FALSE); + BOOL validateProgramObject(GLhandleARB obj); + GLhandleARB loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type); + + // Implemented in the application to actually point to the shader directory. + virtual std::string getShaderDirPrefix(void) = 0; // Pure Virtual + + // Implemented in the application to actually update out of date uniforms for a particular shader + virtual void updateShaderUniforms(LLGLSLShader * shader) = 0; // Pure Virtual + +public: + // Map of shader names to compiled + std::map<std::string, GLhandleARB> mShaderObjects; + + //global (reserved slot) shader parameters + std::vector<std::string> mReservedAttribs; + + std::vector<std::string> mReservedUniforms; + +protected: + + // our parameter manager singleton instance + static LLShaderMgr * sInstance; + +}; //LLShaderMgr + +#endif diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h index 2b5f4e200b..45f501fe1e 100644 --- a/indra/llrender/llvertexbuffer.h +++ b/indra/llrender/llvertexbuffer.h @@ -41,6 +41,7 @@ #include "llmemory.h" #include <set> #include <vector> +#include <list> //============================================================================ // NOTES |